Skip to content

Instantly share code, notes, and snippets.

@e111077
Last active March 13, 2025 20:19
Show Gist options
  • Select an option

  • Save e111077/7e1c4212bc8b408d8f8d0abacac824a8 to your computer and use it in GitHub Desktop.

Select an option

Save e111077/7e1c4212bc8b408d8f8d0abacac824a8 to your computer and use it in GitHub Desktop.
Naiive Tagged Template Literal Support in Codemirror 6
import { LanguageSupport, LRLanguage } from '@codemirror/language';
import { LRParser } from '@lezer/lr';
import { Input, parseMixed, SyntaxNodeRef } from '@lezer/common';
import { htmlLanguage } from '@codemirror/lang-html';
import {javascript} from '@codemirror/lang-javascript';
import {CodeMirrorExtensionElement} from 'codemirror-elements/lib/cm-extension-element.js';
function mixedTaggedTemplate(node: SyntaxNodeRef, input: Input) {
const isTaggedTemplate = node.type.name === "TaggedTemplateExpression";
let isHtmlTag = false;
if (isTaggedTemplate) {
const tag = node.node.getChild("VariableName");
isHtmlTag = !!tag && input.read(tag.from, tag.to) === "html";
}
// Check if the node is a TaggedTemplate literal and the tag is "html"
if (isHtmlTag) {
const content = node.node.getChild("TemplateString");
// jump into the html language parser
if (content) {
return {
from: content.from,
to: content.to,
parser: htmlLanguage.parser,
delims: { open: "${", close: "}" }
};
}
}
return null;
}
// Create our mixed wrapper using parseMixed.
const mixedWrapper = parseMixed(mixedTaggedTemplate);
@customElement('cm-lang-javascript')
export class CodeMirrorLangJavascript extends CodeMirrorExtensionElement {
@property({ type: Boolean })
jsx = false;
@property({ type: Boolean })
typescript = false;
override update(changedProperties: PropertyValues<this>) {
if (changedProperties.has('jsx') || changedProperties.has('typescript')) {
// Create the base JavaScript language support extension
const jsSupport = javascript({
jsx: this.jsx,
typescript: this.typescript
});
const baseParser = jsSupport.language.parser as LRParser;
// Configure the parser to use our mixed-language wrapper.
const wrappedParser = baseParser.configure({ wrap: mixedWrapper });
// Create a language from the wrapped parser
const taggedTemplateLanguage = LRLanguage.define({
parser: wrappedParser,
languageData: jsSupport.language.data.of({})
});
// Build a new LanguageSupport extension with the new parser.
const taggedTemplateLiteralLanguageSupport = new LanguageSupport(
taggedTemplateLanguage,
jsSupport.extension
);
// Set the new extension on the editor.
this.setExtensions([taggedTemplateLiteralLanguageSupport]);
}
super.update(changedProperties);
}
}
@e111077
Copy link
Author

e111077 commented Mar 13, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment