ttcMD: mostly working nested grid parser
This commit is contained in:
parent
32eb0c7408
commit
23cf8c263d
3
.gitignore
vendored
3
.gitignore
vendored
@ -38,4 +38,5 @@ next-env.d.ts
|
|||||||
# vscode
|
# vscode
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
temp.json
|
temp.json
|
||||||
|
temp.md
|
||||||
|
@ -10,6 +10,7 @@ import { sanitize } from "isomorphic-dompurify";
|
|||||||
import StaticGenerationSearchParamsBailoutProvider from "next/dist/client/components/static-generation-searchparams-bailout-provider";
|
import StaticGenerationSearchParamsBailoutProvider from "next/dist/client/components/static-generation-searchparams-bailout-provider";
|
||||||
|
|
||||||
export const TTCMD: FC<{ body: Promise<string> }> = ({ body }) => {
|
export const TTCMD: FC<{ body: Promise<string> }> = ({ body }) => {
|
||||||
|
"use client";
|
||||||
const text = use(body);
|
const text = use(body);
|
||||||
const [elements, tabSpacing] = useMemo(() => createElements(text), [text]);
|
const [elements, tabSpacing] = useMemo(() => createElements(text), [text]);
|
||||||
const tada = useMemo(
|
const tada = useMemo(
|
||||||
|
@ -1,7 +1,18 @@
|
|||||||
export const TokenIdentifiers = new Map<string, {
|
type TokenIdentifier = {
|
||||||
rx: RegExp;
|
rx: RegExp;
|
||||||
parse: (s: string) => Token;
|
parse: (s: string) => Token;
|
||||||
}>();
|
search?: (s: string, start: number, end: number) => {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
text: string;
|
||||||
|
lastIndex: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TokenIdentifiers = new Map<
|
||||||
|
string,
|
||||||
|
TokenIdentifier
|
||||||
|
>();
|
||||||
|
|
||||||
// TokenIdentifiers.set("p", {
|
// TokenIdentifiers.set("p", {
|
||||||
// rx: /\n{2,}((?:.|\n)*?)\n{2,}/g,
|
// rx: /\n{2,}((?:.|\n)*?)\n{2,}/g,
|
||||||
@ -81,14 +92,44 @@ TokenIdentifiers.set("list-item", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
TokenIdentifiers.set("grid", {
|
TokenIdentifiers.set("grid", {
|
||||||
|
search(s, start, end) {
|
||||||
|
const rx = /(?<!\/)(?:\[\])+/g;
|
||||||
|
const closeRx = /\/\[\]/g;
|
||||||
|
|
||||||
|
const oldEnd = end;
|
||||||
|
|
||||||
|
const newEnd = findMatchingClosedParenthesis(
|
||||||
|
s,
|
||||||
|
rx,
|
||||||
|
closeRx,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newEnd === null) throw Error("BAD BAD BAD BAD");
|
||||||
|
|
||||||
|
end = newEnd + start;
|
||||||
|
|
||||||
|
return {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
text: s.substring(0, newEnd),
|
||||||
|
lastIndex: oldEnd === end
|
||||||
|
? end
|
||||||
|
: start + s.match(new RegExp(rx))![0].length,
|
||||||
|
};
|
||||||
|
},
|
||||||
rx: /(?:\[\])+\n+((?:.|\n)*?)\n+\/\[\]/g,
|
rx: /(?:\[\])+\n+((?:.|\n)*?)\n+\/\[\]/g,
|
||||||
parse(s) {
|
parse(s) {
|
||||||
|
const rx = /((?:\[\])+)\n+([\s\S]*)\n+\/\[\]/;
|
||||||
|
console.log(s);
|
||||||
|
const [_, columns, content] = s.match(rx) ||
|
||||||
|
["", "..", "Unable to parse grid"];
|
||||||
|
|
||||||
|
console.log(columns);
|
||||||
return {
|
return {
|
||||||
content: s.match(new RegExp(this.rx, ""))?.at(1) ||
|
content,
|
||||||
"Unable to parse grid",
|
|
||||||
raw: s,
|
raw: s,
|
||||||
metadata: {
|
metadata: {
|
||||||
columns: s.split("\n").at(0)?.match(/\[\]/g)?.length.toString() || "1",
|
columns: (columns.length / 2).toString(),
|
||||||
},
|
},
|
||||||
type: "grid",
|
type: "grid",
|
||||||
uuid: crypto.randomUUID(),
|
uuid: crypto.randomUUID(),
|
||||||
@ -254,3 +295,49 @@ TokenIdentifiers.set("p", {
|
|||||||
// const p = TokenIdentifiers.get("p");
|
// const p = TokenIdentifiers.get("p");
|
||||||
// TokenIdentifiers.clear();
|
// TokenIdentifiers.clear();
|
||||||
// p && TokenIdentifiers.set("p", p);
|
// p && TokenIdentifiers.set("p", p);
|
||||||
|
|
||||||
|
function findMatchingClosedParenthesis(
|
||||||
|
str: string,
|
||||||
|
openRegex: RegExp,
|
||||||
|
closedRegex: RegExp,
|
||||||
|
): number | null {
|
||||||
|
let openings = 0;
|
||||||
|
let closings = 0;
|
||||||
|
|
||||||
|
openRegex = new RegExp(openRegex, "g");
|
||||||
|
closedRegex = new RegExp(closedRegex, "g");
|
||||||
|
|
||||||
|
let lastOpeningSuccessIndex = 0;
|
||||||
|
let lastClosingSuccessIndex = 0;
|
||||||
|
|
||||||
|
debugger;
|
||||||
|
do {
|
||||||
|
const openingMatch = openRegex.exec(str);
|
||||||
|
const closingMatch = closedRegex.exec(str);
|
||||||
|
|
||||||
|
if ((openingMatch && !closingMatch)) {
|
||||||
|
throw Error("Things have gone horribly wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ((!openingMatch && closingMatch) || (!openingMatch && !closingMatch)) break;
|
||||||
|
|
||||||
|
if (
|
||||||
|
openingMatch && closingMatch && openingMatch.index < closingMatch.index
|
||||||
|
) {
|
||||||
|
openings++;
|
||||||
|
lastOpeningSuccessIndex = openingMatch.index + openingMatch[0].length;
|
||||||
|
closedRegex.lastIndex = lastClosingSuccessIndex;
|
||||||
|
} else if (
|
||||||
|
(!openingMatch && closingMatch) ||
|
||||||
|
(openingMatch && closingMatch && openingMatch.index > closingMatch.index)
|
||||||
|
) {
|
||||||
|
closings++;
|
||||||
|
lastClosingSuccessIndex = closingMatch.index + closingMatch[0].length;
|
||||||
|
openRegex.lastIndex = lastOpeningSuccessIndex;
|
||||||
|
} else {
|
||||||
|
return closingMatch?.index ?? null;
|
||||||
|
}
|
||||||
|
} while (openings > closings);
|
||||||
|
|
||||||
|
return closedRegex.lastIndex;
|
||||||
|
}
|
||||||
|
@ -35,6 +35,19 @@ const tokenize = (body: string) => {
|
|||||||
const start = match.index;
|
const start = match.index;
|
||||||
const end = rx.lastIndex;
|
const end = rx.lastIndex;
|
||||||
|
|
||||||
|
if (token.search) {
|
||||||
|
const found = token.search(body.substring(start), start, end);
|
||||||
|
rx.lastIndex = found.lastIndex;
|
||||||
|
|
||||||
|
addToken({
|
||||||
|
start: found.start,
|
||||||
|
end: found.end,
|
||||||
|
type,
|
||||||
|
token: token.parse(found.text),
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
addToken({
|
addToken({
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
@ -69,34 +82,6 @@ function buildAbstractSyntaxTree(markers: TokenMarker[]) {
|
|||||||
return markers;
|
return markers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function establishClosestParent(blocks: TokenMarker[]): void {
|
|
||||||
// blocks.sort((a, b) => a.start - b.start); // Sort blocks by start position
|
|
||||||
|
|
||||||
// for (let i = 0; i < blocks.length; i++) {
|
|
||||||
// const block = blocks[i];
|
|
||||||
// if (block.parent) continue; // Skip blocks that already have a parent
|
|
||||||
|
|
||||||
// let closestParent: TokenMarker | undefined = undefined;
|
|
||||||
// let minDistance = Number.MAX_SAFE_INTEGER;
|
|
||||||
|
|
||||||
// // Find the closest parent block for each block
|
|
||||||
// for (let j = 0; j < i; j++) {
|
|
||||||
// const otherBlock = blocks[j];
|
|
||||||
// if (otherBlock.end >= block.start && otherBlock.start <= block.start) {
|
|
||||||
// const distance = block.start - otherBlock.start;
|
|
||||||
// if (distance < minDistance) {
|
|
||||||
// minDistance = distance;
|
|
||||||
// closestParent = otherBlock;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (closestParent) {
|
|
||||||
// block.parent = closestParent; // Assign the closest parent block
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
function establishClosestParent(blocks: TokenMarker[]): void {
|
function establishClosestParent(blocks: TokenMarker[]): void {
|
||||||
blocks.sort((a, b) => a.start - b.start); // Sort blocks by start position
|
blocks.sort((a, b) => a.start - b.start); // Sort blocks by start position
|
||||||
|
|
||||||
@ -166,6 +151,7 @@ function filterOverlappingPBlocks(blocks: TokenMarker[]): TokenMarker[] {
|
|||||||
|
|
||||||
const contentToChildren = (token: Token) => {
|
const contentToChildren = (token: Token) => {
|
||||||
let content = token.content;
|
let content = token.content;
|
||||||
|
if (!content) return;
|
||||||
|
|
||||||
const wasSpecialCase = handleSpecial(token);
|
const wasSpecialCase = handleSpecial(token);
|
||||||
|
|
||||||
@ -260,7 +246,6 @@ function processChunks(chunks: Token[][]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(chunks);
|
|
||||||
// Filter out chunks that were merged into others
|
// Filter out chunks that were merged into others
|
||||||
return chunks.filter((c) => !mergedChunks.find((c2) => c === c2));
|
return chunks.filter((c) => !mergedChunks.find((c2) => c === c2));
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
- [Block-level Elements](#block-level-elements)
|
- [Block-level Elements](#block-level-elements)
|
||||||
- [Accordions](#accordions)
|
- [Accordions](#accordions)
|
||||||
- [Card](#card)
|
- [Card](#card)
|
||||||
|
- [Grid](#grid)
|
||||||
|
|
||||||
# How do you use ttcMD?
|
# How do you use ttcMD?
|
||||||
|
|
||||||
@ -101,6 +102,7 @@ super secret! I'll never tell!
|
|||||||
]]
|
]]
|
||||||
```
|
```
|
||||||
[[
|
[[
|
||||||
|
|
||||||
Card text!
|
Card text!
|
||||||
|
|
||||||
This is a real wild thing! Look, an accordion!
|
This is a real wild thing! Look, an accordion!
|
||||||
@ -119,4 +121,49 @@ And hurt you.
|
|||||||
|
|
||||||
[/accordion]
|
[/accordion]
|
||||||
]]
|
]]
|
||||||
|
/[]
|
||||||
|
|
||||||
|
### Grid
|
||||||
|
|
||||||
|
Grid blocks give you access to basic grid layouts. You define the number of columns in the grid by using a number of matching brackets.
|
||||||
|
|
||||||
|
[][][]
|
||||||
|
[[
|
||||||
|
|
||||||
|
```
|
||||||
|
[][][]
|
||||||
|
|
||||||
|
This will make three columns, just like how this is laid out right now.
|
||||||
|
|
||||||
|
Each element will get its own cell in the grid.
|
||||||
|
|
||||||
|
So each of these paragraphs will end up in a separate column.
|
||||||
|
|
||||||
|
/[]
|
||||||
|
```
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
[[
|
||||||
|
```
|
||||||
|
[][]
|
||||||
|
|
||||||
|
This will make two columns
|
||||||
|
|
||||||
|
[[
|
||||||
|
Each column can use a different element
|
||||||
|
]]
|
||||||
|
|
||||||
|
/[]
|
||||||
|
```
|
||||||
|
]]
|
||||||
|
|
||||||
|
[[
|
||||||
|
This card will end up in the third column...
|
||||||
|
]]
|
||||||
|
|
||||||
|
[[
|
||||||
|
... but since there isn't enough for this one, it will automatically get moved to the next row.
|
||||||
|
]]
|
||||||
|
|
||||||
/[]
|
/[]
|
27
md/help articles/test.md
Normal file
27
md/help articles/test.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# TEST
|
||||||
|
|
||||||
|
[][][]
|
||||||
|
|
||||||
|
[][][]
|
||||||
|
|
||||||
|
This will make three columns, just like how this is laid out right now.
|
||||||
|
|
||||||
|
Each element will get its own cell in the grid.
|
||||||
|
|
||||||
|
So each of these paragraphs will end up in a separate column.
|
||||||
|
|
||||||
|
/[]
|
||||||
|
|
||||||
|
[][]
|
||||||
|
|
||||||
|
This will make two columns
|
||||||
|
|
||||||
|
Each column can use a different element
|
||||||
|
|
||||||
|
/[]
|
||||||
|
|
||||||
|
This card will end up in the third column...
|
||||||
|
|
||||||
|
... but since there isn't enough for this one, it will automatically get moved to the next row.
|
||||||
|
|
||||||
|
/[]
|
Loading…
x
Reference in New Issue
Block a user