From a5ae9785ed12cd88489b06e4cdce3391d0634452 Mon Sep 17 00:00:00 2001 From: Alexander Mohr Date: Wed, 20 Aug 2025 22:06:09 +0200 Subject: [PATCH] add text output mode solves #104 --- README.md | 3 +- examples/worf-warden/src/main.rs | 14 ++++++-- worf/src/lib/config.rs | 56 +++++++++++++++++++++++++++----- worf/src/lib/modes/emoji.rs | 14 ++++++-- worf/src/lib/modes/math.rs | 24 ++++++++++++-- worf/src/main.rs | 7 ++-- 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index d857c97..763a3f3 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ The command line options have precedence over the configuration file. | matching | MatchMethod | Contains | Defines the matching method | | insensitive | bool | true | Control if search is case-insensitive | | parse_search | bool | None | Parse search option | -| location | [Anchor] | None | Set where the window is displayed | +| location | Anchor | None | Set where the window is displayed | | no_actions | bool | false | If true, sub actions will be disabled | | lines | int | None | Number of lines to show | | lines_additional_space | int | 0 | Additional space for lines | @@ -191,6 +191,7 @@ The command line options have precedence over the configuration file. | submit_with_expand | bool | true | Allow submit with expand key | | auto_select_on_search | bool | false | Auto select when only 1 choice left | | rollover | bool | true | Jump to first/last entry at end/start | +| text_output_mode | TextOutputMode | Clipboard | Output for text modes (i.e. math and emoji) | ### Enum Values - **MatchMethod**: Fuzzy, Contains, MultiContains, None diff --git a/examples/worf-warden/src/main.rs b/examples/worf-warden/src/main.rs index 45af06e..ce947a7 100644 --- a/examples/worf-warden/src/main.rs +++ b/examples/worf-warden/src/main.rs @@ -10,7 +10,7 @@ use std::{ use clap::Parser; use serde::{Deserialize, Serialize}; use worf::{ - config::{self, Config, CustomKeyHintLocation, Key}, + config::{self, Config, CustomKeyHintLocation, Key, TextOutputMode}, desktop::{copy_to_clipboard, spawn_fork}, gui::{ self, CustomKeyHint, CustomKeys, ExpandMode, ItemProvider, KeyBinding, MenuItem, Modifier, @@ -416,8 +416,16 @@ fn show( } } else { let pw = rbw_get_password(id, true)?; - if let Err(e) = copy_to_clipboard(pw, None) { - log::error!("failed to copy to clipboard: {e}"); + match config.read().unwrap().text_output_mode() { + TextOutputMode::Clipboard => { + if let Err(e) = copy_to_clipboard(pw, None) { + log::error!("failed to copy to clipboard: {e}"); + } + } + TextOutputMode::StandardOutput => { + println!("{pw}"); + } + TextOutputMode::None => {} } } Ok(()) diff --git a/worf/src/lib/config.rs b/worf/src/lib/config.rs index 06d3ba5..f0211a5 100644 --- a/worf/src/lib/config.rs +++ b/worf/src/lib/config.rs @@ -70,15 +70,22 @@ pub enum Layer { Overlay, } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum TextOutputMode { + None, + Clipboard, + StandardOutput, +} + impl FromStr for Layer { type Err = String; fn from_str(s: &str) -> Result { - match s { - "Background" => Ok(Layer::Background), - "Bottom" => Ok(Layer::Bottom), - "Top" => Ok(Layer::Top), - "Overlay" => Ok(Layer::Overlay), + match s.trim().to_lowercase().as_str() { + "background" => Ok(Layer::Background), + "bottom" => Ok(Layer::Bottom), + "top" => Ok(Layer::Top), + "overlay" => Ok(Layer::Overlay), _ => Err(format!("{s} is not a valid layer.")), } } @@ -88,7 +95,7 @@ impl FromStr for Anchor { type Err = String; fn from_str(s: &str) -> Result { - match s.trim() { + match s.trim().to_lowercase().as_str() { "top" => Ok(Anchor::Top), "left" => Ok(Anchor::Left), "bottom" => Ok(Anchor::Bottom), @@ -102,7 +109,7 @@ impl FromStr for WrapMode { type Err = Error; fn from_str(s: &str) -> Result { - match s { + match s.trim().to_lowercase().as_str() { "none" => Ok(WrapMode::None), "word" => Ok(WrapMode::Word), "inherit" => Ok(WrapMode::Inherit), @@ -117,7 +124,7 @@ impl FromStr for SortOrder { type Err = Error; fn from_str(s: &str) -> Result { - match s { + match s.trim().to_lowercase().as_str() { "alphabetical" => Ok(SortOrder::Alphabetical), "default" => Ok(SortOrder::Default), _ => Err(Error::InvalidArgument( @@ -131,7 +138,7 @@ impl FromStr for KeyDetectionType { type Err = Error; fn from_str(s: &str) -> Result { - match s { + match s.trim().to_lowercase().as_str() { "value" => Ok(KeyDetectionType::Value), "code" => Ok(KeyDetectionType::Code), _ => Err(Error::InvalidArgument( @@ -141,6 +148,19 @@ impl FromStr for KeyDetectionType { } } +impl FromStr for TextOutputMode { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.trim().to_lowercase().as_str() { + "clipboard" => Ok(TextOutputMode::Clipboard), + "stdout" | "standardoutput" => Ok(TextOutputMode::StandardOutput), + "none" => Ok(TextOutputMode::None), + _ => Err(format!("{s} is not a valid layer.")), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] pub enum Key { None, @@ -632,7 +652,18 @@ pub struct Config { /// Jump to the first/last entry when at the end/start and down/up is pressed /// Defaults to true + #[clap(long = "rollover")] rollover: Option, + + /// For text modes, defines which output is used. + /// This is per default used in math and emoji mode. + /// Defaults to `Clipboard` + /// For emoji mode, setting this to None will disable the text output + /// so the mode isn't too useful anymore. + /// For math mode, setting this to None will provide no output but keep running + /// math mode in a loop. Other modes will exit and provide results on selected output. + #[clap(long = "text-output-mode")] + text_output_mode: Option, } impl Config { @@ -927,6 +958,13 @@ impl Config { pub fn rollover(&self) -> bool { self.rollover.unwrap_or(true) } + + #[must_use] + pub fn text_output_mode(&self) -> TextOutputMode { + self.text_output_mode + .clone() + .unwrap_or(TextOutputMode::Clipboard) + } } fn default_false() -> bool { diff --git a/worf/src/lib/modes/emoji.rs b/worf/src/lib/modes/emoji.rs index 69ab940..183c5ff 100644 --- a/worf/src/lib/modes/emoji.rs +++ b/worf/src/lib/modes/emoji.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex, RwLock}; use crate::{ Error, - config::{Config, SortOrder}, + config::{Config, SortOrder, TextOutputMode}, desktop::copy_to_clipboard, gui::{self, ExpandMode, ItemProvider, MenuItem, ProviderData}, }; @@ -75,6 +75,16 @@ pub fn show(config: &Arc>) -> Result<(), Error> { let selection_result = gui::show(config, provider, None, None, ExpandMode::Verbatim, None)?; match selection_result.menu.data { None => Err(Error::MissingAction), - Some(action) => copy_to_clipboard(action, None), + Some(action) => match config.read().unwrap().text_output_mode() { + TextOutputMode::Clipboard => { + copy_to_clipboard(action, None)?; + Ok(()) + } + TextOutputMode::StandardOutput => { + println!("{action}"); + Ok(()) + } + TextOutputMode::None => Ok(()), + }, } } diff --git a/worf/src/lib/modes/math.rs b/worf/src/lib/modes/math.rs index 480f21f..cda95b7 100644 --- a/worf/src/lib/modes/math.rs +++ b/worf/src/lib/modes/math.rs @@ -6,7 +6,8 @@ use std::{ use regex::Regex; use crate::{ - config::Config, + Error, + config::{Config, TextOutputMode}, gui::{ self, ArcFactory, ArcProvider, DefaultItemFactory, ExpandMode, ItemProvider, MenuItem, ProviderData, @@ -346,7 +347,11 @@ fn calc(input: &str) -> String { /// Shows the math mode /// # Panics /// When failing to unwrap the arc lock -pub fn show(config: &Arc>) { +/// +/// # Errors +/// Forwards the errors from `crate::desktop::copy_to_clipboard` +/// if the text output mode is set to `Clipboard`. +pub fn show(config: &Arc>) -> Result<(), Error> { let mut calc: Vec> = vec![]; let provider = Arc::new(Mutex::new(MathProvider::new(()))); let factory: ArcFactory<()> = Arc::new(Mutex::new(DefaultItemFactory::new())); @@ -361,11 +366,24 @@ pub fn show(config: &Arc>) { ExpandMode::Verbatim, None, ); + if let Ok(mi) = selection_result { - calc.push(mi.menu); + match config.read().unwrap().text_output_mode() { + TextOutputMode::Clipboard => { + crate::desktop::copy_to_clipboard(mi.menu.label, None)?; + break; + } + TextOutputMode::StandardOutput => { + println!("{}", mi.menu.label); + break; + } + TextOutputMode::None => calc.push(mi.menu), + } } else { log::error!("No item selected"); break; } } + + Ok(()) } diff --git a/worf/src/main.rs b/worf/src/main.rs index d9a19d1..f01723b 100644 --- a/worf/src/main.rs +++ b/worf/src/main.rs @@ -44,7 +44,7 @@ pub enum Mode { )] struct MainConfig { /// Defines the mode worf is running in - #[clap(long = "show")] + #[clap(long = "show", alias = "mode")] show: Mode, #[command(flatten)] @@ -124,10 +124,7 @@ fn main() { Mode::Drun => modes::drun::show(&cfg_arc), Mode::Dmenu => modes::dmenu::show(&cfg_arc), Mode::File => modes::file::show(&cfg_arc), - Mode::Math => { - modes::math::show(&cfg_arc); - Ok(()) - } + Mode::Math => modes::math::show(&cfg_arc), Mode::Ssh => modes::ssh::show(&cfg_arc), Mode::Emoji => modes::emoji::show(&cfg_arc), Mode::Auto => modes::auto::show(&cfg_arc),