howzit 2.1.28 → 2.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/Rakefile +4 -3
- data/bin/howzit +65 -65
- data/howzit.gemspec +1 -1
- data/lib/howzit/buildnote.rb +4 -8
- data/lib/howzit/colors.rb +50 -22
- data/lib/howzit/condition_evaluator.rb +307 -0
- data/lib/howzit/conditional_content.rb +96 -0
- data/lib/howzit/config.rb +15 -3
- data/lib/howzit/console_logger.rb +14 -2
- data/lib/howzit/prompt.rb +20 -12
- data/lib/howzit/run_report.rb +1 -1
- data/lib/howzit/script_comm.rb +105 -0
- data/lib/howzit/stringutils.rb +4 -4
- data/lib/howzit/task.rb +11 -2
- data/lib/howzit/topic.rb +29 -9
- data/lib/howzit/util.rb +11 -3
- data/lib/howzit/version.rb +1 -1
- data/lib/howzit.rb +3 -0
- data/spec/condition_evaluator_spec.rb +261 -0
- data/spec/conditional_blocks_integration_spec.rb +159 -0
- data/spec/conditional_content_spec.rb +296 -0
- data/spec/script_comm_spec.rb +303 -0
- data/spec/spec_helper.rb +3 -1
- metadata +14 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c70619dce51a18faa84ba9516cf1e48bb2b3028f88e22397a8690e75ae65fff
|
|
4
|
+
data.tar.gz: 5f28a55772ca45c4f7a755b545c7fbf532460fee20533ff0714a304ea87d6799
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 73247bd6dfbc7dc0b777f88825673dc1fa36575582d29b57c8d3a2a1996d985ad01e72917b8ac3e6626119e9a1182cddad2a166850d9e1cb5bb7aa01e68ffb93
|
|
7
|
+
data.tar.gz: 53aa254ba30a35a78880dcb7e9431d354ee4304e8244b290fb6d046dc29c60eb2becb023565ad4072e17c6af69ed5ec6faf062a15a407d87a293d7a67a14ad84
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,50 @@
|
|
|
1
|
+
### 2.1.29
|
|
2
|
+
|
|
3
|
+
2026-01-01 06:55
|
|
4
|
+
|
|
5
|
+
#### CHANGED
|
|
6
|
+
|
|
7
|
+
- Updated rubocop from version 0.93.1 to 1.82.1 for Ruby 3.4.4 compatibility
|
|
8
|
+
- Updated .rubocop.yml to use plugins syntax instead of require for rubocop extensions
|
|
9
|
+
- Updated .rubocop.yml to inherit from .rubocop_todo.yml and removed Max settings that were overriding todo file limits
|
|
10
|
+
- Added Security/YAMLLoad exception to .rubocop.yml to allow YAML.load usage (intentionally not using safe_load)
|
|
11
|
+
- Added Layout/LineLength exceptions for files with intentionally long lines (bin/howzit, task.rb, util.rb, stringutils.rb, buildnote.rb)
|
|
12
|
+
|
|
13
|
+
#### NEW
|
|
14
|
+
|
|
15
|
+
- Scripts can now communicate back to Howzit by writing to a communication file specified in HOWZIT_COMM_FILE environment variable, allowing scripts to send log messages (LOG:level:message) and set variables (VAR:KEY=value) that are available for subsequent tasks and conditional logic
|
|
16
|
+
- Added ScriptComm module to handle bidirectional communication between scripts and Howzit
|
|
17
|
+
- Added @if and @unless conditional blocks that allow content and tasks to be conditionally included or excluded based on evaluated conditions, with support for nested blocks
|
|
18
|
+
- Conditional blocks support string comparisons (==, =~ /regex/, *= contains, ^= starts with, $= ends with) and numeric comparisons (==, !=, >, >=, <, <=)
|
|
19
|
+
- Conditions can test against metadata keys, environment variables, positional arguments ($1, $2, etc.), named arguments, and script-set variables
|
|
20
|
+
- Added special condition checks: git dirty/clean, file exists <path>, dir exists <path>, topic exists <name>, and cwd/working directory
|
|
21
|
+
- Conditions support negation with 'not' or '!' prefix
|
|
22
|
+
- Added @elsif directive for alternative conditions in @if/@unless blocks, allowing multiple conditional branches
|
|
23
|
+
- Added @else directive for fallback branches in conditional blocks when all previous conditions are false
|
|
24
|
+
- Conditional blocks now support chaining multiple @elsif statements between @if/@unless and @else
|
|
25
|
+
- @elsif and @else work correctly with nested conditional blocks
|
|
26
|
+
- Added **= fuzzy match operator for string comparisons that matches if search string characters appear in order within the target string (e.g., "fluffy" **= "ffy" matches)
|
|
27
|
+
- Added file contents condition that reads file contents and performs string comparisons using any comparison operator (e.g., file contents VERSION.txt ^= 0.)
|
|
28
|
+
- File contents condition supports file paths as variables from metadata, named arguments, or environment variables
|
|
29
|
+
|
|
30
|
+
#### IMPROVED
|
|
31
|
+
|
|
32
|
+
- Auto-corrected rubocop style offenses including string literals, redundant self, parentheses, and other correctable issues
|
|
33
|
+
- Fixed Lint/Void issue in buildnote.rb by simplifying conditional logic
|
|
34
|
+
- Cwd and working directory can now be used with string comparison operators (==, =~, *=, ^=, $=) to check the current directory path
|
|
35
|
+
- Conditions now support ${var} syntax in addition to var for consistency with variable substitution syntax
|
|
36
|
+
- String comparison operators (*=, ^=, $=) now treat unquoted strings that aren't found as variables as literal strings, allowing simpler syntax like template *= gem instead of template *= "gem"
|
|
37
|
+
|
|
38
|
+
#### FIXED
|
|
39
|
+
|
|
40
|
+
- Resolved NameError for 'white' color method by generating escape codes directly from configured_colors hash instead of calling dynamically generated methods
|
|
41
|
+
- Fixed infinite recursion in ConsoleLogger by using $stderr.puts directly instead of calling warn method recursively
|
|
42
|
+
- Color template method now properly respects coloring? setting and returns empty strings when coloring is disabled
|
|
43
|
+
- Resolved test failures caused by Howzit.buildnote caching stale instances by resetting @buildnote in spec_helper before each test
|
|
44
|
+
- Fixed bug where @end statements failed to close conditional blocks when conditions evaluated to false, preventing subsequent conditional blocks from working correctly
|
|
45
|
+
- Fixed issue where named arguments from topic titles were not available when evaluating conditions in conditional blocks
|
|
46
|
+
- Suppressed EPIPE errors that occur when writing to stdout/stderr after pipes are closed, preventing error messages from appearing in terminal output
|
|
47
|
+
|
|
1
48
|
### 2.1.28
|
|
2
49
|
|
|
3
50
|
2025-12-31 10:21
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# require 'bump/tasks'
|
|
4
|
+
require 'English'
|
|
4
5
|
require 'bundler/gem_tasks'
|
|
5
6
|
require 'rspec/core/rake_task'
|
|
6
7
|
require 'rubocop/rake_task'
|
|
@@ -13,7 +14,7 @@ module TempFixForRakeLastComment
|
|
|
13
14
|
last_description
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
|
-
Rake::Application.
|
|
17
|
+
Rake::Application.include TempFixForRakeLastComment
|
|
17
18
|
|
|
18
19
|
Rake::RDocTask.new do |rd|
|
|
19
20
|
rd.main = 'README.rdoc'
|
|
@@ -77,7 +78,7 @@ task :dockertest, :version, :login do |_, args|
|
|
|
77
78
|
file = 'docker/Dockerfile'
|
|
78
79
|
end
|
|
79
80
|
|
|
80
|
-
d_spinner = TTY::Spinner.new(
|
|
81
|
+
d_spinner = TTY::Spinner.new('[:spinner] Setting up Docker', hide_cursor: true, format: :dots)
|
|
81
82
|
d_spinner.auto_spin
|
|
82
83
|
`docker build . --file #{file} -t #{img} &> /dev/null`
|
|
83
84
|
d_spinner.success
|
|
@@ -90,7 +91,7 @@ task :dockertest, :version, :login do |_, args|
|
|
|
90
91
|
spinner.auto_spin
|
|
91
92
|
res = `docker run --rm -v #{File.dirname(__FILE__)}:/howzit -it #{img}`
|
|
92
93
|
commit = `bash -c "docker commit $(docker ps -a|grep #{img}|awk '{print $1}'|head -n 1) #{img}"`.strip
|
|
93
|
-
if
|
|
94
|
+
if $CHILD_STATUS.exitstatus.zero?
|
|
94
95
|
spinner.success
|
|
95
96
|
else
|
|
96
97
|
spinner.error
|
data/bin/howzit
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
$LOAD_PATH.unshift File.join(__dir__,
|
|
5
|
-
require
|
|
4
|
+
$LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
|
|
5
|
+
require 'howzit'
|
|
6
6
|
|
|
7
7
|
Howzit::Color.coloring = $stdout.isatty
|
|
8
8
|
|
|
@@ -13,127 +13,127 @@ Howzit.named_arguments = {}
|
|
|
13
13
|
|
|
14
14
|
OptionParser.new do |opts|
|
|
15
15
|
opts.banner = "Usage: #{File.basename(__FILE__)} [OPTIONS] [TOPIC]"
|
|
16
|
-
opts.separator
|
|
16
|
+
opts.separator ''
|
|
17
17
|
opts.separator "Show build notes for the current project (buildnotes.md).
|
|
18
18
|
Include a topic name to see just that topic, or no argument to display all."
|
|
19
|
-
opts.separator
|
|
20
|
-
opts.separator
|
|
19
|
+
opts.separator ''
|
|
20
|
+
opts.separator 'Options:'
|
|
21
21
|
|
|
22
22
|
opts.separator " Behavior:\n\n" #=================================================================== BEHAVIOR
|
|
23
23
|
|
|
24
|
-
opts.on(
|
|
24
|
+
opts.on('--ask', 'Request confirmation for all tasks when running a topic') { Howzit.options[:ask] = true }
|
|
25
25
|
|
|
26
|
-
opts.on(
|
|
27
|
-
raise
|
|
26
|
+
opts.on('--default', 'Answer all prompts with default response') do
|
|
27
|
+
raise '--default cannot be used with --yes or --no' if Howzit.options[:yes] || Howzit.options[:no]
|
|
28
28
|
|
|
29
29
|
Howzit.options[:default] = true
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
opts.on(
|
|
32
|
+
opts.on('-f', '--force', 'Continue executing after an error') { Howzit.options[:force] = true }
|
|
33
33
|
|
|
34
|
-
opts.on(
|
|
35
|
-
|
|
34
|
+
opts.on('-m', '--matching TYPE', MATCHING_OPTIONS,
|
|
35
|
+
'Topics matching type', "(#{MATCHING_OPTIONS.join(', ').sub(/#{Howzit.options[:matching]}/, "*#{Howzit.options[:matching]}")})") do |c|
|
|
36
36
|
Howzit.options[:matching] = c
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
opts.on(
|
|
40
|
-
|
|
39
|
+
opts.on('--multiple TYPE', MULTIPLE_OPTIONS,
|
|
40
|
+
'Multiple result handling', "(#{MULTIPLE_OPTIONS.join(', ').sub(/#{Howzit.options[:multiple_matches]}/, "*#{Howzit.options[:multiple_matches]}")}, default choose)") do |c|
|
|
41
41
|
Howzit.options[:multiple_matches] = c.to_sym
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
opts.on(
|
|
44
|
+
opts.on('-u', '--[no-]upstream', 'Traverse up parent directories for additional build notes') do |p|
|
|
45
45
|
Howzit.options[:include_upstream] = p
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
opts.on(
|
|
49
|
-
raise
|
|
48
|
+
opts.on('-y', '--yes', 'Answer yes to all prompts') do
|
|
49
|
+
raise '--default cannot be used with --yes' if Howzit.options[:default]
|
|
50
50
|
|
|
51
51
|
Howzit.options[:yes] = true
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
opts.on(
|
|
55
|
-
raise
|
|
54
|
+
opts.on('-n', '--no', 'Answer no to all prompts') do
|
|
55
|
+
raise '--default cannot be used with --no' if Howzit.options[:default]
|
|
56
56
|
|
|
57
57
|
Howzit.options[:no] = true
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
opts.separator "\n Listing:\n\n" #=================================================================== LISTING
|
|
61
61
|
|
|
62
|
-
opts.on(
|
|
62
|
+
opts.on('-L', '--list-completions', 'List topics (completion-compatible)') do
|
|
63
63
|
Howzit.options[:list_topics] = true
|
|
64
64
|
Howzit.options[:list_topic_titles] = true
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
opts.on(
|
|
67
|
+
opts.on('-l', '--list', 'List available topics') do
|
|
68
68
|
Howzit.options[:list_topics] = true
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
opts.on(
|
|
71
|
+
opts.on('-R', '--list-runnable [PATTERN]', 'List topics containing @ directives (verbose)') do |pat|
|
|
72
72
|
Howzit.options[:for_topic] = pat
|
|
73
73
|
Howzit.options[:list_runnable] = true
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
opts.on(
|
|
76
|
+
opts.on('-T', '--task-list', 'List topics containing @ directives (completion-compatible)') do
|
|
77
77
|
Howzit.options[:list_runnable] = true
|
|
78
78
|
Howzit.options[:list_runnable_titles] = true
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
opts.on(
|
|
81
|
+
opts.on('--templates', 'List available templates') do
|
|
82
82
|
out = []
|
|
83
83
|
Dir.chdir(Howzit.config.template_folder)
|
|
84
|
-
Dir.glob(
|
|
85
|
-
template = File.basename(file,
|
|
84
|
+
Dir.glob('*.md').each do |file|
|
|
85
|
+
template = File.basename(file, '.md')
|
|
86
86
|
out.push(Howzit::Color.template("{Mk}template:{Yk}#{template}{x}"))
|
|
87
|
-
out.push(Howzit::Color.template(
|
|
87
|
+
out.push(Howzit::Color.template('{bk}[{bl}tasks{bk}]──────────────────────────────────────┐{x}'))
|
|
88
88
|
metadata = file.extract_metadata
|
|
89
89
|
topics = Howzit::BuildNote.new(file: file).topics
|
|
90
90
|
topics.each do |topic|
|
|
91
|
-
out.push(Howzit::Color.template(" {bk}│{bw}-{x} {bcK}#{template}:#{topic.title.sub(/^.*?:/,
|
|
91
|
+
out.push(Howzit::Color.template(" {bk}│{bw}-{x} {bcK}#{template}:#{topic.title.sub(/^.*?:/, '')}{x}"))
|
|
92
92
|
end
|
|
93
93
|
unless metadata.empty?
|
|
94
94
|
meta = []
|
|
95
|
-
meta << metadata[
|
|
96
|
-
meta << metadata[
|
|
97
|
-
out.push(Howzit::Color.template(
|
|
98
|
-
out.push(Howzit::Color.template(" {bk}│ {xw}#{meta.join(
|
|
95
|
+
meta << metadata['required'].split(/\s*,\s*/).map { |m| "*{bw}#{m}{xw}" } if metadata.key?('required')
|
|
96
|
+
meta << metadata['optional'].split(/\s*,\s*/).map(&:to_s) if metadata.key?('optional')
|
|
97
|
+
out.push(Howzit::Color.template('{bk}[{bl}meta{bk}]───────────────────────────────────────┤{x}'))
|
|
98
|
+
out.push(Howzit::Color.template(" {bk}│ {xw}#{meta.join(', ')}{x}"))
|
|
99
99
|
end
|
|
100
|
-
out.push(Howzit::Color.template(
|
|
100
|
+
out.push(Howzit::Color.template(' {bk}└───────────────────────────────────────────┘{x}'))
|
|
101
101
|
end
|
|
102
102
|
Howzit::Util.page out.join("\n")
|
|
103
103
|
Process.exit 0
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
opts.on(
|
|
106
|
+
opts.on('--templates-c', 'List available templates in a format for completion') do
|
|
107
107
|
out = []
|
|
108
108
|
Dir.chdir(Howzit.config.template_folder)
|
|
109
|
-
Dir.glob(
|
|
110
|
-
template = File.basename(file,
|
|
109
|
+
Dir.glob('*.md').each do |file|
|
|
110
|
+
template = File.basename(file, '.md')
|
|
111
111
|
out.push(template)
|
|
112
112
|
end
|
|
113
113
|
puts out.join("\n")
|
|
114
114
|
Process.exit 0
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
opts.on(
|
|
117
|
+
opts.on('--title-only', 'Output title only') do
|
|
118
118
|
Howzit.options[:output_title] = true
|
|
119
119
|
Howzit.options[:title_only] = true
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
opts.separator("\n Commands:\n\n") #=================================================================== COMMANDS
|
|
123
123
|
|
|
124
|
-
opts.on(
|
|
124
|
+
opts.on('-c', '--create', 'Create a skeleton build note in the current working directory') do
|
|
125
125
|
Howzit.buildnote.create_note
|
|
126
126
|
Process.exit 0
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
opts.on(
|
|
129
|
+
opts.on('--config-get [KEY]', 'Display the configuration settings or setting for a specific key') do |k|
|
|
130
130
|
if k.nil?
|
|
131
131
|
Howzit::Config::DEFAULTS.sort_by { |key, _| key }.each do |key, _|
|
|
132
132
|
print "#{key}: "
|
|
133
133
|
p Howzit.options[key]
|
|
134
134
|
end
|
|
135
135
|
else
|
|
136
|
-
k.sub!(/^:/,
|
|
136
|
+
k.sub!(/^:/, '')
|
|
137
137
|
if Howzit.options.key?(k.to_sym)
|
|
138
138
|
puts Howzit.options[k.to_sym]
|
|
139
139
|
else
|
|
@@ -143,12 +143,12 @@ OptionParser.new do |opts|
|
|
|
143
143
|
Process.exit 0
|
|
144
144
|
end
|
|
145
145
|
|
|
146
|
-
opts.on(
|
|
147
|
-
raise
|
|
146
|
+
opts.on('--config-set KEY=VALUE', 'Set a config value (must be a valid key)') do |key|
|
|
147
|
+
raise 'Argument must be KEY=VALUE' unless key =~ /\S=\S/
|
|
148
148
|
|
|
149
149
|
parts = key.split(/=/)
|
|
150
|
-
k = parts.shift.sub(/^:/,
|
|
151
|
-
v = parts.join(
|
|
150
|
+
k = parts.shift.sub(/^:/, '')
|
|
151
|
+
v = parts.join(' ')
|
|
152
152
|
|
|
153
153
|
if Howzit.options.key?(k.to_sym)
|
|
154
154
|
Howzit.options[k.to_sym] = v.to_config_value(Howzit.options[k.to_sym])
|
|
@@ -160,103 +160,103 @@ OptionParser.new do |opts|
|
|
|
160
160
|
end
|
|
161
161
|
|
|
162
162
|
desc = %(Edit buildnotes file in current working directory using default editor)
|
|
163
|
-
opts.on(
|
|
163
|
+
opts.on('-e', '--edit', desc) do
|
|
164
164
|
Howzit.buildnote.edit
|
|
165
165
|
Process.exit 0
|
|
166
166
|
end
|
|
167
167
|
|
|
168
|
-
opts.on(
|
|
168
|
+
opts.on('--edit-config', 'Edit configuration file using default editor') do
|
|
169
169
|
Howzit.config.editor
|
|
170
170
|
Process.exit 0
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
-
opts.on(
|
|
173
|
+
opts.on('--edit-template NAME', 'Create or edit a template') do |template|
|
|
174
174
|
Howzit.buildnote.edit_template(template)
|
|
175
175
|
Process.exit 0
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
-
opts.on(
|
|
178
|
+
opts.on('--grep PATTERN', 'Display sections matching a search pattern') do |pat|
|
|
179
179
|
Howzit.options[:grep] = pat
|
|
180
180
|
end
|
|
181
181
|
|
|
182
|
-
opts.on(
|
|
182
|
+
opts.on('--hook', 'Copy a link to the build note file, ready for pasting into Hook.app or other notes') do
|
|
183
183
|
Howzit.buildnote.hook
|
|
184
184
|
Process.exit 0
|
|
185
185
|
end
|
|
186
186
|
|
|
187
|
-
opts.on(
|
|
187
|
+
opts.on('-r', '--run', 'Execute @run, @open, and/or @copy commands for given topic') do
|
|
188
188
|
Howzit.options[:run] = true
|
|
189
189
|
end
|
|
190
190
|
|
|
191
|
-
opts.on(
|
|
191
|
+
opts.on('-s', '--select', 'Select topic from menu') do
|
|
192
192
|
Howzit.options[:choose] = true
|
|
193
193
|
end
|
|
194
194
|
|
|
195
195
|
opts.separator("\n Formatting:\n\n") #=================================================================== FORMATTING
|
|
196
196
|
|
|
197
|
-
opts.on(
|
|
197
|
+
opts.on('--[no-]color', 'Colorize output (default on)') do |c|
|
|
198
198
|
Howzit.options[:color] = c
|
|
199
199
|
Howzit.options[:highlight] = false unless c
|
|
200
200
|
end
|
|
201
201
|
|
|
202
|
-
opts.on(
|
|
203
|
-
"Formatting style for topic titles (#{HEADER_FORMAT_OPTIONS.join(
|
|
202
|
+
opts.on('--header-format TYPE', HEADER_FORMAT_OPTIONS,
|
|
203
|
+
"Formatting style for topic titles (#{HEADER_FORMAT_OPTIONS.join(', ')})") do |t|
|
|
204
204
|
Howzit.options[:header_format] = t
|
|
205
205
|
end
|
|
206
206
|
|
|
207
|
-
opts.on(
|
|
207
|
+
opts.on('--[no-]md-highlight', 'Highlight Markdown syntax (default on), requires mdless or mdcat') do |m|
|
|
208
208
|
Howzit.options[:highlight] = Howzit.options[:color] ? m : false
|
|
209
209
|
end
|
|
210
210
|
|
|
211
|
-
opts.on(
|
|
211
|
+
opts.on('--[no-]pager', 'Paginate output (default on)') do |p|
|
|
212
212
|
Howzit.options[:paginate] = p
|
|
213
213
|
end
|
|
214
214
|
|
|
215
|
-
opts.on(
|
|
215
|
+
opts.on('--show-code', 'Display the content of fenced run blocks') do
|
|
216
216
|
Howzit.options[:show_all_code] = true
|
|
217
217
|
end
|
|
218
218
|
|
|
219
|
-
opts.on(
|
|
219
|
+
opts.on('-t', '--title', 'Output title with build notes') do
|
|
220
220
|
Howzit.options[:output_title] = true
|
|
221
221
|
end
|
|
222
222
|
|
|
223
|
-
opts.on(
|
|
223
|
+
opts.on('-w', '--wrap COLUMNS', 'Wrap to specified width (default 80, 0 to disable)') do |w|
|
|
224
224
|
Howzit.options[:wrap] = w.to_i
|
|
225
225
|
end
|
|
226
226
|
|
|
227
227
|
opts.separator("\n Logging:\n\n") #=================================================================== LOGGING
|
|
228
228
|
|
|
229
|
-
opts.on(
|
|
229
|
+
opts.on('-d', '--debug', 'Show debug messages (and all messages)') do
|
|
230
230
|
Howzit.options[:log_level] = 0
|
|
231
231
|
Howzit.console.reset_level
|
|
232
232
|
end
|
|
233
233
|
|
|
234
|
-
opts.on(
|
|
234
|
+
opts.on('-q', '--quiet', 'Silence info message') do
|
|
235
235
|
Howzit.options[:log_level] = 4
|
|
236
236
|
Howzit.console.reset_level
|
|
237
237
|
end
|
|
238
238
|
|
|
239
|
-
opts.on(
|
|
239
|
+
opts.on('--verbose', 'Show all messages') do
|
|
240
240
|
Howzit.options[:log_level] = 1
|
|
241
241
|
Howzit.console.reset_level
|
|
242
242
|
end
|
|
243
243
|
|
|
244
244
|
opts.separator("\n Misc:\n\n") #=================================================================== MISC
|
|
245
245
|
|
|
246
|
-
opts.on(
|
|
246
|
+
opts.on('-h', '--help', 'Display this screen') do
|
|
247
247
|
Howzit::Util.page opts.to_s
|
|
248
248
|
Process.exit 0
|
|
249
249
|
end
|
|
250
250
|
|
|
251
|
-
opts.on(
|
|
251
|
+
opts.on('-v', '--version', 'Display version number') do
|
|
252
252
|
puts "#{File.basename(__FILE__)} v#{Howzit::VERSION}"
|
|
253
253
|
Process.exit 0
|
|
254
254
|
end
|
|
255
255
|
end.parse!(args)
|
|
256
256
|
|
|
257
|
-
trap(
|
|
257
|
+
trap('INT') do
|
|
258
258
|
puts
|
|
259
|
-
puts
|
|
259
|
+
puts 'Cancelled'
|
|
260
260
|
Process.exit 0
|
|
261
261
|
end
|
|
262
262
|
|
data/howzit.gemspec
CHANGED
|
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
|
|
36
36
|
spec.add_development_dependency 'cli-test', '~> 1.0'
|
|
37
37
|
spec.add_development_dependency 'rspec', '~> 3.13'
|
|
38
|
-
spec.add_development_dependency 'rubocop', '~>
|
|
38
|
+
spec.add_development_dependency 'rubocop', '~> 1.60'
|
|
39
39
|
spec.add_development_dependency 'simplecov', '~> 0.9'
|
|
40
40
|
# spec.add_development_dependency 'codecov', '~> 0.1'
|
|
41
41
|
spec.add_development_dependency 'fuubar', '~> 2.0'
|
data/lib/howzit/buildnote.rb
CHANGED
|
@@ -290,11 +290,7 @@ module Howzit
|
|
|
290
290
|
|
|
291
291
|
title = File.basename(Dir.pwd)
|
|
292
292
|
# prompt = TTY::Prompt.new
|
|
293
|
-
|
|
294
|
-
title
|
|
295
|
-
else
|
|
296
|
-
title = Prompt.get_line('{bw}Project name{x}'.c, default: title)
|
|
297
|
-
end
|
|
293
|
+
title = Prompt.get_line('{bw}Project name{x}'.c, default: title) unless default
|
|
298
294
|
summary = ''
|
|
299
295
|
summary = Prompt.get_line('{bw}Project summary{x}'.c) unless default
|
|
300
296
|
|
|
@@ -670,7 +666,7 @@ module Howzit
|
|
|
670
666
|
## @return [String] file path
|
|
671
667
|
##
|
|
672
668
|
def glob_note
|
|
673
|
-
Dir.glob('*.{txt,md,markdown}').select(&:build_note?).
|
|
669
|
+
Dir.glob('*.{txt,md,markdown}').select(&:build_note?).min
|
|
674
670
|
end
|
|
675
671
|
|
|
676
672
|
##
|
|
@@ -784,7 +780,7 @@ module Howzit
|
|
|
784
780
|
title = "#{short_path}:#{title}"
|
|
785
781
|
end
|
|
786
782
|
|
|
787
|
-
topic = Topic.new(title, prefix + lines.join("\n").strip.render_template(@metadata))
|
|
783
|
+
topic = Topic.new(title, prefix + lines.join("\n").strip.render_template(@metadata), @metadata)
|
|
788
784
|
|
|
789
785
|
topics.push(topic)
|
|
790
786
|
end
|
|
@@ -1098,7 +1094,7 @@ module Howzit
|
|
|
1098
1094
|
when :first
|
|
1099
1095
|
[matches[0]]
|
|
1100
1096
|
when :best
|
|
1101
|
-
[matches.
|
|
1097
|
+
[matches.min_by { |a| [a.title.comp_distance(search_term), a.title.length] }]
|
|
1102
1098
|
when :all
|
|
1103
1099
|
matches
|
|
1104
1100
|
else
|
data/lib/howzit/colors.rb
CHANGED
|
@@ -281,11 +281,40 @@ module Howzit
|
|
|
281
281
|
end
|
|
282
282
|
end
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
284
|
+
# Build colors hash from configured_colors, generating escape codes directly
|
|
285
|
+
color_map = configured_colors.to_h
|
|
286
|
+
colors = if coloring?
|
|
287
|
+
{
|
|
288
|
+
w: "\e[#{color_map[:white]}m",
|
|
289
|
+
k: "\e[#{color_map[:black]}m",
|
|
290
|
+
g: "\e[#{color_map[:green]}m",
|
|
291
|
+
l: "\e[#{color_map[:blue]}m",
|
|
292
|
+
y: "\e[#{color_map[:yellow]}m",
|
|
293
|
+
c: "\e[#{color_map[:cyan]}m",
|
|
294
|
+
m: "\e[#{color_map[:magenta]}m",
|
|
295
|
+
r: "\e[#{color_map[:red]}m",
|
|
296
|
+
W: "\e[#{color_map[:bgwhite]}m",
|
|
297
|
+
K: "\e[#{color_map[:bgblack]}m",
|
|
298
|
+
G: "\e[#{color_map[:bggreen]}m",
|
|
299
|
+
L: "\e[#{color_map[:bgblue]}m",
|
|
300
|
+
Y: "\e[#{color_map[:bgyellow]}m",
|
|
301
|
+
C: "\e[#{color_map[:bgcyan]}m",
|
|
302
|
+
M: "\e[#{color_map[:bgmagenta]}m",
|
|
303
|
+
R: "\e[#{color_map[:bgred]}m",
|
|
304
|
+
d: "\e[#{color_map[:dark]}m",
|
|
305
|
+
b: "\e[#{color_map[:bold]}m",
|
|
306
|
+
u: "\e[#{color_map[:underline]}m",
|
|
307
|
+
i: "\e[#{color_map[:italic]}m",
|
|
308
|
+
x: "\e[#{color_map[:reset]}m"
|
|
309
|
+
}
|
|
310
|
+
else
|
|
311
|
+
# When coloring is disabled, return empty strings
|
|
312
|
+
{
|
|
313
|
+
w: '', k: '', g: '', l: '', y: '', c: '', m: '', r: '',
|
|
314
|
+
W: '', K: '', G: '', L: '', Y: '', C: '', M: '', R: '',
|
|
315
|
+
d: '', b: '', u: '', i: '', x: ''
|
|
316
|
+
}
|
|
317
|
+
end
|
|
289
318
|
|
|
290
319
|
result = fmt.empty? ? input : format(fmt, colors)
|
|
291
320
|
# Unescape braces and dollar signs that were escaped to prevent color code interpretation
|
|
@@ -295,24 +324,24 @@ module Howzit
|
|
|
295
324
|
|
|
296
325
|
# Dynamically generate methods for each color name. Each
|
|
297
326
|
# resulting method can be called with a string or a block.
|
|
298
|
-
configured_colors.each do |c, v|
|
|
327
|
+
Color.configured_colors.each do |c, v|
|
|
299
328
|
new_method = <<-EOSCRIPT
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
329
|
+
# Color string as #{c}
|
|
330
|
+
def #{c}(string = nil)
|
|
331
|
+
result = ''
|
|
332
|
+
result << "\e[#{v}m" if Howzit::Color.coloring?
|
|
333
|
+
if block_given?
|
|
334
|
+
result << yield
|
|
335
|
+
elsif string.respond_to?(:to_str)
|
|
336
|
+
result << string.to_str
|
|
337
|
+
elsif respond_to?(:to_str)
|
|
338
|
+
result << to_str
|
|
339
|
+
else
|
|
340
|
+
return result #only switch on
|
|
341
|
+
end
|
|
342
|
+
result << "\e[0m" if Howzit::Color.coloring?
|
|
343
|
+
result
|
|
312
344
|
end
|
|
313
|
-
result << "\e[0m" if Howzit::Color.coloring?
|
|
314
|
-
result
|
|
315
|
-
end
|
|
316
345
|
EOSCRIPT
|
|
317
346
|
|
|
318
347
|
module_eval(new_method)
|
|
@@ -383,6 +412,5 @@ module Howzit
|
|
|
383
412
|
def attributes
|
|
384
413
|
ATTRIBUTE_NAMES
|
|
385
414
|
end
|
|
386
|
-
extend self
|
|
387
415
|
end
|
|
388
416
|
end
|