Class: Rubino::UI::EscapeReader

Inherits:
Object
  • Object
show all
Defined in:
lib/rubino/ui/escape_reader.rb

Overview

Reads and parses the byte tail of an ESC keystroke for the BottomComposer: arrows / Home / End / Delete / word-jump / Shift+Tab / Alt+Enter and the bracketed-paste body. PURE input: it only consumes bytes from the keystroke source and returns a semantic action tuple —the composer maps actions to its editing/menu/turn behavior, so all rendering and state stay on its side of the seam.

Three escape families are handled:

* CSI  — ESC '[' params final  (arrows, Home/End, Delete, Shift+Tab,
         xterm modified keys like ESC[1;5C for Ctrl+→, bracketed paste)
* SS3  — ESC 'O' final          (application-cursor arrows / Home/End)
* Meta — ESC b / ESC f          (Alt+b / Alt+f word-jump on many terms)

Constant Summary collapse

PASTE_END =

Bracketed paste (DEC 2004) end marker tail: the terminal closes a paste with ESC[201~ (the opener ESC[200~ arrives as a normal CSI above).

"201~"

Instance Method Summary collapse

Constructor Details

#initialize(source) ⇒ EscapeReader

Returns a new instance of EscapeReader.

Parameters:

  • source (#call)

    returns the keystroke IO to read from. A callable rather than a captured IO so the reader always follows the composer’s CURRENT input — the escape tail must come from the same stream the leading “e” byte was read from, even if the IO is swapped (tests).



26
27
28
# File 'lib/rubino/ui/escape_reader.rb', line 26

def initialize(source)
  @source = source
end

Instance Method Details

#read_actionObject

Consume the remainder of the escape sequence after a read “e” and return what it MEANS, as one of:

[:esc]                      lone ESC (no following bytes)
[:esc_esc]                  two ESC bytes in ONE burst (fast double-tap)
[:alt_enter]                Alt/Meta+Enter (ESC CR / ESC LF)
[:paste, body]              bracketed paste with its raw body
[:mode_cycle]               Shift+Tab (ESC[Z)
[:history_up] / [:history_down]      ↑ / ↓
[:move_by, ±1]              bare ← / →
[:word_left] / [:word_right]         modified ←/→, Alt+b/f
[:move_home] / [:move_end]  Home / End (CSI, SS3 and tilde forms)
[:delete_forward]           Delete (ESC[3~)
nil                         unrecognized sequence (a quiet no-op)

Non-blocking reads so a lone ESC doesn’t hang.



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rubino/ui/escape_reader.rb', line 46

def read_action
  case read_nonblock_char
  when nil        then [:esc]
  when "\e"       then double_escape_action
  when "\r", "\n" then [:alt_enter]
  when "["        then csi_action(read_csi)
  when "O"        then final_action(read_nonblock_char, modifier: 1)
  when "b"        then [:word_left]
  when "f"        then [:word_right]
  end
end