diff --git a/assets/shell-completion/bash b/assets/shell-completion/bash index 9e0a9b9ed..fc90c86c0 100644 --- a/assets/shell-completion/bash +++ b/assets/shell-completion/bash @@ -1451,7 +1451,7 @@ _wezterm() { return 0 ;; wezterm__imgcat) - opts="-h --width --height --no-preserve-aspect-ratio --help [FILE_NAME]" + opts="-h --width --height --no-preserve-aspect-ratio --position --no-move-cursor --hold --help [FILE_NAME]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1465,6 +1465,10 @@ _wezterm() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --position) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; *) COMPREPLY=() ;; diff --git a/assets/shell-completion/fish b/assets/shell-completion/fish index d094a71a5..6da8859ad 100644 --- a/assets/shell-completion/fish +++ b/assets/shell-completion/fish @@ -160,7 +160,10 @@ complete -c wezterm -n "__fish_seen_subcommand_from cli; and __fish_seen_subcomm complete -c wezterm -n "__fish_seen_subcommand_from cli; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from list; and not __fish_seen_subcommand_from list-clients; and not __fish_seen_subcommand_from proxy; and not __fish_seen_subcommand_from tlscreds; and not __fish_seen_subcommand_from move-pane-to-new-tab; and not __fish_seen_subcommand_from split-pane; and not __fish_seen_subcommand_from spawn; and not __fish_seen_subcommand_from send-text; and not __fish_seen_subcommand_from get-text; and not __fish_seen_subcommand_from activate-pane-direction; and not __fish_seen_subcommand_from get-pane-direction; and not __fish_seen_subcommand_from kill-pane; and not __fish_seen_subcommand_from activate-pane; and not __fish_seen_subcommand_from adjust-pane-size; and not __fish_seen_subcommand_from activate-tab; and not __fish_seen_subcommand_from set-tab-title; and not __fish_seen_subcommand_from set-window-title; and not __fish_seen_subcommand_from rename-workspace; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l width -d 'Specify the display width; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value `N` to specify the number of cells, or `Npx` to specify the number of pixels, or `N%` to size relative to the terminal width' -r complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l height -d 'Specify the display height; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value `N` to specify the number of cells, or `Npx` to specify the number of pixels, or `N%` to size relative to the terminal height' -r +complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l position -d 'Set the cursor position prior to displaying the image. The default is to use the current cursor position. Coordinates are expressed in cells with 0,0 being the top left cell position' -r complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-preserve-aspect-ratio -d 'Do not respect the aspect ratio. The default is to respect the aspect ratio' +complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-move-cursor -d 'Do not move the cursor after displaying the image. Note that when used like this from the shell, there is a very high chance that shell prompt will overwrite the image; you may wish to also use `--hold` in that case' +complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l hold -d 'Wait for enter to be pressed after displaying the image' complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -s h -l help -d 'Print help' complete -c wezterm -n "__fish_seen_subcommand_from set-working-directory" -s h -l help -d 'Print help' complete -c wezterm -n "__fish_seen_subcommand_from record" -s h -l help -d 'Print help' diff --git a/assets/shell-completion/zsh b/assets/shell-completion/zsh index b927ee526..dba29e12b 100644 --- a/assets/shell-completion/zsh +++ b/assets/shell-completion/zsh @@ -381,7 +381,10 @@ esac _arguments "${_arguments_options[@]}" \ '--width=[Specify the display width; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value \`N\` to specify the number of cells, or \`Npx\` to specify the number of pixels, or \`N%\` to size relative to the terminal width]:WIDTH: ' \ '--height=[Specify the display height; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value \`N\` to specify the number of cells, or \`Npx\` to specify the number of pixels, or \`N%\` to size relative to the terminal height]:HEIGHT: ' \ +'--position=[Set the cursor position prior to displaying the image. The default is to use the current cursor position. Coordinates are expressed in cells with 0,0 being the top left cell position]:POSITION: ' \ '--no-preserve-aspect-ratio[Do not respect the aspect ratio. The default is to respect the aspect ratio]' \ +'--no-move-cursor[Do not move the cursor after displaying the image. Note that when used like this from the shell, there is a very high chance that shell prompt will overwrite the image; you may wish to also use \`--hold\` in that case]' \ +'--hold[Wait for enter to be pressed after displaying the image]' \ '-h[Print help]' \ '--help[Print help]' \ '::file_name -- The name of the image file to be displayed. If omitted, will attempt to read it from stdin:_files' \ diff --git a/docs/changelog.md b/docs/changelog.md index e74f1c0b0..e5e9d3f83 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -25,6 +25,9 @@ As features stabilize some brief notes about them will accumulate here. * The default for [front_end](config/lua/config/front_end.md) is now `WebGpu`. #### New +* [wezterm imgcat](cli/imgcat.md) now has `--position`, `--no-move-cursor` and + `--hold` options. #3716 + #### Fixed * Command Palette was using now-invalid Nerd Font 2.0 symbols for macOS keyboard shortcuts. #3988 diff --git a/docs/examples/cmd-synopsis-wezterm--help.txt b/docs/examples/cmd-synopsis-wezterm--help.txt index 55b776e5a..190b77049 100644 --- a/docs/examples/cmd-synopsis-wezterm--help.txt +++ b/docs/examples/cmd-synopsis-wezterm--help.txt @@ -1,4 +1,3 @@ - Wez's Terminal Emulator http://github.com/wez/wezterm diff --git a/docs/examples/cmd-synopsis-wezterm-cli-activate-pane--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-activate-pane--help.txt index 14e2a41bb..ec4252690 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-activate-pane--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-activate-pane--help.txt @@ -1,4 +1,3 @@ - Activate (focus) a pane Usage: wezterm cli activate-pane [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-activate-pane-direction--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-activate-pane-direction--help.txt index ecf1f0471..57e69ea41 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-activate-pane-direction--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-activate-pane-direction--help.txt @@ -1,4 +1,3 @@ - Activate an adjacent pane in the specified direction Usage: wezterm cli activate-pane-direction [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-activate-tab--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-activate-tab--help.txt index b20fb45b7..b9c1021b6 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-activate-tab--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-activate-tab--help.txt @@ -1,4 +1,3 @@ - Activate a tab Usage: wezterm cli activate-tab [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-adjust-pane-size--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-adjust-pane-size--help.txt index a2e2832cd..9f48c789e 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-adjust-pane-size--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-adjust-pane-size--help.txt @@ -1,4 +1,3 @@ - Adjust the size of a pane directionally Usage: wezterm cli adjust-pane-size [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-get-pane-direction--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-get-pane-direction--help.txt index 097a66c17..1d257e3be 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-get-pane-direction--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-get-pane-direction--help.txt @@ -1,4 +1,3 @@ - Determine the adjacent pane in the specified direction. Prints the pane id in that direction, or nothing if there is no pane in that diff --git a/docs/examples/cmd-synopsis-wezterm-cli-get-text--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-get-text--help.txt index c05005bbe..a57e56f55 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-get-text--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-get-text--help.txt @@ -1,4 +1,3 @@ - Retrieves the textual content of a pane and output it to stdout Usage: wezterm cli get-text [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-kill-pane--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-kill-pane--help.txt index 44bef7852..dc768222c 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-kill-pane--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-kill-pane--help.txt @@ -1,4 +1,3 @@ - Kill a pane Usage: wezterm cli kill-pane [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-list--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-list--help.txt index e08b18166..8682bd2ca 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-list--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-list--help.txt @@ -1,4 +1,3 @@ - list windows, tabs and panes Usage: wezterm cli list [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-list-clients--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-list-clients--help.txt index 173b81ab3..3202f36d8 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-list-clients--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-list-clients--help.txt @@ -1,4 +1,3 @@ - list clients Usage: wezterm cli list-clients [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-move-pane-to-new-tab--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-move-pane-to-new-tab--help.txt index b0f0d5c8b..7d8f5251c 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-move-pane-to-new-tab--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-move-pane-to-new-tab--help.txt @@ -1,4 +1,3 @@ - Move a pane into a new tab Usage: wezterm cli move-pane-to-new-tab [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-rename-workspace--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-rename-workspace--help.txt index d5fba3565..142beba67 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-rename-workspace--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-rename-workspace--help.txt @@ -1,4 +1,3 @@ - Rename a workspace Usage: wezterm cli rename-workspace [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-send-text--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-send-text--help.txt index 477526578..cb62d3693 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-send-text--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-send-text--help.txt @@ -1,4 +1,3 @@ - Send text to a pane as though it were pasted. If bracketed paste mode is enabled in the pane, then the text will be sent as a bracketed paste diff --git a/docs/examples/cmd-synopsis-wezterm-cli-set-tab-title--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-set-tab-title--help.txt index b3676a024..4e2574526 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-set-tab-title--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-set-tab-title--help.txt @@ -1,4 +1,3 @@ - Change the title of a tab Usage: wezterm cli set-tab-title [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-cli-set-window-title--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-set-window-title--help.txt index 25cd1ac80..6b60b3446 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-set-window-title--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-set-window-title--help.txt @@ -1,4 +1,3 @@ - Change the title of a window Usage: wezterm cli set-window-title [OPTIONS] <TITLE> diff --git a/docs/examples/cmd-synopsis-wezterm-cli-spawn--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-spawn--help.txt index 3c1fe7604..e32f3e82c 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-spawn--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-spawn--help.txt @@ -1,4 +1,3 @@ - Spawn a command into a new window or tab Outputs the pane-id for the newly created pane on success diff --git a/docs/examples/cmd-synopsis-wezterm-cli-split-pane--help.txt b/docs/examples/cmd-synopsis-wezterm-cli-split-pane--help.txt index f08d8cb87..31a2c71c9 100644 --- a/docs/examples/cmd-synopsis-wezterm-cli-split-pane--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-cli-split-pane--help.txt @@ -1,4 +1,3 @@ - split the current pane. Outputs the pane-id for the newly created pane on success diff --git a/docs/examples/cmd-synopsis-wezterm-connect--help.txt b/docs/examples/cmd-synopsis-wezterm-connect--help.txt index c18c22fd9..47fc01363 100644 --- a/docs/examples/cmd-synopsis-wezterm-connect--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-connect--help.txt @@ -1,4 +1,3 @@ - Connect to wezterm multiplexer Usage: wezterm connect [OPTIONS] <DOMAIN_NAME> [PROG]... diff --git a/docs/examples/cmd-synopsis-wezterm-imgcat--help.txt b/docs/examples/cmd-synopsis-wezterm-imgcat--help.txt index a3fed38b6..594508484 100644 --- a/docs/examples/cmd-synopsis-wezterm-imgcat--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-imgcat--help.txt @@ -1,4 +1,3 @@ - Output an image to the terminal Usage: wezterm imgcat [OPTIONS] [FILE_NAME] @@ -21,5 +20,16 @@ Options: --no-preserve-aspect-ratio Do not respect the aspect ratio. The default is to respect the aspect ratio + --position <POSITION> + Set the cursor position prior to displaying the image. The default is + to use the current cursor position. Coordinates are expressed in cells + with 0,0 being the top left cell position + --no-move-cursor + Do not move the cursor after displaying the image. Note that when used + like this from the shell, there is a very high chance that shell + prompt will overwrite the image; you may wish to also use `--hold` in + that case + --hold + Wait for enter to be pressed after displaying the image -h, --help Print help diff --git a/docs/examples/cmd-synopsis-wezterm-ls-fonts--help.txt b/docs/examples/cmd-synopsis-wezterm-ls-fonts--help.txt index 731649351..fad6b6fca 100644 --- a/docs/examples/cmd-synopsis-wezterm-ls-fonts--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-ls-fonts--help.txt @@ -1,4 +1,3 @@ - Display information about fonts Usage: wezterm ls-fonts [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-record--help.txt b/docs/examples/cmd-synopsis-wezterm-record--help.txt index 67978c012..d99571c61 100644 --- a/docs/examples/cmd-synopsis-wezterm-record--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-record--help.txt @@ -1,4 +1,3 @@ - Record a terminal session as an asciicast Usage: wezterm record [PROG]... diff --git a/docs/examples/cmd-synopsis-wezterm-replay--help.txt b/docs/examples/cmd-synopsis-wezterm-replay--help.txt index 20dd81983..1ef3d4841 100644 --- a/docs/examples/cmd-synopsis-wezterm-replay--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-replay--help.txt @@ -1,4 +1,3 @@ - Replay an asciicast terminal session Usage: wezterm replay [OPTIONS] <CAST_FILE> diff --git a/docs/examples/cmd-synopsis-wezterm-serial--help.txt b/docs/examples/cmd-synopsis-wezterm-serial--help.txt index d49cb0e75..53cf7c703 100644 --- a/docs/examples/cmd-synopsis-wezterm-serial--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-serial--help.txt @@ -1,4 +1,3 @@ - Open a serial port Usage: wezterm serial [OPTIONS] <PORT> diff --git a/docs/examples/cmd-synopsis-wezterm-set-working-directory--help.txt b/docs/examples/cmd-synopsis-wezterm-set-working-directory--help.txt index 0c84343f1..bd79e7166 100644 --- a/docs/examples/cmd-synopsis-wezterm-set-working-directory--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-set-working-directory--help.txt @@ -1,4 +1,3 @@ - Advise the terminal of the current working directory by emitting an OSC 7 escape sequence diff --git a/docs/examples/cmd-synopsis-wezterm-show-keys--help.txt b/docs/examples/cmd-synopsis-wezterm-show-keys--help.txt index 2a9778ee5..671c4abc5 100644 --- a/docs/examples/cmd-synopsis-wezterm-show-keys--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-show-keys--help.txt @@ -1,4 +1,3 @@ - Show key assignments Usage: wezterm show-keys [OPTIONS] diff --git a/docs/examples/cmd-synopsis-wezterm-ssh--help.txt b/docs/examples/cmd-synopsis-wezterm-ssh--help.txt index c31fa7fbe..b734a1196 100644 --- a/docs/examples/cmd-synopsis-wezterm-ssh--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-ssh--help.txt @@ -1,4 +1,3 @@ - Establish an ssh session Usage: wezterm ssh [OPTIONS] <USER_AT_HOST_AND_PORT> [PROG]... diff --git a/docs/examples/cmd-synopsis-wezterm-start--help.txt b/docs/examples/cmd-synopsis-wezterm-start--help.txt index 9048b8e4e..d1f172217 100644 --- a/docs/examples/cmd-synopsis-wezterm-start--help.txt +++ b/docs/examples/cmd-synopsis-wezterm-start--help.txt @@ -1,4 +1,3 @@ - Start the GUI, optionally running an alternative program Usage: wezterm start [OPTIONS] [PROG]... diff --git a/wezterm/src/main.rs b/wezterm/src/main.rs index 3f3746540..8370392d6 100644 --- a/wezterm/src/main.rs +++ b/wezterm/src/main.rs @@ -6,6 +6,11 @@ use config::{wezterm_version, ConfigHandle}; use mux::Mux; use std::ffi::OsString; use std::io::Read; +use termwiz::caps::Capabilities; +use termwiz::escape::esc::{Esc, EscCode}; +use termwiz::escape::OneBased; +use termwiz::input::{InputEvent, KeyCode, KeyEvent}; +use termwiz::terminal::Terminal; use umask::UmaskSaver; use wezterm_gui_subcommands::*; @@ -153,12 +158,52 @@ struct ImgCatCommand { /// ratio #[arg(long = "no-preserve-aspect-ratio")] no_preserve_aspect_ratio: bool, + + /// Set the cursor position prior to displaying the image. + /// The default is to use the current cursor position. + /// Coordinates are expressed in cells with 0,0 being the top left + /// cell position. + #[arg(long, value_parser=ValueParser::new(x_comma_y))] + position: Option<ImagePosition>, + + /// Do not move the cursor after displaying the image. + /// Note that when used like this from the shell, there is a very + /// high chance that shell prompt will overwrite the image; + /// you may wish to also use `--hold` in that case. + #[arg(long)] + no_move_cursor: bool, + + /// Wait for enter to be pressed after displaying the image + #[arg(long)] + hold: bool, + /// The name of the image file to be displayed. /// If omitted, will attempt to read it from stdin. #[arg(value_parser, value_hint=ValueHint::FilePath)] file_name: Option<OsString>, } +#[derive(Clone, Copy, Debug)] +struct ImagePosition { + x: u32, + y: u32, +} + +fn x_comma_y(arg: &str) -> Result<ImagePosition, String> { + if let Some(eq) = arg.find(',') { + let (left, right) = arg.split_at(eq); + let x = left.parse().map_err(|err| { + format!("Expected x,y to be integer values, got {arg}. '{left}': {err:#}") + })?; + let y = right[1..].parse().map_err(|err| { + format!("Expected x,y to be integer values, got {arg}. '{right}': {err:#}") + })?; + Ok(ImagePosition { x, y }) + } else { + Err(format!("Expected name=value, but got {}", arg)) + } +} + impl ImgCatCommand { fn run(&self) -> anyhow::Result<()> { let mut data = Vec::new(); @@ -171,6 +216,18 @@ impl ImgCatCommand { stdin.read_to_end(&mut data)?; } + if let Some(position) = &self.position { + let save_cursor = Esc::Code(EscCode::DecSaveCursorPosition); + + let csi = termwiz::escape::CSI::Cursor( + termwiz::escape::csi::Cursor::CharacterAndLinePosition { + col: OneBased::from_zero_based(position.x), + line: OneBased::from_zero_based(position.y), + }, + ); + print!("{save_cursor}{csi}"); + } + let osc = OperatingSystemCommand::ITermProprietary(ITermProprietary::File(Box::new( ITermFileData { name: None, @@ -179,12 +236,34 @@ impl ImgCatCommand { height: self.height.unwrap_or_default(), preserve_aspect_ratio: !self.no_preserve_aspect_ratio, inline: true, - do_not_move_cursor: false, + do_not_move_cursor: self.no_move_cursor, data, }, ))); println!("{}", osc); + if self.position.is_some() { + let restore_cursor = Esc::Code(EscCode::DecRestoreCursorPosition); + print!("{restore_cursor}"); + } + + if self.hold { + let caps = Capabilities::new_from_env()?; + let mut term = termwiz::terminal::new_terminal(caps)?; + + while let Ok(Some(event)) = term.poll_input(None) { + match event { + InputEvent::Key(KeyEvent { + key: KeyCode::Enter, + modifiers: _, + }) => { + break; + } + _ => {} + } + } + } + Ok(()) } }