kramdown-ansi 0.5.0 → 0.6.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: 737af675856867287e33a53bf18bbb08517b3743900132f826b77cdad9b47c01
4
- data.tar.gz: f533ff7b8927579aead7c482039813091cf55796621febd5658a5c469d7e0957
3
+ metadata.gz: 0e9bbd4a032cd0f37629bc21f4967590fcb7140875fe79687e01f5941cdea10c
4
+ data.tar.gz: 2805ae302ae89c97266f7cfb690ab7a8b87662c6654e802d42ac7b9ae125515c
5
5
  SHA512:
6
- metadata.gz: 5578a1e962bf25fbc54f00be909cb53a647bc3e56f67934a984c37f8c4a156e1dd499e446aa549817c35fd83c26c31a0f975319b06dcc7e556e73ba39b5be9cf
7
- data.tar.gz: b48b3cab8c7d2c05181efe12cd794be25a59d1319aaaa6ad26ae2a31b7a54311153f24076ae109a696c5cec791c958b6e6eba84bc2f3c9823c5feec9916ee825
6
+ metadata.gz: 7268907b0b2467c70767f995d7cf1823d81378c2da7f5b9d324846b54ec63ad3357a91de8cfc116b49d5efd687a79537788d5c2e2cd2c0a5f66afa0715abbce6
7
+ data.tar.gz: 2a19614f212d5f2a8a55310d6ecc51d64050378a744dd0ea180b576f7da6a90d976ffb606ff62f4ab48d5e132425ca5616d17cb88479e5d555f5013c729db31a
data/.utilsrc CHANGED
@@ -41,7 +41,6 @@ code_indexer do
41
41
  date
42
42
  debug
43
43
  diff-lcs
44
- docile
45
44
  erb
46
45
  excon
47
46
  fileutils
@@ -79,8 +78,6 @@ code_indexer do
79
78
  search_ui
80
79
  shellwords
81
80
  simplecov
82
- simplecov-html
83
- simplecov_json_formatter
84
81
  stringio
85
82
  sync
86
83
  term-ansicolor
data/CHANGES.md CHANGED
@@ -1,5 +1,73 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-10-21 v0.6.0
4
+
5
+ ### Features
6
+
7
+ - Add support for nested blockquotes with cycling typographic quotation marks
8
+ based on nesting depth.
9
+ - Add ANSI styling support for HTML elements: `ins`/`u` (underline), `mark`
10
+ (negative/inverse), `tt` (code), `small` (faint), and passthrough for
11
+ `span`/`sub`/`sup`.
12
+ - Add strikethrough support for `del` and `s` HTML elements.
13
+ - Introduce `ProtectEnvVars` module in test helper to isolate environment
14
+ variable changes during tests tagged with `:protect_env`.
15
+
16
+ ### Fixes
17
+
18
+ - Fix GFM table parsing by inserting required blank lines before and after pipe
19
+ tables to ensure correct recognition by `kramdown`.
20
+ - Fix `Integer#size` regression in table column width calculation by using
21
+ `display_width` directly instead of `.size`, ensuring correct column ratios
22
+ on Ruby 4.
23
+ - Fix empty table cell rendering by replacing empty strings with a single space
24
+ and falling back to equal-width splits when total width is zero.
25
+ - Fix typo in `convert_html_element` where `e.value` was used instead of
26
+ `el.value` for the `del`/`s` branch.
27
+ - Make `Token` definition in `Kramdown::ANSI::Width` compatible with Ruby
28
+ versions lacking `Data` by providing a `Struct`-based fallback.
29
+
30
+ ### Improvements
31
+
32
+ - Rewrite `Kramdown::ANSI::Width#truncate` to be ANSI-aware, correctly handling
33
+ escape sequences, wide characters (emojis), and zero-width characters using
34
+ `display_width`.
35
+ - Optimize `wrap` and `truncate` methods by using `scan` instead of `gsub` to
36
+ reduce allocation.
37
+ - Generalize the `capture:tables` Rake task to `capture:ansi` to regenerate
38
+ golden files for all `spec/assets/*.md` fixtures.
39
+ - Update `README.md` style examples to include `blockquote` and add a nested
40
+ dialog example.
41
+
42
+ ### Build & CI
43
+
44
+ - Add `tins` gem (`~> 1.61`) as a runtime dependency.
45
+ - Upgrade `gem_hadar` development dependency to `>= 2.20.1`.
46
+ - Update `rubygems_version` in gemspec to **4.0.22**.
47
+ - Remove unused gems (`docile`, `simplecov-html`, `simplecov_json_formatter`)
48
+ from `.utilsrc`.
49
+ - Add `git config --global --add safe.directory /work` to Docker test script.
50
+ - Use `nproc` instead of `getconf _NPROCESSORS_ONLN` for CPU count in Docker
51
+ test script.
52
+ - Add `tmp/.gitkeep` to track the empty `tmp` directory.
53
+
54
+ ### Testing
55
+
56
+ - Add `spec/kramdown/render_spec.rb` to test `Kramdown::ANSI.parse` for
57
+ headers, inline emphasis, code blocks, blockquotes, horizontal rules, lists,
58
+ links, images, and paragraphs.
59
+ - Add `spec/assets/tables.md` and `spec/assets/tables.ansi` golden files
60
+ covering 26 edge cases for table rendering.
61
+ - Add `spec/kramdown/ansi_golden_spec.rb` for output regression testing against
62
+ golden files.
63
+ - Add `spec/assets/html.md` and `spec/assets/html.ansi` golden files covering
64
+ HTML element styling.
65
+ - Add 9 new specs for `Kramdown::ANSI::Width#truncate` covering wide emojis,
66
+ empty strings, pure ANSI, zero-width characters, newline preservation,
67
+ multi-cell ellipsis, nested-style reset, and post-cut escape omission.
68
+ - Stub `Tins::Terminal.columns` to 80 in `ansi_spec.rb` and `render_spec.rb`
69
+ for deterministic output.
70
+
3
71
  ## 2026-03-21 v0.5.0
4
72
 
5
73
  - Added `spec/kramdown/ansi_table_spec.rb` to the test suite and gemspec file
data/README.md CHANGED
@@ -47,10 +47,11 @@ You can customize the ANSI styles by passing an `ansi_styles` option:
47
47
  require 'kramdown/ansi'
48
48
 
49
49
  ansi_styles = {
50
- header: [:bold, :magenta],
51
- strong: :green,
52
- em: :yellow,
53
- code: [:cyan, :underline]
50
+ header: [:bold, :magenta],
51
+ strong: :green,
52
+ em: :yellow,
53
+ code: [:cyan, :underline],
54
+ blockquote: :blue,
54
55
  }
55
56
 
56
57
  puts Kramdown::ANSI.parse(markdown, ansi_styles:)
@@ -65,7 +66,7 @@ methods:
65
66
  require 'kramdown/ansi'
66
67
 
67
68
  # Using from_json method
68
- json_config = '{"header": ["bold", "magenta"], "code": ["cyan", "underline"]}'
69
+ json_config = '{"header": ["bold", "magenta"], "code": ["cyan", "underline"], "blockquote": ["magenta", "underline"]}'
69
70
  ansi_styles = Kramdown::ANSI::Styles.from_json(json_config)
70
71
 
71
72
  # Apply to parsing
@@ -177,6 +178,10 @@ The homepage of this library is located at
177
178
 
178
179
  ![cat](./spec/assets/kitten.jpg)
179
180
 
181
+ Dialog:
182
+ > What's that, Fluffy?
183
+ >> That's my new friend.
184
+
180
185
  ---
181
186
 
182
187
  This is the end.
data/Rakefile CHANGED
@@ -37,6 +37,7 @@ GemHadar do
37
37
  dependency 'term-ansicolor', '~> 1.11'
38
38
  dependency 'kramdown-parser-gfm', '~> 1.1'
39
39
  dependency 'terminal-table', '~> 4.0'
40
+ dependency 'tins', '~> 1.61'
40
41
  dependency 'json', '~> 2.0'
41
42
  dependency 'unicode-display_width', '~> 3.0'
42
43
  development_dependency 'all_images', '~> 0.4'
@@ -48,3 +49,21 @@ GemHadar do
48
49
 
49
50
  clobber 'coverage'
50
51
  end
52
+
53
+ namespace :capture do
54
+ desc 'Capture golden file ansi output for all spec/assets/*.md files'
55
+ task :ansi do
56
+ require 'kramdown/ansi'
57
+ module Tins::Terminal
58
+ def self.columns
59
+ 80
60
+ end
61
+ end
62
+ Dir[File.join('spec', 'assets', '*.md')].sort.each do |md|
63
+ out_path = md.sub('.md', '.ansi')
64
+ out = Kramdown::ANSI.parse(File.read(md))
65
+ File.write(out_path, out)
66
+ puts "Captured #{out_path} (#{out.bytesize} bytes)"
67
+ end
68
+ end
69
+ end
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: kramdown-ansi 0.5.0 ruby lib
2
+ # stub: kramdown-ansi 0.6.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "kramdown-ansi".freeze
6
- s.version = "0.5.0".freeze
6
+ s.version = "0.6.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]
@@ -13,18 +13,18 @@ Gem::Specification.new do |s|
13
13
  s.email = "flori@ping.de".freeze
14
14
  s.executables = ["md".freeze, "git-md".freeze]
15
15
  s.extra_rdoc_files = ["README.md".freeze, "lib/kramdown/ansi.rb".freeze, "lib/kramdown/ansi/pager.rb".freeze, "lib/kramdown/ansi/styles.rb".freeze, "lib/kramdown/ansi/width.rb".freeze, "lib/kramdown/version.rb".freeze]
16
- s.files = [".utilsrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/git-md".freeze, "bin/md".freeze, "img/git-md.png".freeze, "img/md.png".freeze, "kramdown-ansi.gemspec".freeze, "lib/kramdown/ansi.rb".freeze, "lib/kramdown/ansi/pager.rb".freeze, "lib/kramdown/ansi/styles.rb".freeze, "lib/kramdown/ansi/width.rb".freeze, "lib/kramdown/version.rb".freeze, "spec/assets/README.ansi".freeze, "spec/assets/kitten.jpg".freeze, "spec/kramdown/ansi/pager_spec.rb".freeze, "spec/kramdown/ansi/styles_spec.rb".freeze, "spec/kramdown/ansi/width_spec.rb".freeze, "spec/kramdown/ansi_spec.rb".freeze, "spec/kramdown/ansi_table_spec.rb".freeze, "spec/spec_helper.rb".freeze]
16
+ s.files = [".utilsrc".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/git-md".freeze, "bin/md".freeze, "img/git-md.png".freeze, "img/md.png".freeze, "kramdown-ansi.gemspec".freeze, "lib/kramdown/ansi.rb".freeze, "lib/kramdown/ansi/pager.rb".freeze, "lib/kramdown/ansi/styles.rb".freeze, "lib/kramdown/ansi/width.rb".freeze, "lib/kramdown/version.rb".freeze, "spec/assets/README.ansi".freeze, "spec/assets/html.ansi".freeze, "spec/assets/html.md".freeze, "spec/assets/kitten.jpg".freeze, "spec/assets/tables.ansi".freeze, "spec/assets/tables.md".freeze, "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, "tmp/.gitkeep".freeze]
17
17
  s.homepage = "https://github.com/flori/kramdown-ansi".freeze
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.8".freeze
21
+ s.rubygems_version = "4.0.22".freeze
22
22
  s.summary = "Output markdown in the terminal with ANSI escape sequences".freeze
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_spec.rb".freeze, "spec/kramdown/ansi_table_spec.rb".freeze, "spec/spec_helper.rb".freeze]
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.17.0".freeze])
27
+ s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.20.1".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])
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
32
32
  s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
33
33
  s.add_runtime_dependency(%q<kramdown-parser-gfm>.freeze, ["~> 1.1".freeze])
34
34
  s.add_runtime_dependency(%q<terminal-table>.freeze, ["~> 4.0".freeze])
35
+ s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.61".freeze])
35
36
  s.add_runtime_dependency(%q<json>.freeze, ["~> 2.0".freeze])
36
37
  s.add_runtime_dependency(%q<unicode-display_width>.freeze, ["~> 3.0".freeze])
37
38
  end
@@ -24,10 +24,15 @@ class Kramdown::ANSI::Styles
24
24
  # configuration.
25
25
  def initialize
26
26
  @default_ansi_styles = {
27
- header: %i[ bold underline ],
28
- strong: :bold,
29
- em: :italic,
30
- code: :blue,
27
+ header: %i[ bold underline ],
28
+ strong: :bold,
29
+ em: :italic,
30
+ code: :blue,
31
+ blockquote: :faint,
32
+ del: :strikethrough,
33
+ ins: :underline,
34
+ mark: :negative,
35
+ small: :faint,
31
36
  }
32
37
  @ansi_styles = @default_ansi_styles.dup
33
38
  end
@@ -19,20 +19,24 @@ module Kramdown::ANSI::Width
19
19
 
20
20
  module_function
21
21
 
22
- # Returns the width of the terminal in characters, given a percentage.
23
- #
24
- # @param percentage [Numeric] the percentage value (defaults to 100.0)
25
- # @return [Integer] the calculated width
26
- def width(percentage: 100.0)
27
- ((Float(percentage) * Tins::Terminal.columns) / 100).floor
28
- end
22
+ ANSI_ESCAPES = /\e\[.*?m|\e\].*?(\e|\a)\\?/
23
+
24
+ private_constant :ANSI_ESCAPES
29
25
 
30
26
  # Removes ANSI escape sequences from the given string.
31
27
  #
32
28
  # @param line [String] the string potentially containing ANSI escape codes.
33
29
  # @return [String] the string with all ANSI escape sequences removed.
34
30
  def remove_ansi_escapes(line)
35
- line.to_s.gsub(/\e\[.*?m|\e\].*?(\e|\a)\\?/, '')
31
+ line.to_s.gsub(ANSI_ESCAPES, '')
32
+ end
33
+
34
+ # Returns the width of the terminal in characters, given a percentage.
35
+ #
36
+ # @param percentage [Numeric] the percentage value (defaults to 100.0)
37
+ # @return [Integer] the calculated width
38
+ def width(percentage: 100.0)
39
+ ((Float(percentage) * Tins::Terminal.columns) / 100).floor
36
40
  end
37
41
 
38
42
  # Calculates the display width of a string after removing ANSI escape
@@ -67,8 +71,8 @@ module Kramdown::ANSI::Width
67
71
  end
68
72
  length = length.clamp(1..)
69
73
  length_without_ansi = 0
70
- result = ''
71
- text.gsub(/(?<nws>\S+)|(?<ws>\s)/) do
74
+ result = +''
75
+ text.scan(/(?<nws>\S+)|(?<ws>\s)/) do
72
76
  token_value = $&
73
77
  token_length = display_width(token_value)
74
78
  if $~[:nws]
@@ -91,6 +95,28 @@ module Kramdown::ANSI::Width
91
95
  result
92
96
  end
93
97
 
98
+ if defined?(Data)
99
+ # A frozen data record for a single token in the `truncate` scan.
100
+ #
101
+ # +type+ is `:esc` (ANSI escape, zero display width) or
102
+ # `:txt` (visible character, display width from
103
+ # `Unicode::DisplayWidth`).
104
+ # +value+ is the raw matched substring.
105
+ # +length+ is the display width in terminal columns (0 for escapes).
106
+ Token = Data.define(:type, :value, :length)
107
+ else
108
+ class Token < Struct.new(:type, :value, :length)
109
+ def initialize(**opts)
110
+ opts.each do |key, value|
111
+ self.send("#{key}=", value)
112
+ end
113
+ freeze
114
+ end
115
+ end
116
+ end
117
+
118
+ private_constant :Token
119
+
94
120
  # Truncates a given string to a specified length or percentage. If the text
95
121
  # is longer an ellipsis sequence is added at the end of the generated string,
96
122
  # to indicate that a truncation has been performed.
@@ -105,13 +131,59 @@ module Kramdown::ANSI::Width
105
131
  percentage.nil? ^ length.nil? or
106
132
  raise ArgumentError, "either pass percentage or length argument"
107
133
  percentage and length ||= width(percentage:)
108
- ellipsis_length = ellipsis.size
109
- if length < ellipsis_length
110
- +''
111
- elsif text.size >= length + ellipsis_length
112
- text[0, length - ellipsis_length] + ellipsis
113
- else
114
- text
134
+ ellipsis_length = display_width(remove_ansi_escapes(ellipsis))
135
+ found_esc = false
136
+ result = +''
137
+
138
+ return result if text.empty?
139
+ return result if length < ellipsis_length
140
+
141
+ current_length = 0
142
+ tokens = []
143
+
144
+ text.scan(/(?<esc>#{ANSI_ESCAPES})|(?<txt>.)/m) do
145
+ token = Token.new(
146
+ type: $~[:esc] ? :esc : :txt,
147
+ value: $&,
148
+ length: $~[:esc] ? 0 : display_width($&)
149
+ )
150
+ tokens << token
151
+ end
152
+
153
+ while token = tokens.shift
154
+ if token.type == :esc
155
+ found_esc = true
156
+ result << token.value
157
+ next
158
+ end
159
+
160
+ if current_length + token.length == length && tokens.empty?
161
+ result << token.value
162
+ current_length += token.length
163
+ break
164
+ elsif current_length + token.length + ellipsis_length > length
165
+ result << ellipsis
166
+ break
167
+ elsif current_length + token.length + ellipsis_length == length
168
+ result << token.value
169
+ current_length += token.length
170
+ remaining_text_length = tokens.select { _1.type == :txt }.map(&:length).sum
171
+ if current_length + remaining_text_length == length
172
+ next
173
+ elsif current_length + remaining_text_length > length
174
+ result << ellipsis
175
+ break
176
+ else
177
+ next
178
+ end
179
+ else
180
+ current_length += token.length
181
+ result << token.value
182
+ end
183
+
115
184
  end
185
+
186
+ result << reset if found_esc && !result.end_with?(reset)
187
+ result
116
188
  end
117
189
  end
data/lib/kramdown/ansi.rb CHANGED
@@ -91,6 +91,35 @@ class Kramdown::ANSI < Kramdown::Converter::Base
91
91
  options = { input: :mygfm, auto_ids: false, entity_output: :as_char }.merge(
92
92
  options.transform_keys(&:to_sym)
93
93
  )
94
+ # Insert blank line before GFM pipe tables glued to preceding
95
+ # content; kramdown requires it to parse the table correctly.
96
+ #
97
+ # Matches: a non-table line immediately followed by a table header,
98
+ # a valid GFM separator row, and at least one body row.
99
+ # A two-line "table" (header + separator, no body) is not a table
100
+ # per GFM, so no blank line is inserted.
101
+ source = source.gsub(
102
+ /
103
+ ( [^|\n][^\n]*\n ) # $1: preceding line (not a pipe line)
104
+ ( \|[^\n]*\n ) # $2: table header (starts with |)
105
+ ( \|(?:\s*:?-+:?\s*\|)+\n ) # $3: GFM separator + newline
106
+ ( \|[^\n]* ) # $4: first body row (starts with |)
107
+ \n
108
+ /x,
109
+ "\\1\n\\2\\3\\4\n"
110
+ )
111
+ # Insert blank line after a table's last row when glued to
112
+ # following content; kramdown requires it to close the table.
113
+ source = source.gsub(
114
+ /(\|[^\n]*\n)([^|\n])/,
115
+ ) do |match|
116
+ next_char = Regexp.last_match(2)
117
+ if next_char.match?(/\A\s*:?-+/)
118
+ match
119
+ else
120
+ "#{Regexp.last_match(1)}\n#{next_char}"
121
+ end
122
+ end
94
123
  @doc = Kramdown::Document.new(source, options).to_ansi
95
124
  end
96
125
 
@@ -253,6 +282,28 @@ class Kramdown::ANSI < Kramdown::Converter::Base
253
282
  apply_style(:code) { el.value }
254
283
  end
255
284
 
285
+ BLOCKQUOTE_QUOTES = [
286
+ %w[“ ”],
287
+ %w[‘ ’],
288
+ %w[ » « ],
289
+ %w[ › ‹ ],
290
+ ].map(&:freeze).freeze
291
+ private_constant :BLOCKQUOTE_QUOTES
292
+
293
+ # Wraps the content of a blockquote level with the corresponding
294
+ # typographic quotation marks, cycling through a predefined set of
295
+ # quote pairs based on the nesting depth.
296
+ #
297
+ # @param level [ Integer ] the nesting level of the blockquote
298
+ # @yield [ String ] the inner content to be wrapped in quotation marks
299
+ # @return [ String ] the content enclosed by the appropriate opening and
300
+ # closing quote characters
301
+ def blockquote_quote(level, &block)
302
+ quote = BLOCKQUOTE_QUOTES[level % BLOCKQUOTE_QUOTES.size]
303
+ quote[0] + block.() + quote[1]
304
+ end
305
+ private :blockquote_quote
306
+
256
307
  # The convert_blockquote method processes a blockquote element by applying
257
308
  # proper formatting.
258
309
  #
@@ -266,7 +317,19 @@ class Kramdown::ANSI < Kramdown::Converter::Base
266
317
  # @return [String] the formatted blockquote content with quotation marks and
267
318
  # proper newlines
268
319
  def convert_blockquote(el, opts)
269
- newline ?“ + inner(el, opts).sub(/\n+\z/, '') + ?”
320
+ old_level = opts[:blockquote_level] ||= -1
321
+ level = opts[:blockquote_level] = old_level + 1
322
+ if level.zero?
323
+ newline(
324
+ blockquote_quote(level) {
325
+ apply_style(:blockquote) { inner(el, opts).strip }
326
+ }.gsub(/^/, ' ')
327
+ )
328
+ else
329
+ blockquote_quote(level) { inner(el, opts).strip }.gsub(/^/, ' ')
330
+ end
331
+ ensure
332
+ opts[:blockquote_level] = old_level
270
333
  end
271
334
 
272
335
  # The convert_hr method processes a horizontal rule element by generating a
@@ -373,6 +436,18 @@ class Kramdown::ANSI < Kramdown::Converter::Base
373
436
  apply_style(:em) { inner(el, opts) }
374
437
  elsif el.value == 'b' || el.value == 'strong'
375
438
  apply_style(:strong) { inner(el, opts) }
439
+ elsif el.value == 'ins' || el.value == 'u'
440
+ apply_style(:ins) { inner(el, opts) }
441
+ elsif el.value == 'mark'
442
+ apply_style(:mark) { inner(el, opts) }
443
+ elsif el.value == 'del' || el.value == 's'
444
+ apply_style(:del) { inner(el, opts) }
445
+ elsif el.value == 'tt'
446
+ apply_style(:code) { inner(el, opts) }
447
+ elsif el.value == 'small'
448
+ apply_style(:small) { inner(el, opts) }
449
+ elsif %w[ span sub sup ].include?(el.value)
450
+ inner(el, opts)
376
451
  else
377
452
  ''
378
453
  end
@@ -457,13 +532,22 @@ class Kramdown::ANSI < Kramdown::Converter::Base
457
532
  # addition of the row to the table instance
458
533
  def convert_tr(el, opts)
459
534
  return '' if el.children.empty?
460
- cols = el.children.map { |c| convert(c, opts).strip }
535
+ cols = el.children.map do |c|
536
+ stripped = convert(c, opts).strip
537
+ stripped.empty? ? ' ' : stripped
538
+ end
461
539
  return '' if cols.empty?
462
- col_widths = cols.map { |c| display_width(c).size }
540
+ col_widths = cols.map { |c| display_width(c) }
463
541
  col_widths_sum = col_widths.sum
464
- full_width = width(percentage: 90)
465
- ratios = cols.each_with_index.map { |c, i| col_widths[i] / col_widths_sum.to_f }
466
- wrapped_cols = cols.zip(ratios).map { |c, r| wrap(c, length: r * full_width) }
542
+ full_width = width(percentage: 90)
543
+ ratios = cols.each_with_index.map do |c, i|
544
+ if col_widths_sum.zero?
545
+ 1.0 / cols.size
546
+ else
547
+ col_widths[i] / col_widths_sum.to_f
548
+ end
549
+ end
550
+ wrapped_cols = cols.zip(ratios).map { |c, r| wrap(c, length: r * full_width) }
467
551
  opts[:table] << wrapped_cols
468
552
  ''
469
553
  end
@@ -1,6 +1,11 @@
1
+ # Version information for the Kramdown gem.
2
+ #
3
+ # This module is auto-generated by GemHadar and exposes the
4
+ # current release version as a set of constants. Do not edit it
5
+ # by hand; it is rewritten on every `rake version` invocation.
1
6
  module Kramdown
2
- # Kramdown version
3
- VERSION = '0.5.0'
7
+ # The current version of the Kramdown gem as a String.
8
+ VERSION = '0.6.0'
4
9
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
10
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
11
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -0,0 +1,28 @@
1
+ HTML Elements
2
+
3
+ Emphasis
4
+
5
+ italic i and italic em
6
+
7
+ Strong
8
+
9
+ bold b and bold strong
10
+
11
+ Strikethrough
12
+
13
+ strikethrough and html s tag and del tag
14
+
15
+ Underline
16
+
17
+ Code
18
+
19
+ tt text
20
+
21
+ Mark
22
+
23
+ marked
24
+
25
+ Passthrough (no style)
26
+
27
+ span text and subscript and superscript
28
+ and small text
@@ -0,0 +1,28 @@
1
+ # HTML Elements
2
+
3
+ ## Emphasis
4
+
5
+ <i>italic i</i> and <em>italic em</em>
6
+
7
+ ## Strong
8
+
9
+ <b>bold b</b> and <strong>bold strong</strong>
10
+
11
+ ## Strikethrough
12
+
13
+ ~~strikethrough~~ and <s>html s tag</s> and <del>del tag</del>
14
+
15
+ ## Underline
16
+
17
+ ## Code
18
+
19
+ <tt>tt text</tt>
20
+
21
+ ## Mark
22
+
23
+ <mark>marked</mark>
24
+
25
+ ## Passthrough (no style)
26
+
27
+ <span>span text</span> and <sub>subscript</sub> and <sup>superscript</sup>
28
+ and <small>small text</small>