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
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
such as [dmenu](https://tools.suckless.org/dmenu/),
It should be easy to adapt that default config for usage with other menu
programs such as [dmenu](https://tools.suckless.org/dmenu/),
[bemenu](https://github.com/Cloudef/bemenu),
[rofi](https://github.com/davatorium/rofi), a script spawning a terminal with
[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:
```toml
[launcher]
[menu]
executable = 'wofi'
args = [
'--show=dmenu',
@ -118,9 +118,9 @@ urgency_start = '<span background="darkred" foreground="yellow">'
urgency_end = '</span>'
```
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
In the `[menu]` section, you can specify the 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
@ -144,11 +144,11 @@ right now.
* `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.
It is crucial that during selection (using wofi or some other menu program)
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

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

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

@ -24,13 +24,27 @@ use std::path::Path;
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
pub launcher: Option<Launcher>,
pub menu: Option<Menu>,
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 {
Launcher {
Menu {
executable: Some("wofi".to_string()),
args: Some(vec![
"--show=dmenu".to_string(),
@ -71,26 +85,12 @@ impl Default for Format {
impl Default for Config {
fn default() -> Self {
Config {
launcher: Some(Launcher::default()),
menu: Some(Menu::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> {
let proj_dirs = ProjectDirs::from("", "", "swayr").expect("");
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
// 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::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,
choices: &'b [TS],
) -> Option<&'b TS>
@ -52,41 +52,41 @@ where
map.insert(s, c);
}
let launcher_default = cfg::Launcher::default();
let launcher_exec = cfg
.launcher
let menu_default = cfg::Menu::default();
let menu_exec = cfg
.menu
.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
.launcher
.menu
.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()
.map(|a| a.replace("{prompt}", prompt))
.collect();
let mut launcher = proc::Command::new(launcher_exec)
let mut menu = proc::Command::new(menu_exec)
.args(args)
.stdin(proc::Stdio::piped())
.stdout(proc::Stdio::piped())
.spawn()
.expect(&("Error running ".to_owned() + launcher_exec));
.expect(&("Error running ".to_owned() + menu_exec));
{
let stdin = launcher
let stdin = menu
.stdin
.as_mut()
.expect("Failed to open the launcher's stdin");
.expect("Failed to open the menu program's stdin");
let input = strs.join("\n");
println!("Launcher {} input:\n{}", launcher_exec, input);
println!("Menu program {} input:\n{}", menu_exec, input);
stdin
.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 mut choice = String::from(choice);
choice.pop(); // Remove trailing \n from choice.

Loading…
Cancel
Save