Class: SwarmCLI::V3::RawInputReader
- Inherits:
-
Object
- Object
- SwarmCLI::V3::RawInputReader
- Defined in:
- lib/swarm_cli/v3/raw_input_reader.rb
Overview
This class directly controls terminal state via stty. Always call #stop or #restore_terminal before exiting.
Raw terminal input reader with history support.
Manages raw terminal mode and reads characters in a background Thread, producing events on a Thread::Queue. The Async scheduler intercepts Thread#value in #next_event, yielding the fiber so the agent task can run concurrently.
Events: [:line, text], [:interrupt], [:eof], [:exit]
Instance Method Summary collapse
-
#initialize(display) ⇒ RawInputReader
constructor
A new instance of RawInputReader.
-
#load_history_file(path) ⇒ void
Load history from a file (one entry per line).
-
#next_event ⇒ Array
Returns the next input event, yielding the Async fiber while waiting.
-
#restore_terminal ⇒ void
Restore terminal to its original state (idempotent).
-
#save_history_file(path, max: 1000) ⇒ void
Save history to a file, keeping the last
maxentries. -
#start ⇒ void
Enter raw terminal mode and start the input thread.
-
#stop ⇒ void
Stop the input thread and restore terminal state.
Constructor Details
#initialize(display) ⇒ RawInputReader
Returns a new instance of RawInputReader.
18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/swarm_cli/v3/raw_input_reader.rb', line 18 def initialize(display) @display = display @queue = Thread::Queue.new @history = [] @history_index = nil @saved_buffer = nil @original_stty = nil @thread = nil @running = false @at_exit_registered = false @last_ctrl_c = nil @last_escape = nil end |
Instance Method Details
#load_history_file(path) ⇒ void
This method returns an undefined value.
Load history from a file (one entry per line).
82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/swarm_cli/v3/raw_input_reader.rb', line 82 def load_history_file(path) return unless File.exist?(path) File.open(path, "r:UTF-8") do |f| f.each_line do |line| line = line.chomp @history << line unless line.empty? end end rescue Errno::ENOENT, Errno::EACCES nil end |
#next_event ⇒ Array
Returns the next input event, yielding the Async fiber while waiting.
Async’s scheduler intercepts Thread#value and suspends the fiber, letting the agent task run while we wait for user input.
74 75 76 |
# File 'lib/swarm_cli/v3/raw_input_reader.rb', line 74 def next_event Thread.new { @queue.pop }.value end |
#restore_terminal ⇒ void
This method returns an undefined value.
Restore terminal to its original state (idempotent).
61 62 63 64 65 66 |
# File 'lib/swarm_cli/v3/raw_input_reader.rb', line 61 def restore_terminal return unless @original_stty && !@original_stty.empty? system("stty #{@original_stty} 2>/dev/null") @original_stty = nil end |
#save_history_file(path, max: 1000) ⇒ void
This method returns an undefined value.
Save history to a file, keeping the last max entries.
100 101 102 103 104 105 106 |
# File 'lib/swarm_cli/v3/raw_input_reader.rb', line 100 def save_history_file(path, max: 1000) FileUtils.mkdir_p(File.dirname(path)) lines = @history.last(max) File.open(path, "w", 0o600) { |f| lines.each { |l| f.puts(l) } } rescue Errno::EACCES, Errno::ENOENT nil end |
#start ⇒ void
This method returns an undefined value.
Enter raw terminal mode and start the input thread.
35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/swarm_cli/v3/raw_input_reader.rb', line 35 def start @original_stty = %x(stty -g 2>/dev/null).chomp system("stty -icanon -echo -isig min 1 2>/dev/null") @running = true @thread = Thread.new { read_loop } return if @at_exit_registered at_exit { restore_terminal } @at_exit_registered = true end |
#stop ⇒ void
This method returns an undefined value.
Stop the input thread and restore terminal state.
50 51 52 53 54 55 56 |
# File 'lib/swarm_cli/v3/raw_input_reader.rb', line 50 def stop @running = false @thread&.kill @thread&.join(0.1) @thread = nil restore_terminal end |