Class: Clacky::UI2::Components::InlineInput

Inherits:
Object
  • Object
show all
Includes:
LineEditor
Defined in:
lib/clacky/ui2/components/inline_input.rb

Overview

InlineInput provides inline input for confirmations and simple prompts Renders at the end of output area, not at fixed bottom position

Constant Summary

Constants included from LineEditor

LineEditor::MAX_CONTENT_WIDTH_RATIO

Instance Attribute Summary collapse

Attributes included from LineEditor

#cursor_position

Instance Method Summary collapse

Methods included from LineEditor

#backspace, #calculate_display_width, #char_display_width, #clear_line_content, #current_line, #cursor_column, #cursor_end, #cursor_home, #cursor_left, #cursor_position_with_wrap, #cursor_right, #delete_char, #initialize_line_editor, #insert_char, #insert_text, #kill_to_end, #kill_to_start, #kill_word, #render_line_segment_with_cursor, #render_line_with_cursor, #set_line, #strip_ansi_codes, #wrap_line

Constructor Details

#initialize(prompt: "", default: nil) ⇒ InlineInput

Returns a new instance of InlineInput.



15
16
17
18
19
20
21
22
23
24
# File 'lib/clacky/ui2/components/inline_input.rb', line 15

def initialize(prompt: "", default: nil)
  initialize_line_editor
  @prompt = prompt
  @default_value = default
  @active = false
  @result_queue = nil
  @paste_counter = 0
  @paste_placeholders = {}
  @continuation_prompt = "> "  # Continuation prompt for wrapped lines
end

Instance Attribute Details

#default_valueObject (readonly)

Returns the value of attribute default_value.



13
14
15
# File 'lib/clacky/ui2/components/inline_input.rb', line 13

def default_value
  @default_value
end

#promptObject (readonly)

Returns the value of attribute prompt.



13
14
15
# File 'lib/clacky/ui2/components/inline_input.rb', line 13

def prompt
  @prompt
end

Instance Method Details

#active?Boolean

Check if active

Returns:

  • (Boolean)


36
37
38
# File 'lib/clacky/ui2/components/inline_input.rb', line 36

def active?
  @active
end

#collectString

Activate inline input and wait for user input

Returns:

  • (String)

    User input



28
29
30
31
32
33
# File 'lib/clacky/ui2/components/inline_input.rb', line 28

def collect
  @active = true
  @result_queue = Queue.new
  # Don't set default as initial text - start empty
  @result_queue.pop
end

#cursor_colInteger

Get cursor column position

Returns:

  • (Integer)

    Column position



146
147
148
# File 'lib/clacky/ui2/components/inline_input.rb', line 146

def cursor_col
  cursor_column(@prompt)
end

#cursor_position_for_display(width = TTY::Screen.width) ⇒ Array<Integer>

Get cursor position for display (considering line wrapping and continuation prompt)

Parameters:

  • width (Integer) (defaults to: TTY::Screen.width)

    Terminal width

Returns:

  • (Array<Integer>)

    Row and column position (0-indexed)



153
154
155
156
157
# File 'lib/clacky/ui2/components/inline_input.rb', line 153

def cursor_position_for_display(width = TTY::Screen.width)
  # Use effective content width (respecting MAX_CONTENT_WIDTH_RATIO)
  content_width = effective_content_width(width)
  cursor_position_with_wrap(@prompt, content_width, @continuation_prompt)
end

#deactivateObject

Deactivate inline input



174
175
176
177
# File 'lib/clacky/ui2/components/inline_input.rb', line 174

def deactivate
  @active = false
  @result_queue = nil
end

#expand_placeholders(text) ⇒ Object



192
193
194
# File 'lib/clacky/ui2/components/inline_input.rb', line 192

def expand_placeholders(text)
  super(text, @paste_placeholders)
end

#handle_cancelObject



196
197
198
199
200
201
202
# File 'lib/clacky/ui2/components/inline_input.rb', line 196

def handle_cancel
  queue = @result_queue
  deactivate
  queue&.push(nil)

  { action: :cancel }
end

#handle_enterObject



180
181
182
183
184
185
186
187
188
189
190
# File 'lib/clacky/ui2/components/inline_input.rb', line 180

def handle_enter
  result = expand_placeholders(current_line)
  # If empty and has default, use default
  result = @default_value.to_s if result.empty? && @default_value

  queue = @result_queue
  deactivate
  queue&.push(result)

  { action: :submit, result: result }
end

#handle_key(key) ⇒ Hash

Handle keyboard input

Parameters:

  • key (Symbol, String)

    Key input

Returns:

  • (Hash)

    Result with action



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
# File 'lib/clacky/ui2/components/inline_input.rb', line 43

def handle_key(key)
  return { action: nil } unless @active

  case key
  when Hash
    if key[:type] == :rapid_input
      # Handle multi-line paste with placeholder
      pasted_text = key[:text]
      pasted_lines = pasted_text.split(/\r\n|\r|\n/)

      if pasted_lines.size > 1
        # Multi-line paste - use placeholder
        @paste_counter += 1
        placeholder = "[##{@paste_counter} Paste Text]"
        @paste_placeholders[placeholder] = pasted_text
        insert_text(placeholder)
      else
        # Single line - insert directly
        insert_text(pasted_text)
      end
    end
    { action: :update }
  when :enter
    handle_enter
  when :backspace
    backspace
    { action: :update }
  when :delete
    delete_char
    { action: :update }
  when :left_arrow, :ctrl_b
    cursor_left
    { action: :update }
  when :right_arrow, :ctrl_f
    cursor_right
    { action: :update }
  when :home, :ctrl_a
    cursor_home
    { action: :update }
  when :end, :ctrl_e
    cursor_end
    { action: :update }
  when :ctrl_k
    kill_to_end
    { action: :update }
  when :ctrl_u
    kill_to_start
    { action: :update }
  when :ctrl_w
    kill_word
    { action: :update }
  when :shift_tab
    handle_shift_tab
  when :ctrl_o
    handle_toggle_expand
  when :ctrl_c
    handle_cancel
  when :escape
    handle_cancel
  else
    if key.is_a?(String) && key.length >= 1 && key.ord >= 32
      insert_char(key)
      { action: :update }
    else
      { action: nil }
    end
  end
end

#handle_shift_tabObject



204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/clacky/ui2/components/inline_input.rb', line 204

def handle_shift_tab
  # Auto-confirm as yes (or use default if it's true)
  result = if @default_value == true || @default_value.to_s.downcase == "yes"
    @default_value.to_s
  else
    "yes"
  end

  queue = @result_queue
  deactivate
  queue&.push(result)

  { action: :toggle_mode }
end

#line_count(width = TTY::Screen.width) ⇒ Integer

Get the number of lines this input will occupy when rendered

Parameters:

  • width (Integer) (defaults to: TTY::Screen.width)

    Terminal width

Returns:

  • (Integer)

    Number of lines



162
163
164
165
166
167
168
169
170
171
# File 'lib/clacky/ui2/components/inline_input.rb', line 162

def line_count(width = TTY::Screen.width)
  # Use effective content width (respecting MAX_CONTENT_WIDTH_RATIO)
  content_width = effective_content_width(width)
  prompt_width = calculate_display_width(strip_ansi_codes(@prompt))
  available_width = content_width - prompt_width
  return 1 if available_width <= 0

  segments = wrap_line(@line, available_width)
  segments.size
end

#renderString

Render inline input with prompt and cursor

Returns:

  • (String)

    Rendered line (may wrap to multiple lines)



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
# File 'lib/clacky/ui2/components/inline_input.rb', line 114

def render
  width = TTY::Screen.width
  # Use effective content width (respecting MAX_CONTENT_WIDTH_RATIO)
  content_width = effective_content_width(width)
  prompt_width = calculate_display_width(strip_ansi_codes(@prompt))
  available_width = content_width - prompt_width

  # Get wrapped segments
  wrapped_segments = wrap_line(@line, available_width)

  # Build rendered output with cursor
  output = ""

  wrapped_segments.each_with_index do |segment, idx|
    prefix = if idx == 0
      @prompt
    else
      "> "  # Continuation prompt indicator
    end

    # Render segment with cursor if needed
    segment_text = render_line_segment_with_cursor(@line, segment[:start], segment[:end])

    output += "#{prefix}#{segment_text}"
    output += "\n" unless idx == wrapped_segments.size - 1
  end

  output
end