howzit 1.2.13 → 1.2.16
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.
- 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
|