kramdown-ansi 0.5.0 → 0.7.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 +94 -0
- data/README.md +10 -5
- data/Rakefile +20 -1
- 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 +101 -6
- data/lib/kramdown/version.rb +7 -2
- data/scripts/capture-ansi +3 -0
- data/spec/assets/html.ansi +28 -0
- data/spec/assets/html.md +28 -0
- data/spec/assets/tables.ansi +345 -0
- data/spec/assets/tables.md +241 -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 +28 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Kramdown::ANSI golden files' do
|
|
4
|
+
before do
|
|
5
|
+
allow(Tins::Terminal).to receive(:columns).and_return 80
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
Dir[File.join(__dir__, '../assets/*.md')].each do |md|
|
|
9
|
+
name = File.basename(md, '.md')
|
|
10
|
+
expected_path = md.sub('.md', '.ansi')
|
|
11
|
+
|
|
12
|
+
it "renders #{name} matching golden file" do
|
|
13
|
+
skip "no golden file at #{expected_path}" unless File.exist?(expected_path)
|
|
14
|
+
expected = File.read(expected_path)
|
|
15
|
+
actual = Kramdown::ANSI.parse(File.read(md))
|
|
16
|
+
expect(actual).to eq(expected)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/spec/kramdown/ansi_spec.rb
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
describe Kramdown::ANSI do
|
|
2
|
+
before do
|
|
3
|
+
allow(Tins::Terminal).to receive(:columns).and_return 80
|
|
4
|
+
end
|
|
5
|
+
|
|
2
6
|
let :source do
|
|
3
7
|
File.read(Pathname.new(__dir__) + '..' + '..' + 'README.md')
|
|
4
8
|
end
|
|
@@ -8,9 +12,9 @@ describe Kramdown::ANSI do
|
|
|
8
12
|
ansi = described_class.parse(source)
|
|
9
13
|
expect(ansi).to include("\e[1m\e[4mDescription\e[0m\e[0m")
|
|
10
14
|
expect(ansi).to include("\e[1mKramdown::ANSI\e[0m")
|
|
11
|
-
expect(ansi).to include("\e[3min the\nterminal\e[0m") # wrap adds linebreak
|
|
12
15
|
expect(ansi).to include("\e[34mgem install kramdown-ansi\n\e[0m")
|
|
13
16
|
expect(ansi).to include("\e[34mbundle install\e[0m")
|
|
17
|
+
expect(ansi).to include("Dialog:\n “\e[2mWhat's that, Fluffy?\n ‘That's my new friend.’\e[0m”")
|
|
14
18
|
expect(ansi).to include("This is the end.")
|
|
15
19
|
output.puts ansi
|
|
16
20
|
end
|
|
@@ -23,13 +27,13 @@ describe Kramdown::ANSI do
|
|
|
23
27
|
strong: %i[ green ],
|
|
24
28
|
em: %i[ yellow ],
|
|
25
29
|
code: %i[ bold color208 ],
|
|
30
|
+
blockquote: %i[ magenta ],
|
|
26
31
|
)
|
|
27
32
|
ansi = described_class.parse(source, ansi_styles:)
|
|
28
33
|
expect(ansi).to include("\e[31m\e[4mDescription\e[0m\e[0")
|
|
29
34
|
expect(ansi).to include("\e[32mKramdown::ANSI\e[0m")
|
|
30
|
-
expect(ansi).to include("\e[33min the\nterminal\e[0m") # wrap adds linebreak
|
|
31
35
|
expect(ansi).to include("\e[1m\e[38;5;208mgem install kramdown-ansi\n\e[0m\e[0m")
|
|
32
|
-
expect(ansi).to include("
|
|
36
|
+
expect(ansi).to include("Dialog:\n “\e[35mWhat's that, Fluffy?\n ‘That's my new friend.’\e[0m”")
|
|
33
37
|
expect(ansi).to include("This is the end.")
|
|
34
38
|
output.puts ansi
|
|
35
39
|
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Kramdown::ANSI rendering' do
|
|
4
|
+
before do
|
|
5
|
+
allow(Tins::Terminal).to receive(:columns).and_return 80
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
subject(:render) { Kramdown::ANSI.parse(md) }
|
|
9
|
+
|
|
10
|
+
describe 'headers' do
|
|
11
|
+
context 'level 1' do
|
|
12
|
+
let(:md) { "# Hello\n" }
|
|
13
|
+
it 'applies bold+underline' do
|
|
14
|
+
expect(render).to eq "\e[1m\e[4mHello\e[0m\e[0m\n"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context 'level 2' do
|
|
19
|
+
let(:md) { "## World\n" }
|
|
20
|
+
it 'applies bold+underline' do
|
|
21
|
+
expect(render).to eq "\e[1m\e[4mWorld\e[0m\e[0m\n"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'level 3' do
|
|
26
|
+
let(:md) { "### Deep\n" }
|
|
27
|
+
it 'applies bold+underline' do
|
|
28
|
+
expect(render).to eq "\e[1m\e[4mDeep\e[0m\e[0m\n"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe 'inline emphasis' do
|
|
34
|
+
context 'strong' do
|
|
35
|
+
let(:md) { "This is **bold** text.\n" }
|
|
36
|
+
it 'wraps in bold' do
|
|
37
|
+
expect(render).to eq "This is \e[1mbold\e[0m text.\n"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context 'emphasis' do
|
|
42
|
+
let(:md) { "This is *italic* text.\n" }
|
|
43
|
+
it 'wraps in italic' do
|
|
44
|
+
expect(render).to eq "This is \e[3mitalic\e[0m text.\n"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context 'strikethrough' do
|
|
49
|
+
let(:md) { "This is ~~gone~~ text.\n" }
|
|
50
|
+
it 'wraps in strikethrough' do
|
|
51
|
+
expect(render).to eq "This is \e[9mgone\e[0m text.\n"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'code span' do
|
|
56
|
+
let(:md) { "Use `puts` here.\n" }
|
|
57
|
+
it 'wraps in blue' do
|
|
58
|
+
expect(render).to eq "Use \e[34mputs\e[0m here.\n"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'mixed inline' do
|
|
63
|
+
let(:md) { "A **bold** and *em* and `code` word.\n" }
|
|
64
|
+
it 'applies each style independently' do
|
|
65
|
+
expect(render).to eq(
|
|
66
|
+
"A \e[1mbold\e[0m and \e[3mem\e[0m and \e[34mcode\e[0m word.\n"
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe 'code blocks' do
|
|
73
|
+
context 'fenced with language' do
|
|
74
|
+
let(:md) { "```ruby\nputs \"hi\"\n```\n" }
|
|
75
|
+
it 'applies code style to content' do
|
|
76
|
+
expect(render).to eq "\e[34mputs \"hi\"\n\e[0m"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context 'fenced without language' do
|
|
81
|
+
let(:md) { "```\nplain code\n```\n" }
|
|
82
|
+
it 'applies code style to content' do
|
|
83
|
+
expect(render).to eq "\e[34mplain code\n\e[0m"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe 'blockquotes' do
|
|
89
|
+
context 'single level' do
|
|
90
|
+
let(:md) { "> quoted line\n" }
|
|
91
|
+
it 'wraps in faint + double quotes' do
|
|
92
|
+
expect(render).to eq " “\e[2mquoted line\e[0m”\n"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context 'nested' do
|
|
97
|
+
let(:md) { "> > nested\n" }
|
|
98
|
+
it 'cycles to single quotes for inner level' do
|
|
99
|
+
expect(render).to eq " “\e[2m‘nested’\e[0m”\n"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe 'horizontal rule' do
|
|
105
|
+
let(:md) { "---\n" }
|
|
106
|
+
it 'renders full-width unicode line' do
|
|
107
|
+
expect(render).to eq((?─ * 80) + "\n")
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
describe 'lists' do
|
|
112
|
+
context 'unordered' do
|
|
113
|
+
let(:md) { "- one\n- two\n" }
|
|
114
|
+
it 'prefixes with bullet' do
|
|
115
|
+
expect(render).to eq "· one\n\n· two\n\n"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
context 'ordered' do
|
|
120
|
+
let(:md) { "1. first\n2. second\n" }
|
|
121
|
+
it 'prefixes with sequential numbers' do
|
|
122
|
+
expect(render).to eq "1. first\n\n2. second\n\n"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
context 'nested unordered' do
|
|
127
|
+
let(:md) { "- one\n - sub\n- two\n" }
|
|
128
|
+
it 'indents nested items by 2 spaces' do
|
|
129
|
+
expect(render).to eq "· one\n\n · sub\n \n\n· two\n\n"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe 'links' do
|
|
135
|
+
let(:md) { "[click](https://example.com)\n" }
|
|
136
|
+
it 'emits OSC 8 hyperlink' do
|
|
137
|
+
expect(render).to eq "\e]8;;https://example.com\e\\click\e]8;;\e\\\n"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe 'images' do
|
|
142
|
+
let(:md) { "\n" }
|
|
143
|
+
it 'prepends emoji and emits OSC 8 hyperlink' do
|
|
144
|
+
expect(render).to eq "\e]8;;kitten.jpg\e\\🖼 kitten\e]8;;\e\\\n"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
describe 'paragraph' do
|
|
149
|
+
context 'plain text' do
|
|
150
|
+
let(:md) { "Just a paragraph.\n" }
|
|
151
|
+
it 'outputs verbatim with trailing newline' do
|
|
152
|
+
expect(render).to eq "Just a paragraph.\n"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -73,3 +73,36 @@ end
|
|
|
73
73
|
def asset(name)
|
|
74
74
|
File.join(__dir__, 'assets', name)
|
|
75
75
|
end
|
|
76
|
+
|
|
77
|
+
# A module that provides functionality for protecting environment variables
|
|
78
|
+
# during tests.
|
|
79
|
+
#
|
|
80
|
+
# This module ensures that environment variable changes made during test
|
|
81
|
+
# execution are automatically restored to their original values after the test
|
|
82
|
+
# completes. It is designed to prevent side effects between tests that modify
|
|
83
|
+
# environment variables, maintaining a clean testing environment.
|
|
84
|
+
module ProtectEnvVars
|
|
85
|
+
# The apply method creates a lambda that protects environment variables
|
|
86
|
+
# during test execution.
|
|
87
|
+
#
|
|
88
|
+
# @return [Proc] a lambda that wraps test execution with environment variable
|
|
89
|
+
# preservation
|
|
90
|
+
def self.apply
|
|
91
|
+
-> example do
|
|
92
|
+
if example.metadata[:protect_env]
|
|
93
|
+
begin
|
|
94
|
+
stored_env = ENV.to_h
|
|
95
|
+
example.run
|
|
96
|
+
ensure
|
|
97
|
+
ENV.replace(stored_env)
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
example.run
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
RSpec.configure do |config|
|
|
107
|
+
config.around(&ProtectEnvVars.apply)
|
|
108
|
+
end
|
data/tmp/.gitkeep
ADDED
|
File without changes
|
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.
|
|
4
|
+
version: 0.7.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.
|
|
18
|
+
version: 2.20.1
|
|
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.
|
|
25
|
+
version: 2.20.1
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: all_images
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,6 +121,20 @@ dependencies:
|
|
|
121
121
|
- - "~>"
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
123
|
version: '4.0'
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: tins
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '1.61'
|
|
131
|
+
type: :runtime
|
|
132
|
+
prerelease: false
|
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - "~>"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '1.61'
|
|
124
138
|
- !ruby/object:Gem::Dependency
|
|
125
139
|
name: json
|
|
126
140
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -181,14 +195,22 @@ files:
|
|
|
181
195
|
- lib/kramdown/ansi/styles.rb
|
|
182
196
|
- lib/kramdown/ansi/width.rb
|
|
183
197
|
- lib/kramdown/version.rb
|
|
198
|
+
- scripts/capture-ansi
|
|
184
199
|
- spec/assets/README.ansi
|
|
200
|
+
- spec/assets/html.ansi
|
|
201
|
+
- spec/assets/html.md
|
|
185
202
|
- spec/assets/kitten.jpg
|
|
203
|
+
- spec/assets/tables.ansi
|
|
204
|
+
- spec/assets/tables.md
|
|
186
205
|
- spec/kramdown/ansi/pager_spec.rb
|
|
187
206
|
- spec/kramdown/ansi/styles_spec.rb
|
|
188
207
|
- spec/kramdown/ansi/width_spec.rb
|
|
208
|
+
- spec/kramdown/ansi_golden_spec.rb
|
|
189
209
|
- spec/kramdown/ansi_spec.rb
|
|
190
210
|
- spec/kramdown/ansi_table_spec.rb
|
|
211
|
+
- spec/kramdown/render_spec.rb
|
|
191
212
|
- spec/spec_helper.rb
|
|
213
|
+
- tmp/.gitkeep
|
|
192
214
|
homepage: https://github.com/flori/kramdown-ansi
|
|
193
215
|
licenses:
|
|
194
216
|
- MIT
|
|
@@ -211,13 +233,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
211
233
|
- !ruby/object:Gem::Version
|
|
212
234
|
version: '0'
|
|
213
235
|
requirements: []
|
|
214
|
-
rubygems_version: 4.0.
|
|
236
|
+
rubygems_version: 4.0.22
|
|
215
237
|
specification_version: 4
|
|
216
238
|
summary: Output markdown in the terminal with ANSI escape sequences
|
|
217
239
|
test_files:
|
|
218
240
|
- spec/kramdown/ansi/pager_spec.rb
|
|
219
241
|
- spec/kramdown/ansi/styles_spec.rb
|
|
220
242
|
- spec/kramdown/ansi/width_spec.rb
|
|
243
|
+
- spec/kramdown/ansi_golden_spec.rb
|
|
221
244
|
- spec/kramdown/ansi_spec.rb
|
|
222
245
|
- spec/kramdown/ansi_table_spec.rb
|
|
246
|
+
- spec/kramdown/render_spec.rb
|
|
223
247
|
- spec/spec_helper.rb
|