Skip to content

feat(nvim): add terraform LSP and tooling support#5

Open
maybebyte wants to merge 2 commits into
masterfrom
nvim-add-terraform-lsp
Open

feat(nvim): add terraform LSP and tooling support#5
maybebyte wants to merge 2 commits into
masterfrom
nvim-add-terraform-lsp

Conversation

@maybebyte
Copy link
Copy Markdown
Owner

Summary

Adds full Terraform tooling support to the Neovim config so .tf and
.tfvars files get the same treatment as every other supported language:

  • LSP: terraform-ls (HashiCorp) auto-installed via
    mason-tool-installer; auto-enabled by mason-lspconfig with
    defaults; inherits the global '*' capabilities and the existing
    LspAttach keymap/inlay-hint logic.
  • Formatter: terraform_fmt wired into conform.nvim for both
    terraform and terraform-vars filetypes (shells out to
    terraform fmt -; CLI itself is manual-install).
  • Linter: tflint wired into nvim-lint; installed via Mason.
  • Treesitter: terraform and hcl parsers added to
    ensure_installed; .tfvars buffers reuse the terraform parser
    via vim.treesitter.language.register("terraform", "terraform-vars").

Two subtleties caught during verification

  1. Empty .tf files don't get the terraform filetype. Neovim's
    built-in detect.tf inspects file content and falls back to the
    legacy tf filetype when the buffer is empty or comment-only, which
    prevents terraform-ls from attaching to fresh files. Fixed via a
    new lua/my/settings/filetypes.lua that forces *.tf -> terraform
    unconditionally.

  2. tflint runs as both an LSP and an nvim-lint linter. When the
    Mason tflint package is installed, mason-lspconfig's
    automatic_enable picks it up as a language server (lspconfig has a
    tflint server definition that wraps tflint --langserver). That
    produces duplicate diagnostics alongside the nvim-lint runner.
    mason-lspconfig.setup() now passes
    automatic_enable = { exclude = { "tflint" } } so linting stays in
    nvim-lint where the rest of the project's linters live.

Files

  • lua/my/plugins/mason-tool-installer.luaterraformls + tflint
    added; header comment notes terraform CLI as manual-only
  • lua/my/plugins/lspconfig.luaautomatic_enable exclude for
    tflint
  • lua/my/plugins/conform.luaterraform + terraform-vars in
    ft lazy-load and formatters_by_ft
  • lua/my/plugins/nvim-lint.luaterraform = { "tflint" }
  • lua/my/plugins/treesitter.luahcl + terraform parsers and
    terraform-vars language register
  • lua/my/settings/filetypes.lua (new) + init.lua wire-up — forces
    .tf -> terraform to bypass content-based detection
  • README.md — Formatters/Linters tables updated;
    tflint --init note added

Test plan

Verified end-to-end on a clean Neovim instance:

  • .tf (empty file) → filetype terraform; terraformls
    attaches
  • .tfvars → filetype terraform-vars; treesitter highlighter
    active (proves language.register worked); terraformls
    attaches
  • terraform-ls and tflint auto-installed via
    mason-tool-installer on VimEnter
  • treesitter parsers terraform and hcl installed
  • nvim-lint linters_by_ft.terraform == { "tflint" }
  • conform formatters_by_ft.terraform == { "terraform_fmt" }
    and same for terraform-vars
  • Only terraformls attaches to a .tf buffer (the tflint LSP
    duplicate is correctly suppressed)

Outstanding

terraform CLI is not in the Mason registry, so format-on-save is a
no-op until the user installs it via system package manager / tfenv
/ asdf. Documented in both the mason-tool-installer header comment
and the README Formatters table.

Bring .tf and .tfvars files to feature parity with other supported
languages: terraform-ls LSP attaches automatically, conform runs
`terraform fmt` on save, nvim-lint runs tflint, and treesitter
highlights both filetypes (the .tfvars buffer reuses the terraform
parser via vim.treesitter.language.register).

Two subtleties caught during verification:

* Neovim's builtin .tf detection is content-based and falls back to
  the legacy `tf` filetype on empty buffers, which blocks the LSP
  from attaching to fresh files. lua/my/settings/filetypes.lua
  forces `.tf` -> `terraform` unconditionally.

* mason-lspconfig auto-enables tflint as an LSP whenever its Mason
  package is installed, which produces duplicate diagnostics
  alongside the nvim-lint runner. The bare `mason-lspconfig.setup()`
  call now passes `automatic_enable = { exclude = { "tflint" } }`
  to keep linting in nvim-lint where the rest of the project's
  linters live.

terraform-ls and tflint are installed via mason-tool-installer; the
`terraform` CLI itself is not in the Mason registry and must come
from a system package manager / tfenv / asdf (documented in the
mason-tool-installer header comment alongside perltidy and
clang-format).
@maybebyte
Copy link
Copy Markdown
Owner Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

The `terraform` package is in fact in the Mason registry (categories:
Formatter, Linter, Runtime) — the previous commit's claim that it was
not was wrong. Add it to mason-tool-installer's formatters block so
conform's `terraform_fmt` works out of the box without requiring the
user to install the CLI separately via tfenv / asdf / system package
manager. Drop the matching "manual-only" entry from the header
comment, and update the README Formatters row to reflect that the
binary is Mason-managed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant