10 KiB
Files
The package
| File | Role |
|---|---|
main.py |
Entry point. Imports every command and listener class so Sublime discovers them, and defines plugin_loaded(). |
vterm/terminal.py |
Terminal: pty process, emulator ownership, the reader/renderer threads, and everything written back to the app. |
vterm/emulator.py |
VtScreen and VtStream: pyte subclasses adding the terminal features these agents need. |
vterm/render.py |
Screen → view text, colour overlays, caret, folding, trimming. |
vterm/scheme.py |
SchemeManager: generates one theme's colour scheme, the scopes the renderer paints with. get_scheme_manager caches one instance per theme name, each terminal frozen to the instance it was opened or rethemed with. |
vterm/themes.py |
The built-in palettes (default, homebrew, pro, slate, red-alert). |
vterm/commands.py |
The Sublime commands: open, keypress, copy/paste, theme picker, clear, cleanup, close. |
vterm/listeners.py |
VtermCoreEventListener: focus, IME capture, copy/paste rerouting, the mousemap context. |
vterm/mouse.py |
Wheel and click handling. |
vterm/keys.py |
Key name + modifiers → escape sequence tables. |
vterm/utils.py |
settings(), the responsive throttle, the intermission pacer, rev_wcwidth. |
Sublime-facing files at the repo root
| File | Role |
|---|---|
vterm.sublime-settings |
Defaults for the eleven plugin settings. |
vterm.sublime-commands |
Four palette entries: open, open terminal in project folder, clear screen, select theme. |
vterm.sublime-syntax |
An intentionally empty hidden syntax, so terminal text is never tokenized. |
Default.sublime-keymap |
245 generated bindings. Do not edit by hand — regenerate with tools/gen_keymap.py. |
Default (OSX).sublime-mousemap |
Two wheel bindings and the middle button. |
dependencies.json |
Package Control libraries. |
Generated at runtime, not in the repo: Packages/User/vterm/vterm.hidden-color-scheme.
Classes
Terminal(terminal.py) — one per terminal tab. Owns the pty, theVtScreenandVtStream, and the two threads. Instances live in the class-level registryTerminal._terminals, keyed by view id;Terminal.from_id(view.id())is how every command and listener finds its terminal, and it is a plain dict lookup, so it is the cheapest possible gate to put at the top of a hook.TerminalPtyProcess(terminal.py) —ptyprocess.PtyProcessthat acceptsstr.VtScreen(emulator.py) —pyte.Screenplus the alternate screen, scrollback, synchronized output, mouse/focus/paste modes, cursor styles, query replies, OSC handling. Mutated only by the renderer thread, so it carries no lock.VtStream(emulator.py) —pyte.Streamwith a rewritten parser FSM. Stock pyte drops what these agents rely on:>/</=prefixed CSI, the DECRQM$pintermediate, and OSC codes longer than one digit. Itsfeed()regex-matches complete plain CSI and dispatches them directly (params memoized) — pyte resumes the parser coroutine once per character, which dominated escape-heavy floods. OSC, charsets, private/prefixed CSI and:subparams still take the coroutine, byte for byte; a read ending mid-CSI is carried into the next one. Parity is enforced by a differential test (run_fast_path_cases).Cursor(emulator.py) — replaces pyte's so the default attribute set can be aCharcarrying the extralinefeedfield.SchemeManager(scheme.py) — module singletonscheme_manager. Owns the generated scheme file and the mapping from colour combination to scope name.VtermRenderCommand(render.py) — Sublime keeps one command instance per view, so itscolored_lines,_row_cache,_key_counter, the scrollback chunk bookkeeping (_archived_chunks,_open_rows,_open_chunk,_trimmed) and_lastroware that view's render state.
Commands
| Command | Class | Reached from |
|---|---|---|
vterm_open |
VtermOpenCommand |
palette, user keybindings |
vterm_open_terminal_project_folder |
VtermOpenTerminalProjectFolderCommand |
palette |
vterm_initialize_view |
VtermInitializeViewCommand |
internal |
vterm_keypress |
VtermKeypressCommand |
244 keymap bindings |
vterm_render |
VtermRenderCommand |
renderer thread |
vterm_show_cursor |
VtermShowCursorCommand |
internal |
vterm_copy / vterm_paste / vterm_paste_text |
commands.py |
on_text_command, IME capture |
vterm_paste_selection |
commands.py |
mousemap, middle button |
vterm_select_theme |
VtermSelectThemeCommand |
palette |
vterm_clear_screen |
VtermClearScreenCommand |
palette, super+shift+k |
vterm_cleanup |
VtermCleanupCommand |
renderer, on process exit |
vterm_close |
VtermCloseCommand |
nothing — available for a user keybinding |
vterm_clear_undo_stack / vterm_noop |
commands.py |
internal |
vterm_scroll / vterm_mouse_click |
mouse.py |
mousemap, drag_select interception |
Two application-wide EventListeners: VtermCoreEventListener (listeners.py) and
VtermMouseEventListener (mouse.py).
Terminal concepts, briefly
For anyone who has not worked with terminal protocols before. The ones vterm implements are marked ✅.
Control bytes — single characters below 0x20 with an effect rather than a glyph: CR
(\r) return to column 0, LF (\n) next line, BS backspace, HT tab, BEL bell.
Escape sequence — ESC (0x1B) followed by more bytes. Everything below is one.
- CSI ✅ — Control Sequence Introducer,
ESC [. The workhorse:ESC[2Jclear screen,ESC[10;5Hmove the cursor. Ends with a final byte that names the operation; numbers in between are its parameters. - SGR ✅ — Select Graphic Rendition,
CSI … m. Sets colour and style:ESC[1mbold,ESC[31mred foreground,ESC[38;5;208ma 256-palette colour,ESC[38;2;r;g;bmtruecolor,ESC[0mreset. This is what TUIs emit most. - OSC ✅ — Operating System Command,
ESC ], ending at BEL or ST. Carries strings rather than numbers:OSC 0/2set the window title,OSC 10/11query the default foreground/background,OSC 52reads or writes the system clipboard. - DCS / APC — Device Control String (
ESC P) and Application Program Command (ESC _). Long payloads: sixel images, kitty graphics. vterm parses their framing and discards the payload, so an image never leaks into the text. - SS3 ✅ —
ESC O, a single shifted character. Cursor keys take this form in application mode; F1-F4 use it too. - ST — String Terminator,
ESC \, which ends OSC/DCS/APC payloads (BEL also ends OSC).
Modes are switches. DEC private modes are set with CSI ? n h (DECSET) and cleared
with CSI ? n l (DECRST); DECRQM ✅ (CSI ? n $p) asks whether one is on, which is
how an app discovers what the terminal supports.
- 1049 ✅ alternate screen — a second, scrollback-less buffer for full-screen apps, so leaving vim restores your shell exactly as it was.
- 2026 ✅ synchronized output — "I am mid-frame, do not draw yet"; what makes a fullscreen UI update without tearing.
- 2004 ✅ bracketed paste — pasted text is wrapped in
ESC[200~/ESC[201~so an app can tell it apart from typing and not auto-indent it. - 1000 / 1002 / 1003 ✅ mouse reporting — clicks / clicks with drag / all motion.
- 1006 ✅ SGR mouse encoding — the modern wire form,
ESC[<button;col;rowM, without the 223-column limit of the original. - 1004 ✅ focus reporting —
ESC[Ion focus,ESC[Oon blur. - DECCKM ✅ — application cursor keys: arrows switch from
CSI AtoSS3 A. - DECAWM ✅ — autowrap at the right margin.
- DECSCNM ✅ — reverse video for the whole screen.
- DECSCUSR ✅ (
CSI n SP q) — caret shape: block, underline or bar, blinking or not. - DECSTBM ✅ (
CSI t;b r) — set the scrolling region to a band of rows. - DECKPAM — application keypad mode, the numeric keypad's equivalent of DECCKM. vterm ignores it.
- LNM ✅ — line feed/new line mode; decides whether Enter sends CR or CR LF.
Queries — the app asks, the terminal answers on the input stream, as if typed:
- DA1 / DA2 ✅ (
CSI c,CSI > c) — Device Attributes: what kind of terminal are you, and what version. Claude Code waits on DA1 with no timeout, so failing to answer hangs it. - DSR / CPR ✅ (
CSI n,CSI 6n) — Device Status Report / Cursor Position Report: "are you ok" and "where is the cursor". PrivateDSR 996reports whether the palette is light or dark. - XTVERSION ✅ (
CSI > q) — the terminal's name and version. Naming ourselves is what lets apps enable 2026 on a genericTERM. - Kitty keyboard protocol — a richer key encoding with release events. vterm answers
the probe (
CSI ? u) with zero flags, so apps fall back to something else — for pi that is modifyOtherKeys, which it then enables unprompted. - modifyOtherKeys ✅ (
CSI > 4 ; n m) — xterm's pre-kitty answer to the same problem: keys whose modified form has no legacy encoding are sent asCSI 27 ; <mod> ; <code> ~. While an app has it on, vterm uses that form for modified enter, tab, backspace and space — Shift+Enter isCSI 27;2;13~, since a bareESC CRis indistinguishable from Alt+Enter. Ctrl+letters keep their control bytes, so Ctrl+C stays\x03.
Other terms
- pty — pseudo-terminal: a kernel device pair. The child thinks its stdin/stdout is a terminal; we hold the master end and read what it writes.
- TIOCSWINSZ / SIGWINCH ✅ — telling the pty its new size delivers SIGWINCH to the child, which is how a resize reaches the app.
- wcwidth ✅ — how many columns a character occupies: 1 for ASCII, 2 for CJK and most emoji, 0 for combining marks. Terminals are grids, so this has to agree with the font or the caret drifts.
- IME — Input Method Editor: the OS layer that turns keystrokes into composed text
(pinyin → 中文, dead keys → accents). It commits text without a matching key event,
which is why
on_modifiedexists. - TERM / COLORTERM ✅ — environment variables describing the terminal's capabilities.
Children get
TERM=xterm-256colorandCOLORTERM=truecolor.