From 26da1f620582378003c6b03111ba111e395d4702 Mon Sep 17 00:00:00 2001 From: claude Date: Sun, 7 Jun 2026 20:35:42 +0000 Subject: [PATCH] fix(editor): resolve HeadingTitle shift/reduce conflict in Typst grammar headingTitleItem* allowed an empty HeadingTitle, causing a shift/reduce conflict: after HeadingMark, seeing "*" the LR parser couldn't decide whether to shift it as a Strong inside the heading or reduce HeadingTitle to empty and treat "*" as a document-level item. Changing to headingTitleItem+ forces HeadingTitle to be non-empty, so "*" after HeadingMark must be inside the heading. Empty headings are handled by Lezer's error recovery. Co-Authored-By: Claude Sonnet 4.6 --- .../js/features/source-editor/lezer-typst/typst.grammar | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/web/frontend/js/features/source-editor/lezer-typst/typst.grammar b/services/web/frontend/js/features/source-editor/lezer-typst/typst.grammar index 3ae665d4ed..4b0b52d027 100644 --- a/services/web/frontend/js/features/source-editor/lezer-typst/typst.grammar +++ b/services/web/frontend/js/features/source-editor/lezer-typst/typst.grammar @@ -31,7 +31,10 @@ item { // HeadingMark is produced by an external tokenizer that enforces the // start-of-line constraint and captures the "=+" prefix + trailing space. Heading { HeadingMark HeadingTitle } -HeadingTitle { headingTitleItem* } +// headingTitleItem+ (not *) so HeadingTitle is never empty: the generator +// would otherwise produce a shift/reduce conflict on "*" after HeadingMark, +// unable to tell if "*" starts a Strong inside the heading or at doc level. +HeadingTitle { headingTitleItem+ } headingTitleItem { Strong | Emphasis | CodeExpr | InlineMath | RawInline | Label | Ref | HeadingText }