mdless 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mdless/console.rb +653 -0
- data/lib/mdless/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cc069a55f00ad3b4165a8001caac96382742d1cb653ceb20b45402a76d2ec22
|
4
|
+
data.tar.gz: 1e9749a769176d7c9513c61d5edf51332525282e4067a4b63612028d05f89a3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee64552eeb8c46715bcda2a3ce812affc8988837deacbc70fd856c426fc280108b561f5c2c005c2354cf02e1f09821441df8f0a1331bbf31c5c59e3991f73a70
|
7
|
+
data.tar.gz: 409a8507a1e6419aa2e408872a16a68af8e53e0d5b23594c0cec3175259d35b63474dd39428de78654a7b249cc914f23c03926768210e239de39bf6a8b1a6d06
|
@@ -0,0 +1,653 @@
|
|
1
|
+
module Redcarpet
|
2
|
+
module Render
|
3
|
+
class Console < Base
|
4
|
+
include CLIMarkdown::Colors
|
5
|
+
include CLIMarkdown::Theme
|
6
|
+
attr_writer :theme, :cols, :log, :options, :file
|
7
|
+
|
8
|
+
@@listitemid = 0
|
9
|
+
@@listid = 0
|
10
|
+
@@footnotes = []
|
11
|
+
|
12
|
+
def xc
|
13
|
+
x + color('text')
|
14
|
+
end
|
15
|
+
|
16
|
+
def x
|
17
|
+
c([:reset])
|
18
|
+
end
|
19
|
+
|
20
|
+
def color_table(input)
|
21
|
+
first = true
|
22
|
+
input.split(/\n/).map do |line|
|
23
|
+
if first
|
24
|
+
if line =~ /^\+-+/
|
25
|
+
line.gsub!(/^/, color('table border'))
|
26
|
+
else
|
27
|
+
first = false
|
28
|
+
line.gsub!(/\|/, "#{color('table border')}|#{color('table header')}")
|
29
|
+
end
|
30
|
+
elsif line.strip =~ /^[|:\- +]+$/
|
31
|
+
line.gsub!(/^(.*)$/, "#{color('table border')}\\1#{color('table color')}")
|
32
|
+
line.gsub!(/([:\-+]+)/, "#{color('table divider')}\\1#{color('table border')}")
|
33
|
+
else
|
34
|
+
line.gsub!(/\|/, "#{color('table border')}|#{color('table color')}")
|
35
|
+
end
|
36
|
+
end.join("\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
def exec_available(cli)
|
40
|
+
if File.exist?(File.expand_path(cli))
|
41
|
+
File.executable?(File.expand_path(cli))
|
42
|
+
else
|
43
|
+
TTY::Which.exist?(cli)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def valid_lexer?(language)
|
48
|
+
lexers = %w(Clipper XBase Cucumber cucumber Gherkin gherkin RobotFramework robotframework abap ada ada95ada2005 ahk antlr-as antlr-actionscript antlr-cpp antlr-csharp antlr-c# antlr-java antlr-objc antlr-perl antlr-python antlr-ruby antlr-rb antlr apacheconf aconf apache applescript as actionscript as3 actionscript3 aspectj aspx-cs aspx-vb asy asymptote autoit Autoit awk gawk mawk nawk basemake bash sh ksh bat bbcode befunge blitzmax bmax boo brainfuck bf bro bugs winbugs openbugs c-objdump c ca65 cbmbas ceylon cfengine3 cf3 cfm cfs cheetah spitfire clojure clj cmake cobol cobolfree coffee-script coffeescript common-lisp cl console control coq cpp c++ cpp-objdump c++-objdumb cxx-objdump croc csharp c# css+django css+jinja css+erb css+ruby css+genshitext css+genshi css+lasso css+mako css+myghty css+php css+smarty css cuda cu cython pyx d-objdump d dart delphi pas pascal objectpascal dg diff udiff django jinja dpatch dtd duel Duel Engine Duel View JBST jbst JsonML+BST dylan-console dylan-repl dylan-lid lid dylan ec ecl elixir ex exs erb erl erlang evoque factor fan fancy fy felix flx fortran fsharp gas genshi kid xml+genshi xml+kid genshitext glsl gnuplot go gooddata-cl gosu groff nroff man groovy gst haml HAML haskell hs haxeml hxml html+cheetah html+spitfire html+django html+jinja html+evoque html+genshi html+kid html+lasso html+mako html+myghty html+php html+smarty html+velocity html http hx haXe hybris hy idl iex ini cfg io ioke ik irc jade JADE jags java jlcon js+cheetah javascript+cheetah js+spitfire javascript+spitfire js+django javascript+django js+jinja javascript+jinja js+erb javascript+erb js+ruby javascript+ruby js+genshitext js+genshi javascript+genshitext javascript+genshi js+lasso javascript+lasso js+mako javascript+mako js+myghty javascript+myghty js+php javascript+php js+smarty javascript+smarty js javascript json jsp julia jl kconfig menuconfig linux-config kernel-config koka kotlin lasso lassoscript lhs literate-haskell lighty lighttpd live-script livescript llvm logos logtalk lua make makefile mf bsdmake mako maql mason matlab matlabsession minid modelica modula2 m2 monkey moocode moon moonscript mscgen msc mupad mxml myghty mysql nasm nemerle newlisp newspeak nginx nimrod nim nsis nsi nsh numpy objdump objective-c++ objectivec++ obj-c++ objc++ objective-c objectivec obj-c objc objective-j objectivej obj-j objj ocaml octave ooc opa openedge abl progress perl pl php php3 php4 php5 plpgsql postgresql postgres postscript pot po pov powershell posh ps1 prolog properties protobuf psql postgresql-console postgres-console puppet py3tb pycon pypylog pypy pytb python py sage python3 py3 qml Qt Meta Language Qt modeling Language racket rkt ragel-c ragel-cpp ragel-d ragel-em ragel-java ragel-objc ragel-ruby ragel-rb ragel raw rb ruby duby rbcon irb rconsole rout rd rebol redcode registry rhtml html+erb html+ruby rst rest restructuredtext rust sass SASS scala scaml SCAML scheme scm scilab scss shell-session smali smalltalk squeak smarty sml snobol sourceslist sources.list sp spec splus s r sql sqlite3 squidconf squid.conf squid ssp stan systemverilog sv tcl tcsh csh tea tex latex text trac-wiki moin treetop ts urbiscript vala vapi vb.net vbnet velocity verilog v vgl vhdl vim xml+cheetah xml+spitfire xml+django xml+jinja xml+erb xml+ruby xml+evoque xml+lasso xml+mako xml+myghty xml+php xml+smarty xml+velocity xml xquery xqy xq xql xqm xslt xtend yaml)
|
49
|
+
lexers.include? language.strip
|
50
|
+
end
|
51
|
+
|
52
|
+
def hilite_code(code_block, language)
|
53
|
+
@log.error('Syntax highlighting requested by pygmentize is not available') if @options[:syntax_higlight] && !exec_available('pygmentize')
|
54
|
+
|
55
|
+
if @options[:syntax_higlight] && exec_available('pygmentize')
|
56
|
+
lexer = language && valid_lexer?(language) ? "-l #{language}" : '-g'
|
57
|
+
begin
|
58
|
+
cmd = [
|
59
|
+
'pygmentize -f terminal256',
|
60
|
+
"-O style=#{@theme['code_block']['pygments_theme']}",
|
61
|
+
lexer,
|
62
|
+
'2> /dev/null'
|
63
|
+
].join(' ')
|
64
|
+
hilite, s = Open3.capture2(cmd,
|
65
|
+
stdin_data: code_block)
|
66
|
+
if s.success?
|
67
|
+
hilite = xc + hilite.split(/\n/).map do |l|
|
68
|
+
[
|
69
|
+
color('code_block marker'),
|
70
|
+
'> ',
|
71
|
+
"#{color('code_block bg')}#{l.strip}#{xc}"
|
72
|
+
].join
|
73
|
+
end.join("\n").blackout(@theme['code_block']['bg']) + "#{xc}\n"
|
74
|
+
end
|
75
|
+
rescue StandardError => e
|
76
|
+
@log.error(e)
|
77
|
+
hilite = code_block
|
78
|
+
end
|
79
|
+
else
|
80
|
+
hilite = code_block.split(/\n/).map do |line|
|
81
|
+
[
|
82
|
+
color('code_block marker'),
|
83
|
+
'> ',
|
84
|
+
color('code_block color'),
|
85
|
+
line,
|
86
|
+
xc
|
87
|
+
].join
|
88
|
+
end.join("\n").blackout(@theme['code_block']['bg']) + "#{xc}\n"
|
89
|
+
end
|
90
|
+
|
91
|
+
[
|
92
|
+
xc,
|
93
|
+
color('code_block border'),
|
94
|
+
'-' * @cols,
|
95
|
+
xc,
|
96
|
+
"\n",
|
97
|
+
color('code_block color'),
|
98
|
+
hilite.chomp,
|
99
|
+
"\n",
|
100
|
+
color('code_block border'),
|
101
|
+
'-' * @cols,
|
102
|
+
xc
|
103
|
+
].join
|
104
|
+
end
|
105
|
+
|
106
|
+
def color(key)
|
107
|
+
val = nil
|
108
|
+
keys = key.split(/[ ,>]/)
|
109
|
+
if @theme.key?(keys[0])
|
110
|
+
val = @theme[keys.shift]
|
111
|
+
else
|
112
|
+
@log.error("Invalid theme key: #{key}") unless keys[0] =~ /^text/
|
113
|
+
return c([:reset])
|
114
|
+
end
|
115
|
+
keys.each do |k|
|
116
|
+
if val.key?(k)
|
117
|
+
val = val[k]
|
118
|
+
else
|
119
|
+
@log.error("Invalid theme key: #{k}")
|
120
|
+
return c([:reset])
|
121
|
+
end
|
122
|
+
end
|
123
|
+
if val.is_a? String
|
124
|
+
val = "x #{val}"
|
125
|
+
res = val.split(/ /).map(&:to_sym)
|
126
|
+
c(res)
|
127
|
+
else
|
128
|
+
c([:reset])
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def block_code(code, language)
|
133
|
+
"\n\n#{hilite_code(code, language)}#{xc}\n\n"
|
134
|
+
end
|
135
|
+
|
136
|
+
def block_quote(quote)
|
137
|
+
ret = "\n\n"
|
138
|
+
quote.split("\n").each do |line|
|
139
|
+
ret += [
|
140
|
+
color('blockquote marker color'),
|
141
|
+
@theme['blockquote']['marker']['character'],
|
142
|
+
color('blockquote color'),
|
143
|
+
line,
|
144
|
+
"\n"
|
145
|
+
].join('')
|
146
|
+
end
|
147
|
+
"#{ret}\n\n"
|
148
|
+
end
|
149
|
+
|
150
|
+
def block_html(raw_html)
|
151
|
+
"#{color('html color')}#{color_tags(raw_html)}#{xc}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def header(text, header_level)
|
155
|
+
pad = ''
|
156
|
+
ansi = ''
|
157
|
+
case header_level
|
158
|
+
when 1
|
159
|
+
ansi = color('h1 color')
|
160
|
+
pad = color('h1 pad')
|
161
|
+
char = @theme['h1']['pad_char'] || '='
|
162
|
+
pad += text.length + 2 > @cols ? char * text.length : char * (@cols - (text.length + 1))
|
163
|
+
when 2
|
164
|
+
ansi = color('h2 color')
|
165
|
+
pad = color('h2 pad')
|
166
|
+
char = @theme['h2']['pad_char'] || '-'
|
167
|
+
pad += text.length + 2 > @cols ? char * text.length : char * (@cols - (text.length + 1))
|
168
|
+
when 3
|
169
|
+
ansi = color('h3 color')
|
170
|
+
when 4
|
171
|
+
ansi = color('h4 color')
|
172
|
+
when 5
|
173
|
+
ansi = color('h5 color')
|
174
|
+
else
|
175
|
+
ansi = color('h6 color')
|
176
|
+
end
|
177
|
+
|
178
|
+
# If we're in iTerm and not paginating, add
|
179
|
+
# iTerm Marks for navigation on h1-3
|
180
|
+
if header_level < 4 &&
|
181
|
+
ENV['TERM_PROGRAM'] =~ /^iterm/i &&
|
182
|
+
@options[:pager] == false
|
183
|
+
ansi = "\e]1337;SetMark\a#{ansi}"
|
184
|
+
end
|
185
|
+
|
186
|
+
"\n#{xc}#{ansi}#{text} #{pad}#{xc}\n\n"
|
187
|
+
end
|
188
|
+
|
189
|
+
def hrule()
|
190
|
+
"\n\n#{color('hr color')}#{'_' * @cols}#{xc}\n\n"
|
191
|
+
end
|
192
|
+
|
193
|
+
def list(contents, list_type)
|
194
|
+
@@listitemid = 0
|
195
|
+
@@listid += 1
|
196
|
+
"<<list#{@@listid}>>#{contents}<</list#{@@listid}>>"
|
197
|
+
end
|
198
|
+
|
199
|
+
def list_item(text, list_type)
|
200
|
+
case list_type
|
201
|
+
when :unordered
|
202
|
+
[
|
203
|
+
"#{color('list bullet')}• ",
|
204
|
+
color('list color'),
|
205
|
+
text,
|
206
|
+
xc
|
207
|
+
].join('')
|
208
|
+
when :ordered
|
209
|
+
@@listitemid += 1
|
210
|
+
[
|
211
|
+
color('list number'),
|
212
|
+
"#{@@listitemid}. ",
|
213
|
+
color('list color'),
|
214
|
+
text,
|
215
|
+
xc
|
216
|
+
].join('')
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def paragraph(text)
|
221
|
+
"#{xc}#{text}#{xc}#{x}\n\n"
|
222
|
+
end
|
223
|
+
|
224
|
+
@table_cols = nil
|
225
|
+
|
226
|
+
def table_header_row
|
227
|
+
@header_row.map do |alignment|
|
228
|
+
case alignment
|
229
|
+
when :left
|
230
|
+
'|:---'
|
231
|
+
when :right
|
232
|
+
'|---:'
|
233
|
+
when :center
|
234
|
+
'|:--:'
|
235
|
+
else
|
236
|
+
'|----'
|
237
|
+
end
|
238
|
+
end.join('') + '|'
|
239
|
+
end
|
240
|
+
|
241
|
+
def table(header, body)
|
242
|
+
formatted = CLIMarkdown::MDTableCleanup.new([
|
243
|
+
"#{header}",
|
244
|
+
table_header_row,
|
245
|
+
"|\n",
|
246
|
+
"#{body}\n\n"
|
247
|
+
].join(''))
|
248
|
+
res = formatted.to_md
|
249
|
+
"#{color_table(res)}\n"
|
250
|
+
# res
|
251
|
+
end
|
252
|
+
|
253
|
+
def table_row(content)
|
254
|
+
@table_cols = content.scan(/\|/).count
|
255
|
+
%(#{content}\n)
|
256
|
+
end
|
257
|
+
|
258
|
+
def table_cell(content, alignment)
|
259
|
+
@header_row ||= []
|
260
|
+
if @table_cols && @header_row.count < @table_cols
|
261
|
+
@header_row << alignment
|
262
|
+
end
|
263
|
+
%(#{content} |)
|
264
|
+
end
|
265
|
+
|
266
|
+
def autolink(link, _)
|
267
|
+
[
|
268
|
+
color('link brackets'),
|
269
|
+
'<',
|
270
|
+
color('link url'),
|
271
|
+
link,
|
272
|
+
color('link brackets'),
|
273
|
+
'>',
|
274
|
+
xc
|
275
|
+
].join('')
|
276
|
+
end
|
277
|
+
|
278
|
+
def codespan(code)
|
279
|
+
[
|
280
|
+
color('code_span marker'),
|
281
|
+
'`',
|
282
|
+
color('code_span color'),
|
283
|
+
code,
|
284
|
+
color('code_span marker'),
|
285
|
+
'`',
|
286
|
+
xc
|
287
|
+
].join('')
|
288
|
+
end
|
289
|
+
|
290
|
+
def double_emphasis(text)
|
291
|
+
"#{color('emphasis bold')}#{text}#{xc}"
|
292
|
+
end
|
293
|
+
|
294
|
+
def emphasis(text)
|
295
|
+
"#{color('emphasis italic')}#{text}#{xc}"
|
296
|
+
end
|
297
|
+
|
298
|
+
def triple_emphasis(text)
|
299
|
+
"#{color('emphasis bold-italic')}#{text}#{xc}"
|
300
|
+
end
|
301
|
+
|
302
|
+
def highlight(text)
|
303
|
+
"#{color('highlight')}#{text}#{xc}"
|
304
|
+
end
|
305
|
+
|
306
|
+
def color_image_tag(link, title, alt_text)
|
307
|
+
[
|
308
|
+
color('image bang'),
|
309
|
+
'!',
|
310
|
+
color('image brackets'),
|
311
|
+
'[',
|
312
|
+
color('image title'),
|
313
|
+
alt_text,
|
314
|
+
color('image brackets'),
|
315
|
+
'](',
|
316
|
+
color('image url'),
|
317
|
+
link,
|
318
|
+
title.nil? ? '' : %( "#{title}"),
|
319
|
+
color('image brackets'),
|
320
|
+
')',
|
321
|
+
xc
|
322
|
+
].join
|
323
|
+
end
|
324
|
+
|
325
|
+
def image(link, title, alt_text)
|
326
|
+
if (exec_available('imgcat') || exec_available('chafa')) && @options[:local_images]
|
327
|
+
if exec_available('imgcat')
|
328
|
+
@log.info('Using imgcat for image rendering')
|
329
|
+
elsif exec_available('chafa')
|
330
|
+
@log.info('Using chafa for image rendering')
|
331
|
+
end
|
332
|
+
img_path = link
|
333
|
+
if img_path =~ /^http/ && @options[:remote_images]
|
334
|
+
if exec_available('imgcat')
|
335
|
+
@log.info('Using imgcat for image rendering')
|
336
|
+
begin
|
337
|
+
res, s = Open3.capture2(%(curl -sS "#{img_path}" 2> /dev/null | imgcat))
|
338
|
+
|
339
|
+
if s.success?
|
340
|
+
pre = !alt_text.nil? ? " #{c(%i[d blue])}[#{alt_text.strip}]\n" : ''
|
341
|
+
post = !title.nil? ? "\n #{c(%i[b blue])}-- #{title} --" : ''
|
342
|
+
result = pre + res + post
|
343
|
+
end
|
344
|
+
rescue StandardError => e
|
345
|
+
@log.error(e)
|
346
|
+
end
|
347
|
+
elsif exec_available('chafa')
|
348
|
+
@log.info('Using chafa for image rendering')
|
349
|
+
term = '-f sixels'
|
350
|
+
term = ENV['TERMINAL_PROGRAM'] =~ /iterm/i ? '-f iterm' : term
|
351
|
+
term = ENV['TERMINAL_PROGRAM'] =~ /kitty/i ? '-f kitty' : term
|
352
|
+
FileUtils.rm_r '.mdless_tmp', force: true if File.directory?('.mdless_tmp')
|
353
|
+
Dir.mkdir('.mdless_tmp')
|
354
|
+
Dir.chdir('.mdless_tmp')
|
355
|
+
`curl -SsO #{img_path} 2> /dev/null`
|
356
|
+
tmp_img = File.basename(img_path)
|
357
|
+
img = `chafa #{term} "#{tmp_img}"`
|
358
|
+
pre = alt_text ? " #{c(%i[d blue])}[#{alt_text.strip}]\n" : ''
|
359
|
+
post = title ? "\n #{c(%i[b blue])}-- #{tail} --" : ''
|
360
|
+
result = pre + img + post
|
361
|
+
Dir.chdir('..')
|
362
|
+
FileUtils.rm_r '.mdless_tmp', force: true
|
363
|
+
else
|
364
|
+
@log.warn('No viewer for remote images')
|
365
|
+
end
|
366
|
+
else
|
367
|
+
if img_path =~ %r{^[~/]}
|
368
|
+
img_path = File.expand_path(img_path)
|
369
|
+
elsif @file
|
370
|
+
base = File.expand_path(File.dirname(@file))
|
371
|
+
img_path = File.join(base, img_path)
|
372
|
+
end
|
373
|
+
if File.exist?(img_path)
|
374
|
+
pre = !alt_text.nil? ? " #{c(%i[d blue])}[#{alt_text.strip}]\n" : ''
|
375
|
+
post = !title.nil? ? "\n #{c(%i[b blue])}-- #{title} --" : ''
|
376
|
+
if exec_available('imgcat')
|
377
|
+
img = `imgcat "#{img_path}"`
|
378
|
+
elsif exec_available('chafa')
|
379
|
+
term = '-f sixels'
|
380
|
+
term = ENV['TERMINAL_PROGRAM'] =~ /iterm/i ? '-f iterm' : term
|
381
|
+
term = ENV['TERMINAL_PROGRAM'] =~ /kitty/i ? '-f kitty' : term
|
382
|
+
img = `chafa #{term} "#{img_path}"`
|
383
|
+
end
|
384
|
+
result = pre + img + post
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
if result.nil?
|
389
|
+
color_image_tag(link, title, alt_text)
|
390
|
+
else
|
391
|
+
result + xc
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
def linebreak()
|
396
|
+
"\n"
|
397
|
+
end
|
398
|
+
|
399
|
+
def link(link, title, content)
|
400
|
+
[
|
401
|
+
color('link brackets'),
|
402
|
+
'[',
|
403
|
+
color('link text'),
|
404
|
+
content,
|
405
|
+
color('link brackets'),
|
406
|
+
'](',
|
407
|
+
color('link url'),
|
408
|
+
link,
|
409
|
+
title.nil? ? '' : %( "#{title}"),
|
410
|
+
color('link brackets'),
|
411
|
+
')',
|
412
|
+
xc
|
413
|
+
].join
|
414
|
+
end
|
415
|
+
|
416
|
+
def color_tags(html)
|
417
|
+
html.gsub(%r{(<\S+( .*?)?/?>)}, "#{color('html brackets')}\\1#{xc}")
|
418
|
+
end
|
419
|
+
|
420
|
+
def raw_html(raw_html)
|
421
|
+
"#{color('html color')}#{color_tags(raw_html)}#{xc}"
|
422
|
+
end
|
423
|
+
|
424
|
+
def strikethrough(text)
|
425
|
+
"#{color('strikethrough')}#{text}#{xc}"
|
426
|
+
end
|
427
|
+
|
428
|
+
def superscript(text)
|
429
|
+
"#{color('super')}^#{text}#{xc}"
|
430
|
+
end
|
431
|
+
|
432
|
+
def footnotes(text)
|
433
|
+
# [
|
434
|
+
# color('footnote note'),
|
435
|
+
# text,
|
436
|
+
# "\n",
|
437
|
+
# xc,
|
438
|
+
# ].join('')
|
439
|
+
nil
|
440
|
+
end
|
441
|
+
|
442
|
+
def color_footnote_def(idx)
|
443
|
+
text = @@footnotes[idx]
|
444
|
+
[
|
445
|
+
color('footnote brackets'),
|
446
|
+
"[",
|
447
|
+
color('footnote caret'),
|
448
|
+
"^",
|
449
|
+
color('footnote title'),
|
450
|
+
idx,
|
451
|
+
color('footnote brackets'),
|
452
|
+
"]:",
|
453
|
+
color('footnote note'),
|
454
|
+
' ',
|
455
|
+
text.uncolor.strip,
|
456
|
+
xc,
|
457
|
+
"\n"
|
458
|
+
].join('')
|
459
|
+
end
|
460
|
+
|
461
|
+
def footnote_def(text, idx)
|
462
|
+
@@footnotes[idx] = text
|
463
|
+
end
|
464
|
+
|
465
|
+
def footnote_ref(text)
|
466
|
+
[
|
467
|
+
color('footnote title'),
|
468
|
+
"[^#{text}]",
|
469
|
+
xc
|
470
|
+
].join('')
|
471
|
+
end
|
472
|
+
|
473
|
+
def insert_footnotes(input)
|
474
|
+
input.split(/\n/).map do |line|
|
475
|
+
notes = line.to_enum(:scan, /\[\^(?<ref>\d+)\]/).map { Regexp.last_match }
|
476
|
+
if notes.count.positive?
|
477
|
+
footnotes = notes.map { |n| color_footnote_def(n['ref'].to_i) }.join("\n")
|
478
|
+
"#{line}\n\n#{footnotes}\n\n"
|
479
|
+
else
|
480
|
+
line
|
481
|
+
end
|
482
|
+
end.join("\n")
|
483
|
+
end
|
484
|
+
|
485
|
+
def fix_lists(input, indent = 0)
|
486
|
+
input.gsub(%r{(?<line><<list(?<id>\d+)>>(?<content>.*?)<</list\k<id>>>)}m) do
|
487
|
+
m = Regexp.last_match
|
488
|
+
fix_lists(m['content'].split(/\n/).map do |l|
|
489
|
+
outdent = l.scan(%r{<</list\d+>>}).count
|
490
|
+
indent += l.scan(/<<list\d+>>/).count
|
491
|
+
indent -= outdent
|
492
|
+
"#{' ' * indent}#{l}"
|
493
|
+
end.join("\n"), indent)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
def get_headers(input)
|
498
|
+
unless @headers && !@headers.empty?
|
499
|
+
@headers = []
|
500
|
+
headers = input.scan(/^((?!#!)(\#{1,6})\s*([^#]+?)(?: #+)?\s*|(\S.+)\n([=-]+))$/i)
|
501
|
+
|
502
|
+
headers.each do |h|
|
503
|
+
hlevel = 6
|
504
|
+
title = nil
|
505
|
+
if h[4] =~ /=+/
|
506
|
+
hlevel = 1
|
507
|
+
title = h[3]
|
508
|
+
elsif h[4] =~ /-+/
|
509
|
+
hlevel = 2
|
510
|
+
title = h[3]
|
511
|
+
else
|
512
|
+
hlevel = h[1].length
|
513
|
+
title = h[2]
|
514
|
+
end
|
515
|
+
@headers << [
|
516
|
+
'#' * hlevel,
|
517
|
+
title,
|
518
|
+
h[0]
|
519
|
+
]
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
@headers
|
524
|
+
end
|
525
|
+
|
526
|
+
def preprocess(input)
|
527
|
+
in_yaml = false
|
528
|
+
if input.split("\n")[0] =~ /(?i-m)^---[ \t]*?(\n|$)/
|
529
|
+
@log.info('Found YAML')
|
530
|
+
# YAML
|
531
|
+
in_yaml = true
|
532
|
+
input.sub!(/(?i-m)^---[ \t]*\n([\s\S]*?)\n[-.]{3}[ \t]*\n/) do
|
533
|
+
m = Regexp.last_match
|
534
|
+
@log.info('Processing YAML Header')
|
535
|
+
m[0].split(/\n/).map do |line|
|
536
|
+
if line =~ /^[-.]{3}\s*$/
|
537
|
+
line = "#{color('metadata marker')}%% #{color('metadata border')}#{line}"
|
538
|
+
else
|
539
|
+
line.sub!(/^(.*?:)[ \t]+(\S)/, '\1 \2')
|
540
|
+
line = "#{color('metadata marker')}%% #{color('metadata color')}#{line}"
|
541
|
+
end
|
542
|
+
line += ' ' * (@cols - line.uncolor.size) if (@cols - line.uncolor.size).positive?
|
543
|
+
line
|
544
|
+
end.join("\n") + "#{xc}\n"
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
if !in_yaml && input.gsub(/\n/, ' ') =~ /(?i-m)^\w.+:\s+\S+/
|
549
|
+
@log.info('Found MMD Headers')
|
550
|
+
input.sub!(/(?i-m)^([\S ]+:[\s\S]*?)+(?=\n\n)/) do |mmd|
|
551
|
+
mmd.split(/\n/).map do |line|
|
552
|
+
line.sub!(/^(.*?:)[ \t]+(\S)/, '\1 \2')
|
553
|
+
line = "#{color('metadata marker')}%% #{color('metadata color')}#{line}"
|
554
|
+
line += ' ' * (@cols - line.uncolor.size) if (@cols - line.uncolor.size).positive?
|
555
|
+
line
|
556
|
+
end.join("\n") + "#{' ' * @cols}#{xc}\n"
|
557
|
+
end
|
558
|
+
|
559
|
+
end
|
560
|
+
|
561
|
+
## Replace setex headers with ATX
|
562
|
+
input.gsub!(/^([^\n]+)\n={3,}\s*$/m, "# \\1\n")
|
563
|
+
input.gsub!(/^([^\n]+?)\n-{3,}\s*$/m, "## \\1\n")
|
564
|
+
|
565
|
+
@headers = get_headers(input)
|
566
|
+
|
567
|
+
if @options[:section]
|
568
|
+
new_content = []
|
569
|
+
@options[:section].each do |sect|
|
570
|
+
in_section = false
|
571
|
+
top_level = 1
|
572
|
+
input.split(/\n/).each do |graf|
|
573
|
+
if graf =~ /^(#+) *(.*?)( *#+)?$/
|
574
|
+
m = Regexp.last_match
|
575
|
+
level = m[1].length
|
576
|
+
title = m[2]
|
577
|
+
if in_section
|
578
|
+
if level >= top_level
|
579
|
+
new_content.push(graf)
|
580
|
+
else
|
581
|
+
in_section = false
|
582
|
+
break
|
583
|
+
end
|
584
|
+
elsif title.downcase == @headers[sect - 1][1].downcase
|
585
|
+
in_section = true
|
586
|
+
top_level = level + 1
|
587
|
+
new_content.push(graf)
|
588
|
+
else
|
589
|
+
next
|
590
|
+
end
|
591
|
+
elsif in_section
|
592
|
+
new_content.push(graf)
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|
596
|
+
input = new_content.join("\n")
|
597
|
+
end
|
598
|
+
|
599
|
+
# definition lists
|
600
|
+
input.gsub!(/(?mi)(?<=\n|\A)(?<term>(?!<:)[^\n]+)(?<def>(\n+: [^\n]+)+)/) do
|
601
|
+
m = Regexp.last_match
|
602
|
+
"#{color('dd term')}#{m['term']}#{xc}#{color('dd color')}#{color_dd_def(m['def'])}"
|
603
|
+
end
|
604
|
+
|
605
|
+
input
|
606
|
+
end
|
607
|
+
|
608
|
+
def color_dd_def(input)
|
609
|
+
input.gsub(/(?<=\n|\A)(?::)\s+(.*)/) do
|
610
|
+
m = Regexp.last_match
|
611
|
+
[
|
612
|
+
color('dd marker'),
|
613
|
+
": ",
|
614
|
+
color('dd color'),
|
615
|
+
m[1],
|
616
|
+
xc
|
617
|
+
].join
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
def postprocess(input)
|
622
|
+
if @options[:inline_footnotes]
|
623
|
+
input = insert_footnotes(input)
|
624
|
+
else
|
625
|
+
footnotes = @@footnotes.map.with_index do |fn, i|
|
626
|
+
next if fn.nil?
|
627
|
+
|
628
|
+
color_footnote_def(i)
|
629
|
+
end.join("\n")
|
630
|
+
input = "#{input}\n\n#{footnotes}"
|
631
|
+
end
|
632
|
+
# escaped characters
|
633
|
+
input.gsub!(/\\(\S)/, '\1')
|
634
|
+
# equations
|
635
|
+
input.gsub!(/((\\\\\[|\$\$)(.*?)(\\\\\]|\$\$)|(\\\\\(|\$)(.*?)(\\\\\)|\$))/) do
|
636
|
+
m = Regexp.last_match
|
637
|
+
if m[2]
|
638
|
+
brackets = [m[2], m[4]]
|
639
|
+
equat = m[3]
|
640
|
+
else
|
641
|
+
brackets = [m[5], m[7]]
|
642
|
+
equat = m[6]
|
643
|
+
end
|
644
|
+
"#{c(%i[b black])}#{brackets[0]}#{xc}#{c(%i[b blue])}#{equat}#{c(%i[b black])}#{brackets[1]}" + xc
|
645
|
+
end
|
646
|
+
# misc html
|
647
|
+
input.gsub!(%r{<br */?>}, "\n")
|
648
|
+
# lists
|
649
|
+
fix_lists(input, 0)
|
650
|
+
end
|
651
|
+
end
|
652
|
+
end
|
653
|
+
end
|
data/lib/mdless/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mdless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- bin/mdless
|
80
80
|
- lib/mdless.rb
|
81
81
|
- lib/mdless/colors.rb
|
82
|
+
- lib/mdless/console.rb
|
82
83
|
- lib/mdless/converter.rb
|
83
84
|
- lib/mdless/hash.rb
|
84
85
|
- lib/mdless/tables.rb
|