marked-conductor 1.0.20 → 1.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +4 -1
- data/buildnotes.md +41 -0
- data/lib/conductor/env.rb +1 -1
- data/lib/conductor/filter.rb +152 -7
- data/lib/conductor/version.rb +1 -1
- data/lib/conductor.rb +1 -0
- data/src/_README.md +4 -1
- data/test.sh +2 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dd28de6ae0aaf52e49579cb6d42e7d5ae46c5e74fa9016c661f983330ba1163
|
4
|
+
data.tar.gz: 4a376f1832720b796dca464b62e3ee4bc47217892658b043fd0eeaf53417cf13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdfe7d8bfd2834f5bd21ef4c2294f5b1295e26c0e065154f671bcde34ac81af5c79b2beb9405f8b71a69156a69143ead64609ee327459f41f37bfbf7fe0ad739
|
7
|
+
data.tar.gz: 5aece7af60fd7a296cc21ab28ea64d8cd5fe8fd22e2dd93c6fe1b7579080aba8bc6aca61fb945c015ecb3899114a2663b4ff98c69b7eadb24c24f79987fc3568
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
### 1.0.22
|
2
|
+
|
3
|
+
2024-07-16 12:30
|
4
|
+
|
5
|
+
#### IMPROVED
|
6
|
+
|
7
|
+
- When injecting CSS or JS paths, URL encode the path
|
8
|
+
|
9
|
+
#### FIXED
|
10
|
+
|
11
|
+
- Shell escape environment variables
|
12
|
+
|
13
|
+
### 1.0.21
|
14
|
+
|
15
|
+
2024-07-10 12:18
|
16
|
+
|
17
|
+
#### NEW
|
18
|
+
|
19
|
+
- New filter `fixHeaders` will adapt all headlines in the document to be in semantic order
|
20
|
+
|
1
21
|
### 1.0.20
|
2
22
|
|
3
23
|
2024-07-04 12:18
|
data/README.md
CHANGED
@@ -163,6 +163,7 @@ The action can be `script`, `command`, or `filter`.
|
|
163
163
|
| `prepend/appendCode(path)` | insert a file as a code block at beginning or end of content |
|
164
164
|
| `insertCSS(path)` | insert custom CSS into document |
|
165
165
|
| `autoLink()` | Turn bare URLs into \<self-linked\> urls |
|
166
|
+
| `fixHeaders()` | Reorganize headline levels to semantic order |
|
166
167
|
|
167
168
|
For `replace` and `replaceAll`: If *search* is surrounded with forward slashes followed by optional flags (*i* for case-insensitive, *m* to make dot match newlines), e.g. `/contribut(ing)?/i`, it will be interpreted as a regular expression. The *replace* value can include numeric capture groups, e.g. `Follow$2`.
|
168
169
|
|
@@ -176,7 +177,9 @@ If the path for `insertScript` or `insertCSS` is a URL instead of a filename, th
|
|
176
177
|
|
177
178
|
For all of the prepend/append file filters, you can store files in `~/.config/conductor/files` and reference them with just a filename. Otherwise a full path will be assumed.
|
178
179
|
|
179
|
-
For `autoLink`, any URL that's not contained in parenthesis or following a `[]: url` pattern will be autolinked (surrounded by angle brackets). URLs must contain `//` to be recognized, but any protocol will work, e.g. `x-marked://refresh`.
|
180
|
+
For `autoLink`, any URL that's not contained in parenthesis or following a `[]: url` pattern will be autolinked (surrounded by angle brackets). URLs must contain `//` to be recognized, but any protocol will work, e.g. `x-marked://refresh`. Must be run on Markdown (prior to any postprocessor HTML conversion).
|
181
|
+
|
182
|
+
For `fixHeaders`, it will be ensured that the document has an h1, and all header levels will be adapted to never jump more than one header level when increasing. If no H1 exists in the document, the first header of the lowest existing level will be turned into an H1 and all other headers will be decremented to fit the hierarchy. It's not perfect, but it does a pretty good job. When saving the document as Markdown from Marked, the new headers will be applied. Must be run on Markdown (prior to any postprocessor HTML conversion).
|
180
183
|
|
181
184
|
**Note:** successive filters in a sequence that insert or prepend will always insert content before/above the result of the previous insert filter. So if you have an `insertTitle` filter followed by an `insertCSS` filter, the CSS will appear above the inserted title. If you want elements inserted in reverse order, reverse the order of the inserts in the sequence.
|
182
185
|
|
data/buildnotes.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
template: git, gem, project
|
2
|
+
project: conductor
|
3
|
+
readme: src/_README.md
|
4
|
+
|
5
|
+
# marked-conductor
|
6
|
+
|
7
|
+
Train conductor for Marked
|
8
|
+
|
9
|
+
## File Structure
|
10
|
+
|
11
|
+
Standard gem structure.
|
12
|
+
|
13
|
+
## Deploy
|
14
|
+
|
15
|
+
You no longer need to manually bump the version, it will be incremented when this task runs.
|
16
|
+
|
17
|
+
```run Update Changelog
|
18
|
+
#!/bin/bash
|
19
|
+
|
20
|
+
changelog -u
|
21
|
+
```
|
22
|
+
|
23
|
+
@include(project:Update GitHub README)
|
24
|
+
|
25
|
+
```run Commit with changelog
|
26
|
+
#!/bin/bash
|
27
|
+
|
28
|
+
changelog | git commit -a -F -
|
29
|
+
git pull
|
30
|
+
git push
|
31
|
+
```
|
32
|
+
|
33
|
+
@include(gem:Release Gem) Release Gem
|
34
|
+
@include(project:Update Blog Project) Update Blog Project
|
35
|
+
@run(rake bump[patch]) Bump Version
|
36
|
+
|
37
|
+
@run(git commit -am 'Version bump')
|
38
|
+
|
39
|
+
@after
|
40
|
+
Don't forget to publish the website!
|
41
|
+
@end
|
data/lib/conductor/env.rb
CHANGED
data/lib/conductor/filter.rb
CHANGED
@@ -69,12 +69,35 @@ class ::String
|
|
69
69
|
first
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
72
|
+
##
|
73
|
+
## Count the characters in a string
|
74
|
+
##
|
75
|
+
## @return [Integer] number of characters
|
76
|
+
##
|
77
|
+
def chars
|
78
|
+
split(//).count
|
74
79
|
end
|
75
80
|
|
76
|
-
def
|
77
|
-
|
81
|
+
def decrease_headers(amt = 1)
|
82
|
+
gsub(/^(\#{1,6})(?!=#)/) do
|
83
|
+
m = Regexp.last_match
|
84
|
+
level = m[1].chars
|
85
|
+
level -= amt
|
86
|
+
level = 1 if level < 1
|
87
|
+
"#{"#" * level}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def decrease_headers!(amt = 1)
|
92
|
+
replace decrease_headers(amt)
|
93
|
+
end
|
94
|
+
|
95
|
+
def increase_headers(amt = 1)
|
96
|
+
gsub(/^#/, "#{"#" * amt}#").gsub(/^\#{7,}/, '######')
|
97
|
+
end
|
98
|
+
|
99
|
+
def increase_headers!(amt = 1)
|
100
|
+
replace increase_headers(amt)
|
78
101
|
end
|
79
102
|
|
80
103
|
def insert_toc(max = nil, after = :h1)
|
@@ -101,7 +124,7 @@ class ::String
|
|
101
124
|
end
|
102
125
|
|
103
126
|
def insert_stylesheet(path)
|
104
|
-
inject_after_meta(%(<link rel="stylesheet" href="#{path.strip}">))
|
127
|
+
inject_after_meta(%(<link rel="stylesheet" href="#{ERB::Util.url_encode(path.strip)}">))
|
105
128
|
end
|
106
129
|
|
107
130
|
def insert_css(path)
|
@@ -177,7 +200,7 @@ class ::String
|
|
177
200
|
end
|
178
201
|
|
179
202
|
def insert_javascript(path)
|
180
|
-
%(#{self}\n<script type="javascript" src="#{path.strip}"></script>\n)
|
203
|
+
%(#{self}\n<script type="javascript" src="#{ERB::Util.url_encode(path.strip)}"></script>\n)
|
181
204
|
end
|
182
205
|
|
183
206
|
def insert_raw_javascript(content)
|
@@ -245,7 +268,7 @@ class ::String
|
|
245
268
|
def insert_title(shift: 0)
|
246
269
|
content = dup
|
247
270
|
title = get_title
|
248
|
-
content.
|
271
|
+
content.increase_headers!(shift) if shift.positive?
|
249
272
|
lines = content.split(/\n/)
|
250
273
|
insert_point = content.meta_insert_point
|
251
274
|
insert_at = insert_point.positive? ? insert_point + 1 : 0
|
@@ -342,6 +365,121 @@ class ::String
|
|
342
365
|
'<\1>')
|
343
366
|
end
|
344
367
|
|
368
|
+
##
|
369
|
+
## Count the number of h1 headers in the document
|
370
|
+
##
|
371
|
+
## @return Number of h1s.
|
372
|
+
##
|
373
|
+
def count_h1s
|
374
|
+
scan(/^#[^#]/).count
|
375
|
+
end
|
376
|
+
|
377
|
+
##
|
378
|
+
## Normalize Setext headers to ATX
|
379
|
+
##
|
380
|
+
## @return [String] content with headers updated
|
381
|
+
##
|
382
|
+
def normalize_headers
|
383
|
+
gsub(/^(\S.*)\n([=-]+)\n/) do
|
384
|
+
m = Regexp.last_match
|
385
|
+
case m[2]
|
386
|
+
when /\=/
|
387
|
+
"# #{m[1]}\n\n"
|
388
|
+
else
|
389
|
+
"## #{m[1]}\n\n"
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def normalize_headers!
|
395
|
+
replace normalize_headers
|
396
|
+
end
|
397
|
+
|
398
|
+
##
|
399
|
+
## Ensure there's at least 1 h1 in the document
|
400
|
+
##
|
401
|
+
## If no h1 is found, converts the lowest level header (first one) into an h1
|
402
|
+
##
|
403
|
+
## @return [String] content with at least 1 h1
|
404
|
+
##
|
405
|
+
def ensure_h1
|
406
|
+
headers = to_enum(:scan, /(\#{1,6})([^#].*?)$/m).map { Regexp.last_match }
|
407
|
+
return self if headers.select { |h| h[1].chars == 1 }.count.positive?
|
408
|
+
|
409
|
+
lowest_header = headers.min_by { |h| h[1].chars }
|
410
|
+
level = lowest_header[1].chars
|
411
|
+
|
412
|
+
sub(/#{Regexp.escape(lowest_header[0])}/, "# #{lowest_header[2].strip}").decrease_headers(level)
|
413
|
+
end
|
414
|
+
|
415
|
+
def ensure_h1!
|
416
|
+
replace ensure_h1
|
417
|
+
end
|
418
|
+
|
419
|
+
##
|
420
|
+
## Bump all headers except for first H1
|
421
|
+
##
|
422
|
+
## @return Content with adjusted headers
|
423
|
+
##
|
424
|
+
def fix_headers
|
425
|
+
return self if count_h1s == 1
|
426
|
+
|
427
|
+
first_h1 = true
|
428
|
+
|
429
|
+
gsub(%r/^(\#{1,6})([^#].*?)$/m) do
|
430
|
+
m = Regexp.last_match
|
431
|
+
level = m[1].chars
|
432
|
+
content = m[2].strip
|
433
|
+
if level == 1 && first_h1
|
434
|
+
first_h1 = false
|
435
|
+
m[0]
|
436
|
+
else
|
437
|
+
level += 1 if level < 6
|
438
|
+
|
439
|
+
"#{"#" * level} #{content}"
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def fix_headers!
|
445
|
+
replace fix_headers
|
446
|
+
end
|
447
|
+
|
448
|
+
##
|
449
|
+
## Adjust header levels so there's no jump greater than 1
|
450
|
+
##
|
451
|
+
## @return Content with adjusted headers
|
452
|
+
##
|
453
|
+
def fix_hierarchy
|
454
|
+
normalize_headers!
|
455
|
+
ensure_h1!
|
456
|
+
fix_headers!
|
457
|
+
headers = to_enum(:scan, /(\#{1,6})([^#].*?)$/m).map { Regexp.last_match }
|
458
|
+
content = dup
|
459
|
+
last = 1
|
460
|
+
headers.each do |h|
|
461
|
+
level = h[1].chars
|
462
|
+
if level <= last + 1
|
463
|
+
last = level
|
464
|
+
next
|
465
|
+
end
|
466
|
+
|
467
|
+
level = last + 1
|
468
|
+
content.sub!(/#{Regexp.escape(h[0])}/, "#{"#" * level} #{h[2].strip}")
|
469
|
+
end
|
470
|
+
|
471
|
+
content
|
472
|
+
end
|
473
|
+
|
474
|
+
##
|
475
|
+
## Convert a string to a regular expression
|
476
|
+
##
|
477
|
+
## If the string matches /xxx/, it will be interpreted
|
478
|
+
## directly as a regex. Otherwise it will be escaped and
|
479
|
+
## converted to regex.
|
480
|
+
##
|
481
|
+
## @return [Regexp] Regexp representation of the string.
|
482
|
+
##
|
345
483
|
def to_rx
|
346
484
|
if self =~ %r{^/(.*?)/([im]+)?$}
|
347
485
|
m = Regexp.last_match
|
@@ -353,6 +491,11 @@ class ::String
|
|
353
491
|
end
|
354
492
|
end
|
355
493
|
|
494
|
+
##
|
495
|
+
## Convert a string containing $1, $2 to a Regexp replace pattern
|
496
|
+
##
|
497
|
+
## @return [String] Pattern representation of the object.
|
498
|
+
##
|
356
499
|
def to_pattern
|
357
500
|
gsub(/\$(\d+)/, '\\\\\1').gsub(/(^["']|["']$)/, "")
|
358
501
|
end
|
@@ -445,6 +588,8 @@ class Filter < String
|
|
445
588
|
content.replace_one(@params[0], @params[1])
|
446
589
|
when /(auto|self)link/
|
447
590
|
content.autolink
|
591
|
+
when /fix(head(lines|ers)|hierarchy)/
|
592
|
+
content.fix_hierarchy
|
448
593
|
end
|
449
594
|
end
|
450
595
|
end
|
data/lib/conductor/version.rb
CHANGED
data/lib/conductor.rb
CHANGED
data/src/_README.md
CHANGED
@@ -163,6 +163,7 @@ The action can be `script`, `command`, or `filter`.
|
|
163
163
|
| `prepend/appendCode(path)` | insert a file as a code block at beginning or end of content |
|
164
164
|
| `insertCSS(path)` | insert custom CSS into document |
|
165
165
|
| `autoLink()` | Turn bare URLs into \<self-linked\> urls |
|
166
|
+
| `fixHeaders()` | Reorganize headline levels to semantic order |
|
166
167
|
|
167
168
|
For `replace` and `replaceAll`: If *search* is surrounded with forward slashes followed by optional flags (*i* for case-insensitive, *m* to make dot match newlines), e.g. `/contribut(ing)?/i`, it will be interpreted as a regular expression. The *replace* value can include numeric capture groups, e.g. `Follow$2`.
|
168
169
|
|
@@ -176,7 +177,9 @@ If the path for `insertScript` or `insertCSS` is a URL instead of a filename, th
|
|
176
177
|
|
177
178
|
For all of the prepend/append file filters, you can store files in `~/.config/conductor/files` and reference them with just a filename. Otherwise a full path will be assumed.
|
178
179
|
|
179
|
-
For `autoLink`, any URL that's not contained in parenthesis or following a `[]: url` pattern will be autolinked (surrounded by angle brackets). URLs must contain `//` to be recognized, but any protocol will work, e.g. `x-marked://refresh`.
|
180
|
+
For `autoLink`, any URL that's not contained in parenthesis or following a `[]: url` pattern will be autolinked (surrounded by angle brackets). URLs must contain `//` to be recognized, but any protocol will work, e.g. `x-marked://refresh`. Must be run on Markdown (prior to any postprocessor HTML conversion).
|
181
|
+
|
182
|
+
For `fixHeaders`, it will be ensured that the document has an h1, and all header levels will be adapted to never jump more than one header level when increasing. If no H1 exists in the document, the first header of the lowest existing level will be turned into an H1 and all other headers will be decremented to fit the hierarchy. It's not perfect, but it does a pretty good job. When saving the document as Markdown from Marked, the new headers will be applied. Must be run on Markdown (prior to any postprocessor HTML conversion).
|
180
183
|
|
181
184
|
**Note:** successive filters in a sequence that insert or prepend will always insert content before/above the result of the previous insert filter. So if you have an `insertTitle` filter followed by an `insertCSS` filter, the CSS will appear above the inserted title. If you want elements inserted in reverse order, reverse the order of the inserts in the sequence.
|
182
185
|
|
data/test.sh
CHANGED
@@ -49,7 +49,7 @@ if [[ -z $1 ]]; then
|
|
49
49
|
exit 1
|
50
50
|
fi
|
51
51
|
|
52
|
-
FILE=$(realpath $1)
|
52
|
+
FILE=$(realpath "$1")
|
53
53
|
FILENAME=$(basename -- "$FILE")
|
54
54
|
EXTENSION="${FILENAME##*.}"
|
55
55
|
PHASE=$(echo $PHASE | tr [a-z] [A-Z])
|
@@ -67,7 +67,7 @@ export MARKED_EXT="$EXTENSION"
|
|
67
67
|
export MARKED_CSS_PATH="/Applications/Marked 2.app/Contents/Resources/swiss.css"
|
68
68
|
export PATH="$PATH:$(dirname "$FILE")"
|
69
69
|
export MARKED_PATH="$FILE"
|
70
|
-
export MARKED_INCLUDES=""
|
70
|
+
export MARKED_INCLUDES="/Applications/Marked 2.app/Contents/Resources/tocstyle.css"
|
71
71
|
export MARKED_PHASE="$PHASE"
|
72
72
|
|
73
73
|
if [[ $STD =~ ^(STD)?E ]]; then
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marked-conductor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -204,6 +204,7 @@ files:
|
|
204
204
|
- README.rdoc
|
205
205
|
- Rakefile
|
206
206
|
- bin/conductor
|
207
|
+
- buildnotes.md
|
207
208
|
- images/preferences.jpg
|
208
209
|
- lib/conductor.rb
|
209
210
|
- lib/conductor/array.rb
|
@@ -243,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
243
244
|
- !ruby/object:Gem::Version
|
244
245
|
version: '0'
|
245
246
|
requirements: []
|
246
|
-
rubygems_version: 3.2.
|
247
|
+
rubygems_version: 3.2.15
|
247
248
|
signing_key:
|
248
249
|
specification_version: 4
|
249
250
|
summary: A custom processor manager for Marked 2 (Mac)
|