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.
@@ -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
@@ -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