mirror of
https://github.com/heyman/heynote.git
synced 2025-02-16 10:19:55 +01:00
Optimize block parsing when syntax tree isn't available.
If the syntax tree isn't available, use String.indexOf to parse the blocks.
This commit is contained in:
parent
48a29c7552
commit
29d4eb26cc
@ -1,7 +1,7 @@
|
|||||||
import { ViewPlugin, EditorView, Decoration, WidgetType, lineNumbers } from "@codemirror/view"
|
import { ViewPlugin, EditorView, Decoration, WidgetType, lineNumbers } from "@codemirror/view"
|
||||||
import { layer, RectangleMarker } from "@codemirror/view"
|
import { layer, RectangleMarker } from "@codemirror/view"
|
||||||
import { EditorState, RangeSetBuilder, StateField, Facet , StateEffect, RangeSet} from "@codemirror/state";
|
import { EditorState, RangeSetBuilder, StateField, Facet , StateEffect, RangeSet} from "@codemirror/state";
|
||||||
import { syntaxTree, ensureSyntaxTree } from "@codemirror/language"
|
import { syntaxTree, ensureSyntaxTree, syntaxTreeAvailable } from "@codemirror/language"
|
||||||
import { Note, Document, NoteDelimiter } from "../lang-heynote/parser.terms.js"
|
import { Note, Document, NoteDelimiter } from "../lang-heynote/parser.terms.js"
|
||||||
import { IterMode } from "@lezer/common";
|
import { IterMode } from "@lezer/common";
|
||||||
import { heynoteEvent, LANGUAGE_CHANGE } from "../annotation.js";
|
import { heynoteEvent, LANGUAGE_CHANGE } from "../annotation.js";
|
||||||
@ -10,12 +10,28 @@ import { mathBlock } from "./math.js"
|
|||||||
import { emptyBlockSelected } from "./select-all.js";
|
import { emptyBlockSelected } from "./select-all.js";
|
||||||
|
|
||||||
|
|
||||||
|
function startTimer() {
|
||||||
|
const timeStart = performance.now();
|
||||||
|
return function () {
|
||||||
|
return Math.round(performance.now() - timeStart);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// tracks the size of the first delimiter
|
// tracks the size of the first delimiter
|
||||||
let firstBlockDelimiterSize
|
let firstBlockDelimiterSize
|
||||||
|
|
||||||
function getBlocks(state, timeout=50) {
|
/**
|
||||||
|
* Return a list of blocks in the document from the syntax tree.
|
||||||
|
* syntaxTreeAvailable() should have been called before this function to ensure the syntax tree is available.
|
||||||
|
* @param {*} state
|
||||||
|
* @param {*} timeout
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function getBlocksFromSyntaxTree(state, timeout=50) {
|
||||||
|
//const timer = startTimer()
|
||||||
const blocks = [];
|
const blocks = [];
|
||||||
const tree = ensureSyntaxTree(state, state.doc.length, timeout)
|
const tree = syntaxTree(state, state.doc.length, timeout)
|
||||||
if (tree) {
|
if (tree) {
|
||||||
tree.iterate({
|
tree.iterate({
|
||||||
enter: (type) => {
|
enter: (type) => {
|
||||||
@ -52,9 +68,79 @@ function getBlocks(state, timeout=50) {
|
|||||||
});
|
});
|
||||||
firstBlockDelimiterSize = blocks[0]?.delimiter.to
|
firstBlockDelimiterSize = blocks[0]?.delimiter.to
|
||||||
}
|
}
|
||||||
|
//console.log("getBlocksSyntaxTree took", timer(), "ms")
|
||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the blocks for the document state.
|
||||||
|
* If the syntax tree is available, we'll extract the blocks from that. Otherwise
|
||||||
|
* the blocks are parsed from the string contents of the document, which is much faster
|
||||||
|
* than waiting for the tree parsing to finnish.
|
||||||
|
*/
|
||||||
|
function getBlocks(state) {
|
||||||
|
if (syntaxTreeAvailable(state, state.doc.length)) {
|
||||||
|
return getBlocksFromSyntaxTree(state)
|
||||||
|
}
|
||||||
|
//const timer = startTimer()
|
||||||
|
const blocks = []
|
||||||
|
const doc = state.doc
|
||||||
|
if (doc.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const content = doc.sliceString(0, doc.length)
|
||||||
|
const delim = "\n∞∞∞"
|
||||||
|
let pos = 0
|
||||||
|
while (pos < doc.length) {
|
||||||
|
const blockStart = content.indexOf(delim, pos);
|
||||||
|
if (blockStart != pos) {
|
||||||
|
console.error("Error parsing blocks, expected delimiter at", pos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const langStart = blockStart + delim.length;
|
||||||
|
const delimiterEnd = content.indexOf("\n", langStart)
|
||||||
|
if (delimiterEnd < 0) {
|
||||||
|
console.error("Error parsing blocks. Delimiter didn't end with newline")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
const langFull = content.substring(langStart, delimiterEnd);
|
||||||
|
let auto = false;
|
||||||
|
let lang = langFull;
|
||||||
|
if (langFull.endsWith("-a")) {
|
||||||
|
auto = true;
|
||||||
|
lang = langFull.substring(0, langFull.length - 2);
|
||||||
|
}
|
||||||
|
const contentFrom = delimiterEnd + 1;
|
||||||
|
let blockEnd = content.indexOf(delim, contentFrom);
|
||||||
|
if (blockEnd < 0) {
|
||||||
|
blockEnd = doc.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const block = {
|
||||||
|
language: {
|
||||||
|
name: lang,
|
||||||
|
auto: auto,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
from: contentFrom,
|
||||||
|
to: blockEnd,
|
||||||
|
},
|
||||||
|
delimiter: {
|
||||||
|
from: blockStart,
|
||||||
|
to: delimiterEnd + 1,
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
from: blockStart,
|
||||||
|
to: blockEnd,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
blocks.push(block);
|
||||||
|
pos = blockEnd;
|
||||||
|
}
|
||||||
|
//console.log("getBlocks (string parsing) took", timer(), "ms")
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
export const blockState = StateField.define({
|
export const blockState = StateField.define({
|
||||||
create(state) {
|
create(state) {
|
||||||
return getBlocks(state, 1000);
|
return getBlocks(state, 1000);
|
||||||
|
Loading…
Reference in New Issue
Block a user