← Blog

crystal.nvim — Neovim plugin for Crystal-lang

I am returning to Crystal-lang. I have not used it seriously since the all-in-one Asterisk shard days. For some recent VoIP and CLI projects I want a language that compiles to a small static binary and has Ruby-like syntax — Crystal still fits.

The editor support has not aged well. vim-crystal is regex-based and has not had a real update in years. On the Neovim side, there is no plugin that wires the modern crystal-lang-tools/tree-sitter-crystal parser into a complete editing experience — filetype detection, indent, text objects, commands, LSP. A few repositories cover one or two pieces; none cover everything.

So I have authored one: andrius/crystal.nvim.

What’s Included

  • Targets Neovim 0.11+.
  • Registers the upstream tree-sitter parser. Works with both the classic master and the new main (rewrite) branches of nvim-treesitter, which now expose incompatible APIs.
  • Ships three gap-filler queries — indents.scm, locals.scm, textobjects.scm — verified against the live grammar (the upstream parser already provides highlights, folds, injections).
  • Filetype detection for .cr, .ecr, and shard.{yml,lock,override.yml}.
  • Five commands you actually use day-to-day: :CrystalRun, :CrystalSpec, :CrystalFormat, :CrystalDocs, :CrystalExpandMacro.
  • Opt-in Crystalline LSP via the native vim.lsp.enable(). No nvim-lspconfig dependency.
  • :checkhealth crystal, :help crystal, CI, MIT licence.

Built with Claude Code

The whole thing — design specification, implementation plan, twenty commits, debugging tree-sitter node names against the actual grammar, README, CI, tagged release on GitHub — was built end-to-end in one afternoon session with Claude Code doing the typing. I made the design decisions; Claude Code wrote the code, ran the smoke tests, and caught its own mistakes through review subagents.

The interesting part was not the speed. It was that I never had to context-switch from “what should this plugin do” to “how do I express this in Lua”.

Install

With lazy.nvim:

{
  'andrius/crystal.nvim',
  dependencies = { 'nvim-treesitter/nvim-treesitter' },
  lazy = false,
  build = ':TSInstall! crystal',
  opts = {},
}

The full installation, configuration and command reference is in the README. Issues and PRs are welcome.