marked-conductor 1.0.20 → 1.0.21
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/CHANGELOG.md +8 -0
- data/README.md +4 -1
- data/lib/conductor/filter.rb +150 -5
- data/lib/conductor/version.rb +1 -1
- data/src/_README.md +4 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5e859f85b430fafdb74633e795caefd6cfc14ce26585970026d77c20ddce06c2
         | 
| 4 | 
            +
              data.tar.gz: 292fbc78bdeaeb3480092872afa558c25fa156c1cb80784eee98c87dca55f253
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5ea468effe4d2be8b534d7bc9ea27dbb09a57f756393d7aebe4a33cda998326fb0eaa8b31194bc8c17e21487d3dd28aeaf3cedf21b707e61bda65a2253a609b8
         | 
| 7 | 
            +
              data.tar.gz: 893e362f929e2a26a4815bc3782d758d6f4d25270ca2137867c56de846b5755adbb4dc1bf3983b996b88a61e904731220d2c76123f523825d88be39dc5bb4ebd
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        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, not HTML.
         | 
| 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.
         | 
| 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/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)
         | 
| @@ -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/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, not HTML.
         | 
| 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.
         | 
| 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 |  | 
    
        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.21
         | 
| 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-10 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: awesome_print
         |