Add cursor shape indicator for vi mode#1558
Open
joryeugene wants to merge 2 commits intodbcli:mainfrom
Open
Conversation
When vi = True, users expect the cursor to reflect modal state (block in NORMAL, beam in INSERT, underline in REPLACE). ModalCursorShapeConfig exists in prompt_toolkit for exactly this. Without it, cursor=None resolves to CursorShape._NEVER_CHANGE, so no DECSCUSR sequences are ever written regardless of mode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In vi mode, the cursor never changes shape regardless of the current editing mode (INSERT / NORMAL / REPLACE). The cursor stays static because
PromptSessiondefaults tocursor=None, which prompt_toolkit resolves toSimpleCursorShapeConfig(CursorShape._NEVER_CHANGE). That sentinel causesset_cursor_shape()to return immediately, so no DECSCUSR escape sequences are ever emitted.Root cause
CursorShape._NEVER_CHANGEexists for IPython compatibility: IPython manages its own cursor state and pgcli (as an embedded REPL) must not interfere. pgcli runs standalone and owns the full terminal session, so this constraint does not apply here.Fix
Two lines in
pgcli/main.py:ModalCursorShapeConfigreadsvi_state.input_modeon every render and emits the appropriate DECSCUSR sequence:|X_Non-breaking
DECSCUSR sequences are silently ignored on terminals that do not support cursor shape changes (VT100, most multiplexer fallback modes). Users without vi mode are unaffected:
ModalCursorShapeConfigonly acts whenvi_state.input_modechanges, which only occurs when vi mode is active.Manual verification
pgcliEsc: block cursor (NORMAL)i: beam cursor (INSERT)R: underline cursor (REPLACE)Tested on macOS with iTerm2, WezTerm, and Terminal.app. Terminal.app ignores DECSCUSR as expected.
Prior art
PR #620 ("Display vi mode in the toolbar", 2016) added a text indicator for the current vi mode. This PR adds cursor-shape signaling alongside it, which is the standard terminal convention that vi-mode users expect.
Known limitation
Pressing
Escshows the beam cursor for one render cycle before switching to block. Cursor shape is emitted as part of the render pass, which is scheduled after the key event. Moving the cursor triggers the next render, which correctly shows block. This is inherent to howModalCursorShapeConfigintegrates with prompt_toolkit's event loop.Notes
mycli and litecli have the same gap. Worth a follow-up PR to those projects.