legion-tty 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/legion/tty/app.rb +31 -3
- data/lib/legion/tty/components/input_bar.rb +12 -2
- data/lib/legion/tty/components/status_bar.rb +2 -1
- data/lib/legion/tty/screens/chat/ui_commands.rb +2 -1
- data/lib/legion/tty/screens/chat.rb +21 -8
- data/lib/legion/tty/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c79bfc84ae3c3bc48ae055db72296b3aec2ab24c9a86dba5d7604e5732a3503e
|
|
4
|
+
data.tar.gz: 96cb9a58135228887222a4fcc6064209ae1e825fad949c0cbd143c40c5249ed7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea7ed87c3baffa35d8e02852ce301c532e0aef8deab17a40892db373abd7f82ac49ae60f22a88e4ea66e90f3d56996db0850cef8e8e09ffd743f8e0a924ff0e3
|
|
7
|
+
data.tar.gz: dd2e68abefc811eface7a9db9c7c2014bccf433d7b859b42068746fc952afdbcc4470ec41e761a0d86df40236bb2aebeb334afddcbe278be06fe9acb78f6715f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.1] - 2026-04-18
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Alternate screen buffer** — `App#run_loop` now enables `\e[?1049h` on startup and `\e[?1049l` on shutdown so the TUI no longer pollutes shell scrollback and the prior shell session is restored on exit (closes #20)
|
|
7
|
+
- **Mouse wheel scroll** — enabled SGR mouse tracking (`\e[?1000h` + `\e[?1006h`) and routed wheel-up/wheel-down events to `MessageStream#scroll_up` / `#scroll_down` with 3-line increments (closes #20)
|
|
8
|
+
- **Vim-style scroll bindings** — added `Ctrl+B` (half-page up) and `Ctrl+F` (half-page down) on the Chat screen; wired `Home` / `End` to jump-to-top / jump-to-bottom when the input bar is empty (closes #20)
|
|
9
|
+
- **Scroll hint in status bar** — `scroll_segment` now shows directional arrows (`↑↓ scroll` or `↑ scroll`) alongside the position counter when content overflows the viewport (closes #20)
|
|
10
|
+
- **Help text updated** — added scroll binding reference line to the help overlay
|
|
11
|
+
|
|
3
12
|
## [0.5.0] - 2026-04-17
|
|
4
13
|
|
|
5
14
|
### Added
|
data/lib/legion/tty/app.rb
CHANGED
|
@@ -30,11 +30,18 @@ module Legion
|
|
|
30
30
|
"\e[1~" => :home, "\e[4~" => :end,
|
|
31
31
|
"\x7f" => :backspace, "\b" => :backspace, "\t" => :tab,
|
|
32
32
|
"\x03" => :ctrl_c, "\x04" => :ctrl_d,
|
|
33
|
-
"\x01" => :ctrl_a, "\
|
|
33
|
+
"\x01" => :ctrl_a, "\x02" => :ctrl_b,
|
|
34
|
+
"\x05" => :ctrl_e, "\x06" => :ctrl_f,
|
|
34
35
|
"\x0B" => :ctrl_k, "\x0C" => :ctrl_l, "\x13" => :ctrl_s,
|
|
35
36
|
"\x15" => :ctrl_u
|
|
36
37
|
}.freeze
|
|
37
38
|
|
|
39
|
+
ENABLE_ALT_SCREEN = "\e[?1049h"
|
|
40
|
+
DISABLE_ALT_SCREEN = "\e[?1049l"
|
|
41
|
+
ENABLE_MOUSE = "\e[?1000h\e[?1006h"
|
|
42
|
+
DISABLE_MOUSE = "\e[?1000h\e[?1006l"
|
|
43
|
+
SGR_MOUSE_RE = /\A\e\[<(\d+);(\d+);(\d+)([Mm])\z/
|
|
44
|
+
|
|
38
45
|
attr_reader :config, :credentials, :screen_manager, :hotkeys, :llm_chat, :input_bar
|
|
39
46
|
|
|
40
47
|
def self.run(argv = [])
|
|
@@ -157,6 +164,8 @@ module Legion
|
|
|
157
164
|
|
|
158
165
|
@running = true
|
|
159
166
|
@raw_mode = true
|
|
167
|
+
$stdout.print ENABLE_ALT_SCREEN
|
|
168
|
+
$stdout.print ENABLE_MOUSE
|
|
160
169
|
$stdout.print cursor.hide
|
|
161
170
|
$stdout.print cursor.clear_screen
|
|
162
171
|
|
|
@@ -175,9 +184,9 @@ module Legion
|
|
|
175
184
|
nil
|
|
176
185
|
ensure
|
|
177
186
|
@raw_mode = false
|
|
187
|
+
$stdout.print DISABLE_MOUSE
|
|
178
188
|
$stdout.print cursor.show
|
|
179
|
-
$stdout.print
|
|
180
|
-
$stdout.puts
|
|
189
|
+
$stdout.print DISABLE_ALT_SCREEN
|
|
181
190
|
shutdown
|
|
182
191
|
end
|
|
183
192
|
# rubocop:enable Metrics/AbcSize
|
|
@@ -188,6 +197,9 @@ module Legion
|
|
|
188
197
|
end
|
|
189
198
|
|
|
190
199
|
def normalize_key(raw)
|
|
200
|
+
mouse = parse_sgr_mouse(raw)
|
|
201
|
+
return mouse if mouse
|
|
202
|
+
|
|
191
203
|
KEY_MAP[raw] || raw
|
|
192
204
|
end
|
|
193
205
|
|
|
@@ -213,6 +225,11 @@ module Legion
|
|
|
213
225
|
active = @screen_manager.active_screen
|
|
214
226
|
return unless active
|
|
215
227
|
|
|
228
|
+
if %i[scroll_up scroll_down].include?(key)
|
|
229
|
+
dispatch_to_screen(active, key)
|
|
230
|
+
return
|
|
231
|
+
end
|
|
232
|
+
|
|
216
233
|
if active.respond_to?(:needs_input_bar?) && active.needs_input_bar? && @input_bar
|
|
217
234
|
dispatch_to_input_screen(active, key)
|
|
218
235
|
else
|
|
@@ -297,6 +314,17 @@ module Legion
|
|
|
297
314
|
seq
|
|
298
315
|
end
|
|
299
316
|
|
|
317
|
+
def parse_sgr_mouse(raw)
|
|
318
|
+
match = SGR_MOUSE_RE.match(raw)
|
|
319
|
+
return nil unless match
|
|
320
|
+
|
|
321
|
+
button = match[1].to_i
|
|
322
|
+
return :scroll_up if button == 64
|
|
323
|
+
return :scroll_down if button == 65
|
|
324
|
+
|
|
325
|
+
nil
|
|
326
|
+
end
|
|
327
|
+
|
|
300
328
|
# --- Rendering ---
|
|
301
329
|
|
|
302
330
|
# rubocop:disable Metrics/AbcSize
|
|
@@ -49,10 +49,20 @@ module Legion
|
|
|
49
49
|
when :left
|
|
50
50
|
@cursor_pos = [@cursor_pos - 1, 0].max
|
|
51
51
|
:handled
|
|
52
|
-
when :home
|
|
52
|
+
when :home
|
|
53
|
+
return :pass if @buffer.empty?
|
|
54
|
+
|
|
55
|
+
@cursor_pos = 0
|
|
56
|
+
:handled
|
|
57
|
+
when :ctrl_a
|
|
53
58
|
@cursor_pos = 0
|
|
54
59
|
:handled
|
|
55
|
-
when :end
|
|
60
|
+
when :end
|
|
61
|
+
return :pass if @buffer.empty?
|
|
62
|
+
|
|
63
|
+
@cursor_pos = @buffer.length
|
|
64
|
+
:handled
|
|
65
|
+
when :ctrl_e
|
|
56
66
|
@cursor_pos = @buffer.length
|
|
57
67
|
:handled
|
|
58
68
|
when :ctrl_u
|
|
@@ -122,7 +122,8 @@ module Legion
|
|
|
122
122
|
scroll = @state[:scroll]
|
|
123
123
|
return nil unless scroll.is_a?(Hash) && scroll[:total].to_i > scroll[:visible].to_i
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
hint = scroll[:current].to_i.positive? ? "\u2191\u2193 scroll" : "\u2191 scroll"
|
|
126
|
+
Theme.c(:muted, "#{scroll[:current]}/#{scroll[:total]} #{hint}")
|
|
126
127
|
end
|
|
127
128
|
|
|
128
129
|
def level_to_priority(level)
|
|
@@ -36,7 +36,8 @@ module Legion
|
|
|
36
36
|
'TOOLS : /tools /export /bookmark /pin /pins /alias /snippet /history',
|
|
37
37
|
'UTILS : /calc /rand',
|
|
38
38
|
'',
|
|
39
|
-
'Hotkeys: Ctrl+D=dashboard Ctrl+K=palette Ctrl+S=sessions Esc=back'
|
|
39
|
+
'Hotkeys: Ctrl+D=dashboard Ctrl+K=palette Ctrl+S=sessions Esc=back',
|
|
40
|
+
'Scroll : Mouse wheel PgUp/PgDn Ctrl+B/F (half-page) Home/End (top/bottom)'
|
|
40
41
|
].freeze
|
|
41
42
|
|
|
42
43
|
CALC_SAFE_PATTERN = %r{\A[\d\s+\-*/.()%]*\z}
|
|
@@ -200,20 +200,33 @@ module Legion
|
|
|
200
200
|
end
|
|
201
201
|
|
|
202
202
|
def handle_input(key)
|
|
203
|
+
scroll = handle_scroll_key(key)
|
|
204
|
+
return scroll if scroll
|
|
205
|
+
|
|
206
|
+
:pass
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def handle_scroll_key(key)
|
|
203
210
|
case key
|
|
204
|
-
when :page_up
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
when :
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
211
|
+
when :page_up then @message_stream.scroll_up(10)
|
|
212
|
+
when :page_down then @message_stream.scroll_down(10)
|
|
213
|
+
when :scroll_up then @message_stream.scroll_up(3)
|
|
214
|
+
when :scroll_down then @message_stream.scroll_down(3)
|
|
215
|
+
when :ctrl_b then @message_stream.scroll_up(half_page_lines)
|
|
216
|
+
when :ctrl_f then @message_stream.scroll_down(half_page_lines)
|
|
217
|
+
when :home then @message_stream.scroll_up(@message_stream.messages.size * 5)
|
|
218
|
+
when :end then @message_stream.scroll_down(@message_stream.scroll_offset)
|
|
219
|
+
else return nil
|
|
212
220
|
end
|
|
221
|
+
:handled
|
|
213
222
|
end
|
|
214
223
|
|
|
215
224
|
private
|
|
216
225
|
|
|
226
|
+
def half_page_lines
|
|
227
|
+
[(terminal_height - 3) / 2, 1].max
|
|
228
|
+
end
|
|
229
|
+
|
|
217
230
|
def render_focus(width, height)
|
|
218
231
|
stream_lines = @message_stream.render(width: width, height: [height, 1].max)
|
|
219
232
|
@status_bar.update(scroll: @message_stream.scroll_position)
|
data/lib/legion/tty/version.rb
CHANGED