From 299c4d93597b3065e6a1017ebe692cde66fc5e39 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 11 Oct 2021 01:03:21 +0200 Subject: feat(web): experiment with Lezer parser --- language-web/src/main/js/editor/indentation.ts | 84 ++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 language-web/src/main/js/editor/indentation.ts (limited to 'language-web/src/main/js/editor/indentation.ts') diff --git a/language-web/src/main/js/editor/indentation.ts b/language-web/src/main/js/editor/indentation.ts new file mode 100644 index 00000000..b2f0134b --- /dev/null +++ b/language-web/src/main/js/editor/indentation.ts @@ -0,0 +1,84 @@ +import { TreeIndentContext } from '@codemirror/language'; + +/** + * Finds the `from` of first non-skipped token, if any, + * after the opening keyword in the first line of the declaration. + * + * Based on + * https://github.com/codemirror/language/blob/cd7f7e66fa51ddbce96cf9396b1b6127d0ca4c94/src/indent.ts#L246 + * + * @param context the indentation context + * @returns the alignment or `null` if there is no token after the opening keyword + */ +function findAlignmentAfterOpening(context: TreeIndentContext): number | null { + const { + node: tree, + simulatedBreak, + } = context; + const openingToken = tree.childAfter(tree.from); + if (openingToken === null) { + return null; + } + const openingLine = context.state.doc.lineAt(openingToken.from); + const lineEnd = simulatedBreak == null || simulatedBreak <= openingLine.from + ? openingLine.to + : Math.min(openingLine.to, simulatedBreak); + const { cursor } = openingToken; + while (cursor.next() && cursor.from < lineEnd) { + if (!cursor.type.isSkipped) { + return cursor.from; + } + } + return null; +} + +/** + * Indents text after declarations by a single unit if it begins on a new line, + * otherwise it aligns with the text after the declaration. + * + * Based on + * https://github.com/codemirror/language/blob/cd7f7e66fa51ddbce96cf9396b1b6127d0ca4c94/src/indent.ts#L275 + * + * @example + * Result with no hanging indent (indent unit = 2 spaces, units = 1): + * ``` + * scope + * Family = 1, + * Person += 5..10. + * ``` + * + * @example + * Result with hanging indent: + * ``` + * scope Family = 1, + * Person += 5..10. + * ``` + * + * @param context the indentation context + * @param units the number of units to indent + * @returns the desired indentation level + */ +function indentDeclarationStrategy(context: TreeIndentContext, units: number): number { + const alignment = findAlignmentAfterOpening(context); + if (alignment !== null) { + return context.column(alignment); + } + return context.baseIndent + units * context.unit; +} + +export function indentBlockComment(): number { + // Do not indent. + return -1; +} + +export function indentDeclaration(context: TreeIndentContext): number { + return indentDeclarationStrategy(context, 1); +} + +export function indentPredicate(context: TreeIndentContext): number { + const clauseIndent = indentDeclarationStrategy(context, 1); + if (/^\s+(;|\.)/.exec(context.textAfter) !== null) { + return clauseIndent - context.unit; + } + return clauseIndent; +} -- cgit v1.2.3-70-g09d2