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
102
103
104
|
# File 'lib/tempest/repl/screen.rb', line 102
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
49
50
51
|
# File 'lib/tempest/repl/screen.rb', line 49
def enabled?
@enabled
end
|
#flush ⇒ Object
90
91
92
|
# File 'lib/tempest/repl/screen.rb', line 90
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.
58
59
60
|
# File 'lib/tempest/repl/screen.rb', line 58
def notify_resize(rows: nil, cols: nil)
@pending_resize = { rows: rows, cols: cols }
end
|
#print(*args) ⇒ Object
82
83
84
|
# File 'lib/tempest/repl/screen.rb', line 82
def print(*args)
@io.print(*args)
end
|
#puts(*lines) ⇒ Object
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/tempest/repl/screen.rb', line 62
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
98
99
100
|
# File 'lib/tempest/repl/screen.rb', line 98
def respond_to_missing?(name, include_private = false)
@io.respond_to?(name, include_private)
end
|
#tty? ⇒ Boolean
94
95
96
|
# File 'lib/tempest/repl/screen.rb', line 94
def tty?
@io.respond_to?(:tty?) ? @io.tty? : false
end
|
#write(*args) ⇒ Object
86
87
88
|
# File 'lib/tempest/repl/screen.rb', line 86
def write(*args)
@io.write(*args)
end
|