Creating a simple extension syntax… examples? Guidance

I’m not finding the documentation on how to create a language extension syntax simple.

All I want to do is define multiline comments embedded inside .ts, .js, and .css files (for starters) that start with a bang as being markdown and, ideally, embedded code in markdown as being of the appropriate language so that:

Note that I’m using the tag here because quoting the markdown for it is fraught :smiley:

<pre>js
// is treated as javascript
</pre>

I’ve written a documentation system that relies on this (I used to use /** */ but so many programs — visual study code, cough — treat that as jsDoc that I gave up. It even finds contiguous sets of code comments and assembles them into live examples (“fiddles”). You can check it the <live-example> web-component here if you’re curious.

The documentation says this only works for syntaxes defined using tree sitter but there’s no information on whether the ts, js, or css grammars build into Nova qualify.

Anyway, thanks in advance if you have any pointers.

1 Like

The ts, js, and css are all tree-sitters based grammars. :deciduous_tree:

I do not think this is possible at the moment. I however done a similar feature request for this on the dev forum not long ago. It is actually something very useful with countless use cases including the one you mentioned here. Hopefully as more of us start asking, they would eventually add support? :eyes:

It is definitely technically possible but I am not sure how they would implement it. I hope the API is a clean one!

There is also a NeoVim example on the feature request on how you might be able to achieve this, once, if ever supported, but again this is very dirty, you need to dig and mess around with each tree-sitters grammar manually which in turn might break things etc. :joy: I am really not a fan of that for sure!

It seems to me that the problem isn’t functionality it’s documentation.

The documentation for language injections literally suggests that the markdown grammar already supports embedded languages via injection but the documentation is so vague as to be useless.

https://docs.nova.app/syntax-reference/syntaxes/#injections

All I want is for:

/*! */ and

to be considered markdown (and then for html to be considered embedded HTML etc), and I haven’t the foggiest where to start despite the fact that it’s all but cited as an example in the “documentation”.

This is pretty straightforward in Visual Studio Code.

I totally understand what you mean, or trying to do. Unfortunately it is the Nova API shortcoming … which is quite frustrating.
As you said easily achieved in VS Code. But having said that, IF Nova implements this, the Tree-Sitter is far more superior :wink:

To clear up the confusion, let me expand a bit more.

With markdown, the injection node is defined by the grammar, under $.fenced_code_block_delimiter [It is defined as an external scanner it is not part of grammar.js].
As it is fundamental part of markdown, of course it makes sense to be part of the grammar.
Now that we have the facility. The injection happens sort of dynamic like this after capturing the node’s content. again defined in the markdown queries folder.

; Fenced code blocks
(fenced_code_block
  (info_string (language) @injection.language)
  (code_fence_content) @injection.content
)

Now in your case, this means, sending pull request to every single tree-sitter repo and ask them to define pre or /*! */ or <pre> in their grammar which is not practical… and to be honest not the best way anyways.

For example AlpineJS is used by many other frameworks, or even stand-alone. Rather than me changing the base tree-sitter-html or any other framework, to define the x-whatever and then inject JS inside it, Nova should give us a facility to “extend the injections” for the html. Which is exactly what you need. The ability to extend the injection for css, html or any language you want to implement your functionality.

To give you a concrete example of the end result, here is how it can be achieved in NeoVim. As the guts are out and ready for manipulation, here is how one user managed to get the AlpineJS injection working in any framework, language, basically everywhere that is being parsed as html. But that meant him manually changing content of the injections.scm for tree-sitter-html:

Look at the code example under “AlpineJS injection”. They are basically saying, in html if the attribute name is such and such, treat it’s attribute value’s content as JS.

In your case you are doing the exact same thing, if it was allowed by Nova.

  1. grab the $.tag_name and check if it is <pre>
  2. Somehow grab the first word that follows
    • This might be your biggest hurdle. As when you write:
    <pre>html
       //content
    </pre>
    
    • The whole html+content are grabbed as ONE node called $.text
    • Not sure if you can grab the first-word pre space/newline/tab using the tree-sittter query capture and then apply the language.
  3. Use whatever language captured, as an injected language, inside the $.text

It is geniunely a valid request you have but, for some reason our hands are tight, and a bit more complicated than it needs to be… If supported it will give us all a super power though.

As long as I know, injections :syringe: were a pain, in any code editor I have ever worked in with… :expressionless: we are so close to nailing it, with tree-sitter though. This is the best and closest we have been in fixing the injection hell!