Tidy up menu display formatting

timeout_old
Tassilo Horn 3 years ago
parent 068b9ade84
commit 7e16b735b2
  1. 19
      src/cmds.rs
  2. 16
      src/config.rs
  3. 220
      src/tree.rs
  4. 2
      src/util.rs

@ -430,11 +430,6 @@ pub fn switch_to_urgent_or_lru_window(
let root = get_tree(false); let root = get_tree(false);
let tree = t::get_tree(&root, extra_props); let tree = t::get_tree(&root, extra_props);
if let Some(win) = tree.get_windows().get(0) { if let Some(win) = tree.get_windows().get(0) {
println!(
"Switching to {}, id: {}",
win.node.get_app_name().unwrap_or_else(|e| e),
win.node.id
);
focus_window_by_id(win.node.id) focus_window_by_id(win.node.id)
} else { } else {
println!("No window to switch to.") println!("No window to switch to.")
@ -607,18 +602,8 @@ fn move_focused_to_container_or_window(id: i64) {
"--add", "--add",
"__SWAYR_MOVE_TARGET__", "__SWAYR_MOVE_TARGET__",
]); ]);
run_sway_command(&[ run_sway_command(&["move", "to", "mark", "__SWAYR_MOVE_TARGET__"]);
"move", run_sway_command(&["unmark", "__SWAYR_MOVE_TARGET__"]);
"container",
"to",
"mark",
"__SWAYR_MOVE_TARGET__",
]);
run_sway_command(&[
&format!("[con_id\"{}\"]", id),
"unmark",
"__SWAYR_MOVE_TARGET__",
]);
} }
fn select_and_move_focused_to(prompt: &str, choices: &[t::DisplayNode]) { fn select_and_move_focused_to(prompt: &str, choices: &[t::DisplayNode]) {

@ -215,20 +215,20 @@ impl Default for Menu {
impl Default for Format { impl Default for Format {
fn default() -> Self { fn default() -> Self {
Format { Format {
window_format: Some( workspace_format: Some(
"img:{app_icon}:text:{indent}<i>{app_name}</i> \ "{indent}<b>Workspace {name} [{layout}]</b> \
{urgency_start}<b>{title}</b>{urgency_end} \
on workspace {workspace_name} <i>{marks}</i> \
<span alpha=\"20000\">({id})</span>" <span alpha=\"20000\">({id})</span>"
.to_string(), .to_string(),
), ),
workspace_format: Some( container_format: Some(
"{indent}<b>Workspace {name}</b> {layout} \ "{indent}<b>Container [{layout}]</b> \
on workspace {workspace_name} <i>{marks}</i> \
<span alpha=\"20000\">({id})</span>" <span alpha=\"20000\">({id})</span>"
.to_string(), .to_string(),
), ),
container_format: Some( window_format: Some(
"{indent}<b>Container {layout}</b> \ "img:{app_icon}:text:{indent}<i>{app_name}</i> \
{urgency_start}<b>{title}</b>{urgency_end} \
on workspace {workspace_name} <i>{marks}</i> \ on workspace {workspace_name} <i>{marks}</i> \
<span alpha=\"20000\">({id})</span>" <span alpha=\"20000\">({id})</span>"
.to_string(), .to_string(),

@ -70,7 +70,7 @@ pub enum Type {
pub trait NodeMethods { pub trait NodeMethods {
fn iter(&self) -> NodeIter; fn iter(&self) -> NodeIter;
fn get_type(&self) -> Type; fn get_type(&self) -> Type;
fn get_app_name(&self) -> Result<&str, &str>; fn get_app_name(&self) -> &str;
fn nodes_of_type(&self, t: Type) -> Vec<&s::Node>; fn nodes_of_type(&self, t: Type) -> Vec<&s::Node>;
fn get_name(&self) -> &str; fn get_name(&self) -> &str;
fn is_scratchpad(&self) -> bool; fn is_scratchpad(&self) -> bool;
@ -120,17 +120,17 @@ impl NodeMethods for s::Node {
} }
} }
fn get_app_name(&self) -> Result<&str, &str> { fn get_app_name(&self) -> &str {
if let Some(app_id) = &self.app_id { if let Some(app_id) = &self.app_id {
Ok(app_id) app_id
} else if let Some(wp_class) = self } else if let Some(wp_class) = self
.window_properties .window_properties
.as_ref() .as_ref()
.and_then(|wp| wp.class.as_ref()) .and_then(|wp| wp.class.as_ref())
{ {
Ok(wp_class) wp_class
} else { } else {
Err("<unknown_app>") "<unknown_app>"
} }
} }
@ -389,136 +389,110 @@ fn maybe_html_escape(do_it: bool, text: &str) -> String {
} }
} }
fn format_marks(marks: &Vec<String>) -> String {
if marks.is_empty() {
"".to_string()
} else {
format!("[{}]", marks.join(", "))
}
}
impl DisplayFormat for DisplayNode<'_> { impl DisplayFormat for DisplayNode<'_> {
fn format_for_display(&self, cfg: &config::Config) -> String { fn format_for_display(&self, cfg: &config::Config) -> String {
let indent = cfg.get_format_indent(); let indent = cfg.get_format_indent();
let html_escape = cfg.get_format_html_escape(); let html_escape = cfg.get_format_html_escape();
let urgency_start = cfg.get_format_urgency_start();
let urgency_end = cfg.get_format_urgency_end();
let icon_dirs = cfg.get_format_icon_dirs();
// fallback_icon has no default value.
let fallback_icon: Option<Box<std::path::Path>> = cfg
.get_format_fallback_icon()
.as_ref()
.map(|i| std::path::Path::new(i).to_owned().into_boxed_path());
match self.node.get_type() { let app_name_no_version =
APP_NAME_AND_VERSION_RX.replace(self.node.get_app_name(), "$1");
let fmt = match self.node.get_type() {
Type::Root => String::from("Cannot format Root"), Type::Root => String::from("Cannot format Root"),
Type::Output => String::from("Cannot format Output"), Type::Output => String::from("Cannot format Output"),
Type::Workspace => cfg Type::Workspace => cfg.get_format_workspace_format(),
.get_format_workspace_format() Type::Container => cfg.get_format_container_format(),
.replace("{indent}", &indent.repeat(self.get_indent_level())) Type::Window => cfg.get_format_window_format(),
.replace("{layout}", format!("{:?}", self.node.layout).as_str()) };
.replace("{id}", format!("{}", self.node.id).as_str()) fmt.replace("{indent}", &indent.repeat(self.get_indent_level()))
.replace( .replace("{layout}", format!("{:?}", self.node.layout).as_str())
"{name}", .replace("{id}", format!("{}", self.node.id).as_str())
&maybe_html_escape(html_escape, self.node.get_name()), .replace(
"{marks}",
&maybe_html_escape(
html_escape,
&format_marks(&self.node.marks),
), ),
Type::Container => cfg )
.get_format_container_format() .replace(
.replace("{indent}", &indent.repeat(self.get_indent_level())) "{urgency_start}",
.replace("{layout}", format!("{:?}", self.node.layout).as_str()) if self.node.urgent {
.replace("{id}", format!("{}", self.node.id).as_str()) urgency_start.as_str()
.replace( } else {
"{marks}", ""
&maybe_html_escape( },
html_escape, )
&self.node.marks.join(", "), .replace(
), "{urgency_end}",
) if self.node.urgent {
.replace( urgency_end.as_str()
"{workspace_name}", } else {
&maybe_html_escape( ""
html_escape, },
self.tree )
.get_workspace_node(self.node.id) .replace(
.map_or("<no_workspace>", |w| w.get_name()), "{app_name}",
), &maybe_html_escape(html_escape, self.node.get_app_name()),
)
.replace(
"{name}",
&maybe_html_escape(html_escape, self.node.get_name()),
)
.replace(
"{workspace_name}",
&maybe_html_escape(
html_escape,
self.tree
.get_workspace_node(self.node.id)
.map_or("<no_workspace>", |w| w.get_name()),
), ),
Type::Window => { )
let urgency_start = cfg.get_format_urgency_start(); .replace(
let urgency_end = cfg.get_format_urgency_end(); "{workspace_name}",
let icon_dirs = cfg.get_format_icon_dirs(); &maybe_html_escape(
// fallback_icon has no default value. html_escape,
let fallback_icon: Option<Box<std::path::Path>> = self.tree
cfg.get_format_fallback_icon().as_ref().map(|i| { .get_workspace_node(self.node.id)
std::path::Path::new(i).to_owned().into_boxed_path() .map_or("<no_workspace>", |w| w.get_name()),
}); ),
)
// Some apps report, e.g., Gimp-2.10 but the icon is still named .replace(
// gimp.png. "{app_icon}",
let app_name = util::get_icon(self.node.get_app_name(), &icon_dirs)
self.node.get_app_name().unwrap_or("_unknown_app_"); .or_else(|| {
let app_name_no_version = util::get_icon(&app_name_no_version, &icon_dirs)
APP_NAME_AND_VERSION_RX.replace(app_name, "$1"); })
.or_else(|| {
cfg.get_format_window_format()
.replace(
"{indent}",
&indent.repeat(self.get_indent_level()),
)
.replace(
"{layout}",
format!("{:?}", self.node.layout).as_str(),
)
.replace("{id}", format!("{}", self.node.id).as_str())
.replace(
"{urgency_start}",
if self.node.urgent {
urgency_start.as_str()
} else {
""
},
)
.replace(
"{urgency_end}",
if self.node.urgent {
urgency_end.as_str()
} else {
""
},
)
.replace(
"{app_name}",
&maybe_html_escape(
html_escape,
self.node.get_app_name().unwrap_or_else(|e| e),
),
)
.replace(
"{workspace_name}",
&maybe_html_escape(
html_escape,
self.tree
.get_workspace_node(self.node.id)
.map_or("<no_workspace>", |w| w.get_name()),
),
)
.replace(
"{marks}",
&maybe_html_escape(
html_escape,
&self.node.marks.join(", "),
),
)
.replace(
"{app_icon}",
util::get_icon( util::get_icon(
self.node.get_app_name().unwrap_or_else(|e| e), &app_name_no_version.to_lowercase(),
&icon_dirs, &icon_dirs,
) )
.or_else(|| { })
util::get_icon(&app_name_no_version, &icon_dirs) .or(fallback_icon)
}) .map(|i| i.to_string_lossy().into_owned())
.or_else(|| { .unwrap_or_else(String::new)
util::get_icon( .as_str(),
&app_name_no_version.to_lowercase(), )
&icon_dirs, .replace(
) "{title}",
}) &maybe_html_escape(html_escape, self.node.get_name()),
.or(fallback_icon) )
.map(|i| i.to_string_lossy().into_owned())
.unwrap_or_else(String::new)
.as_str(),
)
.replace(
"{title}",
&maybe_html_escape(html_escape, self.node.get_name()),
)
}
}
} }
fn get_indent_level(&self) -> usize { fn get_indent_level(&self) -> usize {

@ -278,7 +278,7 @@ where
.as_mut() .as_mut()
.expect("Failed to open the menu program's stdin"); .expect("Failed to open the menu program's stdin");
let input = strs.join("\n"); let input = strs.join("\n");
println!("Menu program {} input:\n{}", menu_exec, input); //println!("Menu program {} input:\n{}", menu_exec, input);
stdin stdin
.write_all(input.as_bytes()) .write_all(input.as_bytes())
.expect("Failed to write to the menu program's stdin"); .expect("Failed to write to the menu program's stdin");

Loading…
Cancel
Save