Class: LLM::Repl::Input Private

Inherits:
Object
  • Object
show all
Defined in:
lib/llm/repl/input.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.

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
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

Instance Method Summary collapse

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.

Parameters:



59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/llm/repl/input.rb', line 59

def initialize(repl, options = {})
  @name = repl.name
  @agent = repl.agent
  @provider = @agent.llm.name
  @buffer = +""
  @cursor = 0
  @scroll = 0
  @height = options.fetch(:height, 3)
  @last_char_at = nil
  @memory = @agent.messages.select(&:user?).map(&:content)
  @walker = Walker.new(@memory)
  @paste = false
end

Instance Attribute Details

#bufferString (readonly)

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:

  • (String)


49
50
51
# File 'lib/llm/repl/input.rb', line 49

def buffer
  @buffer
end

#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.

Parameters:

  • value (Boolean)


54
55
56
# File 'lib/llm/repl/input.rb', line 54

def paste=(value)
  @paste = value
end

Instance Method Details

#autocompletevoid

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.



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/llm/repl/input.rb', line 230

def autocomplete
  return unless @buffer[0] == "/"
  ##
  # This method implements a simple autocomplete
  # that supports cycling through all known
  # commands. When given tab in quick succession,
  # we cycle to the nearest neighbour for the last
  # full match. However, it's not based on similarity,
  # it's just the next element in the array.
  keys = LLM::Command.registry.keys
  candidates = LLM::Command.complete(@buffer)
  if REPEATS[TAB] >= 1
    candidate = keys[keys.index(candidates[0]) + 1] || keys[0]
  else
    candidate = candidates[0]
  end
  @buffer = "/#{candidate}"
  @cursor = @buffer.size
end

#cursorInteger

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:

  • (Integer)


165
166
167
# File 'lib/llm/repl/input.rb', line 165

def cursor
  prompt.size + @cursor
end

#cursor_posArray(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.

Returns:

  • (Array(Integer, Integer))


190
191
192
193
194
195
196
# File 'lib/llm/repl/input.rb', line 190

def cursor_pos
  scroll!
  before = to_s[0...cursor]
  line  = before.count("\n")
  col   = cursor - (before.rindex("\n") || -1) - 1
  [line - @scroll, col]
end

#deletevoid

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.



260
261
262
263
# File 'lib/llm/repl/input.rb', line 260

def delete
  @buffer[@cursor] = ""
  @cursor = [0, @cursor].max
end

#heightInteger

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:

  • (Integer)


171
172
173
# File 'lib/llm/repl/input.rb', line 171

def height
  @height
end

#killvoid

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.



252
253
254
255
256
# File 'lib/llm/repl/input.rb', line 252

def kill
  @copy = @buffer.slice(@cursor, @buffer.size)
  @buffer[@cursor, @buffer.size] = ""
  @cursor = @buffer.size
end

#linesArray<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, split by newlines. The viewport follows the cursor so the cursor line is always visible.

Returns:

  • (Array<String>)


180
181
182
183
184
# File 'lib/llm/repl/input.rb', line 180

def lines
  scroll!
  chunks = to_s.split("\n", -1)
  chunks[@scroll, height] || []
end

#move_endvoid

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.



206
207
208
# File 'lib/llm/repl/input.rb', line 206

def move_end
  @cursor = [0, @buffer.size].max
end

#move_forwardvoid

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.



224
225
226
# File 'lib/llm/repl/input.rb', line 224

def move_forward
  @cursor = [0, @cursor + 1].max
end

#move_leftvoid

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.



212
213
214
# File 'lib/llm/repl/input.rb', line 212

def move_left
  @cursor = [@cursor - 1, 0].max
end

#move_rightvoid

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.



218
219
220
# File 'lib/llm/repl/input.rb', line 218

def move_right
  @cursor = [@cursor + 1, @buffer.size].min
end

#move_startvoid

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.



200
201
202
# File 'lib/llm/repl/input.rb', line 200

def move_start
  @cursor = 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.

Parameters:

Returns:

  • (Symbol, nil)


77
78
79
80
81
82
83
84
85
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
# File 'lib/llm/repl/input.rb', line 77

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
    @buffer = @walker.prev.dup
    @cursor = @buffer.size
    :ctrl_p
  elsif CTRL[:N] == char
    @buffer = @walker.next.dup
    @cursor = @buffer.size
    :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 BACKSPACE == char
    backspace
    :backspace
  elsif ENTER == char
    if @paste = is_paste.()
      insert("\n")
      :char
    else
      @memory.push(@buffer.dup)
      @walker.cursor = @memory.size
      :submit
    end
  elsif char == UP
    window.scroll_up
    :up
  elsif char == DOWN
    window.scroll_down
    :down
  elsif String === char
    insert(char)
    :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.

Returns:

  • (Boolean)


285
286
287
# File 'lib/llm/repl/input.rb', line 285

def paste?
  @paste
end

#restorevoid

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.



267
268
269
270
271
# File 'lib/llm/repl/input.rb', line 267

def restore
  return unless @copy
  @buffer.insert(@cursor, @copy)
  @cursor += @copy.size
end

#takeString

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:

  • (String)


275
276
277
278
279
280
281
# File 'lib/llm/repl/input.rb', line 275

def take
  @buffer.dup.tap do
    @buffer.clear
    @cursor = 0
    @scroll = 0
  end
end

#to_sString

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:

  • (String)


159
160
161
# File 'lib/llm/repl/input.rb', line 159

def to_s
  "#{prompt}#{@buffer}"
end