marked-conductor 1.0.27 → 1.0.28
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.irbrc +2 -2
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +4 -4
- data/bin/conductor +8 -98
- data/lib/conductor/array.rb +36 -2
- data/lib/conductor/boolean.rb +10 -0
- data/lib/conductor/command.rb +25 -1
- data/lib/conductor/condition.rb +41 -16
- data/lib/conductor/config.rb +37 -8
- data/lib/conductor/env.rb +3 -3
- data/lib/conductor/filter.rb +341 -196
- data/lib/conductor/hash.rb +15 -0
- data/lib/conductor/script.rb +2 -2
- data/lib/conductor/string.rb +51 -8
- data/lib/conductor/version.rb +1 -1
- data/lib/conductor/{yui-compressor.rb → yui_compressor.rb} +105 -85
- data/lib/conductor.rb +94 -2
- data/marked-conductor.gemspec +2 -1
- metadata +4 -4
data/lib/conductor/filter.rb
CHANGED
@@ -2,19 +2,33 @@
|
|
2
2
|
|
3
3
|
# String helpers
|
4
4
|
class ::String
|
5
|
+
##
|
6
|
+
## Search config folder for multiple subfolders and content
|
7
|
+
##
|
8
|
+
## @param paths [Array] The possible directory names
|
9
|
+
## @param filename [String] The filename to search for
|
10
|
+
## @param ext [String] The file extension
|
11
|
+
##
|
5
12
|
def find_file_in(paths, filename, ext)
|
6
13
|
return filename if File.exist?(filename)
|
7
14
|
|
8
15
|
filename = File.basename(filename, ".#{ext}")
|
9
16
|
|
10
17
|
paths.each do |path|
|
11
|
-
exp = File.join(File.expand_path(
|
18
|
+
exp = File.join(File.expand_path("~/.config/conductor/"), path, "#{filename}.#{ext}")
|
12
19
|
return exp if File.exist?(exp)
|
13
20
|
end
|
14
21
|
|
15
22
|
"#{filename}.#{ext}"
|
16
23
|
end
|
17
24
|
|
25
|
+
##
|
26
|
+
## Normalize the filter name and parameters, downcasing and removing spaces,
|
27
|
+
## underscores, splitting params by comma
|
28
|
+
##
|
29
|
+
## @return [Array<String,Array>] array containing normalize filter and
|
30
|
+
## array of parameters
|
31
|
+
##
|
18
32
|
def normalize_filter
|
19
33
|
parts = match(/(?<filter>[\w_]+)(?:\((?<paren>.*?)\))?$/i)
|
20
34
|
filter = parts["filter"].downcase.gsub(/_/, "")
|
@@ -34,11 +48,18 @@ class ::String
|
|
34
48
|
:yaml
|
35
49
|
when /^ *[ \w]+: +\S+/
|
36
50
|
:mmd
|
51
|
+
when /^% +\S/
|
52
|
+
:pandoc
|
37
53
|
else
|
38
54
|
:none
|
39
55
|
end
|
40
56
|
end
|
41
57
|
|
58
|
+
##
|
59
|
+
## Determine which line to use to insert after existing metadata
|
60
|
+
##
|
61
|
+
## @return [Integer] line index
|
62
|
+
##
|
42
63
|
def meta_insert_point
|
43
64
|
insert_point = 0
|
44
65
|
|
@@ -57,6 +78,14 @@ class ::String
|
|
57
78
|
lines.each_with_index do |line, idx|
|
58
79
|
next if line =~ /^ *[ \w]+: +\S+/
|
59
80
|
|
81
|
+
insert_point = idx
|
82
|
+
break
|
83
|
+
end
|
84
|
+
when :pandoc
|
85
|
+
lines = split(/\n/)
|
86
|
+
lines.each_with_index do |line, idx|
|
87
|
+
next if line =~ /^% +\S/
|
88
|
+
|
60
89
|
insert_point = idx
|
61
90
|
break
|
62
91
|
end
|
@@ -65,10 +94,15 @@ class ::String
|
|
65
94
|
insert_point
|
66
95
|
end
|
67
96
|
|
97
|
+
##
|
98
|
+
## Locate the first H1 in the document
|
99
|
+
##
|
100
|
+
## @return [Integer] index of first H1
|
101
|
+
##
|
68
102
|
def first_h1
|
69
|
-
first =
|
103
|
+
first = nil
|
70
104
|
split(/\n/).each_with_index do |line, idx|
|
71
|
-
if line =~ /^(#
|
105
|
+
if line =~ /^(# *[^#]|={2,} *$)/
|
72
106
|
first = idx
|
73
107
|
break
|
74
108
|
end
|
@@ -76,10 +110,18 @@ class ::String
|
|
76
110
|
first
|
77
111
|
end
|
78
112
|
|
113
|
+
##
|
114
|
+
## Locate the first H2 in the document
|
115
|
+
##
|
116
|
+
## @return [Integer] index of first H2
|
117
|
+
##
|
79
118
|
def first_h2
|
80
|
-
first =
|
119
|
+
first = nil
|
120
|
+
meta_end = meta_insert_point
|
81
121
|
split(/\n/).each_with_index do |line, idx|
|
82
|
-
if
|
122
|
+
next if idx <= meta_end
|
123
|
+
|
124
|
+
if line =~ /^(## *[^#]|-{2,} *$)/
|
83
125
|
first = idx
|
84
126
|
break
|
85
127
|
end
|
@@ -88,44 +130,60 @@ class ::String
|
|
88
130
|
end
|
89
131
|
|
90
132
|
##
|
91
|
-
##
|
133
|
+
## Decrease all headers by given amount
|
92
134
|
##
|
93
|
-
## @
|
135
|
+
## @param amt [Integer] The amount to decrease
|
94
136
|
##
|
95
|
-
def chars
|
96
|
-
split(//).count
|
97
|
-
end
|
98
|
-
|
99
137
|
def decrease_headers(amt = 1)
|
100
138
|
gsub(/^(\#{1,6})(?!=#)/) do
|
101
139
|
m = Regexp.last_match
|
102
|
-
level = m[1].
|
140
|
+
level = m[1].size
|
103
141
|
level -= amt
|
104
142
|
level = 1 if level < 1
|
105
|
-
"#
|
143
|
+
"#" * level
|
106
144
|
end
|
107
145
|
end
|
108
146
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
147
|
+
##
|
148
|
+
## Increase all header levels by amount
|
149
|
+
##
|
150
|
+
## @param amt [Integer] number to increase by (1-5)
|
151
|
+
##
|
152
|
+
## @return [String] content with headers increased
|
153
|
+
##
|
113
154
|
def increase_headers(amt = 1)
|
114
|
-
gsub(/^#/, "#{"#" * amt}#").gsub(/^\#{7,}/,
|
155
|
+
gsub(/^#/, "#{"#" * amt}#").gsub(/^\#{7,}/, "######")
|
115
156
|
end
|
116
157
|
|
158
|
+
##
|
159
|
+
## Destructive version of #increase_headers
|
160
|
+
##
|
161
|
+
## @see #increase_headers
|
162
|
+
##
|
163
|
+
## @param amt [Integer] The amount
|
164
|
+
##
|
165
|
+
## @return [String] content with headers increased
|
166
|
+
##
|
117
167
|
def increase_headers!(amt = 1)
|
118
168
|
replace increase_headers(amt)
|
119
169
|
end
|
120
170
|
|
171
|
+
##
|
172
|
+
## Insert a Table of Contents at given position
|
173
|
+
##
|
174
|
+
## @param max [Integer] The maximum depth of the TOC
|
175
|
+
## @param after [Symbol] Where to place TOC after (:top, :h1, :h2)
|
176
|
+
##
|
177
|
+
## @return [String] content with TOC tag added
|
178
|
+
##
|
121
179
|
def insert_toc(max = nil, after = :h1)
|
122
180
|
lines = split(/\n/)
|
123
181
|
max = max.to_i&.positive? ? " max#{max}" : ""
|
124
182
|
line = case after.to_sym
|
125
183
|
when :h2
|
126
|
-
first_h2.
|
184
|
+
first_h2.nil? ? 0 : first_h2 + 1
|
127
185
|
when :h1
|
128
|
-
first_h1.
|
186
|
+
first_h1.nil? ? 0 : first_h1 + 1
|
129
187
|
else
|
130
188
|
meta_insert_point.positive? ? meta_insert_point + 1 : 0
|
131
189
|
end
|
@@ -133,6 +191,11 @@ class ::String
|
|
133
191
|
lines.insert(line, "\n<!--toc#{max}-->\n").join("\n")
|
134
192
|
end
|
135
193
|
|
194
|
+
##
|
195
|
+
## Wrap content in <style> tag if needed
|
196
|
+
##
|
197
|
+
## @return [String] wrapped content
|
198
|
+
##
|
136
199
|
def wrap_style
|
137
200
|
if match(%r{<style>.*?</style>}m)
|
138
201
|
self
|
@@ -141,30 +204,41 @@ class ::String
|
|
141
204
|
end
|
142
205
|
end
|
143
206
|
|
207
|
+
##
|
208
|
+
## Insert a <link> tag for the given path
|
209
|
+
##
|
210
|
+
## @param path [String] path to CSS files
|
211
|
+
##
|
212
|
+
## @return [String] path with <style> link added
|
213
|
+
##
|
144
214
|
def insert_stylesheet(path)
|
145
|
-
path = find_file_in([
|
215
|
+
path = find_file_in(%w[css styles], path, "css") unless path =~ /^http/
|
146
216
|
inject_after_meta(%(<link rel="stylesheet" href="#{path.strip}">))
|
147
217
|
end
|
148
218
|
|
219
|
+
##
|
220
|
+
## Insert raw CSS into the document, reading from a file and compressing
|
221
|
+
## contents
|
222
|
+
##
|
223
|
+
## @param path [String] The CSS file path
|
224
|
+
##
|
225
|
+
## @return [String] content with raw CSS injected
|
226
|
+
##
|
149
227
|
def insert_css(path)
|
150
228
|
return insert_stylesheet(path) if path.strip =~ /^http/
|
151
229
|
|
152
|
-
path.sub
|
230
|
+
path = path.sub(/(\.css)?$/, ".css")
|
153
231
|
|
154
|
-
if path =~ %r{^[
|
232
|
+
if path =~ %r{^[~/.]}
|
155
233
|
path = File.expand_path(path)
|
156
|
-
|
157
|
-
|
158
|
-
path = new_path if File.exist?(new_path)
|
159
|
-
elsif File.directory?(File.expand_path("~/.config/conductor/files"))
|
160
|
-
new_path = File.expand_path("~/.config/conductor/files/#{path}")
|
161
|
-
path = new_path if File.exist?(new_path)
|
234
|
+
else
|
235
|
+
path = find_file_in(%w[css styles files], path, "css")
|
162
236
|
end
|
163
237
|
|
164
238
|
if File.exist?(path)
|
165
239
|
content = IO.read(path)
|
166
240
|
yui = YuiCompressor::Yui.new
|
167
|
-
content = yui.compress(content)
|
241
|
+
content = yui.compress(content.force_encoding('utf-8'))
|
168
242
|
inject_after_meta(content.wrap_style)
|
169
243
|
else
|
170
244
|
warn "File not found (#{path})"
|
@@ -172,6 +246,13 @@ class ::String
|
|
172
246
|
end
|
173
247
|
end
|
174
248
|
|
249
|
+
##
|
250
|
+
## Insert the given content after any existing metadata
|
251
|
+
##
|
252
|
+
## @param content [String] The content
|
253
|
+
##
|
254
|
+
## @return [String] string with content injected
|
255
|
+
##
|
175
256
|
def inject_after_meta(content)
|
176
257
|
lines = split(/\n/)
|
177
258
|
insert_point = meta_insert_point
|
@@ -180,15 +261,23 @@ class ::String
|
|
180
261
|
lines.join("\n")
|
181
262
|
end
|
182
263
|
|
264
|
+
##
|
265
|
+
## Insert a file include syntax for various types
|
266
|
+
##
|
267
|
+
## @param path [String] The file path
|
268
|
+
## @param type [Symbol] The type (:file, :code, :raw)
|
269
|
+
## @param position [Symbol] The position (:start, :h1, :h2, :end)
|
270
|
+
##
|
183
271
|
def insert_file(path, type = :file, position = :end)
|
184
|
-
path.strip
|
272
|
+
path = path.strip
|
185
273
|
|
186
|
-
if path =~ %r{^[
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
274
|
+
path = if path =~ %r{^[.~/]}
|
275
|
+
File.expand_path(path)
|
276
|
+
else
|
277
|
+
find_file_in(%w[files], path, File.extname(path))
|
278
|
+
end
|
279
|
+
|
280
|
+
warn "File not found: #{path}" unless File.exist?(path)
|
192
281
|
|
193
282
|
out = case type
|
194
283
|
when :code
|
@@ -204,53 +293,87 @@ class ::String
|
|
204
293
|
when :start
|
205
294
|
inject_after_meta(out)
|
206
295
|
when :h1
|
207
|
-
|
296
|
+
h1 = first_h1.nil? ? 0 : first_h1 + 1
|
297
|
+
split(/\n/).insert(h1, out).join("\n")
|
208
298
|
when :h2
|
209
|
-
|
299
|
+
h2 = first_h2.nil? ? 0 : first_h2 + 1
|
300
|
+
split(/\n/).insert(h2, out).join("\n")
|
210
301
|
else
|
211
302
|
"#{self}\n#{out}"
|
212
303
|
end
|
213
304
|
end
|
214
305
|
|
306
|
+
##
|
307
|
+
## Append string to self
|
308
|
+
##
|
309
|
+
## @param string [String] The string to append
|
310
|
+
##
|
311
|
+
## @return self with string appended
|
312
|
+
##
|
215
313
|
def append(string)
|
216
314
|
"#{self}\n#{string}"
|
217
315
|
end
|
218
316
|
|
317
|
+
##
|
318
|
+
## Destructive version of #append
|
319
|
+
## @see #append
|
320
|
+
##
|
321
|
+
## @return self with string appended
|
322
|
+
##
|
219
323
|
def append!(string)
|
220
324
|
replace append(string)
|
221
325
|
end
|
222
326
|
|
327
|
+
##
|
328
|
+
## Append a <script> tag for a given path
|
329
|
+
##
|
330
|
+
## @param path [String] The path
|
331
|
+
##
|
332
|
+
## @return self with javascript tag appended
|
333
|
+
##
|
223
334
|
def insert_javascript(path)
|
224
|
-
%(#{self}\n<script type="javascript" src="#{
|
335
|
+
%(#{self}\n<script type="javascript" src="#{path.strip}"></script>\n)
|
225
336
|
end
|
226
337
|
|
338
|
+
##
|
339
|
+
## Append raw javascript
|
340
|
+
##
|
341
|
+
## @param content [String] The content
|
342
|
+
##
|
343
|
+
## @return self with script tag containing contents appended
|
344
|
+
##
|
227
345
|
def insert_raw_javascript(content)
|
228
|
-
%(#{self}\n<script>#{content}</script
|
346
|
+
%(#{self}\n<script>#{content}</script>\n)
|
229
347
|
end
|
230
348
|
|
349
|
+
##
|
350
|
+
## Insert javascript, detecting raw js and files, inserting appropriately
|
351
|
+
##
|
352
|
+
## Paths that are just a filename will be searched for in various .config
|
353
|
+
## directories. If found, a full path will be used.
|
354
|
+
##
|
355
|
+
## @param path [String] The path or raw content to inject
|
356
|
+
##
|
231
357
|
def insert_script(path)
|
232
|
-
path.strip
|
358
|
+
path = path.strip
|
359
|
+
orig_path = path
|
360
|
+
|
233
361
|
return insert_javascript(path) if path =~ /^http/
|
234
362
|
|
235
363
|
return insert_raw_javascript(path) if path =~ /\(.*?\)/
|
236
364
|
|
237
|
-
path
|
365
|
+
path = if path =~ %r{^[~/.]}
|
366
|
+
File.expand_path(path)
|
367
|
+
else
|
368
|
+
find_file_in(%w[javascript javascripts js scripts], path.sub(/(\.js)?$/, ".js"), "js")
|
369
|
+
end
|
238
370
|
|
239
|
-
if path
|
240
|
-
|
371
|
+
if File.exist?(path)
|
372
|
+
insert_javascript(path)
|
241
373
|
else
|
242
|
-
|
243
|
-
|
244
|
-
elsif File.directory?(File.expand_path("~/.config/conductor/javascripts"))
|
245
|
-
File.expand_path("~/.config/conductor/javascripts/#{path}")
|
246
|
-
else
|
247
|
-
File.expand_path("~/.config/conductor/scripts/#{path}")
|
248
|
-
end
|
249
|
-
|
250
|
-
path = new_path if File.exist?(new_path)
|
374
|
+
warn "Javascript not found: #{path}"
|
375
|
+
insert_javascript(orig_path)
|
251
376
|
end
|
252
|
-
|
253
|
-
insert_javascript(path)
|
254
377
|
end
|
255
378
|
|
256
379
|
def title_from_slug
|
@@ -258,10 +381,10 @@ class ::String
|
|
258
381
|
filename.sub!(/-?\d{4}-\d{2}-\d{2}-?/, "")
|
259
382
|
filename.sub!(/\bdot\b/, ".")
|
260
383
|
filename.sub!(/ dash /, "-")
|
261
|
-
filename
|
384
|
+
filename.gsub(/-/, ' ')
|
262
385
|
end
|
263
386
|
|
264
|
-
def
|
387
|
+
def read_title
|
265
388
|
title = nil
|
266
389
|
|
267
390
|
case meta_type
|
@@ -276,6 +399,15 @@ class ::String
|
|
276
399
|
break
|
277
400
|
end
|
278
401
|
end
|
402
|
+
when :pandoc
|
403
|
+
title = nil
|
404
|
+
split(/\n/).each do |line|
|
405
|
+
if line =~ /^% +(.*?)$/
|
406
|
+
title = Regexp.last_match(1)
|
407
|
+
break
|
408
|
+
end
|
409
|
+
end
|
410
|
+
title
|
279
411
|
else
|
280
412
|
m = match(/title: (.*?)$/i)
|
281
413
|
title = m ? m[0] : nil
|
@@ -288,7 +420,7 @@ class ::String
|
|
288
420
|
|
289
421
|
def insert_title(shift: 0)
|
290
422
|
content = dup
|
291
|
-
title =
|
423
|
+
title = read_title
|
292
424
|
content.increase_headers!(shift) if shift.positive?
|
293
425
|
lines = content.split(/\n/)
|
294
426
|
insert_point = content.meta_insert_point
|
@@ -336,7 +468,7 @@ class ::String
|
|
336
468
|
else
|
337
469
|
lines = split(/\n/)
|
338
470
|
lines.insert(meta_insert_point, "#{key}: #{value}")
|
339
|
-
lines.join("\n")
|
471
|
+
"#{lines.join("\n")}\n"
|
340
472
|
end
|
341
473
|
end
|
342
474
|
|
@@ -344,16 +476,16 @@ class ::String
|
|
344
476
|
sub(/^ *#{key}:.*?\n/i, "")
|
345
477
|
end
|
346
478
|
|
347
|
-
def
|
479
|
+
def comment?(key)
|
348
480
|
match(/^<!--.*?#{key}: \S.*?-->/m)
|
349
481
|
end
|
350
482
|
|
351
483
|
def add_comment(key, value)
|
352
|
-
if
|
484
|
+
if comment?(key)
|
353
485
|
sub(/ *#{key}: .*?$/, "#{key}: #{value}")
|
354
486
|
else
|
355
487
|
lines = split(/\n/)
|
356
|
-
lines.insert(meta_insert_point + 1, "<!--\n#{key}: #{value}\n-->")
|
488
|
+
lines.insert(meta_insert_point + 1, "\n<!--\n#{key}: #{value}\n-->")
|
357
489
|
lines.join("\n")
|
358
490
|
end
|
359
491
|
end
|
@@ -364,6 +496,8 @@ class ::String
|
|
364
496
|
delete_yaml(key)
|
365
497
|
when :mmd
|
366
498
|
delete_mmd(key)
|
499
|
+
else
|
500
|
+
self
|
367
501
|
end
|
368
502
|
end
|
369
503
|
|
@@ -373,7 +507,12 @@ class ::String
|
|
373
507
|
sub(/^---.*?(---|\.\.\.)/m, "")
|
374
508
|
when :mmd
|
375
509
|
lines = split(/\n/)
|
376
|
-
lines[meta_insert_point..]
|
510
|
+
lines[meta_insert_point..].join("\n")
|
511
|
+
when :pandoc
|
512
|
+
lines = split(/\n/)
|
513
|
+
lines[meta_insert_point..].join("\n")
|
514
|
+
else
|
515
|
+
gsub(/(\n|^)<!--\n[\w\d\s]+: ([\w\d\s]+)\n-->\n/m, '')
|
377
516
|
end
|
378
517
|
end
|
379
518
|
|
@@ -393,7 +532,7 @@ class ::String
|
|
393
532
|
##
|
394
533
|
## Count the number of h1 headers in the document
|
395
534
|
##
|
396
|
-
## @return Number of h1s.
|
535
|
+
## @return [Integer] Number of h1s.
|
397
536
|
##
|
398
537
|
def count_h1s
|
399
538
|
scan(/^#[^#]/).count
|
@@ -405,10 +544,10 @@ class ::String
|
|
405
544
|
## @return [String] content with headers updated
|
406
545
|
##
|
407
546
|
def normalize_headers
|
408
|
-
gsub(/^(?<=\n\n)(\S
|
547
|
+
gsub(/^(?<=\n\n|^)(\S[^\n]+)\n([=-]{2,})\n/) do
|
409
548
|
m = Regexp.last_match
|
410
549
|
case m[2]
|
411
|
-
when
|
550
|
+
when /=/
|
412
551
|
"# #{m[1]}\n\n"
|
413
552
|
else
|
414
553
|
"## #{m[1]}\n\n"
|
@@ -416,29 +555,42 @@ class ::String
|
|
416
555
|
end
|
417
556
|
end
|
418
557
|
|
558
|
+
##
|
559
|
+
## Destructive version of #normalize_headers
|
560
|
+
## @see #normalize_headers
|
561
|
+
##
|
562
|
+
## @return String with setext headers converted to ATX
|
563
|
+
##
|
419
564
|
def normalize_headers!
|
420
565
|
replace normalize_headers
|
421
566
|
end
|
422
567
|
|
423
568
|
##
|
424
|
-
## Ensure there's at least
|
569
|
+
## Ensure there's at least one H1 in the document
|
425
570
|
##
|
426
|
-
## If no
|
571
|
+
## If no H1 is found, converts the lowest level header (first one) into an H1
|
427
572
|
##
|
428
|
-
## @return [String] content with at least 1
|
573
|
+
## @return [String] content with at least 1 H1
|
429
574
|
##
|
430
575
|
def ensure_h1
|
431
576
|
headers = to_enum(:scan, /(\#{1,6})([^#].*?)$/m).map { Regexp.last_match }
|
432
|
-
return self if headers.select { |h| h[1].
|
577
|
+
return self if headers.select { |h| h[1].size == 1 }.count.positive?
|
433
578
|
|
434
|
-
lowest_header = headers.min_by { |h| h[1].
|
579
|
+
lowest_header = headers.min_by { |h| h[1].size }
|
435
580
|
return self if lowest_header.nil?
|
436
581
|
|
437
|
-
level = lowest_header[1].
|
582
|
+
level = lowest_header[1].size - 1
|
438
583
|
|
439
584
|
sub(/#{Regexp.escape(lowest_header[0])}/, "# #{lowest_header[2].strip}").decrease_headers(level)
|
440
585
|
end
|
441
586
|
|
587
|
+
##
|
588
|
+
## Destructive version of #ensure_h1
|
589
|
+
##
|
590
|
+
## @see #ensure_h1
|
591
|
+
##
|
592
|
+
## @return Content with at least one H1
|
593
|
+
##
|
442
594
|
def ensure_h1!
|
443
595
|
replace ensure_h1
|
444
596
|
end
|
@@ -451,14 +603,14 @@ class ::String
|
|
451
603
|
def fix_headers
|
452
604
|
return self if count_h1s == 1
|
453
605
|
|
454
|
-
|
606
|
+
h1 = true
|
455
607
|
|
456
|
-
gsub(
|
608
|
+
gsub(/^(\#{1,6})([^#].*?)$/) do
|
457
609
|
m = Regexp.last_match
|
458
|
-
level = m[1].
|
610
|
+
level = m[1].size
|
459
611
|
content = m[2].strip
|
460
|
-
if level == 1 &&
|
461
|
-
|
612
|
+
if level == 1 && h1
|
613
|
+
h1 = false
|
462
614
|
m[0]
|
463
615
|
else
|
464
616
|
level += 1 if level < 6
|
@@ -468,6 +620,14 @@ class ::String
|
|
468
620
|
end
|
469
621
|
end
|
470
622
|
|
623
|
+
##
|
624
|
+
## Destructive version of #fix_headers
|
625
|
+
##
|
626
|
+
##
|
627
|
+
## @see #fix_headers # #
|
628
|
+
##
|
629
|
+
## @return [String] headers fixed #
|
630
|
+
##
|
471
631
|
def fix_headers!
|
472
632
|
replace fix_headers
|
473
633
|
end
|
@@ -485,7 +645,7 @@ class ::String
|
|
485
645
|
content = dup
|
486
646
|
last = 1
|
487
647
|
headers.each do |h|
|
488
|
-
level = h[1].
|
648
|
+
level = h[1].size
|
489
649
|
if level <= last + 1
|
490
650
|
last = level
|
491
651
|
next
|
@@ -497,131 +657,116 @@ class ::String
|
|
497
657
|
|
498
658
|
content
|
499
659
|
end
|
500
|
-
|
501
|
-
##
|
502
|
-
## Convert a string to a regular expression
|
503
|
-
##
|
504
|
-
## If the string matches /xxx/, it will be interpreted
|
505
|
-
## directly as a regex. Otherwise it will be escaped and
|
506
|
-
## converted to regex.
|
507
|
-
##
|
508
|
-
## @return [Regexp] Regexp representation of the string.
|
509
|
-
##
|
510
|
-
def to_rx
|
511
|
-
if self =~ %r{^/(.*?)/([im]+)?$}
|
512
|
-
m = Regexp.last_match
|
513
|
-
regex = m[1]
|
514
|
-
flags = m[2]
|
515
|
-
Regexp.new(regex, flags)
|
516
|
-
else
|
517
|
-
Regexp.new(Regexp.escape(self))
|
518
|
-
end
|
519
|
-
end
|
520
|
-
|
521
|
-
##
|
522
|
-
## Convert a string containing $1, $2 to a Regexp replace pattern
|
523
|
-
##
|
524
|
-
## @return [String] Pattern representation of the object.
|
525
|
-
##
|
526
|
-
def to_pattern
|
527
|
-
gsub(/\$(\d+)/, '\\\\\1').gsub(/(^["']|["']$)/, "")
|
528
|
-
end
|
529
660
|
end
|
530
661
|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
662
|
+
module Conductor
|
663
|
+
# String filtering
|
664
|
+
class Filter < String
|
665
|
+
attr_reader :filter, :params
|
666
|
+
|
667
|
+
##
|
668
|
+
## Instantiate a filter
|
669
|
+
##
|
670
|
+
## @param filter [Filter] The filter
|
671
|
+
##
|
672
|
+
def initialize(filter)
|
673
|
+
@filter, @params = filter.normalize_filter
|
674
|
+
super
|
675
|
+
end
|
539
676
|
|
540
|
-
|
541
|
-
|
677
|
+
##
|
678
|
+
## Process STDIN with @filter
|
679
|
+
##
|
680
|
+
## @return [String] processed text
|
681
|
+
##
|
682
|
+
def process
|
683
|
+
content = Conductor.stdin
|
684
|
+
|
685
|
+
case @filter
|
686
|
+
when /(insert|add|inject)stylesheet/
|
687
|
+
@params.each do |sheet|
|
688
|
+
content = content.insert_stylesheet(sheet)
|
689
|
+
end
|
690
|
+
content
|
691
|
+
when /(insert|add|inject)(css|style)/
|
692
|
+
@params.each do |css|
|
693
|
+
content = content.insert_css(css)
|
694
|
+
end
|
695
|
+
content
|
696
|
+
when /(insert|add|inject)title/
|
697
|
+
amt = 0
|
698
|
+
if @params
|
699
|
+
amt = if @params[0] =~ /^[yts]/
|
700
|
+
1
|
701
|
+
else
|
702
|
+
@params[0].to_i
|
703
|
+
end
|
704
|
+
end
|
705
|
+
content.insert_title(shift: amt)
|
706
|
+
when /(insert|add|inject)script/
|
707
|
+
content.append!("\n\n<div>")
|
708
|
+
@params.each do |script|
|
709
|
+
content = content.insert_script(script)
|
710
|
+
end
|
711
|
+
"#{content}</div>"
|
712
|
+
when /(prepend|append|insert|inject)(raw|file|code)/
|
713
|
+
m = Regexp.last_match
|
714
|
+
|
715
|
+
position = if @params.count == 2
|
716
|
+
@params[1].normalize_position
|
717
|
+
else
|
718
|
+
m[1].normalize_position
|
719
|
+
end
|
720
|
+
content.insert_file(@params[0], m[2].normalize_include_type, position)
|
721
|
+
when /inserttoc/
|
722
|
+
max = @params.nil? || @params.empty? ? nil : @params[0]
|
723
|
+
|
724
|
+
after = if @params && @params.count == 2
|
725
|
+
@params[1] =~ /2/ ? :h2 : :h1
|
726
|
+
else
|
727
|
+
:start
|
728
|
+
end
|
729
|
+
|
730
|
+
content.insert_toc(max, after)
|
731
|
+
when /(add|set)meta/
|
732
|
+
unless @params.count == 2
|
733
|
+
warn "Invalid filter parameters: #{@filter}(#{@params.join(",")})"
|
734
|
+
return content
|
735
|
+
end
|
542
736
|
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
@params[0].to_i
|
561
|
-
end
|
562
|
-
end
|
563
|
-
content.insert_title(shift: amt)
|
564
|
-
when /(insert|add|inject)script/
|
565
|
-
content.append!("\n\n<div>")
|
566
|
-
@params.each do |script|
|
567
|
-
content = content.insert_script(script)
|
568
|
-
end
|
569
|
-
"#{content}</div>"
|
570
|
-
when /(prepend|append|insert|inject)(raw|file|code)/
|
571
|
-
m = Regexp.last_match
|
737
|
+
# needs to test for existing meta, setting key if exists, adding if not
|
738
|
+
# should recognize yaml and mmd
|
739
|
+
content.set_meta(@params[0], @params[1], style: content.meta_type)
|
740
|
+
when /(strip|remove|delete)meta/
|
741
|
+
if @params&.count&.positive?
|
742
|
+
content.delete_meta(@params[0])
|
743
|
+
else
|
744
|
+
content.strip_meta
|
745
|
+
end
|
746
|
+
when /setstyle/
|
747
|
+
# Should check for existing style first
|
748
|
+
content.set_meta("marked style", @params[0], style: :comment)
|
749
|
+
when /replaceall/
|
750
|
+
unless @params.count == 2
|
751
|
+
warn "Invalid filter parameters: #{@filter}(#{@params.join(",")})"
|
752
|
+
return content
|
753
|
+
end
|
572
754
|
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
when /inserttoc/
|
580
|
-
max = @params.count.positive? ? @params[0] : nil
|
581
|
-
|
582
|
-
after = if @params.count == 2
|
583
|
-
@params[1] =~ /2/ ? :h2 : :h1
|
584
|
-
else
|
585
|
-
:start
|
586
|
-
end
|
587
|
-
|
588
|
-
content.insert_toc(max, after)
|
589
|
-
when /(add|set)meta/
|
590
|
-
unless @params.count == 2
|
591
|
-
warn "Invalid filter parameters: #{@filter}(#{@params.join(",")})"
|
592
|
-
return content
|
593
|
-
end
|
755
|
+
content.replace_all(@params[0], @params[1])
|
756
|
+
when /replace$/
|
757
|
+
unless @params.count == 2
|
758
|
+
warn "Invalid filter parameters: #{@filter}(#{@params.join(",")})"
|
759
|
+
return content
|
760
|
+
end
|
594
761
|
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
content.delete_meta(@params[0])
|
762
|
+
content.replace_one(@params[0], @params[1])
|
763
|
+
when /(auto|self)link/
|
764
|
+
content.autolink
|
765
|
+
when /fix(head(lines|ers)|hierarchy)/
|
766
|
+
content.fix_hierarchy
|
601
767
|
else
|
602
|
-
content
|
768
|
+
content
|
603
769
|
end
|
604
|
-
when /setstyle/
|
605
|
-
# Should check for existing style first
|
606
|
-
content.set_meta("marked style", @params[0], style: :comment)
|
607
|
-
when /replaceall/
|
608
|
-
unless @params.count == 2
|
609
|
-
warn "Invalid filter parameters: #{@filter}(#{@params.join(",")})"
|
610
|
-
return content
|
611
|
-
end
|
612
|
-
|
613
|
-
content.replace_all(@params[0], @params[1])
|
614
|
-
when /replace$/
|
615
|
-
unless @params.count == 2
|
616
|
-
warn "Invalid filter parameters: #{@filter}(#{@params.join(",")})"
|
617
|
-
return content
|
618
|
-
end
|
619
|
-
|
620
|
-
content.replace_one(@params[0], @params[1])
|
621
|
-
when /(auto|self)link/
|
622
|
-
content.autolink
|
623
|
-
when /fix(head(lines|ers)|hierarchy)/
|
624
|
-
content.fix_hierarchy
|
625
770
|
end
|
626
771
|
end
|
627
772
|
end
|