Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for attribute value continuation across multiple lines #30

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion grammar/asciidoc-block.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,62 @@ attribute_entry = ':' negatedPrefix:'!'? name:attribute_name negatedSuffix:'!'?
return [name, negatedPrefix || negatedSuffix ? null : value || '', range()]
}

attribute_entry_head = ':' '!'? attribute_name '!'? ':' (space / eol)

// TODO permit non-ASCII letters in attribute name
attribute_name = $([a-zA-Z0-9_] [a-zA-Z0-9_-]*)

attribute_value = space @$(!lf .)+
//attribute_value = space lines:($(!lf .)*)|1.., &{ let idx = offset(), count = 0; while (input[--idx] === '\\') count++; return !!(count % 2) } lf (&space / !(attribute_entry_head / eol / list_continuation / any_block_delimiter_line / block_attribute_line))|
//{
// if (lines.length === 1) {
// const line = lines[0]
// if (!line) return line
// const len = line.length
// if (len > 2 && line[len - 1] === '\\' && line[len - 2] === ' ' && line[len - 3] === ' ') return line.slice(0, len - 3)
// return line[0] === ' ' ? line.trimStart() : line
// }
// let hardWrapNext = false
// const lastLineIdx = lines.length - 1
// return lines.reduce((buf, line, lineIdx) => {
// const hardWrap = hardWrapNext
// if (hardWrap) buf += '\n'
// hardWrapNext = false
// let len = line.length
// if (lineIdx < lastLineIdx) {
// if (!(line = line.substring(0, --len))) return buf
// if (len > 1 && line[len - 2] === ' ' && line[len - 1] === ' ' && (hardWrapNext = true)) {
// return buf + line.substring(0, len - 2)
// }
// } else if (len > 2 && line[len - 1] === '\\' && line[len - 2] === ' ' && line[len - 3] === ' ') {
// return buf + line.substring(0, len - 3)
// }
// return buf + (hardWrap || line[0] !== ' ' ? line : line.trimStart())
// }, '')
//}

attribute_value = space lines:($(!('\\' / lf) . / '\\' !lf .)*)|1.., '\\' lf (&space / !(attribute_entry_head / eol / list_continuation / any_block_delimiter_line / block_attribute_line))| trailer:('\\' / '')
{
if (lines.length === 1) {
const line = lines[0]
if (!line) return trailer
if (!trailer) return line[0] === ' ' ? line.trimStart() : line
const len = line.length
if (len > 1 && line[len - 1] === ' ' && line[len - 2] === ' ') return line.substring(0, len - 2)
return (line[0] === ' ' ? line.trimStart() : line) + trailer
}
let hardWrapNext = false
const lastLineIdx = lines.length - 1
return lines.reduce((buf, line, lineIdx) => {
const hardWrap = hardWrapNext
if (hardWrap) buf += '\n'
hardWrapNext = false
if (!line) return buf
const len = line.length
return len > 1 && line[len - 1] === ' ' && line[len - 2] === ' ' && (hardWrapNext = true)
? buf + line.substring(0, len - 2) + (lineIdx === lastLineIdx ? (trailer = '') : '')
: buf + (hardWrap || line[0] !== ' ' ? line : line.trimStart())
}, '') + trailer
}

body = @section_block* remainder

Expand Down
1 change: 1 addition & 0 deletions test/tests/block/attributes/backslash-only-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:esc: \
11 changes: 11 additions & 0 deletions test/tests/block/attributes/backslash-only-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"esc": { "value": "\\", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 7 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 7 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 7 }]
}
3 changes: 3 additions & 0 deletions test/tests/block/attributes/dangling-hard-wrap-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:source: \
foo \
bar \
11 changes: 11 additions & 0 deletions test/tests/block/attributes/dangling-hard-wrap-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"source": { "value": "foo\nbar", "location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 6 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 6 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 6 }]
}
1 change: 1 addition & 0 deletions test/tests/block/attributes/empty-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:reproducible:
5 changes: 5 additions & 0 deletions test/tests/block/attributes/empty-lines-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:lines: foo \
\
bar \
\
baz
11 changes: 11 additions & 0 deletions test/tests/block/attributes/empty-lines-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"lines": { "value": "foo\nbar\nbaz", "location": [{ "line": 1, "col": 1 }, { "line": 5, "col": 3 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 5, "col": 3 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 5, "col": 3 }]
}
11 changes: 11 additions & 0 deletions test/tests/block/attributes/empty-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"reproducible": { "value": "", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 14 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 14 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 14 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"ensureTrailingNewline": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:reproducible:
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"reproducible": { "value": "", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 16 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 16 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 0 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:reproducible:
11 changes: 11 additions & 0 deletions test/tests/block/attributes/empty-trailing-space-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"reproducible": { "value": "", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 16 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 16 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 16 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:drive: C:\\
11 changes: 11 additions & 0 deletions test/tests/block/attributes/escaped-value-continuation-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"drive": { "value": "C:\\\\", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 12 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 12 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 12 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:dbs: \\\\
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"dbs": { "value": "\\\\\\\\", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 10 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 10 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 10 }]
}
2 changes: 2 additions & 0 deletions test/tests/block/attributes/hard-line-break-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:bars: Roses are red, + \
Violets are blue.
11 changes: 11 additions & 0 deletions test/tests/block/attributes/hard-line-break-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"bars": { "value": "Roses are red, +\nViolets are blue.", "location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 17 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 17 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 17 }]
}
4 changes: 4 additions & 0 deletions test/tests/block/attributes/hard-wrap-indented-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:filetree: article.adoc \
assets/ \
example.rb \
image.png \
11 changes: 11 additions & 0 deletions test/tests/block/attributes/hard-wrap-indented-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"filetree": { "value": "article.adoc\nassets/\n example.rb\n image.png", "location": [{ "line": 1, "col": 1 }, { "line": 4, "col": 14 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 4, "col": 14 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 4, "col": 14 }]
}
2 changes: 2 additions & 0 deletions test/tests/block/attributes/hard-wrap-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:output: 499 passing \
1 pending
11 changes: 11 additions & 0 deletions test/tests/block/attributes/hard-wrap-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"output": { "value": "499 passing\n1 pending", "location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 9 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 9 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 9 }]
}
1 change: 1 addition & 0 deletions test/tests/block/attributes/indented-hard-wrap-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:source: foo \
11 changes: 11 additions & 0 deletions test/tests/block/attributes/indented-hard-wrap-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"source": { "value": " foo", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 17 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 17 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 17 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:source: indented \
11 changes: 11 additions & 0 deletions test/tests/block/attributes/indented-single-line-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"source": { "value": " indented", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 22 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 22 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 22 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:bs: \
:org: ACME
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"bs": { "value": "\\", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 6 }] },
"org": { "value": "ACME", "location": [{ "line": 2, "col": 1 }, { "line": 2, "col": 10 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 10 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 10 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"options": {
"parseInlines": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:appsdir: C:\Program Files\

Look for the installed application in {appsdir}.
26 changes: 26 additions & 0 deletions test/tests/block/attributes/interrupted-by-empty-line-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"appsdir": { "value": "C:\\Program Files\\", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 27 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 27 }]
},
"blocks": [
{
"name": "paragraph",
"type": "block",
"inlines": [
{
"name": "text",
"type": "string",
"value": "Look for the installed application in C:\\Program Files\\.",
"location": [{ "line": 3, "col": 1 }, { "line": 3, "col": 48 }]
}
],
"location": [{ "line": 3, "col": 1 }, { "line": 3, "col": 48 }]
}
],
"location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 48 }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:name: value\
+
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"name": { "value": "value\\", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 13 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 13 }]
},
"blocks": [
{
"name": "paragraph",
"type": "block",
"inlines": [
{
"name": "text",
"type": "string",
"value": "+",
"location": [{ "line": 2, "col": 1 }, { "line": 2, "col": 1 }]
}
],
"location": [{ "line": 2, "col": 1 }, { "line": 2, "col": 1 }]
}
],
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 1 }]
}
3 changes: 3 additions & 0 deletions test/tests/block/attributes/leading-indentation-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:icons: font
:toc: preamble
:toclevels: 1
13 changes: 13 additions & 0 deletions test/tests/block/attributes/leading-indentation-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"icons": { "value": "font", "location": [{ "line": 1, "col": 1 }, { "line": 1, "col": 16 }] },
"toc": { "value": "preamble", "location": [{ "line": 2, "col": 1 }, { "line": 2, "col": 20 }] },
"toclevels": { "value": "1", "location": [{ "line": 3, "col": 1 }, { "line": 3, "col": 13 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 13 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 13 }]
}
3 changes: 3 additions & 0 deletions test/tests/block/attributes/soft-wrap-after-space-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:lml: lightweight \
markup \
language
11 changes: 11 additions & 0 deletions test/tests/block/attributes/soft-wrap-after-space-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"lml": { "value": "lightweight markup language", "location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 8 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 8 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 3, "col": 8 }]
}
2 changes: 2 additions & 0 deletions test/tests/block/attributes/soft-wrap-indented-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:description: This is the description. \
It summaries the contents of this article.
11 changes: 11 additions & 0 deletions test/tests/block/attributes/soft-wrap-indented-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "document",
"type": "block",
"header": {
"attributes": {
"description": { "value": "This is the description. It summaries the contents of this article.", "location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 56 }] }
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 56 }]
},
"location": [{ "line": 1, "col": 1 }, { "line": 2, "col": 56 }]
}
2 changes: 2 additions & 0 deletions test/tests/block/attributes/soft-wrap-input.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:ad: Ascii\
Doc
Loading