Skip to content

🐛bug: builtin pager ignores Shift keys in Ghostty #1363

Description

@vegerot

Description

When using Sapling's internal pager (pager=internal:streampager, the default for sl log), any key that requires Shift does not work when running outside of tmux in Ghostty.app (and cmux.app which uses libghostty).

Observed failures:

  • G (Shift+g) to go to bottom of pager does nothing
  • Typing @ (Shift+2 on US layout) in search prompt (/) results in empty input
  • Searching for any capital letter (e.g. Foo) does not insert the capital
  • All shifted punctuation / symbols affected

Inside tmux it works (tmux re-encodes keys as plain chars), and inside Terminal.app it works. Only Ghostty (and libghostty-based terms) outside tmux reproduces.

Repro steps (Ghostty, no tmux)

  1. cd ~/code/github.com/facebook/sapling && sl log -l 5000 --pager=always
  2. Press lowercase g -> goes to top (works)
  3. Press uppercase G (Shift+g) -> should go to bottom, stays at top
  4. Press / to search
  5. Type @ (Shift+2) -> prompt stays empty, should show @
  6. Type ABC -> nothing inserted or only lowercase

Repro with hex injection (works inside tmux too, to avoid needing Ghostty)

Ghostty with modifyOtherKeys=2 enabled (which Sapling enables via termwiz ESC[>4;2m in set_raw_mode) encodes shifted keys as xterm modifyOtherKeys:

  • Shift+G: ESC[27;2;71~ hex 1b 5b 32 37 3b 32 3b 37 31 7e
  • Shift+@: ESC[27;2;64~ hex 1b 5b 32 37 3b 32 3b 36 34 7e
tmux new -d -s repro -x 200 -y 20
tmux send-keys -t repro "sl log -l 5000 --pager=always" C-m; sleep 2
tmux send-keys -t repro -l "g"; sleep 0.5    # top works
tmux send-keys -t repro -H '1b5b32373b323b37317e'; sleep 0.8  # Shift+G Ghostty
# expected bottom, actual stays at top -> bug
tmux send-keys -t repro -l "/"; sleep 0.3
tmux send-keys -t repro -H '1b5b32373b323b36347e'; sleep 0.6  # @ shift
# expected Search: @, actual empty
tmux send-keys -t repro "q"; tmux kill-session -t repro

Technical overview

Sapling's pager enables xterm modifyOtherKeys and Ghostty sends Shift+G as ESC[27;2;71~ which termwiz decodes as Char('G')+SHIFT. The pager's keymap expects Char('G')+NONE and prompt only accepts NONE, so the exact modifier check fails. tmux hides this by re-encoding to plain G.

Disclosure: Written by Meta Muse Spark 1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions