howzit 1.2.13 → 1.2.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -0
- data/README.md +18 -5
- data/bin/howzit +193 -2
- data/lib/howzit/buildnote.rb +543 -0
- data/lib/howzit/buildnotes.rb +115 -37
- data/lib/howzit/colors.rb +3 -3
- data/lib/howzit/config.rb +128 -0
- data/lib/howzit/hash.rb +35 -0
- data/lib/howzit/prompt.rb +84 -11
- data/lib/howzit/stringutils.rb +79 -8
- data/lib/howzit/task.rb +22 -0
- data/lib/howzit/topic.rb +233 -0
- data/lib/howzit/util.rb +149 -0
- data/lib/howzit/version.rb +1 -1
- data/lib/howzit.rb +42 -5
- data/spec/ruby_gem_spec.rb +87 -17
- metadata +8 -2
data/lib/howzit/buildnotes.rb
CHANGED
@@ -124,7 +124,7 @@ module Howzit
|
|
124
124
|
pipes = "|#{hl}" if hl
|
125
125
|
end
|
126
126
|
|
127
|
-
output = `echo #{Shellwords.escape(string.strip)}#{pipes}
|
127
|
+
output = `echo #{Shellwords.escape(string.strip)}#{pipes}`.strip
|
128
128
|
|
129
129
|
if @options[:paginate]
|
130
130
|
page(output)
|
@@ -247,17 +247,22 @@ module Howzit
|
|
247
247
|
|
248
248
|
options.merge!(opts)
|
249
249
|
|
250
|
-
|
250
|
+
case @options[:header_format]
|
251
|
+
when :block
|
252
|
+
Color.template("#{options[:color]}\u{258C}#{title}#{should_mark_iterm? && options[:mark] ? iterm_marker : ''}{x}")
|
253
|
+
else
|
254
|
+
cols = TTY::Screen.columns
|
251
255
|
|
252
|
-
|
253
|
-
|
256
|
+
cols = @options[:wrap] if (@options[:wrap]).positive? && cols > @options[:wrap]
|
257
|
+
title = Color.template("#{options[:border]}#{options[:hr] * 2}( #{options[:color]}#{title}#{options[:border]} )")
|
254
258
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
259
|
+
tail = if should_mark_iterm?
|
260
|
+
"#{options[:hr] * (cols - title.uncolor.length - 15)}#{options[:mark] ? iterm_marker : ''}"
|
261
|
+
else
|
262
|
+
options[:hr] * (cols - title.uncolor.length)
|
263
|
+
end
|
264
|
+
Color.template("#{title}#{tail}{x}")
|
265
|
+
end
|
261
266
|
end
|
262
267
|
|
263
268
|
def os_open(command)
|
@@ -356,7 +361,9 @@ module Howzit
|
|
356
361
|
end
|
357
362
|
output.push("Ran #{tasks} #{tasks == 1 ? 'task' : 'tasks'}") if @options[:log_level] < 2
|
358
363
|
|
359
|
-
puts postreqs.join("\n\n")
|
364
|
+
puts postreqs.join("\n\n") unless postreqs.empty?
|
365
|
+
|
366
|
+
output
|
360
367
|
end
|
361
368
|
|
362
369
|
# Output a topic with fancy title and bright white text.
|
@@ -382,12 +389,12 @@ module Howzit
|
|
382
389
|
unless matches.empty?
|
383
390
|
if opt[:single]
|
384
391
|
title = "From #{matches[0]}:"
|
385
|
-
color = '{
|
386
|
-
rule = '{
|
392
|
+
color = '{Kyd}'
|
393
|
+
rule = '{kKd}'
|
387
394
|
else
|
388
395
|
title = "Include #{matches[0]}"
|
389
|
-
color = '{
|
390
|
-
rule = '{
|
396
|
+
color = '{Kyd}'
|
397
|
+
rule = '{kKd}'
|
391
398
|
end
|
392
399
|
output.push(format_header("#{'> ' * @nest_level}#{title}", { color: color, hr: '.', border: rule })) unless @included.include?(matches[0])
|
393
400
|
|
@@ -666,7 +673,6 @@ module Howzit
|
|
666
673
|
topics
|
667
674
|
end
|
668
675
|
|
669
|
-
|
670
676
|
def match_topic(search)
|
671
677
|
matches = []
|
672
678
|
|
@@ -700,7 +706,8 @@ module Howzit
|
|
700
706
|
choose: false,
|
701
707
|
quiet: false,
|
702
708
|
verbose: false,
|
703
|
-
default: false
|
709
|
+
default: false,
|
710
|
+
grep: nil
|
704
711
|
}
|
705
712
|
|
706
713
|
defaults = {
|
@@ -715,7 +722,8 @@ module Howzit
|
|
715
722
|
show_all_on_error: false,
|
716
723
|
include_upstream: false,
|
717
724
|
show_all_code: false,
|
718
|
-
|
725
|
+
multiple_matches: 'choose',
|
726
|
+
header_format: 'border',
|
719
727
|
log_level: 1 # 0: debug, 1: info, 2: warn, 3: error
|
720
728
|
}
|
721
729
|
|
@@ -767,6 +775,11 @@ module Howzit
|
|
767
775
|
@options[:matching] = c
|
768
776
|
end
|
769
777
|
|
778
|
+
opts.on('--multiple TYPE', MULTIPLE_OPTIONS,
|
779
|
+
'Multiple result handling', "(#{MULTIPLE_OPTIONS.join(', ')}, default choose)") do |c|
|
780
|
+
@options[:multiple_matches] = c.to_sym
|
781
|
+
end
|
782
|
+
|
770
783
|
opts.on('-R', '--list-runnable', 'List topics containing @ directives (verbose)') do
|
771
784
|
@options[:list_runnable] = true
|
772
785
|
end
|
@@ -808,6 +821,39 @@ module Howzit
|
|
808
821
|
@options[:wrap] = w.to_i
|
809
822
|
end
|
810
823
|
|
824
|
+
opts.on('--config-get [KEY]', 'Display the configuration settings or setting for a specific key') do |k|
|
825
|
+
|
826
|
+
if k.nil?
|
827
|
+
config.sort_by { |key, _| key }.each do |key, val|
|
828
|
+
print "#{key}: "
|
829
|
+
p val
|
830
|
+
end
|
831
|
+
else
|
832
|
+
k.sub!(/^:/, '')
|
833
|
+
if config.key?(k.to_sym)
|
834
|
+
puts config[k.to_sym]
|
835
|
+
else
|
836
|
+
puts "Key #{k} not found"
|
837
|
+
end
|
838
|
+
end
|
839
|
+
Process.exit 0
|
840
|
+
end
|
841
|
+
|
842
|
+
opts.on('--config-set KEY=VALUE', 'Set a config value (must be a valid key)') do |key|
|
843
|
+
raise 'Argument must be KEY=VALUE' unless key =~ /\S=\S/
|
844
|
+
|
845
|
+
k, v = key.split(/=/)
|
846
|
+
k.sub!(/^:/, '')
|
847
|
+
|
848
|
+
if config.key?(k.to_sym)
|
849
|
+
config[k.to_sym] = v.to_config_value(config[k.to_sym])
|
850
|
+
else
|
851
|
+
puts "Key #{k} not found"
|
852
|
+
end
|
853
|
+
write_config(config)
|
854
|
+
Process.exit 0
|
855
|
+
end
|
856
|
+
|
811
857
|
opts.on('--edit-config', "Edit configuration file using default $EDITOR") do
|
812
858
|
edit_config(defaults)
|
813
859
|
Process.exit 0
|
@@ -841,6 +887,11 @@ module Howzit
|
|
841
887
|
Process.exit 0
|
842
888
|
end
|
843
889
|
|
890
|
+
opts.on('--header-format TYPE', HEADER_FORMAT_OPTIONS,
|
891
|
+
"Formatting style for topic titles (#{HEADER_FORMAT_OPTIONS.join(', ')})") do |t|
|
892
|
+
@options[:header_format] = t
|
893
|
+
end
|
894
|
+
|
844
895
|
opts.on('--[no-]color', 'Colorize output (default on)') do |c|
|
845
896
|
@options[:color] = c
|
846
897
|
@options[:highlight] = false unless c
|
@@ -869,6 +920,9 @@ module Howzit
|
|
869
920
|
end
|
870
921
|
end.parse!(args)
|
871
922
|
|
923
|
+
@options[:multiple_matches] = @options[:multiple_matches].to_sym
|
924
|
+
@options[:header_format] = @options[:header_format].to_sym
|
925
|
+
|
872
926
|
@cli_args = args
|
873
927
|
end
|
874
928
|
|
@@ -1001,12 +1055,20 @@ module Howzit
|
|
1001
1055
|
|
1002
1056
|
def choose(matches)
|
1003
1057
|
if command_exist?('fzf')
|
1004
|
-
|
1058
|
+
settings = [
|
1059
|
+
'-0',
|
1060
|
+
'-1',
|
1061
|
+
'-m',
|
1062
|
+
"--height=#{matches.count + 2}",
|
1063
|
+
'--header="Use tab to mark multiple selections, enter to display/run"',
|
1064
|
+
'--prompt="Select a section > "'
|
1065
|
+
]
|
1066
|
+
res = `echo #{Shellwords.escape(matches.join("\n"))} | fzf #{settings.join(' ')}`.strip
|
1005
1067
|
if res.nil? || res.empty?
|
1006
1068
|
warn 'Cancelled'
|
1007
1069
|
Process.exit 0
|
1008
1070
|
end
|
1009
|
-
return res
|
1071
|
+
return res.split(/\n/)
|
1010
1072
|
end
|
1011
1073
|
|
1012
1074
|
res = matches[0..9]
|
@@ -1107,7 +1169,7 @@ module Howzit
|
|
1107
1169
|
out = get_note_title(20)
|
1108
1170
|
$stdout.print(out.strip)
|
1109
1171
|
Process.exit(0)
|
1110
|
-
elsif @options[:output_title]
|
1172
|
+
elsif @options[:output_title] && !@options[:run]
|
1111
1173
|
title = get_note_title
|
1112
1174
|
if title && !title.empty?
|
1113
1175
|
header = format_header(title, { hr: "\u{2550}", color: '{bwK}' })
|
@@ -1136,33 +1198,49 @@ module Howzit
|
|
1136
1198
|
Process.exit(0)
|
1137
1199
|
end
|
1138
1200
|
|
1139
|
-
|
1201
|
+
topic_matches = []
|
1140
1202
|
if @options[:grep]
|
1141
|
-
|
1203
|
+
matches = grep_topics(@options[:grep])
|
1204
|
+
case @options[:multiple_matches]
|
1205
|
+
when :all
|
1206
|
+
topic_matches.concat(matches.sort)
|
1207
|
+
else
|
1208
|
+
topic_matches.concat(choose(matches))
|
1209
|
+
end
|
1142
1210
|
elsif @options[:choose]
|
1143
|
-
|
1211
|
+
topic_matches.concat(choose(topics.keys))
|
1144
1212
|
# If there are arguments use those to search for a matching topic
|
1145
1213
|
elsif !@cli_args.empty?
|
1214
|
+
search = @cli_args.join(' ').strip.downcase.split(/ *, */).map(&:strip)
|
1146
1215
|
|
1147
|
-
search
|
1148
|
-
|
1216
|
+
search.each do |s|
|
1217
|
+
matches = match_topic(s)
|
1149
1218
|
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1219
|
+
if matches.empty?
|
1220
|
+
output.push(Color.template(%({bR}ERROR:{xr} No topic match found for {bw}#{s}{x}\n)))
|
1221
|
+
else
|
1222
|
+
case @options[:multiple_matches]
|
1223
|
+
when :first
|
1224
|
+
topic_matches.push(matches[0])
|
1225
|
+
when :best
|
1226
|
+
topic_matches.push(matches.sort.min_by(&:length))
|
1227
|
+
when :all
|
1228
|
+
topic_matches.concat(matches)
|
1229
|
+
else
|
1230
|
+
topic_matches.concat(choose(matches))
|
1231
|
+
end
|
1155
1232
|
end
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
if topic_matches.empty? && !@options[:show_all_on_error]
|
1236
|
+
show(output.join("\n"), { color: true, highlight: false, paginate: false, wrap: 0 })
|
1237
|
+
Process.exit 1
|
1160
1238
|
end
|
1161
1239
|
end
|
1162
1240
|
|
1163
|
-
if
|
1241
|
+
if !topic_matches.empty?
|
1164
1242
|
# If we found a match
|
1165
|
-
output.push(process_topic(topic_match, @options[:run], true))
|
1243
|
+
topic_matches.each { |topic_match| output.push(process_topic(topic_match, @options[:run], true)) }
|
1166
1244
|
else
|
1167
1245
|
# If there's no argument or no match found, output all
|
1168
1246
|
topics.each_key { |k| output.push(process_topic(k, false, false)) }
|
data/lib/howzit/colors.rb
CHANGED
@@ -223,8 +223,8 @@ module Howzit
|
|
223
223
|
##
|
224
224
|
def template(input)
|
225
225
|
input = input.join(' ') if input.is_a? Array
|
226
|
-
input.gsub
|
227
|
-
fmt =
|
226
|
+
fmt = input.gsub(/%/, '%%')
|
227
|
+
fmt = fmt.gsub(/\{(\w+)\}/) do
|
228
228
|
Regexp.last_match(1).split('').map { |c| "%<#{c}>s" }.join('')
|
229
229
|
end
|
230
230
|
|
@@ -232,7 +232,7 @@ module Howzit
|
|
232
232
|
y: yellow, c: cyan, m: magenta, r: red,
|
233
233
|
W: bgwhite, K: bgblack, G: bggreen, L: bgblue,
|
234
234
|
Y: bgyellow, C: bgcyan, M: bgmagenta, R: bgred,
|
235
|
-
b: bold, u: underline, i: italic, x: reset }
|
235
|
+
d: dark, b: bold, u: underline, i: italic, x: reset }
|
236
236
|
|
237
237
|
format(fmt, colors)
|
238
238
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Howzit
|
2
|
+
# Config Class
|
3
|
+
class Config
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
DEFAULTS = {
|
7
|
+
color: true,
|
8
|
+
config_editor: ENV['EDITOR'] || nil,
|
9
|
+
editor: ENV['EDITOR'] || nil,
|
10
|
+
header_format: 'border',
|
11
|
+
highlight: true,
|
12
|
+
highlighter: 'auto',
|
13
|
+
include_upstream: false,
|
14
|
+
log_level: 1, # 0: debug, 1: info, 2: warn, 3: error
|
15
|
+
matching: 'partial', # exact, partial, fuzzy, beginswith
|
16
|
+
multiple_matches: 'choose',
|
17
|
+
output_title: false,
|
18
|
+
pager: 'auto',
|
19
|
+
paginate: true,
|
20
|
+
show_all_code: false,
|
21
|
+
show_all_on_error: false,
|
22
|
+
wrap: 0
|
23
|
+
}.deep_freeze
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
load_options
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_config(config)
|
30
|
+
File.open(config_file, 'w') { |f| f.puts config.to_yaml }
|
31
|
+
end
|
32
|
+
|
33
|
+
def should_ignore(filename)
|
34
|
+
return false unless File.exist?(ignore_file)
|
35
|
+
|
36
|
+
@ignore_patterns ||= YAML.safe_load(IO.read(ignore_file))
|
37
|
+
|
38
|
+
ignore = false
|
39
|
+
|
40
|
+
@ignore_patterns.each do |pat|
|
41
|
+
if filename =~ /#{pat}/
|
42
|
+
ignore = true
|
43
|
+
break
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
ignore
|
48
|
+
end
|
49
|
+
|
50
|
+
def template_folder
|
51
|
+
File.join(config_dir, 'templates')
|
52
|
+
end
|
53
|
+
|
54
|
+
def editor
|
55
|
+
edit_config(DEFAULTS)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def load_options
|
61
|
+
Color.coloring = $stdout.isatty
|
62
|
+
flags = {
|
63
|
+
choose: false,
|
64
|
+
default: false,
|
65
|
+
grep: nil,
|
66
|
+
list_runnable: false,
|
67
|
+
list_runnable_titles: false,
|
68
|
+
list_topic_titles: false,
|
69
|
+
list_topics: false,
|
70
|
+
quiet: false,
|
71
|
+
run: false,
|
72
|
+
title_only: false,
|
73
|
+
verbose: false
|
74
|
+
}
|
75
|
+
|
76
|
+
config = load_config
|
77
|
+
@options = flags.merge(config)
|
78
|
+
end
|
79
|
+
|
80
|
+
def config_dir
|
81
|
+
File.expand_path(CONFIG_DIR)
|
82
|
+
end
|
83
|
+
|
84
|
+
def config_file
|
85
|
+
File.join(config_dir, CONFIG_FILE)
|
86
|
+
end
|
87
|
+
|
88
|
+
def ignore_file
|
89
|
+
File.join(config_dir, IGNORE_FILE)
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_config(d)
|
93
|
+
unless File.directory?(config_dir)
|
94
|
+
warn "Creating config directory at #{config_dir}"
|
95
|
+
FileUtils.mkdir_p(config_dir)
|
96
|
+
end
|
97
|
+
|
98
|
+
unless File.exist?(config_file)
|
99
|
+
warn "Writing fresh config file to #{config_file}"
|
100
|
+
write_config(d)
|
101
|
+
end
|
102
|
+
config_file
|
103
|
+
end
|
104
|
+
|
105
|
+
def load_config
|
106
|
+
file = create_config(DEFAULTS)
|
107
|
+
config = YAML.load(IO.read(file))
|
108
|
+
newconfig = config ? DEFAULTS.merge(config) : DEFAULTS
|
109
|
+
write_config(newconfig)
|
110
|
+
newconfig.dup
|
111
|
+
end
|
112
|
+
|
113
|
+
def edit_config(d)
|
114
|
+
editor = Howzit.options.fetch(:config_editor, ENV['EDITOR'])
|
115
|
+
|
116
|
+
raise 'No config_editor defined' if editor.nil?
|
117
|
+
|
118
|
+
# raise "Invalid editor (#{editor})" unless Util.valid_command?(editor)
|
119
|
+
|
120
|
+
load_config
|
121
|
+
if Util.valid_command?(editor.split(/ /).first)
|
122
|
+
system %(#{editor} "#{config_file}")
|
123
|
+
else
|
124
|
+
`open -a "#{editor}" "#{config_file}"`
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/howzit/hash.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Hash helpers
|
4
|
+
class ::Hash
|
5
|
+
##
|
6
|
+
## Freeze all values in a hash
|
7
|
+
##
|
8
|
+
## @return Hash with all values frozen
|
9
|
+
##
|
10
|
+
def deep_freeze
|
11
|
+
chilled = {}
|
12
|
+
each do |k, v|
|
13
|
+
chilled[k] = v.is_a?(Hash) ? v.deep_freeze : v.freeze
|
14
|
+
end
|
15
|
+
|
16
|
+
chilled.freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
def deep_freeze!
|
20
|
+
replace deep_thaw.deep_freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
def deep_thaw
|
24
|
+
chilled = {}
|
25
|
+
each do |k, v|
|
26
|
+
chilled[k] = v.is_a?(Hash) ? v.deep_thaw : v.dup
|
27
|
+
end
|
28
|
+
|
29
|
+
chilled.dup
|
30
|
+
end
|
31
|
+
|
32
|
+
def deep_thaw!
|
33
|
+
replace deep_thaw
|
34
|
+
end
|
35
|
+
end
|
data/lib/howzit/prompt.rb
CHANGED
@@ -3,17 +3,90 @@
|
|
3
3
|
module Howzit
|
4
4
|
# Command line prompt utils
|
5
5
|
module Prompt
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
class << self
|
7
|
+
def yn(prompt, default = true)
|
8
|
+
return default if !$stdout.isatty
|
9
|
+
|
10
|
+
system 'stty cbreak'
|
11
|
+
yn = color_single_options(default ? %w[Y n] : %w[y N])
|
12
|
+
$stdout.syswrite "\e[1;37m#{prompt} #{yn}\e[1;37m? \e[0m"
|
13
|
+
res = $stdin.sysread 1
|
14
|
+
res.chomp!
|
15
|
+
puts
|
16
|
+
system 'stty cooked'
|
17
|
+
res =~ /y/i
|
18
|
+
end
|
19
|
+
|
20
|
+
def color_single_options(choices = %w[y n])
|
21
|
+
out = []
|
22
|
+
choices.each do |choice|
|
23
|
+
case choice
|
24
|
+
when /[A-Z]/
|
25
|
+
out.push(Color.template("{bg}#{choice}{xg}"))
|
26
|
+
else
|
27
|
+
out.push(Color.template("{w}#{choice}"))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
Color.template("{g}[#{out.join('/')}{g}]{x}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def options_list(matches)
|
34
|
+
counter = 1
|
35
|
+
puts
|
36
|
+
matches.each do |match|
|
37
|
+
printf("%<counter>2d ) %<option>s\n", counter: counter, option: match)
|
38
|
+
counter += 1
|
39
|
+
end
|
40
|
+
puts
|
41
|
+
end
|
42
|
+
|
43
|
+
def choose(matches)
|
44
|
+
if Util.command_exist?('fzf')
|
45
|
+
settings = [
|
46
|
+
'-0',
|
47
|
+
'-1',
|
48
|
+
'-m',
|
49
|
+
"--height=#{matches.count + 2}",
|
50
|
+
'--header="Use tab to mark multiple selections, enter to display/run"',
|
51
|
+
'--prompt="Select a section > "'
|
52
|
+
]
|
53
|
+
res = `echo #{Shellwords.escape(matches.join("\n"))} | fzf #{settings.join(' ')}`.strip
|
54
|
+
if res.nil? || res.empty?
|
55
|
+
warn 'Cancelled'
|
56
|
+
Process.exit 0
|
57
|
+
end
|
58
|
+
return res.split(/\n/)
|
59
|
+
end
|
60
|
+
|
61
|
+
res = matches[0..9]
|
62
|
+
stty_save = `stty -g`.chomp
|
63
|
+
|
64
|
+
trap('INT') do
|
65
|
+
system('stty', stty_save)
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
|
69
|
+
options_list(matches)
|
70
|
+
|
71
|
+
begin
|
72
|
+
printf("Type 'q' to cancel, enter for first item", res.length)
|
73
|
+
while (line = Readline.readline(': ', true))
|
74
|
+
if line =~ /^[a-z]/i
|
75
|
+
system('stty', stty_save) # Restore
|
76
|
+
exit
|
77
|
+
end
|
78
|
+
line = line == '' ? 1 : line.to_i
|
79
|
+
|
80
|
+
return matches[line - 1] if line.positive? && line <= matches.length
|
81
|
+
|
82
|
+
puts 'Out of range'
|
83
|
+
options_list(matches)
|
84
|
+
end
|
85
|
+
rescue Interrupt
|
86
|
+
system('stty', stty_save)
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
end
|
17
90
|
end
|
18
91
|
end
|
19
92
|
end
|
data/lib/howzit/stringutils.rb
CHANGED
@@ -3,6 +3,44 @@
|
|
3
3
|
module Howzit
|
4
4
|
# String Extensions
|
5
5
|
module StringUtils
|
6
|
+
# Convert a string to a valid YAML value
|
7
|
+
def to_config_value(orig_value = nil)
|
8
|
+
if orig_value
|
9
|
+
case orig_value.class.to_s
|
10
|
+
when /Integer/
|
11
|
+
to_i
|
12
|
+
when /(True|False)Class/
|
13
|
+
self =~ /^(t(rue)?|y(es)?|1)$/i ? true : false
|
14
|
+
else
|
15
|
+
self
|
16
|
+
end
|
17
|
+
else
|
18
|
+
case self
|
19
|
+
when /^[0-9]+$/
|
20
|
+
to_i
|
21
|
+
when /^(t(rue)?|y(es)?)$/i
|
22
|
+
true
|
23
|
+
when /^(f(alse)?|n(o)?)$/i
|
24
|
+
false
|
25
|
+
else
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_rx
|
32
|
+
case Howzit.options[:matching]
|
33
|
+
when 'exact'
|
34
|
+
/^#{self}$/i
|
35
|
+
when 'beginswith'
|
36
|
+
/^#{self}/i
|
37
|
+
when 'fuzzy'
|
38
|
+
/#{split(//).join('.*?')}/i
|
39
|
+
else
|
40
|
+
/#{self}/i
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
6
44
|
# Just strip out color codes when requested
|
7
45
|
def uncolor
|
8
46
|
gsub(/\e\[[\d;]+m/, '').gsub(/\e\]1337;SetMark/,'')
|
@@ -78,20 +116,15 @@ module Howzit
|
|
78
116
|
end
|
79
117
|
|
80
118
|
def available?
|
81
|
-
|
82
|
-
File.executable?(File.expand_path(self))
|
83
|
-
else
|
84
|
-
system "which #{self}", out: File::NULL
|
85
|
-
end
|
119
|
+
Util.valid_command?(self)
|
86
120
|
end
|
87
121
|
|
88
122
|
def render_template(vars)
|
89
|
-
content = dup
|
90
123
|
vars.each do |k, v|
|
91
|
-
|
124
|
+
gsub!(/\[%#{k}(:.*?)?\]/, v)
|
92
125
|
end
|
93
126
|
|
94
|
-
|
127
|
+
gsub(/\[%(.*?):(.*?)\]/, '\2')
|
95
128
|
end
|
96
129
|
|
97
130
|
def render_template!(vars)
|
@@ -129,6 +162,44 @@ module Howzit
|
|
129
162
|
end
|
130
163
|
data
|
131
164
|
end
|
165
|
+
|
166
|
+
def should_mark_iterm?
|
167
|
+
ENV['TERM_PROGRAM'] =~ /^iTerm/ && !Howzit.options[:run] && !Howzit.options[:paginate]
|
168
|
+
end
|
169
|
+
|
170
|
+
def iterm_marker
|
171
|
+
"\e]1337;SetMark\a" if should_mark_iterm?
|
172
|
+
end
|
173
|
+
|
174
|
+
# Make a fancy title line for the topic
|
175
|
+
def format_header(opts = {})
|
176
|
+
title = dup
|
177
|
+
options = {
|
178
|
+
hr: "\u{254C}",
|
179
|
+
color: '{bg}',
|
180
|
+
border: '{x}',
|
181
|
+
mark: should_mark_iterm?
|
182
|
+
}
|
183
|
+
|
184
|
+
options.merge!(opts)
|
185
|
+
|
186
|
+
case Howzit.options[:header_format]
|
187
|
+
when :block
|
188
|
+
Color.template("#{options[:color]}\u{258C}#{title}#{should_mark_iterm? && options[:mark] ? iterm_marker : ''}{x}")
|
189
|
+
else
|
190
|
+
cols = TTY::Screen.columns
|
191
|
+
|
192
|
+
cols = Howzit.options[:wrap] if (Howzit.options[:wrap]).positive? && cols > Howzit.options[:wrap]
|
193
|
+
title = Color.template("#{options[:border]}#{options[:hr] * 2}( #{options[:color]}#{title}#{options[:border]} )")
|
194
|
+
|
195
|
+
tail = if should_mark_iterm?
|
196
|
+
"#{options[:hr] * (cols - title.uncolor.length - 15)}#{options[:mark] ? iterm_marker : ''}"
|
197
|
+
else
|
198
|
+
options[:hr] * (cols - title.uncolor.length)
|
199
|
+
end
|
200
|
+
Color.template("#{title}#{tail}{x}")
|
201
|
+
end
|
202
|
+
end
|
132
203
|
end
|
133
204
|
end
|
134
205
|
|
data/lib/howzit/task.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Howzit
|
4
|
+
class Task
|
5
|
+
attr_reader :type, :title, :action, :parent
|
6
|
+
|
7
|
+
def initialize(type, title, action, parent = nil)
|
8
|
+
@type = type
|
9
|
+
@title = title
|
10
|
+
@action = action
|
11
|
+
@parent = parent
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@title
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_list
|
19
|
+
" * #{@type}: #{@title}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|