howzit 2.0.10 → 2.0.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd8307dc1bdbf51c7a78333c5880990b0bf82acb3fb2401d9e9969fe312ce125
4
- data.tar.gz: 72ef1a744da1debcd5faf9ff9ee170eae3389b04e585cd652450eb65ba177c30
3
+ metadata.gz: e269532605e044c35e2a0ebe322fe51ba5199d690a57385a358a3bad4fc2921f
4
+ data.tar.gz: 4ca045a0c3c2d1627b04a47363beb8e2de6718f5c708e1f4bf96285af96e09d4
5
5
  SHA512:
6
- metadata.gz: affa665e5f83a8b836f5fe0a3d3c8e178d6fc880bcf3cecfe13afe44e61f4392831a45ff57f1a412a6ae7878f5cd7c00cd541aea1d780eb2b61aa01247268855
7
- data.tar.gz: 85449c9184c5927d56acbd00e4086f11a9f4ee85085bfe07c12eb3e7b27e71c00eccee203fd73bda94919dfef000ead8f99f61e275b4d73700b442e25caa38c9
6
+ metadata.gz: 803b06d4a85632357eb1e61a898f88c39971df388107a62f67479e34788346f1824f78a3b3473cf5ee45dc445a494e7a144590d5df33ffd1b73d2114ba19049d
7
+ data.tar.gz: 51c6ec7213c4b7c531e53c32140dc485d897f40ee79d242ee8ec446804ad0edac8a9bac61d3b68189bf60884a3dbee28fe6d5f5f3040dae23ec8cb7ddb24903c
data/.rubocop.yml CHANGED
@@ -6,6 +6,7 @@ AllCops:
6
6
 
7
7
  Metrics/BlockLength:
8
8
  Exclude:
9
+ - Rakefile
9
10
  - bin/howzit
10
11
  - lib/*.rb
11
12
 
data/.travis.yml CHANGED
@@ -4,10 +4,10 @@ sudo: required
4
4
  dist: trusty
5
5
  cache: bundler
6
6
  rvm:
7
+ - ruby-2.6.4
7
8
  - ruby-2.7.0
8
9
  - ruby-3.0.1
9
10
  install:
10
- - gem uninstall bundler
11
11
  - gem install bundler --version '2.2.29'
12
12
  - bundle install
13
- script: "rake"
13
+ script: "bundle exec rspec spec --exclude-pattern 'cli*'"
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ ### 2.0.13
2
+
3
+ 2022-08-05 13:19
4
+
5
+ #### IMPROVED
6
+
7
+ - Add tests for more ruby versions via Docker
8
+
9
+ ### 2.0.12
10
+
11
+ 2022-08-05 11:27
12
+
13
+ #### IMPROVED
14
+
15
+ - Show how many tasks will be included when requesting confirmation for an include? directive
16
+
17
+ ### 2.0.11
18
+
19
+ 2022-08-05 11:21
20
+
21
+ #### IMPROVED
22
+
23
+ - Update fish completions with all current command line options
24
+
1
25
  ### 2.0.10
2
26
 
3
27
  2022-08-05 08:17
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ require 'bundler/gem_tasks'
5
5
  require 'rspec/core/rake_task'
6
6
  require 'rubocop/rake_task'
7
7
  require 'yard'
8
+ require 'tty-spinner'
8
9
 
9
10
  task default: %i[test yard]
10
11
 
@@ -34,3 +35,43 @@ desc 'Changelog version check'
34
35
  task :cver do
35
36
  puts IO.read(File.join(File.dirname(__FILE__), 'CHANGELOG.md')).match(/^#+ (\d+\.\d+\.\d+(\w+)?)/)[1]
36
37
  end
38
+
39
+ desc 'Run tests in Docker'
40
+ task :dockertest, :version, :login do |_, args|
41
+ args.with_defaults(version: 'all', login: false)
42
+ case args[:version]
43
+ when /^a/
44
+ %w[6 7 3].each do |v|
45
+ Rake::Task['dockertest'].reenable
46
+ Rake::Task['dockertest'].invoke(v, false)
47
+ end
48
+ Process.exit 0
49
+ when /^3/
50
+ img = 'howzittest3'
51
+ file = 'docker/Dockerfile-3.0'
52
+ when /6$/
53
+ img = 'howzittest26'
54
+ file = 'docker/Dockerfile-2.6'
55
+ when /(^2|7$)/
56
+ img = 'howzittest27'
57
+ file = 'docker/Dockerfile-2.7'
58
+ else
59
+ img = 'howzittest'
60
+ file = 'docker/Dockerfile'
61
+ end
62
+
63
+ puts `docker build . --file #{file} -t #{img}`
64
+
65
+ exec "docker run -v #{File.dirname(__FILE__)}:/howzit -it #{img} /bin/bash -l" if args[:login]
66
+
67
+ spinner = TTY::Spinner.new('[:spinner] Running tests ...', hide_cursor: true)
68
+
69
+ spinner.auto_spin
70
+ res = `docker run --rm -v #{File.dirname(__FILE__)}:/howzit -it #{img}`
71
+ # commit = puts `bash -c "docker commit $(docker ps -a|grep #{img}|awk '{print $1}'|head -n 1) #{img}"`.strip
72
+ spinner.success
73
+ spinner.stop
74
+
75
+ puts res
76
+ # puts commit&.empty? ? "Error commiting Docker tag #{img}" : "Committed Docker tag #{img}"
77
+ end
data/bin/howzit CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby -W1
1
+ #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
4
  $LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
data/docker/Dockerfile ADDED
@@ -0,0 +1,11 @@
1
+ FROM ruby:3.0.1
2
+ # RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
3
+ RUN mkdir /howzit
4
+ WORKDIR /howzit
5
+ # COPY ./ /howzit/
6
+ RUN gem install bundler:2.2.17
7
+ RUN apt-get update -y
8
+ RUN apt-get install -y less vim
9
+ COPY ./docker/inputrc /root/.inputrc
10
+ COPY ./docker/bash_profile /root/.bash_profile
11
+ CMD ["scripts/runtests.sh"]
@@ -0,0 +1,11 @@
1
+ FROM ruby:2.6
2
+ # RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
3
+ RUN mkdir /howzit
4
+ WORKDIR /howzit
5
+ # COPY ./ /howzit/
6
+ RUN gem install bundler:2.2.17
7
+ RUN apt-get update -y
8
+ RUN apt-get install -y less vim
9
+ COPY ./docker/inputrc /root/.inputrc
10
+ COPY ./docker/bash_profile /root/.bash_profile
11
+ CMD ["scripts/runtests.sh"]
@@ -0,0 +1,11 @@
1
+ FROM ruby:2.7
2
+ # RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
3
+ RUN mkdir /howzit
4
+ WORKDIR /howzit
5
+ # COPY ./ /howzit/
6
+ RUN gem install bundler:2.2.17
7
+ RUN apt-get update -y
8
+ RUN apt-get install -y less vim
9
+ COPY ./docker/inputrc /root/.inputrc
10
+ COPY ./docker/bash_profile /root/.bash_profile
11
+ CMD ["scripts/runtests.sh"]
@@ -0,0 +1,11 @@
1
+ FROM ruby:3.0.0
2
+ # RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
3
+ RUN mkdir /howzit
4
+ WORKDIR /howzit
5
+ # COPY ./ /howzit/
6
+ RUN gem install bundler:2.2.17
7
+ RUN apt-get update -y
8
+ RUN apt-get install -y less vim
9
+ COPY ./docker/inputrc /root/.inputrc
10
+ COPY ./docker/bash_profile /root/.bash_profile
11
+ CMD ["scripts/runtests.sh"]
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+ export GLI_DEBUG=true
3
+ export EDITOR="/usr/bin/vim"
4
+ alias b="bundle exec bin/howzit"
5
+
6
+ shopt -s nocaseglob
7
+ shopt -s histappend
8
+ shopt -s histreedit
9
+ shopt -s histverify
10
+ shopt -s cmdhist
11
+
12
+ cd /howzit
13
+ bundle install
data/docker/inputrc ADDED
@@ -0,0 +1,57 @@
1
+ "\e[3~": delete-char
2
+ "\ex": 'cd !$ \015ls\015'
3
+ "\ez": 'cd -\015'
4
+ "\e\C-m": '\C-a "$(\C-e|fzf)"\C-a'
5
+ "\e/": '"$(!!|fzf)"\C-a \C-m\C-m'
6
+ # these allow you to use alt+left/right arrow keys
7
+ # to jump the cursor over words
8
+ "\e[1;5C": forward-word
9
+ "\e[1;5D": backward-word
10
+ # "\e[D": backward-word
11
+ # "\e[C": forward-word
12
+ "\ea": menu-complete
13
+ # TAB: menu-complete
14
+ # "\e[Z": "\e-1\C-i"
15
+
16
+ "\e\C-l": history-and-alias-expand-line
17
+
18
+ # these allow you to start typing a command and
19
+ # use the up/down arrow to auto complete from
20
+ # commands in your history
21
+ "\e[B": history-search-forward
22
+ "\e[A": history-search-backward
23
+ "\ew": history-search-backward
24
+ "\es": history-search-forward
25
+ # this lets you hit tab to auto-complete a file or
26
+ # directory name ignoring case
27
+ set completion-ignore-case On
28
+ set mark-symlinked-directories On
29
+ set completion-prefix-display-length 2
30
+ set bell-style none
31
+ # set bell-style visible
32
+ set meta-flag on
33
+ set convert-meta off
34
+ set input-meta on
35
+ set output-meta on
36
+ set show-all-if-ambiguous on
37
+ set show-all-if-unmodified on
38
+ set completion-map-case on
39
+ set visible-stats on
40
+
41
+ # Do history expansion when space entered?
42
+ $if bash
43
+ Space: magic-space
44
+ $endif
45
+
46
+ # Show extra file information when completing, like `ls -F` does
47
+ set visible-stats on
48
+
49
+ # Be more intelligent when autocompleting by also looking at the text after
50
+ # the cursor. For example, when the current line is "cd ~/src/mozil", and
51
+ # the cursor is on the "z", pressing Tab will not autocomplete it to "cd
52
+ # ~/src/mozillail", but to "cd ~/src/mozilla". (This is supported by the
53
+ # Readline used by Bash 4.)
54
+ set skip-completed-text on
55
+
56
+ # Use Alt/Meta + Delete to delete the preceding word
57
+ "\e[3;3~": kill-word
@@ -1,3 +1,35 @@
1
1
  complete -xc howzit -a "(howzit -L)"
2
- complete -xc howzit -s r -a "(howzit -T)"
3
-
2
+ complete -c howzit -l default -d "Answer all prompts with default response"
3
+ complete -c howzit -x -s m -l matching -a "partial exact fuzzy beginswith" -d "Topics matching type"
4
+ complete -c howzit -x -l multiple -a "first best all choose" -d "Multiple result handling"
5
+ complete -c howzit -s u -l no-upstream -d "Don't traverse up parent directories for additional build notes"
6
+ complete -c howzit -s u -l upstream -d "Traverse up parent directories for additional build notes"
7
+ complete -c howzit -s L -l list-completions -d "List topics for completion"
8
+ complete -c howzit -s l -l list -d "List available topics"
9
+ complete -c howzit -s R -l list-runnable -d "List topics containing @ directives (verbose)"
10
+ complete -c howzit -s T -l task-list -d "List topics containing @ directives (completion-compatible)"
11
+ complete -c howzit -l templates -d "List available templates"
12
+ complete -c howzit -l title-only -d "Output title only"
13
+ complete -c howzit -s c -l create -d "Create a skeleton build note in the current working directory"
14
+ complete -c howzit -f -l config-get -d "Display the configuration settings or setting for a specific key"
15
+ complete -c howzit -f -l config-set -d "Set a config value (must be a valid key)"
16
+ complete -c howzit -l edit-config -d "Edit configuration file using editor (subl)"
17
+ complete -c howzit -s e -l edit -d "Edit buildnotes file in current working directory using editor (subl)"
18
+ complete -c howzit -x -l grep -d "Display sections matching a search pattern"
19
+ complete -c howzit -s r -l run -a "(howzit -T)" -d "Execute @run, @open, and/or @copy commands for given topic"
20
+ complete -c howzit -s s -l select -d "Select topic from menu"
21
+ complete -c howzit -l color -d "Colorize output (default on)"
22
+ complete -c howzit -l no-color -d "Don't colorize output (default on)"
23
+ complete -c howzit -x -l header-format -d "Formatting style for topic titles (border, block)"
24
+ complete -c howzit -l md-highlight -d "Highlight Markdown syntax (default on), requires mdless or mdcat"
25
+ complete -c howzit -l no-md-highlight -d "Don't highlight Markdown syntax (default on), requires mdless or mdcat"
26
+ complete -c howzit -l pager -d "Paginate output (default on)"
27
+ complete -c howzit -l no-pager -d "Don't paginate output (default on)"
28
+ complete -c howzit -l show-code -d "Display the content of fenced run blocks"
29
+ complete -c howzit -s t -l title -d "Output title with build notes"
30
+ complete -c howzit -x -s w -l wrap -d "Wrap to specified width (default 80, 0 to disable)"
31
+ complete -c howzit -s d -l debug -d "Show debug messages (and all messages)"
32
+ complete -c howzit -s q -l quiet -d "Silence info message"
33
+ complete -c howzit -l verbose -d "Show all messages"
34
+ complete -c howzit -s h -l help -d "Display this screen"
35
+ complete -c howzit -s v -l version -d "Display version number"
data/howzit.gemspec CHANGED
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency 'yard', '~> 0.9.5'
39
39
  spec.add_development_dependency 'redcarpet', '~> 3.2'
40
40
  spec.add_development_dependency 'github-markup', '~> 1.3'
41
+ spec.add_development_dependency 'tty-spinner', '~> 0.9'
41
42
 
42
43
  spec.add_runtime_dependency 'mdless', '~> 1.0', '>= 1.0.28'
43
44
  spec.add_runtime_dependency 'tty-screen', '~> 0.8'
@@ -120,7 +120,7 @@ module Howzit
120
120
 
121
121
  ##
122
122
  ## Return a formatted list of topics containing
123
- ## @directives suitable for console output
123
+ ## directives suitable for console output
124
124
  ##
125
125
  ## @return [String] formatted list
126
126
  ##
@@ -275,38 +275,15 @@ module Howzit
275
275
  buildnotes.reverse
276
276
  end
277
277
 
278
- ##
279
- ## Test if the filename matches the conditions to be a build note
280
- ##
281
- ## @param filename [String] The filename to test
282
- ##
283
- ## @return [Boolean] true if filename passes test
284
- ##
285
- def build_note?(filename)
286
- return false if filename.downcase !~ /^(howzit[^.]*|build[^.]+)/
287
-
288
- return false if Howzit.config.should_ignore(filename)
289
-
290
- true
291
- end
292
-
293
278
  ##
294
279
  ## Glob current directory for valid build note filenames
280
+ ## (must start with "build" or "howzit" and have
281
+ ## extension of "txt", "md", or "markdown")
295
282
  ##
296
283
  ## @return [String] file path
297
284
  ##
298
285
  def glob_note
299
- filename = nil
300
- # Check for a build note file in the current folder. Filename must start
301
- # with "build" and have an extension of txt, md, or markdown.
302
-
303
- Dir.glob('*.{txt,md,markdown}').each do |f|
304
- if build_note?(f)
305
- filename = f
306
- break
307
- end
308
- end
309
- filename
286
+ Dir.glob('*.{txt,md,markdown}').select(&:build_note?)[0]
310
287
  end
311
288
 
312
289
  ##
data/lib/howzit/hash.rb CHANGED
@@ -5,7 +5,7 @@ class ::Hash
5
5
  ##
6
6
  ## Freeze all values in a hash
7
7
  ##
8
- ## @return Hash with all values frozen
8
+ ## @return [Hash] Hash with all values frozen
9
9
  ##
10
10
  def deep_freeze
11
11
  chilled = {}
@@ -16,10 +16,18 @@ class ::Hash
16
16
  chilled.freeze
17
17
  end
18
18
 
19
+ ##
20
+ ## Deep freeze a hash in place (destructive)
21
+ ##
19
22
  def deep_freeze!
20
23
  replace deep_thaw.deep_freeze
21
24
  end
22
25
 
26
+ ##
27
+ ## Unfreeze nested hash values
28
+ ##
29
+ ## @return [Hash] Hash with all values unfrozen
30
+ ##
23
31
  def deep_thaw
24
32
  chilled = {}
25
33
  each do |k, v|
@@ -29,26 +37,39 @@ class ::Hash
29
37
  chilled.dup
30
38
  end
31
39
 
40
+ ##
41
+ ## Unfreeze nested hash values in place (destructive)
42
+ ##
32
43
  def deep_thaw!
33
44
  replace deep_thaw
34
45
  end
35
46
 
36
47
  # Turn all keys into string
37
48
  #
38
- # Return a copy of the hash where all its keys are strings
49
+ # @return [Hash] hash with all keys as strings
50
+ #
39
51
  def stringify_keys
40
52
  each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v.is_a?(Hash) ? v.stringify_keys : v }
41
53
  end
42
54
 
55
+ ##
56
+ ## Turn all keys into strings in place (destructive)
57
+ ##
43
58
  def stringify_keys!
44
59
  replace stringify_keys
45
60
  end
46
61
 
47
62
  # Turn all keys into symbols
63
+ #
64
+ # @return [Hash] hash with all keys as symbols
65
+ #
48
66
  def symbolize_keys
49
67
  each_with_object({}) { |(k, v), hsh| hsh[k.to_sym] = v.is_a?(Hash) ? v.symbolize_keys : v }
50
68
  end
51
69
 
70
+ ##
71
+ ## Turn all keys into symbols in place (destructive)
72
+ ##
52
73
  def symbolize_keys!
53
74
  replace symbolize_keys
54
75
  end
data/lib/howzit/prompt.rb CHANGED
@@ -4,10 +4,22 @@ module Howzit
4
4
  # Command line prompt utils
5
5
  module Prompt
6
6
  class << self
7
- def yn(prompt, default: true)
7
+
8
+ ##
9
+ ## Display and read a Yes/No prompt
10
+ ##
11
+ ## @param prompt [String] The prompt string
12
+ ## @param default [Boolean] default value if
13
+ ## return is pressed or prompt is
14
+ ## skipped
15
+ ##
16
+ ## @return [Boolean] result
17
+ ##
18
+ def yn(prompt, default: true)
8
19
  return default unless $stdout.isatty
9
20
 
10
21
  return default if Howzit.options[:default]
22
+
11
23
  tty_state = `stty -g`
12
24
  system 'stty raw -echo cbreak isig'
13
25
  yn = color_single_options(default ? %w[Y n] : %w[y N])
@@ -20,6 +32,14 @@ module Howzit
20
32
  res.empty? ? default : res =~ /y/i
21
33
  end
22
34
 
35
+ ##
36
+ ## Helper function to colorize the Y/N prompt
37
+ ##
38
+ ## @param choices [Array] The choices with
39
+ ## default capitalized
40
+ ##
41
+ ## @return [String] colorized string
42
+ ##
23
43
  def color_single_options(choices = %w[y n])
24
44
  out = []
25
45
  choices.each do |choice|
@@ -33,6 +53,12 @@ module Howzit
33
53
  Color.template("{xg}[#{out.join('/')}{xg}]{x}")
34
54
  end
35
55
 
56
+ ##
57
+ ## Create a numbered list of options. Outputs directly
58
+ ## to console, returns nothing
59
+ ##
60
+ ## @param matches [Array] The list items
61
+ ##
36
62
  def options_list(matches)
37
63
  counter = 1
38
64
  puts
@@ -43,6 +69,15 @@ module Howzit
43
69
  puts
44
70
  end
45
71
 
72
+ ##
73
+ ## Choose from a list of items. If fzf is available,
74
+ ## uses that, otherwise generates its own list of
75
+ ## options and accepts a numeric response
76
+ ##
77
+ ## @param matches [Array] The options list
78
+ ##
79
+ ## @return [Array] the selected results
80
+ ##
46
81
  def choose(matches)
47
82
  if Util.command_exist?('fzf')
48
83
  settings = [
@@ -80,7 +115,7 @@ module Howzit
80
115
  end
81
116
  line = line == '' ? 1 : line.to_i
82
117
 
83
- return matches[line - 1] if line.positive? && line <= matches.length
118
+ return [matches[line - 1]] if line.positive? && line <= matches.length
84
119
 
85
120
  puts 'Out of range'
86
121
  options_list(matches)
@@ -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
@@ -5,11 +5,14 @@ module Howzit
5
5
  class Task
6
6
  attr_reader :type, :title, :action, :parent, :optional, :default
7
7
 
8
- def initialize(type, title, action, parent = nil, optional: false, default: true)
9
- @type = type
10
- @title = title
11
- @action = action.render_arguments
12
- @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
13
16
  @optional = optional
14
17
  @default = default
15
18
  end
@@ -23,7 +26,7 @@ module Howzit
23
26
  end
24
27
 
25
28
  def to_list
26
- " * #{@type}: #{@title.gsub(/\\n/, '\​n')}"
29
+ " * #{@type}: #{@title.preserve_escapes}"
27
30
  end
28
31
  end
29
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.10'
6
+ VERSION = '2.0.13'
7
7
  end
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ bundle install
4
+ rake test
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.10
4
+ version: 2.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
@@ -220,6 +220,20 @@ dependencies:
220
220
  - - "~>"
221
221
  - !ruby/object:Gem::Version
222
222
  version: '1.3'
223
+ - !ruby/object:Gem::Dependency
224
+ name: tty-spinner
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: '0.9'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: '0.9'
223
237
  - !ruby/object:Gem::Dependency
224
238
  name: mdless
225
239
  requirement: !ruby/object:Gem::Requirement
@@ -289,6 +303,12 @@ files:
289
303
  - README.md
290
304
  - Rakefile
291
305
  - bin/howzit
306
+ - docker/Dockerfile
307
+ - docker/Dockerfile-2.6
308
+ - docker/Dockerfile-2.7
309
+ - docker/Dockerfile-3.0
310
+ - docker/bash_profile
311
+ - docker/inputrc
292
312
  - fish/completions/bld.fish
293
313
  - fish/completions/fisher.fish
294
314
  - fish/completions/howzit.fish
@@ -307,9 +327,9 @@ files:
307
327
  - lib/howzit/topic.rb
308
328
  - lib/howzit/util.rb
309
329
  - lib/howzit/version.rb
330
+ - scripts/runtests.sh
310
331
  - spec/.rubocop.yml
311
332
  - spec/buildnote_spec.rb
312
- - spec/buildnotes.md.bak
313
333
  - spec/cli_spec.rb
314
334
  - spec/ruby_gem_spec.rb
315
335
  - spec/spec_helper.rb
@@ -343,7 +363,6 @@ summary: Provides a way to access Markdown project notes by topic with query cap
343
363
  test_files:
344
364
  - spec/.rubocop.yml
345
365
  - spec/buildnote_spec.rb
346
- - spec/buildnotes.md.bak
347
366
  - spec/cli_spec.rb
348
367
  - spec/ruby_gem_spec.rb
349
368
  - spec/spec_helper.rb
@@ -1,22 +0,0 @@
1
- # spec
2
-
3
-
4
-
5
- ## File Structure
6
-
7
- Where are the main editable files? Is there a dist/build folder that should be ignored?
8
-
9
- ## Build
10
-
11
- What build system/parameters does this use?
12
-
13
- @run(./build command)
14
-
15
- ## Deploy
16
-
17
- What are the procedures/commands to deploy this project?
18
-
19
- ## Other
20
-
21
- Version control notes, additional gulp/rake/make/etc tasks...
22
-