diff --git a/.changeset/quiet-berries-sniff.md b/.changeset/quiet-berries-sniff.md new file mode 100644 index 0000000..d482fa5 --- /dev/null +++ b/.changeset/quiet-berries-sniff.md @@ -0,0 +1,10 @@ +--- +'uniorg-parse': major +'uniorg-stringify': minor +'uniorg-rehype': minor +'uniorg': minor +--- + +Support `line-break` in uniorg, uniorg-parse, uniorg-rehype, and uniorg-stringify. + +This is a breaking change for uniorg-parse as it may output nodes unknown to downstream users (uniorg-rehype and uniorg-stringify). If you upgrade uniorg-parse, you should also upgrade uniorg-rehype and uniorg-stringify to the corresponding versions. diff --git a/README.md b/README.md index 78bacd5..e1fd341 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,6 @@ However, there are a couple of places I haven't finished yet: - babel-call, inline-babel-call, inline-src-block - dynamic-block - target, radio-target -- line-break -- export-snippet - macro - switches and parameters in src-block and example-block - repeater/warning props in timestamp diff --git a/packages/uniorg-parse/src/__snapshots__/parser.spec.ts.snap b/packages/uniorg-parse/src/__snapshots__/parser.spec.ts.snap index 0021453..e81d787 100644 --- a/packages/uniorg-parse/src/__snapshots__/parser.spec.ts.snap +++ b/packages/uniorg-parse/src/__snapshots__/parser.spec.ts.snap @@ -2438,6 +2438,79 @@ children: value: "." `; +exports[`org/parser line-break fake line break (must be at end of line) 1`] = ` +type: "org-data" +contentsBegin: 0 +contentsEnd: 27 +children: + - type: "paragraph" + affiliated: {} + contentsBegin: 0 + contentsEnd: 27 + children: + - type: "text" + value: "some text\\\\" + - type: "entity" + useBrackets: false + name: "not" + latex: "\\\\textlnot{}" + requireLatexMath: false + html: "¬" + ascii: "[angled dash]" + latin1: "¬" + utf8: "¬" + - type: "text" + value: " a line break" +`; + +exports[`org/parser line-break fake line break (triple backslash) 1`] = ` +type: "org-data" +contentsBegin: 0 +contentsEnd: 26 +children: + - type: "paragraph" + affiliated: {} + contentsBegin: 0 + contentsEnd: 26 + children: + - type: "text" + value: "some text\\\\\\\\\\\\\\nnot next line" +`; + +exports[`org/parser line-break valid line break 1`] = ` +type: "org-data" +contentsBegin: 0 +contentsEnd: 22 +children: + - type: "paragraph" + affiliated: {} + contentsBegin: 0 + contentsEnd: 22 + children: + - type: "text" + value: "some text" + - type: "line-break" + - type: "text" + value: "line break" +`; + +exports[`org/parser line-break whitespace after \\\\ 1`] = ` +type: "org-data" +contentsBegin: 0 +contentsEnd: 24 +children: + - type: "paragraph" + affiliated: {} + contentsBegin: 0 + contentsEnd: 24 + children: + - type: "text" + value: "some text" + - type: "line-break" + - type: "text" + value: "line break" +`; + exports[`org/parser links ./ as start of file link 1`] = ` type: "org-data" contentsBegin: 0 diff --git a/packages/uniorg-parse/src/parser.spec.ts b/packages/uniorg-parse/src/parser.spec.ts index 837b8aa..a9f93cc 100644 --- a/packages/uniorg-parse/src/parser.spec.ts +++ b/packages/uniorg-parse/src/parser.spec.ts @@ -1106,4 +1106,25 @@ more text itParses('fake export snippet, missing backend', '@@@@'); }); + + describe('line-break', () => { + itParses( + 'valid line break', + `some text\\\\ +line break` + ); + + itParses('whitespace after \\\\', `some text\\\\ \nline break`); + + itParses( + 'fake line break (must be at end of line)', + `some text\\\\not a line break` + ); + + itParses( + 'fake line break (triple backslash)', + `some text\\\\\\ +not next line` + ); + }); }); diff --git a/packages/uniorg-parse/src/parser.ts b/packages/uniorg-parse/src/parser.ts index b281ced..a62b2df 100644 --- a/packages/uniorg-parse/src/parser.ts +++ b/packages/uniorg-parse/src/parser.ts @@ -53,6 +53,7 @@ import { CitationSuffix, CitationCommonSuffix, ExportSnippet, + LineBreak, } from 'uniorg'; import { getOrgEntity } from './entities.js'; @@ -638,7 +639,9 @@ class Parser { break; case '\\': if (c[1] === '\\') { - // TODO: line break parser + if (restriction.has('line-break')) { + return this.parseLineBreak(); + } } else { const offset = this.r.offset(); const entity = restriction.has('entity') && this.parseEntity(); @@ -1707,6 +1710,19 @@ class Parser { return u('latex-fragment', { value, contents: contents ?? value }); } + private parseLineBreak(): LineBreak | null { + const m = this.r.lookingAt(/\\\\[ \t]*$/m); + if (!m) return null; + + // check character before linebreak + this.r.backoff(1); + if (this.r.peek(1) === '\\') return null; + + this.r.advance(this.r.line()); + + return u('line-break'); + } + private parseFootnoteReference(): FootnoteReference | null { const begin = this.r.offset(); const m = this.r.match(footnoteRe); diff --git a/packages/uniorg-rehype/src/__snapshots__/org-to-hast.spec.ts.snap b/packages/uniorg-rehype/src/__snapshots__/org-to-hast.spec.ts.snap index 72305c0..913a87e 100644 --- a/packages/uniorg-rehype/src/__snapshots__/org-to-hast.spec.ts.snap +++ b/packages/uniorg-rehype/src/__snapshots__/org-to-hast.spec.ts.snap @@ -354,6 +354,12 @@ exports[`org/org-to-hast latex-fragment 1`] = ` `; +exports[`org/org-to-hast line-break 1`] = ` + +
hello
world