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 +4 -4
- data/.rubocop.yml +1 -0
- data/.travis.yml +2 -2
- data/CHANGELOG.md +24 -0
- data/Rakefile +41 -0
- data/bin/howzit +1 -1
- data/docker/Dockerfile +11 -0
- data/docker/Dockerfile-2.6 +11 -0
- data/docker/Dockerfile-2.7 +11 -0
- data/docker/Dockerfile-3.0 +11 -0
- data/docker/bash_profile +13 -0
- data/docker/inputrc +57 -0
- data/fish/completions/howzit.fish +34 -2
- data/howzit.gemspec +1 -0
- data/lib/howzit/buildnote.rb +4 -27
- data/lib/howzit/hash.rb +23 -2
- data/lib/howzit/prompt.rb +37 -2
- data/lib/howzit/stringutils.rb +130 -3
- data/lib/howzit/task.rb +9 -6
- data/lib/howzit/topic.rb +59 -8
- data/lib/howzit/util.rb +25 -0
- data/lib/howzit/version.rb +1 -1
- data/scripts/runtests.sh +4 -0
- data/spec/task_spec.rb +6 -1
- metadata +22 -3
- data/spec/buildnotes.md.bak +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e269532605e044c35e2a0ebe322fe51ba5199d690a57385a358a3bad4fc2921f
|
4
|
+
data.tar.gz: 4ca045a0c3c2d1627b04a47363beb8e2de6718f5c708e1f4bf96285af96e09d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 803b06d4a85632357eb1e61a898f88c39971df388107a62f67479e34788346f1824f78a3b3473cf5ee45dc445a494e7a144590d5df33ffd1b73d2114ba19049d
|
7
|
+
data.tar.gz: 51c6ec7213c4b7c531e53c32140dc485d897f40ee79d242ee8ec446804ad0edac8a9bac61d3b68189bf60884a3dbee28fe6d5f5f3040dae23ec8cb7ddb24903c
|
data/.rubocop.yml
CHANGED
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: "
|
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
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"]
|
data/docker/bash_profile
ADDED
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 -
|
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'
|
data/lib/howzit/buildnote.rb
CHANGED
@@ -120,7 +120,7 @@ module Howzit
|
|
120
120
|
|
121
121
|
##
|
122
122
|
## Return a formatted list of topics containing
|
123
|
-
##
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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)
|
data/lib/howzit/stringutils.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@
|
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.
|
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
|
-
|
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.
|
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(:
|
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(:
|
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(:
|
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(:
|
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(:
|
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?
|
data/lib/howzit/version.rb
CHANGED
data/scripts/runtests.sh
ADDED
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)
|
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.
|
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
|
data/spec/buildnotes.md.bak
DELETED
@@ -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
|
-
|