red_quilt 0.7.2 → 0.9.0
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 +99 -0
- data/README.md +38 -0
- data/docs/api.md +33 -1
- data/lib/red_quilt/arena.rb +117 -0
- data/lib/red_quilt/block_parser.rb +50 -389
- data/lib/red_quilt/blockquote.rb +15 -2
- data/lib/red_quilt/cli.rb +8 -2
- data/lib/red_quilt/code_block.rb +145 -0
- data/lib/red_quilt/document.rb +18 -4
- data/lib/red_quilt/footnote_anchors.rb +24 -0
- data/lib/red_quilt/footnote_pass.rb +6 -2
- data/lib/red_quilt/frontmatter.rb +54 -0
- data/lib/red_quilt/html_block.rb +161 -0
- data/lib/red_quilt/indentation.rb +35 -0
- data/lib/red_quilt/inline/builder.rb +16 -193
- data/lib/red_quilt/inline/emphasis_resolver.rb +184 -0
- data/lib/red_quilt/inline/lexer.rb +4 -4
- data/lib/red_quilt/inline/url_sanitizer.rb +64 -0
- data/lib/red_quilt/inline_pass.rb +15 -2
- data/lib/red_quilt/line.rb +6 -1
- data/lib/red_quilt/lint_pass.rb +2 -2
- data/lib/red_quilt/list.rb +13 -4
- data/lib/red_quilt/node_ref.rb +106 -11
- data/lib/red_quilt/renderer/html.rb +32 -20
- data/lib/red_quilt/renderer/mdast.rb +19 -15
- data/lib/red_quilt/source_map.rb +45 -5
- data/lib/red_quilt/table.rb +97 -0
- data/lib/red_quilt/version.rb +1 -1
- data/lib/red_quilt.rb +19 -4
- data/sig/red_quilt.rbs +35 -0
- metadata +10 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 211bfba5adede6552fb64c3dfadf6c895325af2c58a577eadb86c8d426a3dd0b
|
|
4
|
+
data.tar.gz: 2e542ae344e626dc5a1bf0198b80761dfac3317b48f11011569235e5418048c9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8526155c616d353741dd68ad7740a0ad3d18e08139c239a6d2ff2d48198721e4b1a84a8da3eca98dae033d1da73a59817a766fe0b3bf89391897559a0fc37047
|
|
7
|
+
data.tar.gz: 272a4918326acc93dc8699308a8597c9e621f98518f0307ef7a8f2eed9ba03dc3153f2fbea641e6b02eb76af0adf612a7d8e8fca7b08360c130d1e34b7b5266c
|
data/CHANGELOG.md
CHANGED
|
@@ -7,8 +7,107 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.0] - 2026-07-20
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Breaking: source positions now follow the unist Point convention**, which
|
|
15
|
+
cmark sourcepos and mdast both use. Three related changes:
|
|
16
|
+
- `source_location` columns are 1-based (they were 0-based; lines were
|
|
17
|
+
already 1-based). Both are counted in characters, and `end` remains
|
|
18
|
+
exclusive.
|
|
19
|
+
- Block spans cover the block as authored rather than its content alone.
|
|
20
|
+
`# H1` now starts at the `#`, `> quote` at the `>`, a list item at its
|
|
21
|
+
bullet, a fenced code block includes both fences, and a setext heading
|
|
22
|
+
includes its `===` / `---` underline.
|
|
23
|
+
- Leading indent is excluded from block spans, so ` text` starts at
|
|
24
|
+
column 3 rather than column 1. This applies to ATX and setext headings,
|
|
25
|
+
paragraphs, blockquotes, fenced code blocks, lists, list items, and
|
|
26
|
+
thematic breaks.
|
|
27
|
+
- The fenced code block change also fixes a wrong *line* number: the span
|
|
28
|
+
used to start at the first content line, reporting the block one line
|
|
29
|
+
below its opening fence.
|
|
30
|
+
|
|
31
|
+
Every expected value was verified against commonmark.js and
|
|
32
|
+
mdast-util-from-markdown; RedQuilt now agrees with mdast on all of them
|
|
33
|
+
except an unclosed fence, where the two references disagree and RedQuilt
|
|
34
|
+
follows cmark. Callers that added 1 to columns, or that relied on a
|
|
35
|
+
heading span excluding `# `, need updating.
|
|
36
|
+
|
|
37
|
+
`NodeRef#text` is unaffected: a heading's text remains its content, without
|
|
38
|
+
the marker.
|
|
39
|
+
|
|
40
|
+
- **Breaking: `NodeRef#info` returns nil for nodes that are not code
|
|
41
|
+
blocks**, where 0.8.0 returned `""`. A code block written without an info
|
|
42
|
+
string still returns `""`, so the two cases are now distinguishable. This
|
|
43
|
+
matches the new attribute accessors, which all use nil for "this node's
|
|
44
|
+
type does not carry the attribute".
|
|
45
|
+
- Lowered the minimum supported Ruby from 3.3 to 3.1. The only 3.1
|
|
46
|
+
incompatibility was `String#byteindex` (added in Ruby 3.2), used in two
|
|
47
|
+
inline hot paths; both operate on a binary (`String#b`) view of the source,
|
|
48
|
+
where `String#index` returns the same byte offsets. CI now runs the test
|
|
49
|
+
suite on 3.1 through 4.0.
|
|
50
|
+
- `Gemfile.lock` is no longer committed. A lockfile resolved on one Ruby pins
|
|
51
|
+
development gem versions that do not exist for the others (e.g. `rdoc 8.0.0`
|
|
52
|
+
and `rbs 4.0.3` have no Ruby 3.1 release), so a single committed lockfile
|
|
53
|
+
cannot serve the supported range. Each Ruby now resolves its own.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- `source_location` reported wrong line numbers for any source containing a
|
|
58
|
+
multibyte character. The line-start table is indexed by byte offset, but it
|
|
59
|
+
was built with `String#index`, which counts characters, so every line after
|
|
60
|
+
the first multibyte character drifted. Existing multibyte coverage did not
|
|
61
|
+
catch this because it used single-line sources.
|
|
62
|
+
- `Renderer::MDAST` emitted positions that violated the unist spec: `column`
|
|
63
|
+
was 0-based where unist requires 1-based, and `offset` was a byte index
|
|
64
|
+
where unist requires a 0-based character index. The latter made every
|
|
65
|
+
offset after a multibyte character wrong.
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
|
|
69
|
+
- Node attribute accessors on `NodeRef`: `heading_level`, `list_ordered?`,
|
|
70
|
+
`list_start`, `list_tight?`, `list_delimiter`, `link_destination`,
|
|
71
|
+
`link_title`, `footnote_label`, `footnote_number`, and `header?`. Each
|
|
72
|
+
returns nil when the node's type does not carry the attribute, so callers
|
|
73
|
+
can walk a document branching on `#type` and read that type's fields
|
|
74
|
+
directly. Previously the only public route was `#to_h`, which builds a Hash
|
|
75
|
+
for the whole subtree — 5391 objects for a 257-node list where these
|
|
76
|
+
accessors allocate none.
|
|
77
|
+
|
|
78
|
+
These wrappers are the safe way to read attributes. The `Arena` accessors
|
|
79
|
+
they delegate to are the raw layer and skip the type check, and several
|
|
80
|
+
attributes share a storage column, so reading one off a mismatched node
|
|
81
|
+
there returns another field's value rather than nil (`Arena#link_destination`
|
|
82
|
+
on a paragraph returns the paragraph's text).
|
|
83
|
+
|
|
84
|
+
## [0.8.0] - 2026-06-24
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- `NodeRef#info`: returns the fence info string of a code block (e.g. `ruby`
|
|
89
|
+
in ` ```ruby `, or `vtt audio="x.mp3"`); `""` for code blocks without one
|
|
90
|
+
and for every other node type. The raw code content remains available via
|
|
91
|
+
`NodeRef#text`.
|
|
92
|
+
- `Renderer::HTML#render_fragment(nodes)`: renders an Array of `NodeRef` in
|
|
93
|
+
order and returns the HTML fragment without affecting the main render
|
|
94
|
+
output. Renderer state shared across nodes (e.g. the heading-id slugger) is
|
|
95
|
+
preserved between calls. Lets callers that partition a document render the
|
|
96
|
+
pieces separately without reaching into renderer internals.
|
|
97
|
+
- `Arena` semantic payload accessors (`heading_level`, `list_ordered?`,
|
|
98
|
+
`code_block_info`, `link_destination`, `footnote_number`, …) for callers
|
|
99
|
+
that walk `Document#arena`, replacing direct use of the raw `int1`/`str2`
|
|
100
|
+
columns.
|
|
101
|
+
|
|
102
|
+
## [0.7.2] - 2026-06-23
|
|
103
|
+
|
|
10
104
|
### Added
|
|
11
105
|
|
|
106
|
+
- Opt-in YAML frontmatter support via the `frontmatter:` option on `parse` /
|
|
107
|
+
`render_html` and the `--frontmatter` CLI flag (off by default). A leading
|
|
108
|
+
`---` … `---` block is removed from the rendered body and exposed as
|
|
109
|
+
`Document#frontmatter`; in standalone output its `title` / `lang` keys fill
|
|
110
|
+
in `<title>` / `<html lang>`.
|
|
12
111
|
- Opt-in Mermaid diagram support via the `mermaid:` option on `render_html` /
|
|
13
112
|
`Document#to_html` and the `--mermaid` CLI flag (off by default). Fenced
|
|
14
113
|
` ```mermaid ` code blocks render as `<pre class="mermaid">` containers; in
|
data/README.md
CHANGED
|
@@ -48,6 +48,7 @@ RedQuilt.render_html("Hi <em>tag</em>", allow_html: true)
|
|
|
48
48
|
| `extended_autolinks:` | `false` | GFM: linkify bare `http(s)://` / `www.` / email addresses |
|
|
49
49
|
| `footnotes:` | `false` | GFM footnotes (see below) |
|
|
50
50
|
| `lint:` | `false` | Collect lint diagnostics (empty links, missing image alt, heading-level skips) |
|
|
51
|
+
| `frontmatter:` | `false` | Parse leading YAML frontmatter (`---`) as metadata (see below) |
|
|
51
52
|
|
|
52
53
|
### Footnotes (opt-in)
|
|
53
54
|
|
|
@@ -100,6 +101,41 @@ RedQuilt.parse("```mermaid\ngraph LR\n A --> B\n```")
|
|
|
100
101
|
In standalone output each diagram is made interactive with
|
|
101
102
|
[svg-pan-zoom](https://github.com/bumbu/svg-pan-zoom) (loaded from a CDN).
|
|
102
103
|
|
|
104
|
+
### YAML frontmatter (opt-in)
|
|
105
|
+
|
|
106
|
+
`parse` / `render_html` accept `frontmatter:` to extract a leading YAML
|
|
107
|
+
frontmatter block (the `---` … `---` fences used by Jekyll, Hugo).
|
|
108
|
+
The block is parsed with `Psych.safe_load` and removed from the rendered body;
|
|
109
|
+
the parsed Hash is exposed as `Document#frontmatter`.
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
doc = RedQuilt.parse(<<~MD, frontmatter: true)
|
|
113
|
+
---
|
|
114
|
+
title: My Page
|
|
115
|
+
lang: ja
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
# Body
|
|
119
|
+
MD
|
|
120
|
+
doc.frontmatter # => {"title" => "My Page", "lang" => "ja"}
|
|
121
|
+
doc.to_html # => "<h1>Body</h1>\n" (frontmatter stripped)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
In standalone output the frontmatter's `title` / `lang` fill in `<title>` /
|
|
125
|
+
`<html lang>` when no explicit argument is given (explicit argument >
|
|
126
|
+
frontmatter > default):
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
doc.to_html(standalone: true)
|
|
130
|
+
# <html lang="ja"> … <title>My Page</title> …
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The feature is opt-in, so a bare `---` is never mistaken for frontmatter
|
|
134
|
+
unless `frontmatter: true` is passed. Frontmatter lines are blanked rather
|
|
135
|
+
than deleted, so body source spans and diagnostic line numbers stay relative
|
|
136
|
+
to the start of the file. Invalid YAML records a `:frontmatter` warning
|
|
137
|
+
diagnostic and leaves `Document#frontmatter` as `nil` without raising.
|
|
138
|
+
|
|
103
139
|
### Tilt integration
|
|
104
140
|
|
|
105
141
|
RedQuilt ships a [Tilt](https://github.com/jeremyevans/tilt) adapter.
|
|
@@ -186,6 +222,8 @@ redquilt --mermaid --open input.md
|
|
|
186
222
|
Dir.tmpdir when -o is not given)
|
|
187
223
|
--mermaid Render `mermaid` code blocks as diagrams (loads
|
|
188
224
|
mermaid.js from a CDN in standalone output)
|
|
225
|
+
--frontmatter Parse leading YAML frontmatter (---) as metadata;
|
|
226
|
+
fills <title>/lang in standalone output
|
|
189
227
|
--diagnostics Print diagnostics to stderr
|
|
190
228
|
--diagnostics-only Print diagnostics only (suppress output)
|
|
191
229
|
-h, --help Show help
|
data/docs/api.md
CHANGED
|
@@ -18,6 +18,7 @@ doc.source_map # Line/column lookup (lazy memoized)
|
|
|
18
18
|
doc.diagnostics # Array of RedQuilt::Diagnostic collected while parsing
|
|
19
19
|
doc.allow_html? # Check HTML pass-through setting
|
|
20
20
|
doc.disallow_raw_html? # Check GFM disallowed-raw-HTML filtering setting
|
|
21
|
+
doc.frontmatter # Parsed YAML frontmatter Hash, or nil (see below)
|
|
21
22
|
|
|
22
23
|
# Standalone document with an embedded theme:
|
|
23
24
|
doc.to_html(standalone: true, theme: :default, title: "My Doc", lang: "en")
|
|
@@ -27,6 +28,15 @@ doc.to_html(standalone: true, theme: :default, title: "My Doc", lang: "en")
|
|
|
27
28
|
# Render `mermaid` code blocks as <pre class="mermaid"> diagrams; in
|
|
28
29
|
# standalone mode the mermaid.js runtime is loaded from a CDN too.
|
|
29
30
|
doc.to_html(standalone: true, mermaid: true)
|
|
31
|
+
|
|
32
|
+
# Parse a leading YAML frontmatter block (--- ... ---). Off by default; when
|
|
33
|
+
# enabled the block is removed from the rendered body and exposed as a Hash.
|
|
34
|
+
doc = RedQuilt.parse("---\ntitle: Hi\nlang: ja\n---\n\n# Body", frontmatter: true)
|
|
35
|
+
doc.frontmatter # => {"title" => "Hi", "lang" => "ja"} (nil when absent/disabled)
|
|
36
|
+
# In standalone output frontmatter title/lang fill <title>/<html lang> unless
|
|
37
|
+
# an explicit argument overrides them. Invalid YAML adds a :frontmatter
|
|
38
|
+
# warning diagnostic and leaves doc.frontmatter as nil.
|
|
39
|
+
doc.to_html(standalone: true)
|
|
30
40
|
```
|
|
31
41
|
|
|
32
42
|
## NodeRef (AST node wrapper)
|
|
@@ -41,12 +51,34 @@ node.walk # Enumerator[NodeRef] or { |node| ... } block
|
|
|
41
51
|
node.find_all(:link) # Array[NodeRef] with matching type
|
|
42
52
|
node.text # String (concatenated child text)
|
|
43
53
|
|
|
54
|
+
# Node attributes, by type. Each returns nil when the node's type does not
|
|
55
|
+
# carry the attribute, so you can branch on #type and read that type's own
|
|
56
|
+
# fields without building a Hash per node.
|
|
57
|
+
node.info # CODE_BLOCK: fence info, e.g. "ruby". "" when the
|
|
58
|
+
# block was written without one.
|
|
59
|
+
node.heading_level # HEADING: 1..6
|
|
60
|
+
node.list_ordered? # LIST: true for "1.", false for "-"
|
|
61
|
+
node.list_start # LIST: start number of an ordered list
|
|
62
|
+
node.list_tight? # LIST: tight vs loose
|
|
63
|
+
node.list_delimiter # LIST: delimiter as authored, e.g. "-" or "."
|
|
64
|
+
node.link_destination # LINK / IMAGE: destination URL
|
|
65
|
+
node.link_title # LINK / IMAGE: title, nil when absent
|
|
66
|
+
node.footnote_label # FOOTNOTE_DEFINITION / FOOTNOTE_REFERENCE: label
|
|
67
|
+
node.footnote_number # FOOTNOTE_DEFINITION / FOOTNOTE_REFERENCE: 1-based
|
|
68
|
+
node.header? # TABLE_ROW / TABLE_CELL: part of the header row?
|
|
69
|
+
|
|
44
70
|
# Position information (byte offset)
|
|
45
71
|
node.source_span # SourceSpan with start_byte, end_byte
|
|
46
72
|
|
|
47
73
|
# Position information (line/column)
|
|
48
74
|
node.source_location # { start_line, start_column, end_line, end_column }
|
|
49
|
-
# line
|
|
75
|
+
# line and column are both 1-indexed and counted in
|
|
76
|
+
# characters, following the unist Point convention that
|
|
77
|
+
# cmark sourcepos and mdast use. `end` is exclusive: it
|
|
78
|
+
# is the position just past the node's last character.
|
|
79
|
+
# Block spans cover the block as authored, including
|
|
80
|
+
# markers ("# H1" starts at the "#", "```" fences are
|
|
81
|
+
# part of the code block), but excluding leading indent.
|
|
50
82
|
|
|
51
83
|
# AST export
|
|
52
84
|
node.to_h # Export subtree as Hash[Symbol, untyped]
|
data/lib/red_quilt/arena.rb
CHANGED
|
@@ -231,6 +231,116 @@ module RedQuilt
|
|
|
231
231
|
@str2[id]
|
|
232
232
|
end
|
|
233
233
|
|
|
234
|
+
# --- Semantic payload accessors -------------------------------------
|
|
235
|
+
#
|
|
236
|
+
# int1..int3 / str1 / str2 are anonymous columns; their meaning is
|
|
237
|
+
# per-NodeType (see the class comment). These readers are the single
|
|
238
|
+
# source of truth for those conventions, so callers (renderers, the
|
|
239
|
+
# NodeRef wrapper, AST/MDAST export) never need to know which raw
|
|
240
|
+
# column a field lives in. Writers use add_node's keyword args,
|
|
241
|
+
# update_*, or a small set of typed writers (e.g.
|
|
242
|
+
# #resolve_footnote_definition) when the intent is worth naming.
|
|
243
|
+
#
|
|
244
|
+
# The reader is responsible for calling these only on the matching
|
|
245
|
+
# NodeType; on a mismatching node they return whatever the raw column
|
|
246
|
+
# holds (typically the 0 / nil default).
|
|
247
|
+
|
|
248
|
+
# HEADING: nesting level (1..6).
|
|
249
|
+
def heading_level(id)
|
|
250
|
+
@int1[id]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# HEADING: byte range of the heading text alone, excluding the `#` marker
|
|
254
|
+
# and any closing hashes. The node's source_span covers the heading as
|
|
255
|
+
# authored (for position reporting), so inline parsing needs this narrower
|
|
256
|
+
# range to avoid lexing the marker as content. Setext headings carry no
|
|
257
|
+
# marker prefix and leave this zeroed, in which case the span is the
|
|
258
|
+
# content range.
|
|
259
|
+
def heading_content_start(id)
|
|
260
|
+
@int2[id]
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def heading_content_len(id)
|
|
264
|
+
@int3[id]
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# LIST: ordered (`1.`) vs bullet (`-`).
|
|
268
|
+
def list_ordered?(id)
|
|
269
|
+
@int1[id] == 1
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# LIST: the start number of an ordered list (1 unless overridden).
|
|
273
|
+
def list_start(id)
|
|
274
|
+
@int2[id]
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# LIST: tight (no blank lines between items) vs loose.
|
|
278
|
+
def list_tight?(id)
|
|
279
|
+
@int3[id] == 1
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# LIST: the item delimiter as authored (e.g. "-", "1.").
|
|
283
|
+
def list_delimiter(id)
|
|
284
|
+
@str1[id]
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# TABLE_ROW: header row (rendered in <thead>) vs body row.
|
|
288
|
+
def table_row_header?(id)
|
|
289
|
+
@int1[id] == 1
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# TABLE_CELL: header cell (<th>) vs data cell (<td>).
|
|
293
|
+
def table_cell_header?(id)
|
|
294
|
+
@int1[id] == 1
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# CODE_BLOCK: the fence info string (e.g. 'ruby', 'vtt audio="x"').
|
|
298
|
+
def code_block_info(id)
|
|
299
|
+
@str2[id]
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# LINK / IMAGE: destination URL.
|
|
303
|
+
def link_destination(id)
|
|
304
|
+
@str1[id]
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# LINK / IMAGE: optional title attribute (nil/empty when absent).
|
|
308
|
+
def link_title(id)
|
|
309
|
+
@str2[id]
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# FOOTNOTE_REFERENCE: the assigned footnote number.
|
|
313
|
+
def footnote_number(id)
|
|
314
|
+
@int1[id]
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# FOOTNOTE_REFERENCE: which occurrence of a repeated reference this is
|
|
318
|
+
# (1-based), used to give each backref a unique anchor.
|
|
319
|
+
def footnote_occurrence(id)
|
|
320
|
+
@int2[id]
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# FOOTNOTE_REFERENCE / FOOTNOTE_DEFINITION: the author-written label.
|
|
324
|
+
def footnote_label(id)
|
|
325
|
+
@str1[id]
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# FOOTNOTE_DEFINITION: total number of references to this footnote,
|
|
329
|
+
# materialized by FootnotePass so renderers can read it off the node
|
|
330
|
+
# instead of consulting the registry. (FOOTNOTE_REFERENCE reuses int2
|
|
331
|
+
# for its own occurrence index; see #footnote_occurrence.)
|
|
332
|
+
def footnote_total_references(id)
|
|
333
|
+
@int2[id]
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# FOOTNOTE_DEFINITION: records the resolved number and total reference
|
|
337
|
+
# count onto the node (read back via #footnote_number /
|
|
338
|
+
# #footnote_total_references).
|
|
339
|
+
def resolve_footnote_definition(id, number, total_references)
|
|
340
|
+
@int1[id] = number
|
|
341
|
+
@int2[id] = total_references
|
|
342
|
+
end
|
|
343
|
+
|
|
234
344
|
# Returns a SourceSpan for the node, or nil when the node has no
|
|
235
345
|
# span (source_start < 0, meaning the content is held in str1).
|
|
236
346
|
def source_span(id)
|
|
@@ -251,6 +361,13 @@ module RedQuilt
|
|
|
251
361
|
start_byte = @source_start[id]
|
|
252
362
|
return nil if start_byte.nil? || start_byte.negative?
|
|
253
363
|
|
|
364
|
+
# An ATX heading's span deliberately covers its `#` marker so that
|
|
365
|
+
# positions point at the heading as authored. Text is the content
|
|
366
|
+
# alone, so slice the narrower content range instead.
|
|
367
|
+
if @type[id] == NodeType::HEADING && @int2[id].positive?
|
|
368
|
+
return @source.byteslice(@int2[id], @int3[id])
|
|
369
|
+
end
|
|
370
|
+
|
|
254
371
|
@source.byteslice(start_byte, @source_len[id])
|
|
255
372
|
end
|
|
256
373
|
|