Files
wayscriber/src/app/usage.rs
T
devmobasa fcbc437816 feat(cli): choose and list the interface language from the command line
`--language CODE` sets the interface language for one run of --active,
--freeze, --daemon or --about without changing config.toml. It accepts
the spellings `[ui] language` does and takes precedence over both
WAYSCRIBER_LANGUAGE and the config. A daemon started with it gives it to
the About windows it opens, and to its overlays as an optional
environment input that an older overlay ignores. The process broker
strips that input from every other helper, so a configurator opened from
an overlay keeps previewing its own Language row. With --daemon-toggle or
an overlay action the flag is an error, since a running daemon's
overlays cannot be changed from outside.

`--list-languages` prints each language's code and name, the configured
language, and the language in effect with the setting that decided it.

Languages now carry their native and English names, and the
configurator's Language row takes its labels from them. The help text,
README, CONFIG.md, I18N.md and config.example.toml describe both options.
2026-10-16 18:42:33 +02:00

247 lines
9.7 KiB
Rust

use std::collections::HashMap;
use crate::config::{Action, KeybindingsConfig, Shortcut, action_display_label, action_label};
use crate::label_format::format_binding_labels;
fn default_action_bindings() -> HashMap<Action, Vec<Shortcut>> {
match KeybindingsConfig::default().build_action_bindings() {
Ok(bindings) => bindings,
Err(err) => {
log::warn!("Failed to build default keybindings: {}", err);
HashMap::new()
}
}
}
/// Bindings as the config file spells them.
///
/// The terminal control listing is what a user copies into `config.toml`, so it
/// stays on the canonical [`std::fmt::Display`] form: raw key names
/// (`ArrowLeft`), and `>` rather than `then` between sequence steps. The glyph
/// labels ([`Shortcut::display_label`]) belong to the on-screen surfaces, which
/// can render a glyph the terminal has no font for.
fn action_binding_labels(bindings: &HashMap<Action, Vec<Shortcut>>, action: Action) -> Vec<String> {
bindings
.get(&action)
.map(|list| list.iter().map(Shortcut::to_string).collect())
.unwrap_or_default()
}
fn action_binding_label(bindings: &HashMap<Action, Vec<Shortcut>>, action: Action) -> String {
format_binding_labels(&action_binding_labels(bindings, action))
}
fn action_primary_binding_label(
bindings: &HashMap<Action, Vec<Shortcut>>,
action: Action,
) -> Option<String> {
bindings
.get(&action)
.and_then(|list| list.first())
.map(Shortcut::to_string)
}
fn color_binding_labels(bindings: &HashMap<Action, Vec<Shortcut>>) -> String {
let colors = [
Action::SetColorRed,
Action::SetColorGreen,
Action::SetColorBlue,
Action::SetColorYellow,
Action::SetColorOrange,
Action::SetColorPink,
Action::SetColorWhite,
Action::SetColorBlack,
];
let mut parts = Vec::new();
for action in colors {
let label = action_label(action);
if let Some(binding) = action_primary_binding_label(bindings, action) {
parts.push(format!("{binding} ({label})"));
} else {
parts.push(label.to_string());
}
}
parts.join(", ")
}
pub(crate) fn log_overlay_controls(freeze: bool) {
log::info!("Starting Wayland overlay...");
log::info!("Starting annotation overlay...");
log::info!("Controls:");
let bindings = default_action_bindings();
log_drawing_controls(&bindings);
log_canvas_controls(&bindings);
log_ui_controls(&bindings);
if freeze {
log::info!("Starting frozen mode (freeze-on-start requested)");
}
log::info!("");
}
fn log_drawing_controls(bindings: &HashMap<Action, Vec<Shortcut>>) {
log::info!(
" - {}: Just drag",
action_display_label(Action::SelectPenTool)
);
log::info!(
" - {}: Hold Shift + drag",
action_display_label(Action::SelectLineTool)
);
log::info!(
" - {}: Hold Ctrl + drag",
action_display_label(Action::SelectRectTool)
);
log::info!(
" - {}: Hold Tab + drag",
action_display_label(Action::SelectEllipseTool)
);
log::info!(
" - {}: Hold Ctrl+Shift + drag",
action_display_label(Action::SelectArrowTool)
);
log::info!(
" - {}: {}, click to position, type, press Enter",
action_display_label(Action::EnterTextMode),
action_binding_label(bindings, Action::EnterTextMode)
);
log::info!(" - Colors: {}", color_binding_labels(bindings));
}
fn log_canvas_controls(bindings: &HashMap<Action, Vec<Shortcut>>) {
log::info!(
" - {} / {}: {} / {}",
action_display_label(Action::Undo),
action_display_label(Action::Redo),
action_binding_label(bindings, Action::Undo),
action_binding_label(bindings, Action::Redo)
);
log::info!(
" - {}: {}",
action_display_label(Action::ClearCanvas),
action_binding_label(bindings, Action::ClearCanvas)
);
log::info!(
" - {}: {} or scroll up",
action_display_label(Action::IncreaseThickness),
action_binding_label(bindings, Action::IncreaseThickness)
);
log::info!(
" - {}: {} or scroll down",
action_display_label(Action::DecreaseThickness),
action_binding_label(bindings, Action::DecreaseThickness)
);
log::info!(
" - {}: {} (toggle frozen background)",
action_display_label(Action::ToggleFrozenMode),
action_binding_label(bindings, Action::ToggleFrozenMode)
);
log::info!(
" - {} / {}: {} / {} (Ctrl + scroll)",
action_display_label(Action::ZoomIn),
action_display_label(Action::ZoomOut),
action_binding_label(bindings, Action::ZoomIn),
action_binding_label(bindings, Action::ZoomOut)
);
log::info!(
" - {}: {} • {}: {} • Pan view: middle drag/arrow keys",
action_display_label(Action::ResetZoom),
action_binding_label(bindings, Action::ResetZoom),
action_display_label(Action::ToggleZoomLock),
action_binding_label(bindings, Action::ToggleZoomLock)
);
}
fn log_ui_controls(bindings: &HashMap<Action, Vec<Shortcut>>) {
log::info!(
" - {}: Right Click or {}",
action_display_label(Action::OpenContextMenu),
action_binding_label(bindings, Action::OpenContextMenu)
);
log::info!(
" - {}: {} • {}: {} • {}: {} • {}: {} • {}: {}",
action_display_label(Action::ToggleHelp),
action_binding_label(bindings, Action::ToggleHelp),
action_display_label(Action::ToggleToolbar),
action_binding_label(bindings, Action::ToggleToolbar),
action_display_label(Action::TogglePresenterMode),
action_binding_label(bindings, Action::TogglePresenterMode),
action_display_label(Action::OpenConfigurator),
action_binding_label(bindings, Action::OpenConfigurator),
action_display_label(Action::ToggleStatusBar),
action_binding_label(bindings, Action::ToggleStatusBar)
);
log::info!(
" - {}: {}",
action_display_label(Action::Exit),
action_binding_label(bindings, Action::Exit)
);
}
pub(crate) fn print_usage() {
println!("wayscriber: Screen annotation tool for Wayland compositors");
println!();
println!("Usage:");
println!(" wayscriber -d, --daemon [--session-file PATH] Run as background daemon");
println!(
" wayscriber --daemon --freeze-on-show Run daemon with frozen activation by default"
);
println!(" wayscriber --daemon-toggle [--freeze] [--mode MODE] [--session-file PATH]");
println!(" Toggle running daemon with launch args");
println!(
" [--exit-after-capture|--no-exit-after-capture] [--resume-session|--no-resume-session]"
);
println!(
" wayscriber --light-toggle | --light-draw-toggle Control light passthrough through the daemon"
);
println!(
" wayscriber --light-draw-on | --light-draw-off Press/release controls for hold-to-draw"
);
println!(" wayscriber -a, --active Show overlay immediately (one-shot mode)");
println!(" wayscriber --freeze Start overlay already frozen");
println!(" wayscriber --active --session-file PATH Use a named session file");
println!(" wayscriber --freeze --session-file PATH Use a named session file");
println!(" wayscriber --session-info [--session-file PATH] Inspect saved session data");
println!(
" wayscriber --rename-session NAME --session-file PATH Rename a catalog display name"
);
println!(" wayscriber --clear-session [--session-file PATH] Remove saved session data");
println!(
" wayscriber --clear-tool-state [--session-file PATH] Reset saved tool defaults only"
);
println!(
" wayscriber --exit-after-capture Exit overlay after a capture completes (override auto clipboard exit)"
);
println!(
" wayscriber --no-exit-after-capture Keep overlay open (disable auto clipboard exit)"
);
println!(" wayscriber --no-tray Skip system tray (headless daemon)");
println!(" wayscriber --about Show the About window");
println!(" wayscriber --check-update Check wayscriber.com for a newer release");
println!(" wayscriber --list-languages List interface languages and the one in effect");
println!(
" wayscriber --active --language CODE Use an interface language for this run (also --freeze, --daemon, --about)"
);
println!(
" wayscriber --resume-session Force session resume on (all boards/history/tool state)"
);
println!(" wayscriber --no-resume-session Disable session resume for this run");
println!(" wayscriber -h, --help Show help");
println!();
println!("Daemon mode (recommended). Example Hyprland setup:");
println!(" 1. Run: wayscriber --daemon");
println!(" Optional: wayscriber --daemon --freeze-on-show");
println!(" 2. Add to Hyprland config:");
println!(" exec-once = wayscriber --daemon");
println!(" bind = SUPER, D, exec, wayscriber --daemon-toggle");
println!(" bind = SUPER SHIFT, D, exec, wayscriber --daemon-toggle --freeze");
println!(" bind = SUPER ALT, L, exec, wayscriber --light-toggle");
println!(" bind = SUPER ALT, D, exec, wayscriber --light-draw-toggle");
println!(" bind = SUPER ALT, F, exec, wayscriber --light-draw-on");
println!(" bindr = SUPER ALT, F, exec, wayscriber --light-draw-off");
println!(" 3. Press your bound shortcut (e.g. Super+D) to toggle overlay on/off");
println!();
println!("Requirements:");
println!(" - Wayland compositor (Hyprland, Sway, etc.)");
println!(" - wlr-layer-shell protocol support");
}