jtag 0.2.0 → 1.0.0
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 +4 -4
- data/.irbrc +6 -0
- data/CHANGELOG.md +27 -0
- data/Gemfile +3 -0
- data/Jekyll/plugins/autotag_gen.rb +58 -0
- data/Jekyll/source/_layouts/tags_json.html +11 -0
- data/README.md +159 -0
- data/Rakefile +110 -0
- data/bin/jtag +378 -271
- data/jtag.completion.bash +9 -0
- data/jtag.gemspec +27 -0
- data/lib/jtag/array.rb +48 -0
- data/lib/jtag/config_files/config.yml +3 -2
- data/lib/jtag/errors.rb +31 -0
- data/lib/jtag/hash.rb +103 -0
- data/lib/jtag/jekylltag.rb +294 -224
- data/lib/jtag/string.rb +240 -42
- data/lib/jtag/stupid_json.rb +319 -0
- data/lib/jtag/util.rb +244 -0
- data/lib/jtag/version.rb +1 -1
- data/lib/jtag.rb +19 -13
- data/mise.toml +2 -0
- metadata +47 -41
data/lib/jtag/jekylltag.rb
CHANGED
|
@@ -1,267 +1,337 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
module JekyllTag
|
|
4
|
+
class JTag
|
|
5
|
+
attr_reader :default_post_location
|
|
6
|
+
attr_reader :tags_loc
|
|
7
|
+
attr_reader :post_extension
|
|
8
|
+
attr_accessor :tags_key
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@
|
|
11
|
-
@
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
def initialize(support_dir, config, options = {})
|
|
11
|
+
config = config.symbolize_keys
|
|
12
|
+
@support = support_dir
|
|
13
|
+
@util = JekyllTag::Util.new
|
|
14
|
+
@min_matches = config[:min_matches] || 2
|
|
15
|
+
@post_extension = (config[:post_extension] || "md").to_s.sub(/^\./, "")
|
|
16
|
+
@tags_key = config[:tags_key] || "tags"
|
|
17
|
+
@default_post_location = normalize_post_location(config[:default_post_location], config[:post_extension])
|
|
18
|
+
begin
|
|
19
|
+
if options[:files]
|
|
20
|
+
@tags_loc = :auto
|
|
21
|
+
files = options[:files].map(&:File.expand_path)
|
|
22
|
+
elsif config[:tags_location].to_s =~ /^(auto|posts?)$/
|
|
23
|
+
@tags_loc = :auto
|
|
24
|
+
files = Dir.glob(File.join(@default_post_location.to_s, "**", "*.#{@post_extension}"))
|
|
25
|
+
else
|
|
26
|
+
@tags_loc = config[:tags_location]
|
|
27
|
+
if File.exist?(File.expand_path(@tags_loc))
|
|
28
|
+
@tags_loc = File.expand_path(@tags_loc)
|
|
29
|
+
else
|
|
30
|
+
@tags_loc.sub!(/^https?:\/\//, "")
|
|
31
|
+
end
|
|
32
|
+
files = nil
|
|
33
|
+
end
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
raise InvalidTagsFile, "Error reading configured tags locatio (#{e})"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
unless config.has_key?(:default_post_location)
|
|
39
|
+
str = ["#{color("yellow")}No #{color("boldyellow")}default_post_location#{color("yellow")} set.",
|
|
40
|
+
"If you commonly work on the same posts you can add the path and extension",
|
|
41
|
+
"to these key in ~/.jtag/config.yml. Then, if you don't specify files",
|
|
42
|
+
"to act on in a command, it will fall back to those. Nice!#{color("default")}"].join("\n")
|
|
43
|
+
@util.console_log str, err: true, level: :error
|
|
44
|
+
@default_post_location = false
|
|
45
|
+
end
|
|
46
|
+
@blacklistfile = File.join(@support, "blacklist.txt")
|
|
47
|
+
@blacklist = IO.read(@blacklistfile).split("\n") || []
|
|
48
|
+
@skipwords = IO.read(File.join(support_dir, "stopwords.txt")).split("\n") || []
|
|
49
|
+
remote_tags = tags(files: files)
|
|
50
|
+
@tags = {}
|
|
51
|
+
remote_tags.each do |tag|
|
|
52
|
+
@tags[tag.root_words] = tag if tag
|
|
53
|
+
end
|
|
54
|
+
synonyms.each { |k, v|
|
|
55
|
+
@tags[k.to_s.downcase] = v unless @blacklist.include?(k.to_s.downcase)
|
|
56
|
+
}
|
|
14
57
|
end
|
|
15
|
-
@min_matches = config['min_matches'] || 2
|
|
16
|
-
@tags_key = config['tags_key'] || 'tags'
|
|
17
58
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
59
|
+
# Older configs stored a glob (…/_posts/*.md). Commands expect a directory
|
|
60
|
+
# plus post_extension, so peel the glob off and keep the extension.
|
|
61
|
+
def normalize_post_location(location, explicit_extension)
|
|
62
|
+
return false if location.nil? || location.to_s.strip.empty?
|
|
63
|
+
|
|
64
|
+
raw = location.to_s.strip
|
|
65
|
+
if raw.match?(/[*?\[{]/)
|
|
66
|
+
unless explicit_extension
|
|
67
|
+
ext = raw[/\*\.([A-Za-z0-9]+)\z/, 1]
|
|
68
|
+
@post_extension = ext if ext
|
|
69
|
+
end
|
|
70
|
+
dir = File.expand_path(File.dirname(raw))
|
|
71
|
+
return File.directory?(dir) ? dir : false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
File.expand_path(raw)
|
|
26
75
|
end
|
|
27
|
-
@blacklistfile = File.join(@support,'blacklist.txt')
|
|
28
|
-
@blacklist = IO.read(@blacklistfile).split("\n") || []
|
|
29
|
-
@skipwords = IO.read(File.join(support_dir,'stopwords.txt')).split("\n") || []
|
|
30
|
-
remote_tags = get_tags
|
|
31
|
-
@tags = {}
|
|
32
|
-
remote_tags.each {|tag| @tags[Text::PorterStemming.stem(tag).downcase] = tag if tag}
|
|
33
|
-
synonyms.each { |k,v|
|
|
34
|
-
@tags[k.to_s.downcase] = v unless @blacklist.include?(k.to_s.downcase)
|
|
35
|
-
}
|
|
36
|
-
end
|
|
37
76
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
77
|
+
def tags(options = {})
|
|
78
|
+
blacklisted = options[:blacklisted] || false
|
|
79
|
+
counts = options[:counts] || false
|
|
80
|
+
if options[:files]
|
|
81
|
+
tags = {}
|
|
82
|
+
tag_counts = {}
|
|
83
|
+
options[:files].each do |file|
|
|
84
|
+
tags["tags"] ||= []
|
|
85
|
+
|
|
86
|
+
file_tags = post_tags(File.expand_path(file))
|
|
87
|
+
file_tags.each do |tag|
|
|
88
|
+
tag_counts[tag] ||= 0
|
|
89
|
+
tag_counts[tag] += 1
|
|
90
|
+
tags["tags"].push(tag)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
tags["tags_count"] = []
|
|
94
|
+
tag_counts.each { |k, v| tags["tags_count"] << { "name" => k, "count" => v } }
|
|
95
|
+
elsif File.exist?(@tags_loc)
|
|
96
|
+
begin
|
|
97
|
+
tags = YAML.load_file(@tags_loc)
|
|
98
|
+
rescue LoadError
|
|
99
|
+
tags = JSON.parse(IO.read(@tags_loc))
|
|
100
|
+
rescue
|
|
101
|
+
raise InvalidTagsFile, "Tags file is not in YAML or JSON format."
|
|
102
|
+
end
|
|
55
103
|
else
|
|
56
|
-
|
|
57
|
-
|
|
104
|
+
host, path = @tags_loc.match(/^([^\/]+)(\/.*)/)[1, 2]
|
|
105
|
+
tags = ""
|
|
106
|
+
# http = Net::HTTP.new(host, 80)
|
|
107
|
+
# http.start do |http|
|
|
108
|
+
# request = Net::HTTP::Get.new(path)
|
|
109
|
+
# response = http.request(request)
|
|
110
|
+
# response.value
|
|
111
|
+
# tags = response.body
|
|
112
|
+
# end
|
|
113
|
+
tags = `curl -sSL "#{@tags_loc}"`
|
|
114
|
+
tags = YAML.load(tags) rescue JSON.parse(tags)
|
|
115
|
+
raise InvalidTagsFile, "Tags file is not in YAML or JSON format." unless tags
|
|
116
|
+
end
|
|
117
|
+
if tags && tags.key?("tags")
|
|
118
|
+
if counts && tags.key?("tags_count")
|
|
119
|
+
tags["tags_count"].delete_if { |tag| !tag || @blacklist.include?(tag["name"].downcase) } unless blacklisted
|
|
120
|
+
return tags["tags_count"]
|
|
121
|
+
else
|
|
122
|
+
tags["tags"].delete_if { |tag| !tag || @blacklist.include?(tag.downcase) } unless blacklisted
|
|
123
|
+
return tags["tags"]
|
|
58
124
|
end
|
|
59
|
-
|
|
125
|
+
else
|
|
126
|
+
return false
|
|
60
127
|
end
|
|
61
|
-
else
|
|
62
|
-
return false
|
|
63
128
|
end
|
|
64
|
-
end
|
|
65
129
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
130
|
+
def synonyms
|
|
131
|
+
if File.exist?(File.join(@support, "synonyms.yml"))
|
|
132
|
+
syn = YAML::load(File.open(File.join(@support, "synonyms.yml")))
|
|
133
|
+
compiled = {}
|
|
134
|
+
syn.each { |k, v|
|
|
135
|
+
v.each { |synonym|
|
|
136
|
+
compiled[synonym] = k
|
|
137
|
+
}
|
|
73
138
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
compiled
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def split_post(file, piped = false)
|
|
82
|
-
input = piped ? file : IO.read(file)
|
|
83
|
-
# Check to see if it's a full post with YAML headers
|
|
84
|
-
post_parts = input.split(/^[\.\-]{3}\s*$/)
|
|
85
|
-
if post_parts.length >= 3
|
|
86
|
-
after = post_parts[2].strip
|
|
87
|
-
yaml = YAML::load(input)
|
|
88
|
-
else
|
|
89
|
-
after = input
|
|
90
|
-
yaml = YAML::load("--- title: #{File.basename(file)}")
|
|
139
|
+
else
|
|
140
|
+
return false
|
|
141
|
+
end
|
|
142
|
+
compiled
|
|
91
143
|
end
|
|
92
|
-
[yaml, after]
|
|
93
|
-
end
|
|
94
144
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
145
|
+
def split_post(file, piped = false)
|
|
146
|
+
input = piped ? file : IO.read(file)
|
|
147
|
+
# Check to see if it's a full post with YAML headers
|
|
148
|
+
post_parts = input.split(/^[\.\-]{3}\s*$/)
|
|
149
|
+
if post_parts.length >= 3
|
|
150
|
+
after = post_parts[2].strip
|
|
151
|
+
yaml = YAML::load(input)
|
|
152
|
+
else
|
|
153
|
+
after = input
|
|
154
|
+
yaml = YAML::load("--- title: #{File.basename(file)}")
|
|
155
|
+
end
|
|
156
|
+
[yaml, after]
|
|
102
157
|
end
|
|
103
|
-
end
|
|
104
158
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
159
|
+
def post_tags(file, piped = false)
|
|
160
|
+
begin
|
|
161
|
+
input = piped ? file.strip : IO.read(File.expand_path(file))
|
|
162
|
+
yaml = YAML::load(input)
|
|
163
|
+
tags = yaml.is_a?(Hash) ? yaml[@tags_key] : nil
|
|
164
|
+
case tags
|
|
165
|
+
when Array
|
|
166
|
+
tags.compact.map(&:to_s)
|
|
167
|
+
when String
|
|
168
|
+
[tags]
|
|
169
|
+
else
|
|
170
|
+
[]
|
|
171
|
+
end
|
|
172
|
+
rescue
|
|
173
|
+
return []
|
|
112
174
|
end
|
|
113
|
-
|
|
114
|
-
return false unless post_has_tag
|
|
115
|
-
current_tags.push(merged)
|
|
116
|
-
current_tags.uniq!
|
|
117
|
-
current_tags.sort
|
|
118
|
-
end
|
|
175
|
+
end
|
|
119
176
|
|
|
177
|
+
def merge_tags(tags, merged, file)
|
|
178
|
+
current_tags = post_tags(file)
|
|
179
|
+
post_has_tag = false
|
|
180
|
+
tags.each { |tag|
|
|
181
|
+
if current_tags.include?(tag)
|
|
182
|
+
current_tags.delete(tag)
|
|
183
|
+
post_has_tag = true
|
|
184
|
+
end
|
|
185
|
+
}
|
|
186
|
+
return false unless post_has_tag
|
|
187
|
+
current_tags.push(merged)
|
|
188
|
+
current_tags.uniq!
|
|
189
|
+
current_tags.sort
|
|
190
|
+
end
|
|
120
191
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
192
|
+
def suggest(input)
|
|
193
|
+
parts = input.split(/^[\.\-]{3}\s*$/)
|
|
194
|
+
if parts.length >= 2
|
|
195
|
+
begin
|
|
196
|
+
yaml = YAML::load(parts[1])
|
|
197
|
+
current_tags = yaml[@tags_key] || []
|
|
198
|
+
title = yaml["title"] || ""
|
|
199
|
+
rescue
|
|
200
|
+
current_tags = []
|
|
201
|
+
title = ""
|
|
202
|
+
end
|
|
203
|
+
else
|
|
129
204
|
current_tags = []
|
|
130
205
|
title = ""
|
|
131
206
|
end
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
207
|
+
@content = (title + parts[2..-1].join(" ")).strip_all.strip_urls rescue input.strip_all.strip_urls
|
|
208
|
+
@words = split_words
|
|
209
|
+
@auto_tags = []
|
|
210
|
+
populate_auto_tags
|
|
211
|
+
|
|
212
|
+
@auto_tags.concat(current_tags).uniq
|
|
135
213
|
end
|
|
136
|
-
@content = (title + parts[2..-1].join(" ")).strip_all.strip_urls rescue input.strip_all.strip_urls
|
|
137
|
-
@words = split_words
|
|
138
|
-
@auto_tags = []
|
|
139
|
-
populate_auto_tags
|
|
140
214
|
|
|
141
|
-
|
|
142
|
-
|
|
215
|
+
def split_words
|
|
216
|
+
@content.gsub(/([\/\\]|\s+)/, " ").gsub(/[^a-z0-9\s-]/i, "").split(" ").delete_if { |word|
|
|
217
|
+
word =~ /^[^a-z]+$/ || word.length < 4
|
|
218
|
+
}.map! { |word|
|
|
219
|
+
Text::PorterStemming.stem(word).downcase
|
|
220
|
+
}.delete_if { |word|
|
|
221
|
+
@skipwords.include?(word) && !@tags.keys.include?(word)
|
|
222
|
+
}
|
|
223
|
+
end
|
|
143
224
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
word
|
|
147
|
-
|
|
148
|
-
Text::PorterStemming.stem(word).downcase
|
|
149
|
-
}.delete_if{ |word|
|
|
150
|
-
@skipwords.include?(word) && !@tags.keys.include?(word)
|
|
151
|
-
}
|
|
152
|
-
end
|
|
225
|
+
def populate_auto_tags
|
|
226
|
+
freqs = Hash.new(0)
|
|
227
|
+
@words.each { |word| freqs[word] += 1 }
|
|
228
|
+
freqs.delete_if { |k, v| v < @min_matches }
|
|
153
229
|
|
|
154
|
-
|
|
155
|
-
freqs = Hash.new(0)
|
|
156
|
-
@words.each { |word| freqs[word] += 1 }
|
|
157
|
-
freqs.delete_if {|k,v| v < @min_matches }
|
|
230
|
+
return [] if freqs.empty?
|
|
158
231
|
|
|
159
|
-
|
|
232
|
+
freqs.sort_by { |k, v| [v * -1, k] }.each { |word|
|
|
233
|
+
index = @tags.keys.index(word[0])
|
|
234
|
+
unless index.nil? || @blacklist.include?(@tags.keys[index])
|
|
235
|
+
@auto_tags.push(@tags[@tags.keys[index]]) unless index.nil?
|
|
236
|
+
end
|
|
237
|
+
}
|
|
160
238
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
239
|
+
@tags.each { |k, v|
|
|
240
|
+
occurrences = @content.scan(/\b#{k}\b/i)
|
|
241
|
+
if occurrences.count >= @min_matches
|
|
242
|
+
@auto_tags.push(v)
|
|
243
|
+
end
|
|
244
|
+
}
|
|
245
|
+
end
|
|
167
246
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
247
|
+
def blacklist(tags)
|
|
248
|
+
tags.each { |word|
|
|
249
|
+
@blacklist.push(word.downcase)
|
|
250
|
+
}
|
|
251
|
+
File.open(@blacklistfile, "w+") do |f|
|
|
252
|
+
f.puts @blacklist.uniq.sort.join("\n")
|
|
172
253
|
end
|
|
173
|
-
}
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def blacklist(tags)
|
|
177
|
-
tags.each {|word|
|
|
178
|
-
@blacklist.push(word.downcase)
|
|
179
|
-
}
|
|
180
|
-
File.open(@blacklistfile,'w+') do |f|
|
|
181
|
-
f.puts @blacklist.uniq.sort.join("\n")
|
|
182
254
|
end
|
|
183
|
-
end
|
|
184
255
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
256
|
+
def unblacklist(tags)
|
|
257
|
+
tags.each { |word|
|
|
258
|
+
@blacklist.delete_if { |x| x == word }
|
|
259
|
+
}
|
|
260
|
+
File.open(@blacklistfile, "w+") do |f|
|
|
261
|
+
f.puts @blacklist.uniq.sort.join("\n")
|
|
262
|
+
end
|
|
191
263
|
end
|
|
192
|
-
end
|
|
193
264
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
265
|
+
def update_file_tags(file, tags, piped = false)
|
|
266
|
+
begin
|
|
267
|
+
if File.exist?(file) || piped
|
|
268
|
+
yaml, after = split_post(file, piped)
|
|
269
|
+
yaml[@tags_key] = tags
|
|
270
|
+
if piped
|
|
271
|
+
puts yaml.to_yaml
|
|
272
|
+
puts "---"
|
|
273
|
+
puts after
|
|
274
|
+
else
|
|
275
|
+
File.open(file, "w+") do |f|
|
|
276
|
+
f.puts yaml.to_yaml
|
|
277
|
+
f.puts "---"
|
|
278
|
+
f.puts after
|
|
279
|
+
end
|
|
208
280
|
end
|
|
281
|
+
else
|
|
282
|
+
raise "File does not exist: #{file}"
|
|
209
283
|
end
|
|
210
|
-
|
|
211
|
-
|
|
284
|
+
return true
|
|
285
|
+
rescue Exception => e
|
|
286
|
+
raise e
|
|
287
|
+
return false
|
|
212
288
|
end
|
|
213
|
-
return true
|
|
214
|
-
rescue Exception => e
|
|
215
|
-
raise e
|
|
216
|
-
return false
|
|
217
289
|
end
|
|
218
|
-
end
|
|
219
290
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def color(name)
|
|
291
|
+
def color(name)
|
|
223
292
|
color = {}
|
|
224
|
-
color[
|
|
225
|
-
color[
|
|
226
|
-
color[
|
|
227
|
-
color[
|
|
228
|
-
color[
|
|
229
|
-
color[
|
|
230
|
-
color[
|
|
231
|
-
color[
|
|
232
|
-
color[
|
|
233
|
-
color[
|
|
234
|
-
color[
|
|
235
|
-
color[
|
|
236
|
-
color[
|
|
237
|
-
color[
|
|
238
|
-
color[
|
|
239
|
-
color[
|
|
240
|
-
color[
|
|
241
|
-
color[
|
|
242
|
-
color[
|
|
243
|
-
color[
|
|
244
|
-
color[
|
|
245
|
-
color[
|
|
246
|
-
color[
|
|
247
|
-
color[
|
|
248
|
-
color[
|
|
249
|
-
color[
|
|
250
|
-
color[
|
|
251
|
-
color[
|
|
252
|
-
color[
|
|
253
|
-
color[
|
|
254
|
-
color[
|
|
255
|
-
color[
|
|
256
|
-
color[
|
|
257
|
-
color[
|
|
258
|
-
color[
|
|
259
|
-
color[
|
|
260
|
-
color[
|
|
261
|
-
color[
|
|
262
|
-
color[
|
|
263
|
-
color[
|
|
264
|
-
color[
|
|
265
|
-
color[name]
|
|
293
|
+
color["black"] = "\033[0;30m"
|
|
294
|
+
color["red"] = "\033[0;31m"
|
|
295
|
+
color["green"] = "\033[0;32m"
|
|
296
|
+
color["yellow"] = "\033[0;33m"
|
|
297
|
+
color["blue"] = "\033[0;34m"
|
|
298
|
+
color["magenta"] = "\033[0;35m"
|
|
299
|
+
color["cyan"] = "\033[0;36m"
|
|
300
|
+
color["white"] = "\033[0;37m"
|
|
301
|
+
color["bgblack"] = "\033[0;40m"
|
|
302
|
+
color["bgred"] = "\033[0;41m"
|
|
303
|
+
color["bggreen"] = "\033[0;42m"
|
|
304
|
+
color["bgyellow"] = "\033[0;43m"
|
|
305
|
+
color["bgblue"] = "\033[0;44m"
|
|
306
|
+
color["bgmagenta"] = "\033[0;45m"
|
|
307
|
+
color["bgcyan"] = "\033[0;46m"
|
|
308
|
+
color["bgwhite"] = "\033[0;47m"
|
|
309
|
+
color["boldblack"] = "\033[1;30m"
|
|
310
|
+
color["boldred"] = "\033[1;31m"
|
|
311
|
+
color["boldgreen"] = "\033[1;32m"
|
|
312
|
+
color["boldyellow"] = "\033[1;33m"
|
|
313
|
+
color["boldblue"] = "\033[1;34m"
|
|
314
|
+
color["boldmagenta"] = "\033[1;35m"
|
|
315
|
+
color["boldcyan"] = "\033[1;36m"
|
|
316
|
+
color["boldwhite"] = "\033[1;37m"
|
|
317
|
+
color["boldbgblack"] = "\033[1;40m"
|
|
318
|
+
color["boldbgred"] = "\033[1;41m"
|
|
319
|
+
color["boldbggreen"] = "\033[1;42m"
|
|
320
|
+
color["boldbgyellow"] = "\033[1;43m"
|
|
321
|
+
color["boldbgblue"] = "\033[1;44m"
|
|
322
|
+
color["boldbgmagenta"] = "\033[1;45m"
|
|
323
|
+
color["boldbgcyan"] = "\033[1;46m"
|
|
324
|
+
color["boldbgwhite"] = "\033[1;47m"
|
|
325
|
+
color["default"] = "\033[0;39m"
|
|
326
|
+
color["warning"] = color["yellow"]
|
|
327
|
+
color["warningb"] = color["boldyellow"]
|
|
328
|
+
color["success"] = color["green"]
|
|
329
|
+
color["successb"] = color["boldgreen"]
|
|
330
|
+
color["neutral"] = color["white"]
|
|
331
|
+
color["neutralb"] = color["boldwhite"]
|
|
332
|
+
color["info"] = color["cyan"]
|
|
333
|
+
color["infob"] = color["boldcyan"]
|
|
334
|
+
color[name.to_s]
|
|
335
|
+
end
|
|
266
336
|
end
|
|
267
337
|
end
|