home ~ socials ~ projects ~ rss

Initial Notes on Making the Neopoligen Template LSP

June 2025

The LSP code and tutorail referenced in this post is for tower_lsp. It's older and unmaintained. I've moved to using the lsp_server from rust_analyzer. You can read more about that here:

A Basic LSP Server Scaffold Written in Rust

Where It Started...

I use MijiJinjamj any time I need to use templatestmpl.

I find the default tokens hard to read. I change them to ones I like bettertoken. Only problem is that the linters/formatters out there don't support changing thingslint. I could fight with them to figure it out. That would involved trying to figure out this regular expressionregex.

a code snippet showing a very long regular expression that

Or, I could make my own LSPlsp and make my own parser...

...7 seconds keyboard clicking sounds...

A github page showing an initial commit for a new repository called neoj_lsp
The Notes
  • This is for .neoj template files that Neopoligen uses.
  • They're the same thing as Jinja files but flip the tokens to something I find more readable. Specifically:

    {{ }} becomes [@ @]

    {% %} becomes [! !]

    {# #} becomes [# #]

  • I started by watching a video where someone was using the tower_lsptower rust crate. They were basically just typing it in. When I realized that I just went to the page myself.
  • First code was just a copy paste from the example on the tower_lsp home page

    I dropped the code in a new Rust project named neoj_lsp and ran cargo install --path . in it to install it on my system.

  • I updated my Neovim config (which for me is at ~/.config/nvim/init.lua to add this at the bottom:

    vim.lsp.config['neoj_lsp'] = {
    cmd = { 'neoj_lsp' },
    filetypes = {'html', 'neoj'},
    -- root_markers = { '.git' },
    --
    }
    
    vim.lsp.enable('neoj_lsp')
    
    vim.filetype.add({
      extension = {
        neoj = 'neoj',
      }
    })

    This is straight from the Neovim LSP Quick-Startqs and filetypeft docs.

  • The quick start also had lines for root_makers and settings like:

    vim.lsp.config['luals'] = {
      -- previous stuff
      root_markers = { { '.luarc.json', '.luarc.jsonc' }, '.git' },
      settings = {
        Lua = {
          runtime = {
            version = 'LuaJIT',
          }
        }
      }
    }

    I didn't need those to get started though. (That uses the luals from the demo instead of my neoj_lsp. Left that as is so the lua stuff in the body of the code makes a little more sense)

  • I'm sure there's a more standard place to put that, This got me started until I figure that out.
  • The vim.filetype.add() also supports a pattern key that can be used to match the content. Will look at that later so that .html files can use it too.
  • That's all it took to get the basic text completion for the word "Hello" to show up in Neovim.

    My apologies. I haven't added alt text to this image yet.
  • Took a few more hours after that to figure out how to return a formatted version of a document. I've got the pipe working. Now it's on to writing the parser. I already know how to do that, though. It'll take a while, but it's not looking for new knowledge. Less burning of the mental energy required.
end of line

Endnotes

I'm going to be building an LSP for Neopolitan as well. This works as nice practice for that.

I've got a refined example of the approach for getting the formatting response working. It's in the new version of my Rust Grimoire which I haven't wired up to publish yet. It'll be here when it's done. (That page will throw a page not found error until that point)

References

This is the first video I started watching. It's basically manually typing in the example from the tower_lsp page without a lot of additional explanation. I jumped to the docs when I figured that out. Way easier and less error prone to just copy from the source.

This is the other video I watched through to get an idea of the different parts of the communications. I've spent time in the LSP Docs but it's a lot easier to see someone running code.

The video is really just building what tower_lsp give you out of the box. It's TypeScript instead of Rust, but the principals are the same. The main thing I was after was to see the calls and response that did formatting.

Footnotes

Places for templates

For example, the Neopoligen website builder

Token Switch

Here are the defaults and what I change them to:

{% %} - [! !]

{{ }} - [@ @]

{# #} - [# #]

One of the extensions I found for VS Code seem to have a way to change the tokens via configuration. I wasn't able to get it working though. Also, I'm mostly in Neovim. I need a solution there regardless.

Basically, a way to describe what a programming language should look like and then offer tool (via LSP servers, which is really what I'm making) to do things like auto-completion and formatting.

Regular Expressions (or Reg Ex) are patterns used to match text in files. For example \d+ matches "one or more" numbers. So, it would match: 1, 123, 4545. If the file had 123a456 it would match the 123, stopping at the a since that's not a number.

Up and running in no time with the basic text completion recommendation. Would have been great to have had a formatting example too. I'll end up submitting one if I have the spoons.

Nvim docs rock. Once you find the one you need. That's not a complaint. Just a fact of life given there are so many of them. Way better than there being too few, though.

The final piece of the puzzle (along with vim.lsp.enable()) which I missed the first time through.

Share link:
https://www.alanwsmith.com/en/2y/i2/cv/gw/?initial-notes-on-making-the-neopoligen-template-lsp