Class: Bcat::ANSI

Inherits:
Object
  • Object
show all
Defined in:
lib/bcat/ansi.rb

Overview

Converts ANSI color sequences to HTML.

The ANSI module is based on code from the following libraries:

ansi2html.sh:

http://github.com/pixelb/scripts/blob/master/scripts/ansi2html.sh

HTML::FromANSI:

http://cpansearch.perl.org/src/NUFFIN/HTML-FromANSI-2.03/lib/HTML/FromANSI.pm

Constant Summary collapse

ESCAPE =
"\x1b"
STYLES =

Linux console palette

{
  'ef0'  => 'color:#000',
  'ef1'  => 'color:#A00',
  'ef2'  => 'color:#0A0',
  'ef3'  => 'color:#A50',
  'ef4'  => 'color:#00A',
  'ef5'  => 'color:#A0A',
  'ef6'  => 'color:#0AA',
  'ef7'  => 'color:#AAA',
  'ef8'  => 'color:#555',
  'ef9'  => 'color:#F55',
  'ef10' => 'color:#5F5',
  'ef11' => 'color:#FF5',
  'ef12' => 'color:#55F',
  'ef13' => 'color:#F5F',
  'ef14' => 'color:#5FF',
  'ef15' => 'color:#FFF',
  'eb0'  => 'background-color:#000',
  'eb1'  => 'background-color:#A00',
  'eb2'  => 'background-color:#0A0',
  'eb3'  => 'background-color:#A50',
  'eb4'  => 'background-color:#00A',
  'eb5'  => 'background-color:#A0A',
  'eb6'  => 'background-color:#0AA',
  'eb7'  => 'background-color:#AAA',
  'eb8'  => 'background-color:#555',
  'eb9'  => 'background-color:#F55',
  'eb10' => 'background-color:#5F5',
  'eb11' => 'background-color:#FF5',
  'eb12' => 'background-color:#55F',
  'eb13' => 'background-color:#F5F',
  'eb14' => 'background-color:#5FF',
  'eb15' => 'background-color:#FFF'
}

Instance Method Summary collapse

Constructor Details

#initialize(input) ⇒ ANSI

Returns a new instance of ANSI.



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/bcat/ansi.rb', line 74

def initialize(input)
  @input =
    if input.respond_to?(:to_str)
      [input]
    elsif !input.respond_to?(:each)
      raise ArgumentError, "input must respond to each"
    else
      input
    end
  @stack = []
end

Instance Method Details

#each {|buf| ... } ⇒ Object

Yields:

  • (buf)


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/bcat/ansi.rb', line 92

def each
  buf = ''
  @input.each do |chunk|
    buf << chunk
    tokenize(buf) do |tok, data|
      case tok
      when :text
        yield data
      when :display
        case code = data
        when 0        ; yield reset_styles if @stack.any?
        when 1        ; yield push_tag("b") # bright
        when 2        ; #dim
        when 3, 4     ; yield push_tag("u")
        when 5, 6     ; yield push_tag("blink")
        when 7        ; #reverse
        when 8        ; yield push_style("display:none")
        when 9        ; yield push_tag("strike")
        when 30..37   ; yield push_style("ef#{code - 30}")
        when 40..47   ; yield push_style("eb#{code - 40}")
        when 90..97   ; yield push_style("ef#{8 + code - 90}")
        when 100..107 ; yield push_style("eb#{8 + code - 100}")
        end 
      end
    end
  end
  yield buf if !buf.empty?
  yield reset_styles if @stack.any?
  self
end

#push_style(style) ⇒ Object



132
133
134
# File 'lib/bcat/ansi.rb', line 132

def push_style(style)
  push_tag "span", style
end

#push_tag(tag, style = nil) ⇒ Object



123
124
125
126
127
128
129
130
# File 'lib/bcat/ansi.rb', line 123

def push_tag(tag, style=nil)
  style = STYLES[style] if style && !style.include?(':')
  @stack.push tag
  [ "<#{tag}",
    (" style='#{style}'" if style),
    ">"
  ].join
end

#redObject

The default xterm 256 colour palette



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/bcat/ansi.rb', line 54

(0..5).each do |red|
  (0..5).each do |green|
    (0..5).each do |blue|
      c = 16 + (red * 36) + (green * 6) + blue
      r = red   > 0 ? red   * 40 + 55 : 0
      g = green > 0 ? green * 40 + 55 : 0
      b = blue  > 0 ? blue  * 40 + 55 : 0
      STYLES["ef#{c}"] = "color:#%2.2x%2.2x%2.2x" % [r, g, b]
      STYLES["eb#{c}"] = "background-color:#%2.2x%2.2x%2.2x" % [r, g, b]
    end
  end
end

#reset_stylesObject



136
137
138
139
# File 'lib/bcat/ansi.rb', line 136

def reset_styles
  stack, @stack = @stack, []
  stack.reverse.map { |tag| "</#{tag}>" }.join
end

#to_htmlObject



86
87
88
89
90
# File 'lib/bcat/ansi.rb', line 86

def to_html
  buf = []
  each { |chunk| buf << chunk }
  buf.join
end

#tokenize(text) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/bcat/ansi.rb', line 141

def tokenize(text)
  tokens = [
    # characters to remove completely
    [/\A\x08+/, lambda { |m| '' }],

    # ansi escape sequences that mess with the display
    [/\A\x1b\[((?:\d{1,3};?)+|)m/, lambda { |m|
      m = '0' if m.strip.empty?
      m.chomp(';').split(';').
      each { |code| yield :display, code.to_i };
      '' }],

    # malformed sequences
    [/\A\x1b\[?[\d;]{0,3}/, lambda { |m| '' }],

    # real text
    [/\A([^\x1b\x08]+)/m, lambda { |m| yield :text, m; '' }]
  ]

  while (size = text.size) > 0
    tokens.each do |pattern, sub|
      while text.sub!(pattern) { sub.call($1) }
      end
    end
    break if text.size == size
  end
end