arTTY 0.9.48
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/arTTY +486 -0
- data/lib/arTTY.rb +78 -0
- data/lib/arTTY/art.rb +111 -0
- data/lib/arTTY/cache.rb +117 -0
- data/lib/arTTY/error.rb +9 -0
- data/lib/arTTY/error/art_not_found.rb +6 -0
- data/lib/arTTY/error/failed_to_download.rb +5 -0
- data/lib/arTTY/error/image_magick_not_found.rb +5 -0
- data/lib/arTTY/error/image_named_improperly.rb +6 -0
- data/lib/arTTY/error/image_not_found.rb +6 -0
- data/lib/arTTY/error/no_pixel_data_found.rb +5 -0
- data/lib/arTTY/generator.rb +156 -0
- data/lib/arTTY/system_info.rb +212 -0
- metadata +198 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: df17d6bc87a48aafd84c5371ff5bad973bc9c5e6
|
4
|
+
data.tar.gz: abcb987b6e79acfe71b1da42b520bba0d11ee556
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 866089b6a04d29a56c1a42fbbd303615eed3b3d72257dae6103f05c7f75c406bfdba251017ff4f194964298d7876e55fa1ea1e8ceaed0ccf6cc99d36386639de
|
7
|
+
data.tar.gz: 88e6e76cc7678f2c52fef9bbb67b63ee4ea0bfd31ad384df5dc6c801cdede9f1692f14de2ed23fb9c47757a9e69968bb34798746df77bc79d038ae0f72388954
|
data/bin/arTTY
ADDED
@@ -0,0 +1,486 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "arTTY"
|
4
|
+
require "hilighter"
|
5
|
+
require "io/wait"
|
6
|
+
require "jsoncfg"
|
7
|
+
require "optparse"
|
8
|
+
require "scoobydoo"
|
9
|
+
require "typhoeus"
|
10
|
+
|
11
|
+
class ArTTYConfig < JSONConfig
|
12
|
+
extend JSONConfig::Keys
|
13
|
+
|
14
|
+
add_key("art")
|
15
|
+
add_bool_key("clear_screen")
|
16
|
+
add_bool_key("devexcuse")
|
17
|
+
add_key("exclude")
|
18
|
+
add_key("fields")
|
19
|
+
add_bool_key("fit")
|
20
|
+
add_bool_key("fortune")
|
21
|
+
add_key("match")
|
22
|
+
add_bool_key("random")
|
23
|
+
add_bool_key("sysinfo")
|
24
|
+
|
25
|
+
def initialize(file = nil)
|
26
|
+
file ||= "~/.config/arTTY/rc"
|
27
|
+
@defaults = {
|
28
|
+
"art" => "",
|
29
|
+
"clear_screen" => true,
|
30
|
+
"devexcuse" => false,
|
31
|
+
"exclude" => "",
|
32
|
+
"fields" => Array.new,
|
33
|
+
"fit" => true,
|
34
|
+
"fortune" => false,
|
35
|
+
"match" => "",
|
36
|
+
"random" => true,
|
37
|
+
"sysinfo" => true
|
38
|
+
}
|
39
|
+
super(file, false)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class ArTTYExit
|
44
|
+
GOOD = 0
|
45
|
+
INVALID_OPTION = 1
|
46
|
+
INVALID_ARGUMENT = 2
|
47
|
+
MISSING_ARGUMENT = 3
|
48
|
+
EXTRA_ARGUMENTS = 4
|
49
|
+
EXCEPTION = 5
|
50
|
+
AMBIGUOUS_ARGUMENT = 6
|
51
|
+
UNSUPPORTED_ART = 7
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_devexcuse
|
55
|
+
begin
|
56
|
+
Typhoeus::Request.get(
|
57
|
+
"http://developerexcuses.com"
|
58
|
+
).body.match(/<a href.+>(.+)<\/a>/) do |m|
|
59
|
+
return m[1]
|
60
|
+
end
|
61
|
+
rescue
|
62
|
+
return nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse(args)
|
67
|
+
options = Hash.new
|
68
|
+
options["action"] = "draw"
|
69
|
+
options["all"] = false
|
70
|
+
options["art"] = ""
|
71
|
+
options["clear"] = false
|
72
|
+
options["conf"] = ArTTYConfig.new
|
73
|
+
options["devexcuse"] = false
|
74
|
+
options["exclude"] = ""
|
75
|
+
options["fields"] = Array.new
|
76
|
+
options["fit"] = false
|
77
|
+
options["fortune"] = false
|
78
|
+
options["generate"] = nil
|
79
|
+
options["match"] = ""
|
80
|
+
options["plain"] = false
|
81
|
+
options["random"] = false
|
82
|
+
options["sysinfo"] = false
|
83
|
+
options["verbose"] = false
|
84
|
+
|
85
|
+
info = "Art for your TTY."
|
86
|
+
|
87
|
+
parser = OptionParser.new do |opts|
|
88
|
+
opts.summary_width = 25
|
89
|
+
|
90
|
+
opts.banner = "Usage: #{File.basename($0)} [OPTIONS] [art]"
|
91
|
+
|
92
|
+
opts.on("", "DESCRIPTION")
|
93
|
+
|
94
|
+
info.scan(/\S.{0,76}\S(?=\s|$)|\S+/).each do |line|
|
95
|
+
opts.on(" #{line}")
|
96
|
+
end
|
97
|
+
|
98
|
+
opts.on("", "OPTIONS")
|
99
|
+
|
100
|
+
opts.on("-a", "--all", "Ignore previous filtering") do
|
101
|
+
options["all"] = true
|
102
|
+
end
|
103
|
+
|
104
|
+
opts.on("--cache", "Refresh the cache") do
|
105
|
+
case options["action"]
|
106
|
+
when "draw"
|
107
|
+
options["action"] = "cache"
|
108
|
+
else
|
109
|
+
puts(opts)
|
110
|
+
exit ArTTYExit::INVALID_OPTION
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.on("-c", "--clear", "Clear screen first") do
|
115
|
+
options["clear"] = true
|
116
|
+
end
|
117
|
+
|
118
|
+
opts.on("--demo", "Demo art matching filters") do
|
119
|
+
case options["action"]
|
120
|
+
when "draw"
|
121
|
+
options["action"] = "demo"
|
122
|
+
else
|
123
|
+
puts(opts)
|
124
|
+
exit ArTTYExit::INVALID_OPTION
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
opts.on("-d", "--devexcuse", "Display a developer excuse") do
|
129
|
+
options["devexcuse"] = true
|
130
|
+
end
|
131
|
+
|
132
|
+
opts.on(
|
133
|
+
"-e",
|
134
|
+
"--exclude=PATTERN",
|
135
|
+
"Exclude art matching pattern"
|
136
|
+
) do |pattern|
|
137
|
+
options["exclude"] = pattern
|
138
|
+
end
|
139
|
+
|
140
|
+
opts.on(
|
141
|
+
"--fields=FIELDS",
|
142
|
+
"Specify order of sysinfo (comma-separated, see",
|
143
|
+
"FIELDS)"
|
144
|
+
) do |fields|
|
145
|
+
options["fields"] = fields.split(",")
|
146
|
+
options["sysinfo"] = true
|
147
|
+
end
|
148
|
+
|
149
|
+
opts.on(
|
150
|
+
"--fit",
|
151
|
+
"Only use art that fits in the current window"
|
152
|
+
) do |f|
|
153
|
+
options["fit"] = true
|
154
|
+
end
|
155
|
+
|
156
|
+
opts.on(
|
157
|
+
"-f",
|
158
|
+
"--fortune",
|
159
|
+
"Display a fortune (if installed)"
|
160
|
+
) do
|
161
|
+
options["fortune"] = true
|
162
|
+
end
|
163
|
+
|
164
|
+
opts.on("-h", "--help", "Display this help message") do
|
165
|
+
puts(opts)
|
166
|
+
exit ArTTYExit::GOOD
|
167
|
+
end
|
168
|
+
|
169
|
+
opts.on(
|
170
|
+
"-g",
|
171
|
+
"--generate=IMAGE",
|
172
|
+
"Generate ArTTY art from image (NAME_WxH.png)"
|
173
|
+
) do |image|
|
174
|
+
case options["action"]
|
175
|
+
when "draw"
|
176
|
+
options["action"] = "generate"
|
177
|
+
else
|
178
|
+
puts(opts)
|
179
|
+
exit ArTTYExit::INVALID_OPTION
|
180
|
+
end
|
181
|
+
options["generate"] = image
|
182
|
+
end
|
183
|
+
|
184
|
+
opts.on("--ls", "List art matching filters") do
|
185
|
+
case options["action"]
|
186
|
+
when "draw"
|
187
|
+
options["action"] = "list"
|
188
|
+
else
|
189
|
+
puts(opts)
|
190
|
+
exit ArTTYExit::INVALID_OPTION
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
opts.on(
|
195
|
+
"-m",
|
196
|
+
"--match=PATTERN",
|
197
|
+
"Only use art matching pattern"
|
198
|
+
) do |pattern|
|
199
|
+
options["match"] = pattern
|
200
|
+
end
|
201
|
+
|
202
|
+
opts.on("--[no-]color", "Disable colorized output") do |c|
|
203
|
+
Hilighter.disable if (!c)
|
204
|
+
end
|
205
|
+
|
206
|
+
opts.on(
|
207
|
+
"-p",
|
208
|
+
"--plain",
|
209
|
+
"Ignore previous flags and filtering (useful for",
|
210
|
+
"tab-completion with --ls)"
|
211
|
+
) do
|
212
|
+
options["plain"] = true
|
213
|
+
end
|
214
|
+
|
215
|
+
opts.on(
|
216
|
+
"-r",
|
217
|
+
"--random",
|
218
|
+
"Display random art matching filters"
|
219
|
+
) do
|
220
|
+
options["random"] = true
|
221
|
+
end
|
222
|
+
|
223
|
+
opts.on("--save", "Save specified options as default") do
|
224
|
+
case options["action"]
|
225
|
+
when "draw"
|
226
|
+
options["action"] = "save"
|
227
|
+
else
|
228
|
+
puts(opts)
|
229
|
+
exit ArTTYExit::INVALID_OPTION
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
opts.on(
|
234
|
+
"--show-config",
|
235
|
+
"Show the current config with any other options applied",
|
236
|
+
) do
|
237
|
+
case options["action"]
|
238
|
+
when "draw"
|
239
|
+
options["action"] = "show"
|
240
|
+
else
|
241
|
+
puts(opts)
|
242
|
+
exit ArTTYExit::INVALID_OPTION
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
opts.on("-s", "--sysinfo", "Display system info") do
|
247
|
+
options["sysinfo"] = true
|
248
|
+
end
|
249
|
+
|
250
|
+
opts.on(
|
251
|
+
"-u",
|
252
|
+
"--update",
|
253
|
+
"Download new art and refresh the cache"
|
254
|
+
) do
|
255
|
+
case options["action"]
|
256
|
+
when "draw"
|
257
|
+
options["action"] = "update"
|
258
|
+
else
|
259
|
+
puts(opts)
|
260
|
+
exit ArTTYExit::INVALID_OPTION
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
opts.on(
|
265
|
+
"-v",
|
266
|
+
"--verbose",
|
267
|
+
"Show backtrace when error occurs"
|
268
|
+
) do
|
269
|
+
options["verbose"] = true
|
270
|
+
end
|
271
|
+
|
272
|
+
opts.on("-V", "--version", "Show version") do
|
273
|
+
__FILE__.match(/arTTY-(\d+\.\d+\.\d+)/) do |m|
|
274
|
+
puts("arTTY version #{m[1]}")
|
275
|
+
end
|
276
|
+
exit ArTTYExit::GOOD
|
277
|
+
end
|
278
|
+
|
279
|
+
opts.on(
|
280
|
+
"",
|
281
|
+
"FIELDS",
|
282
|
+
" colors Show terminal colors",
|
283
|
+
" cpu Show cpu info",
|
284
|
+
" fs Show filesystem usage",
|
285
|
+
" host, hostname Show hostname",
|
286
|
+
" ip Show IPv4 and IPv6 addresses",
|
287
|
+
" ipv4 Show only IPv4 addresses",
|
288
|
+
" ipv6 Show only IPv6 addresses",
|
289
|
+
" kernel Show kernel info",
|
290
|
+
" os Show operating system info",
|
291
|
+
" ram Show RAM usage",
|
292
|
+
" shell Show current shell",
|
293
|
+
" tty Show TTY info",
|
294
|
+
" uptime Show uptime"
|
295
|
+
)
|
296
|
+
end
|
297
|
+
|
298
|
+
begin
|
299
|
+
parser.parse!
|
300
|
+
rescue OptionParser::InvalidOption => e
|
301
|
+
puts(e.message)
|
302
|
+
puts(parser)
|
303
|
+
exit ArTTYExit::INVALID_OPTION
|
304
|
+
rescue OptionParser::InvalidArgument => e
|
305
|
+
puts(e.message)
|
306
|
+
puts(parser)
|
307
|
+
exit ArTTYExit::INVALID_ARGUMENT
|
308
|
+
rescue OptionParser::MissingArgument => e
|
309
|
+
puts(e.message)
|
310
|
+
puts(parser)
|
311
|
+
exit ArTTYExit::MISSING_ARGUMENT
|
312
|
+
rescue OptionParser::AmbiguousOption => e
|
313
|
+
puts(e.message)
|
314
|
+
puts(parser)
|
315
|
+
exit ArTTYExit::AMBIGUOUS_ARGUMENT
|
316
|
+
end
|
317
|
+
|
318
|
+
if (args.length == 1)
|
319
|
+
options["random"] = false
|
320
|
+
options["art"] = args[0]
|
321
|
+
elsif (args.length > 1)
|
322
|
+
puts(parser)
|
323
|
+
exit ArTTYExit::EXTRA_ARGUMENTS
|
324
|
+
end
|
325
|
+
|
326
|
+
return options
|
327
|
+
end
|
328
|
+
|
329
|
+
def validate(cfg, opts)
|
330
|
+
if opts["all"]
|
331
|
+
cfg.no_fit
|
332
|
+
cfg.set_exclude("")
|
333
|
+
cfg.set_match("")
|
334
|
+
elsif opts["plain"]
|
335
|
+
cfg.default
|
336
|
+
cfg.no_clear_screen
|
337
|
+
cfg.no_fit
|
338
|
+
cfg.no_random
|
339
|
+
cfg.no_sysinfo
|
340
|
+
end
|
341
|
+
|
342
|
+
cfg.set_art(opts["art"])
|
343
|
+
cfg.clear_screen if (opts["clear"])
|
344
|
+
cfg.devexcuse if (opts["devexcuse"])
|
345
|
+
cfg.set_exclude(opts["exclude"]) if (!opts["exclude"].empty?)
|
346
|
+
cfg.set_fields(opts["fields"]) if (!opts["fields"].empty?)
|
347
|
+
cfg.fit if (opts["fit"])
|
348
|
+
cfg.fortune if (opts["fortune"])
|
349
|
+
cfg.set_match(opts["match"]) if (!opts["match"].empty?)
|
350
|
+
cfg.random if (opts["random"])
|
351
|
+
cfg.sysinfo if (opts["sysinfo"])
|
352
|
+
end
|
353
|
+
|
354
|
+
begin
|
355
|
+
options = parse(ARGV)
|
356
|
+
rescue Interrupt
|
357
|
+
# Exit gracefully on ^C
|
358
|
+
exit ArTTYExit::GOOD
|
359
|
+
end
|
360
|
+
|
361
|
+
begin
|
362
|
+
config = options["conf"]
|
363
|
+
validate(config, options)
|
364
|
+
|
365
|
+
arTTY = ArTTY.new
|
366
|
+
arTTY.exclude(config.get_exclude) if (config.exclude?)
|
367
|
+
arTTY.match(config.get_match) if (config.match?)
|
368
|
+
|
369
|
+
devexcuse = nil
|
370
|
+
if (config.devexcuse?)
|
371
|
+
devexcuse = get_devexcuse
|
372
|
+
end
|
373
|
+
|
374
|
+
fortune = nil
|
375
|
+
if (config.fortune? && ScoobyDoo.where_are_you("fortune"))
|
376
|
+
fortune = %x(fortune -s)
|
377
|
+
end
|
378
|
+
|
379
|
+
info = nil
|
380
|
+
if (config.sysinfo?)
|
381
|
+
info = ArTTY::SystemInfo.new(config.get_fields)
|
382
|
+
end
|
383
|
+
|
384
|
+
# Remove all that do not fit
|
385
|
+
if (config.fit?)
|
386
|
+
height = %x(tput lines).to_i - 4 # Leave some space for prompt
|
387
|
+
width = %x(tput cols).to_i - 1
|
388
|
+
if (config.sysinfo?)
|
389
|
+
width -= (info.width + 2)
|
390
|
+
info = nil if ((height <= info.height) || (width <= 0))
|
391
|
+
end
|
392
|
+
if (devexcuse)
|
393
|
+
eheight = devexcuse.split("\n").length
|
394
|
+
ewidth = devexcuse.split("\n").map(&:length).max
|
395
|
+
devexcuse = nil if (height <= eheight || ewidth > width)
|
396
|
+
height -= eheight if (devexcuse)
|
397
|
+
end
|
398
|
+
if (fortune)
|
399
|
+
fheight = fortune.split("\n").length
|
400
|
+
fwidth = fortune.split("\n").map(&:length).max
|
401
|
+
fortune = nil if (height <= fheight || fwidth > width)
|
402
|
+
height -= fheight if (fortune)
|
403
|
+
end
|
404
|
+
arTTY.fits(width, height)
|
405
|
+
end
|
406
|
+
|
407
|
+
case options["action"]
|
408
|
+
when "cache"
|
409
|
+
arTTY.cache
|
410
|
+
when "demo"
|
411
|
+
arTTY.art.each do |name|
|
412
|
+
puts("### #{name} ###".white)
|
413
|
+
art = arTTY.get(name, info).draw
|
414
|
+
puts("\n#{art}\n") if (!art.empty?)
|
415
|
+
end
|
416
|
+
when "draw"
|
417
|
+
# Randomize
|
418
|
+
if (!config.art? && config.random?)
|
419
|
+
config.set_art(arTTY.random)
|
420
|
+
end
|
421
|
+
|
422
|
+
# Ensure art is not nil
|
423
|
+
config.set_art("none") if (!config.art?)
|
424
|
+
|
425
|
+
# Clear screen if requested
|
426
|
+
system("clear") if (config.clear_screen?)
|
427
|
+
|
428
|
+
art = arTTY.get(config.get_art, info).draw
|
429
|
+
puts("\n#{art}\n") if (!art.empty?)
|
430
|
+
puts(devexcuse) if (devexcuse)
|
431
|
+
puts(fortune) if (fortune)
|
432
|
+
when "generate"
|
433
|
+
puts(
|
434
|
+
ArTTY::Generator.new.generate(
|
435
|
+
options["generate"],
|
436
|
+
options["conf"].getdiff("art")
|
437
|
+
)
|
438
|
+
)
|
439
|
+
when "list"
|
440
|
+
puts(arTTY.art)
|
441
|
+
when "save"
|
442
|
+
config.save
|
443
|
+
when "show"
|
444
|
+
puts(config)
|
445
|
+
when "update"
|
446
|
+
arTTY.cache(true)
|
447
|
+
end
|
448
|
+
rescue ArTTY::Error => e
|
449
|
+
$stderr.puts(e.message.white.on_red)
|
450
|
+
if (options["verbose"])
|
451
|
+
e.backtrace.each do |line|
|
452
|
+
$stderr.puts(line.yellow)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
exit ArTTYExit::EXCEPTION
|
456
|
+
rescue Interrupt
|
457
|
+
# Exit gracefully on ^C
|
458
|
+
rescue Errno::EPIPE
|
459
|
+
# Do nothing. This can happen if piping to another program such as
|
460
|
+
# less. Usually if less is closed before we're done with STDOUT.
|
461
|
+
rescue Exception => e
|
462
|
+
$stderr.puts(
|
463
|
+
[
|
464
|
+
"Oops! Looks like an error has occured! If the error",
|
465
|
+
"persists, file a bug at:"
|
466
|
+
].join(" ").wrap
|
467
|
+
)
|
468
|
+
$stderr.puts
|
469
|
+
$stderr.puts(" https://gitlab.com/mjwhitta/arTTY/issues")
|
470
|
+
$stderr.puts
|
471
|
+
$stderr.puts(
|
472
|
+
[
|
473
|
+
"Maybe the message below will help. If not, you can use",
|
474
|
+
"the --verbose flag to get a backtrace."
|
475
|
+
].join(" ").wrap
|
476
|
+
)
|
477
|
+
|
478
|
+
$stderr.puts(e.message.white.on_red)
|
479
|
+
if (options["verbose"])
|
480
|
+
e.backtrace.each do |line|
|
481
|
+
$stderr.puts(line.light_yellow)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
exit ArTTYExit::EXCEPTION
|
485
|
+
end
|
486
|
+
exit ArTTYExit::GOOD
|