howzit 2.0.9 → 2.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,37 @@
3
3
  module Howzit
4
4
  # String Extensions
5
5
  module StringUtils
6
+ ##
7
+ ## Test if the filename matches the conditions to be a build note
8
+ ##
9
+ ## @return [Boolean] true if filename passes test
10
+ ##
11
+ def build_note?
12
+ return false if downcase !~ /^(howzit[^.]*|build[^.]+)/
13
+
14
+ return false if Howzit.config.should_ignore(self)
15
+
16
+ true
17
+ end
18
+
19
+ ##
20
+ ## Replace slash escaped characters in a string with a
21
+ ## zero-width space that will prevent a shell from
22
+ ## interpreting them when output to console
23
+ ##
24
+ ## @return [String] new string
25
+ ##
26
+ def preserve_escapes
27
+ gsub(/\\([a-z])/, '\​\1')
28
+ end
29
+
6
30
  # Convert a string to a valid YAML value
31
+ #
32
+ # @param orig_value The original value from which
33
+ # type will be determined
34
+ #
35
+ # @return coerced value
36
+ #
7
37
  def to_config_value(orig_value = nil)
8
38
  if orig_value
9
39
  case orig_value.class.to_s
@@ -28,10 +58,21 @@ module Howzit
28
58
  end
29
59
  end
30
60
 
61
+ ##
62
+ ## Shortcut for calling Color.template
63
+ ##
64
+ ## @return [String] colorized string
65
+ ##
31
66
  def c
32
67
  Color.template(self)
33
68
  end
34
69
 
70
+
71
+ ##
72
+ ## Convert a string to a regex object based on matching settings
73
+ ##
74
+ ## @return [Regexp] Receive regex representation of the object.
75
+ ##
35
76
  def to_rx
36
77
  case Howzit.options[:matching]
37
78
  when 'exact'
@@ -50,9 +91,17 @@ module Howzit
50
91
  gsub(/\e\[[\d;]+m/, '').gsub(/\e\]1337;SetMark/,'')
51
92
  end
52
93
 
94
+ # Wrap text at a specified width.
95
+ #
53
96
  # Adapted from https://github.com/pazdera/word_wrap/,
54
- # copyright (c) 2014, 2015 Radek Pazdera
55
- # Distributed under the MIT License
97
+ # copyright (c) 2014, 2015 Radek Pazdera Distributed
98
+ # under the MIT License
99
+ #
100
+ # @param width [Integer] The width at which to
101
+ # wrap lines
102
+ #
103
+ # @return [String] wrapped string
104
+ #
56
105
  def wrap(width)
57
106
  width ||= 80
58
107
  output = []
@@ -84,12 +133,19 @@ module Howzit
84
133
  output.join("\n")
85
134
  end
86
135
 
136
+ ##
137
+ ## Wrap string in place (destructive)
138
+ ##
139
+ ## @param width [Integer] The width at which to wrap
140
+ ##
87
141
  def wrap!(width)
88
142
  replace(wrap(width))
89
143
  end
90
144
 
91
145
  # Truncate string to nearest word
92
- # @param len <number> max length of string
146
+ #
147
+ # @param len [Integer] max length of string
148
+ #
93
149
  def trunc(len)
94
150
  split(/ /).each_with_object([]) do |x, ob|
95
151
  break ob unless ob.join(' ').length + ' '.length + x.length <= len
@@ -98,10 +154,21 @@ module Howzit
98
154
  end.join(' ').strip
99
155
  end
100
156
 
157
+ ##
158
+ ## Truncate string in place (destructive)
159
+ ##
160
+ ## @param len [Integer] The length to truncate at
161
+ ##
101
162
  def trunc!(len)
102
163
  replace trunc(len)
103
164
  end
104
165
 
166
+ ##
167
+ ## Splits a line at nearest word break
168
+ ##
169
+ ## @param width [Integer] The width of the first segment
170
+ ## @param indent [String] The indent string
171
+ ##
105
172
  def split_line(width, indent = '')
106
173
  line = dup
107
174
  at = line.index(/\s/)
@@ -119,10 +186,23 @@ module Howzit
119
186
  end
120
187
  end
121
188
 
189
+ ##
190
+ ## Test if an executable is available on the system
191
+ ##
192
+ ## @return [Boolean] executable is available
193
+ ##
122
194
  def available?
123
195
  Util.valid_command?(self)
124
196
  end
125
197
 
198
+ ##
199
+ ## Render [%variable] placeholders in a templated string
200
+ ##
201
+ ## @param vars [Hash] Key/value pairs of variable
202
+ ## values
203
+ ##
204
+ ## @return [String] Rendered string
205
+ ##
126
206
  def render_template(vars)
127
207
  vars.each do |k, v|
128
208
  gsub!(/\[%#{k}(:.*?)?\]/, v)
@@ -131,10 +211,20 @@ module Howzit
131
211
  gsub(/\[%(.*?):(.*?)\]/, '\2')
132
212
  end
133
213
 
214
+ ##
215
+ ## Render [%variable] placeholders in place
216
+ ##
217
+ ## @param vars [Hash] Key/value pairs of variable values
218
+ ##
134
219
  def render_template!(vars)
135
220
  replace render_template(vars)
136
221
  end
137
222
 
223
+ ##
224
+ ## Render $X placeholders based on positional arguments
225
+ ##
226
+ ## @return [String] rendered string
227
+ ##
138
228
  def render_arguments
139
229
  return self if Howzit.arguments.nil? || Howzit.arguments.empty?
140
230
 
@@ -145,6 +235,13 @@ module Howzit
145
235
  gsub(/\$[@*]/, Shellwords.join(Howzit.arguments))
146
236
  end
147
237
 
238
+ ##
239
+ ## Split the content at the first top-level header and
240
+ ## assume everything before it is metadata. Passes to
241
+ ## #get_metadata for processing
242
+ ##
243
+ ## @return [Hash] key/value pairs
244
+ ##
148
245
  def extract_metadata
149
246
  if File.exist?(self)
150
247
  leader = Util.read_file(self).split(/^#/)[0].strip
@@ -154,6 +251,11 @@ module Howzit
154
251
  end
155
252
  end
156
253
 
254
+ ##
255
+ ## Examine text for multimarkdown-style metadata and return key/value pairs
256
+ ##
257
+ ## @return [Hash] The metadata as key/value pairs
258
+ ##
157
259
  def get_metadata
158
260
  data = {}
159
261
  scan(/(?mi)^(\S[\s\S]+?): ([\s\S]*?)(?=\n\S[\s\S]*?:|\Z)/).each do |m|
@@ -162,6 +264,13 @@ module Howzit
162
264
  normalize_metadata(data)
163
265
  end
164
266
 
267
+ ##
268
+ ## Autocorrect some keys
269
+ ##
270
+ ## @param meta [Hash] The metadata
271
+ ##
272
+ ## @return [Hash] corrected metadata
273
+ ##
165
274
  def normalize_metadata(meta)
166
275
  data = {}
167
276
  meta.each do |k, v|
@@ -177,15 +286,33 @@ module Howzit
177
286
  data
178
287
  end
179
288
 
289
+ ##
290
+ ## Test if iTerm markers should be output. Requires that
291
+ ## the $TERM_PROGRAM be iTerm and howzit is not running
292
+ ## directives or paginating output
293
+ ##
294
+ ## @return [Boolean] should mark?
295
+ ##
180
296
  def should_mark_iterm?
181
297
  ENV['TERM_PROGRAM'] =~ /^iTerm/ && !Howzit.options[:run] && !Howzit.options[:paginate]
182
298
  end
183
299
 
300
+ ##
301
+ ## Output an iTerm marker
302
+ ##
303
+ ## @return [String] ANSI escape sequence for iTerm
304
+ ## marker
305
+ ##
184
306
  def iterm_marker
185
307
  "\e]1337;SetMark\a" if should_mark_iterm?
186
308
  end
187
309
 
188
310
  # Make a fancy title line for the topic
311
+ #
312
+ # @param opts [Hash] options
313
+ #
314
+ # @return [String] formatted string
315
+ #
189
316
  def format_header(opts = {})
190
317
  title = dup
191
318
  options = {
data/lib/howzit/task.rb CHANGED
@@ -1,14 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Howzit
4
+ # Task object
4
5
  class Task
5
6
  attr_reader :type, :title, :action, :parent, :optional, :default
6
7
 
7
- def initialize(type, title, action, parent = nil, optional: false, default: true)
8
- @type = type
9
- @title = title
10
- @action = action.render_arguments
11
- @parent = parent
8
+ ##
9
+ ## Initialize a Task object
10
+ ##
11
+ def initialize(params, optional: false, default: true)
12
+ @type = params[:type]
13
+ @title = params[:title]
14
+ @action = params[:action].render_arguments
15
+ @parent = params[:parent] || nil
12
16
  @optional = optional
13
17
  @default = default
14
18
  end
@@ -22,7 +26,7 @@ module Howzit
22
26
  end
23
27
 
24
28
  def to_list
25
- " * #{@type}: #{@title.gsub(/\\n/, '\​n')}"
29
+ " * #{@type}: #{@title.preserve_escapes}"
26
30
  end
27
31
  end
28
32
  end
data/lib/howzit/topic.rb CHANGED
@@ -52,7 +52,13 @@ module Howzit
52
52
 
53
53
  @tasks.each do |task|
54
54
  if task.optional
55
- q = %({bg}#{task.type.to_s.capitalize} {xw}"{bw}#{task.title}{xw}"{x}).c
55
+ note = if task.type == :include
56
+ task_count = Howzit.buildnote.find_topic(task.action)[0].tasks.count
57
+ " (#{task_count} tasks)"
58
+ else
59
+ ""
60
+ end
61
+ q = %({bg}#{task.type.to_s.capitalize} {xw}"{bw}#{task.title}{xw}"#{note}{x}).c
56
62
  res = Prompt.yn(q, default: task.default)
57
63
  next unless res
58
64
 
@@ -81,7 +87,7 @@ module Howzit
81
87
 
82
88
  $stderr.puts "{by}Running tasks from {bw}#{matches[0].title}{x}".c if Howzit.options[:log_level] < 2
83
89
  output.push(matches[0].run(nested: true))
84
- $stderr.puts "{by}End include: #{matches[0].tasks.count} tasks".c if Howzit.options[:log_level] < 2
90
+ $stderr.puts "{by}End include: #{matches[0].tasks.count} tasks{x}".c if Howzit.options[:log_level] < 2
85
91
  tasks += matches[0].tasks.count
86
92
  when :run
87
93
  $stderr.puts "{bg}Running {bw}#{title}{x}".c if Howzit.options[:log_level] < 2
@@ -107,6 +113,11 @@ module Howzit
107
113
  output
108
114
  end
109
115
 
116
+ ##
117
+ ## Platform-agnostic copy-to-clipboard
118
+ ##
119
+ ## @param string [String] The string to copy
120
+ ##
110
121
  def os_copy(string)
111
122
  os = RbConfig::CONFIG['target_os']
112
123
  out = "{bg}Copying {bw}#{string}".c
@@ -131,6 +142,11 @@ module Howzit
131
142
  end
132
143
  end
133
144
 
145
+ ##
146
+ ## Platform-agnostic open command
147
+ ##
148
+ ## @param command [String] The command
149
+ ##
134
150
  def os_open(command)
135
151
  os = RbConfig::CONFIG['target_os']
136
152
  out = "{bg}Opening {bw}#{command}".c
@@ -153,6 +169,11 @@ module Howzit
153
169
  end
154
170
 
155
171
  # Output a topic with fancy title and bright white text.
172
+ #
173
+ # @param options [Hash] The options
174
+ #
175
+ # @return [Array] array of formatted lines
176
+ #
156
177
  def print_out(options = {})
157
178
  defaults = { single: false, header: true }
158
179
  opt = defaults.merge(options)
@@ -223,7 +244,7 @@ module Howzit
223
244
  "\u{279A}"
224
245
  end
225
246
 
226
- output.push("{bmK}#{icon} {bwK}#{title.gsub(/\\n/, '\​n')}{x}#{option}".c)
247
+ output.push("{bmK}#{icon} {bwK}#{title.preserve_escapes}{x}#{option}".c)
227
248
  when /(?<fence>`{3,})run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
228
249
  m = Regexp.last_match.named_captures.symbolize_keys
229
250
  optional = m[:optional] =~ /[?!]+/ ? true : false
@@ -256,6 +277,11 @@ module Howzit
256
277
 
257
278
  private
258
279
 
280
+ ##
281
+ ## Collect all directives in the topic content
282
+ ##
283
+ ## @return [Array] array of Task objects
284
+ ##
259
285
  def gather_tasks
260
286
  runnable = []
261
287
  @prereqs = @content.scan(/(?<=@before\n).*?(?=\n@end)/im).map(&:strip)
@@ -275,7 +301,12 @@ module Howzit
275
301
  default = c[:optional2] =~ /!/ ? false : true
276
302
  title = c[:title2].nil? ? '' : c[:title2].strip
277
303
  block = c[:block]&.strip
278
- runnable << Howzit::Task.new(:block, title, block, optional: optional, default: default)
304
+ runnable << Howzit::Task.new({ type: :block,
305
+ title: title,
306
+ action: block,
307
+ parent: nil },
308
+ optional: optional,
309
+ default: default)
279
310
  else
280
311
  cmd = c[:cmd]
281
312
  optional = c[:optional] =~ /[?!]{1,2}/ ? true : false
@@ -294,15 +325,35 @@ module Howzit
294
325
  # end
295
326
  # runnable.concat(tasks)
296
327
  # end
297
- runnable << Howzit::Task.new(:include, title, obj, optional: optional, default: default)
328
+ runnable << Howzit::Task.new({ type: :include,
329
+ title: title,
330
+ action: obj,
331
+ parent: nil },
332
+ optional: optional,
333
+ default: default)
298
334
  when /run/i
299
335
  # warn "{bg}Running {bw}#{obj}{x}".c if Howzit.options[:log_level] < 2
300
- runnable << Howzit::Task.new(:run, title, obj, optional: optional, default: default)
336
+ runnable << Howzit::Task.new({ type: :run,
337
+ title: title,
338
+ action: obj,
339
+ parent: nil },
340
+ optional: optional,
341
+ default: default)
301
342
  when /copy/i
302
343
  # warn "{bg}Copied {bw}#{obj}{bg} to clipboard{x}".c if Howzit.options[:log_level] < 2
303
- runnable << Howzit::Task.new(:copy, title, Shellwords.escape(obj), optional: optional, default: default)
344
+ runnable << Howzit::Task.new({ type: :copy,
345
+ title: title,
346
+ action: Shellwords.escape(obj),
347
+ parent: nil },
348
+ optional: optional,
349
+ default: default)
304
350
  when /open|url/i
305
- runnable << Howzit::Task.new(:open, title, obj, optional: optional, default: default)
351
+ runnable << Howzit::Task.new({ type: :open,
352
+ title: title,
353
+ action: obj,
354
+ parent: nil },
355
+ optional: optional,
356
+ default: default)
306
357
  end
307
358
  end
308
359
  end
data/lib/howzit/util.rb CHANGED
@@ -4,15 +4,40 @@ module Howzit
4
4
  # Util class
5
5
  module Util
6
6
  class << self
7
+
8
+ ##
9
+ ## Read a file with UTF-8 encoding and
10
+ ## leading/trailing whitespace removed
11
+ ##
12
+ ## @param path [String] The path to read
13
+ ##
14
+ ## @return [String] UTF-8 encoded string
15
+ ##
7
16
  def read_file(path)
8
17
  IO.read(path).force_encoding('utf-8').strip
9
18
  end
10
19
 
20
+ ##
21
+ ## Test if an external command exists and is
22
+ ## executable. Removes additional arguments and passes
23
+ ## just the executable to #command_exist?
24
+ ##
25
+ ## @param command [String] The command
26
+ ##
27
+ ## @return [Boolean] command is valid
28
+ ##
11
29
  def valid_command?(command)
12
30
  cmd = command.split(' ')[0]
13
31
  command_exist?(cmd)
14
32
  end
15
33
 
34
+ ##
35
+ ## Test if external command exists
36
+ ##
37
+ ## @param command [String] The command
38
+ ##
39
+ ## @return [Boolean] command exists
40
+ ##
16
41
  def command_exist?(command)
17
42
  exts = ENV.fetch('PATHEXT', '').split(::File::PATH_SEPARATOR)
18
43
  if Pathname.new(command).absolute?
@@ -3,5 +3,5 @@
3
3
  # Primary module for this gem.
4
4
  module Howzit
5
5
  # Current Howzit version.
6
- VERSION = '2.0.9'
6
+ VERSION = '2.0.12'
7
7
  end
data/lib/howzit.rb CHANGED
@@ -24,11 +24,22 @@ require 'tty/screen'
24
24
  require 'tty/box'
25
25
  # require 'tty/prompt'
26
26
 
27
+ # Main config dir
27
28
  CONFIG_DIR = '~/.config/howzit'
29
+
30
+ # Config file name
28
31
  CONFIG_FILE = 'howzit.yaml'
32
+
33
+ # Ignore file name
29
34
  IGNORE_FILE = 'ignore.yaml'
35
+
36
+ # Available options for matching method
30
37
  MATCHING_OPTIONS = %w[partial exact fuzzy beginswith].freeze
38
+
39
+ # Available options for multiple_matches method
31
40
  MULTIPLE_OPTIONS = %w[first best all choose].freeze
41
+
42
+ # Available options for header formatting
32
43
  HEADER_FORMAT_OPTIONS = %w[border block].freeze
33
44
 
34
45
  # Main module for howzit
data/spec/task_spec.rb CHANGED
@@ -3,7 +3,12 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Howzit::Task do
6
- subject(:task) { Howzit::Task.new(:run, 'List Directory', 'ls') }
6
+ subject(:task) do
7
+ Howzit::Task.new({ type: :run,
8
+ title: 'List Directory',
9
+ action: 'ls',
10
+ parent: nil })
11
+ end
7
12
 
8
13
  describe ".new" do
9
14
  it "makes a new task instance" do
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.9
4
+ version: 2.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
@@ -297,7 +297,6 @@ files:
297
297
  - lib/.rubocop.yml
298
298
  - lib/howzit.rb
299
299
  - lib/howzit/buildnote.rb
300
- - lib/howzit/buildnotes.rb
301
300
  - lib/howzit/colors.rb
302
301
  - lib/howzit/config.rb
303
302
  - lib/howzit/console_logger.rb
@@ -310,7 +309,6 @@ files:
310
309
  - lib/howzit/version.rb
311
310
  - spec/.rubocop.yml
312
311
  - spec/buildnote_spec.rb
313
- - spec/buildnotes.md.bak
314
312
  - spec/cli_spec.rb
315
313
  - spec/ruby_gem_spec.rb
316
314
  - spec/spec_helper.rb
@@ -344,7 +342,6 @@ summary: Provides a way to access Markdown project notes by topic with query cap
344
342
  test_files:
345
343
  - spec/.rubocop.yml
346
344
  - spec/buildnote_spec.rb
347
- - spec/buildnotes.md.bak
348
345
  - spec/cli_spec.rb
349
346
  - spec/ruby_gem_spec.rb
350
347
  - spec/spec_helper.rb