doing 2.0.18 → 2.0.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/Gemfile.lock +15 -5
  4. data/README.md +1 -1
  5. data/bin/doing +2 -18
  6. data/doing.gemspec +5 -4
  7. data/doing.rdoc +2 -2
  8. data/generate_completions.sh +3 -3
  9. data/lib/doing/cli_status.rb +6 -2
  10. data/lib/doing/completion/bash_completion.rb +185 -0
  11. data/lib/doing/completion/fish_completion.rb +175 -0
  12. data/lib/doing/completion/string.rb +17 -0
  13. data/lib/doing/completion/zsh_completion.rb +140 -0
  14. data/lib/doing/completion.rb +39 -0
  15. data/lib/doing/version.rb +1 -1
  16. data/lib/doing/wwid.rb +18 -6
  17. data/lib/doing.rb +1 -1
  18. data/lib/helpers/fzf/.goreleaser.yml +119 -0
  19. data/lib/helpers/fzf/.rubocop.yml +28 -0
  20. data/lib/helpers/fzf/ADVANCED.md +565 -0
  21. data/lib/helpers/fzf/BUILD.md +49 -0
  22. data/lib/helpers/fzf/CHANGELOG.md +1193 -0
  23. data/lib/helpers/fzf/Dockerfile +11 -0
  24. data/lib/helpers/fzf/LICENSE +21 -0
  25. data/lib/helpers/fzf/Makefile +166 -0
  26. data/lib/helpers/fzf/README-VIM.md +486 -0
  27. data/lib/helpers/fzf/README.md +712 -0
  28. data/lib/helpers/fzf/bin/fzf-tmux +233 -0
  29. data/lib/helpers/fzf/doc/fzf.txt +512 -0
  30. data/lib/helpers/fzf/go.mod +17 -0
  31. data/lib/helpers/fzf/go.sum +31 -0
  32. data/lib/helpers/fzf/install +382 -0
  33. data/lib/helpers/fzf/install.ps1 +65 -0
  34. data/lib/helpers/fzf/main.go +14 -0
  35. data/lib/helpers/fzf/man/man1/fzf-tmux.1 +68 -0
  36. data/lib/helpers/fzf/man/man1/fzf.1 +1001 -0
  37. data/lib/helpers/fzf/plugin/fzf.vim +1048 -0
  38. data/lib/helpers/fzf/shell/completion.bash +381 -0
  39. data/lib/helpers/fzf/shell/completion.zsh +329 -0
  40. data/lib/helpers/fzf/shell/key-bindings.bash +96 -0
  41. data/lib/helpers/fzf/shell/key-bindings.fish +172 -0
  42. data/lib/helpers/fzf/shell/key-bindings.zsh +114 -0
  43. data/lib/helpers/fzf/src/LICENSE +21 -0
  44. data/lib/helpers/fzf/src/algo/algo.go +884 -0
  45. data/lib/helpers/fzf/src/algo/algo_test.go +197 -0
  46. data/lib/helpers/fzf/src/algo/normalize.go +492 -0
  47. data/lib/helpers/fzf/src/ansi.go +409 -0
  48. data/lib/helpers/fzf/src/ansi_test.go +427 -0
  49. data/lib/helpers/fzf/src/cache.go +81 -0
  50. data/lib/helpers/fzf/src/cache_test.go +39 -0
  51. data/lib/helpers/fzf/src/chunklist.go +89 -0
  52. data/lib/helpers/fzf/src/chunklist_test.go +80 -0
  53. data/lib/helpers/fzf/src/constants.go +85 -0
  54. data/lib/helpers/fzf/src/core.go +351 -0
  55. data/lib/helpers/fzf/src/history.go +96 -0
  56. data/lib/helpers/fzf/src/history_test.go +68 -0
  57. data/lib/helpers/fzf/src/item.go +44 -0
  58. data/lib/helpers/fzf/src/item_test.go +23 -0
  59. data/lib/helpers/fzf/src/matcher.go +235 -0
  60. data/lib/helpers/fzf/src/merger.go +120 -0
  61. data/lib/helpers/fzf/src/merger_test.go +88 -0
  62. data/lib/helpers/fzf/src/options.go +1691 -0
  63. data/lib/helpers/fzf/src/options_test.go +457 -0
  64. data/lib/helpers/fzf/src/pattern.go +425 -0
  65. data/lib/helpers/fzf/src/pattern_test.go +209 -0
  66. data/lib/helpers/fzf/src/protector/protector.go +8 -0
  67. data/lib/helpers/fzf/src/protector/protector_openbsd.go +10 -0
  68. data/lib/helpers/fzf/src/reader.go +201 -0
  69. data/lib/helpers/fzf/src/reader_test.go +63 -0
  70. data/lib/helpers/fzf/src/result.go +243 -0
  71. data/lib/helpers/fzf/src/result_others.go +16 -0
  72. data/lib/helpers/fzf/src/result_test.go +159 -0
  73. data/lib/helpers/fzf/src/result_x86.go +16 -0
  74. data/lib/helpers/fzf/src/terminal.go +2832 -0
  75. data/lib/helpers/fzf/src/terminal_test.go +638 -0
  76. data/lib/helpers/fzf/src/terminal_unix.go +26 -0
  77. data/lib/helpers/fzf/src/terminal_windows.go +45 -0
  78. data/lib/helpers/fzf/src/tokenizer.go +253 -0
  79. data/lib/helpers/fzf/src/tokenizer_test.go +112 -0
  80. data/lib/helpers/fzf/src/tui/dummy.go +46 -0
  81. data/lib/helpers/fzf/src/tui/light.go +987 -0
  82. data/lib/helpers/fzf/src/tui/light_unix.go +110 -0
  83. data/lib/helpers/fzf/src/tui/light_windows.go +145 -0
  84. data/lib/helpers/fzf/src/tui/tcell.go +721 -0
  85. data/lib/helpers/fzf/src/tui/tcell_test.go +392 -0
  86. data/lib/helpers/fzf/src/tui/ttyname_unix.go +47 -0
  87. data/lib/helpers/fzf/src/tui/ttyname_windows.go +14 -0
  88. data/lib/helpers/fzf/src/tui/tui.go +625 -0
  89. data/lib/helpers/fzf/src/tui/tui_test.go +20 -0
  90. data/lib/helpers/fzf/src/util/atomicbool.go +34 -0
  91. data/lib/helpers/fzf/src/util/atomicbool_test.go +17 -0
  92. data/lib/helpers/fzf/src/util/chars.go +198 -0
  93. data/lib/helpers/fzf/src/util/chars_test.go +46 -0
  94. data/lib/helpers/fzf/src/util/eventbox.go +96 -0
  95. data/lib/helpers/fzf/src/util/eventbox_test.go +61 -0
  96. data/lib/helpers/fzf/src/util/slab.go +12 -0
  97. data/lib/helpers/fzf/src/util/util.go +138 -0
  98. data/lib/helpers/fzf/src/util/util_test.go +40 -0
  99. data/lib/helpers/fzf/src/util/util_unix.go +47 -0
  100. data/lib/helpers/fzf/src/util/util_windows.go +83 -0
  101. data/lib/helpers/fzf/test/fzf.vader +175 -0
  102. data/lib/helpers/fzf/test/test_go.rb +2626 -0
  103. data/lib/helpers/fzf/uninstall +117 -0
  104. data/scripts/generate_bash_completions.rb +6 -12
  105. data/scripts/generate_fish_completions.rb +7 -16
  106. data/scripts/generate_zsh_completions.rb +6 -15
  107. metadata +144 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbd007c83df322397ff7da7025dfbc0e31fd0b54b3247bfffb2e7a61134366a5
4
- data.tar.gz: 78e741e12e3f28771d68bc7028caf2ed03edb677be1cfe8f975f32406d3d4f01
3
+ metadata.gz: 36dd66af3e00464697ab6eb89101e501e0b50ee6b21bc8629a13e21b3906c18a
4
+ data.tar.gz: 758903fc78fd9a812ab723a5af00cdec0c6cd13c1316dc638e9ca10f24bf939a
5
5
  SHA512:
6
- metadata.gz: 1a7262555d07ecea5e0e504df1edaacd48654156a50dff44f1d5ee365c04b6c5ae5f4785d9a97f7b6363c450d8184f186aff21ac47653684494e5aec3d1e5f8a
7
- data.tar.gz: 1b2e38445ffbe3a6a9687bdd8607f5b41591a4370e4ac68f4036155baceac97e98a50c58cb31e1948f6bdbfd6419fa419e9e1db75170e339227e09361f0b601b
6
+ metadata.gz: e755266bcfedb72b69f966a2621af76b5014168cd44898c2ba24b0dfc711482aef6a3694afd8010abbeb3bdeb88749532b15f1699ab6926227679ffb7308758d
7
+ data.tar.gz: f892efc03f34754866f436603e49c3e3f9b9ec52496ecdcddb1c5783abc485b7996bb5385d531a5814a4ee9b52d262f754545ee4a0a0559e49ccfff56de38bdb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ### 2.0.22
2
+
3
+ #### IMPROVED
4
+
5
+ - include fzf source directly, in case git isn't installed
6
+
7
+ ### 2.0.20
8
+
9
+ #### IMPROVED
10
+
11
+ - completion script generator refactor and progress bars
12
+
13
+ #### FIXED
14
+
15
+ - compile fzf for current operating system
16
+
17
+ ### 2.0.19
18
+
19
+ #### FIXED
20
+
21
+ - Remove any coloring before writing to doing file
22
+
1
23
  ### 2.0.18
2
24
 
3
25
  #### FIXED
data/Gemfile.lock CHANGED
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- doing (2.0.18)
4
+ doing (2.0.22)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  deep_merge (~> 1.2, >= 1.2.1)
7
7
  gli (~> 2.19, >= 2.19.2)
8
8
  haml (~> 5.0.0, >= 5.0.0)
9
9
  safe_yaml (~> 1.0)
10
+ tty-progressbar (~> 0.18, >= 0.18.2)
10
11
 
11
12
  GEM
12
13
  remote: http://rubygems.org/
@@ -89,6 +90,7 @@ GEM
89
90
  rspec-support (~> 3.10.0)
90
91
  rspec-support (3.10.3)
91
92
  safe_yaml (1.0.5)
93
+ strings-ansi (0.2.0)
92
94
  sys-uname (1.2.2)
93
95
  ffi (~> 1.1)
94
96
  temple (0.8.2)
@@ -97,8 +99,16 @@ GEM
97
99
  thor (1.1.0)
98
100
  thread_safe (0.3.6)
99
101
  tilt (2.0.10)
102
+ tty-cursor (0.7.1)
103
+ tty-progressbar (0.18.2)
104
+ strings-ansi (~> 0.2)
105
+ tty-cursor (~> 0.7)
106
+ tty-screen (~> 0.8)
107
+ unicode-display_width (>= 1.6, < 3.0)
108
+ tty-screen (0.8.1)
100
109
  tzinfo (2.0.4)
101
110
  concurrent-ruby (~> 1.0)
111
+ unicode-display_width (2.1.0)
102
112
  yard (0.9.26)
103
113
  zeitwerk (2.5.1)
104
114
 
@@ -108,13 +118,13 @@ PLATFORMS
108
118
  DEPENDENCIES
109
119
  aruba (~> 1.0.2)
110
120
  doing!
111
- github-markup
112
- parallel_tests
121
+ github-markup (~> 4.0, >= 4.0.0)
122
+ parallel_tests (~> 3.7, >= 3.7.3)
113
123
  rake (~> 13.0, >= 13.0.1)
114
124
  rdoc (~> 6.3.1)
115
- redcarpet
125
+ redcarpet (~> 3.5, >= 3.5.1)
116
126
  test-unit (~> 3.4.4)
117
- yard
127
+ yard (~> 0.9, >= 0.9.26)
118
128
 
119
129
  BUNDLED WITH
120
130
  2.2.17
data/README.md CHANGED
@@ -6,7 +6,7 @@ _If you're one of the rare people like me who find this useful, feel free to [bu
6
6
 
7
7
  <!--README-->
8
8
 
9
- The current version of `doing` is <!--VER-->2.0.17<!--END VER-->.
9
+ The current version of `doing` is <!--VER-->2.0.21<!--END VER-->.
10
10
 
11
11
  Find all of the documentation in the [doing wiki](https://github.com/ttscoff/doing/wiki).
12
12
 
data/bin/doing CHANGED
@@ -2149,28 +2149,12 @@ command :completion do |c|
2149
2149
 
2150
2150
  c.desc 'File to write output to'
2151
2151
  c.arg_name 'PATH'
2152
- c.flag %i[f file], default_value: 'stdout'
2152
+ c.flag %i[f file], default_value: 'STDOUT'
2153
2153
 
2154
2154
  c.action do |_global_options, options, _args|
2155
2155
  script_dir = File.join(File.dirname(__FILE__), '..', 'scripts')
2156
2156
 
2157
- case options[:type]
2158
- when /^b/
2159
- result = `ruby #{File.join(script_dir, 'generate_bash_completions.rb')}`
2160
- when /^z/
2161
- result = `ruby #{File.join(script_dir, 'generate_zsh_completions.rb')}`
2162
- when /^f/
2163
- result = `ruby #{File.join(script_dir, 'generate_fish_completions.rb')}`
2164
- end
2165
-
2166
- if options[:file] =~ /^stdout$/i
2167
- $stdout.puts result
2168
- else
2169
- File.open(File.expand_path(options[:file]), 'w') do |f|
2170
- f.puts result
2171
- end
2172
- Doing.logger.warn('File written:', "#{options[:type]} completions written to #{options[:file]}")
2173
- end
2157
+ Doing::Completion.generate_completion(type: options[:type], file: options[:file])
2174
2158
  end
2175
2159
  end
2176
2160
 
data/doing.gemspec CHANGED
@@ -27,10 +27,11 @@ spec = Gem::Specification.new do |s|
27
27
  s.add_development_dependency 'rdoc', '~> 6.3.1'
28
28
  s.add_development_dependency 'aruba', '~> 1.0.2'
29
29
  s.add_development_dependency 'test-unit', '~> 3.4.4'
30
- s.add_development_dependency 'yard'
31
- s.add_development_dependency 'redcarpet'
32
- s.add_development_dependency 'github-markup'
33
- s.add_development_dependency 'parallel_tests'
30
+ s.add_development_dependency 'yard', '~> 0.9', '>= 0.9.26'
31
+ s.add_development_dependency 'redcarpet', '~> 3.5', '>= 3.5.1'
32
+ s.add_development_dependency 'github-markup', '~> 4.0', '>= 4.0.0'
33
+ s.add_development_dependency 'parallel_tests', '~> 3.7', '>= 3.7.3'
34
+ s.add_runtime_dependency('tty-progressbar', '~> 0.18', '>= 0.18.2')
34
35
  s.add_runtime_dependency('gli', '~> 2.19', '>= 2.19.2')
35
36
  s.add_runtime_dependency('haml','~>5.0.0', '>= 5.0.0')
36
37
  s.add_runtime_dependency('chronic','~> 0.10', '>= 0.10.2')
data/doing.rdoc CHANGED
@@ -5,7 +5,7 @@ record of what you've been doing, complete with tag-based time tracking. The
5
5
  command line tool allows you to add entries, annotate with tags and notes, and
6
6
  view your entries with myriad options, with a focus on a "natural" language syntax.
7
7
 
8
- v2.0.18
8
+ v2.0.22
9
9
 
10
10
  === Global Options
11
11
  === --config_file arg
@@ -374,7 +374,7 @@ Generate shell completion scripts
374
374
 
375
375
  File to write output to
376
376
 
377
- [Default Value] stdout
377
+ [Default Value] STDOUT
378
378
 
379
379
 
380
380
  ===== -t|--type SHELL
@@ -1,5 +1,5 @@
1
1
  #!/bin/bash
2
2
 
3
- scripts/generate_fish_completions.rb > lib/completion/doing.fish
4
- scripts/generate_bash_completions.rb > lib/completion/doing.bash
5
- scripts/generate_zsh_completions.rb > lib/completion/_doing.zsh
3
+ bundle exec bin/doing completion --type fish --file lib/completion/doing.fish
4
+ bundle exec bin/doing completion --type bash --file lib/completion/doing.bash
5
+ bundle exec bin/doing completion --type zsh --file lib/completion/_doing.zsh
@@ -14,8 +14,12 @@ module Status
14
14
  $stderr.print format("#{esc['kill']}#{esc['boldyellow']}> #{esc['boldgreen']}%s #{esc['white']}[#{esc['boldwhite']}%#{@commands.count.to_s.length}d#{esc['boldblack']}/#{esc['boldyellow']}%d#{esc['white']}]: #{esc['boldcyan']}%s#{esc['default']}\r", msg, idx, total, tail)
15
15
  end
16
16
 
17
- def status(msg, reset: true)
18
- $stderr.print format("#{esc['kill']}#{esc['boldyellow']}> #{esc['whiteboard']}%s#{esc['default']}%s", msg, reset ? "\r" : "\n")
17
+ def status(msg, reset: true, end_char: "\n")
18
+ $stderr.print format("#{esc['kill']}#{esc['boldyellow']}> #{esc['whiteboard']}%s#{esc['default']}%s", msg, reset ? "\r" : end_char)
19
+ end
20
+
21
+ def msg(msg, reset: true, color: 'green', end_char: "\n")
22
+ $stderr.print format("#{esc['kill']}#{esc[color]}%s#{esc['default']}%s", msg, reset ? "\r" : end_char)
19
23
  end
20
24
 
21
25
  def clear
@@ -0,0 +1,185 @@
1
+ module Doing
2
+ module Completion
3
+ class BashCompletions
4
+ attr_accessor :commands, :global_options
5
+
6
+ def main_function
7
+ first = true
8
+ out = []
9
+ logic = []
10
+ need_export = []
11
+
12
+ @commands.each_with_index do |cmd, i|
13
+ @bar.advance
14
+
15
+ data = get_help_sections(cmd[:commands].first)
16
+
17
+ arg = data[:synopsis].join(' ').strip.split(/ /).last
18
+ case arg
19
+ when /(path|file)/i
20
+ type = :file
21
+ when /sect/i
22
+ type = 'sections'
23
+ when /view/i
24
+ type = 'views'
25
+ else
26
+ type = nil
27
+ end
28
+
29
+ if data[:command_options]
30
+ options = parse_options(data[:command_options])
31
+ out << command_function(cmd[:commands].first, options, type)
32
+
33
+ if first
34
+ op = 'if'
35
+ first = false
36
+ else
37
+ op = 'elif'
38
+ end
39
+ logic << %(#{op} [[ $last =~ (#{cmd[:commands].join('|')}) ]]; then _doing_#{cmd[:commands].first})
40
+ end
41
+ end
42
+
43
+ out << <<~EOFUNC
44
+ _doing()
45
+ {
46
+ local last="${@: -1}"
47
+ local token=${COMP_WORDS[$COMP_CWORD]}
48
+
49
+ #{logic.join("\n ")}
50
+ else
51
+ OLD_IFS="$IFS"
52
+ IFS=$'\n'
53
+ COMPREPLY=( $(compgen -W "$(doing help -c)" -- $token) )
54
+ IFS="$OLD_IFS"
55
+ fi
56
+ }
57
+ EOFUNC
58
+ out.join("\n")
59
+ end
60
+
61
+ def command_function(command, options, type)
62
+ long_options = []
63
+ short_options = []
64
+
65
+ options.each do |o|
66
+ next if o.nil?
67
+
68
+ long_options << o[:long] if o[:long]
69
+ short_options << o[:short] if o[:short]
70
+ end
71
+
72
+ long = long_options.map! {|o| "--#{o}"}.join(' ')
73
+ short = short_options.map! {|o| "-#{o}"}.join(' ')
74
+ words = ''
75
+ logic = ''
76
+ words, logic = get_words(type) if type && type.is_a?(String)
77
+
78
+ func = <<~ENDFUNC
79
+ _doing_#{command}() {
80
+ #{words}
81
+ if [[ "$token" == --* ]]; then
82
+ COMPREPLY=( $( compgen -W '#{long}' -- $token ) )
83
+ elif [[ "$token" == -* ]]; then
84
+ COMPREPLY=( $( compgen -W '#{short} #{long}' -- $token ) )
85
+ #{logic}
86
+ fi
87
+ }
88
+ ENDFUNC
89
+
90
+ func
91
+ end
92
+
93
+ def get_words(type)
94
+ func = <<~EOFUNC
95
+ OLD_IFS="$IFS"
96
+ local token=${COMP_WORDS[$COMP_CWORD]}
97
+ IFS=$'\t'
98
+ local words=$(doing #{type})
99
+ IFS="$OLD_IFS"
100
+ EOFUNC
101
+
102
+ logic = <<~EOLOGIC
103
+ else
104
+ local nocasematchWasOff=0
105
+ shopt nocasematch >/dev/null || nocasematchWasOff=1
106
+ (( nocasematchWasOff )) && shopt -s nocasematch
107
+ local w matches=()
108
+ OLD_IFS="$IFS"
109
+ IFS=$'\t'‰
110
+ for w in $words; do
111
+ if [[ "$w" == "$token"* ]]; then
112
+ matches+=("${w// /\ }")
113
+ fi
114
+ done
115
+ IFS="$OLD_IFS"
116
+ (( nocasematchWasOff )) && shopt -u nocasematch
117
+ COMPREPLY=("${matches[@]}")
118
+ EOLOGIC
119
+
120
+ [func, logic]
121
+ end
122
+
123
+
124
+
125
+ def get_help_sections(command = '')
126
+ res = `doing help #{command}`.strip
127
+ scanned = res.scan(/(?m-i)^([A-Z ]+)\n([\s\S]*?)(?=\n+[A-Z]+|\Z)/)
128
+ sections = {}
129
+ scanned.each do |sect|
130
+ title = sect[0].downcase.strip.gsub(/ +/, '_').to_sym
131
+ content = sect[1].split(/\n/).map(&:strip).delete_if(&:empty?)
132
+ sections[title] = content
133
+ end
134
+ sections
135
+ end
136
+
137
+ def parse_option(option)
138
+ res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>[\w_]+)(?:=(?<arg>\w+))?)\s+- (?<desc>.*?)$/)
139
+ return nil unless res
140
+ {
141
+ short: res['short'],
142
+ long: res['long'],
143
+ arg: res[:arg],
144
+ description: res['desc'].short_desc
145
+ }
146
+ end
147
+
148
+ def parse_options(options)
149
+ options.map { |opt| parse_option(opt) }
150
+ end
151
+
152
+ def parse_command(command)
153
+ res = command.match(/^(?<cmd>[^, \t]+)(?<alias>(?:, [^, \t]+)*)?\s+- (?<desc>.*?)$/)
154
+ commands = [res['cmd']]
155
+ commands.concat(res['alias'].split(/, /).delete_if(&:empty?)) if res['alias']
156
+
157
+ {
158
+ commands: commands,
159
+ description: res['desc'].short_desc
160
+ }
161
+ end
162
+
163
+ def parse_commands(commands)
164
+ commands.map { |cmd| parse_command(cmd) }
165
+ end
166
+
167
+ def initialize
168
+ data = get_help_sections
169
+ @global_options = parse_options(data[:global_options])
170
+ @commands = parse_commands(data[:commands])
171
+ @bar = TTY::ProgressBar.new("\033[0;0;33mGenerating Bash completions: \033[0;35;40m[:bar]\033[0m", total: @commands.count, bar_format: :blade)
172
+ @bar.resize(25)
173
+ end
174
+
175
+ def generate_completions
176
+ @bar.start
177
+ out = []
178
+ out << main_function
179
+ out << 'complete -F _doing doing'
180
+ @bar.finish
181
+ out.join("\n")
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,175 @@
1
+ module Doing
2
+ module Completion
3
+ class FishCompletions
4
+
5
+ attr_accessor :commands, :global_options
6
+
7
+ def generate_helpers
8
+ <<~EOFUNCTIONS
9
+ function __fish_doing_needs_command
10
+ # Figure out if the current invocation already has a command.
11
+
12
+ set -l opts h-help config_file= f-doing_file= n-notes v-version stdout d-debug default x-noauto
13
+ set cmd (commandline -opc)
14
+ set -e cmd[1]
15
+ argparse -s $opts -- $cmd 2>/dev/null
16
+ or return 0
17
+ # These flags function as commands, effectively.
18
+ if set -q argv[1]
19
+ # Also print the command, so this can be used to figure out what it is.
20
+ echo $argv[1]
21
+ return 1
22
+ end
23
+ return 0
24
+ end
25
+
26
+ function __fish_doing_using_command
27
+ set -l cmd (__fish_doing_needs_command)
28
+ test -z "$cmd"
29
+ and return 1
30
+ contains -- $cmd $argv
31
+ and return 0
32
+ end
33
+
34
+ function __fish_doing_complete_sections
35
+ doing sections -c
36
+ end
37
+
38
+ function __fish_doing_complete_views
39
+ doing views -c
40
+ end
41
+
42
+ function __fish_doing_subcommands
43
+ doing help -c
44
+ end
45
+
46
+ function __fish_doing_export_plugins
47
+ doing plugins --type export -c
48
+ end
49
+
50
+ function __fish_doing_import_plugins
51
+ doing plugins --type import -c
52
+ end
53
+
54
+ function __fish_doing_complete_templates
55
+ doing template -c
56
+ end
57
+
58
+ complete -c doing -f
59
+ complete -xc doing -n '__fish_doing_needs_command' -a '(__fish_doing_subcommands)'
60
+
61
+ complete -f -c doing -n '__fish_doing_using_command show' -a '(__fish_doing_complete_sections)'
62
+ complete -f -c doing -n '__fish_doing_using_command view' -a '(__fish_doing_complete_views)'
63
+ complete -f -c doing -n '__fish_doing_using_command template' -a '(__fish_doing_complete_templates)'
64
+ complete -f -c doing -s t -l type -x -n '__fish_doing_using_command import' -a '(__fish_doing_import_plugins)'
65
+
66
+ complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"
67
+ EOFUNCTIONS
68
+ end
69
+
70
+ def get_help_sections(command = '')
71
+ res = `doing help #{command}`.strip
72
+ scanned = res.scan(/(?m-i)^([A-Z ]+)\n([\s\S]*?)(?=\n+[A-Z]+|\Z)/)
73
+ sections = {}
74
+ scanned.each do |sect|
75
+ title = sect[0].downcase.strip.gsub(/ +/, '_').to_sym
76
+ content = sect[1].split(/\n/).map(&:strip).delete_if(&:empty?)
77
+ sections[title] = content
78
+ end
79
+ sections
80
+ end
81
+
82
+ def parse_option(option)
83
+ res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>[\w_]+)(?:=(?<arg>\w+))?)\s+- (?<desc>.*?)$/)
84
+ return nil unless res
85
+ {
86
+ short: res['short'],
87
+ long: res['long'],
88
+ arg: res[:arg],
89
+ description: res['desc'].short_desc
90
+ }
91
+ end
92
+
93
+ def parse_options(options)
94
+ options.map { |opt| parse_option(opt) }
95
+ end
96
+
97
+ def parse_command(command)
98
+ res = command.match(/^(?<cmd>[^, \t]+)(?<alias>(?:, [^, \t]+)*)?\s+- (?<desc>.*?)$/)
99
+ commands = [res['cmd']]
100
+ commands.concat(res['alias'].split(/, /).delete_if(&:empty?)) if res['alias']
101
+
102
+ {
103
+ commands: commands,
104
+ description: res['desc'].short_desc
105
+ }
106
+ end
107
+
108
+ def parse_commands(commands)
109
+ commands.map { |cmd| parse_command(cmd) }
110
+ end
111
+
112
+ def generate_subcommand_completions
113
+ out = []
114
+ @commands.each_with_index do |cmd, i|
115
+ out << "complete -xc doing -n '__fish_doing_needs_command' -a '#{cmd[:commands].join(' ')}' -d #{Shellwords.escape(cmd[:description])}"
116
+ end
117
+
118
+ out.join("\n")
119
+ end
120
+
121
+ def generate_subcommand_option_completions
122
+
123
+ out = []
124
+ need_export = []
125
+
126
+ @commands.each_with_index do |cmd, i|
127
+ @bar.advance
128
+ data = get_help_sections(cmd[:commands].first)
129
+
130
+ if data[:synopsis].join(' ').strip.split(/ /).last =~ /(path|file)/i
131
+ out << "complete -c doing -F -n '__fish_doing_using_command #{cmd[:commands].join(" ")}'"
132
+ end
133
+
134
+ if data[:command_options]
135
+ parse_options(data[:command_options]).each do |option|
136
+ next if option.nil?
137
+
138
+ arg = option[:arg] ? '-r' : ''
139
+ short = option[:short] ? "-s #{option[:short]}" : ''
140
+ long = option[:long] ? "-l #{option[:long]}" : ''
141
+ out << "complete -c doing #{long} #{short} -f #{arg} -n '__fish_doing_using_command #{cmd[:commands].join(' ')}' -d #{Shellwords.escape(option[:description])}"
142
+
143
+ need_export.concat(cmd[:commands]) if option[:long] == 'output'
144
+ end
145
+ end
146
+ end
147
+
148
+ unless need_export.empty?
149
+ out << "complete -f -c doing -s o -l output -x -n '__fish_doing_using_command #{need_export.join(' ')}' -a '(__fish_doing_export_plugins)'"
150
+ end
151
+
152
+ # clear
153
+ out.join("\n")
154
+ end
155
+
156
+ def initialize
157
+ data = get_help_sections
158
+ @global_options = parse_options(data[:global_options])
159
+ @commands = parse_commands(data[:commands])
160
+ @bar = TTY::ProgressBar.new("\033[0;0;33mGenerating Fish completions: \033[0;35;40m[:bar]\033[0m", total: @commands.count, bar_format: :blade)
161
+ @bar.resize(25)
162
+ end
163
+
164
+ def generate_completions
165
+ @bar.start
166
+ out = []
167
+ out << generate_helpers
168
+ out << generate_subcommand_completions
169
+ out << generate_subcommand_option_completions
170
+ @bar.finish
171
+ out.join("\n")
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,17 @@
1
+ class ::String
2
+ def short_desc
3
+ split(/[,.]/)[0].sub(/ \(.*?\)?$/, '').strip
4
+ end
5
+
6
+ def ltrunc(max)
7
+ if length > max
8
+ sub(/^.*?(.{#{max - 3}})$/, '...\1')
9
+ else
10
+ self
11
+ end
12
+ end
13
+
14
+ def ltrunc!(max)
15
+ replace ltrunc(max)
16
+ end
17
+ end