howzit 2.0.4 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fba7a6b730f2aabb0e92a26b772cc06fa4182ad07edf7f8620733be70debf766
4
- data.tar.gz: 60900d73ffee99002daa4e32b5970c81986756c117fec172c824d59e87e72995
3
+ metadata.gz: 8ad8cdc085654826428d432429473e7b12375288058f3c0ce993f94937441485
4
+ data.tar.gz: 8dfda4d862d35559b0cd9a1e89c4a69597aa16ef9dba5dac29eff1ee61ed295a
5
5
  SHA512:
6
- metadata.gz: 819083c882f7f330d050d23486e390179beb95c4f220458c4a66c496a0fe99eb69746e762d90ce4c033983764693e5dc77499779e1138ae41e64c346b3930d45
7
- data.tar.gz: 38d58943e9f8a8d32794ecc638257eb64f67cf09f0a22bc9811ca367627bafb48d22ceed7091551453700fd392fa857b94e37551208735433f0cf4a39ef27f6e
6
+ metadata.gz: 9ec8eea72d9177717e0ed6dcd07c35d9eb12f998dabea1347efae1dca1fc145a8c5e4b8317f1cf4805606a86209e389643c959aa60deb240ebd2808ddbe456f4
7
+ data.tar.gz: a9f3e5472866af519bc053ab50ef3f6a5089ddc4334e9687cb64dd9a8e026d00a0b2bb12d1246631f209892de9bb03168cb05cbaa852d97c44734395b00b122b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ### 2.0.7
2
+
3
+ 2022-08-04 13:04
4
+
5
+ #### NEW
6
+
7
+ - --debug flag (shortcut for :log_level: 0)
8
+
9
+ #### IMPROVED
10
+
11
+ - Console output now gets log levels, so :log_level: config option and --quiet/verbose have more utility
12
+
13
+ ### 2.0.6
14
+
15
+ 2022-08-04 11:08
16
+
17
+ ### 2.0.5
18
+
19
+ 2022-08-04 10:50
20
+
21
+ #### NEW
22
+
23
+ - Make any task optional when running by adding a ? (@open?(...))
24
+ - Optional tasks default to yes when you hit enter, invert by using a ! (@open?!(...)) to make default "no"
25
+
26
+ #### FIXED
27
+
28
+ - Replace escaped newlines in task list output so that they don't trigger a newline in the shell
29
+
1
30
  ### 2.0.4
2
31
 
3
32
  2022-08-04 06:25
data/README.md CHANGED
@@ -94,6 +94,18 @@ You can include commands that can be executed by howzit. Commands start at the b
94
94
 
95
95
  A block defined between @after and @end markers will be displayed after a topic is run. Use it to remind yourself of additional tasks after automated ones have been executed. The content between these markers is still included when viewing the topic, but the tags themselves do not show up in output.
96
96
 
97
+ ### Adding Titles
98
+
99
+ When displaying a topic, howzit can display a title instead of the contents of a directive. Any text after the closing parenthesis will be considered the task title.
100
+
101
+ ```
102
+ @run(~/scripts/deploy.sh) Deploy script
103
+ ```
104
+
105
+ When the topic is displayed, it will now show "Run Deploy script" instead of the path to the script. This can be overridden with the `--show-code` flag, which will instead show the contents of the directive.
106
+
107
+ For adding titles to run blocks (fenced code), see below.
108
+
97
109
  ### Run blocks (embedded scripts)
98
110
 
99
111
  For longer scripts you can write shell scripts and then call them with `@run(myscript.sh)`. For those in-between cases where you need a few commands but aren't motivated to create a separate file, you can use fenced code blocks with `run` as the language.
@@ -117,6 +129,12 @@ Example:
117
129
 
118
130
  Multiple blocks can be included in a topic. @commands take priority over code blocks and will be run first if they exist in the same topic.
119
131
 
132
+ ### Requiring Confirmation
133
+
134
+ You can have howzit confirm whether to execute an @command at runtime by including a question mark to the directive, e.g. `@run?(...)`. This will present a yes/no dialog before running the directive, with a default response of "yes" if you just hit return. To make the default response "no," add an exclamation point, e.g. `@run?!(...)`.
135
+
136
+ This works for any directive, including `@include`, and run blocks, which can use `run?` as the language specifier.
137
+
120
138
  ### Variables
121
139
 
122
140
  When running commands in a topic, you can use a double dash (`--`) in the command line (surrounded by spaces) and anything after it will be interpreted as shell arguments. These can be used in commands with `$` placeholders. `$1` represents the first argument, counting up from there. Use `$@` to pass all arguments as a shell-escaped string.
@@ -255,17 +273,21 @@ Some of the command line options can be set as defaults. The first time you run
255
273
 
256
274
  ---
257
275
  :color: true
276
+ :config_editor: subl
277
+ :editor: subl
278
+ :header_format: block
258
279
  :highlight: true
259
- :paginate: true
260
- :wrap: 80
280
+ :highlighter: mdcat
281
+ :include_upstream: true
282
+ :log_level: 0
283
+ :matching: fuzzy
284
+ :multiple_matches: choose
261
285
  :output_title: false
262
- :highlighter: auto
263
286
  :pager: auto
264
- :matching: partial
265
- :include_upstream: false
266
- :log_level: 1
267
- :multiple_matches: choose
268
- :header_format: border
287
+ :paginate: true
288
+ :show_all_code: false
289
+ :show_all_on_error: false
290
+ :wrap: 0
269
291
 
270
292
  If `:color:` is false, output will not be colored, and markdown highlighting will be bypassed.
271
293
 
@@ -336,6 +358,12 @@ If set to `auto` howzit will look for markdown highlighters in this order, using
336
358
 
337
359
  If you're combining a highlighter with howzit's pagination, include any flags needed to disable the highlighter's pagination (e.g. `mdless --no-pager`).
338
360
 
361
+ ### Configuring from the Command Line
362
+
363
+ You can get and set config options from the command line using `--config-get` and `--config-set`. If you run `--config-get` with no argument, it will display all config options. If you add a key (exact match required) you can get just the value for that key.
364
+
365
+ Using `--config-set` requires an argument in the format `key=value`. The type of the value (boolean, integer, string, symbol) will be automatically determined and converted. To change your highlighter, for example, use `howzit --config-set highlighter=mdcat`.
366
+
339
367
  ## Shell Integration
340
368
 
341
369
  I personally like to alias `bld` to `howzit -r`. If you define a function in your shell, you can have it default to "build" but accept an alternate argument. There's an example for Fish included, and in Bash it would be as simple as `howzit -r ${1:build}`.
data/bin/howzit CHANGED
@@ -74,11 +74,18 @@ OptionParser.new do |opts|
74
74
  end
75
75
 
76
76
  opts.on('-q', '--quiet', 'Silence info message') do
77
- Howzit.options[:log_level] = 3
77
+ Howzit.options[:log_level] = 4
78
+ Howzit.console.reset_level
78
79
  end
79
80
 
80
81
  opts.on('-v', '--verbose', 'Show all messages') do
82
+ Howzit.options[:log_level] = 1
83
+ Howzit.console.reset_level
84
+ end
85
+
86
+ opts.on('-d', '--debug', 'Show debug messages (and all messages)') do
81
87
  Howzit.options[:log_level] = 0
88
+ Howzit.console.reset_level
82
89
  end
83
90
 
84
91
  opts.on('-u', '--[no-]upstream', 'Traverse up parent directories for additional build notes') do |p|
@@ -114,8 +121,8 @@ OptionParser.new do |opts|
114
121
  raise 'Argument must be KEY=VALUE' unless key =~ /\S=\S/
115
122
 
116
123
  parts = key.split(/=/)
117
- k = parts[0].sub(/^:/, '')
118
- v = parts[1..-1].join(' ')
124
+ k = parts.shift.sub(/^:/, '')
125
+ v = parts.join(' ')
119
126
 
120
127
  if Howzit.options.key?(k.to_sym)
121
128
  Howzit.options[k.to_sym] = v.to_config_value(Howzit.options[k.to_sym])
@@ -89,7 +89,7 @@ module Howzit
89
89
  # Create a buildnotes skeleton
90
90
  def create_note
91
91
  trap('SIGINT') do
92
- warn "\nCanceled"
92
+ Howzit.console.info "\nCanceled"
93
93
  exit!
94
94
  end
95
95
  default = !$stdout.isatty || Howzit.options[:default]
@@ -269,8 +269,8 @@ module Howzit
269
269
  required = t_meta['required'].strip.split(/\s*,\s*/)
270
270
  required.each do |req|
271
271
  unless @metadata.keys.include?(req.downcase)
272
- warn %({xr}ERROR: Missing required metadata key from template '{bw}#{File.basename(template, '.md')}{xr}'{x}).c
273
- warn %({xr}Please define {by}#{req.downcase}{xr} in build notes{x}).c
272
+ Howzit.console.error %({xr}ERROR: Missing required metadata key from template '{bw}#{File.basename(template, '.md')}{xr}'{x}).c
273
+ Howzit.console.error %({xr}Please define {by}#{req.downcase}{xr} in build notes{x}).c
274
274
  Process.exit 1
275
275
  end
276
276
  end
data/lib/howzit/config.rb CHANGED
@@ -91,12 +91,12 @@ module Howzit
91
91
 
92
92
  def create_config(d)
93
93
  unless File.directory?(config_dir)
94
- warn "Creating config directory at #{config_dir}"
94
+ Howzit.console.info "Creating config directory at #{config_dir}"
95
95
  FileUtils.mkdir_p(config_dir)
96
96
  end
97
97
 
98
98
  unless File.exist?(config_file)
99
- warn "Writing fresh config file to #{config_file}"
99
+ Howzit.console.info "Writing fresh config file to #{config_file}"
100
100
  write_config(d)
101
101
  end
102
102
  config_file
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ LOG_LEVELS = {
4
+ debug: 0,
5
+ info: 1,
6
+ warn: 2,
7
+ error: 3
8
+ }.deep_freeze
9
+
10
+ module Howzit
11
+ # Console logging
12
+ class ConsoleLogger
13
+ attr_accessor :log_level
14
+
15
+ def initialize(level = nil)
16
+ @log_level = level || Howzit.options[:log_level]
17
+ end
18
+
19
+ def reset_level
20
+ @log_level = Howzit.options[:log_level]
21
+ end
22
+
23
+ def write(msg, level = :info)
24
+ $stderr.puts msg if LOG_LEVELS[level] >= @log_level
25
+ end
26
+
27
+ def debug(msg)
28
+ write msg, :debug
29
+ end
30
+
31
+ def info(msg)
32
+ write msg, :info
33
+ end
34
+
35
+ def warn(msg)
36
+ write msg, :warn
37
+ end
38
+
39
+ def error(msg)
40
+ write msg, :error
41
+ end
42
+ end
43
+ end
data/lib/howzit/hash.rb CHANGED
@@ -32,4 +32,24 @@ class ::Hash
32
32
  def deep_thaw!
33
33
  replace deep_thaw
34
34
  end
35
+
36
+ # Turn all keys into string
37
+ #
38
+ # Return a copy of the hash where all its keys are strings
39
+ def stringify_keys
40
+ each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v.is_a?(Hash) ? v.stringify_keys : v }
41
+ end
42
+
43
+ def stringify_keys!
44
+ replace stringify_keys
45
+ end
46
+
47
+ # Turn all keys into symbols
48
+ def symbolize_keys
49
+ each_with_object({}) { |(k, v), hsh| hsh[k.to_sym] = v.is_a?(Hash) ? v.symbolize_keys : v }
50
+ end
51
+
52
+ def symbolize_keys!
53
+ replace symbolize_keys
54
+ end
35
55
  end
data/lib/howzit/prompt.rb CHANGED
@@ -54,7 +54,7 @@ module Howzit
54
54
  ]
55
55
  res = `echo #{Shellwords.escape(matches.join("\n"))} | fzf #{settings.join(' ')}`.strip
56
56
  if res.nil? || res.empty?
57
- warn 'Cancelled'
57
+ Howzit.console.info 'Cancelled'
58
58
  Process.exit 0
59
59
  end
60
60
  return res.split(/\n/)
data/lib/howzit/task.rb CHANGED
@@ -2,13 +2,19 @@
2
2
 
3
3
  module Howzit
4
4
  class Task
5
- attr_reader :type, :title, :action, :parent
5
+ attr_reader :type, :title, :action, :parent, :optional, :default
6
6
 
7
- def initialize(type, title, action, parent = nil)
7
+ def initialize(type, title, action, parent = nil, optional: false, default: true)
8
8
  @type = type
9
9
  @title = title
10
10
  @action = action.render_arguments
11
11
  @parent = parent
12
+ @optional = optional
13
+ @default = default
14
+ end
15
+
16
+ def inspect
17
+ %(<#Howzit::Task @type=:#{@type} @title="#{@title}" @block?=#{@action.split(/\n/).count > 1}>)
12
18
  end
13
19
 
14
20
  def to_s
@@ -16,7 +22,7 @@ module Howzit
16
22
  end
17
23
 
18
24
  def to_list
19
- " * #{@type}: #{@title}"
25
+ " * #{@type}: #{@title.gsub(/\\n/, '\​n')}"
20
26
  end
21
27
  end
22
28
  end
data/lib/howzit/topic.rb CHANGED
@@ -28,14 +28,21 @@ module Howzit
28
28
  if @tasks.count.positive?
29
29
  unless @prereqs.empty?
30
30
  puts @prereqs.join("\n\n")
31
- res = Prompt.yn('This task has prerequisites, have they been met?', default: true)
31
+ res = Prompt.yn('This topic has prerequisites, have they been met?', default: true)
32
32
  Process.exit 1 unless res
33
33
 
34
34
  end
35
35
 
36
36
  @tasks.each do |task|
37
+ if task.optional
38
+ q = %({bg}#{task.type.to_s.capitalize} {xw}"{bw}#{task.title}{xw}"{x}).c
39
+ res = Prompt.yn(q, default: task.default)
40
+ next unless res
41
+
42
+ end
43
+
37
44
  if task.type == :block
38
- warn "{bg}Running block {bw}#{title}{x}".c if Howzit.options[:log_level] < 2
45
+ Howzit.console.info "{bg}Running block {bw}#{title}{x}".c if Howzit.options[:log_level] < 2
39
46
  block = task.action
40
47
  script = Tempfile.new('howzit_script')
41
48
  begin
@@ -74,7 +81,7 @@ module Howzit
74
81
  end
75
82
  end
76
83
  else
77
- warn "{r}--run: No {br}@directive{xr} found in {bw}#{key}{x}".c
84
+ Howzit.console.warn "{r}--run: No {br}@directive{xr} found in {bw}#{@title}{x}".c
78
85
  end
79
86
  output.push("{bm}Ran #{tasks} #{tasks == 1 ? 'task' : 'tasks'}{x}".c) if Howzit.options[:log_level] < 2 && !nested
80
87
 
@@ -88,21 +95,21 @@ module Howzit
88
95
  out = "{bg}Copying {bw}#{string}".c
89
96
  case os
90
97
  when /darwin.*/i
91
- warn "#{out} (macOS){x}".c if Howzit.options[:log_level] < 2
98
+ $stderr.puts "#{out} (macOS){x}".c if Howzit.options[:log_level].zero?
92
99
  `echo #{Shellwords.escape(string)}'\\c'|pbcopy`
93
100
  when /mingw|mswin/i
94
- warn "#{out} (Windows){x}".c if Howzit.options[:log_level] < 2
101
+ $stderr.puts "#{out} (Windows){x}".c if Howzit.options[:log_level].zero?
95
102
  `echo #{Shellwords.escape(string)} | clip`
96
103
  else
97
104
  if 'xsel'.available?
98
- warn "#{out} (Linux, xsel){x}".c if Howzit.options[:log_level] < 2
105
+ $stderr.puts "#{out} (Linux, xsel){x}".c if Howzit.options[:log_level].zero?
99
106
  `echo #{Shellwords.escape(string)}'\\c'|xsel -i`
100
107
  elsif 'xclip'.available?
101
- warn "#{out} (Linux, xclip){x}".c if Howzit.options[:log_level] < 2
108
+ $stderr.puts "#{out} (Linux, xclip){x}".c if Howzit.options[:log_level].zero?
102
109
  `echo #{Shellwords.escape(string)}'\\c'|xclip -i`
103
110
  else
104
- warn out if Howzit.options[:log_level] < 2
105
- warn 'Unable to determine executable for clipboard.'
111
+ $stderr.puts out if Howzit.options[:log_level].zero?
112
+ $stderr.puts 'Unable to determine executable for clipboard.'
106
113
  end
107
114
  end
108
115
  end
@@ -112,18 +119,18 @@ module Howzit
112
119
  out = "{bg}Opening {bw}#{command}".c
113
120
  case os
114
121
  when /darwin.*/i
115
- warn "#{out} (macOS){x}".c if Howzit.options[:log_level] < 2
122
+ Howzit.console.debug "#{out} (macOS){x}".c if Howzit.options[:log_level] < 2
116
123
  `open #{Shellwords.escape(command)}`
117
124
  when /mingw|mswin/i
118
- warn "#{out} (Windows){x}".c if Howzit.options[:log_level] < 2
125
+ Howzit.console.debug "#{out} (Windows){x}".c if Howzit.options[:log_level] < 2
119
126
  `start #{Shellwords.escape(command)}`
120
127
  else
121
128
  if 'xdg-open'.available?
122
- warn "#{out} (Linux){x}".c if Howzit.options[:log_level] < 2
129
+ Howzit.console.debug "#{out} (Linux){x}".c if Howzit.options[:log_level] < 2
123
130
  `xdg-open #{Shellwords.escape(command)}`
124
131
  else
125
- warn out if Howzit.options[:log_level] < 2
126
- warn 'Unable to determine executable for `open`.'
132
+ Howzit.console.debug out if Howzit.options[:log_level] < 2
133
+ Howzit.console.debug 'Unable to determine executable for `open`.'
127
134
  end
128
135
  end
129
136
  end
@@ -139,49 +146,57 @@ module Howzit
139
146
  output.push('')
140
147
  end
141
148
  topic = @content.dup
142
- topic.gsub!(/(?mi)^(`{3,})run *([^\n]*)[\s\S]*?\n\1\s*$/, '@@@run \2') unless Howzit.options[:show_all_code]
149
+ topic.gsub!(/(?mi)^(`{3,})run([?!]*) *([^\n]*)[\s\S]*?\n\1\s*$/, '@@@run\2 \3') unless Howzit.options[:show_all_code]
143
150
  topic.split(/\n/).each do |l|
144
151
  case l
145
152
  when /@(before|after|prereq|end)/
146
153
  next
147
- when /@include\((.*?)\)/
148
- m = Regexp.last_match
149
- matches = Howzit.buildnote.find_topic(m[1])
154
+ when /@include(?<optional>[!?]{1,2})?\((?<action>.*?)\)/
155
+ m = Regexp.last_match.named_captures.symbolize_keys
156
+ matches = Howzit.buildnote.find_topic(m[:action])
150
157
  unless matches.empty?
151
- if opt[:single]
152
- title = "From #{matches[0].title}:"
153
- color = '{Kyd}'
154
- rule = '{kKd}'
155
- else
156
- title = "Include #{matches[0].title}"
157
- color = '{Kyd}'
158
- rule = '{kKd}'
159
- end
160
- unless Howzit.inclusions.include?(matches[0])
161
- output.push("#{'> ' * @nest_level}#{title}".format_header({ color: color, hr: '.', border: rule }))
158
+ i_topic = matches[0]
159
+ rule = '{kKd}'
160
+ color = '{Kyd}'
161
+ option = if i_topic.tasks.empty?
162
+ ''
163
+ else
164
+ optional = m[:optional] =~ /[?!]+/ ? true : false
165
+ default = m[:optional] =~ /!/ ? false : true
166
+ if optional
167
+ default ? " {xKk}[{gbK}Y{xKk}/{dbwK}n{xKk}]{x}#{color}".c : " {xKk}[{dbwK}y{xKk}/{bgK}N{xKk}]{x}#{color}".c
168
+ else
169
+ ''
170
+ end
171
+ end
172
+ title = "#{opt[:single] ? 'From' : 'Include'} #{i_topic.title}#{option}:"
173
+ options = { color: color, hr: '.', border: rule }
174
+ unless Howzit.inclusions.include?(i_topic)
175
+ output.push("#{'> ' * @nest_level}#{title}".format_header(options))
162
176
  end
163
177
 
164
- if opt[:single]
165
- if Howzit.inclusions.include?(matches[0])
166
- output.push("#{'> ' * @nest_level}#{title} included above".format_header({
167
- color: color, hr: '.', border: rule }))
168
- else
169
- @nest_level += 1
170
- output.concat(matches[0].print_out({ single: true, header: false }))
171
- @nest_level -= 1
172
- end
173
- unless Howzit.inclusions.include?(matches[0])
174
- output.push("#{'> ' * @nest_level}...".format_header({ color: color, hr: '.', border: rule }))
175
- end
178
+ if opt[:single] && Howzit.inclusions.include?(i_topic)
179
+ output.push("#{'> ' * @nest_level}#{title} included above".format_header(options))
180
+ elsif opt[:single]
181
+ @nest_level += 1
182
+ output.concat(i_topic.print_out({ single: true, header: false }))
183
+ output.push("#{'> ' * @nest_level}...".format_header(options))
184
+ @nest_level -= 1
176
185
  end
177
- Howzit.inclusions.push(matches[0])
186
+ Howzit.inclusions.push(i_topic)
178
187
  end
179
-
180
- when /@(run|copy|open|url|include)\((.*?)\)(.*?)$/
181
- m = Regexp.last_match
182
- cmd = m[1]
183
- obj = m[2]
184
- title = m[3].empty? ? obj : m[3]
188
+ when /@(?<cmd>run|copy|open|url|include)(?<optional>[?!]{1,2})?\((?<action>.*?)\) *(?<title>.*?)$/
189
+ m = Regexp.last_match.named_captures.symbolize_keys
190
+ cmd = m[:cmd]
191
+ obj = m[:action]
192
+ title = m[:title].empty? ? obj : m[:title].strip
193
+ optional = m[:optional] =~ /[?!]+/ ? true : false
194
+ default = m[:optional] =~ /!/ ? false : true
195
+ option = if optional
196
+ default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
197
+ else
198
+ ''
199
+ end
185
200
  icon = case cmd
186
201
  when 'run'
187
202
  "\u{25B6}"
@@ -191,14 +206,28 @@ module Howzit
191
206
  "\u{279A}"
192
207
  end
193
208
 
194
- output.push("{bmK}#{icon} {bwK}#{title.gsub(/\\n/, '\​n')}{x}".c)
195
- when /(`{3,})run *(.*?)$/i
196
- m = Regexp.last_match
197
- desc = m[2].length.positive? ? "Block: #{m[2]}" : 'Code Block'
209
+ output.push("{bmK}#{icon} {bwK}#{title.gsub(/\\n/, '\​n')}{x}#{option}".c)
210
+ when /(?<fence>`{3,})run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
211
+ m = Regexp.last_match.named_captures.symbolize_keys
212
+ optional = m[:optional] =~ /[?!]+/ ? true : false
213
+ default = m[:optional] =~ /!/ ? false : true
214
+ option = if optional
215
+ default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
216
+ else
217
+ ''
218
+ end
219
+ desc = m[:title].length.positive? ? "Block: #{m[:title]}#{option}" : "Code Block#{option}"
198
220
  output.push("{bmK}\u{25B6} {bwK}#{desc}{x}\n```".c)
199
- when /@@@run *(.*?)$/i
200
- m = Regexp.last_match
201
- desc = m[1].length.positive? ? "Block: #{m[1]}" : 'Code Block'
221
+ when /@@@run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
222
+ m = Regexp.last_match.named_captures.symbolize_keys
223
+ optional = m[:optional] =~ /[?!]+/ ? true : false
224
+ default = m[:optional] =~ /!/ ? false : true
225
+ option = if optional
226
+ default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
227
+ else
228
+ ''
229
+ end
230
+ desc = m[:title].length.positive? ? "Block: #{m[:title]}#{option}" : "Code Block#{option}"
202
231
  output.push("{bmK}\u{25B6} {bwK}#{desc}{x}".c)
203
232
  else
204
233
  l.wrap!(Howzit.options[:wrap]) if Howzit.options[:wrap].positive?
@@ -215,18 +244,27 @@ module Howzit
215
244
  @prereqs = @content.scan(/(?<=@before\n).*?(?=\n@end)/im).map(&:strip)
216
245
  @postreqs = @content.scan(/(?<=@after\n).*?(?=\n@end)/im).map(&:strip)
217
246
 
218
- rx = /(?:@(include|run|copy|open|url)\((.*?)\) *(.*?)(?=$)|(`{3,})run(?: +([^\n]+))?(.*?)\4)/mi
219
- directives = @content.scan(rx)
247
+ rx = /(?mix)(?:
248
+ @(?<cmd>include|run|copy|open|url)(?<optional>[!?]{1,2})?\((?<action>[^)]*?)\)(?<title>[^\n]+)?
249
+ |(?<fence>`{3,})run(?<optional2>[!?]{1,2})?(?<title2>[^\n]+)?(?<block>.*?)\k<fence>
250
+ )/
251
+ matches = []
252
+ @content.scan(rx) { matches << Regexp.last_match }
253
+ matches.each do |m|
254
+ c = m.named_captures.symbolize_keys
220
255
 
221
- directives.each do |c|
222
- if c[0].nil?
223
- title = c[4] ? c[4].strip : ''
224
- block = c[5].strip
225
- runnable << Howzit::Task.new(:block, title, block)
256
+ if c[:cmd].nil?
257
+ optional = c[:optional2] =~ /[?!]{1,2}/ ? true : false
258
+ default = c[:optional2] =~ /!/ ? false : true
259
+ title = c[:title2].nil? ? '' : c[:title2].strip
260
+ block = c[:block]&.strip
261
+ runnable << Howzit::Task.new(:block, title, block, optional: optional, default: default)
226
262
  else
227
- cmd = c[0]
228
- obj = c[1]
229
- title = c[3] || obj
263
+ cmd = c[:cmd]
264
+ optional = c[:optional] =~ /[?!]{1,2}/ ? true : false
265
+ default = c[:optional] =~ /!/ ? false : true
266
+ obj = c[:action]
267
+ title = c[:title].nil? ? obj : c[:title].strip
230
268
 
231
269
  case cmd
232
270
  when /include/i
@@ -239,17 +277,15 @@ module Howzit
239
277
  # end
240
278
  # runnable.concat(tasks)
241
279
  # end
242
- title = c[3] || obj
243
- runnable << Howzit::Task.new(:include, title, obj)
280
+ runnable << Howzit::Task.new(:include, title, obj, optional: optional, default: default)
244
281
  when /run/i
245
- title = c[3] || obj
246
282
  # warn "{bg}Running {bw}#{obj}{x}".c if Howzit.options[:log_level] < 2
247
- runnable << Howzit::Task.new(:run, title, obj)
283
+ runnable << Howzit::Task.new(:run, title, obj, optional: optional, default: default)
248
284
  when /copy/i
249
285
  # warn "{bg}Copied {bw}#{obj}{bg} to clipboard{x}".c if Howzit.options[:log_level] < 2
250
- runnable << Howzit::Task.new(:copy, title, Shellwords.escape(obj))
286
+ runnable << Howzit::Task.new(:copy, title, Shellwords.escape(obj), optional: optional, default: default)
251
287
  when /open|url/i
252
- runnable << Howzit::Task.new(:open, title, obj)
288
+ runnable << Howzit::Task.new(:open, title, obj, optional: optional, default: default)
253
289
  end
254
290
  end
255
291
  end
data/lib/howzit/util.rb CHANGED
@@ -40,7 +40,7 @@ module Howzit
40
40
  if hl.available?
41
41
  Howzit.options[:highlighter]
42
42
  else
43
- warn Color.template("{Rw}Error:{xbw} Specified highlighter (#{Howzit.options[:highlighter]}) not found, switching to auto")
43
+ Howzit.console.error Color.template("{Rw}Error:{xbw} Specified highlighter (#{Howzit.options[:highlighter]}) not found, switching to auto")
44
44
  Howzit.options[:highlighter] = 'auto'
45
45
  which_highlighter
46
46
  end
@@ -78,7 +78,7 @@ module Howzit
78
78
  if pg.available?
79
79
  Howzit.options[:pager]
80
80
  else
81
- warn Color.template("{Rw}Error:{xbw} Specified pager (#{Howzit.options[:pager]}) not found, switching to auto")
81
+ Howzit.console.error Color.template("{Rw}Error:{xbw} Specified pager (#{Howzit.options[:pager]}) not found, switching to auto")
82
82
  Howzit.options[:pager] = 'auto'
83
83
  which_pager
84
84
  end
@@ -104,7 +104,7 @@ module Howzit
104
104
  begin
105
105
  exec(pager)
106
106
  rescue SystemCallError => e
107
- @log.error(e)
107
+ Howzit.console.error(e)
108
108
  exit 1
109
109
  end
110
110
  end
@@ -3,5 +3,5 @@
3
3
  # Primary module for this gem.
4
4
  module Howzit
5
5
  # Current Howzit version.
6
- VERSION = '2.0.4'
6
+ VERSION = '2.0.7'
7
7
  end
data/lib/howzit.rb CHANGED
@@ -5,8 +5,9 @@ require_relative 'howzit/prompt'
5
5
  require_relative 'howzit/colors'
6
6
  require_relative 'howzit/stringutils'
7
7
 
8
- require_relative 'howzit/util'
9
8
  require_relative 'howzit/hash'
9
+ require_relative 'howzit/console_logger'
10
+ require_relative 'howzit/util'
10
11
  require_relative 'howzit/config'
11
12
  require_relative 'howzit/task'
12
13
  require_relative 'howzit/topic'
@@ -52,5 +53,9 @@ module Howzit
52
53
  def buildnote
53
54
  @buildnote ||= BuildNote.new
54
55
  end
56
+
57
+ def console
58
+ @console ||= Howzit::ConsoleLogger.new(options[:log_level])
59
+ end
55
60
  end
56
61
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: howzit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
@@ -272,6 +272,7 @@ files:
272
272
  - lib/howzit/buildnotes.rb
273
273
  - lib/howzit/colors.rb
274
274
  - lib/howzit/config.rb
275
+ - lib/howzit/console_logger.rb
275
276
  - lib/howzit/hash.rb
276
277
  - lib/howzit/prompt.rb
277
278
  - lib/howzit/stringutils.rb