Skip to content
Kward Search API index

Class: Kward::PromptInterface::ComposerState

Inherits:
Object
  • Object
show all
Defined in:
lib/kward/prompt_interface/composer_state.rb

Overview

Mutable text, cursor, history, and overlay state for the composer.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeComposerState

Returns a new instance of ComposerState.



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/kward/prompt_interface/composer_state.rb', line 32

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
end

Instance Attribute Details

#attachmentsArray<Hash> (readonly)

Returns pending image/file attachments submitted with the next turn.

Returns:

  • (Array<Hash>)

    pending image/file attachments submitted with the next turn



28
29
30
# File 'lib/kward/prompt_interface/composer_state.rb', line 28

def attachments
  @attachments
end

#cursorInteger

Returns cursor offset into input.

Returns:

  • (Integer)

    cursor offset into input



12
13
14
# File 'lib/kward/prompt_interface/composer_state.rb', line 12

def cursor
  @cursor
end

#historyArray<String> (readonly)

Returns submitted input history.

Returns:

  • (Array<String>)

    submitted input history



30
31
32
# File 'lib/kward/prompt_interface/composer_state.rb', line 30

def history
  @history
end

#history_draftString?

Returns draft restored after leaving history navigation.

Returns:

  • (String, nil)

    draft restored after leaving history navigation



18
19
20
# File 'lib/kward/prompt_interface/composer_state.rb', line 18

def history_draft
  @history_draft
end

#history_indexInteger?

Returns active history index while navigating history.

Returns:

  • (Integer, nil)

    active history index while navigating history



16
17
18
# File 'lib/kward/prompt_interface/composer_state.rb', line 16

def history_index
  @history_index
end

#history_search_draftString?

Returns draft restored after canceling history search.

Returns:

  • (String, nil)

    draft restored after canceling history search



24
25
26
# File 'lib/kward/prompt_interface/composer_state.rb', line 24

def history_search_draft
  @history_search_draft
end

#history_search_indexInteger

Returns active selection index while searching history.

Returns:

  • (Integer)

    active selection index while searching history



26
27
28
# File 'lib/kward/prompt_interface/composer_state.rb', line 26

def history_search_index
  @history_search_index
end

#history_search_queryString?

Returns query typed while searching history.

Returns:

  • (String, nil)

    query typed while searching history



22
23
24
# File 'lib/kward/prompt_interface/composer_state.rb', line 22

def history_search_query
  @history_search_query
end

#inputString

Returns editable text currently shown in the composer.

Returns:

  • (String)

    editable text currently shown in the composer



10
11
12
# File 'lib/kward/prompt_interface/composer_state.rb', line 10

def input
  @input
end

#kill_bufferString

Returns most recently killed text available for yank.

Returns:

  • (String)

    most recently killed text available for yank



14
15
16
# File 'lib/kward/prompt_interface/composer_state.rb', line 14

def kill_buffer
  @kill_buffer
end

#prefill_inputString?

Returns text queued for the next composer prompt.

Returns:

  • (String, nil)

    text queued for the next composer prompt



20
21
22
# File 'lib/kward/prompt_interface/composer_state.rb', line 20

def prefill_input
  @prefill_input
end

Instance Method Details

#accept_history_searchObject



260
261
262
263
264
# File 'lib/kward/prompt_interface/composer_state.rb', line 260

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.



52
53
54
55
56
57
58
59
60
61
# File 'lib/kward/prompt_interface/composer_state.rb', line 52

def add_attachment(attachment)
  return false unless attachment.respond_to?(:key?)

  source = attachment[:source_text] || attachment["source_text"] || attachment[:original_path] || attachment["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 << attachment
  true
end

#add_history(value) ⇒ Object

Stores a submitted input unless it is blank or duplicates the previous entry.



181
182
183
184
185
186
187
188
# File 'lib/kward/prompt_interface/composer_state.rb', line 181

def add_history(value)
  stripped = value.to_s.strip
  return false if stripped.empty?
  return false if @history.last == value

  @history << value
  true
end

#cancel_history_searchObject



266
267
268
269
# File 'lib/kward/prompt_interface/composer_state.rb', line 266

def cancel_history_search
  replace_input(@history_search_draft.to_s)
  reset_history_search
end

#clear_attachmentsObject

Removes all pending attachments without changing text input.



47
48
49
# File 'lib/kward/prompt_interface/composer_state.rb', line 47

def clear_attachments
  @attachments.clear
end

#cursor_logical_positionObject

Returns [row, column] for cursor placement in multi-line input.



168
169
170
171
# File 'lib/kward/prompt_interface/composer_state.rb', line 168

def cursor_logical_position
  before_cursor = @input[0...@cursor]
  [before_cursor.count("\n"), (before_cursor.split("\n", -1).last || "").length]
end

#delete_at_cursorObject

Deletes one character at the cursor without moving it.



89
90
91
92
93
94
# File 'lib/kward/prompt_interface/composer_state.rb', line 89

def delete_at_cursor
  return false unless @cursor < @input.length

  @input = @input[0...@cursor] + @input[(@cursor + 1)..]
  true
end

#delete_before_cursorObject

Deletes one character before the cursor.



80
81
82
83
84
85
86
# File 'lib/kward/prompt_interface/composer_state.rb', line 80

def delete_before_cursor
  return false if @cursor.zero?

  @input = @input[0...(@cursor - 1)] + @input[@cursor..]
  @cursor -= 1
  true
end

#delete_word_after_cursorObject

Kills the word after the cursor into kill_buffer.



132
133
134
# File 'lib/kward/prompt_interface/composer_state.rb', line 132

def delete_word_after_cursor
  kill_range(@cursor, TextBoundary.next_word_boundary(@input, @cursor))
end

#delete_word_before_cursorObject

Kills the word before the cursor into kill_buffer.



127
128
129
# File 'lib/kward/prompt_interface/composer_state.rb', line 127

def delete_word_before_cursor
  kill_range(TextBoundary.previous_word_boundary(@input, @cursor), @cursor)
end

#fuzzy_history_match?(value, query) ⇒ Boolean

Returns:

  • (Boolean)


277
278
279
280
281
282
283
284
285
286
287
# File 'lib/kward/prompt_interface/composer_state.rb', line 277

def fuzzy_history_match?(value, query)
  query.chars.all? do |char|
    index = value.index(char)
    if index
      value = value[(index + 1)..].to_s
      true
    else
      false
    end
  end
end

#history_search_active?Boolean

Returns:

  • (Boolean)


225
226
227
# File 'lib/kward/prompt_interface/composer_state.rb', line 225

def history_search_active?
  !@history_search_query.nil?
end

#history_search_matchesObject



235
236
237
238
239
240
# File 'lib/kward/prompt_interface/composer_state.rb', line 235

def history_search_matches
  query = @history_search_query.to_s.downcase
  return @history.reverse if query.empty?

  @history.reverse.select { |value| fuzzy_history_match?(value.downcase, query) }
end

#insert_string(string) ⇒ Object

Inserts text at the cursor and advances by the inserted length.



72
73
74
75
76
77
# File 'lib/kward/prompt_interface/composer_state.rb', line 72

def insert_string(string)
  return if string.empty?

  @input = @input[0...@cursor] + string + @input[@cursor..]
  @cursor += string.length
end

#kill_line_after_cursorObject

Kills all text after the cursor into kill_buffer.



142
143
144
# File 'lib/kward/prompt_interface/composer_state.rb', line 142

def kill_line_after_cursor
  kill_range(@cursor, @input.length)
end

#kill_line_before_cursorObject

Kills all text before the cursor into kill_buffer.



137
138
139
# File 'lib/kward/prompt_interface/composer_state.rb', line 137

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.



147
148
149
150
151
152
153
154
# File 'lib/kward/prompt_interface/composer_state.rb', line 147

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

#load_history(values) ⇒ Object

Replaces the in-memory history list with persisted entries.



174
175
176
177
178
# File 'lib/kward/prompt_interface/composer_state.rb', line 174

def load_history(values)
  @history = Array(values).map(&:to_s).reject { |value| value.strip.empty? }
  reset_history_navigation
  reset_history_search
end

#move_cursor_leftObject

Moves the cursor one character left when possible.



97
98
99
# File 'lib/kward/prompt_interface/composer_state.rb', line 97

def move_cursor_left
  @cursor -= 1 if @cursor.positive?
end

#move_cursor_rightObject

Moves the cursor one character right when possible.



102
103
104
# File 'lib/kward/prompt_interface/composer_state.rb', line 102

def move_cursor_right
  @cursor += 1 if @cursor < @input.length
end

#move_to_end_of_lineObject

Moves the cursor to the end of the input buffer.



112
113
114
# File 'lib/kward/prompt_interface/composer_state.rb', line 112

def move_to_end_of_line
  @cursor = @input.length
end

#move_to_next_wordObject

Moves the cursor to the next word boundary.



122
123
124
# File 'lib/kward/prompt_interface/composer_state.rb', line 122

def move_to_next_word
  @cursor = TextBoundary.next_word_boundary(@input, @cursor)
end

#move_to_previous_wordObject

Moves the cursor to the previous word boundary.



117
118
119
# File 'lib/kward/prompt_interface/composer_state.rb', line 117

def move_to_previous_word
  @cursor = TextBoundary.previous_word_boundary(@input, @cursor)
end

#move_to_start_of_lineObject

Moves the cursor to the beginning of the input buffer.



107
108
109
# File 'lib/kward/prompt_interface/composer_state.rb', line 107

def move_to_start_of_line
  @cursor = 0
end

#recall_next_historyObject

Replaces input with the next history entry or restores the saved draft.



200
201
202
203
204
205
206
207
208
209
210
# File 'lib/kward/prompt_interface/composer_state.rb', line 200

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 || "")
    reset_history_navigation
  end
end

#recall_previous_historyObject

Replaces input with the previous history entry, preserving the draft first.



191
192
193
194
195
196
197
# File 'lib/kward/prompt_interface/composer_state.rb', line 191

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_attachmentObject

Removes the most recently added attachment.



64
65
66
67
68
69
# File 'lib/kward/prompt_interface/composer_state.rb', line 64

def remove_last_attachment
  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.



162
163
164
165
# File 'lib/kward/prompt_interface/composer_state.rb', line 162

def replace_input(value)
  @input = value.to_s
  @cursor = @input.length
end

#reset_history_navigationObject

Leaves history navigation and clears the saved draft/index state.



213
214
215
216
# File 'lib/kward/prompt_interface/composer_state.rb', line 213

def reset_history_navigation
  @history_index = nil
  @history_draft = nil
end

#reset_history_searchObject



271
272
273
274
275
# File 'lib/kward/prompt_interface/composer_state.rb', line 271

def reset_history_search
  @history_search_query = nil
  @history_search_draft = nil
  @history_search_index = 0
end

#select_next_history_search_matchObject



253
254
255
256
257
258
# File 'lib/kward/prompt_interface/composer_state.rb', line 253

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_matchObject



249
250
251
# File 'lib/kward/prompt_interface/composer_state.rb', line 249

def select_previous_history_search_match
  @history_search_index = [@history_search_index - 1, 0].max
end

#selected_history_search_matchObject



242
243
244
245
246
247
# File 'lib/kward/prompt_interface/composer_state.rb', line 242

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_searchObject



218
219
220
221
222
223
# File 'lib/kward/prompt_interface/composer_state.rb', line 218

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



229
230
231
232
233
# File 'lib/kward/prompt_interface/composer_state.rb', line 229

def update_history_search_query(value)
  @history_search_query = value.to_s
  @history_search_index = 0
  replace_input(@history_search_query)
end

#yank_kill_bufferObject

Inserts the last killed text at the cursor.



157
158
159
# File 'lib/kward/prompt_interface/composer_state.rb', line 157

def yank_kill_buffer
  insert_string(@kill_buffer.to_s) unless @kill_buffer.to_s.empty?
end