Class: Tempest::REPL::Screen
- Inherits:
-
Object
- Object
- Tempest::REPL::Screen
show all
- Defined in:
- lib/tempest/repl/screen.rb
Overview
Implements the earthquake-style split layout: the bottom row holds the tempest> prompt, while the rest of the terminal scrolls timeline lines in from below. Built on the DECSTBM (top/bottom margin) escape sequence so we don’t need a full curses screen.
Sequences used:
CSI top;bottom r set scrolling region
CSI r reset scrolling region (full screen)
CSI row;col H move cursor
ESC 7 / ESC 8 save/restore cursor (DECSC/DECRC)
Instance Method Summary
collapse
Constructor Details
#initialize(io:, rows: nil, cols: nil) ⇒ Screen
Returns a new instance of Screen.
17
18
19
20
21
22
23
24
|
# File 'lib/tempest/repl/screen.rb', line 17
def initialize(io:, rows: nil, cols: nil)
@io = io
@rows = rows
@cols = cols
@enabled = false
@mutex = Mutex.new
@pending_resize = nil
end
|
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, **kwargs, &block) ⇒ Object
122
123
124
|
# File 'lib/tempest/repl/screen.rb', line 122
def method_missing(name, *args, **kwargs, &block)
@io.send(name, *args, **kwargs, &block)
end
|
Instance Method Details
#disable ⇒ Object
40
41
42
43
44
45
46
47
|
# File 'lib/tempest/repl/screen.rb', line 40
def disable
return unless @enabled
uninstall_resize_trap
@io.print "\e_Ga=d,q=2\e\\"
@io.print "\e[r"
@io.flush if @io.respond_to?(:flush)
@enabled = false
end
|
#enable ⇒ Object
26
27
28
29
30
31
32
33
34
35
36
37
38
|
# File 'lib/tempest/repl/screen.rb', line 26
def enable
return unless @io.respond_to?(:tty?) && @io.tty?
rows = @rows || detect_rows
return unless rows && rows >= 4
@rows = rows
@cols ||= detect_cols
@io.print "\e[1;#{rows - 1}r" @io.print "\e[#{rows};1H" @io.flush if @io.respond_to?(:flush)
@enabled = true
install_resize_trap
end
|
#enabled? ⇒ Boolean
69
70
71
|
# File 'lib/tempest/repl/screen.rb', line 69
def enabled?
@enabled
end
|
#flush ⇒ Object
110
111
112
|
# File 'lib/tempest/repl/screen.rb', line 110
def flush
@io.flush if @io.respond_to?(:flush)
end
|
#notify_resize(rows: nil, cols: nil) ⇒ Object
SIGWINCH hook. Trap handlers in Ruby are restricted (can’t reliably acquire mutexes or drive Reline), so we only stash the new dimensions here and apply them on the next mutex-protected write. If rows/cols are omitted (the production path), they’re read from IO.console at apply time so coalesced WINCHes still pick up the latest size.
78
79
80
|
# File 'lib/tempest/repl/screen.rb', line 78
def notify_resize(rows: nil, cols: nil)
@pending_resize = { rows: rows, cols: cols }
end
|
#print(*args) ⇒ Object
102
103
104
|
# File 'lib/tempest/repl/screen.rb', line 102
def print(*args)
@io.print(*args)
end
|
#puts(*lines) ⇒ Object
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# File 'lib/tempest/repl/screen.rb', line 82
def puts(*lines)
@mutex.synchronize do
apply_pending_resize
if @enabled
flat = lines.empty? ? [""] : lines.flat_map { |l| l.to_s.split("\n") }
flat.each { |line| insert_above_prompt(line) }
else
(lines.empty? ? [""] : lines).each do |line|
@io.print "\r\e[2K"
@io.puts line
end
@io.flush if @io.respond_to?(:flush)
end
end
rerender_prompt
end
|
#respond_to_missing?(name, include_private = false) ⇒ Boolean
118
119
120
|
# File 'lib/tempest/repl/screen.rb', line 118
def respond_to_missing?(name, include_private = false)
@io.respond_to?(name, include_private)
end
|
#resume ⇒ Object
64
65
66
67
|
# File 'lib/tempest/repl/screen.rb', line 64
def resume
return if @enabled
enable
end
|
#suspend ⇒ Object
Transient teardown for handing the terminal off to a subprocess (e.g. $EDITOR via ‘:compose`). Unlike `disable`, this does NOT issue the Kitty graphics delete sequence — terminals that support the Kitty protocol keep image placements in the main screen buffer even while the editor draws on the alternate buffer, so suspending without deleting lets the avatars re-appear automatically when the editor exits. Pair with `resume` to re-establish the scrolling region.
56
57
58
59
60
61
62
|
# File 'lib/tempest/repl/screen.rb', line 56
def suspend
return unless @enabled
uninstall_resize_trap
@io.print "\e[r"
@io.flush if @io.respond_to?(:flush)
@enabled = false
end
|
#tty? ⇒ Boolean
114
115
116
|
# File 'lib/tempest/repl/screen.rb', line 114
def tty?
@io.respond_to?(:tty?) ? @io.tty? : false
end
|
#write(*args) ⇒ Object
106
107
108
|
# File 'lib/tempest/repl/screen.rb', line 106
def write(*args)
@io.write(*args)
end
|