howzit 2.1.47 → 2.1.49

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: 477bc94918f7906d52412423ee73992f2d255279d757f36d0feed85f74c1f454
4
- data.tar.gz: 926727bfe69e059367fa75d4b55b095786663487cdc8f311b13ee92dd44d15e0
3
+ metadata.gz: 91e3e382d6e58e8a3a50cb663de149af066ee02b80bafcdbf6db5d68c79426af
4
+ data.tar.gz: ebaf51a69ba374ba5fa64a548560cfa0b8e03f70b85a77de3a1f43aa94baf944
5
5
  SHA512:
6
- metadata.gz: 8f4c4228bc522c7608f77d0ab4e7f4f802753e71c7f37d2f41d9f81e01764a8b0b285aaed8bc5bad6a9ccaa0544d83007bde4c7aea7c0e41bc2fc834bb8304d7
7
- data.tar.gz: a24505c7b3f22f7d4bb52eb91372f44d0ef200285faf4006bb8a93588bdb63318063d26b5571026374f8f67b648678d0bd4edf4223c5561c39ad625ec2a08a69
6
+ metadata.gz: 96e353abbe3fec9eb5cce2c1fcbbdc45d425394594f394251dc2719937ba69a2acbf87e7d3ccae437baf25b33c400ef0ddf7c01cd42765cc4f39009968f703cf
7
+ data.tar.gz: 48c8b7253abbd0adfe88a0b5ccb1108684db73252c87823ef29aa59507feefd814bc689831585255e73624136f55cd39ee0797ab84666c49dc3a56107b76fa31
data/CHANGELOG.md CHANGED
@@ -1,3 +1,34 @@
1
+ ### 2.1.49
2
+
3
+ 2026-10-21 05:15
4
+
5
+ #### CHANGED
6
+
7
+ - **Markdown highlighting** tries `apex` first when `:highlighter:` is `auto`, then mdcat, then mdless. mdless is still installed with the gem
8
+ - **Directives inside a code fence** are shown as code instead of being turned into tasks
9
+
10
+ #### FIXED
11
+
12
+ - **Apex output** uses `-t terminal256 --no-paginate`, including when `:highlighter:` is set to `apex` alone, so topics render as terminal color instead of HTML
13
+ - **Placeholders inside fenced code** are left as written, so a syntax highlighter such as Pygments does not print howzit's color codes as text like `[1m`
14
+
15
+ ### 2.1.48
16
+
17
+ 2026-10-09 07:20
18
+
19
+ #### CHANGED
20
+
21
+ - **@before blocks** from a topic, its subtopics, and any included topics are shown together in one box before anything runs, with a single confirmation prompt instead of one prompt per topic
22
+ - **@after blocks** from a topic, its subtopics, and any included topics are shown together in one box at the end of the run instead of after each topic finishes
23
+
24
+ #### IMPROVED
25
+
26
+ - **Collected notes** appear in document order: the topic's own block, then included topics in @include order, then subtopics
27
+ - **@after notes from subtopics skipped after a failure** are still shown in the final box
28
+ - **Notes from included topics** render variables with the bracketed arguments passed via @include(Topic [args])
29
+ - **@before blocks** now render ${variables}, matching @after
30
+ - **Topics included more than once** only contribute their notes once
31
+
1
32
  ### 2.1.47
2
33
 
3
34
  2026-09-27 13:20
data/README.md CHANGED
@@ -37,7 +37,7 @@ Howzit is a tool that allows you to keep Markdown-formatted notes about a projec
37
37
  - Ruby 2.4+ (It probably works on older Rubys, but is untested prior to 2.4.1.)
38
38
  - Optional: if [`fzf`](https://github.com/junegunn/fzf) is available, it will be used for handling multiple choice selections
39
39
  - Optional: if [`bat`](https://github.com/sharkdp/bat) is available it will page with that
40
- - Optional: [`mdless`](https://github.com/ttscoff/mdless) or [`mdcat`](https://github.com/lunaryorn/mdcat) for formatting output
40
+ - Optional: [`apex`](https://github.com/ApexMarkdown/apex) is preferred for formatting output when it is installed. Otherwise howzit uses [`mdcat`](https://github.com/lunaryorn/mdcat) or [`mdless`](https://github.com/ttscoff/mdless). mdless is installed with the howzit gem.
41
41
 
42
42
  ### Installing
43
43
 
data/bin/howzit CHANGED
@@ -210,7 +210,7 @@ OptionParser.new do |opts|
210
210
  Howzit.options[:header_format] = t
211
211
  end
212
212
 
213
- opts.on('--[no-]md-highlight', 'Highlight Markdown syntax (default on), requires mdless or mdcat') do |m|
213
+ opts.on('--[no-]md-highlight', 'Highlight Markdown syntax (default on), prefers apex, then mdcat or mdless') do |m|
214
214
  Howzit.options[:highlight] = Howzit.options[:color] ? m : false
215
215
  end
216
216
 
data/lib/howzit/task.rb CHANGED
@@ -6,7 +6,7 @@ module Howzit
6
6
  # Task object
7
7
  class Task
8
8
  attr_reader :type, :title, :action, :arguments, :parent, :optional, :default, :last_status, :log_level, :source_file,
9
- :include_results
9
+ :include_results, :include_args
10
10
 
11
11
  ##
12
12
  ## Initialize a Task object
data/lib/howzit/topic.rb CHANGED
@@ -165,34 +165,58 @@ module Howzit
165
165
  ## @return [Array] output lines
166
166
  ##
167
167
  def run(nested: false, as_subtopic: false)
168
- @results = { total: 0, success: 0, errors: 0, message: ''.c }
169
- output = []
170
- cols = check_cols
171
-
172
- confirm_prereqs(cols) if !@prereqs.empty? && (all_tasks.any? || sequential?)
173
-
174
- if sequential?
175
- run_sequential(output: output)
176
- elsif @tasks.any?
177
- run_tasks(output)
178
- elsif all_tasks.empty? && !as_subtopic && !directives?
179
- Howzit.console.warn "{r}--run: No {br}@directive{xr} found in {bw}#{@title}{x}".c
180
- end
168
+ # The outermost run shows @before/@after notes for the whole tree
169
+ return run_topic(nested: nested, as_subtopic: as_subtopic) if Howzit.topic_run_active
181
170
 
182
- if halted?
183
- log_skipped_tasks(@subtopics.flat_map(&:all_tasks))
184
- else
185
- run_subtopics(output)
171
+ Howzit.topic_run_active = true
172
+ begin
173
+ cols = check_cols
174
+ confirm_prereqs(cols) if all_tasks.any? || sequential?
175
+ output = run_topic(nested: nested, as_subtopic: as_subtopic)
176
+ show_postreqs(cols)
177
+ output
178
+ ensure
179
+ Howzit.topic_run_active = false
186
180
  end
181
+ end
187
182
 
188
- if @results[:total].positive? || (all_tasks.any? && !sequential?)
189
- @results[:message] += results_message
190
- output.push(@results[:message]) if Howzit.options[:log_level] < 2 && !nested && !Howzit.options[:run]
191
- end
183
+ ##
184
+ ## @before notes for this topic, the topics it includes, and its
185
+ ## subtopics, in document order
186
+ ##
187
+ ## @return [Array] rendered notes
188
+ ##
189
+ def all_prereqs
190
+ collect_notes(:prereqs)
191
+ end
192
192
 
193
- show_postreqs(cols)
193
+ ##
194
+ ## @after notes for this topic, the topics it includes, and its
195
+ ## subtopics, in document order
196
+ ##
197
+ ## @return [Array] rendered notes
198
+ ##
199
+ def all_postreqs
200
+ collect_notes(:postreqs)
201
+ end
194
202
 
195
- output
203
+ ##
204
+ ## Gather notes recursively through @include tasks and subtopics
205
+ ##
206
+ ## @param kind [Symbol] :prereqs or :postreqs
207
+ ## @param args [Array] Bracketed arguments from an @include
208
+ ## @param seen [Array] Titles of topics already collected
209
+ ##
210
+ def collect_notes(kind, args = nil, seen = [])
211
+ return [] if seen.include?(@title)
212
+
213
+ seen << @title
214
+ notes = render_notes(kind == :prereqs ? @prereqs : @postreqs, args)
215
+ @tasks.select { |task| task.type == :include }.each do |task|
216
+ topic = Howzit.buildnote.find_topic(task.action.sub(/ *\[.*?\] *$/, ''))[0]
217
+ notes.concat(topic.collect_notes(kind, task.include_args, seen)) if topic
218
+ end
219
+ notes + @subtopics.flat_map { |sub| sub.collect_notes(kind, nil, seen) }
196
220
  end
197
221
 
198
222
  ##
@@ -215,8 +239,11 @@ module Howzit
215
239
  end
216
240
 
217
241
  def confirm_prereqs(cols)
242
+ prereqs = all_prereqs
243
+ return if prereqs.empty?
244
+
218
245
  begin
219
- puts TTY::Box.frame("{by}#{@prereqs.join("\n\n").wrap(cols - 4)}{x}".c, width: cols)
246
+ puts TTY::Box.frame("{by}#{prereqs.join("\n\n").wrap(cols - 4)}{x}".c, width: cols)
220
247
  rescue Errno::EPIPE
221
248
  # Pipe closed, ignore
222
249
  end
@@ -225,11 +252,11 @@ module Howzit
225
252
  end
226
253
 
227
254
  def show_postreqs(cols)
228
- return if @postreqs.empty?
255
+ postreqs = all_postreqs
256
+ return if postreqs.empty?
229
257
 
230
- # Apply variable substitution to postreqs content, then wrap each line individually to preserve structure
231
- postreqs_content = @postreqs.join("\n\n").render_arguments
232
- wrapped_content = postreqs_content.split(/\n/).map { |line| line.wrap(cols - 4) }.join("\n")
258
+ # Wrap each line individually to preserve structure
259
+ wrapped_content = postreqs.join("\n\n").split(/\n/).map { |line| line.wrap(cols - 4) }.join("\n")
233
260
  puts TTY::Box.frame("{bw}#{wrapped_content}{x}".c, width: cols)
234
261
  rescue Errno::EPIPE
235
262
  # Pipe closed, ignore
@@ -466,7 +493,18 @@ module Howzit
466
493
  topic.gsub!(/(?mix)^(`{3,})run([?!]*)\s*
467
494
  ([^\n]*)[\s\S]*?\n\1\s*$/, '@@@run\2 \3')
468
495
  end
496
+ in_fence = false
497
+ fence_char = nil
498
+ fence_len = 0
469
499
  topic.split(/\n/).each do |l|
500
+ # Fenced code is passed through unchanged. Howzit color codes inside a
501
+ # fence get mangled by the syntax highlighter Apex shells out to.
502
+ if in_fence
503
+ output.push(l)
504
+ in_fence = false if closing_fence?(l, fence_char, fence_len)
505
+ next
506
+ end
507
+
470
508
  case l
471
509
  when /@(before|after|prereq|end|if|unless)/
472
510
  next
@@ -477,12 +515,22 @@ module Howzit
477
515
  when /(?<fence>`{3,})run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
478
516
  desc = title_code_block(Regexp.last_match.named_captures.symbolize_keys)
479
517
  output.push("{bmK}\u{25B6} {bwK}#{desc}{x}\n```".c)
518
+ fence_char = '`'
519
+ fence_len = Regexp.last_match[:fence].length
520
+ in_fence = true
480
521
  when /@@@run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
481
522
  output.push("{bmK}\u{25B6} {bwK}#{title_code_block(Regexp.last_match.named_captures.symbolize_keys)}{x}".c)
482
523
  else
483
- l.wrap!(Howzit.options[:wrap]) if Howzit.options[:wrap].positive?
484
- # Highlight variable placeholders in content
485
- output.push(highlight_variables(l))
524
+ opened = opening_fence(l)
525
+ if opened
526
+ fence_char, fence_len = opened
527
+ in_fence = true
528
+ output.push(l)
529
+ else
530
+ l.wrap!(Howzit.options[:wrap]) if Howzit.options[:wrap].positive?
531
+ # Highlight variable placeholders in content
532
+ output.push(highlight_variables(l))
533
+ end
486
534
  end
487
535
  end
488
536
  Howzit.named_arguments = @named_args
@@ -593,6 +641,72 @@ module Howzit
593
641
 
594
642
  private
595
643
 
644
+ ##
645
+ ## A markdown opening fence (` ``` ` or `~~~`, up to three spaces of indent)
646
+ ##
647
+ ## @return [Array(String, Integer), nil] fence character and length
648
+ ##
649
+ def opening_fence(line)
650
+ match = line.match(/\A {0,3}(?<marker>`{3,}|~{3,})/)
651
+ return unless match
652
+
653
+ marker = match[:marker]
654
+ [marker[0], marker.length]
655
+ end
656
+
657
+ def closing_fence?(line, char, length)
658
+ line.match?(/\A {0,3}#{Regexp.escape(char)}{#{length},}[ \t]*\z/)
659
+ end
660
+
661
+ def run_topic(nested:, as_subtopic:)
662
+ @results = { total: 0, success: 0, errors: 0, message: ''.c }
663
+ output = []
664
+
665
+ if sequential?
666
+ run_sequential(output: output)
667
+ elsif @tasks.any?
668
+ run_tasks(output)
669
+ elsif all_tasks.empty? && !as_subtopic && !directives?
670
+ Howzit.console.warn "{r}--run: No {br}@directive{xr} found in {bw}#{@title}{x}".c
671
+ end
672
+
673
+ if halted?
674
+ log_skipped_tasks(@subtopics.flat_map(&:all_tasks))
675
+ else
676
+ run_subtopics(output)
677
+ end
678
+
679
+ if @results[:total].positive? || (all_tasks.any? && !sequential?)
680
+ @results[:message] += results_message
681
+ output.push(@results[:message]) if Howzit.options[:log_level] < 2 && !nested && !Howzit.options[:run]
682
+ end
683
+
684
+ output
685
+ end
686
+
687
+ ##
688
+ ## Render notes with this topic's variables, plus any bracketed
689
+ ## @include arguments bound to its title parameters
690
+ ##
691
+ def render_notes(notes, args)
692
+ return [] if notes.empty?
693
+
694
+ previous = Howzit.named_arguments
695
+ begin
696
+ Howzit.named_arguments = (previous || {}).merge(@named_args.compact).merge(bound_arguments(args))
697
+ notes.map(&:render_arguments)
698
+ ensure
699
+ Howzit.named_arguments = previous
700
+ end
701
+ end
702
+
703
+ def bound_arguments(args)
704
+ return {} if args.nil? || args.empty?
705
+
706
+ names = @arg_definitions.map { |definition| definition.split(':', 2).first }
707
+ names.zip(args).to_h.compact
708
+ end
709
+
596
710
  ##
597
711
  ## Collect all directives in the topic content
598
712
  ##
data/lib/howzit/util.rb CHANGED
@@ -50,31 +50,50 @@ module Howzit
50
50
  end
51
51
  end
52
52
 
53
- # If either mdless or mdcat are installed, use that for highlighting
54
- # markdown
53
+ # Prefer apex, then mdcat, then mdless. mdless ships with the gem,
54
+ # so highlighting still works when apex is not installed.
55
55
  def which_highlighter
56
- if Howzit.options[:highlighter] =~ /auto/i
57
- highlighters = %w[mdcat mdless]
58
- highlighters.delete_if(&:nil?).select!(&:available?)
59
- return nil if highlighters.empty?
56
+ command = if Howzit.options[:highlighter] =~ /auto/i
57
+ auto_highlighter
58
+ else
59
+ configured_highlighter
60
+ end
61
+ apex_command(command)
62
+ end
60
63
 
61
- hl = highlighters.first
62
- args = case hl
63
- when 'mdless'
64
- '--no-pager'
65
- end
64
+ # Apex defaults to HTML. Howzit always wants terminal escapes, and it
65
+ # pages the result itself, so add those flags unless the command
66
+ # already sets a format or a pagination option. This covers both
67
+ # auto and an explicit `:highlighter: apex`.
68
+ def apex_command(command)
69
+ return command if command.nil? || command.empty?
70
+ return command unless command.split.first == 'apex'
66
71
 
67
- [hl, args].join(' ')
68
- else
69
- hl = Howzit.options[:highlighter].split(/ /)[0]
70
- if hl.available?
71
- Howzit.options[:highlighter]
72
- else
73
- Howzit.console.error Color.template("{Rw}Error:{xbw} Specified highlighter (#{Howzit.options[:highlighter]}) not found, switching to auto")
74
- Howzit.options[:highlighter] = 'auto'
75
- which_highlighter
76
- end
77
- end
72
+ args = command.split[1..]
73
+ has_format = args.any? { |arg| ['-t', '--to'].include?(arg) || arg.start_with?('--to=') }
74
+ args.push('-t', 'terminal256') unless has_format
75
+ has_pager = args.any? { |arg| ['--no-paginate', '--paginate', '-p'].include?(arg) }
76
+ args << '--no-paginate' unless has_pager
77
+ ['apex', *args].join(' ')
78
+ end
79
+
80
+ def auto_highlighter
81
+ highlighters = %w[apex mdcat mdless]
82
+ highlighters.delete_if(&:nil?).select!(&:available?)
83
+ return nil if highlighters.empty?
84
+
85
+ hl = highlighters.first
86
+ args = '--no-pager' if hl == 'mdless'
87
+ [hl, args].compact.join(' ')
88
+ end
89
+
90
+ def configured_highlighter
91
+ hl = Howzit.options[:highlighter].split(/ /)[0]
92
+ return Howzit.options[:highlighter] if hl.available?
93
+
94
+ Howzit.console.error Color.template("{Rw}Error:{xbw} Specified highlighter (#{Howzit.options[:highlighter]}) not found, switching to auto")
95
+ Howzit.options[:highlighter] = 'auto'
96
+ auto_highlighter
78
97
  end
79
98
 
80
99
  # When pagination is enabled, find the best (in my opinion) option,
@@ -3,5 +3,5 @@
3
3
  # Primary module for this gem.
4
4
  module Howzit
5
5
  # Current Howzit version.
6
- VERSION = '2.1.47'
6
+ VERSION = '2.1.49'
7
7
  end
data/lib/howzit.rb CHANGED
@@ -60,7 +60,8 @@ require 'tty/box'
60
60
  # Main module for howzit
61
61
  module Howzit
62
62
  class << self
63
- attr_accessor :arguments, :named_arguments, :cli_topic_positional_args, :cli_args, :run_log, :multi_topic_run
63
+ attr_accessor :arguments, :named_arguments, :cli_topic_positional_args, :cli_args, :run_log, :multi_topic_run,
64
+ :topic_run_active
64
65
 
65
66
  ##
66
67
  ## Holds a Configuration object with methods and a @settings hash
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fileutils'
5
+ require 'tmpdir'
6
+ require 'stringio'
7
+
8
+ describe 'collected @before/@after notes' do
9
+ let(:temp_dir) { File.expand_path(Dir.mktmpdir('howzit_notes_test')) }
10
+ let(:out_file) { File.join(temp_dir, 'out.txt') }
11
+ let(:child_two_command) { 'false' }
12
+ let(:buildnote) do
13
+ note = Howzit::BuildNote.new
14
+ allow(note).to receive(:finalize_output)
15
+ note
16
+ end
17
+
18
+ before do
19
+ File.write(
20
+ File.join(temp_dir, 'buildnotes.md'),
21
+ <<~NOTE
22
+ # Notes Project
23
+
24
+ ## Parent
25
+
26
+ @before
27
+ Parent before
28
+ @end
29
+
30
+ @run(echo "parent" >> "#{out_file}") Parent task
31
+
32
+ @include(Shared [prod])
33
+
34
+ @after
35
+ Parent after
36
+ @end
37
+
38
+ ### Child One
39
+
40
+ @before
41
+ Child before
42
+ @end
43
+
44
+ @run(echo "child" >> "#{out_file}") Child task
45
+
46
+ @after
47
+ Child after
48
+ @end
49
+
50
+ ### Child Two
51
+
52
+ @run(#{child_two_command}) Child two task
53
+
54
+ ### Child Three
55
+
56
+ @run(echo "three" >> "#{out_file}") Three task
57
+
58
+ @after
59
+ Three after
60
+ @end
61
+
62
+ ## Shared (target)
63
+
64
+ @run(echo "shared ${target}" >> "#{out_file}") Shared task
65
+
66
+ @after
67
+ Shared after ${target}
68
+ @end
69
+ NOTE
70
+ )
71
+
72
+ Dir.chdir(temp_dir)
73
+ Howzit.instance_variable_set(:@buildnote, buildnote)
74
+ Howzit.options[:stack] = false
75
+ Howzit.options[:include_upstream] = false
76
+ Howzit.options[:run] = true
77
+ Howzit.options[:force] = false
78
+ Howzit.options[:log_level] = 3
79
+ Howzit.cli_args = ['parent']
80
+ Howzit.run_log = []
81
+ allow(Howzit::Prompt).to receive(:yn).and_return(true)
82
+ end
83
+
84
+ after do
85
+ Howzit.options[:run] = false
86
+ Howzit.options[:log_level] = 1
87
+ Howzit.cli_args = []
88
+ Howzit.run_log = []
89
+ Dir.chdir(Dir.tmpdir)
90
+ FileUtils.rm_rf(temp_dir) if Dir.exist?(temp_dir)
91
+ Howzit.instance_variable_set(:@buildnote, nil)
92
+ end
93
+
94
+ def run_and_capture
95
+ original = $stdout
96
+ $stdout = StringIO.new
97
+ buildnote.run
98
+ $stdout.string.gsub(/\e\[[\d;]*m/, '')
99
+ ensure
100
+ $stdout = original
101
+ end
102
+
103
+ def positions(text, notes)
104
+ notes.map { |note| text.index(note) }
105
+ end
106
+
107
+ it 'asks once for all prerequisites before running anything' do
108
+ text = run_and_capture
109
+
110
+ expect(Howzit::Prompt).to have_received(:yn).once
111
+ expect(positions(text, ['Parent before', 'Child before'])).to all(be_a(Integer))
112
+ expect(text.scan('Parent before').count).to eq 1
113
+ end
114
+
115
+ it 'shows all @after notes together in document order, including included topics' do
116
+ text = run_and_capture
117
+
118
+ notes = ['Parent after', 'Shared after prod', 'Child after', 'Three after']
119
+ found = positions(text, notes)
120
+ expect(found).to all(be_a(Integer))
121
+ expect(found).to eq(found.sort)
122
+ expect(text.scan('Child after').count).to eq 1
123
+ end
124
+
125
+ it 'shows notes from subtopics skipped after a failure' do
126
+ text = run_and_capture
127
+
128
+ expect(File.read(out_file).lines.map(&:strip)).to eq(['parent', 'shared prod', 'child'])
129
+ expect(text).to include('Three after')
130
+ end
131
+
132
+ context 'when nothing fails' do
133
+ let(:child_two_command) { 'true' }
134
+
135
+ it 'shows the combined @after box after all tasks have run' do
136
+ text = run_and_capture
137
+
138
+ expect(File.read(out_file).lines.map(&:strip)).to eq(['parent', 'shared prod', 'child', 'three'])
139
+ expect(text.scan('Parent after').count).to eq 1
140
+ end
141
+ end
142
+ end
data/spec/topic_spec.rb CHANGED
@@ -103,6 +103,36 @@ describe Howzit::Topic do
103
103
  Howzit.options[:show_all_code] = true
104
104
  expect(topic.print_out({ single: true, header: true }).join("\n").uncolor).to match(/▶ ls -1/)
105
105
  end
106
+
107
+ it 'leaves placeholders inside fenced code for the syntax highlighter' do
108
+ Howzit::Color.coloring = true
109
+ Howzit.options[:show_all_code] = true
110
+ note = Howzit::Topic.new('Widgets', <<~MD)
111
+ We set ${TEST_VAR} in a script block
112
+
113
+ ```bash
114
+ echo "${TEST_VAR}"
115
+ @run(ls) shown as code
116
+ ```
117
+
118
+ ```run Full capture script
119
+ if [[ -n ${only} ]]
120
+ ```
121
+ MD
122
+
123
+ lines = note.print_out({ single: true, header: false })
124
+ prose = lines.find { |line| line.include?('We set') }
125
+ echo_line = lines.find { |line| line.include?('echo') }
126
+ directive = lines.find { |line| line.include?('@run') }
127
+ condition = lines.find { |line| line.include?('only') }
128
+
129
+ expect(prose).to include("\e[")
130
+ expect(echo_line).to eq('echo "${TEST_VAR}"')
131
+ expect(directive).to eq('@run(ls) shown as code')
132
+ expect(condition).to eq('if [[ -n ${only} ]]')
133
+ ensure
134
+ Howzit::Color.coloring = false
135
+ end
106
136
  end
107
137
 
108
138
  describe '.arguments' do
data/spec/util_spec.rb CHANGED
@@ -23,10 +23,50 @@ describe Howzit::Util do
23
23
  end
24
24
 
25
25
  describe '.which_highlighter' do
26
+ after { Howzit.options[:highlighter] = 'auto' }
27
+
26
28
  it 'finds mdless' do
27
29
  Howzit.options[:highlighter] = 'mdless'
28
30
  expect(util.which_highlighter).to eq 'mdless'
29
31
  end
32
+
33
+ it 'prefers apex with terminal256 output and pagination disabled' do
34
+ Howzit.options[:highlighter] = 'auto'
35
+ allow(util).to receive(:command_exist?).and_return(false)
36
+ allow(util).to receive(:command_exist?).with('apex').and_return(true)
37
+
38
+ expect(util.which_highlighter).to eq 'apex -t terminal256 --no-paginate'
39
+ end
40
+
41
+ it 'uses mdcat when apex is not installed' do
42
+ Howzit.options[:highlighter] = 'auto'
43
+ allow(util).to receive(:command_exist?).and_return(false)
44
+ allow(util).to receive(:command_exist?).with('mdcat').and_return(true)
45
+
46
+ expect(util.which_highlighter).to eq 'mdcat'
47
+ end
48
+
49
+ it 'uses mdless without its pager when apex and mdcat are not installed' do
50
+ Howzit.options[:highlighter] = 'auto'
51
+ allow(util).to receive(:command_exist?).and_return(false)
52
+ allow(util).to receive(:command_exist?).with('mdless').and_return(true)
53
+
54
+ expect(util.which_highlighter).to eq 'mdless --no-pager'
55
+ end
56
+
57
+ it 'adds terminal256 output when the highlighter is set to apex' do
58
+ Howzit.options[:highlighter] = 'apex'
59
+ allow(util).to receive(:command_exist?).with('apex').and_return(true)
60
+
61
+ expect(util.which_highlighter).to eq 'apex -t terminal256 --no-paginate'
62
+ end
63
+
64
+ it 'keeps an explicit apex output format' do
65
+ Howzit.options[:highlighter] = 'apex -t html'
66
+ allow(util).to receive(:command_exist?).with('apex').and_return(true)
67
+
68
+ expect(util.which_highlighter).to eq 'apex -t html --no-paginate'
69
+ end
30
70
  end
31
71
 
32
72
  describe '.which_pager' do
data/src/_README.md CHANGED
@@ -37,7 +37,7 @@ Howzit is a tool that allows you to keep Markdown-formatted notes about a projec
37
37
  - Ruby 2.4+ (It probably works on older Rubys, but is untested prior to 2.4.1.)
38
38
  - Optional: if [`fzf`](https://github.com/junegunn/fzf) is available, it will be used for handling multiple choice selections
39
39
  - Optional: if [`bat`](https://github.com/sharkdp/bat) is available it will page with that
40
- - Optional: [`mdless`](https://github.com/ttscoff/mdless) or [`mdcat`](https://github.com/lunaryorn/mdcat) for formatting output
40
+ - Optional: [`apex`](https://github.com/ApexMarkdown/apex) is preferred for formatting output when it is installed. Otherwise howzit uses [`mdcat`](https://github.com/lunaryorn/mdcat) or [`mdless`](https://github.com/ttscoff/mdless). mdless is installed with the howzit gem.
41
41
 
42
42
  ### Installing
43
43
 
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.1.47
4
+ version: 2.1.49
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
@@ -317,6 +317,7 @@ files:
317
317
  - scripts/runtests.sh
318
318
  - spec/buildnote_spec.rb
319
319
  - spec/cli_spec.rb
320
+ - spec/collected_notes_spec.rb
320
321
  - spec/condition_evaluator_spec.rb
321
322
  - spec/conditional_blocks_integration_spec.rb
322
323
  - spec/conditional_content_spec.rb
@@ -367,6 +368,7 @@ summary: Provides a way to access Markdown project notes by topic with query cap
367
368
  test_files:
368
369
  - spec/buildnote_spec.rb
369
370
  - spec/cli_spec.rb
371
+ - spec/collected_notes_spec.rb
370
372
  - spec/condition_evaluator_spec.rb
371
373
  - spec/conditional_blocks_integration_spec.rb
372
374
  - spec/conditional_content_spec.rb