doing 2.0.22 → 2.1.0pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +18 -15
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +36 -1
  6. data/Gemfile.lock +8 -1
  7. data/README.md +7 -1
  8. data/Rakefile +23 -4
  9. data/bin/doing +323 -173
  10. data/doc/Array.html +354 -1
  11. data/doc/Doing/Color.html +104 -92
  12. data/doc/Doing/Completion.html +216 -0
  13. data/doc/Doing/Configuration.html +340 -5
  14. data/doc/Doing/Content.html +229 -0
  15. data/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  16. data/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  17. data/doc/Doing/Errors/DoingStandardError.html +1 -1
  18. data/doc/Doing/Errors/EmptyInput.html +1 -1
  19. data/doc/Doing/Errors/NoResults.html +1 -1
  20. data/doc/Doing/Errors/PluginException.html +1 -1
  21. data/doc/Doing/Errors/UserCancelled.html +1 -1
  22. data/doc/Doing/Errors/WrongCommand.html +1 -1
  23. data/doc/Doing/Errors.html +1 -1
  24. data/doc/Doing/Hooks.html +1 -1
  25. data/doc/Doing/Item.html +337 -49
  26. data/doc/Doing/Items.html +444 -35
  27. data/doc/Doing/LogAdapter.html +139 -51
  28. data/doc/Doing/Note.html +253 -22
  29. data/doc/Doing/Pager.html +74 -36
  30. data/doc/Doing/Plugins.html +1 -1
  31. data/doc/Doing/Prompt.html +674 -0
  32. data/doc/Doing/Section.html +354 -0
  33. data/doc/Doing/Util.html +57 -1
  34. data/doc/Doing/WWID.html +477 -670
  35. data/doc/Doing/WWIDFile.html +398 -0
  36. data/doc/Doing.html +5 -5
  37. data/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  38. data/doc/GLI/Commands.html +1 -1
  39. data/doc/GLI.html +1 -1
  40. data/doc/Hash.html +97 -1
  41. data/doc/Status.html +37 -3
  42. data/doc/String.html +599 -23
  43. data/doc/Symbol.html +3 -3
  44. data/doc/Time.html +1 -1
  45. data/doc/_index.html +22 -1
  46. data/doc/class_list.html +1 -1
  47. data/doc/file.README.html +8 -2
  48. data/doc/index.html +8 -2
  49. data/doc/method_list.html +453 -173
  50. data/doc/top-level-namespace.html +1 -1
  51. data/doing.gemspec +3 -0
  52. data/doing.rdoc +79 -27
  53. data/example_plugin.rb +5 -5
  54. data/lib/completion/_doing.zsh +42 -42
  55. data/lib/completion/doing.bash +10 -10
  56. data/lib/completion/doing.fish +1 -280
  57. data/lib/doing/array.rb +36 -0
  58. data/lib/doing/colors.rb +70 -66
  59. data/lib/doing/completion/bash_completion.rb +1 -2
  60. data/lib/doing/completion/fish_completion.rb +1 -1
  61. data/lib/doing/completion/zsh_completion.rb +1 -1
  62. data/lib/doing/completion.rb +6 -0
  63. data/lib/doing/configuration.rb +134 -23
  64. data/lib/doing/hash.rb +37 -0
  65. data/lib/doing/item.rb +77 -12
  66. data/lib/doing/items.rb +125 -0
  67. data/lib/doing/log_adapter.rb +58 -4
  68. data/lib/doing/note.rb +53 -1
  69. data/lib/doing/pager.rb +49 -38
  70. data/lib/doing/plugins/export/markdown_export.rb +4 -4
  71. data/lib/doing/plugins/export/template_export.rb +2 -2
  72. data/lib/doing/plugins/import/calendar_import.rb +4 -4
  73. data/lib/doing/plugins/import/doing_import.rb +5 -7
  74. data/lib/doing/plugins/import/timing_import.rb +3 -3
  75. data/lib/doing/prompt.rb +206 -0
  76. data/lib/doing/section.rb +30 -0
  77. data/lib/doing/string.rb +123 -35
  78. data/lib/doing/util.rb +14 -6
  79. data/lib/doing/version.rb +1 -1
  80. data/lib/doing/wwid.rb +307 -614
  81. data/lib/doing.rb +6 -2
  82. data/lib/examples/plugins/capture_thing_import.rb +162 -0
  83. data/rdoc_to_mmd.rb +14 -8
  84. data/scripts/generate_bash_completions.rb +1 -1
  85. data/scripts/generate_fish_completions.rb +1 -1
  86. data/scripts/generate_zsh_completions.rb +1 -1
  87. metadata +73 -5
  88. data/lib/doing/wwidfile.rb +0 -117
data/lib/doing/string.rb CHANGED
@@ -20,8 +20,7 @@ module Doing
20
20
  ## can be separated by up to *distance* characters in
21
21
  ## haystack, spaces indicate unlimited distance.
22
22
  ##
23
- ## @example "this word".to_rx(2) =>
24
- ## /t.{0,3}h.{0,3}i.{0,3}s.{0,3}.*?w.{0,3}o.{0,3}r.{0,3}d/
23
+ ## @example `"this word".to_rx(2) => /t.{0,3}h.{0,3}i.{0,3}s.{0,3}.*?w.{0,3}o.{0,3}r.{0,3}d/`
25
24
  ##
26
25
  ## @param distance [Integer] Allowed distance
27
26
  ## between characters
@@ -63,6 +62,15 @@ module Doing
63
62
  end
64
63
  end
65
64
 
65
+ # Compress multiple spaces to single space
66
+ def compress
67
+ gsub(/ +/, ' ').strip
68
+ end
69
+
70
+ def compress!
71
+ replace compress
72
+ end
73
+
66
74
  ## @param (see #highlight_tags)
67
75
  def highlight_tags!(color = 'yellow')
68
76
  replace highlight_tags(color)
@@ -289,11 +297,29 @@ module Doing
289
297
  title
290
298
  end
291
299
 
292
- def tag!(tag, value: nil, remove: false, rename_to: nil, regex: false, single: false)
293
- replace tag(tag, value: value, remove: remove, rename_to: rename_to, regex: regex, single: single)
300
+ ##
301
+ ## Add, rename, or remove a tag in place
302
+ ##
303
+ ## @see #tag
304
+ ##
305
+ def tag!(tag, **options)
306
+ replace tag(tag, **options)
294
307
  end
295
308
 
296
- def tag(tag, value: nil, remove: false, rename_to: nil, regex: false, single: false)
309
+ ##
310
+ ## Add, rename, or remove a tag
311
+ ##
312
+ ## @param tag The tag
313
+ ## @param value [String] Value for tag (@tag(value))
314
+ ## @param remove [Boolean] Remove the tag instead of adding
315
+ ## @param rename_to [String] Replace tag with this tag
316
+ ## @param regex [Boolean] Tag is regular expression
317
+ ## @param single [Boolean] Operating on a single item (for logging)
318
+ ## @param force [Boolean] With rename_to, add tag if it doesn't exist
319
+ ##
320
+ ## @return [String] The string with modified tags
321
+ ##
322
+ def tag(tag, value: nil, remove: false, rename_to: nil, regex: false, single: false, force: false)
297
323
  log_level = single ? :info : :debug
298
324
  title = dup
299
325
  title.chomp!
@@ -307,13 +333,14 @@ module Doing
307
333
  end
308
334
 
309
335
  if remove || rename_to
310
- return title unless title =~ /#{rx_tag}(?=[ (]|$)/
336
+ rx = Regexp.new("(?<=^| )@#{rx_tag}(?<parens>\\((?<value>[^)]*)\\))?(?= |$)", case_sensitive)
337
+ m = title.match(rx)
311
338
 
312
- rx = Regexp.new("(^| )@#{rx_tag}(\\([^)]*\\))?(?= |$)", case_sensitive)
313
- if title =~ rx
339
+ if m.nil? && rename_to && force
340
+ title.tag!(rename_to, value: value, single: single)
341
+ elsif m
314
342
  title.gsub!(rx) do
315
- m = Regexp.last_match
316
- rename_to ? "#{m[1]}@#{rename_to}#{m[2]}" : m[1]
343
+ rename_to ? "@#{rename_to}#{value.nil? ? m['parens'] : "(#{value})"}" : ''
317
344
  end
318
345
 
319
346
  title.dedup_tags!
@@ -373,9 +400,16 @@ module Doing
373
400
  title
374
401
  end
375
402
 
376
- # Returns the last escape sequence from a string
403
+ # Returns the last escape sequence from a string.
404
+ #
405
+ # Actually returns all escape codes, with the assumption
406
+ # that the result of inserting them will generate the
407
+ # same color as was set at the end of the string.
408
+ # Because you can send modifiers like dark and bold
409
+ # separate from color codes, only using the last code
410
+ # may not render the same style.
377
411
  #
378
- # @param string The string to examine
412
+ # @return [String] All escape codes in string
379
413
  #
380
414
  def last_color
381
415
  scan(/\e\[[\d;]+m/).join('')
@@ -386,42 +420,62 @@ module Doing
386
420
  ##
387
421
  ## @param opt [Hash] Additional Options
388
422
  ##
389
- def link_urls!(opt = {})
390
- replace link_urls(opt)
423
+ def link_urls!(**opt)
424
+ fmt = opt.fetch(:format, :html)
425
+ replace link_urls(format: fmt)
391
426
  end
392
427
 
393
- def link_urls(opt = {})
394
- opt[:format] ||= :html
395
- str = self.dup
428
+ def link_urls(**opt)
429
+ fmt = opt.fetch(:format, :html)
430
+ return self unless fmt
396
431
 
397
- if :format == :markdown
398
- # Remove <self-linked> formatting
399
- str.gsub!(/<(.*?)>/) do |match|
400
- m = Regexp.last_match
401
- if m[1] =~ /^https?:/
402
- m[1]
403
- else
404
- match
405
- end
432
+ str = dup
433
+
434
+ str = str.remove_self_links if fmt == :markdown
435
+
436
+ str.replace_qualified_urls(format: fmt).clean_unlinked_urls
437
+ end
438
+
439
+ # Remove <self-linked> formatting
440
+ def remove_self_links
441
+ gsub(/<(.*?)>/) do |match|
442
+ m = Regexp.last_match
443
+ if m[1] =~ /^https?:/
444
+ m[1]
445
+ else
446
+ match
406
447
  end
407
448
  end
449
+ end
408
450
 
409
- # Replace qualified urls
410
- str.gsub!(%r{(?mi)(?<!["'\[(\\])((http|https)://)([\w\-_]+(\.[\w\-_]+)+)([\w\-.,@?^=%&amp;:/~+#]*[\w\-@^=%&amp;/~+#])?}) do |_match|
451
+ # Replace qualified urls
452
+ def replace_qualified_urls(**options)
453
+ fmt = options.fetch(:format, :html)
454
+ gsub(%r{(?mi)(?x:
455
+ (?<!["'\[(\\])
456
+ (?<protocol>(?:http|https)://)
457
+ (?<domain>[\w\-]+(?:\.[\w\-]+)+)
458
+ (?<path>[\w\-.,@?^=%&;:/~+#]*[\w\-@^=%&;/~+#])?
459
+ )}) do |_match|
411
460
  m = Regexp.last_match
412
- proto = m[1].nil? ? 'http://' : ''
413
- case opt[:format]
461
+ url = "#{m['domain']}#{m['path']}"
462
+ proto = m['protocol'].nil? ? 'http://' : m['protocol']
463
+ case fmt
464
+ when :terminal
465
+ TTY::Link.link_to("#{proto}#{url}", "#{proto}#{url}")
414
466
  when :html
415
- %(<a href="#{proto}#{m[0]}" title="Link to #{m[0].sub(/^https?:\/\//, '')}">[#{m[3]}]</a>)
467
+ %(<a href="#{proto}#{url}" title="Link to #{m['domain']}">[#{url}]</a>)
416
468
  when :markdown
417
- "[#{m[0]}](#{proto}#{m[0]})"
469
+ "[#{url}](#{proto}#{url})"
418
470
  else
419
471
  m[0]
420
472
  end
421
473
  end
474
+ end
422
475
 
423
- # Clean up unlinked <urls>
424
- str.gsub!(/<(\w+:.*?)>/) do |match|
476
+ # Clean up unlinked <urls>
477
+ def clean_unlinked_urls
478
+ gsub(/<(\w+:.*?)>/) do |match|
425
479
  m = Regexp.last_match
426
480
  if m[1] =~ /<a href/
427
481
  match
@@ -429,8 +483,42 @@ module Doing
429
483
  %(<a href="#{m[1]}" title="Link to #{m[1]}">[link]</a>)
430
484
  end
431
485
  end
486
+ end
432
487
 
433
- str
488
+ def set_type(kind = nil)
489
+ if kind
490
+ case kind.to_s
491
+ when /^a/i
492
+ gsub(/^\[ *| *\]$/, '').split(/ *, */)
493
+ when /^i/i
494
+ to_i
495
+ when /^f/i
496
+ to_f
497
+ when /^sy/i
498
+ sub(/^:/, '').to_sym
499
+ when /^b/i
500
+ self =~ /^(true|yes)$/ ? true : false
501
+ else
502
+ to_s
503
+ end
504
+ else
505
+ case self
506
+ when / *, */
507
+ gsub(/^\[ *| *\]$/, '').split(/ *, */)
508
+ when /^[0-9]+$/
509
+ to_i
510
+ when /^[0-9]+\.[0-9]+$/
511
+ to_f
512
+ when /^:\w+/
513
+ sub(/^:/, '').to_sym
514
+ when /^(true|yes)$/i
515
+ true
516
+ when /^(false|no)$/i
517
+ false
518
+ else
519
+ to_s
520
+ end
521
+ end
434
522
  end
435
523
  end
436
524
  end
data/lib/doing/util.rb CHANGED
@@ -21,11 +21,17 @@ module Doing
21
21
  def exec_available(cli)
22
22
  return false if cli.nil?
23
23
 
24
- if File.exist?(File.expand_path(cli))
25
- File.executable?(File.expand_path(cli))
26
- else
27
- system "which #{cli}", out: File::NULL, err: File::NULL
28
- end
24
+ !TTY::Which.which(cli).nil?
25
+ end
26
+
27
+ ##
28
+ ## Return the first valid executable from a list of commands
29
+ ##
30
+ ## @example `Doing::Util.first_available_exec('bat', 'less -Xr', 'more -r', 'cat')`
31
+ ##
32
+ def first_available_exec(*commands)
33
+ commands.compact.map(&:strip).reject(&:empty?).uniq
34
+ .find { |cmd| exec_available(cmd.split.first) }
29
35
  end
30
36
 
31
37
  def merge_default_proc(target, overwrite)
@@ -116,6 +122,7 @@ module Doing
116
122
 
117
123
  File.open(file, 'w+') do |f|
118
124
  f.puts content
125
+ Doing.logger.debug('Write:', "File written: #{file}")
119
126
  end
120
127
 
121
128
  Hooks.trigger :post_write, file
@@ -183,7 +190,8 @@ module Doing
183
190
  Doing.logger.debug('ENV:', 'No EDITOR environment variable, testing available editors')
184
191
  editors = %w[vim vi code subl mate mvim nano emacs]
185
192
  editors.each do |ed|
186
- return ed if exec_available(ed)
193
+ return TTY::Which.which(ed) if TTY::Which.which(ed)
194
+
187
195
  Doing.logger.debug('ENV:', "#{ed} not available")
188
196
  end
189
197
 
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.0.22'
2
+ VERSION = '2.1.0pre'
3
3
  end