This repository has been archived by the owner on Nov 9, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 34
/
ansi.rb
174 lines (156 loc) · 4.85 KB
/
ansi.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
81
82
83
84
85
86
87
88
89
90
91
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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
168
169
170
171
172
173
174
class Bcat
# 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
class ANSI
ESCAPE = "\x1b"
# Linux console palette
STYLES = {
'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'
}
##
# The default xterm 256 colour palette
(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
(0..23).each do |gray|
c = gray+232
l = gray*10 + 8
STYLES["ef#{c}"] = "color:#%2.2x%2.2x%2.2x" % [l, l, l]
STYLES["eb#{c}"] = "background-color:#%2.2x%2.2x%2.2x" % [l, l, l]
end
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
def to_html
buf = []
each { |chunk| buf << chunk }
buf.join
end
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
when :xterm256
code = data
yield push_style("ef#{code}")
end
end
end
yield buf if !buf.empty?
yield reset_styles if @stack.any?
self
end
def push_tag(tag, style=nil)
style = STYLES[style] if style && !style.include?(':')
@stack.push tag
[ "<#{tag}",
(" style='#{style}'" if style),
">"
].join
end
def push_style(style)
push_tag "span", style
end
def reset_styles
stack, @stack = @stack, []
stack.reverse.map { |tag| "</#{tag}>" }.join
end
def tokenize(text)
tokens = [
# characters to remove completely
[/\A\x08+/, lambda { |m| '' }],
[/\A\x1b\[38;5;(\d+)m/, lambda { |m| yield :xterm256, $1.to_i; '' } ],
# 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|
break if text.sub!(pattern) { sub.call($1) }
end
break if text.size == size
end
end
end
end