A bit of refactoring; document configuration in README.md

timeout_old
Tassilo Horn 3 years ago
parent 08b69d788f
commit f9d7b0d805
  1. 67
      README.md
  2. 42
      src/con.rs
  3. 63
      src/config.rs
  4. 16
      src/util.rs

@ -6,7 +6,8 @@
Swayr consists of a demon, and a client. The demon `swayrd` records Swayr consists of a demon, and a client. The demon `swayrd` records
window/workspace creations, deletions, and focus changes using sway's JSON IPC window/workspace creations, deletions, and focus changes using sway's JSON IPC
interface. The client `swayr` offers subcommands, see `swayr --help`. interface. The client `swayr` offers subcommands, see `swayr --help`, and
sends them to the demon which executes them.
Right now, there are these subcommands: Right now, there are these subcommands:
* `next-window` focuses the next window in depth-first iteration order of the * `next-window` focuses the next window in depth-first iteration order of the
@ -82,16 +83,72 @@ and logging are optional.
## Configuration ## Configuration
Swayr can be configured using the `~/.config/swayr/config.toml` config file. Swayr can be configured using the `~/.config/swayr/config.toml` config file.
If it doesn't exist, a simple default configuration will be created on the If it doesn't exist, a simple default configuration will be created on the
first invocation for use with the [wofi](https://todo.sr.ht/~scoopta/wofi) first invocation for use with the [wofi](https://todo.sr.ht/~scoopta/wofi)
launcher. It should be easy to adapt that default config for usage with other launcher.
launchers such as [dmenu](https://tools.suckless.org/dmenu/),
It should be easy to adapt that default config for usage with other launchers
such as [dmenu](https://tools.suckless.org/dmenu/),
[bemenu](https://github.com/Cloudef/bemenu), [bemenu](https://github.com/Cloudef/bemenu),
[rofi](https://github.com/davatorium/rofi), a script spawning a terminal with [rofi](https://github.com/davatorium/rofi), a script spawning a terminal with
[fzf](https://github.com/junegunn/fzf), or whatever. The only requirement is [fzf](https://github.com/junegunn/fzf), or whatever. The only requirement is
that the launcher needs to be able to read the items to choose from from stdin. that the launcher needs to be able to read the items to choose from from stdin,
and spit out the selected item to stdout.
The default config looks like this:
```toml
[launcher]
executable = 'wofi'
args = [
'--show=dmenu',
'--allow-markup',
'--allow-images',
'--insensitive',
'--cache-file=/dev/null',
'--parse-search',
'--prompt={prompt}',
]
[format]
window_format = '{urgency_start}<b>“{title}”</b>{urgency_end} — <i>{app_name}</i> on workspace {workspace_name} <span alpha="20000">({id})</span>'
workspace_format = '<b>Workspace {name}</b> <span alpha="20000">({id})</span>'
urgency_start = '<span background="darkred" foreground="yellow">'
urgency_end = '</span>'
```
TODO: Show default config and describe it. In the `[launcher]` section, you can specify the launchen/menu program using
the `executable` name or full path, and the `args` (flags and options) it
should get passed. If some argument contains the placeholder `{prompt}`, it is
replaced with a prompt such as "Switch to window" depending on context.
In the `[format]` section, format strings are specified defining how selection
choises are to be layed out. `wofi` supports [pango
markup](https://docs.gtk.org/Pango/pango_markup.html) which makes it possible
to style the text using HTML and CSS. The following formats are supported
right now.
* `window_format` defines how windows are displayed. The placeholder `{title}`
is replaced with the window's title, `{app_name}` with the application name,
`{workspace_name}` with the name or number of the workspace the window is
shown, and `{id}` is the window's sway-internal con id. There are also the
placeholders `{urcency_start}` and `{urgency_end}` which get replaced by the
empty string if the window has no urgency flag, and with the values of the
same-named formats if the window has the urgency flag set. That makes it
possible to highlight urgent windows as shown in the default config.
* `workspace_format` defines how workspaces are displayed. There are the
placeholders `{name}` which gets replaced by the workspace's number or name,
and `{id}` which gets replaced by the sway-internal con id of the workspace.
* `urgency_start` is a string which replaces the `{urgency_start}` placeholder
in `window_format`.
* `urgency_end` is a string which replaces the `{urgency_end}` placeholder in
`window_format`.
It is crucial that during selection (using wofi or some other launcher) each
window has a different display string. Therefore, it is highly recommended to
include the `{id}` placeholder at least in `window_format`. Otherwise, e.g.,
two terminals (of the same terminal app) with the same working directory (and
therefore, the same title) wouldn't be distinguishable.
## Questions & Patches ## Questions & Patches

@ -122,46 +122,22 @@ impl<'a> fmt::Display for Window<'a> {
impl<'a> DisplayFormat for Window<'a> { impl<'a> DisplayFormat for Window<'a> {
fn format_for_display(&self, cfg: &cfg::Config) -> String { fn format_for_display(&self, cfg: &cfg::Config) -> String {
let default = cfg::Config::default(); let default_format = cfg::Format::default();
let fmt = cfg let fmt = cfg
.format .format
.as_ref() .as_ref()
.and_then(|f| f.window_format.as_ref()) .and_then(|f| f.window_format.as_ref())
.unwrap_or_else(|| { .unwrap_or_else(|| default_format.window_format.as_ref().unwrap());
default
.format
.as_ref()
.unwrap()
.window_format
.as_ref()
.unwrap()
});
let urgency_start = cfg let urgency_start = cfg
.format .format
.as_ref() .as_ref()
.and_then(|f| f.urgency_start.as_ref()) .and_then(|f| f.urgency_start.as_ref())
.unwrap_or_else(|| { .unwrap_or_else(|| default_format.urgency_start.as_ref().unwrap());
default
.format
.as_ref()
.unwrap()
.urgency_start
.as_ref()
.unwrap()
});
let urgency_end = cfg let urgency_end = cfg
.format .format
.as_ref() .as_ref()
.and_then(|f| f.urgency_end.as_ref()) .and_then(|f| f.urgency_end.as_ref())
.unwrap_or_else(|| { .unwrap_or_else(|| default_format.urgency_end.as_ref().unwrap());
default
.format
.as_ref()
.unwrap()
.urgency_end
.as_ref()
.unwrap()
});
fmt.replace("{id}", format!("{}", self.get_id()).as_str()) fmt.replace("{id}", format!("{}", self.get_id()).as_str())
.replace( .replace(
@ -391,19 +367,13 @@ impl<'a> fmt::Display for Workspace<'a> {
impl<'a> DisplayFormat for Workspace<'a> { impl<'a> DisplayFormat for Workspace<'a> {
fn format_for_display(&self, cfg: &cfg::Config) -> String { fn format_for_display(&self, cfg: &cfg::Config) -> String {
let default = cfg::Config::default(); let default_format = cfg::Format::default();
let fmt = cfg let fmt = cfg
.format .format
.as_ref() .as_ref()
.and_then(|f| f.workspace_format.as_ref()) .and_then(|f| f.workspace_format.as_ref())
.unwrap_or_else(|| { .unwrap_or_else(|| {
default default_format.workspace_format.as_ref().unwrap()
.format
.as_ref()
.unwrap()
.workspace_format
.as_ref()
.unwrap()
}); });
fmt.replace("{id}", format!("{}", self.get_id()).as_str()) fmt.replace("{id}", format!("{}", self.get_id()).as_str())

@ -28,30 +28,51 @@ pub struct Config {
pub format: Option<Format>, pub format: Option<Format>,
} }
impl Default for Launcher {
fn default() -> Self {
Launcher {
executable: Some("wofi".to_string()),
args: Some(vec![
"--show=dmenu".to_string(),
"--allow-markup".to_string(),
"--allow-images".to_string(),
"--insensitive".to_string(),
"--cache-file=/dev/null".to_string(),
"--parse-search".to_string(),
"--prompt={prompt}".to_string(),
]),
}
}
}
impl Default for Format {
fn default() -> Self {
Format {
window_format: Some(
"{urgency_start}<b>{title}</b>{urgency_end} \
<i>{app_name}</i> on workspace {workspace_name} \
<span alpha=\"20000\">({id})</span>"
.to_string(),
),
workspace_format: Some(
"<b>Workspace {name}</b> \
<span alpha=\"20000\">({id})</span>"
.to_string(),
),
urgency_start: Some(
"<span background=\"darkred\" foreground=\"yellow\">"
.to_string(),
),
urgency_end: Some("</span>".to_string()),
}
}
}
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Config { Config {
launcher: Some(Launcher { launcher: Some(Launcher::default()),
executable: Some("wofi".to_string()), format: Some(Format::default()),
args: Some(vec![
"--show=dmenu".to_string(),
"--allow-markup".to_string(),
"--allow-images".to_string(),
"--insensitive".to_string(),
"--cache-file=/dev/null".to_string(),
"--parse-search".to_string(),
"--prompt={prompt}".to_string(),
]),
}),
format: Some(Format {
window_format: Some(
"{urgency_start}<b>“{title}”</b>{urgency_end} — <i>{app_name}</i> on workspace {workspace_name} <span alpha=\"20000\">({id})</span>"
.to_string(),
),
workspace_format: Some("<b>Workspace {name}</b> <span alpha=\"20000\">({id})</span>".to_string()),
urgency_start: Some("<span background=\"darkred\" foreground=\"yellow\">".to_string()),
urgency_end: Some("</span>".to_string())
}),
} }
} }
} }

@ -52,27 +52,17 @@ where
map.insert(s, c); map.insert(s, c);
} }
let default = cfg::Config::default(); let launcher_default = cfg::Launcher::default();
let launcher_exec = cfg let launcher_exec = cfg
.launcher .launcher
.as_ref() .as_ref()
.and_then(|l| l.executable.as_ref()) .and_then(|l| l.executable.as_ref())
.unwrap_or_else(|| { .unwrap_or_else(|| launcher_default.executable.as_ref().unwrap());
default
.launcher
.as_ref()
.unwrap()
.executable
.as_ref()
.unwrap()
});
let args: Vec<String> = cfg let args: Vec<String> = cfg
.launcher .launcher
.as_ref() .as_ref()
.and_then(|l| l.args.as_ref()) .and_then(|l| l.args.as_ref())
.unwrap_or_else(|| { .unwrap_or_else(|| launcher_default.args.as_ref().unwrap())
default.launcher.as_ref().unwrap().args.as_ref().unwrap()
})
.iter() .iter()
.map(|a| a.replace("{prompt}", prompt)) .map(|a| a.replace("{prompt}", prompt))
.collect(); .collect();

Loading…
Cancel
Save