kramdown-ansi 0.7.0 → 0.8.0

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: 6d35fcfbc735d86a3f58f59c1eaded0ebdc4f706db3cedb0c807aa6f9f420fe8
4
- data.tar.gz: cd32746d6d592ee48e59bda8211adf670bdef612a5c65da97e114234ef8f0e83
3
+ metadata.gz: bfce0110800a14de98f3322fa646e4432af3a51fcda9c278d5c631d322c2384d
4
+ data.tar.gz: fdad876925cd1ecab465d491b8cca2024dbc40b2e8d103794303b83e316aff3f
5
5
  SHA512:
6
- metadata.gz: d7607e68a92ac9d968febb1179c60a291550306b56ada967fd29f2c9f1dd413f6d18981895b358b5a0ac34bdaae0291d1ed7e452a76dbe52329582fc11b11dc5
7
- data.tar.gz: 07b078aad8c0e3d0b9cf1b509b9f21dc4a2cbdbf3101f4997a079349fb7272848fe58080a18ab4e79c4b13b07061cbe61dfb43c511b8630eb73c077a6ecb866b
6
+ metadata.gz: 624287e2ab60beda1ce2ad7ce0ae3e68feeb8ad430b46828c7af3ee4833dd7d92c8a726919c4ebf6289a35fe79600d9756983e735403ef2269fa1ed3fd00a4a2
7
+ data.tar.gz: 795ffcabcd29c3910d1da3fca407ab2c09d85a416f25b0122353f0176ab59dcb424e869d9b4fac149cde62a03c1792f3b3134d24fe85b0b2c507112e8a181d41
data/CHANGES.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-10-29 v0.8.0
4
+
5
+ ### Fixes
6
+
7
+ - Fixed table width overflow by restructuring column width calculation from
8
+ per-row to per-table in `convert_table`, ensuring `Terminal::Table` is not
9
+ forced wider than the terminal by a single row's content distribution.
10
+ - Fixed a bug in `Kramdown::ANSI::Width.wrap` where a newline was incorrectly
11
+ prepended to the first token when it exceeded the target length, eliminating
12
+ phantom blank lines in narrow table cells.
13
+ - Subtracted table chrome (border, padding, and separator overhead) from the
14
+ column width budget in `convert_table` to prevent tables from exceeding
15
+ width.
16
+
17
+ ### Improvements
18
+
19
+ - Simplified `convert_tr` to read pre-computed column widths and wrap each cell
20
+ to its fixed budget.
21
+
22
+ ### Build & CI
23
+
24
+ - Updated the minimum version of the `gem_hadar` development dependency to
25
+ **2.21.0**.
26
+ - Bumped `rubygems_version` to **4.0.23**.
27
+
28
+ ### Testing
29
+
30
+ - Regenerated `spec/assets/tables.ansi` golden file.
31
+
3
32
  ## 2026-10-22 v0.7.0
4
33
 
5
34
  ### Fixes
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: kramdown-ansi 0.7.0 ruby lib
2
+ # stub: kramdown-ansi 0.8.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "kramdown-ansi".freeze
6
- s.version = "0.7.0".freeze
6
+ s.version = "0.8.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -18,13 +18,13 @@ Gem::Specification.new do |s|
18
18
  s.licenses = ["MIT".freeze]
19
19
  s.rdoc_options = ["--title".freeze, "Kramdown-ansi - Output markdown in the terminal with ANSI escape sequences".freeze, "--main".freeze, "README.md".freeze]
20
20
  s.required_ruby_version = Gem::Requirement.new(">= 3.1".freeze)
21
- s.rubygems_version = "4.0.22".freeze
21
+ s.rubygems_version = "4.0.23".freeze
22
22
  s.summary = "Output markdown in the terminal with ANSI escape sequences".freeze
23
23
  s.test_files = ["spec/kramdown/ansi/pager_spec.rb".freeze, "spec/kramdown/ansi/styles_spec.rb".freeze, "spec/kramdown/ansi/width_spec.rb".freeze, "spec/kramdown/ansi_golden_spec.rb".freeze, "spec/kramdown/ansi_spec.rb".freeze, "spec/kramdown/ansi_table_spec.rb".freeze, "spec/kramdown/render_spec.rb".freeze, "spec/spec_helper.rb".freeze]
24
24
 
25
25
  s.specification_version = 4
26
26
 
27
- s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.20.1".freeze])
27
+ s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.21.0".freeze])
28
28
  s.add_development_dependency(%q<all_images>.freeze, ["~> 0.4".freeze])
29
29
  s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2".freeze])
30
30
  s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
@@ -78,7 +78,9 @@ module Kramdown::ANSI::Width
78
78
  if $~[:nws]
79
79
  if length_without_ansi + token_length > length
80
80
  length_without_ansi = token_length
81
- if result[-1] == ' '
81
+ if result.empty?
82
+ result = token_value
83
+ elsif result[-1] == ' '
82
84
  result[-1, 1] = "\n#{token_value}"
83
85
  else
84
86
  result << "\n#{token_value}"
data/lib/kramdown/ansi.rb CHANGED
@@ -472,6 +472,29 @@ class Kramdown::ANSI < Kramdown::Converter::Base
472
472
  end
473
473
  return newline rows.join("\n")
474
474
  end
475
+ # Compute per-column budgets from the widest cell in each column
476
+ # across all rows. Terminal::Table sizes each column to its widest
477
+ # cell, so per-row ratios would produce columns wider than the
478
+ # terminal budget.
479
+ max_w = Hash.new(0)
480
+ el.children.each do |section|
481
+ next unless %i[thead tbody tfoot].include?(section.type)
482
+ section.children.each do |row|
483
+ row.children.each_with_index do |cell, i|
484
+ max_w[i] = [max_w[i], display_width(convert(cell, opts).strip)].max
485
+ end
486
+ end
487
+ end
488
+ n = max_w.keys.map(&:to_i).max.to_i + 1
489
+ total = max_w.values.sum
490
+ budget = width(percentage: 90) - (3 * n + 1)
491
+ col_w = if total.zero?
492
+ same = (budget.to_f / n).to_i
493
+ Array.new(n, same)
494
+ else
495
+ (0...n).map { |i| ((max_w[i].to_f / total) * budget).to_i }
496
+ end
497
+ opts[:table_col_widths] = col_w
475
498
  table = Terminal::Table.new
476
499
  table.style = {
477
500
  all_separators: true,
@@ -533,33 +556,23 @@ class Kramdown::ANSI < Kramdown::Converter::Base
533
556
  ''
534
557
  end
535
558
 
536
- # The convert_tr method processes a table row element by calculating column
537
- # widths based on content size, wrapping text to fit within the terminal
538
- # width, and adding the formatted row to the terminal table instance.
559
+ # The convert_tr method processes a table row element by wrapping each cell
560
+ # to the pre-computed column width and adding the formatted row to the
561
+ # terminal table instance.
539
562
  #
540
563
  # @param el [Kramdown::Element] the table row element to convert
541
564
  # @param opts [Hash] conversion options containing context for processing
565
+ # (must include :table and :table_col_widths)
542
566
  # @return [String] an empty string to indicate successful processing and
543
567
  # addition of the row to the table instance
544
568
  def convert_tr(el, opts)
545
569
  return '' if el.children.empty?
546
- cols = el.children.map do |c|
570
+ col_w = opts[:table_col_widths]
571
+ cols = el.children.each_with_index.map do |c, i|
547
572
  stripped = convert(c, opts).strip
548
- stripped.empty? ? ' ' : stripped
573
+ stripped.empty? ? ' ' : wrap(stripped, length: col_w[i])
549
574
  end
550
- return '' if cols.empty?
551
- col_widths = cols.map { |c| display_width(c) }
552
- col_widths_sum = col_widths.sum
553
- full_width = width(percentage: 90)
554
- ratios = cols.each_with_index.map do |c, i|
555
- if col_widths_sum.zero?
556
- 1.0 / cols.size
557
- else
558
- col_widths[i] / col_widths_sum.to_f
559
- end
560
- end
561
- wrapped_cols = cols.zip(ratios).map { |c, r| wrap(c, length: r * full_width) }
562
- opts[:table] << wrapped_cols
575
+ opts[:table] << cols
563
576
  ''
564
577
  end
565
578
 
@@ -662,5 +675,4 @@ class Kramdown::ANSI < Kramdown::Converter::Base
662
675
  @ansi_styles.apply(name, &block)
663
676
  end
664
677
  end
665
-
666
678
  Kramdown::Converter.const_set(:Ansi, Kramdown::ANSI)
@@ -5,7 +5,7 @@
5
5
  # by hand; it is rewritten on every `rake version` invocation.
6
6
  module Kramdown
7
7
  # The current version of the Kramdown gem as a String.
8
- VERSION = '0.7.0'
8
+ VERSION = '0.8.0'
9
9
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
10
10
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
11
11
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -286,60 +286,61 @@ a | b
286
286
 
287
287
  ────────────────────────────────────────────────────────────────────────────────
288
288
 
289
- ╭──────┬────────────────────────────────────────────────────────────────╮
290
- │ Case │ What It Stresses │
291
- ├──────┼────────────────────────────────────────────────────────────────┤
292
- │ 01 │ Column count validation / overflow / underflow │
293
- ├──────┼────────────────────────────────────────────────────────────────┤
294
- │ 02 │ Pipe-stripping logic (leading/trailing optional) │
295
- ├──────┼────────────────────────────────────────────────────────────────┤
296
- │ 03 │ Escape sequence handling (\|) │
297
- ├──────┼────────────────────────────────────────────────────────────────┤
298
- │ 04 │ Empty-string cell rendering, border alignment │
299
- ├──────┼────────────────────────────────────────────────────────────────┤
300
- │ 05 │ Single-column edge (degenerate table) │
301
- ├──────┼────────────────────────────────────────────────────────────────┤
302
- │ 06 │ Zero data rows — does it draw a header-only box? │
303
- ├──────┼────────────────────────────────────────────────────────────────┤
304
- │ 07 │ Consecutive tables — does the second become data of the first? │
305
- ├──────┼────────────────────────────────────────────────────────────────┤
306
- │ 08 │ Unicode width calculation for column sizing │
307
- ├──────┼────────────────────────────────────────────────────────────────┤
308
- │ 09 │ Inline markdown rendering inside a table cell │
309
- ├──────┼────────────────────────────────────────────────────────────────┤
310
- │ 10 │ Alignment row with fewer columns than header │
311
- ├──────┼────────────────────────────────────────────────────────────────┤
312
- │ 11 │ Blank line splitting one table into two │
313
- ├──────┼────────────────────────────────────────────────────────────────┤
314
- │ 12 │ Whitespace normalization / trimming │
315
- ├──────┼────────────────────────────────────────────────────────────────┤
316
- │ 13 │ Raw HTML + <br> in cell context │
317
- ├──────┼────────────────────────────────────────────────────────────────┤
318
- │ 14 │ Cell with only whitespace — empty or not? │
319
- ├──────┼────────────────────────────────────────────────────────────────┤
320
- │ 15 │ Very wide table — does it wrap or overflow? │
321
- ├──────┼────────────────────────────────────────────────────────────────┤
322
- │ 16 │ Non-standard alignment markers │
323
- ├──────┼────────────────────────────────────────────────────────────────┤
324
- │ 17 │ Table at doc start, glued to following header │
325
- ├──────┼────────────────────────────────────────────────────────────────┤
326
- │ 18 │ Table glued to preceding header (no blank before) │
327
- ├──────┼────────────────────────────────────────────────────────────────┤
328
- │ 19 │ Single col, missing closing pipe on header │
329
- ├──────┼────────────────────────────────────────────────────────────────┤
330
- │ 20 │ Not a table: single pipe line │
331
- ├──────┼────────────────────────────────────────────────────────────────┤
332
- │ 21 │ Not a table: header + sep, no body, missing pipe │
333
- ├──────┼────────────────────────────────────────────────────────────────┤
334
- │ 22 │ Table after code block, no blank between │
335
- ├──────┼────────────────────────────────────────────────────────────────┤
336
- │ 23 │ Table after list item, no blank between │
337
- ├──────┼────────────────────────────────────────────────────────────────┤
338
- │ 24 │ No leading pipe on separator row │
339
- ├──────┼────────────────────────────────────────────────────────────────┤
340
- │ 25 │ No leading pipe on body row │
341
- ├──────┼────────────────────────────────────────────────────────────────┤
342
- │ 26 │ Indented table inside ordered list item │
343
- ├──────┼────────────────────────────────────────────────────────────────┤
344
- │ 27 │ Not a table just a pipe in a sentence │
345
- ╰──────┴────────────────────────────────────────────────────────────────╯
289
+ ╭──────┬─────────────────────────────────────────────────────────╮
290
+ │ Case │ What It Stresses │
291
+ ├──────┼─────────────────────────────────────────────────────────┤
292
+ │ 01 │ Column count validation / overflow / underflow │
293
+ ├──────┼─────────────────────────────────────────────────────────┤
294
+ │ 02 │ Pipe-stripping logic (leading/trailing optional) │
295
+ ├──────┼─────────────────────────────────────────────────────────┤
296
+ │ 03 │ Escape sequence handling (\|) │
297
+ ├──────┼─────────────────────────────────────────────────────────┤
298
+ │ 04 │ Empty-string cell rendering, border alignment │
299
+ ├──────┼─────────────────────────────────────────────────────────┤
300
+ │ 05 │ Single-column edge (degenerate table) │
301
+ ├──────┼─────────────────────────────────────────────────────────┤
302
+ │ 06 │ Zero data rows — does it draw a header-only box? │
303
+ ├──────┼─────────────────────────────────────────────────────────┤
304
+ │ 07 │ Consecutive tables — does the second become data of the │
305
+ │ │ first? │
306
+ ├──────┼─────────────────────────────────────────────────────────┤
307
+ │ 08 │ Unicode width calculation for column sizing │
308
+ ├──────┼─────────────────────────────────────────────────────────┤
309
+ │ 09 │ Inline markdown rendering inside a table cell │
310
+ ├──────┼─────────────────────────────────────────────────────────┤
311
+ │ 10 │ Alignment row with fewer columns than header │
312
+ ├──────┼─────────────────────────────────────────────────────────┤
313
+ │ 11 │ Blank line splitting one table into two │
314
+ ├──────┼─────────────────────────────────────────────────────────┤
315
+ │ 12 │ Whitespace normalization / trimming │
316
+ ├──────┼─────────────────────────────────────────────────────────┤
317
+ │ 13 │ Raw HTML + <br> in cell context │
318
+ ├──────┼─────────────────────────────────────────────────────────┤
319
+ │ 14 │ Cell with only whitespace — empty or not? │
320
+ ├──────┼─────────────────────────────────────────────────────────┤
321
+ │ 15 │ Very wide table — does it wrap or overflow? │
322
+ ├──────┼─────────────────────────────────────────────────────────┤
323
+ │ 16 │ Non-standard alignment markers │
324
+ ├──────┼─────────────────────────────────────────────────────────┤
325
+ │ 17 │ Table at doc start, glued to following header │
326
+ ├──────┼─────────────────────────────────────────────────────────┤
327
+ │ 18 │ Table glued to preceding header (no blank before) │
328
+ ├──────┼─────────────────────────────────────────────────────────┤
329
+ │ 19 │ Single col, missing closing pipe on header │
330
+ ├──────┼─────────────────────────────────────────────────────────┤
331
+ │ 20 │ Not a table: single pipe line │
332
+ ├──────┼─────────────────────────────────────────────────────────┤
333
+ │ 21 │ Not a table: header + sep, no body, missing pipe │
334
+ ├──────┼─────────────────────────────────────────────────────────┤
335
+ │ 22 │ Table after code block, no blank between │
336
+ ├──────┼─────────────────────────────────────────────────────────┤
337
+ │ 23 │ Table after list item, no blank between │
338
+ ├──────┼─────────────────────────────────────────────────────────┤
339
+ │ 24 │ No leading pipe on separator row │
340
+ ├──────┼─────────────────────────────────────────────────────────┤
341
+ │ 25 │ No leading pipe on body row │
342
+ ├──────┼─────────────────────────────────────────────────────────┤
343
+ │ 26 │ Indented table inside ordered list item │
344
+ ├──────┼─────────────────────────────────────────────────────────┤
345
+ │ 27 │ Not a table just a pipe in a sentence │
346
+ ╰──────┴─────────────────────────────────────────────────────────╯
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kramdown-ansi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 2.20.1
18
+ version: 2.21.0
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 2.20.1
25
+ version: 2.21.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: all_images
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -233,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
233
233
  - !ruby/object:Gem::Version
234
234
  version: '0'
235
235
  requirements: []
236
- rubygems_version: 4.0.22
236
+ rubygems_version: 4.0.23
237
237
  specification_version: 4
238
238
  summary: Output markdown in the terminal with ANSI escape sequences
239
239
  test_files: