Is mixed parsing recursive?

Hello, I’m noticing something goofy, and I’m not sure if I’m doing something silly or not.

I have one language:

export const glimmerLanguage = glimmerPlain.configure({
  wrap: configureNesting(defaultNesting),
});

export function glimmer() {
  return new LanguageSupport(glimmerLanguage, [
    autoCloseTags,
    htmlLanguage.data.of({ autocomplete: htmlCompletionSourceWith({}) }),

    // nested languages
    javascript().support,
    css().support,
  ]);
}

And then I wrap

export function gjs() {
  return new LanguageSupport(gjsLanguage, [glimmer().support, css().support, javascript().support]);

}

export const gjsLanguage = LRLanguage.define({
  parser: metaParser.configure({
    wrap: parseMixed((node) => {
      if (node.type.name === 'Document') return null;
      if (node.type.name === 'GlimmerTemplateTag') return { parser: glimmerParser };

      return { parser: javascriptLanguage.parser };
    }),
  }),
});

my tests with just glimmer correctly highlight <style> tags’ contents as CSS, but that is not the case when I try to use gjs

In both tests, I’m doing, I’m setting up Codemirror this way:

export const mainView = new EditorView({
  state: EditorState.create({
    doc,
    extensions: [
      basicSetup,
      gjs(), // or glimmer()
      oneDark,
      EditorView.lineWrapping,
      syncAST,
    ],
  }),
  parent: document.querySelector('#editor'),
});

is there something silly I’m doing to not get the deeply nested mixed-parsing? or is it not supported?

Yes, nested parsing should work recursively (as you can see for example by putting some HTML with a <script> tag in a Markdown code block).

1 Like

I figured out my issue – I was mixing with the native lezer parser instead of the Built up LRLanguage I made with that parser, which included the nested mixing.

Followup question – with markdown, is it possible to get the completions from the “language-data”? right now, I don’t have completions / snippet support. :thinking:

This is the custom markdown thing I made:

export function glimdown() {
  return markdown({
    base: markdownLang(extendedMarkdown),
    codeLanguages: [
      ...languages,
      LanguageDescription.of({
        name: 'glimmer',
        alias: ['hbs', 'glimmer', 'ember', 'handlebars'],
        extensions: ['hbs'],
        async load() {
          const { glimmer } = await import('codemirror-lang-glimmer');

          return glimmer();
        },
      }),
      LanguageDescription.of({
        name: 'glimmer-js',
        alias: ['gjs', 'glimmer-js', 'javascript.glimmer'],
        extensions: ['gjs'],
        async load() {
          const { gjs } = await import('codemirror-lang-glimmer-js');

          return gjs();
        },
      }),
      LanguageDescription.of({
        name: 'glimmer-ts',
        alias: ['gts', 'glimmer-ts', 'typescript.glimmer'],
        extensions: ['gts'],
        async load() {
          const { gts } = await import('codemirror-lang-glimmer-js');

          return gts();
        },
      }),
    ],
  });
}

and individually each of those languages has snippets / completions / etc.
But now when hosted by the markdown thing here (called glimdown)

I see in this demo that JS has completiions: Try CodeMirror

I must’ve missed something when configuring these :thinking:

When you call .support() does that include the autocompletions?

For example, with gjs:

export function gjs() {
  return new LanguageSupport(gjsLanguage, [glimmer().support]);
}

export const gjsLanguage = LRLanguage.define({
  parser: metaParser.configure({
    wrap: parseMixed((node) => {
      if (node.type.name === 'Document') return null;

      if (node.type.name === 'GlimmerTemplateTag') {
        return { parser: glimmerLanguage.parser };
      }

      return { parser: javascriptLanguage.parser };
    }),
  }),
});

I call glimmer().support
and glimmer is defined as:

export function glimmer() {
  return new LanguageSupport(glimmerLanguage, [
    javascript().support,
    css().support,
    new LanguageSupport(
      LRLanguage.define({
        name: 'glimmer-expression',
        parser: glimmerExpressionParser.configure({}),
      }),
      []
    ),
    glimmerLanguage.data.of({ autocomplete: snippets }),
    glimmerLanguage.data.of({ autocomplete: htmlTagCompletion }),
    autoCloseTags,
  ]);
}

and there are the competitions, using data.of

You’ll have to explicitly include the LanguageSupport.support values for the languages you are interested in in your editor configuration. The Markdown parser can load sub-parsers on demand via language-data, but it won’t reconfigure the editor.