From 21cbb5450e15122f5e05c59dae8b6bda87d1d48c Mon Sep 17 00:00:00 2001 From: "N0\\A" Date: Thu, 10 Sep 2026 07:33:57 +0200 Subject: [PATCH] help text --- src/app.rs | 4 ++-- src/capture.rs | 8 ++++---- src/cli.rs | 46 ++++++++++++++++------------------------------ src/config.rs | 4 ++-- src/main.rs | 16 ++++++++-------- src/overlay.rs | 20 ++++++++++---------- src/shm.rs | 2 +- src/sway.rs | 8 ++------ src/target.rs | 10 +++++----- src/text.rs | 8 ++++---- src/theme.rs | 8 ++++---- 11 files changed, 58 insertions(+), 76 deletions(-) diff --git a/src/app.rs b/src/app.rs index 6e1b599..c3f769e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -130,8 +130,8 @@ pub struct App { } /// Counters worth reporting with --verbose. Live capture is easy to get subtly -/// wrong — a starved buffer pool or a clock that never ticks both look like -/// "nothing updates" — so the numbers that distinguish those stay available. +/// wrong - a starved buffer pool or a clock that never ticks both look like +/// "nothing updates" - so the numbers that distinguish those stay available. #[derive(Default)] pub struct Stats { /// Frame callbacks received, i.e. how often the live clock fired. diff --git a/src/capture.rs b/src/capture.rs index 1384811..e7c094e 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -34,8 +34,8 @@ use crate::app::App; use crate::shm; use crate::target::Kind; -/// One capture buffer. `busy` means the compositor still holds it — either it is -/// on screen or a capture is writing into it — so we must not scribble over it. +/// One capture buffer. `busy` means the compositor still holds it - either it is +/// on screen or a capture is writing into it - so we must not scribble over it. pub struct Slot { pub(crate) buffer: WlBuffer, pub(crate) busy: bool, @@ -299,7 +299,7 @@ impl App { continue; } // Nor is there any point refreshing a tile that is scrolled out of - // sight — that is a readback for pixels nobody sees. + // sight - that is a readback for pixels nobody sees. if self.layout.tile(i as i32, self.scroll).is_none() { continue; } @@ -394,7 +394,7 @@ impl Dispatch for App { /// Release is the whole contract: with wl_shm the compositor copies the pixels /// out at commit and hands the buffer straight back, so the slot currently on /// screen is usually free too. (Waiting for it to stop being the displayed slot -/// instead would deadlock — that release never comes twice.) +/// instead would deadlock - that release never comes twice.) impl Dispatch for App { fn event( app: &mut Self, diff --git a/src/cli.rs b/src/cli.rs index 86b1a36..904986b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -10,19 +10,16 @@ use crate::target::Format; use crate::theme::Theme; const HELP: &str = "\ -wl-pick — a live grid of window and display previews, for picking one +wl-rab - a simple alt-tab switcher for sway -usage: wl-pick [options] +usage: wl-tab [options] --config PATH config file [~/.config/wl-pick/config] --format tsv|json|portal how to report the pick [tsv] - --live all|current|none which tiles keep updating live [all] - (displays are always a single snapshot) --fps N cap on live updates per tile per second [12] - --outputs, --no-outputs include whole displays as tiles [no] --labels, --no-labels a label under each thumbnail [yes] --order mru|tree window ordering: mru or layout tree [mru] - --focus, --no-focus focus the picked target in sway directly [no] + --focus, --no-focus focus the picked target directly [no] --font FAMILY label font family [the system monospace font] --font-size PX label size in logical px [13.3] --timeout SECS exit anyway after SECS, in case the keyboard @@ -30,12 +27,6 @@ usage: wl-pick [options] -v, --verbose phase timings, tile list and capture stats -h, --help this -keys: arrows, hjkl or Tab/Shift+Tab move; PgUp/PgDn and Home/End jump; - Enter picks; Escape or q cancels; in Alt+Tab mode, releasing - the modifier (Alt/Super) picks the selection. -mouse: click a tile to pick it, scroll to move. Hovering does not move the - selection, and a click outside a tile does nothing. - The pick goes to stdout and nothing does if you cancel, so exit status is 0 for a pick and 1 for a cancel. Acting on it is the caller's job. @@ -55,9 +46,6 @@ config: max-width = 90ppt # the box the grid may fill max-height = 90ppt - max-columns = 4 # thumbnails are the box divided by these, - max-rows = 4 # so their size never depends on how many - # windows are open; further rows scroll font = monospace # also --font font-size = 13.3 @@ -90,18 +78,7 @@ formats: [screencast] chooser_type=simple - chooser_cmd=wl-pick --format portal - -focusing on sway: - - wl-pick --focus or: - - IFS=$'\\t' read -r type id toplevel app title < <(wl-pick) && - case $type in - window) swaymsg \"[con_id=$id] focus\" ;; - output) swaymsg \"focus output $id\" ;; - esac -"; + chooser_cmd=wl-pick --format portal"; /// What the command line asked for. Every setting is optional so the config file /// can fill the gaps: a flag beats the file, the file beats the default. @@ -316,10 +293,19 @@ mod tests { // With no flag the file decides, and with no file either, the default (outputs: false). assert!(!args(&[]).resolve(&file(false), &display()).outputs); assert!(!args(&[]).resolve(&Config::default(), &display()).outputs); - assert!(args(&["--outputs"]).resolve(&Config::default(), &display()).outputs); - assert_eq!(args(&[]).resolve(&Config::default(), &display()).order, Order::Mru); + assert!( + args(&["--outputs"]) + .resolve(&Config::default(), &display()) + .outputs + ); assert_eq!( - args(&["--order", "tree"]).resolve(&Config::default(), &display()).order, + args(&[]).resolve(&Config::default(), &display()).order, + Order::Mru + ); + assert_eq!( + args(&["--order", "tree"]) + .resolve(&Config::default(), &display()) + .order, Order::Tree ); } diff --git a/src/config.rs b/src/config.rs index 7ee32d6..76bd5ed 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,13 +1,13 @@ //! The config file: `~/.config/wl-pick/config`. //! -//! Flat `key = value` lines with `#` comments — no sections, no nesting, so a +//! Flat `key = value` lines with `#` comments - no sections, no nesting, so a //! TOML parser would be a dependency bought for nothing. Every setting is //! optional; anything absent keeps its default, and a command-line flag beats //! the file. //! //! Sizes take sway's syntax: `600px` is absolute, `70ppt` is 70 percent of the //! display the grid appears on. That matters on a multi-monitor setup, where a -//! pixel size that suits one screen is wrong on the next — percentages are +//! pixel size that suits one screen is wrong on the next - percentages are //! resolved against whichever display the overlay actually maps on, each time //! it runs. diff --git a/src/main.rs b/src/main.rs index ae8ec6c..14bb292 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,13 +11,13 @@ //! is no thumbnail encoding, no scaler, and no full-resolution image in our //! address space. //! -//! - `cli` — flags and help -//! - `sway` — the window list, over sway's IPC socket -//! - `target` — what a tile stands for, and how a pick is reported -//! - `app` — the Wayland client state everything dispatches into -//! - `capture` — capture sessions and their buffers -//! - `overlay` — the layer surface, the drawing, the keyboard -//! - `theme`, `text`, `shm` — look, labels, and shared memory +//! - `cli` - flags and help +//! - `sway` - the window list, over sway's IPC socket +//! - `target` - what a tile stands for, and how a pick is reported +//! - `app` - the Wayland client state everything dispatches into +//! - `capture` - capture sessions and their buffers +//! - `overlay` - the layer surface, the drawing, the keyboard +//! - `theme`, `text`, `shm` - look, labels, and shared memory // `slice::as_chunks` and friends, which clippy suggests in place of // `chunks_exact`, are newer than the toolchain this crate says it supports. @@ -272,7 +272,7 @@ fn run() -> Result> { /// Every wait before the overlay is interactive is bounded, because a /// compositor is entitled to simply never answer. sway does exactly that for a /// capture request on a toplevel another client is already capturing: no frame, -/// no `failed`, no `stopped`, just silence — and an unbounded wait on that is a +/// no `failed`, no `stopped`, just silence - and an unbounded wait on that is a /// picker with no window that has to be killed from another terminal. fn pump_for( conn: &Connection, diff --git a/src/overlay.rs b/src/overlay.rs index 38ff454..ed7a2bb 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -3,7 +3,7 @@ //! //! Scaling is the compositor's job. A tile attaches its capture buffer directly //! and wp_viewporter names the rectangle to fit it into, so nothing here touches -//! a pixel of window content — only the background, selection and labels. +//! a pixel of window content - only the background, selection and labels. use std::error::Error; use std::os::fd::AsFd; @@ -139,7 +139,7 @@ impl App { /// Put every visible tile where the viewport says, and unmap the rest. /// /// Runs again after each scroll, so a tile scrolled off screen gets a null - /// buffer — the way to hide a subsurface — rather than being left behind. + /// buffer - the way to hide a subsurface - rather than being left behind. /// Scaling stays the compositor's job: the capture buffer is attached as it /// is, and wp_viewporter names the rectangle to fit it into. pub fn sync_tiles(&mut self, qh: &QueueHandle) { @@ -164,8 +164,8 @@ impl App { let surface = self.compositor.create_surface(qh, ()); let subsurface = self.subcompositor.get_subsurface(&surface, &parent, qh, ()); let viewport = self.viewporter.get_viewport(&surface, qh, ()); - // Tiles change independently of the chrome — a live frame - // arrives whenever its window does — so they must not wait on a + // Tiles change independently of the chrome - a live frame + // arrives whenever its window does - so they must not wait on a // parent commit. subsurface.set_desync(); // The capture protocol reports the transform the compositor @@ -239,7 +239,7 @@ impl App { let (cw, ch) = (chrome.w, chrome.h); let mut p = chrome.painter(); p.fill(bg); - // The selection fills the whole element box, padding included — the same + // The selection fills the whole element box, padding included - the same // thing rofi's element background does. It can be scrolled out of sight. if let Some(elem) = elem { p.rect(elem, sel_bg); @@ -293,7 +293,7 @@ impl App { } /// The tile under the pointer, if it is over one. A tile's own subsurface - /// answers directly; over the parent surface — padding, labels, gaps — the + /// answers directly; over the parent surface - padding, labels, gaps - the /// layout is asked instead. fn tile_at_pointer(&self) -> Option { let hover = self.hover.as_ref()?; @@ -308,8 +308,8 @@ impl App { }) } - /// Press and release on the same tile picks it. Anywhere else — the margin, - /// a gap, an empty cell of the last row — does nothing at all. + /// Press and release on the same tile picks it. Anywhere else - the margin, + /// a gap, an empty cell of the last row - does nothing at all. fn click(&mut self, pressed: bool) { if pressed { self.pressed = self.tile_at_pointer(); @@ -523,7 +523,7 @@ impl Dispatch for App { wl_keyboard::Event::Enter { keys, .. } => app.keyboard_enter(keys, qh), wl_keyboard::Event::Leave { .. } => { app.focused = false; - // Clear any held repeat — we no longer have the keyboard. + // Clear any held repeat - we no longer have the keyboard. app.repeat_key = None; app.repeat_next = None; } @@ -532,7 +532,7 @@ impl Dispatch for App { } } -/// Hovering does not move the selection — that belongs to the keyboard — so the +/// Hovering does not move the selection - that belongs to the keyboard - so the /// pointer only tracks where it is and what it clicked. Scrolling is a /// deliberate gesture, so that does move the selection. impl Dispatch for App { diff --git a/src/shm.rs b/src/shm.rs index f34f639..abe5435 100644 --- a/src/shm.rs +++ b/src/shm.rs @@ -3,7 +3,7 @@ //! //! Capture buffers deliberately never get mapped into this process. The //! compositor writes the window pixels and then samples them again for display, -//! so we only need the fd — mapping them would fault ~7 MB per window into our +//! so we only need the fd - mapping them would fault ~7 MB per window into our //! address space for nothing. use std::fs::File; diff --git a/src/sway.rs b/src/sway.rs index 1b65bf2..f37cfdd 100644 --- a/src/sway.rs +++ b/src/sway.rs @@ -186,11 +186,7 @@ pub fn windows(conn: &mut Connection, order: Order) -> Result, swayi return (1, idx, 0); } } - if t.visible { - (2, 0, 0) - } else { - (3, 0, 0) - } + if t.visible { (2, 0, 0) } else { (3, 0, 0) } }); } Ok(out) @@ -228,7 +224,7 @@ fn collect_tree(node: &Node, out: &mut Vec) { /// One active display: what the overlay needs to size itself against. /// /// The overlay maps on the focused display, so percentages and the buffer scale -/// are resolved against *that* one — on a mixed-DPI, mixed-size setup the +/// are resolved against *that* one - on a mixed-DPI, mixed-size setup the /// numbers differ per monitor, and taking the largest of everything would be /// wrong on all but one. #[derive(Clone, Debug)] diff --git a/src/target.rs b/src/target.rs index 23d6d15..3320085 100644 --- a/src/target.rs +++ b/src/target.rs @@ -1,7 +1,7 @@ //! What a tile stands for: a window, or a whole display. //! -//! Both are capture sources as far as the protocol is concerned — one from a -//! foreign-toplevel handle, one from a `wl_output` — so the grid treats them +//! Both are capture sources as far as the protocol is concerned - one from a +//! foreign-toplevel handle, one from a `wl_output` - so the grid treats them //! alike and only differs in how it labels them and what picking one does. use std::fmt; @@ -110,8 +110,8 @@ impl Target { /// `IFS=$'\t' read -r type id toplevel app title`. /// /// Both identifiers are there because both get used: sway scripting acts on - /// the con_id (`[con_id=N] focus`), while tools that capture a window — - /// grim -T, the desktop portal — want the foreign-toplevel identifier. + /// the con_id (`[con_id=N] focus`), while tools that capture a window - + /// grim -T, the desktop portal - want the foreign-toplevel identifier. pub fn tsv(&self) -> String { format!( "{}\t{}\t{}\t{}\t{}", @@ -162,7 +162,7 @@ impl Target { /// What xdg-desktop-portal-wlr's `simple` chooser accepts: `Monitor: NAME` /// or `Window: `. A window the compositor never - /// gave an identifier for cannot be named this way, hence the Option — and + /// gave an identifier for cannot be named this way, hence the Option - and /// an empty stdout is exactly how that chooser says "declined". pub fn portal(&self) -> Option { match self.kind { diff --git a/src/text.rs b/src/text.rs index a97f8e1..a666581 100644 --- a/src/text.rs +++ b/src/text.rs @@ -6,7 +6,7 @@ //! and joined after them: by the time anything is drawn, every label is shaped //! and its glyphs are already in the cache, and painting one costs ~0.1ms. //! -//! Sizes here are physical pixels — the caller scales logical units first, +//! Sizes here are physical pixels - the caller scales logical units first, //! because the chrome buffer it paints into is physical too. use std::thread::{self, JoinHandle}; @@ -54,7 +54,7 @@ const MONO_CANDIDATES: &[&str] = &[ /// Load the smallest font database that can render `family`. /// -/// `FontSystem::new()` scans every system font, which costs ~37ms — most of the +/// `FontSystem::new()` scans every system font, which costs ~37ms - most of the /// startup budget. A user's own font directories are tiny by comparison, so try /// those first and only pay for the full scan when the family really isn't there /// (which is also what makes an unknown family fall back gracefully). The @@ -87,7 +87,7 @@ fn has_family(db: &fontdb::Database, family: &str) -> bool { /// Turn the generic default into a real family name. /// /// cosmic-text's own generic resolves through fontdb's built-in preference -/// ("FreeMono"), which is usually absent and then lands on an arbitrary face — so +/// ("FreeMono"), which is usually absent and then lands on an arbitrary face - so /// ask fontconfig instead, since that is what the rest of the desktop uses. A /// named family passes through untouched; if it turns out to be missing, /// cosmic-text falls back on its own. @@ -145,7 +145,7 @@ fn build(texts: Vec, family: String, font_px: f32, line_h: f32, box_w: f } } -/// Shorten `text` until it fits in `box_w`, ending with an ellipsis — window +/// Shorten `text` until it fits in `box_w`, ending with an ellipsis - window /// titles are arbitrarily long, and rofi ellipsised them too. fn ellipsize( fs: &mut FontSystem, diff --git a/src/theme.rs b/src/theme.rs index 4e92fc2..c76dfdb 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -7,7 +7,7 @@ //! Sizing works from caps rather than from a thumbnail size. The config gives a //! box the grid may fill and a column and row limit; a thumbnail is that box //! divided by those limits. So a thumbnail is the same size whether one window -//! is open or thirty — the overlay hugs whatever is there, and rows past the +//! is open or thirty - the overlay hugs whatever is there, and rows past the //! limit scroll. /// 0xAARRGGBB, premultiplied (everything here is opaque). @@ -24,7 +24,7 @@ pub struct Theme { pub border_px: i32, /// The box the grid may not exceed, in logical px. Thumbnails are sized to /// divide it by the column and row caps below, so a thumbnail is the same - /// size whether one window is open or thirty — only the window around them + /// size whether one window is open or thirty - only the window around them /// shrinks to hug what is there. pub max_w: i32, pub max_h: i32, @@ -108,8 +108,8 @@ impl Layout { /// it does not change with how many windows are open: one window gets a /// normal thumbnail in a small overlay, thirty get the same thumbnail and /// scroll. Columns follow ceil(sqrt(n)) up to the cap, so a handful of - /// windows makes a tidy grid rather than one long row — the rule rofigrid - /// used — and the overlay hugs whatever is there. + /// windows makes a tidy grid rather than one long row - the rule rofigrid + /// used - and the overlay hugs whatever is there. /// Lay out `n` tiles in a single row for a display of the given logical size. /// /// The overlay and the window previews resize automatically to fit all `n`