Class: Hansi::StringRenderer

Inherits:
Object
  • Object
show all
Defined in:
lib/hansi/string_renderer.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(markup = {}, theme: :default, escape: ?\\, tags: false, mode: Hansi.mode) ⇒ StringRenderer

Returns a new instance of StringRenderer.



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/hansi/string_renderer.rb', line 21

def initialize(markup = {}, theme: :default, escape: ?\\, tags: false, mode: Hansi.mode)
  @theme    = Theme[theme]
  @escape   = escape
  @tags     = tags
  @markup   = markup
  @mode     = mode
  @simple   = Regexp.union(@markup.keys)
  reserved  = @markup.keys
  reserved += [?<, ?>] if @tags
  reserved << @escape if @escape
  @reserved = Regexp.union(reserved)
end

Class Method Details

.render(*args, **options) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/hansi/string_renderer.rb', line 7

def self.render(*args, **options)
  input, markup = [], {}

  args.each do |arg|
    if arg.respond_to? :to_hash
      markup.merge! arg.to_hash
    else
      input << arg
    end
  end

  new(markup, **options).render(*input)
end

Instance Method Details

#ansi_for(input) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/hansi/string_renderer.rb', line 88

def ansi_for(input)
  case input
  when /^\e/         then input
  when *@markup.keys then ansi_for(@markup[input])
  when nil, false    then nil
  when AnsiCode      then input.to_ansi(mode: @mode)
  else ansi_for(@theme[input])
  end
end

#color_codes(stack) ⇒ Object



68
69
70
71
# File 'lib/hansi/string_renderer.rb', line 68

def color_codes(stack)
  codes = [Hansi.reset, :default, *stack].map { |element| ansi_for(element) }
  codes.compact.join
end

#describe(element) ⇒ Object



73
74
75
76
77
78
79
# File 'lib/hansi/string_renderer.rb', line 73

def describe(element)
  case element
  when @simple then element.inspect
  when nil     then "end of string"
  else "</#{element}>".inspect
  end
end

#escape(string) ⇒ Object



98
99
100
101
# File 'lib/hansi/string_renderer.rb', line 98

def escape(string)
  return string unless @escape
  string.gsub(@reserved) { |s| "#{@escape}#{s}" }
end

#render(input, *values) ⇒ Object



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
# File 'lib/hansi/string_renderer.rb', line 34

def render(input, *values)
  scanner = StringScanner.new(input)
  insert  = true
  stack   = []
  output  = String.new

  until scanner.eos?
    if scanner.scan(@simple)
      stack.last == scanner[0] ? stack.pop : stack.push(scanner[0])
      insert = true
    elsif @escape and scanner.scan(/#{Regexp.escape(@escape)}(.)/)
      output << color_codes(stack) if insert
      output << scanner[1]
      insert = false
    elsif @tags and scanner.scan(/<(\/)?([^>\s]+)>/)
      insert = true
      if scanner[1]
        unexpected(scanner[2], stack.last)
        stack.pop
      else
        stack << scanner[2]
      end
    else
      output << color_codes(stack) if insert
      output << scanner.getch
      insert = false
    end
  end

  unexpected(nil, stack.last)
  output << Hansi.reset
  values.any? ? output % values : output
end

#unexpected(element, expected) ⇒ Object

Raises:

  • (ParseError)


81
82
83
84
85
86
# File 'lib/hansi/string_renderer.rb', line 81

def unexpected(element, expected)
  return if element == expected
  return if element == "#" and expected.start_with?("#")
  return if expected.start_with?("#{element}(") and expected.end_with?(")")
  raise ParseError, "unexpected #{describe(element)}, expecting #{describe(expected)}"
end