Skip to content

Add cursor shape indicator for vi mode#1558

Open
joryeugene wants to merge 2 commits intodbcli:mainfrom
joryeugene:vi-mode-cursor-shape
Open

Add cursor shape indicator for vi mode#1558
joryeugene wants to merge 2 commits intodbcli:mainfrom
joryeugene:vi-mode-cursor-shape

Conversation

@joryeugene
Copy link

Problem

In vi mode, the cursor never changes shape regardless of the current editing mode (INSERT / NORMAL / REPLACE). The cursor stays static because PromptSession defaults to cursor=None, which prompt_toolkit resolves to SimpleCursorShapeConfig(CursorShape._NEVER_CHANGE). That sentinel causes set_cursor_shape() to return immediately, so no DECSCUSR escape sequences are ever emitted.

Root cause

CursorShape._NEVER_CHANGE exists 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:

# Import (alongside other prompt_toolkit imports):
from prompt_toolkit.cursor_shapes import ModalCursorShapeConfig

# PromptSession kwarg:
cursor=ModalCursorShapeConfig(),

ModalCursorShapeConfig reads vi_state.input_mode on every render and emits the appropriate DECSCUSR sequence:

Mode Cursor shape
INSERT / INSERT_MULTIPLE Beam |
NAVIGATION (Normal) Block X
REPLACE Underline _

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: ModalCursorShapeConfig only acts when vi_state.input_mode changes, which only occurs when vi mode is active.

Manual verification

  1. Connect to any database with pgcli
  2. Default prompt: beam cursor (INSERT)
  3. Press Esc: block cursor (NORMAL)
  4. Press i: beam cursor (INSERT)
  5. Press 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 Esc shows 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 how ModalCursorShapeConfig integrates with prompt_toolkit's event loop.

Notes

mycli and litecli have the same gap. Worth a follow-up PR to those projects.

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant