legion-tty 0.5.2 → 0.5.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e484905e47a82bedca53b308ff66880c8b64bcb320d9af6a1130fe4ad50a056
4
- data.tar.gz: f5c49491e1227c5984e99f161662eef56a5d5924903666aa2ea9dcaecccf098f
3
+ metadata.gz: bdea3050f87e6b47ea8d03d9d3575acdecb2a3968c120cf3f9302068d21a88d9
4
+ data.tar.gz: d90acad8892d80dfab3ba292cb024a969037a4ddbde376535c26418d17cfb5a3
5
5
  SHA512:
6
- metadata.gz: f2eb92406a0f61f109213eec5858122038e270052cdca8c9c4f3bfcfba7d64d0ead54a1f40b53dd356aa08dc172f920a09f47c46dd108c15a708e2a680ffe474
7
- data.tar.gz: e107d25bbb2ce75ce886329f8ef02f2fb5991278c5a4d140cc809d940adf34aba9f14a9c4269309be847ae78c78d48ee4d33540d03bfc71712d4b4261ae7a080
6
+ metadata.gz: a9bc985a693932f6cd1ec9682306dc55eb282c3d7bc6e430305afdeb05962c2bd2c64d70ad6efba4177bf895519a3636ef659508c8182ead8b63410d5bd8bf78
7
+ data.tar.gz: cecd20a8b7842d4c41671458853a030a45e4276b00be917de6578c8c982024ef8c1b6a333ca43ffbbd7f48850c72416e78f47b4217420570dccf721d0ed8d691
data/CHANGELOG.md CHANGED
@@ -1,12 +1,11 @@
1
1
  # Changelog
2
2
 
3
- ## [0.5.2] - 2026-04-20
3
+ ## [0.5.3] - 2026-04-20
4
4
 
5
5
  ### Fixed
6
- - **Bracketed paste support** — `App#run_loop` now enables bracketed paste mode (`\e[?2004h`) on startup and disables (`\e[?2004l`) on shutdown; `read_csi_sequence` detects `\e[200~` / `\e[201~` paste markers and buffers the full pasted text into a `{ paste: text }` event (closes #22)
7
- - **InputBar paste handling** — `handle_key` recognizes paste Hash events and inserts the full pasted text at the cursor position, replacing newlines with spaces, without triggering submit (closes #22)
8
- - **Non-symbol key guard** — `dispatch_key` checks `key.is_a?(Symbol)` before the scroll-event include check, preventing `NoMethodError` on Hash paste events (closes #22)
9
- - **`normalize_key` paste passthrough** — Hash events (paste) pass through without KEY_MAP lookup (closes #22)
6
+ - **Scroll performance** — `MessageStream` now caches rendered lines per message keyed on `(object_id, content_hash, role, width, reactions, annotations, tags, pinned)`; cache invalidates automatically on content change (streaming), display option change, or width change markdown re-parsing only runs for new/changed messages (closes #23)
7
+ - **Input coalescing** — `App#run_loop` drains all queued keys before the next `render_frame`, so rapid typing no longer triggers O(total-messages) renders per keystroke (closes #23)
8
+ - **PgUp/PgDn scroll step** — now scrolls by half-viewport (`(height-3)/2`) instead of a fixed 10 lines, matching Ctrl+B/Ctrl+F behavior (closes #23)
10
9
 
11
10
  ## [0.5.1] - 2026-04-18
12
11
 
@@ -28,10 +28,13 @@ module Legion
28
28
  @show_numbers = false
29
29
  @colorize = true
30
30
  @show_timestamps = true
31
+ @line_cache = {}
32
+ @cache_options_hash = nil
31
33
  end
32
34
 
33
35
  def add_message(role:, content:)
34
36
  @messages << { role: role, content: content, tool_panels: [], timestamp: Time.now }
37
+ compact_cache if @line_cache.size > @messages.size * 2
35
38
  end
36
39
 
37
40
  def append_streaming(text)
@@ -87,15 +90,35 @@ module Legion
87
90
 
88
91
  private
89
92
 
90
- def build_all_lines(width)
93
+ def build_all_lines(width) # rubocop:disable Metrics/AbcSize
94
+ current_opts = options_hash
95
+ if current_opts != @cache_options_hash
96
+ @line_cache.clear
97
+ @cache_options_hash = current_opts
98
+ end
99
+
91
100
  filtered_messages.each_with_index.flat_map do |msg, idx|
92
101
  next [] if @mute_system && msg[:role] == :system
93
102
  next [] if @silent_mode && msg[:role] == :assistant
94
103
 
95
- render_message(msg, width, @show_numbers ? idx + 1 : nil)
104
+ cache_key = message_cache_key(msg, width)
105
+ @line_cache[cache_key] ||= render_message(msg, width, @show_numbers ? idx + 1 : nil)
96
106
  end
97
107
  end
98
108
 
109
+ def options_hash
110
+ [@wrap_width, @show_numbers, @colorize, @show_timestamps, @highlights, @truncate_limit].hash
111
+ end
112
+
113
+ def message_cache_key(msg, width)
114
+ [msg.object_id, msg[:content], msg[:role], width,
115
+ msg[:reactions], msg[:annotations], msg[:tags], msg[:pinned]].hash
116
+ end
117
+
118
+ def compact_cache
119
+ @line_cache.clear
120
+ end
121
+
99
122
  def filtered_messages
100
123
  return @messages if @filter.nil?
101
124
 
@@ -208,12 +208,10 @@ module Legion
208
208
 
209
209
  def handle_scroll_key(key)
210
210
  case key
211
- when :page_up then @message_stream.scroll_up(10)
212
- when :page_down then @message_stream.scroll_down(10)
211
+ when :page_up, :ctrl_b then @message_stream.scroll_up(half_page_lines)
212
+ when :page_down, :ctrl_f then @message_stream.scroll_down(half_page_lines)
213
213
  when :scroll_up then @message_stream.scroll_up(3)
214
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
215
  when :home then @message_stream.scroll_up(@message_stream.messages.size * 5)
218
216
  when :end then @message_stream.scroll_down(@message_stream.scroll_offset)
219
217
  else return nil
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module TTY
5
- VERSION = '0.5.2'
5
+ VERSION = '0.5.3'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legion-tty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity