@remigius42/morg 0.10.0 → 0.10.1
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.
|
@@ -4,7 +4,7 @@ import { positionParser, tryParse } from "../core/render.js";
|
|
|
4
4
|
import { ZERO_WIDTH_SPACE } from "../core/markupBoundary.js";
|
|
5
5
|
import { mapOutsideCode } from "../core/outsideCode.js";
|
|
6
6
|
import { isDrawerStart, isOrgBlockStart, orgElementEnd } from "../core/passthroughSource.js";
|
|
7
|
-
import { readVanillaMarkdownOutline } from "./logseqVanillaMarkdown.js";
|
|
7
|
+
import { columns, dedent as dedentColumns, readVanillaMarkdownOutline } from "./logseqVanillaMarkdown.js";
|
|
8
8
|
// Logseq stores a page as an outline of blocks, each block a content
|
|
9
9
|
// string it parses on its own: org writes a block as its level's stars,
|
|
10
10
|
// a space and the content (an empty block as the bare stars), Markdown
|
|
@@ -710,14 +710,14 @@ function queryCodeToBlocks(content) {
|
|
|
710
710
|
}
|
|
711
711
|
return result;
|
|
712
712
|
}
|
|
713
|
-
// Logseq Markdown:
|
|
714
|
-
// a Vanilla list item would read as its content's column
|
|
713
|
+
// Logseq Markdown: indentation after a bullet the whole content shares,
|
|
714
|
+
// which a Vanilla list item would read as its content's column
|
|
715
715
|
function dedentCommon(content) {
|
|
716
716
|
const indent = Math.min(...content
|
|
717
717
|
.filter(line => line.trim())
|
|
718
|
-
.map(line => /^ */.exec(line)?.[0]
|
|
718
|
+
.map(line => columns(/^[ \t]*/.exec(line)?.[0] ?? "")));
|
|
719
719
|
return Number.isFinite(indent) && indent
|
|
720
|
-
? content.map(line => line
|
|
720
|
+
? content.map(line => dedentColumns(line, indent))
|
|
721
721
|
: content;
|
|
722
722
|
}
|
|
723
723
|
// a translation's page links, but in code
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Outline } from "./logseqOutline.js";
|
|
2
2
|
import type { ConversionContext } from "./types.js";
|
|
3
|
+
export declare function dedent(line: string, column: number): string;
|
|
4
|
+
export declare function columns(text: string, start?: number): number;
|
|
3
5
|
/**
|
|
4
6
|
* Reads a Vanilla Markdown page into Logseq's outline.
|
|
5
7
|
* @param markdown The Markdown page.
|
|
@@ -70,10 +70,29 @@ function readMeta(lines, context) {
|
|
|
70
70
|
}
|
|
71
71
|
return meta;
|
|
72
72
|
}
|
|
73
|
-
// a lazy continuation line sits anywhere left of the column
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
// a lazy continuation line sits anywhere left of the column; a tab
|
|
74
|
+
// reaches the next tab stop (4), the part of it right of the column
|
|
75
|
+
// stays as spaces
|
|
76
|
+
export function dedent(line, column) {
|
|
77
|
+
let width = 0;
|
|
78
|
+
let i = 0;
|
|
79
|
+
while (width < column && (line[i] === " " || line[i] === "\t")) {
|
|
80
|
+
width = columns(line[i++] ?? "", width);
|
|
81
|
+
}
|
|
82
|
+
return " ".repeat(Math.max(0, width - column)) + line.slice(i);
|
|
83
|
+
}
|
|
84
|
+
// the column text ends at, from a start column, a tab reaching the next
|
|
85
|
+
// tab stop
|
|
86
|
+
export function columns(text, start = 0) {
|
|
87
|
+
let width = start;
|
|
88
|
+
for (const char of text) {
|
|
89
|
+
width += char === "\t" ? 4 - (width % 4) : 1;
|
|
90
|
+
}
|
|
91
|
+
return width;
|
|
92
|
+
}
|
|
93
|
+
// the column a list item's content starts at
|
|
94
|
+
function contentColumn(line) {
|
|
95
|
+
return columns(BULLET_RE.exec(line)?.[0] ?? "");
|
|
77
96
|
}
|
|
78
97
|
function leadingProperties(lines) {
|
|
79
98
|
const count = lines.findIndex(line => !PROPERTY_RE.test(line));
|
|
@@ -83,9 +102,9 @@ function leadingProperties(lines) {
|
|
|
83
102
|
// its checkbox read, continuation lines moved left past the bullet
|
|
84
103
|
function itemSource(item, end, lines) {
|
|
85
104
|
const [first = "", ...rest] = lines.slice(span(item)[0], end + 1);
|
|
86
|
-
const column =
|
|
105
|
+
const column = contentColumn(first);
|
|
87
106
|
return [
|
|
88
|
-
taskTitle(item, first.slice(
|
|
107
|
+
taskTitle(item, first.slice(BULLET_RE.exec(first)?.[0].length ?? 0)),
|
|
89
108
|
...rest.map(line => dedent(line, column))
|
|
90
109
|
];
|
|
91
110
|
}
|
|
@@ -123,7 +142,7 @@ function readItem(item, level, ordered, reader) {
|
|
|
123
142
|
reader.blocks.push(block);
|
|
124
143
|
// what follows the first nested list: more lists, and text, which a
|
|
125
144
|
// block's content cannot hold after its children, as child blocks
|
|
126
|
-
const column =
|
|
145
|
+
const column = contentColumn(reader.lines[span(item)[0]] ?? "");
|
|
127
146
|
const rest = nested[0]
|
|
128
147
|
? item.children.slice(item.children.indexOf(nested[0]))
|
|
129
148
|
: [];
|
|
@@ -140,7 +159,7 @@ function readItem(item, level, ordered, reader) {
|
|
|
140
159
|
meta: [],
|
|
141
160
|
content: reader.lines
|
|
142
161
|
.slice(start, end + 1)
|
|
143
|
-
.map(line => dedent(line, column
|
|
162
|
+
.map(line => dedent(line, column))
|
|
144
163
|
});
|
|
145
164
|
}
|
|
146
165
|
}
|
|
@@ -279,7 +298,7 @@ function readText(node, level, body, reader) {
|
|
|
279
298
|
const [start, end] = span(node);
|
|
280
299
|
// a rule's source may be bulleted (`- ---`), a list in a block
|
|
281
300
|
// read from its own column, as an item's content is
|
|
282
|
-
const column = (node.position?.start.column ?? 1) - 1;
|
|
301
|
+
const column = columns(reader.lines[start]?.slice(0, (node.position?.start.column ?? 1) - 1) ?? "");
|
|
283
302
|
const source = node.type === "thematicBreak"
|
|
284
303
|
? ["---"]
|
|
285
304
|
: reader.lines.slice(start, end + 1).map(line => dedent(line, column));
|
package/dist/presets/obsidian.js
CHANGED
|
@@ -23,7 +23,8 @@ export function obsidian() {
|
|
|
23
23
|
translateMarkdown: (markdown, context) => context.side === "input" ? toVanilla(markdown) : markdown
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
// not an embed, whose `|300` is a size
|
|
27
|
+
const ALIASED_WIKILINK_RE = /(?<!!)\[\[([^\][|]+)\|([^\][]+)\]\]/g;
|
|
27
28
|
// in Markdown text: not an embed, whose `|300` is a size, and with a
|
|
28
29
|
// table cell's escaped pipe (`[[Page\|alias]]`)
|
|
29
30
|
const ALIASED_PAGE_LINK_RE = /(?<!!)\[\[([^\][|\\]+)\\?\|([^\][]+)\]\]/g;
|
|
@@ -44,11 +45,17 @@ function fuzzyLinksToWikilinks(uniorgAst) {
|
|
|
44
45
|
return undefined;
|
|
45
46
|
}
|
|
46
47
|
const description = node.children.length ? toString(node) : "";
|
|
48
|
+
// an embed's `!` goes with it, else Markdown escapes it before `[`
|
|
49
|
+
const previous = parent.children[index - 1];
|
|
50
|
+
const embed = previous?.type === "text" && previous.value.endsWith("!");
|
|
51
|
+
if (embed) {
|
|
52
|
+
previous.value = previous.value.slice(0, -1);
|
|
53
|
+
}
|
|
47
54
|
parent.children[index] = {
|
|
48
55
|
type: "verbatim-inline",
|
|
49
|
-
value: description
|
|
56
|
+
value: `${embed ? "!" : ""}${description
|
|
50
57
|
? `[[${node.rawLink}|${description}]]`
|
|
51
|
-
: `[[${node.rawLink}]]`
|
|
58
|
+
: `[[${node.rawLink}]]`}`
|
|
52
59
|
};
|
|
53
60
|
return undefined;
|
|
54
61
|
});
|