doing 2.0.24 → 2.0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +7 -1
- data/bin/doing +142 -70
- data/doing.rdoc +45 -21
- data/example_plugin.rb +2 -2
- data/lib/completion/_doing.zsh +41 -41
- data/lib/completion/doing.bash +2 -2
- data/lib/completion/doing.fish +0 -279
- data/lib/doing/completion/bash_completion.rb +1 -2
- data/lib/doing/completion/fish_completion.rb +1 -1
- data/lib/doing/completion/zsh_completion.rb +1 -1
- data/lib/doing/configuration.rb +85 -15
- data/lib/doing/string.rb +30 -18
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +2 -5
- data/rdoc_to_mmd.rb +14 -8
- data/scripts/generate_bash_completions.rb +1 -1
- data/scripts/generate_fish_completions.rb +1 -1
- data/scripts/generate_zsh_completions.rb +1 -1
- metadata +1 -1
data/lib/doing/configuration.rb
CHANGED
@@ -90,21 +90,56 @@ module Doing
|
|
90
90
|
}
|
91
91
|
|
92
92
|
def initialize(file = nil, options: {})
|
93
|
-
|
94
|
-
cf = File.expand_path(file)
|
95
|
-
# raise MissingConfigFile, "Config not found (#{cf})" unless File.exist?(cf)
|
93
|
+
@config_file = file.nil? ? default_config_file : File.expand_path(file)
|
96
94
|
|
97
|
-
|
95
|
+
@settings = configure(options)
|
96
|
+
end
|
97
|
+
|
98
|
+
def config_file
|
99
|
+
@config_file ||= default_config_file
|
100
|
+
end
|
101
|
+
|
102
|
+
def config_dir
|
103
|
+
@config_dir ||= File.join(Util.user_home, '.config', 'doing')
|
104
|
+
# @config_dir ||= Util.user_home
|
105
|
+
end
|
106
|
+
|
107
|
+
def default_config_file
|
108
|
+
raise DoingRuntimeError, "#{config_dir} exists but is not a directory" if File.exist?(config_dir) && !File.directory?(config_dir)
|
109
|
+
|
110
|
+
unless File.exist?(config_dir)
|
111
|
+
FileUtils.mkdir_p(config_dir)
|
112
|
+
Doing.logger.log_now(:warn, "Config directory created at #{config_dir}")
|
98
113
|
end
|
99
114
|
|
100
|
-
|
115
|
+
# File.join(config_dir, 'config.yml')
|
116
|
+
File.join(config_dir, 'config.yml')
|
101
117
|
end
|
102
118
|
|
119
|
+
def config_file=(file)
|
120
|
+
@config_file = file
|
121
|
+
end
|
122
|
+
|
123
|
+
|
103
124
|
def additional_configs
|
104
125
|
@additional_configs ||= find_local_config
|
105
126
|
end
|
106
127
|
|
107
|
-
def
|
128
|
+
def choose_config
|
129
|
+
if @additional_configs.count.positive?
|
130
|
+
choices = [@config_file]
|
131
|
+
choices.concat(@additional_configs)
|
132
|
+
res = Doing::WWID.new.choose_from(choices.uniq.sort.reverse, sorted: false, prompt: 'Local configs found, select which to update > ')
|
133
|
+
|
134
|
+
raise UserCancelled, 'Cancelled' unless res
|
135
|
+
|
136
|
+
res.strip || @config_file
|
137
|
+
else
|
138
|
+
@config_file
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def resolve_key_path(keypath)
|
108
143
|
cfg = @settings
|
109
144
|
real_path = []
|
110
145
|
unless keypath =~ /^[.*]?$/
|
@@ -113,7 +148,8 @@ module Doing
|
|
113
148
|
path = paths.shift
|
114
149
|
new_cfg = nil
|
115
150
|
cfg.each do |key, val|
|
116
|
-
next unless key =~ path.to_rx(distance:
|
151
|
+
next unless key =~ path.to_rx(distance: 4)
|
152
|
+
|
117
153
|
real_path << key
|
118
154
|
new_cfg = val
|
119
155
|
break
|
@@ -127,9 +163,20 @@ module Doing
|
|
127
163
|
end
|
128
164
|
end
|
129
165
|
Doing.logger.debug('Config:', "translated key path #{keypath} to #{real_path.join('.')}")
|
130
|
-
|
131
|
-
|
132
|
-
|
166
|
+
real_path
|
167
|
+
end
|
168
|
+
|
169
|
+
def value_for_key(keypath = '')
|
170
|
+
cfg = @settings
|
171
|
+
real_path = ['config']
|
172
|
+
unless keypath =~ /^[.*]?$/
|
173
|
+
real_path = resolve_key_path(keypath)
|
174
|
+
return nil unless real_path && real_path.count.positive?
|
175
|
+
|
176
|
+
cfg = cfg.dig(*real_path)
|
177
|
+
end
|
178
|
+
|
179
|
+
cfg.nil? ? nil : { real_path[-1] => cfg }
|
133
180
|
end
|
134
181
|
|
135
182
|
# It takes the input, fills in the defaults where values do not exist.
|
@@ -141,12 +188,33 @@ module Doing
|
|
141
188
|
Util.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
|
142
189
|
end
|
143
190
|
|
144
|
-
def
|
145
|
-
|
146
|
-
|
191
|
+
def update_deprecated_config
|
192
|
+
# return # Until further notice
|
193
|
+
return if File.exist?(default_config_file)
|
147
194
|
|
148
|
-
|
149
|
-
|
195
|
+
old_file = File.join(Util.user_home, '.doingrc')
|
196
|
+
return unless File.exist?(old_file)
|
197
|
+
|
198
|
+
wwid = Doing::WWID.new
|
199
|
+
Doing.logger.log_now(:warn, 'Deprecated:', "main config file location has changed to #{config_file}")
|
200
|
+
res = wwid.yn("Move #{old_file} to new location, preserving settings?", default_response: true)
|
201
|
+
|
202
|
+
if res
|
203
|
+
if File.exist?(default_config_file)
|
204
|
+
res = wwid.yn("#{default_config_file} already exists, overwrite it?", default_response: false)
|
205
|
+
|
206
|
+
unless res
|
207
|
+
@config_file = old_file
|
208
|
+
return
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
FileUtils.mv old_file, default_config_file, force: true
|
213
|
+
Doing.logger.log_now(:warn, 'Config:', "Config file moved to #{default_config_file}")
|
214
|
+
Doing.logger.log_now(:warn, 'Config:', %(If ~/.config/doing/config.yml exists in the future, it will be considered a local
|
215
|
+
config and its values will override the default configuration.))
|
216
|
+
Process.exit 0
|
217
|
+
end
|
150
218
|
end
|
151
219
|
|
152
220
|
##
|
@@ -155,6 +223,8 @@ module Doing
|
|
155
223
|
## @param opt [Hash] Additional Options
|
156
224
|
##
|
157
225
|
def configure(opt = {})
|
226
|
+
update_deprecated_config if config_file == default_config_file
|
227
|
+
|
158
228
|
@ignore_local = opt[:ignore_local] if opt[:ignore_local]
|
159
229
|
|
160
230
|
config = read_config.dup
|
data/lib/doing/string.rb
CHANGED
@@ -392,36 +392,50 @@ module Doing
|
|
392
392
|
|
393
393
|
def link_urls(opt = {})
|
394
394
|
opt[:format] ||= :html
|
395
|
-
str =
|
396
|
-
|
397
|
-
if :format == :markdown
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
395
|
+
str = dup
|
396
|
+
|
397
|
+
str = str.remove_self_links if opt[:format] == :markdown
|
398
|
+
|
399
|
+
str.replace_qualified_urls(format: opt[:format]).clean_unlinked_urls
|
400
|
+
end
|
401
|
+
|
402
|
+
# Remove <self-linked> formatting
|
403
|
+
def remove_self_links
|
404
|
+
gsub(/<(.*?)>/) do |match|
|
405
|
+
m = Regexp.last_match
|
406
|
+
if m[1] =~ /^https?:/
|
407
|
+
m[1]
|
408
|
+
else
|
409
|
+
match
|
406
410
|
end
|
407
411
|
end
|
412
|
+
end
|
408
413
|
|
409
|
-
|
410
|
-
|
414
|
+
# Replace qualified urls
|
415
|
+
def replace_qualified_urls(opt = {})
|
416
|
+
opt[:format] ||= :html
|
417
|
+
gsub(%r{(?mi)(?x:
|
418
|
+
(?<!["'\[(\\])
|
419
|
+
((http|https)://)
|
420
|
+
([\w\-]+(\.[\w\-]+)+)
|
421
|
+
([\w\-.,@?^=%&;:/~+#]*[\w\-@^=%&;/~+#])?
|
422
|
+
)}) do |_match|
|
411
423
|
m = Regexp.last_match
|
412
424
|
proto = m[1].nil? ? 'http://' : ''
|
413
425
|
case opt[:format]
|
414
426
|
when :html
|
415
|
-
%(<a href="#{proto}#{m[0]}" title="Link to #{m[0].sub(
|
427
|
+
%(<a href="#{proto}#{m[0]}" title="Link to #{m[0].sub(%r{^https?://}, '')}">[#{m[3]}]</a>)
|
416
428
|
when :markdown
|
417
429
|
"[#{m[0]}](#{proto}#{m[0]})"
|
418
430
|
else
|
419
431
|
m[0]
|
420
432
|
end
|
421
433
|
end
|
434
|
+
end
|
422
435
|
|
423
|
-
|
424
|
-
|
436
|
+
# Clean up unlinked <urls>
|
437
|
+
def clean_unlinked_urls
|
438
|
+
gsub(/<(\w+:.*?)>/) do |match|
|
425
439
|
m = Regexp.last_match
|
426
440
|
if m[1] =~ /<a href/
|
427
441
|
match
|
@@ -429,8 +443,6 @@ module Doing
|
|
429
443
|
%(<a href="#{m[1]}" title="Link to #{m[1]}">[link]</a>)
|
430
444
|
end
|
431
445
|
end
|
432
|
-
|
433
|
-
str
|
434
446
|
end
|
435
447
|
end
|
436
448
|
end
|
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -25,10 +25,7 @@ module Doing
|
|
25
25
|
@timers = {}
|
26
26
|
@recorded_items = []
|
27
27
|
@content = {}
|
28
|
-
@doingrc_needs_update = false
|
29
|
-
@default_config_file = '.doingrc'
|
30
28
|
@auto_tag = true
|
31
|
-
@user_home = Util.user_home
|
32
29
|
end
|
33
30
|
|
34
31
|
##
|
@@ -626,7 +623,7 @@ module Doing
|
|
626
623
|
Doing.logger.log_now(:warn, 'Compiling and installing fzf -- this will only happen once')
|
627
624
|
Doing.logger.log_now(:warn, 'fzf is copyright Junegunn Choi, MIT License <https://github.com/junegunn/fzf/blob/master/LICENSE>')
|
628
625
|
|
629
|
-
|
626
|
+
system("'#{fzf_dir}/install' --bin --no-key-bindings --no-completion --no-update-rc --no-bash --no-zsh --no-fish &> /dev/null")
|
630
627
|
unless File.exist?(fzf_bin)
|
631
628
|
Doing.logger.log_now(:warn, 'Error installing, trying again as root')
|
632
629
|
system("sudo '#{fzf_dir}/install' --bin --no-key-bindings --no-completion --no-update-rc --no-bash --no-zsh --no-fish &> /dev/null")
|
@@ -1524,7 +1521,7 @@ module Doing
|
|
1524
1521
|
def restore_backup(file)
|
1525
1522
|
if File.exist?("#{file}~")
|
1526
1523
|
FileUtils.cp("#{file}~", file)
|
1527
|
-
logger.warn('File update:', "Restored #{file.sub(/^#{
|
1524
|
+
logger.warn('File update:', "Restored #{file.sub(/^#{Util.user_home}/, '~')}")
|
1528
1525
|
else
|
1529
1526
|
logger.error('Restore error:', 'No backup file found')
|
1530
1527
|
end
|
data/rdoc_to_mmd.rb
CHANGED
@@ -3,18 +3,24 @@
|
|
3
3
|
|
4
4
|
input = IO.read('doing.rdoc')
|
5
5
|
|
6
|
+
input.gsub!(/^======= Options/, "###### Options\n\n")
|
6
7
|
input.gsub!(/^===== Options/, "##### Options\n\n")
|
8
|
+
input.gsub!(/^===== Commands/, "### Commands\n")
|
7
9
|
input.gsub!(/^=== Commands/, "## Commands\n")
|
8
|
-
|
10
|
+
|
11
|
+
input.gsub!(/^(?<pre>={4,6}) Command: <tt>(?<cmd>.*?) (?<arg> .*?)?<\/tt>\n(?<after>.*?)$/) do
|
9
12
|
m = Regexp.last_match
|
10
|
-
|
13
|
+
level = m['pre'].length == 6 ? '####' : '###'
|
14
|
+
r = "#{level} #{m['cmd'].sub(/\|(.*?)$/, ' (*or* \1)')}"
|
15
|
+
r += " #{m['arg']}" if m['arg']
|
16
|
+
r += " {##{m['cmd'].gsub(/\|.*?$/, '')}}" if m['pre'].length == 4
|
17
|
+
r += "\n\n"
|
18
|
+
"#{r}**#{m['after']}**{:.description}\n"
|
11
19
|
end
|
12
|
-
|
20
|
+
|
21
|
+
input.gsub!(/(?<=\n)={5,7} (.*?)\n+((.|\n)+?)(?=\n=|$)/s) do
|
13
22
|
m = Regexp.last_match
|
14
|
-
|
15
|
-
r += " #{m[2]}" if m[2]
|
16
|
-
r += " {##{m[1].gsub(/\|.*?$/, '')}}\n\n"
|
17
|
-
"#{r}**#{m[3]}**{:.description}\n"
|
23
|
+
"`#{m[1]}`\n: #{m[2].gsub(/\|/, '\\|')}"
|
18
24
|
end
|
19
25
|
|
20
26
|
input.gsub!(/^=== Global Options/, "## Global Options\n")
|
@@ -28,7 +34,7 @@ input.gsub!(/\n (?=\S)/, ' ')
|
|
28
34
|
input.gsub!(/^([^:`\n#*](.*?))$/, "\\1\n")
|
29
35
|
input.gsub!(/\n{3,}/, "\n\n")
|
30
36
|
input.gsub!(/^(: .*?)\n\n(:.*?)$/, "\\1\n\\2")
|
31
|
-
input.gsub!(/^\[Default Command\] (.*?)$/, '
|
37
|
+
input.gsub!(/^\[Default Command\] (.*?)$/, '> **Default Command:** [`\1`](#\1)')
|
32
38
|
input.gsub!(/\/Users\/ttscoff\/scripts\/editor.sh/, '$EDITOR')
|
33
39
|
input.gsub!(/\/Users\/ttscoff/, '~')
|
34
40
|
puts %(---
|
@@ -155,7 +155,7 @@ class BashCompletions
|
|
155
155
|
end
|
156
156
|
|
157
157
|
def parse_option(option)
|
158
|
-
res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>
|
158
|
+
res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>w+)(?:=(?<arg>\w+))?)\s+- (?<desc>.*?)$/)
|
159
159
|
return nil unless res
|
160
160
|
{
|
161
161
|
short: res['short'],
|
@@ -100,7 +100,7 @@ class FishCompletions
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def parse_option(option)
|
103
|
-
res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>
|
103
|
+
res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>w+)(?:=(?<arg>\w+))?)\s+- (?<desc>.*?)$/)
|
104
104
|
return nil unless res
|
105
105
|
{
|
106
106
|
short: res['short'],
|
@@ -71,7 +71,7 @@ class ZshCompletions
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def parse_option(option)
|
74
|
-
res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>
|
74
|
+
res = option.match(/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>w+)(?:=(?<arg>\w+))?)\s+- (?<desc>.*?)$/)
|
75
75
|
return nil unless res
|
76
76
|
|
77
77
|
{
|