Class: Foruiman::OutputLine

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

Overview

A single editable terminal row. Used only after a child emits a horizontal cursor control; ordinary append-only logs keep their fast streaming path.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text) ⇒ OutputLine

Returns a new instance of OutputLine.



11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/foruiman/output_line.rb', line 11

def initialize(text)
  @cells = []
  @cursor = 0
  @cost = 0
  styles = Foruiman::ANSI::Styles.new
  text.scan(/\e\[[0-9;:]*m|\X/).each do |token|
    if token.match?(Foruiman::ANSI::SGR)
      styles.apply(token)
    else
      write(token, styles.prefix)
    end
  end
end

Instance Attribute Details

#cost ⇒ Object (readonly)

Returns the value of attribute cost.



9
10
11
# File 'lib/foruiman/output_line.rb', line 9

def cost
  @cost
end

Instance Method Details

#control(token, limit:) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/foruiman/output_line.rb', line 41

def control(token, limit:)
  @cost = to_s.bytesize
  number = token[/\d+/].to_i
  amount = [number, 1].max
  case token
  when "\r" then @cursor = 0
  when "\b" then @cursor = [@cursor - 1, 0].max
  else
    case token[-1]
    when "G" then @cursor = (amount - 1).clamp(0, limit)
    when "C" then @cursor = (@cursor + amount).clamp(0, limit)
    when "D" then @cursor = [@cursor - amount, 0].max
    when "K" then erase(number)
    end
  end
end

#to_s ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/foruiman/output_line.rb', line 58

def to_s
  style = ""
  @cells.each_with_object(+"") do |cell, text|
    next if cell == :continuation

    character, next_style = cell || [" ", ""]
    if next_style != style
      text << Foruiman::ANSI::RESET unless style.empty?
      text << next_style
      style = next_style
    end
    text << character
  end
end

#write(character, style) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/foruiman/output_line.rb', line 25

def write(character, style)
  width = Unicode::DisplayWidth.of(character, emoji: :all)
  if width.zero? && @cursor.positive?
    index = @cursor - 1
    index -= 1 while index.positive? && @cells[index] == :continuation
    @cells[index][0] += character if @cells[index].is_a?(Array)
  else
    width.times { |offset| clear_cell(@cursor + offset) }
    @cells[@cursor] = [character, style]
    (1...width).each { |offset| @cells[@cursor + offset] = :continuation }
    @cursor += width
  end
  # Conservative, constant-time bound including style transitions.
  @cost += character.bytesize + style.bytesize + Foruiman::ANSI::RESET.bytesize
end