hilighter 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/hilight +192 -0
- data/bin/hl +192 -0
- data/lib/hilighter.rb +109 -0
- data/lib/hilighter/codes.rb +151 -0
- data/lib/hilighter/methods.rb +103 -0
- data/lib/string.rb +5 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 12de20d926f333f17c63422220db0c8c5baf18e7870127de78e8ad55cf4598d6
|
4
|
+
data.tar.gz: 23057327a183158182505494e5943733c8da2ab55995af832d363c315dd61b1f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fd5a67726beb497ed99e5357275fe6cabb23ca575152172010fab86873faa40039db76050dad00bcafa987df923dbca75ff12024adfd0ddb4e0f6aa1bf74cf0b
|
7
|
+
data.tar.gz: e139afef30ae8387e7e9dde274a48b907f41d62df8c091a1c2f9eed8eb34c4e3f870c9ce4bcf4a20e23f0f33ff9084dcd8cb705878f90dbcb5829d41baff95ff
|
data/bin/hilight
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "hilighter"
|
4
|
+
require "io/wait"
|
5
|
+
require "optparse"
|
6
|
+
|
7
|
+
### Helpers begin
|
8
|
+
def err(msg)
|
9
|
+
puts("[!] #{msg}".red)
|
10
|
+
end
|
11
|
+
def errx(msg)
|
12
|
+
raise Exception.new(msg)
|
13
|
+
end
|
14
|
+
def good(msg)
|
15
|
+
puts("[+] #{msg}".green)
|
16
|
+
end
|
17
|
+
def info(msg)
|
18
|
+
puts("[*] #{msg}".white)
|
19
|
+
end
|
20
|
+
def subinfo(msg)
|
21
|
+
puts("[=] #{msg}".cyan)
|
22
|
+
end
|
23
|
+
def warn(msg)
|
24
|
+
puts("[-] #{msg}".yellow)
|
25
|
+
end
|
26
|
+
### Helpers end
|
27
|
+
|
28
|
+
class HilighterExit
|
29
|
+
GOOD = 0
|
30
|
+
INVALID_OPTION = 1
|
31
|
+
INVALID_ARGUMENT = 2
|
32
|
+
MISSING_ARGUMENT = 3
|
33
|
+
EXTRA_ARGUMENTS = 4
|
34
|
+
EXCEPTION = 5
|
35
|
+
AMBIGUOUS_ARGUMENT = 6
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse(args)
|
39
|
+
options = Hash.new
|
40
|
+
options["action"] = "default"
|
41
|
+
options["verbose"] = false
|
42
|
+
|
43
|
+
info = [
|
44
|
+
"Hilights the text from stdin using the methods passed on",
|
45
|
+
"the CLI."
|
46
|
+
].join(" ")
|
47
|
+
|
48
|
+
parser = OptionParser.new do |opts|
|
49
|
+
opts.summary_width = 19
|
50
|
+
|
51
|
+
opts.banner = [
|
52
|
+
"Usage: #{File.basename($0)} [OPTIONS] [color1]...",
|
53
|
+
"[colorN]"
|
54
|
+
].join(" ")
|
55
|
+
|
56
|
+
opts.on("", "DESCRIPTION")
|
57
|
+
|
58
|
+
info.wrap(76).each_line do |line|
|
59
|
+
opts.on(" #{line.chomp}")
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on("", "OPTIONS")
|
63
|
+
|
64
|
+
opts.on("-h", "--help", "Display this help message") do
|
65
|
+
puts(opts)
|
66
|
+
exit HilighterExit::GOOD
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("--[no-]color", "Disable colorized output") do |c|
|
70
|
+
Hilighter.disable if (!c)
|
71
|
+
end
|
72
|
+
|
73
|
+
opts.on(
|
74
|
+
"-s",
|
75
|
+
"--sample",
|
76
|
+
"Show sample foreground/background colors"
|
77
|
+
) do
|
78
|
+
options["action"] = "sample"
|
79
|
+
end
|
80
|
+
|
81
|
+
opts.on("-t", "--table", "Show the color table") do
|
82
|
+
options["action"] = "table"
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on(
|
86
|
+
"-v",
|
87
|
+
"--verbose",
|
88
|
+
"Show backtrace when error occurs"
|
89
|
+
) do
|
90
|
+
options["verbose"] = true
|
91
|
+
end
|
92
|
+
|
93
|
+
opts.on("-V", "--version", "Show version") do
|
94
|
+
__FILE__.match(/hilighter-(\d+\.\d+\.\d+)/) do |m|
|
95
|
+
puts(m[1])
|
96
|
+
end
|
97
|
+
exit HilighterExit::GOOD
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
begin
|
102
|
+
parser.parse!
|
103
|
+
rescue OptionParser::InvalidOption => e
|
104
|
+
puts(e.message)
|
105
|
+
puts(parser)
|
106
|
+
exit HilighterExit::INVALID_OPTION
|
107
|
+
rescue OptionParser::InvalidArgument => e
|
108
|
+
puts(e.message)
|
109
|
+
puts(parser)
|
110
|
+
exit HilighterExit::INVALID_ARGUMENT
|
111
|
+
rescue OptionParser::MissingArgument => e
|
112
|
+
puts(e.message)
|
113
|
+
puts(parser)
|
114
|
+
exit HilighterExit::MISSING_ARGUMENT
|
115
|
+
rescue OptionParser::AmbiguousOption => e
|
116
|
+
puts(e.message)
|
117
|
+
puts(parser)
|
118
|
+
exit Exit::AMBIGUOUS_ARGUMENT
|
119
|
+
end
|
120
|
+
|
121
|
+
return options
|
122
|
+
end
|
123
|
+
|
124
|
+
begin
|
125
|
+
options = parse(ARGV)
|
126
|
+
rescue Interrupt
|
127
|
+
# Exit gracefully on ^C
|
128
|
+
exit HilighterExit::GOOD
|
129
|
+
end
|
130
|
+
|
131
|
+
begin
|
132
|
+
case options["action"]
|
133
|
+
when "sample"
|
134
|
+
Hilighter.sample
|
135
|
+
when "table"
|
136
|
+
Hilighter.table
|
137
|
+
else
|
138
|
+
bad = Array.new
|
139
|
+
loop do
|
140
|
+
# Get input
|
141
|
+
input = STDIN.gets
|
142
|
+
|
143
|
+
# Break if EOF, otherwise remove existing color codes
|
144
|
+
break if (input.nil?)
|
145
|
+
|
146
|
+
# Apply all requested color codes
|
147
|
+
ARGV.each do |color|
|
148
|
+
begin
|
149
|
+
input = input.send(color)
|
150
|
+
rescue NoMethodError
|
151
|
+
bad.push(color)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
break if (!bad.empty?)
|
155
|
+
|
156
|
+
# Output
|
157
|
+
puts(input)
|
158
|
+
end
|
159
|
+
puts("Invalid colors: #{bad.join(", ")}") if (!bad.empty?)
|
160
|
+
end
|
161
|
+
rescue Interrupt
|
162
|
+
# Exit gracefully on ^C
|
163
|
+
rescue Errno::EPIPE
|
164
|
+
# Do nothing. This can happen if piping to another program such as
|
165
|
+
# less. Usually if less is closed before we're done with STDOUT.
|
166
|
+
rescue Exception => e
|
167
|
+
$stderr.puts(
|
168
|
+
[
|
169
|
+
"Oops! Looks like an error has occured! If the error",
|
170
|
+
"persists, file a bug at:"
|
171
|
+
].join(" ").wrap
|
172
|
+
)
|
173
|
+
$stderr.puts
|
174
|
+
$stderr.puts(" https://gitlab.com/mjwhitta/hilighter/issues")
|
175
|
+
$stderr.puts
|
176
|
+
$stderr.puts(
|
177
|
+
[
|
178
|
+
"Maybe the message below will help. If not, you can use",
|
179
|
+
"the --verbose flag to get a backtrace."
|
180
|
+
].join(" ").wrap
|
181
|
+
)
|
182
|
+
$stderr.puts
|
183
|
+
|
184
|
+
$stderr.puts(e.message.white.on_red)
|
185
|
+
if (options["verbose"])
|
186
|
+
e.backtrace.each do |line|
|
187
|
+
$stderr.puts(line.light_yellow)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
exit HilighterExit::EXCEPTION
|
191
|
+
end
|
192
|
+
exit HilighterExit::GOOD
|
data/bin/hl
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "hilighter"
|
4
|
+
require "io/wait"
|
5
|
+
require "optparse"
|
6
|
+
|
7
|
+
### Helpers begin
|
8
|
+
def err(msg)
|
9
|
+
puts("[!] #{msg}".red)
|
10
|
+
end
|
11
|
+
def errx(msg)
|
12
|
+
raise Exception.new(msg)
|
13
|
+
end
|
14
|
+
def good(msg)
|
15
|
+
puts("[+] #{msg}".green)
|
16
|
+
end
|
17
|
+
def info(msg)
|
18
|
+
puts("[*] #{msg}".white)
|
19
|
+
end
|
20
|
+
def subinfo(msg)
|
21
|
+
puts("[=] #{msg}".cyan)
|
22
|
+
end
|
23
|
+
def warn(msg)
|
24
|
+
puts("[-] #{msg}".yellow)
|
25
|
+
end
|
26
|
+
### Helpers end
|
27
|
+
|
28
|
+
class HilighterExit
|
29
|
+
GOOD = 0
|
30
|
+
INVALID_OPTION = 1
|
31
|
+
INVALID_ARGUMENT = 2
|
32
|
+
MISSING_ARGUMENT = 3
|
33
|
+
EXTRA_ARGUMENTS = 4
|
34
|
+
EXCEPTION = 5
|
35
|
+
AMBIGUOUS_ARGUMENT = 6
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse(args)
|
39
|
+
options = Hash.new
|
40
|
+
options["action"] = "default"
|
41
|
+
options["verbose"] = false
|
42
|
+
|
43
|
+
info = [
|
44
|
+
"Hilights the text from stdin using the methods passed on",
|
45
|
+
"the CLI."
|
46
|
+
].join(" ")
|
47
|
+
|
48
|
+
parser = OptionParser.new do |opts|
|
49
|
+
opts.summary_width = 19
|
50
|
+
|
51
|
+
opts.banner = [
|
52
|
+
"Usage: #{File.basename($0)} [OPTIONS] [color1]...",
|
53
|
+
"[colorN]"
|
54
|
+
].join(" ")
|
55
|
+
|
56
|
+
opts.on("", "DESCRIPTION")
|
57
|
+
|
58
|
+
info.wrap(76).each_line do |line|
|
59
|
+
opts.on(" #{line.chomp}")
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on("", "OPTIONS")
|
63
|
+
|
64
|
+
opts.on("-h", "--help", "Display this help message") do
|
65
|
+
puts(opts)
|
66
|
+
exit HilighterExit::GOOD
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("--[no-]color", "Disable colorized output") do |c|
|
70
|
+
Hilighter.disable if (!c)
|
71
|
+
end
|
72
|
+
|
73
|
+
opts.on(
|
74
|
+
"-s",
|
75
|
+
"--sample",
|
76
|
+
"Show sample foreground/background colors"
|
77
|
+
) do
|
78
|
+
options["action"] = "sample"
|
79
|
+
end
|
80
|
+
|
81
|
+
opts.on("-t", "--table", "Show the color table") do
|
82
|
+
options["action"] = "table"
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on(
|
86
|
+
"-v",
|
87
|
+
"--verbose",
|
88
|
+
"Show backtrace when error occurs"
|
89
|
+
) do
|
90
|
+
options["verbose"] = true
|
91
|
+
end
|
92
|
+
|
93
|
+
opts.on("-V", "--version", "Show version") do
|
94
|
+
__FILE__.match(/hilighter-(\d+\.\d+\.\d+)/) do |m|
|
95
|
+
puts(m[1])
|
96
|
+
end
|
97
|
+
exit HilighterExit::GOOD
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
begin
|
102
|
+
parser.parse!
|
103
|
+
rescue OptionParser::InvalidOption => e
|
104
|
+
puts(e.message)
|
105
|
+
puts(parser)
|
106
|
+
exit HilighterExit::INVALID_OPTION
|
107
|
+
rescue OptionParser::InvalidArgument => e
|
108
|
+
puts(e.message)
|
109
|
+
puts(parser)
|
110
|
+
exit HilighterExit::INVALID_ARGUMENT
|
111
|
+
rescue OptionParser::MissingArgument => e
|
112
|
+
puts(e.message)
|
113
|
+
puts(parser)
|
114
|
+
exit HilighterExit::MISSING_ARGUMENT
|
115
|
+
rescue OptionParser::AmbiguousOption => e
|
116
|
+
puts(e.message)
|
117
|
+
puts(parser)
|
118
|
+
exit Exit::AMBIGUOUS_ARGUMENT
|
119
|
+
end
|
120
|
+
|
121
|
+
return options
|
122
|
+
end
|
123
|
+
|
124
|
+
begin
|
125
|
+
options = parse(ARGV)
|
126
|
+
rescue Interrupt
|
127
|
+
# Exit gracefully on ^C
|
128
|
+
exit HilighterExit::GOOD
|
129
|
+
end
|
130
|
+
|
131
|
+
begin
|
132
|
+
case options["action"]
|
133
|
+
when "sample"
|
134
|
+
Hilighter.sample
|
135
|
+
when "table"
|
136
|
+
Hilighter.table
|
137
|
+
else
|
138
|
+
bad = Array.new
|
139
|
+
loop do
|
140
|
+
# Get input
|
141
|
+
input = STDIN.gets
|
142
|
+
|
143
|
+
# Break if EOF, otherwise remove existing color codes
|
144
|
+
break if (input.nil?)
|
145
|
+
|
146
|
+
# Apply all requested color codes
|
147
|
+
ARGV.each do |color|
|
148
|
+
begin
|
149
|
+
input = input.send(color)
|
150
|
+
rescue NoMethodError
|
151
|
+
bad.push(color)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
break if (!bad.empty?)
|
155
|
+
|
156
|
+
# Output
|
157
|
+
puts(input)
|
158
|
+
end
|
159
|
+
puts("Invalid colors: #{bad.join(", ")}") if (!bad.empty?)
|
160
|
+
end
|
161
|
+
rescue Interrupt
|
162
|
+
# Exit gracefully on ^C
|
163
|
+
rescue Errno::EPIPE
|
164
|
+
# Do nothing. This can happen if piping to another program such as
|
165
|
+
# less. Usually if less is closed before we're done with STDOUT.
|
166
|
+
rescue Exception => e
|
167
|
+
$stderr.puts(
|
168
|
+
[
|
169
|
+
"Oops! Looks like an error has occured! If the error",
|
170
|
+
"persists, file a bug at:"
|
171
|
+
].join(" ").wrap
|
172
|
+
)
|
173
|
+
$stderr.puts
|
174
|
+
$stderr.puts(" https://gitlab.com/mjwhitta/hilighter/issues")
|
175
|
+
$stderr.puts
|
176
|
+
$stderr.puts(
|
177
|
+
[
|
178
|
+
"Maybe the message below will help. If not, you can use",
|
179
|
+
"the --verbose flag to get a backtrace."
|
180
|
+
].join(" ").wrap
|
181
|
+
)
|
182
|
+
$stderr.puts
|
183
|
+
|
184
|
+
$stderr.puts(e.message.white.on_red)
|
185
|
+
if (options["verbose"])
|
186
|
+
e.backtrace.each do |line|
|
187
|
+
$stderr.puts(line.light_yellow)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
exit HilighterExit::EXCEPTION
|
191
|
+
end
|
192
|
+
exit HilighterExit::GOOD
|
data/lib/hilighter.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
class Hilighter
|
2
|
+
def self.disable(val = true)
|
3
|
+
@@disable = val
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.disable?
|
7
|
+
@@disable ||= false
|
8
|
+
return @@disable
|
9
|
+
end
|
10
|
+
|
11
|
+
# Convert hex to xterm-256 8-bit value
|
12
|
+
# https://stackoverflow.com/questions/11765623/convert-hex-hex_to_256bitto-closest-x11-color-number
|
13
|
+
def self.hex_to_x256(hex)
|
14
|
+
@@cached_codes ||= Hash.new
|
15
|
+
cache = @@cached_codes[hex]
|
16
|
+
return "color_#{cache}" if (!cache.nil?)
|
17
|
+
|
18
|
+
# For simplicity, assume RGB space is perceptually uniform.
|
19
|
+
# There are 5 places where one of two outputs needs to be
|
20
|
+
# chosen when the input is the exact middle:
|
21
|
+
# - The r/g/b channels and the gray value:
|
22
|
+
# - the higher value output is chosen
|
23
|
+
# - If the gray and color values have same distance from the
|
24
|
+
# input
|
25
|
+
# - color is chosen
|
26
|
+
|
27
|
+
# Calculate the nearest 0-based color index at 16..231
|
28
|
+
r = g = b = 0
|
29
|
+
x = "[A-Fa-f0-9]{2}"
|
30
|
+
hex.match(/^#?(#{x})(#{x})(#{x})(#{x})?$/) do |m|
|
31
|
+
r = m[1].to_i(16)
|
32
|
+
g = m[2].to_i(16)
|
33
|
+
b = m[3].to_i(16)
|
34
|
+
end
|
35
|
+
|
36
|
+
# 0..5 each
|
37
|
+
ir = (r < 48) ? 0 : (r < 115) ? 1 : ((r - 35) / 40)
|
38
|
+
ig = (g < 48) ? 0 : (g < 115) ? 1 : ((g - 35) / 40)
|
39
|
+
ib = (b < 48) ? 0 : (b < 115) ? 1 : ((b - 35) / 40)
|
40
|
+
|
41
|
+
# 0..215 lazy evaluation
|
42
|
+
cidx = (36 * ir) + (6 * ig) + ib + 16
|
43
|
+
|
44
|
+
# Calculate the nearest 0-based gray index at 232..255
|
45
|
+
average = (r + g + b) / 3
|
46
|
+
|
47
|
+
# 0..23
|
48
|
+
gidx = (average > 238) ? 23 : (average - 3) / 10
|
49
|
+
|
50
|
+
# Calculate the represented colors back from the index
|
51
|
+
i2cv = [0, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
|
52
|
+
|
53
|
+
# r/g/b 0..255 each
|
54
|
+
cr = i2cv[ir]
|
55
|
+
cg = i2cv[ig]
|
56
|
+
cb = i2cv[ib]
|
57
|
+
|
58
|
+
# same value for r/g/b 0..255
|
59
|
+
gv = (10 * gidx) + 8
|
60
|
+
|
61
|
+
# Return the one which is nearer to the original rgb
|
62
|
+
# values
|
63
|
+
clr_err = ((cr - r) ** 2 + (cg - g) ** 2 + (cb - b) ** 2)
|
64
|
+
gray_err = ((gv - r) ** 2 + (gv - g) ** 2 + (gv - b) ** 2)
|
65
|
+
|
66
|
+
if (clr_err <= gray_err)
|
67
|
+
@@cached_codes[hex] = cidx.to_s.rjust(3, "0")
|
68
|
+
else
|
69
|
+
@@cached_codes[hex] = (gidx + 232).to_s.rjust(3, "0")
|
70
|
+
end
|
71
|
+
|
72
|
+
return "color_#{@@cached_codes[hex]}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.sample
|
76
|
+
String.colors.keys[0..15].each do |fg|
|
77
|
+
String.colors.keys[16..31].each do |bg|
|
78
|
+
print(" mw ".send(fg).send(bg))
|
79
|
+
end
|
80
|
+
puts
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.table
|
85
|
+
(0..15).each do |i|
|
86
|
+
bg = i.to_s.rjust(3, "0")
|
87
|
+
print(" ".send("on_color_#{bg}"))
|
88
|
+
print(bg.black.send("on_color_#{bg}"))
|
89
|
+
print(" ".send("on_color_#{bg}"))
|
90
|
+
print(bg.white.send("on_color_#{bg}"))
|
91
|
+
print(" ".send("on_color_#{bg}"))
|
92
|
+
puts if (((i + 1) % 8) == 0)
|
93
|
+
end
|
94
|
+
|
95
|
+
(16..255).each do |i|
|
96
|
+
bg = i.to_s.rjust(3, "0")
|
97
|
+
print(" ".send("on_color_#{bg}"))
|
98
|
+
print(bg.black.send("on_color_#{bg}"))
|
99
|
+
print(" ".send("on_color_#{bg}"))
|
100
|
+
print(bg.white.send("on_color_#{bg}"))
|
101
|
+
print(" ".send("on_color_#{bg}"))
|
102
|
+
puts if (((i - 15) % 6) == 0)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
require "hilighter/codes"
|
108
|
+
require "hilighter/methods"
|
109
|
+
require "string"
|
@@ -0,0 +1,151 @@
|
|
1
|
+
class Hilighter
|
2
|
+
module Codes
|
3
|
+
def add_methods
|
4
|
+
color_regex = /(^|\n)(\e\[([0-9;]+m|K))+(\n|$)/
|
5
|
+
|
6
|
+
colors.each do |key, val|
|
7
|
+
if (key.start_with?("on_"))
|
8
|
+
on_default = colors["on_default"]
|
9
|
+
define_method key do
|
10
|
+
return self.plain if (Hilighter.disable?)
|
11
|
+
|
12
|
+
return [
|
13
|
+
"\e[#{val}m",
|
14
|
+
self.plain_bg.gsub(
|
15
|
+
/\n/,
|
16
|
+
"\e[#{on_default}m\n\e[#{val}m"
|
17
|
+
),
|
18
|
+
"\e[#{on_default}m"
|
19
|
+
].join.gsub(color_regex, "\\1\\4")
|
20
|
+
end
|
21
|
+
else
|
22
|
+
default = colors["default"]
|
23
|
+
define_method key do
|
24
|
+
return self.plain if (Hilighter.disable?)
|
25
|
+
|
26
|
+
return [
|
27
|
+
"\e[#{val}m",
|
28
|
+
self.plain_fg.gsub(
|
29
|
+
/\n/,
|
30
|
+
"\e[#{default}m\n\e[#{val}m"
|
31
|
+
),
|
32
|
+
"\e[#{default}m"
|
33
|
+
].join.gsub(color_regex, "\\1\\4")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
modes.each do |key, val|
|
39
|
+
rm = [
|
40
|
+
modes[key],
|
41
|
+
modes["no_#{key}".gsub(/^no_no_/, "")]
|
42
|
+
].delete_if(&:nil?).uniq.join("|")
|
43
|
+
|
44
|
+
off = "no_#{key}"
|
45
|
+
if modes.has_key?(off)
|
46
|
+
off = "\e[#{modes[off]}m"
|
47
|
+
else
|
48
|
+
off = ""
|
49
|
+
end
|
50
|
+
|
51
|
+
define_method key do
|
52
|
+
return self.plain if (Hilighter.disable?)
|
53
|
+
self.gsub!(/\e\[(#{rm})m/, "")
|
54
|
+
return "\e[#{val}m#{self}#{off}".gsub(
|
55
|
+
color_regex,
|
56
|
+
"\\1\\4"
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def colors
|
63
|
+
@valid_colors ||= {
|
64
|
+
"black" => 30,
|
65
|
+
"red" => 31,
|
66
|
+
"green" => 32,
|
67
|
+
"yellow" => 33,
|
68
|
+
"blue" => 34,
|
69
|
+
"magenta" => 35,
|
70
|
+
"cyan" => 36,
|
71
|
+
"white" => 37,
|
72
|
+
"light_black" => 90,
|
73
|
+
"light_red" => 91,
|
74
|
+
"light_green" => 92,
|
75
|
+
"light_yellow" => 93,
|
76
|
+
"light_blue" => 94,
|
77
|
+
"light_magenta" => 95,
|
78
|
+
"light_cyan" => 96,
|
79
|
+
"light_white" => 97,
|
80
|
+
|
81
|
+
"on_black" => 40,
|
82
|
+
"on_red" => 41,
|
83
|
+
"on_green" => 42,
|
84
|
+
"on_yellow" => 43,
|
85
|
+
"on_blue" => 44,
|
86
|
+
"on_magenta" => 45,
|
87
|
+
"on_cyan" => 46,
|
88
|
+
"on_white" => 47,
|
89
|
+
"on_light_black" => 100,
|
90
|
+
"on_light_red" => 101,
|
91
|
+
"on_light_green" => 102,
|
92
|
+
"on_light_yellow" => 103,
|
93
|
+
"on_light_blue" => 104,
|
94
|
+
"on_light_magenta" => 105,
|
95
|
+
"on_light_cyan" => 106,
|
96
|
+
"on_light_white" => 107,
|
97
|
+
|
98
|
+
"default" => 39,
|
99
|
+
"on_default" => 49
|
100
|
+
}
|
101
|
+
if (@valid_colors.length < 256)
|
102
|
+
256.times.each do |i|
|
103
|
+
clr = i.to_s.rjust(3, "0")
|
104
|
+
@valid_colors["color_#{clr}"] = "38;5;#{clr}"
|
105
|
+
@valid_colors["on_color_#{clr}"] = "48;5;#{clr}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
return @valid_colors
|
109
|
+
end
|
110
|
+
|
111
|
+
def modes
|
112
|
+
return {
|
113
|
+
"reset" => 0,
|
114
|
+
"normal" => 0,
|
115
|
+
"bold" => 1,
|
116
|
+
"dim" => 2,
|
117
|
+
"faint" => 2,
|
118
|
+
"italic" => 3,
|
119
|
+
"underline" => 4,
|
120
|
+
"blink" => 5,
|
121
|
+
"blink_slow" => 5,
|
122
|
+
"blink_rapid" => 6,
|
123
|
+
"inverse" => 7,
|
124
|
+
"negative" => 7,
|
125
|
+
"swap" => 7,
|
126
|
+
"hide" => 8,
|
127
|
+
"conceal" => 8,
|
128
|
+
"crossed_out" => 9,
|
129
|
+
"strikethrough" => 9,
|
130
|
+
"fraktur" => 20,
|
131
|
+
|
132
|
+
"no_bold" => 21,
|
133
|
+
"no_dim" => 22,
|
134
|
+
"no_faint" => 22,
|
135
|
+
"no_italic" => 23,
|
136
|
+
"no_fraktur" => 23,
|
137
|
+
"no_underline" => 24,
|
138
|
+
"no_blink" => 25,
|
139
|
+
"no_blink_slow" => 25,
|
140
|
+
"no_blink_rapid" => 26,
|
141
|
+
"no_inverse" => 27,
|
142
|
+
"no_negative" => 27,
|
143
|
+
"no_swap" => 27,
|
144
|
+
"no_hide" => 28,
|
145
|
+
"no_conceal" => 28,
|
146
|
+
"no_crossed_out" => 29,
|
147
|
+
"no_strikethrough" => 29
|
148
|
+
}
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
class Hilighter
|
2
|
+
module Methods
|
3
|
+
def color_regex
|
4
|
+
return /\e\[([0-9;]*m|K)/
|
5
|
+
end
|
6
|
+
private :color_regex
|
7
|
+
|
8
|
+
def hex_color(hex)
|
9
|
+
return self.send(Hilighter.hex_to_x256(hex))
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(method_name, *args)
|
13
|
+
method_name.to_s.match(/^([A-Fa-f0-9]{6})$/) do |m|
|
14
|
+
return self.hex_color(m[1])
|
15
|
+
end
|
16
|
+
method_name.to_s.match(/^on_([A-Fa-f0-9]{6})$/) do |m|
|
17
|
+
return self.on_hex_color(m[1])
|
18
|
+
end
|
19
|
+
method_name.to_s.match(/^wrap(_(\d+))?$/) do |m|
|
20
|
+
width = nil
|
21
|
+
width = m[2].to_i if (!m[1].nil?)
|
22
|
+
return self.wrap(width)
|
23
|
+
end
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_hex_color(hex)
|
28
|
+
return self.send("on_#{Hilighter.hex_to_x256(hex)}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_rainbow
|
32
|
+
return self.plain if (Hilighter.disable?)
|
33
|
+
|
34
|
+
clrs = rainbow_colors
|
35
|
+
out = Array.new
|
36
|
+
|
37
|
+
self.plain_bg.each_line do |line|
|
38
|
+
line.chomp!
|
39
|
+
colorized = line.scan(
|
40
|
+
/((#{color_regex})*[^\e](#{color_regex})*)/
|
41
|
+
).map.with_index do |c, i|
|
42
|
+
"\e[#{clrs[i % clrs.length] + 10}m#{c[0]}"
|
43
|
+
end.join
|
44
|
+
out.push("#{colorized}\e[49m\n")
|
45
|
+
end
|
46
|
+
|
47
|
+
return out.join.gsub(/^(#{color_regex})+$/, "")
|
48
|
+
end
|
49
|
+
|
50
|
+
def plain
|
51
|
+
return self.gsub(color_regex, "")
|
52
|
+
end
|
53
|
+
|
54
|
+
def plain_bg
|
55
|
+
return self.gsub(/\e\[(4|10)[0-9;]+m/, "")
|
56
|
+
end
|
57
|
+
|
58
|
+
def plain_fg
|
59
|
+
return self.gsub(/\e\[[39][0-9;]+m/, "")
|
60
|
+
end
|
61
|
+
|
62
|
+
def rainbow_colors
|
63
|
+
return [31, 32, 33, 34, 35, 36, 91, 92, 93, 94, 95, 96]
|
64
|
+
end
|
65
|
+
private :rainbow_colors
|
66
|
+
|
67
|
+
def rainbow
|
68
|
+
return self.plain if (Hilighter.disable?)
|
69
|
+
|
70
|
+
clrs = rainbow_colors
|
71
|
+
out = Array.new
|
72
|
+
|
73
|
+
self.plain_fg.each_line do |line|
|
74
|
+
line.chomp!
|
75
|
+
colorized = line.scan(
|
76
|
+
/((#{color_regex})*[^\e](#{color_regex})*)/
|
77
|
+
).map.with_index do |c, i|
|
78
|
+
"\e[#{clrs[i % clrs.length]}m#{c[0]}"
|
79
|
+
end.join
|
80
|
+
out.push("#{colorized}\n")
|
81
|
+
end
|
82
|
+
|
83
|
+
return out.join.gsub(/^(#{color_regex})+$/, "")
|
84
|
+
end
|
85
|
+
|
86
|
+
def wrap(width = 80)
|
87
|
+
line = ""
|
88
|
+
lines = Array.new
|
89
|
+
self.split(/\s+/).each do |word|
|
90
|
+
if ((line.plain.size + word.plain.size) > width)
|
91
|
+
lines.push("#{line}\n")
|
92
|
+
line = word
|
93
|
+
elsif (line.empty?)
|
94
|
+
line = word
|
95
|
+
else
|
96
|
+
line += " #{word}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
lines.push("#{line}\n") if (!line.empty?)
|
100
|
+
return lines.join
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/string.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hilighter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.5.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Miles Whittaker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-11-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 13.0.0
|
20
|
+
- - "~>"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '13.0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 13.0.0
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '13.0'
|
33
|
+
description: Adds color methods to String class. Also allows for string wrapping that
|
34
|
+
accounts for color escape codes.
|
35
|
+
email: mj@whitta.dev
|
36
|
+
executables:
|
37
|
+
- hl
|
38
|
+
- hilight
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files: []
|
41
|
+
files:
|
42
|
+
- bin/hilight
|
43
|
+
- bin/hl
|
44
|
+
- lib/hilighter.rb
|
45
|
+
- lib/hilighter/codes.rb
|
46
|
+
- lib/hilighter/methods.rb
|
47
|
+
- lib/string.rb
|
48
|
+
homepage: https://gitlab.com/mjwhitta/hilighter/tree/ruby
|
49
|
+
licenses:
|
50
|
+
- GPL-3.0
|
51
|
+
metadata:
|
52
|
+
source_code_uri: https://gitlab.com/mjwhitta/hilighter/tree/ruby
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubygems_version: 3.0.6
|
69
|
+
signing_key:
|
70
|
+
specification_version: 4
|
71
|
+
summary: Adds color methods to String class
|
72
|
+
test_files: []
|