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
|
# frozen_string_literal: true
require 'ripper'
module IRB # :nodoc:
module Color
CLEAR = 0
BOLD = 1
UNDERLINE = 4
RED = 31
GREEN = 32
BLUE = 34
MAGENTA = 35
CYAN = 36
TOKEN_KEYWORDS = {
on_kw: ['nil', 'self', 'true', 'false'],
on_const: ['ENV'],
}
begin
TOKEN_SEQ_EXPRS = {
on_CHAR: [[BLUE, BOLD], [Ripper::EXPR_END]],
on_const: [[BLUE, BOLD, UNDERLINE], [Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
on_embexpr_beg: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_END]],
on_embexpr_end: [[RED], [Ripper::EXPR_END, Ripper::EXPR_ENDFN]],
on_ident: [[BLUE, BOLD], [Ripper::EXPR_ENDFN]],
on_int: [[BLUE, BOLD], [Ripper::EXPR_END]],
on_float: [[MAGENTA, BOLD], [Ripper::EXPR_END]],
on_kw: [[GREEN], [Ripper::EXPR_ARG, Ripper::EXPR_CLASS, Ripper::EXPR_BEG, Ripper::EXPR_END, Ripper::EXPR_FNAME]],
on_label: [[MAGENTA], [Ripper::EXPR_LABELED]],
on_qwords_beg: [[RED], [Ripper::EXPR_BEG]],
on_regexp_beg: [[RED, BOLD], [Ripper::EXPR_BEG]],
on_regexp_end: [[RED, BOLD], [Ripper::EXPR_BEG]],
on_symbeg: [[BLUE, BOLD], [Ripper::EXPR_FNAME]],
on_tstring_beg: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_END, Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
on_tstring_content: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
on_tstring_end: [[RED], [Ripper::EXPR_END]],
}
rescue NameError
TOKEN_SEQ_EXPRS = {}
end
class << self
def colorable?
$stdout.tty? && ENV.key?('TERM') && ENV['TERM'] != 'dumb'
end
def inspect_colorable?(obj)
if obj.is_a?(Module) && obj.name
return true
end
case obj
when Hash
obj.all? { |k, v| inspect_colorable?(k) && inspect_colorable?(v) }
when Array
obj.all? { |o| inspect_colorable?(o) }
when String, Symbol, Regexp, Integer, Float, FalseClass, TrueClass, NilClass
true
else
false
end
end
def clear
return '' unless colorable?
"\e[#{CLEAR}m"
end
def colorize(text, seq)
return text unless colorable?
"#{seq.map { |s| "\e[#{const_get(s)}m" }.join('')}#{text}#{clear}"
end
def colorize_code(code)
return code unless colorable?
colored = +''
Ripper.lex(code).each do |(_line, _col), token, str, expr|
if seq = dispatch_seq(token, expr, str)
colored << "#{seq.map { |s| "\e[#{s}m" }.join('')}#{str}#{clear}"
else
colored << str
end
end
colored
end
private
def dispatch_seq(token, expr, str)
if token == :on_comment
[BLUE, BOLD]
elsif TOKEN_KEYWORDS.fetch(token, []).include?(str)
[CYAN, BOLD]
elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; exprs&.any? { |e| (expr & e) != 0 })
seq
else
nil
end
end
end
end
end
|