Manual Vim & Neovim

Vim & Neovim

elements man vim Read as markdown

Elements ships the same language server that powers its VS Code integration, and it works in Vim and Neovim too: diagnostics, completion, hover, go-to-definition, references, rename, and project-wide symbol search.

Elements builds no editor UI of its own. The server speaks standard LSP, and your editor's own LSP client renders everything, so your existing setup (telescope, trouble, nvim-cmp, coc, the quickfix, whatever you run) works against Elements with nothing new to learn.

Install

Nothing to do. Installing Elements installs the Vim and Neovim integration automatically, the same way it installs the VS Code extension. No plugin manager and no .vimrc/init.lua changes required.

  • Neovim: a self-contained plugin/elements.lua is placed in your config dir (~/.config/nvim/plugin/). That directory is always on the runtimepath, so it loads whether or not you use a plugin manager (lazy.nvim, packer, ...).
  • Classic Vim: the plugin is installed as a native package under ~/.vim/pack/elements/start/vim-elements, which Vim auto-loads. Everything Elements installs lives under pack/elements, so it never touches a pack namespace you're using yourself.

The plugin only attaches inside an Elements project (a directory with an .elements/id marker), so it never interferes with your other work. If you'd rather wire it up yourself (e.g. through nvim-lspconfig), see the snippet below.

Neovim

Neovim (0.8+) has a built-in LSP client, so this works out of the box after install, with nothing to configure. The plugin registers the Elements server for .jsoc, .html, .ts, .js, and .css files in an Elements project, and every UI plugin on Neovim's built-in LSP bus picks it up automatically:

  • Symbol search: vim.lsp.buf.workspace_symbol(), or Telescope's lsp_dynamic_workspace_symbols / fzf-lua's lsp_live_workspace_symbols.
  • Diagnostics: pushed project-wide (an error your edit causes in a file you never opened still shows up). Browse them with vim.diagnostic.setqflist(), trouble.nvim, or fzf-lua.
  • Completion: via nvim-cmp or blink.cmp using the built-in LSP source.
  • Hover, definition, references, rename: vim.lsp.buf.* and your keymaps.

If you drive your LSP setup through nvim-lspconfig, you can point it at the same binary instead of using the bundled plugin:

vim.lsp.config('elements', {
  cmd = { vim.fn.expand('~/elements/bin/elements-lsp'), 'stdio' },
  filetypes = { 'jsoc', 'html', 'typescript', 'javascript', 'css' },
  root_markers = { '.elements' },
})
vim.lsp.enable('elements')

Classic Vim

Classic Vim has no built-in LSP client, so Elements bundles one (vim-lsp) and loads it on demand. it works out of the box with nothing to install. Your own client always wins, so this only kicks in when you don't already have one:

  • You already use vim-lsp: Elements registers with it; the bundled copy is never loaded.
  • You use coc.nvim or ALE: Elements stays out of the way (loading a second client would run the language server twice). Configure Elements through your client instead. See below.
  • You have no client: Elements loads its bundled vim-lsp automatically.

With vim-lsp, the usual commands work:

:LspDefinition
:LspHover
:LspWorkspaceSymbol
:LspDocumentDiagnostics

Escape hatches:

let g:elements_lsp_enabled = 0    " disable Elements LSP entirely
let g:elements_lsp_no_bundle = 1  " never load the bundled vim-lsp

If you use coc.nvim, add Elements to :CocConfig:

{
  "languageserver": {
    "elements": {
      "command": "elements-lsp",
      "args": ["stdio"],
      "filetypes": ["jsoc", "html", "typescript", "javascript", "css"],
      "rootPatterns": [".elements"]
    }
  }
}

Syntax highlighting

Templates are HTML with a TypeScript frontmatter and { } bindings, which Vim's stock HTML syntax doesn't understand, such as a bare > or && in the frontmatter, or the } closing a binding, comes out flagged as an error. Both editors get Elements' own syntax instead, which highlights the frontmatter as TypeScript and colors e: directives and bindings.

It applies to .html files inside an Elements project only. HTML anywhere else on your machine keeps Vim's own syntax, untouched. Turn it off for a buffer with :set syntax=html.

Elements also highlights .jsoc config files, in both editors.

How it connects

The plugin launches elements-lsp stdio, which ensures the project server is running and bridges the editor's stdin/stdout to that project's LSP socket. It's the same server, over the same protocol, that VS Code connects to. Your editor just reaches it through a stdio child process instead of dialing the socket directly.

Troubleshooting

  • Nothing lights up in Neovim: confirm you're inside an Elements project (.elements/id exists) and that ~/elements/bin is on PATH (or set ELEMENTS_SYSTEM_PATH). Check :checkhealth vim.lsp and :LspInfo-style client lists with :lua =vim.lsp.get_clients().
  • Nothing lights up in classic Vim: the bundled vim-lsp loads only when you have no client of your own. If you use coc.nvim or ALE, wire Elements through it (above); Elements won't load a second client on top. Confirm the bundle is installed with :echo globpath(&packpath, 'pack/*/opt/vim-lsp'), and that it loaded with :echo exists(':LspDefinition').
  • A template looks full of syntax errors: Vim's stock HTML syntax is still in charge. Check with :set syntax?: inside a project it should read elementshtml in Neovim, and in classic Vim :echo b:current_syntax should be html with elementsFrontmatter among the groups in :syntax list. If it's the stock one, confirm .elements/id exists and that ~/.config/nvim/syntax/elementshtml.vim (Neovim) or ~/.vim/pack/elements/start/vim-elements/ (Vim) is installed.
  • Logs: server-side detail is in .elements/logs/project.log.