marked-conductor 1.0.27 → 1.0.29
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/.irbrc +2 -2
- data/CHANGELOG.md +18 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +4 -4
- data/README.md +2 -0
- 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 +345 -197
- 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
- data/src/_README.md +2 -0
- 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
|
-
gsub(/^(\#{1,6})(?!=#)/) do
|
138
|
+
normalize_headers.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
|
+
normalize_headers.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,119 @@ 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
|
-
|
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
|
767
|
+
when /(increase|decrease)headers/
|
768
|
+
count = @params ? @params[0].to_i : 1
|
769
|
+
@filter =~ /^inc/ ? content.increase_headers(count) : content.decrease_headers(count)
|
601
770
|
else
|
602
|
-
content
|
771
|
+
content
|
603
772
|
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
773
|
end
|
626
774
|
end
|
627
775
|
end
|