tty-markdown 0.2.0 → 0.3.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/.travis.yml +1 -0
- data/CHANGELOG.md +14 -0
- data/README.md +85 -31
- data/appveyor.yml +2 -0
- data/assets/hr.png +0 -0
- data/assets/link.png +0 -0
- data/assets/quote.png +0 -0
- data/assets/table.png +0 -0
- data/examples/marked.rb +1 -1
- data/lib/tty/markdown.rb +3 -3
- data/lib/tty/markdown/parser.rb +112 -33
- data/lib/tty/markdown/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78fdb3db2ddf8fcb253d3f2b7fd48ce85f34db5b
|
4
|
+
data.tar.gz: b4176a98f2e6238a0b9d1d3eb32585610750a4b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4ddf759c61068a151a2e07ad973fa0268ea671be2006ce1ae0fbd5d4aca6f823d0d682bd005af1473d75dd88b61fa69ac9ab5cc23576773b79b546b5651c232
|
7
|
+
data.tar.gz: 1fa053194d9f4ad41366a4b592888184668f4ea4be628d9cf57e79a296f60b90baaacbac4a8b5df3ed94b29f3baae29268103e7dc3b8328b5a5ecc7cd8547ee4
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.3.0] - 2018-03-17
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add :width option to allow setting maximum display width
|
7
|
+
* Add :colors options for specifying rendering colors capabilities
|
8
|
+
* Add ability to parse multiline table content
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
* Change color scheme to replace table and links blue with yellow
|
12
|
+
|
13
|
+
## Fixed
|
14
|
+
* Fix issue with multiline blockquote elements raising NoMethodError
|
15
|
+
|
3
16
|
## [v0.2.0] - 2018-01-29
|
4
17
|
|
5
18
|
### Added
|
@@ -19,5 +32,6 @@
|
|
19
32
|
|
20
33
|
* Initial implementation and release
|
21
34
|
|
35
|
+
[v0.3.0]: https://github.com/piotrmurach/tty-markdown/compare/v0.2.0...v0.3.0
|
22
36
|
[v0.2.0]: https://github.com/piotrmurach/tty-markdown/compare/v0.1.0...v0.2.0
|
23
37
|
[v0.1.0]: https://github.com/piotrmurach/tty-markdown/compare/v0.1.0
|
data/README.md
CHANGED
@@ -39,13 +39,17 @@ Or install it yourself as:
|
|
39
39
|
## Contents
|
40
40
|
|
41
41
|
* [1. Usage](#1-usage)
|
42
|
-
* [1.1
|
43
|
-
* [1.2
|
44
|
-
* [1.3
|
45
|
-
* [1.4
|
46
|
-
* [1.5
|
42
|
+
* [1.1 Header](#11-header)
|
43
|
+
* [1.2 List](#12-list)
|
44
|
+
* [1.3 Link](#13-link)
|
45
|
+
* [1.4 Blockquote](#14-blockquote)
|
46
|
+
* [1.5 Code and Syntax Highlighting](#15-code-and-syntax-highlighting)
|
47
|
+
* [1.6 Table](#16-table)
|
48
|
+
* [1.7 Horizontal Rule](#17-horizontal-rule)
|
47
49
|
* [2. Options](#2-options)
|
48
|
-
* [2.1 :
|
50
|
+
* [2.1 :colors](#21-colors)
|
51
|
+
* [2.2 :theme](#22-theme)
|
52
|
+
* [2.3 :width](#23-width)
|
49
53
|
|
50
54
|
## 1. Usage
|
51
55
|
|
@@ -64,7 +68,30 @@ parsed = TTY::Markdown.parse('example.md')
|
|
64
68
|
puts parsed
|
65
69
|
```
|
66
70
|
|
67
|
-
### 1.1
|
71
|
+
### 1.1 Header
|
72
|
+
|
73
|
+
```markdown
|
74
|
+
TTY::Markdown
|
75
|
+
=============
|
76
|
+
|
77
|
+
**tty-markdown** converts markdown document into a terminal friendly output.
|
78
|
+
|
79
|
+
## Examples
|
80
|
+
|
81
|
+
### Nested list items
|
82
|
+
```
|
83
|
+
|
84
|
+
and transforming it:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
parsed = TTY::Markdown.parse(markdown_string)
|
88
|
+
```
|
89
|
+
|
90
|
+
`puts parsed` will output:
|
91
|
+
|
92
|
+

|
93
|
+
|
94
|
+
### 1.2 List
|
68
95
|
|
69
96
|
Both numbered and unordered lists are supported. Given a markdown:
|
70
97
|
|
@@ -86,30 +113,19 @@ parsed = TTY::Markdown.parse(markdown_string)
|
|
86
113
|
|
87
114
|

|
88
115
|
|
89
|
-
### 1.
|
90
|
-
|
91
|
-
```markdown
|
92
|
-
TTY::Markdown
|
93
|
-
=============
|
94
|
-
|
95
|
-
**tty-markdown** converts markdown document into a terminal friendly output.
|
96
|
-
|
97
|
-
## Examples
|
98
|
-
|
99
|
-
### Nested list items
|
100
|
-
```
|
116
|
+
### 1.3 Link
|
101
117
|
|
102
|
-
|
118
|
+
A mardown link:
|
103
119
|
|
104
|
-
```
|
105
|
-
|
120
|
+
```markdown
|
121
|
+
[I'm an inline-style link](https://www.google.com)
|
106
122
|
```
|
107
123
|
|
108
|
-
|
124
|
+
will be rendered with actual link content next to it:
|
109
125
|
|
110
|
-

|
111
127
|
|
112
|
-
### 1.
|
128
|
+
### 1.4 Blockquote
|
113
129
|
|
114
130
|
Given a markdown quote:
|
115
131
|
|
@@ -129,7 +145,7 @@ parsed = TTY::Markdown.parse(markdown_string)
|
|
129
145
|
|
130
146
|

|
131
147
|
|
132
|
-
### 1.
|
148
|
+
### 1.5 Code and Syntax Highlighting
|
133
149
|
|
134
150
|
The parser can highlight syntax of many programming languages. Given the markdown codeblock with language specification:
|
135
151
|
|
@@ -153,7 +169,7 @@ parsed = TTY::Markdown.parse(code_snippet)
|
|
153
169
|
|
154
170
|

|
155
171
|
|
156
|
-
### 1.
|
172
|
+
### 1.6 Table
|
157
173
|
|
158
174
|
You can transform tables which understand the markdown alignment.
|
159
175
|
|
@@ -177,21 +193,49 @@ parsed = TTY::Markdown.parse(markdown_string)
|
|
177
193
|
|
178
194
|

|
179
195
|
|
196
|
+
### 1.7 Horizontal Rule
|
197
|
+
|
198
|
+
You can specify a horizontal rule in markdown:
|
199
|
+
|
200
|
+
```markdown
|
201
|
+
***
|
202
|
+
```
|
203
|
+
|
204
|
+
and then transform it:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
parsed = TTY::Markdown.parse(markdown_string)
|
208
|
+
```
|
209
|
+
|
210
|
+
`puts parsed` will output:
|
211
|
+
|
212
|
+

|
213
|
+
|
180
214
|
## 2. Options
|
181
215
|
|
182
|
-
### 2.1 `:
|
216
|
+
### 2.1 `:colors`
|
217
|
+
|
218
|
+
By default the `256` colors scheme is used to render code block elements. You can change that by specifying desired number of colors:
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
TTY::Markdown.pasre(markdown_string, colors: 16)
|
222
|
+
```
|
223
|
+
|
224
|
+
This feauture may be handy when working in terminals with limited color support. By default, **TTY::Markdown** detects your terminal color mode and adjusts output automatically.
|
225
|
+
|
226
|
+
### 2.2 `:theme`
|
183
227
|
|
184
228
|
A hash of styles that allows to customize specific elements of the markdown text. By default the following styles are used:
|
185
229
|
|
186
230
|
```ruby
|
187
231
|
THEME = {
|
188
|
-
em: :
|
232
|
+
em: :yellow,
|
189
233
|
header: [:cyan, :bold],
|
190
234
|
hr: :yellow,
|
191
|
-
link: [:
|
235
|
+
link: [:yellow, :underline],
|
192
236
|
list: :yellow,
|
193
237
|
strong: [:yellow, :bold],
|
194
|
-
table: :
|
238
|
+
table: :yellow,
|
195
239
|
quote: :yellow,
|
196
240
|
}
|
197
241
|
```
|
@@ -202,6 +246,16 @@ In order to provide new styles use `:theme` key:
|
|
202
246
|
TTY::Markdown.parse(markdown_string, theme: { ... })
|
203
247
|
```
|
204
248
|
|
249
|
+
### 2.3 `:width`
|
250
|
+
|
251
|
+
You can easily control the maximum width of the output by using the `:width` key:
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
TTY::Markdown.parse(markdown_string, width: 80)
|
255
|
+
```
|
256
|
+
|
257
|
+
By default the terminal screen width is used.
|
258
|
+
|
205
259
|
## Development
|
206
260
|
|
207
261
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/appveyor.yml
CHANGED
data/assets/hr.png
ADDED
Binary file
|
data/assets/link.png
ADDED
Binary file
|
data/assets/quote.png
CHANGED
Binary file
|
data/assets/table.png
CHANGED
Binary file
|
data/examples/marked.rb
CHANGED
data/lib/tty/markdown.rb
CHANGED
@@ -66,13 +66,13 @@ module TTY
|
|
66
66
|
}.freeze
|
67
67
|
|
68
68
|
THEME = {
|
69
|
-
em: :
|
69
|
+
em: :yellow,
|
70
70
|
header: [:cyan, :bold],
|
71
71
|
hr: :yellow,
|
72
|
-
link: [:
|
72
|
+
link: [:yellow, :underline],
|
73
73
|
list: :yellow,
|
74
74
|
strong: [:yellow, :bold],
|
75
|
-
table: :
|
75
|
+
table: :yellow,
|
76
76
|
quote: :yellow,
|
77
77
|
}.freeze
|
78
78
|
|
data/lib/tty/markdown/parser.rb
CHANGED
@@ -18,7 +18,7 @@ module TTY
|
|
18
18
|
@current_indent = 0
|
19
19
|
@indent = options.fetch(:indent, 2)
|
20
20
|
@pastel = Pastel.new
|
21
|
-
@color_opts = {mode: options[:colors]}
|
21
|
+
@color_opts = { mode: options[:colors] }
|
22
22
|
@width = options.fetch(:width) { TTY::Screen.width }
|
23
23
|
@theme = options.fetch(:theme) { TTY::Markdown::THEME }
|
24
24
|
end
|
@@ -26,7 +26,7 @@ module TTY
|
|
26
26
|
# Invoke an element conversion
|
27
27
|
#
|
28
28
|
# @api public
|
29
|
-
def convert(el, opts = {indent: 0, result: []})
|
29
|
+
def convert(el, opts = { indent: 0, result: [] })
|
30
30
|
send("convert_#{el.type}", el, opts)
|
31
31
|
end
|
32
32
|
|
@@ -64,6 +64,7 @@ module TTY
|
|
64
64
|
def convert_p(el, opts)
|
65
65
|
result_before = @stack.last[1][:result].dup
|
66
66
|
indent = ' ' * @current_indent
|
67
|
+
|
67
68
|
if opts[:parent].type != :blockquote
|
68
69
|
opts[:result] << indent
|
69
70
|
end
|
@@ -88,12 +89,21 @@ module TTY
|
|
88
89
|
end
|
89
90
|
end
|
90
91
|
|
92
|
+
# Format current element by inserting prefix for each
|
93
|
+
# quoted line within the allowed screen size.
|
94
|
+
#
|
95
|
+
# @param [Array[String]] result_before
|
96
|
+
# @param [Array[String]] result
|
97
|
+
#
|
98
|
+
# @return [nil]
|
99
|
+
#
|
100
|
+
# @api private
|
91
101
|
def format_blockquote(result_before, result)
|
92
102
|
indent = ' ' * @current_indent
|
93
103
|
start_index = result_before.size
|
94
104
|
max_index = result.size - 1
|
95
105
|
bar_symbol = TTY::Markdown.symbols[:bar]
|
96
|
-
styles
|
106
|
+
styles = Array(@theme[:quote])
|
97
107
|
prefix = "#{indent}#{@pastel.decorate(bar_symbol, *styles)} "
|
98
108
|
|
99
109
|
result.map!.with_index do |str, i|
|
@@ -101,14 +111,15 @@ module TTY
|
|
101
111
|
str.insert(0, prefix)
|
102
112
|
end
|
103
113
|
|
104
|
-
|
114
|
+
# only modify blockquote element
|
115
|
+
if i >= start_index && str.to_s.include?("\n") # multiline string found
|
105
116
|
str.lines.map! do |line|
|
106
|
-
if line != str.lines.last || i < max_index
|
107
|
-
line.insert(-1, prefix)
|
117
|
+
if (line != str.lines.last || i < max_index)
|
118
|
+
line.insert(-1, line.end_with?("\n") ? prefix : "\n" + prefix)
|
108
119
|
else
|
109
120
|
line
|
110
121
|
end
|
111
|
-
end
|
122
|
+
end.join
|
112
123
|
else
|
113
124
|
str
|
114
125
|
end
|
@@ -117,19 +128,19 @@ module TTY
|
|
117
128
|
|
118
129
|
def convert_text(el, opts)
|
119
130
|
text = el.value
|
120
|
-
opts[:result] << text
|
131
|
+
opts[:result] << Strings.wrap(text, @width)
|
121
132
|
end
|
122
133
|
|
123
134
|
def convert_strong(el, opts)
|
124
135
|
styles = Array(@theme[:strong])
|
125
|
-
opts[:result] <<
|
136
|
+
opts[:result] << @pastel.lookup(*styles)
|
126
137
|
inner(el, opts)
|
127
138
|
opts[:result] << @pastel.lookup(:reset)
|
128
139
|
end
|
129
140
|
|
130
141
|
def convert_em(el, opts)
|
131
142
|
styles = Array(@theme[:em])
|
132
|
-
opts[:result] <<
|
143
|
+
opts[:result] << @pastel.lookup(*styles)
|
133
144
|
inner(el, opts)
|
134
145
|
opts[:result] << @pastel.lookup(:reset)
|
135
146
|
end
|
@@ -143,10 +154,10 @@ module TTY
|
|
143
154
|
end
|
144
155
|
|
145
156
|
def convert_codespan(el, opts)
|
146
|
-
raw_code = el.value
|
157
|
+
raw_code = Strings.wrap(el.value, @width)
|
147
158
|
highlighted = SyntaxHighliter.highlight(raw_code, @color_opts.merge(opts))
|
148
159
|
code = highlighted.split("\n").map.with_index do |line, i|
|
149
|
-
if i
|
160
|
+
if i.zero? # first line
|
150
161
|
line
|
151
162
|
else
|
152
163
|
line.insert(0, ' ' * @current_indent)
|
@@ -227,7 +238,7 @@ module TTY
|
|
227
238
|
symbols = TTY::Markdown.symbols
|
228
239
|
result = []
|
229
240
|
result << symbols[:"#{location}_left"]
|
230
|
-
max_widths(table_data).each.with_index do |width, i|
|
241
|
+
distribute_widths(max_widths(table_data)).each.with_index do |width, i|
|
231
242
|
result << symbols[:"#{location}_center"] if i != 0
|
232
243
|
result << (symbols[:line] * (width + 2))
|
233
244
|
end
|
@@ -256,13 +267,11 @@ module TTY
|
|
256
267
|
end
|
257
268
|
|
258
269
|
def convert_tfoot(el, opts)
|
259
|
-
|
270
|
+
inner(el, opts)
|
260
271
|
end
|
261
272
|
|
262
273
|
def convert_tr(el, opts)
|
263
274
|
indent = ' ' * @current_indent
|
264
|
-
pipe = TTY::Markdown.symbols[:pipe]
|
265
|
-
styles = Array(@theme[:table])
|
266
275
|
table_data = opts[:table_data]
|
267
276
|
|
268
277
|
if opts[:prev] && opts[:prev].type == :tr
|
@@ -271,39 +280,95 @@ module TTY
|
|
271
280
|
opts[:result] << "\n"
|
272
281
|
end
|
273
282
|
|
274
|
-
opts[:
|
283
|
+
opts[:cells] = []
|
284
|
+
|
275
285
|
inner(el, opts)
|
276
|
-
|
286
|
+
|
287
|
+
columns = table_data.first.count
|
288
|
+
|
289
|
+
row = opts[:cells].each_with_index.reduce([]) do |acc, (cell, i)|
|
290
|
+
if cell.size > 1 # multiline
|
291
|
+
cell.each_with_index do |c, j| # zip columns
|
292
|
+
acc[j] = [] if acc[j].nil?
|
293
|
+
acc[j] << c.chomp
|
294
|
+
acc[j] << "\n" if i == (columns - 1)
|
295
|
+
end
|
296
|
+
else
|
297
|
+
acc << cell
|
298
|
+
acc << "\n" if i == (columns - 1)
|
299
|
+
end
|
300
|
+
acc
|
301
|
+
end.join
|
302
|
+
|
303
|
+
opts[:result] << row
|
277
304
|
end
|
278
305
|
|
279
306
|
def convert_td(el, opts)
|
280
|
-
|
281
|
-
|
307
|
+
indent = ' ' * @current_indent
|
308
|
+
pipe = TTY::Markdown.symbols[:pipe]
|
309
|
+
styles = Array(@theme[:table])
|
282
310
|
table_data = opts[:table_data]
|
283
|
-
result
|
311
|
+
result = opts[:cells]
|
312
|
+
suffix = " #{@pastel.decorate(pipe, *styles)} "
|
284
313
|
opts[:result] = []
|
285
314
|
|
286
315
|
inner(el, opts)
|
287
316
|
|
288
|
-
column =
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
317
|
+
row, column = *find_row_column(table_data, opts[:result])
|
318
|
+
cell_widths = distribute_widths(max_widths(table_data))
|
319
|
+
cell_width = cell_widths[column]
|
320
|
+
cell_height = max_height(table_data, row, cell_widths)
|
321
|
+
alignment = opts[:alignment][column]
|
322
|
+
align_opts = alignment == :default ? {} : { direction: alignment }
|
323
|
+
|
324
|
+
wrapped = Strings.wrap(opts[:result].join, cell_width)
|
325
|
+
aligned = Strings.align(wrapped, cell_width, align_opts)
|
326
|
+
padded = if aligned.lines.size < cell_height
|
327
|
+
Strings.pad(aligned, [0, 0, cell_height - aligned.lines.size, 0])
|
328
|
+
else
|
329
|
+
aligned.dup
|
330
|
+
end
|
331
|
+
|
332
|
+
result << padded.lines.map do |line|
|
333
|
+
# add pipe to first column
|
334
|
+
(column.zero? ? indent + @pastel.decorate("#{pipe} ", *styles) : '') +
|
335
|
+
(line.end_with?("\n") ? line.insert(-2, suffix) : line << suffix)
|
336
|
+
end
|
295
337
|
end
|
296
338
|
|
297
|
-
|
298
|
-
|
339
|
+
# Find row and column indexes
|
340
|
+
#
|
341
|
+
# @return [Array[Integer, Integer]]
|
342
|
+
#
|
343
|
+
# @api private
|
344
|
+
def find_row_column(table_data, cell)
|
345
|
+
table_data.each_with_index do |row, row_no|
|
299
346
|
row.size.times do |col|
|
300
|
-
return col if row[col] == cell
|
347
|
+
return [row_no, col] if row[col] == cell
|
301
348
|
end
|
302
349
|
end
|
303
350
|
end
|
304
351
|
|
352
|
+
# Calculate maximum cell width for a given column
|
353
|
+
#
|
354
|
+
# @return [Integer]
|
355
|
+
#
|
356
|
+
# @api private
|
305
357
|
def max_width(table_data, col)
|
306
|
-
table_data.map
|
358
|
+
table_data.map do |row|
|
359
|
+
Strings.sanitize(row[col].join).lines.map(&:length).max
|
360
|
+
end.max
|
361
|
+
end
|
362
|
+
|
363
|
+
# Calculate maximum cell height for a given row
|
364
|
+
#
|
365
|
+
# @return [Integer]
|
366
|
+
#
|
367
|
+
# @api private
|
368
|
+
def max_height(table_data, row, cell_widths)
|
369
|
+
table_data[row].map.with_index do |col, i|
|
370
|
+
Strings.wrap(col.join, cell_widths[i]).lines.size
|
371
|
+
end.max
|
307
372
|
end
|
308
373
|
|
309
374
|
def max_widths(table_data)
|
@@ -313,10 +378,24 @@ module TTY
|
|
313
378
|
end
|
314
379
|
end
|
315
380
|
|
381
|
+
def distribute_widths(widths)
|
382
|
+
indent = ' ' * @current_indent
|
383
|
+
total_width = widths.reduce(&:+)
|
384
|
+
screen_width = @width - (indent.length + 1) * 2 - (widths.size + 1)
|
385
|
+
return widths if total_width <= screen_width
|
386
|
+
|
387
|
+
extra_width = total_width - screen_width
|
388
|
+
|
389
|
+
widths.map do |w|
|
390
|
+
ratio = w / total_width.to_f
|
391
|
+
w - (extra_width * ratio).floor
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
316
395
|
def convert_hr(el, opts)
|
317
396
|
indent = ' ' * @current_indent
|
318
397
|
symbols = TTY::Markdown.symbols
|
319
|
-
width = @width - (indent.length+1) * 2
|
398
|
+
width = @width - (indent.length + 1) * 2
|
320
399
|
styles = Array(@theme[:hr])
|
321
400
|
line = symbols[:diamond] + symbols[:line] * width + symbols[:diamond]
|
322
401
|
|
data/lib/tty/markdown/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tty-markdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kramdown
|
@@ -153,6 +153,8 @@ files:
|
|
153
153
|
- Rakefile
|
154
154
|
- appveyor.yml
|
155
155
|
- assets/headers.png
|
156
|
+
- assets/hr.png
|
157
|
+
- assets/link.png
|
156
158
|
- assets/list.png
|
157
159
|
- assets/quote.png
|
158
160
|
- assets/syntax_highlight.png
|