howzit 2.1.48 → 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: 2a6dffed9d9ce31f4704b3388bbf330f87d86f054067444073ea34b8cba13a54
4
- data.tar.gz: 87cdb843c109e8f0b88e482634d0f35b676ffcd6e2732009f5a7aa60932f7fff
3
+ metadata.gz: 91e3e382d6e58e8a3a50cb663de149af066ee02b80bafcdbf6db5d68c79426af
4
+ data.tar.gz: ebaf51a69ba374ba5fa64a548560cfa0b8e03f70b85a77de3a1f43aa94baf944
5
5
  SHA512:
6
- metadata.gz: 4e278c055f9647bb784cfac2f1fe00616dde57023a5cd08e714097ccc3f32181ad67898da2507fe23c5496a235cdee5143c29918149a0a15d1e70574e3d535d8
7
- data.tar.gz: 409df1fe83a7e46ba317d2c9cceb8346ea94c7578376f1836b7d9bb6cb17b83b51020955470d1371a27abb46150ec6af49da1e5b15ac8108eff9b9fccb625cc9
6
+ metadata.gz: 96e353abbe3fec9eb5cce2c1fcbbdc45d425394594f394251dc2719937ba69a2acbf87e7d3ccae437baf25b33c400ef0ddf7c01cd42765cc4f39009968f703cf
7
+ data.tar.gz: 48c8b7253abbd0adfe88a0b5ccb1108684db73252c87823ef29aa59507feefd814bc689831585255e73624136f55cd39ee0797ab84666c49dc3a56107b76fa31
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
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
+
1
15
  ### 2.1.48
2
16
 
3
17
  2026-10-09 07: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/topic.rb CHANGED
@@ -493,7 +493,18 @@ module Howzit
493
493
  topic.gsub!(/(?mix)^(`{3,})run([?!]*)\s*
494
494
  ([^\n]*)[\s\S]*?\n\1\s*$/, '@@@run\2 \3')
495
495
  end
496
+ in_fence = false
497
+ fence_char = nil
498
+ fence_len = 0
496
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
+
497
508
  case l
498
509
  when /@(before|after|prereq|end|if|unless)/
499
510
  next
@@ -504,12 +515,22 @@ module Howzit
504
515
  when /(?<fence>`{3,})run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
505
516
  desc = title_code_block(Regexp.last_match.named_captures.symbolize_keys)
506
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
507
521
  when /@@@run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
508
522
  output.push("{bmK}\u{25B6} {bwK}#{title_code_block(Regexp.last_match.named_captures.symbolize_keys)}{x}".c)
509
523
  else
510
- l.wrap!(Howzit.options[:wrap]) if Howzit.options[:wrap].positive?
511
- # Highlight variable placeholders in content
512
- 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
513
534
  end
514
535
  end
515
536
  Howzit.named_arguments = @named_args
@@ -620,6 +641,23 @@ module Howzit
620
641
 
621
642
  private
622
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
+
623
661
  def run_topic(nested:, as_subtopic:)
624
662
  @results = { total: 0, success: 0, errors: 0, message: ''.c }
625
663
  output = []
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.48'
6
+ VERSION = '2.1.49'
7
7
  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.48
4
+ version: 2.1.49
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra