launcher -> menu program

timeout_old
Tassilo Horn 3 years ago
parent 373ee382e6
commit b67ba9d5a4
  1. 24
      README.md
  2. 4
      src/cmds.rs
  3. 6
      src/con.rs
  4. 36
      src/config.rs
  5. 30
      src/util.rs

@ -86,10 +86,10 @@ 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. menu program.
It should be easy to adapt that default config for usage with other launchers It should be easy to adapt that default config for usage with other menu
such as [dmenu](https://tools.suckless.org/dmenu/), programs 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
@ -99,7 +99,7 @@ and spit out the selected item to stdout.
The default config looks like this: The default config looks like this:
```toml ```toml
[launcher] [menu]
executable = 'wofi' executable = 'wofi'
args = [ args = [
'--show=dmenu', '--show=dmenu',
@ -118,9 +118,9 @@ urgency_start = '<span background="darkred" foreground="yellow">'
urgency_end = '</span>' urgency_end = '</span>'
``` ```
In the `[launcher]` section, you can specify the launchen/menu program using In the `[menu]` section, you can specify the menu program using the
the `executable` name or full path, and the `args` (flags and options) it `executable` name or full path, and the `args` (flags and options) it should
should get passed. If some argument contains the placeholder `{prompt}`, it is get passed. If some argument contains the placeholder `{prompt}`, it is
replaced with a prompt such as "Switch to window" depending on context. replaced with a prompt such as "Switch to window" depending on context.
In the `[format]` section, format strings are specified defining how selection In the `[format]` section, format strings are specified defining how selection
@ -144,11 +144,11 @@ right now.
* `urgency_end` is a string which replaces the `{urgency_end}` placeholder in * `urgency_end` is a string which replaces the `{urgency_end}` placeholder in
`window_format`. `window_format`.
It is crucial that during selection (using wofi or some other launcher) each It is crucial that during selection (using wofi or some other menu program)
window has a different display string. Therefore, it is highly recommended to each window has a different display string. Therefore, it is highly
include the `{id}` placeholder at least in `window_format`. Otherwise, e.g., recommended to include the `{id}` placeholder at least in `window_format`.
two terminals (of the same terminal app) with the same working directory (and Otherwise, e.g., two terminals (of the same terminal app) with the same working
therefore, the same title) wouldn't be distinguishable. directory (and therefore, the same title) wouldn't be distinguishable.
## Questions & Patches ## Questions & Patches

@ -76,7 +76,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
} }
SwayrCommand::ExecuteSwaymsgCommand => exec_swaymsg_command(), SwayrCommand::ExecuteSwaymsgCommand => exec_swaymsg_command(),
SwayrCommand::ExecuteSwayrCommand => { SwayrCommand::ExecuteSwayrCommand => {
if let Some(c) = util::select_from_choices( if let Some(c) = util::select_from_menu(
"Select swayr command", "Select swayr command",
&[ &[
SwayrCommand::ExecuteSwaymsgCommand, SwayrCommand::ExecuteSwaymsgCommand,
@ -357,7 +357,7 @@ impl DisplayFormat for SwaymsgCmd<'_> {
pub fn exec_swaymsg_command() { pub fn exec_swaymsg_command() {
let cmds = get_swaymsg_commands(); let cmds = get_swaymsg_commands();
let cmd = util::select_from_choices("Execute swaymsg command", &cmds); let cmd = util::select_from_menu("Execute swaymsg command", &cmds);
if let Some(cmd) = cmd { if let Some(cmd) = cmd {
run_sway_command(&cmd.cmd); run_sway_command(&cmd.cmd);
} }

@ -249,14 +249,14 @@ pub fn select_window<'a>(
prompt: &str, prompt: &str,
windows: &'a [Window], windows: &'a [Window],
) -> Option<&'a Window<'a>> { ) -> Option<&'a Window<'a>> {
util::select_from_choices(prompt, windows) util::select_from_menu(prompt, windows)
} }
pub fn select_workspace<'a>( pub fn select_workspace<'a>(
prompt: &str, prompt: &str,
workspaces: &'a [Workspace], workspaces: &'a [Workspace],
) -> Option<&'a Workspace<'a>> { ) -> Option<&'a Workspace<'a>> {
util::select_from_choices(prompt, workspaces) util::select_from_menu(prompt, workspaces)
} }
pub enum WsOrWin<'a> { pub enum WsOrWin<'a> {
@ -306,7 +306,7 @@ pub fn select_workspace_or_window<'a>(
prompt: &'a str, prompt: &'a str,
ws_or_wins: &'a [WsOrWin<'a>], ws_or_wins: &'a [WsOrWin<'a>],
) -> Option<&'a WsOrWin<'a>> { ) -> Option<&'a WsOrWin<'a>> {
util::select_from_choices(prompt, ws_or_wins) util::select_from_menu(prompt, ws_or_wins)
} }
pub struct Workspace<'a> { pub struct Workspace<'a> {

@ -24,13 +24,27 @@ use std::path::Path;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Config { pub struct Config {
pub launcher: Option<Launcher>, pub menu: Option<Menu>,
pub format: Option<Format>, pub format: Option<Format>,
} }
impl Default for Launcher { #[derive(Debug, Serialize, Deserialize)]
pub struct Menu {
pub executable: Option<String>,
pub args: Option<Vec<String>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Format {
pub window_format: Option<String>,
pub workspace_format: Option<String>,
pub urgency_start: Option<String>,
pub urgency_end: Option<String>,
}
impl Default for Menu {
fn default() -> Self { fn default() -> Self {
Launcher { Menu {
executable: Some("wofi".to_string()), executable: Some("wofi".to_string()),
args: Some(vec![ args: Some(vec![
"--show=dmenu".to_string(), "--show=dmenu".to_string(),
@ -71,26 +85,12 @@ impl Default for Format {
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Config { Config {
launcher: Some(Launcher::default()), menu: Some(Menu::default()),
format: Some(Format::default()), format: Some(Format::default()),
} }
} }
} }
#[derive(Debug, Serialize, Deserialize)]
pub struct Launcher {
pub executable: Option<String>,
pub args: Option<Vec<String>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Format {
pub window_format: Option<String>,
pub workspace_format: Option<String>,
pub urgency_start: Option<String>,
pub urgency_end: Option<String>,
}
fn get_config_file_path() -> Box<Path> { fn get_config_file_path() -> Box<Path> {
let proj_dirs = ProjectDirs::from("", "", "swayr").expect(""); let proj_dirs = ProjectDirs::from("", "", "swayr").expect("");
let config_dir = proj_dirs.config_dir(); let config_dir = proj_dirs.config_dir();

@ -13,7 +13,7 @@
// You should have received a copy of the GNU General Public License along with // You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>. // this program. If not, see <https://www.gnu.org/licenses/>.
//! Utility functions including selection between choices using a launcher. //! Utility functions including selection between choices using a menu program.
use crate::con::DisplayFormat; use crate::con::DisplayFormat;
use crate::config as cfg; use crate::config as cfg;
@ -36,7 +36,7 @@ pub fn get_swayr_socket_path() -> String {
) )
} }
pub fn select_from_choices<'a, 'b, TS>( pub fn select_from_menu<'a, 'b, TS>(
prompt: &'a str, prompt: &'a str,
choices: &'b [TS], choices: &'b [TS],
) -> Option<&'b TS> ) -> Option<&'b TS>
@ -52,41 +52,41 @@ where
map.insert(s, c); map.insert(s, c);
} }
let launcher_default = cfg::Launcher::default(); let menu_default = cfg::Menu::default();
let launcher_exec = cfg let menu_exec = cfg
.launcher .menu
.as_ref() .as_ref()
.and_then(|l| l.executable.as_ref()) .and_then(|l| l.executable.as_ref())
.unwrap_or_else(|| launcher_default.executable.as_ref().unwrap()); .unwrap_or_else(|| menu_default.executable.as_ref().unwrap());
let args: Vec<String> = cfg let args: Vec<String> = cfg
.launcher .menu
.as_ref() .as_ref()
.and_then(|l| l.args.as_ref()) .and_then(|l| l.args.as_ref())
.unwrap_or_else(|| launcher_default.args.as_ref().unwrap()) .unwrap_or_else(|| menu_default.args.as_ref().unwrap())
.iter() .iter()
.map(|a| a.replace("{prompt}", prompt)) .map(|a| a.replace("{prompt}", prompt))
.collect(); .collect();
let mut launcher = proc::Command::new(launcher_exec) let mut menu = proc::Command::new(menu_exec)
.args(args) .args(args)
.stdin(proc::Stdio::piped()) .stdin(proc::Stdio::piped())
.stdout(proc::Stdio::piped()) .stdout(proc::Stdio::piped())
.spawn() .spawn()
.expect(&("Error running ".to_owned() + launcher_exec)); .expect(&("Error running ".to_owned() + menu_exec));
{ {
let stdin = launcher let stdin = menu
.stdin .stdin
.as_mut() .as_mut()
.expect("Failed to open the launcher's stdin"); .expect("Failed to open the menu program's stdin");
let input = strs.join("\n"); let input = strs.join("\n");
println!("Launcher {} input:\n{}", launcher_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 launcher's stdin"); .expect("Failed to write to the menu program's stdin");
} }
let output = launcher.wait_with_output().expect("Failed to read stdout"); let output = menu.wait_with_output().expect("Failed to read stdout");
let choice = String::from_utf8_lossy(&output.stdout); let choice = String::from_utf8_lossy(&output.stdout);
let mut choice = String::from(choice); let mut choice = String::from(choice);
choice.pop(); // Remove trailing \n from choice. choice.pop(); // Remove trailing \n from choice.

Loading…
Cancel
Save