Class: TUI::InputBuffer

Inherits:
Object
  • Object
show all
Defined in:
lib/tui/input_buffer.rb

Overview

Manages editable text with cursor position tracking. Supports multiline input with newline insertion, cursor navigation across physical lines, and standard text editing operations.

Pure logic object with no rendering or framework dependencies.

Constant Summary collapse

MAX_LENGTH =
10_000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeInputBuffer

Returns a new instance of InputBuffer.



14
15
16
17
# File 'lib/tui/input_buffer.rb', line 14

def initialize
  @text = ""
  @cursor_pos = 0
end

Instance Attribute Details

#cursor_posObject (readonly)

Returns the value of attribute cursor_pos.



12
13
14
# File 'lib/tui/input_buffer.rb', line 12

def cursor_pos
  @cursor_pos
end

#textObject (readonly)

Returns the value of attribute text.



12
13
14
# File 'lib/tui/input_buffer.rb', line 12

def text
  @text
end

Instance Method Details

#backspaceBoolean

Deletes the character before the cursor.

Returns:

  • (Boolean)

    true if a character was deleted



71
72
73
74
75
76
77
# File 'lib/tui/input_buffer.rb', line 71

def backspace
  return false if @cursor_pos == 0

  @text = "#{@text[0...@cursor_pos - 1]}#{@text[@cursor_pos..]}"
  @cursor_pos -= 1
  true
end

#clamp_cursorvoid

This method returns an undefined value.

Ensures cursor stays within valid bounds after external state changes.



46
47
48
# File 'lib/tui/input_buffer.rb', line 46

def clamp_cursor
  @cursor_pos = @cursor_pos.clamp(0, @text.length)
end

#clearvoid

This method returns an undefined value.

Resets the buffer to empty state.



21
22
23
24
# File 'lib/tui/input_buffer.rb', line 21

def clear
  @text = ""
  @cursor_pos = 0
end

#consumeString

Returns stripped text and clears the buffer for message submission.

Returns:

  • (String)

    the trimmed input text



28
29
30
31
32
# File 'lib/tui/input_buffer.rb', line 28

def consume
  content = @text.strip
  clear
  content
end

#cursor_locationArray(Integer, Integer)

Returns [line_index, column] for current cursor position.

Returns:

  • (Array(Integer, Integer))
    line_index, column

    for current cursor position



157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/tui/input_buffer.rb', line 157

def cursor_location
  return [0, 0] if @text.empty?

  lines = @text.split("\n", -1)
  pos = 0
  lines.each_with_index do |line, index|
    len = line.length
    return [index, @cursor_pos - pos] if @cursor_pos <= pos + len
    pos += len + 1
  end
  [lines.length - 1, lines.last.length]
end

#deleteBoolean

Deletes the character at the cursor (forward delete).

Returns:

  • (Boolean)

    true if a character was deleted



81
82
83
84
85
86
# File 'lib/tui/input_buffer.rb', line 81

def delete
  return false if @cursor_pos >= @text.length

  @text = "#{@text[0...@cursor_pos]}#{@text[@cursor_pos + 1..]}"
  true
end

#full?Boolean

Returns whether the buffer has reached MAX_LENGTH.

Returns:

  • (Boolean)

    whether the buffer has reached MAX_LENGTH



40
41
42
# File 'lib/tui/input_buffer.rb', line 40

def full?
  @text.length >= MAX_LENGTH
end

#insert(char) ⇒ Boolean

Returns true if inserted, false if result would exceed MAX_LENGTH.

Parameters:

  • char (String)

    character(s) to insert at cursor

Returns:

  • (Boolean)

    true if inserted, false if result would exceed MAX_LENGTH



52
53
54
55
56
57
58
# File 'lib/tui/input_buffer.rb', line 52

def insert(char)
  return false if @text.length + char.length > MAX_LENGTH

  @text = "#{@text[0...@cursor_pos]}#{char}#{@text[@cursor_pos..]}"
  @cursor_pos += char.length
  true
end

#line_start_positionsArray<Integer>

Maps each physical line to its starting offset within the text buffer. Position after each newline marks the start of the next line.

Returns:

  • (Array<Integer>)

    start position of each physical line



173
174
175
176
177
178
179
# File 'lib/tui/input_buffer.rb', line 173

def line_start_positions
  positions = [0]
  @text.each_char.with_index do |char, offset|
    positions << (offset + 1) if char == "\n"
  end
  positions
end

#move_downBoolean

Moves cursor down one physical line, preserving column position. Clamps column to the target line’s length when the next line is shorter.

Returns:

  • (Boolean)

    true if cursor moved



145
146
147
148
149
150
151
152
153
154
# File 'lib/tui/input_buffer.rb', line 145

def move_down
  lines = @text.split("\n", -1)
  line_idx, col = cursor_location
  return false if line_idx >= lines.length - 1

  next_idx = line_idx + 1
  target_col = [col, lines[next_idx].length].min
  @cursor_pos = line_start_positions[next_idx] + target_col
  true
end

#move_endBoolean

Moves cursor to the end of the current physical line.

Returns:

  • (Boolean)

    true if cursor moved



119
120
121
122
123
124
125
126
# File 'lib/tui/input_buffer.rb', line 119

def move_end
  newline_pos = @text.index("\n", @cursor_pos)
  target = newline_pos || @text.length
  return false if @cursor_pos == target

  @cursor_pos = target
  true
end

#move_homeBoolean

Moves cursor to the start of the current physical line.

Returns:

  • (Boolean)

    true if cursor moved



106
107
108
109
110
111
112
113
114
115
# File 'lib/tui/input_buffer.rb', line 106

def move_home
  return false if @cursor_pos == 0

  last_newline = @text.rindex("\n", @cursor_pos - 1)
  target = last_newline ? last_newline + 1 : 0
  return false if @cursor_pos == target

  @cursor_pos = target
  true
end

#move_leftBoolean

Returns true if cursor moved.

Returns:

  • (Boolean)

    true if cursor moved



89
90
91
92
93
94
# File 'lib/tui/input_buffer.rb', line 89

def move_left
  return false if @cursor_pos == 0

  @cursor_pos -= 1
  true
end

#move_rightBoolean

Returns true if cursor moved.

Returns:

  • (Boolean)

    true if cursor moved



97
98
99
100
101
102
# File 'lib/tui/input_buffer.rb', line 97

def move_right
  return false if @cursor_pos >= @text.length

  @cursor_pos += 1
  true
end

#move_upBoolean

Moves cursor up one physical line, preserving column position. Clamps column to the target line’s length when the previous line is shorter.

Returns:

  • (Boolean)

    true if cursor moved



131
132
133
134
135
136
137
138
139
140
# File 'lib/tui/input_buffer.rb', line 131

def move_up
  line_idx, col = cursor_location
  return false if line_idx == 0

  lines = @text.split("\n", -1)
  prev_idx = line_idx - 1
  target_col = [col, lines[prev_idx].length].min
  @cursor_pos = line_start_positions[prev_idx] + target_col
  true
end

#multiline?Boolean

Returns whether the buffer contains any newline characters.

Returns:

  • (Boolean)

    whether the buffer contains any newline characters



35
36
37
# File 'lib/tui/input_buffer.rb', line 35

def multiline?
  @text.include?("\n")
end

#newlineBoolean

Returns true if a newline was inserted.

Returns:

  • (Boolean)

    true if a newline was inserted



61
62
63
64
65
66
67
# File 'lib/tui/input_buffer.rb', line 61

def newline
  return false if full?

  @text = "#{@text[0...@cursor_pos]}\n#{@text[@cursor_pos..]}"
  @cursor_pos += 1
  true
end