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 +4 -4
- data/.utilsrc +0 -3
- data/CHANGES.md +68 -0
- data/README.md +10 -5
- data/Rakefile +19 -0
- data/kramdown-ansi.gemspec +7 -6
- data/lib/kramdown/ansi/styles.rb +9 -4
- data/lib/kramdown/ansi/width.rb +89 -17
- data/lib/kramdown/ansi.rb +90 -6
- data/lib/kramdown/version.rb +7 -2
- data/spec/assets/html.ansi +28 -0
- data/spec/assets/html.md +28 -0
- data/spec/assets/tables.ansi +348 -0
- data/spec/assets/tables.md +236 -0
- data/spec/kramdown/ansi/width_spec.rb +90 -0
- data/spec/kramdown/ansi_golden_spec.rb +19 -0
- data/spec/kramdown/ansi_spec.rb +7 -3
- data/spec/kramdown/render_spec.rb +156 -0
- data/spec/spec_helper.rb +33 -0
- data/tmp/.gitkeep +0 -0
- metadata +27 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0e9bbd4a032cd0f37629bc21f4967590fcb7140875fe79687e01f5941cdea10c
|
|
4
|
+
data.tar.gz: 2805ae302ae89c97266f7cfb690ab7a8b87662c6654e802d42ac7b9ae125515c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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:
|
|
51
|
-
strong:
|
|
52
|
-
em:
|
|
53
|
-
code:
|
|
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
|

|
|
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
|
data/kramdown-ansi.gemspec
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: kramdown-ansi 0.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
data/lib/kramdown/ansi/styles.rb
CHANGED
|
@@ -24,10 +24,15 @@ class Kramdown::ANSI::Styles
|
|
|
24
24
|
# configuration.
|
|
25
25
|
def initialize
|
|
26
26
|
@default_ansi_styles = {
|
|
27
|
-
header:
|
|
28
|
-
strong:
|
|
29
|
-
em:
|
|
30
|
-
code:
|
|
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
|
data/lib/kramdown/ansi/width.rb
CHANGED
|
@@ -19,20 +19,24 @@ module Kramdown::ANSI::Width
|
|
|
19
19
|
|
|
20
20
|
module_function
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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(
|
|
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.
|
|
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
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
540
|
+
col_widths = cols.map { |c| display_width(c) }
|
|
463
541
|
col_widths_sum = col_widths.sum
|
|
464
|
-
full_width
|
|
465
|
-
ratios
|
|
466
|
-
|
|
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
|
data/lib/kramdown/version.rb
CHANGED
|
@@ -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
|
|
3
|
-
VERSION = '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
|
+
[1m[4mHTML Elements[0m[0m
|
|
2
|
+
|
|
3
|
+
[1m[4mEmphasis[0m[0m
|
|
4
|
+
|
|
5
|
+
[3mitalic i[0m and [3mitalic em[0m
|
|
6
|
+
|
|
7
|
+
[1m[4mStrong[0m[0m
|
|
8
|
+
|
|
9
|
+
[1mbold b[0m and [1mbold strong[0m
|
|
10
|
+
|
|
11
|
+
[1m[4mStrikethrough[0m[0m
|
|
12
|
+
|
|
13
|
+
[9mstrikethrough[0m and [9mhtml s tag[0m and [9mdel tag[0m
|
|
14
|
+
|
|
15
|
+
[1m[4mUnderline[0m[0m
|
|
16
|
+
|
|
17
|
+
[1m[4mCode[0m[0m
|
|
18
|
+
|
|
19
|
+
[34mtt text[0m
|
|
20
|
+
|
|
21
|
+
[1m[4mMark[0m[0m
|
|
22
|
+
|
|
23
|
+
[7mmarked[0m
|
|
24
|
+
|
|
25
|
+
[1m[4mPassthrough (no style)[0m[0m
|
|
26
|
+
|
|
27
|
+
span text and subscript and superscript
|
|
28
|
+
and [2msmall text[0m
|
data/spec/assets/html.md
ADDED
|
@@ -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>
|