Class: Foruiman::TUI::InputLine

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

Constant Summary collapse

MAX_BYTES =

Leave room for the newline in the child's canonical terminal buffer.

4095
HISTORY_SIZE =
100
SEQUENCES =
{
  "\e[A" => :history_previous, "\e[B" => :history_next,
  "\e[C" => :right, "\e[D" => :left,
  "\e[H" => :home, "\e[F" => :end,
  "\e[1~" => :home, "\e[4~" => :end, "\e[3~" => :delete
}.freeze
CONTROLS =
{
  1 => :home, 3 => :interrupt, 4 => :eof, 5 => :end, 8 => :backspace,
  10 => :submit, 13 => :submit, 18 => :history_previous, 21 => :clear, 23 => :delete_word,
  24 => :detach, 127 => :backspace
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ InputLine

Returns a new instance of InputLine.



22
23
24
25
26
27
28
29
# File 'lib/foruiman/tui/input_line.rb', line 22

def initialize
  @text = +""
  @cursor = 0
  @bytes = +"".b
  @history = []
  @history_index = nil
  @draft = nil
end

Instance Attribute Details

#cursor ⇒ Object (readonly)

Returns the value of attribute cursor.



20
21
22
# File 'lib/foruiman/tui/input_line.rb', line 20

def cursor
  @cursor
end

#text ⇒ Object (readonly)

Returns the value of attribute text.



20
21
22
# File 'lib/foruiman/tui/input_line.rb', line 20

def text
  @text
end

Instance Method Details

#clear ⇒ Object



82
83
84
85
86
# File 'lib/foruiman/tui/input_line.rb', line 82

def clear
  replace("")
  @history_index = nil
  @draft = nil
end

#feed(bytes) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
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
# File 'lib/foruiman/tui/input_line.rb', line 31

def feed(bytes)
  bytes, detach, = bytes.b.partition("\x18")
  @bytes << bytes
  events = []
  until @bytes.empty?
    if @bytes.start_with?("\e")
      if @bytes.bytesize > 64 && incomplete_escape?
        @bytes.clear
        break
      end
      break if incomplete_escape?

      sequence = SEQUENCES.keys.find { |candidate| @bytes.start_with?(candidate) }
      if sequence
        edit(SEQUENCES.fetch(sequence))
        @bytes.slice!(0, sequence.bytesize)
      else
        match = @bytes.match(%r{\A\e(?:\[[0-?]*[ -/]*[@-~]|O.|.)}m)
        @bytes.slice!(0, match ? match[0].bytesize : 1)
      end
      next
    end

    byte = @bytes.getbyte(0)
    if @after_cr && byte == 10
      @bytes.slice!(0, 1)
      @after_cr = false
      next
    end
    @after_cr = byte == 13
    if CONTROLS.key?(byte)
      @bytes.slice!(0, 1)
      event = edit(CONTROLS.fetch(byte))
      events << event if event
    elsif byte < 32
      @bytes.slice!(0, 1)
    else
      character = next_character
      break unless character

      insert(character)
    end
  end
  unless detach.empty?
    @bytes.clear
    clear
    events << :detach
  end
  events
end