Class: LLM::Repl::Input Private
- Inherits:
-
Object
- Object
- LLM::Repl::Input
- Defined in:
- lib/llm/repl/input.rb,
lib/llm/repl/input/row.rb,
lib/llm/repl/input/char.rb,
lib/llm/repl/input/cache.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
The LLM::Repl::Input class manages the editable input line shown at the bottom of the REPL.
Defined Under Namespace
Constant Summary collapse
- CTRL =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
{ A: Curses::KEY_CTRL_A, E: Curses::KEY_CTRL_E, F: Curses::KEY_CTRL_F, K: Curses::KEY_CTRL_K, Y: Curses::KEY_CTRL_Y, D: Curses::KEY_CTRL_D, P: Curses::KEY_CTRL_P, N: Curses::KEY_CTRL_N }
- REPEATS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
This hash tracks how many times a given key was pressed repeatedly without being interrupted by another key. The previous key is reset to 0 when a different key is pressed.
{}
- UP =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Curses::Key::UP
- DOWN =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Curses::Key::DOWN
- LEFT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Curses::Key::LEFT
- RIGHT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Curses::Key::RIGHT
- PGUP =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Curses::KEY_PPAGE
- PGDOWN =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Curses::KEY_NPAGE
- KEY_RESIZE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Curses::KEY_RESIZE
- TAB =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
9- ESC =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
27- ENTER =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
10- BACKSPACE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
127- PASTE_THRESHOLD =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Threshold in seconds. If characters arrive faster than this, we assume the user is pasting multi-line text. Human typing is ~150–300ms per key, so 50ms reliably distinguishes a paste from manual typing.
0.05
Instance Attribute Summary collapse
- #paste ⇒ void writeonly private
Instance Method Summary collapse
- #autocomplete ⇒ void private
-
#buffer ⇒ String
private
The input buffer as an ordinary string.
-
#cursor_pos ⇒ Array(Integer, Integer)
private
Returns the cursor position as [line, column] within the visible viewport.
-
#delete ⇒ void
private
Deletes the character at the cursor, or consumes the break and pulls up the next row at the end of a row.
- #height ⇒ Integer private
- #initialize(repl, options = {}) ⇒ LLM::Repl::Input constructor private
- #kill ⇒ void private
-
#lines ⇒ Array<String>
private
Returns the visible lines of the input buffer.
- #move_end ⇒ void private
- #move_forward ⇒ void private
- #move_left ⇒ void private
- #move_right ⇒ void private
- #move_start ⇒ void private
- #on_char(window, char, now) ⇒ Symbol? private
- #paste? ⇒ Boolean private
- #restore ⇒ void private
- #take ⇒ String private
- #to_s ⇒ String private
Constructor Details
#initialize(repl, options = {}) ⇒ LLM::Repl::Input
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/llm/repl/input.rb', line 60 def initialize(repl, = {}) @repl = repl @name = repl.name @agent = repl.agent @provider = @agent.llm.name @rows = [Row.new] @cursor = [0, 0] @scroll = 0 @height = .fetch(:height, 3) @last_char_at = nil @memory = @agent..select(&:user?).map(&:content) @walker = Walker.new(@memory) @paste = false end |
Instance Attribute Details
#paste=(value) ⇒ void (writeonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
55 56 57 |
# File 'lib/llm/repl/input.rb', line 55 def paste=(value) @paste = value end |
Instance Method Details
#autocomplete ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/llm/repl/input.rb', line 256 def autocomplete return unless text[0] == "/" ## # There are two kinds of an autocomplete # that can take place. The first kind # autocompletes command names, and the # second kind autocompletes command # arguments. # # Command arguments are given to the # `Command#complete(...)` method and # returns an array of potential candidates. if text.include?(" ") complete(:argument) else complete(:command) end end |
#buffer ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns The input buffer as an ordinary string.
78 79 80 |
# File 'lib/llm/repl/input.rb', line 78 def buffer text end |
#cursor_pos ⇒ Array(Integer, Integer)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the cursor position as [line, column] within the visible viewport.
207 208 209 210 211 212 |
# File 'lib/llm/repl/input.rb', line 207 def cursor_pos scroll! row, col = @cursor col += prompt.size if row.zero? [row - @scroll, col] end |
#delete ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Deletes the character at the cursor, or consumes the break and pulls up the next row at the end of a row.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/llm/repl/input.rb', line 292 def delete row, col = @cursor if col < @rows[row].chars.size @rows[row].chars.delete_at(col) elsif row < @rows.size - 1 nxt = @rows[row + 1] ## # A wrapped row was split at a space; restore it so # the merged words don't run together. @rows[row].chars << Char.new(" ") if nxt.break_type == :space @rows[row].chars.concat(nxt.chars) @rows.delete_at(row + 1) end end |
#height ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
187 188 189 |
# File 'lib/llm/repl/input.rb', line 187 def height @height end |
#kill ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
277 278 279 280 281 282 283 284 285 |
# File 'lib/llm/repl/input.rb', line 277 def kill row, col = @cursor tail = @rows[row].chars[col..].map(&:to_s).join tail += @rows[(row + 1)..].map(&:to_s).join("\n") @copy = tail @rows[row].chars.slice!(col..) @rows = @rows[0..row] @cursor = [row, col] end |
#lines ⇒ Array<String>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the visible lines of the input buffer. The viewport follows the cursor so the cursor line is always visible.
195 196 197 198 199 200 201 |
# File 'lib/llm/repl/input.rb', line 195 def lines scroll! visible = @rows[@scroll, height] || [] visible.each_with_index.map do |row, i| (i.zero? && @scroll.zero? ? prompt : "") + row.to_s end end |
#move_end ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
222 223 224 |
# File 'lib/llm/repl/input.rb', line 222 def move_end @cursor = [@rows.size - 1, @rows.last.chars.size] end |
#move_forward ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
250 251 252 |
# File 'lib/llm/repl/input.rb', line 250 def move_forward move_right end |
#move_left ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
228 229 230 231 232 233 234 235 |
# File 'lib/llm/repl/input.rb', line 228 def move_left row, col = @cursor @cursor = if col > 0 then [row, col - 1] elsif row > 0 then [row - 1, @rows[row - 1].chars.size] else [0, 0] end end |
#move_right ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
239 240 241 242 243 244 245 246 |
# File 'lib/llm/repl/input.rb', line 239 def move_right row, col = @cursor @cursor = if col < @rows[row].chars.size then [row, col + 1] elsif row < @rows.size - 1 then [row + 1, 0] else [row, col] end end |
#move_start ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
216 217 218 |
# File 'lib/llm/repl/input.rb', line 216 def move_start @cursor = [0, 0] end |
#on_char(window, char, now) ⇒ Symbol?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/llm/repl/input.rb', line 86 def on_char(window, char, now) is_paste = lambda { @last_char_at and (now - @last_char_at) < PASTE_THRESHOLD } if char and @char != char REPEATS[@char] = 0 end if PGUP == char (window.rows - 3).times { window.scroll_up } :pageup elsif PGDOWN == char (window.rows - 3).times { window.scroll_down } :pagedown elsif TAB == char autocomplete :tab elsif ESC == char @agent.cancel! elsif CTRL[:P] == char set(text: @walker.prev.dup) :ctrl_p elsif CTRL[:N] == char set(text: @walker.next.dup) :ctrl_n elsif CTRL[:D] == char delete :ctrl_d elsif CTRL[:A] == char move_start :ctrl_a elsif CTRL[:E] == char move_end :ctrl_e elsif CTRL[:F] == char move_forward :ctrl_f elsif CTRL[:Y] == char restore :ctrl_y elsif CTRL[:K] == char kill :ctrl_k elsif char == LEFT move_left :left elsif char == RIGHT move_right :right elsif char == BACKSPACE backspace :backspace elsif char == ENTER if @paste = is_paste.() insert("\n") :char else @memory.push(text) @walker.cursor = @memory.size :submit end elsif char == KEY_RESIZE window.resize :resize elsif char == UP window.scroll_up :up elsif char == DOWN window.scroll_down :down elsif String === char ## # A paste arrives as a burst of fast characters. Flag it so the # next loop iteration drains the rest through read_paste in a # single shot, instead of inserting one character at a time and # redrawing after each. A string that is already the product of # read_paste (multi-character) is inserted as-is, one char at a # time, so every newline creates a row and every Char stays a # single character. @paste = true if char.length == 1 && is_paste.() char.each_char { |c| insert(c) } :char else nil end ensure if char REPEATS[char] += 1 @last_char_at = now @char = char end end |
#paste? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
337 338 339 |
# File 'lib/llm/repl/input.rb', line 337 def paste? @paste end |
#restore ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/llm/repl/input.rb', line 309 def restore return unless @copy row, col = @cursor @copy.each_char do |char| if char == "\n" @rows.insert(row + 1, Row.new(:newline)) row += 1 col = 0 else @rows[row].chars.insert(col, Char.new(char)) col += 1 end end @cursor = [row, col] end |
#take ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
327 328 329 330 331 332 333 |
# File 'lib/llm/repl/input.rb', line 327 def take text.tap do @rows = [Row.new] @cursor = [0, 0] @scroll = 0 end end |
#to_s ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
178 179 180 181 182 183 |
# File 'lib/llm/repl/input.rb', line 178 def to_s @rows .each_with_index .map { |row, i| (i.zero? ? prompt : "") + row.to_s } .join("\n") end |