Class: Kward::PromptInterface::ComposerState
- Inherits:
-
Object
- Object
- Kward::PromptInterface::ComposerState
- Defined in:
- lib/kward/prompt_interface/composer_state.rb
Overview
Mutable text, cursor, history, and overlay state for the composer.
Instance Attribute Summary collapse
-
#attachments ⇒ Array<Hash>
readonly
Pending image/file attachments submitted with the next turn.
-
#cursor ⇒ Integer
Cursor offset into
input. -
#history ⇒ Array<String>
readonly
Submitted input history.
-
#history_draft ⇒ String?
Draft restored after leaving history navigation.
-
#history_index ⇒ Integer?
Active history index while navigating history.
-
#history_search_draft ⇒ String?
Draft restored after canceling history search.
-
#history_search_index ⇒ Integer
Active selection index while searching history.
-
#history_search_query ⇒ String?
Query typed while searching history.
-
#input ⇒ String
Editable text currently shown in the composer.
-
#kill_buffer ⇒ String
Most recently killed text available for yank.
-
#prefill_input ⇒ String?
Text queued for the next composer prompt.
Instance Method Summary collapse
- #accept_history_search ⇒ Object
-
#add_attachment(attachment) ⇒ Object
Adds one attachment unless its source is already pending.
-
#add_history(value) ⇒ Object
Stores a submitted input unless it is blank or duplicates the previous entry.
- #cancel_history_search ⇒ Object
-
#clear_attachments ⇒ Object
Removes all pending attachments without changing text input.
-
#delete_at_cursor ⇒ Object
Deletes one grapheme at the cursor without moving it.
-
#delete_before_cursor ⇒ Object
Deletes one grapheme before the cursor.
-
#delete_word_after_cursor ⇒ Object
Kills the word after the cursor into
kill_buffer. -
#delete_word_before_cursor ⇒ Object
Kills the word before the cursor into
kill_buffer. - #history_search_active? ⇒ Boolean
- #history_search_matches ⇒ Object
-
#initialize ⇒ ComposerState
constructor
A new instance of ComposerState.
-
#insert_string(string) ⇒ Object
Inserts text at the cursor and advances by the inserted length.
- #invalidate_history_search_matches ⇒ Object
-
#kill_line_after_cursor ⇒ Object
Kills all text after the cursor into
kill_buffer. -
#kill_line_before_cursor ⇒ Object
Kills all text before the cursor into
kill_buffer. -
#kill_range(start_index, end_index) ⇒ Object
Removes a range, stores it in
kill_buffer, and moves the cursor to the start. -
#lines_and_cursor ⇒ Object
Returns
[lines, row, column]for cursor-aware multi-line layout. -
#load_history(values) ⇒ Object
Replaces the in-memory history list with persisted entries.
-
#move_cursor_left ⇒ Object
Moves the cursor one grapheme left when possible.
-
#move_cursor_right ⇒ Object
Moves the cursor one grapheme right when possible.
-
#move_to_end_of_line ⇒ Object
Moves the cursor to the end of the input buffer.
-
#move_to_next_word ⇒ Object
Moves the cursor to the next word boundary.
-
#move_to_previous_word ⇒ Object
Moves the cursor to the previous word boundary.
-
#move_to_start_of_line ⇒ Object
Moves the cursor to the beginning of the input buffer.
-
#recall_next_history ⇒ Object
Replaces input with the next history entry or restores the saved draft.
-
#recall_previous_history ⇒ Object
Replaces input with the previous history entry, preserving the draft first.
-
#remove_last_attachment ⇒ Object
Removes the most recently added attachment.
-
#replace_input(value) ⇒ Object
Replaces the full input buffer and places the cursor at the end.
-
#reset_history_navigation ⇒ Object
Leaves history navigation and clears the saved draft/index state.
- #reset_history_search ⇒ Object
- #select_next_history_search_match ⇒ Object
- #select_previous_history_search_match ⇒ Object
- #selected_history_search_match ⇒ Object
- #start_history_search ⇒ Object
- #update_history_search_query(value) ⇒ Object
-
#yank_kill_buffer ⇒ Object
Inserts the last killed text at the cursor.
Constructor Details
#initialize ⇒ ComposerState
Returns a new instance of ComposerState.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 34 def initialize @input = +"" @cursor = 0 @attachments = [] @kill_buffer = "" @history = [] @history_index = nil @history_draft = nil @prefill_input = nil @history_search_query = nil @history_search_draft = nil @history_search_index = 0 @history_search_matches_query = nil @history_search_matches = nil end |
Instance Attribute Details
#attachments ⇒ Array<Hash> (readonly)
Returns pending image/file attachments submitted with the next turn.
30 31 32 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 30 def @attachments end |
#cursor ⇒ Integer
Returns cursor offset into input.
14 15 16 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 14 def cursor @cursor end |
#history ⇒ Array<String> (readonly)
Returns submitted input history.
32 33 34 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 32 def history @history end |
#history_draft ⇒ String?
Returns draft restored after leaving history navigation.
20 21 22 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 20 def history_draft @history_draft end |
#history_index ⇒ Integer?
Returns active history index while navigating history.
18 19 20 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 18 def history_index @history_index end |
#history_search_draft ⇒ String?
Returns draft restored after canceling history search.
26 27 28 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 26 def history_search_draft @history_search_draft end |
#history_search_index ⇒ Integer
Returns active selection index while searching history.
28 29 30 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 28 def history_search_index @history_search_index end |
#history_search_query ⇒ String?
Returns query typed while searching history.
24 25 26 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 24 def history_search_query @history_search_query end |
#input ⇒ String
Returns editable text currently shown in the composer.
12 13 14 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 12 def input @input end |
#kill_buffer ⇒ String
Returns most recently killed text available for yank.
16 17 18 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 16 def kill_buffer @kill_buffer end |
#prefill_input ⇒ String?
Returns text queued for the next composer prompt.
22 23 24 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 22 def prefill_input @prefill_input end |
Instance Method Details
#accept_history_search ⇒ Object
276 277 278 279 280 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 276 def accept_history_search match = selected_history_search_match replace_input(match) if match reset_history_search end |
#add_attachment(attachment) ⇒ Object
Adds one attachment unless its source is already pending.
56 57 58 59 60 61 62 63 64 65 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 56 def () return false unless .respond_to?(:key?) source = [:source_text] || ["source_text"] || [:original_path] || ["original_path"] return false if source.to_s.empty? return false if @attachments.any? { |item| (item[:source_text] || item["source_text"]).to_s == source.to_s } @attachments << true end |
#add_history(value) ⇒ Object
Stores a submitted input unless it is blank or duplicates the previous entry.
192 193 194 195 196 197 198 199 200 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 192 def add_history(value) stripped = value.to_s.strip return false if stripped.empty? return false if @history.last == value @history << value invalidate_history_search_matches true end |
#cancel_history_search ⇒ Object
282 283 284 285 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 282 def cancel_history_search replace_input(@history_search_draft.to_s) reset_history_search end |
#clear_attachments ⇒ Object
Removes all pending attachments without changing text input.
51 52 53 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 51 def @attachments.clear end |
#delete_at_cursor ⇒ Object
Deletes one grapheme at the cursor without moving it.
94 95 96 97 98 99 100 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 94 def delete_at_cursor return false unless @cursor < @input.length following = TerminalText.next_grapheme_boundary(@input, @cursor) @input = @input[0...@cursor] + @input[following..] true end |
#delete_before_cursor ⇒ Object
Deletes one grapheme before the cursor.
84 85 86 87 88 89 90 91 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 84 def delete_before_cursor return false if @cursor.zero? previous = TerminalText.previous_grapheme_boundary(@input, @cursor) @input = @input[0...previous] + @input[@cursor..] @cursor = previous true end |
#delete_word_after_cursor ⇒ Object
Kills the word after the cursor into kill_buffer.
138 139 140 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 138 def delete_word_after_cursor kill_range(@cursor, TextBoundary.next_word_boundary(@input, @cursor)) end |
#delete_word_before_cursor ⇒ Object
Kills the word before the cursor into kill_buffer.
133 134 135 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 133 def delete_word_before_cursor kill_range(TextBoundary.previous_word_boundary(@input, @cursor), @cursor) end |
#history_search_active? ⇒ Boolean
237 238 239 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 237 def history_search_active? !@history_search_query.nil? end |
#history_search_matches ⇒ Object
247 248 249 250 251 252 253 254 255 256 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 247 def history_search_matches query = @history_search_query.to_s.downcase return @history_search_matches if @history_search_matches_query == query && @history_search_matches pattern = TextMatcher.subsequence_pattern(query) @history_search_matches_query = query @history_search_matches = @history.reverse.select do |value| TextMatcher.subsequence?(value.downcase, query, pattern) end end |
#insert_string(string) ⇒ Object
Inserts text at the cursor and advances by the inserted length.
76 77 78 79 80 81 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 76 def insert_string(string) return if string.empty? @input = @input[0...@cursor] + string + @input[@cursor..] @cursor += string.length end |
#invalidate_history_search_matches ⇒ Object
293 294 295 296 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 293 def invalidate_history_search_matches @history_search_matches_query = nil @history_search_matches = nil end |
#kill_line_after_cursor ⇒ Object
Kills all text after the cursor into kill_buffer.
148 149 150 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 148 def kill_line_after_cursor kill_range(@cursor, @input.length) end |
#kill_line_before_cursor ⇒ Object
Kills all text before the cursor into kill_buffer.
143 144 145 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 143 def kill_line_before_cursor kill_range(0, @cursor) end |
#kill_range(start_index, end_index) ⇒ Object
Removes a range, stores it in kill_buffer, and moves the cursor to the start.
153 154 155 156 157 158 159 160 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 153 def kill_range(start_index, end_index) return false if start_index == end_index @kill_buffer = @input[start_index...end_index].to_s @input = @input[0...start_index].to_s + @input[end_index..].to_s @cursor = start_index true end |
#lines_and_cursor ⇒ Object
Returns [lines, row, column] for cursor-aware multi-line layout.
174 175 176 177 178 179 180 181 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 174 def lines_and_cursor lines = @input.split("\n", -1) before_cursor = @input[0...@cursor] row = before_cursor.count("\n") line_start = before_cursor.rindex("\n") column = line_start ? before_cursor.length - line_start - 1 : before_cursor.length [lines.empty? ? [""] : lines, row, column] end |
#load_history(values) ⇒ Object
Replaces the in-memory history list with persisted entries.
184 185 186 187 188 189 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 184 def load_history(values) @history = Array(values).map(&:to_s).reject { |value| value.strip.empty? } reset_history_search invalidate_history_search_matches end |
#move_cursor_left ⇒ Object
Moves the cursor one grapheme left when possible.
103 104 105 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 103 def move_cursor_left @cursor = TerminalText.previous_grapheme_boundary(@input, @cursor) if @cursor.positive? end |
#move_cursor_right ⇒ Object
Moves the cursor one grapheme right when possible.
108 109 110 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 108 def move_cursor_right @cursor = TerminalText.next_grapheme_boundary(@input, @cursor) if @cursor < @input.length end |
#move_to_end_of_line ⇒ Object
Moves the cursor to the end of the input buffer.
118 119 120 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 118 def move_to_end_of_line @cursor = @input.length end |
#move_to_next_word ⇒ Object
Moves the cursor to the next word boundary.
128 129 130 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 128 def move_to_next_word @cursor = TextBoundary.next_word_boundary(@input, @cursor) end |
#move_to_previous_word ⇒ Object
Moves the cursor to the previous word boundary.
123 124 125 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 123 def move_to_previous_word @cursor = TextBoundary.previous_word_boundary(@input, @cursor) end |
#move_to_start_of_line ⇒ Object
Moves the cursor to the beginning of the input buffer.
113 114 115 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 113 def move_to_start_of_line @cursor = 0 end |
#recall_next_history ⇒ Object
Replaces input with the next history entry or restores the saved draft.
212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 212 def recall_next_history return if @history_index.nil? if @history_index < @history.length - 1 @history_index += 1 replace_input(@history[@history_index]) else replace_input(@history_draft || "") end end |
#recall_previous_history ⇒ Object
Replaces input with the previous history entry, preserving the draft first.
203 204 205 206 207 208 209 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 203 def recall_previous_history return if @history.empty? @history_draft = @input if @history_index.nil? @history_index = @history_index.nil? ? @history.length - 1 : [@history_index - 1, 0].max replace_input(@history[@history_index]) end |
#remove_last_attachment ⇒ Object
Removes the most recently added attachment.
68 69 70 71 72 73 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 68 def return false if @attachments.empty? @attachments.pop true end |
#replace_input(value) ⇒ Object
Replaces the full input buffer and places the cursor at the end.
168 169 170 171 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 168 def replace_input(value) @input = value.to_s @cursor = @input.length end |
#reset_history_navigation ⇒ Object
Leaves history navigation and clears the saved draft/index state.
225 226 227 228 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 225 def @history_index = nil @history_draft = nil end |
#reset_history_search ⇒ Object
287 288 289 290 291 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 287 def reset_history_search @history_search_query = nil @history_search_draft = nil @history_search_index = 0 end |
#select_next_history_search_match ⇒ Object
269 270 271 272 273 274 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 269 def select_next_history_search_match matches = history_search_matches return if matches.empty? @history_search_index = [@history_search_index + 1, matches.length - 1].min end |
#select_previous_history_search_match ⇒ Object
265 266 267 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 265 def select_previous_history_search_match @history_search_index = [@history_search_index - 1, 0].max end |
#selected_history_search_match ⇒ Object
258 259 260 261 262 263 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 258 def selected_history_search_match matches = history_search_matches return nil if matches.empty? matches[[@history_search_index, matches.length - 1].min] end |
#start_history_search ⇒ Object
230 231 232 233 234 235 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 230 def start_history_search @history_search_draft = @input if @history_search_query.nil? @history_search_query = @input.to_s @history_search_index = 0 replace_input(@history_search_query) end |
#update_history_search_query(value) ⇒ Object
241 242 243 244 245 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 241 def update_history_search_query(value) @history_search_query = value.to_s @history_search_index = 0 replace_input(@history_search_query) end |
#yank_kill_buffer ⇒ Object
Inserts the last killed text at the cursor.
163 164 165 |
# File 'lib/kward/prompt_interface/composer_state.rb', line 163 def yank_kill_buffer insert_string(@kill_buffer.to_s) unless @kill_buffer.to_s.empty? end |