A Neovim plugin for grammar and spell checking using LanguageTool.
- Neovim 0.9+
- A running LanguageTool server (local or remote)
curl
Using lazy.nvim:
{
"auyer/languagetool.nvim",
opts = {
server_url = "http://localhost:8081",
language = "en-US",
},
keys = {
{ "<leader>lc", "<cmd>LTCheck<cr>", desc = "Check line" },
{ "<leader>lc", ":LTCheck<cr>", mode = "v", desc = "Check selection" },
{ "<leader>lb", "<cmd>LTCheckBuffer<cr>", desc = "Check buffer" },
{ "<leader>lf", "<cmd>LTFix<cr>", desc = "Show fixes" },
{ "<leader>la", "<cmd>LTCodeAction<cr>", desc = "Code action" },
{ "<leader>lx", "<cmd>LTClear<cr>", desc = "Clear diagnostics" },
},
}require("languagetool").setup({
-- LanguageTool server URL
server_url = "http://localhost:8081",
-- A language code like en-US, de-DE, fr, auto ...
language = "auto",
-- Optional motherTongue config
motherTongue = nil,
-- "default" and "picky" available
level = "default",
-- Show top N suggestions in diagnostic messages
suggestions_in_diagnostic = 3,
-- Enable virtual text showing top suggestion (set false to disable)
virtual_text = true,
-- Max chars per API call (under 20K free limit; large texts are chunked)
max_chunk_chars = 19000,
-- Max concurrent curl calls when checking large files
max_concurrent_calls = 4,
-- Optional API credentials
username = nil,
api_key = nil,
-- Severity mapping for different issue types
severity = {
typographical = vim.diagnostic.severity.HINT,
grammar = vim.diagnostic.severity.WARN,
misspelling = vim.diagnostic.severity.ERROR,
style = vim.diagnostic.severity.INFO,
default = vim.diagnostic.severity.WARN,
},
})| Command | Description |
|---|---|
:LTCheck |
Check current line |
:'<,'>LTCheck |
Check visual selection |
:LTCheckBuffer |
Check entire buffer |
:LTFix |
Show available fixes at cursor |
:LTCodeAction |
LSP-like code action — show fixes or fall through to native LSP code actions |
:LTClear |
Clear all LanguageTool diagnostics |
- Async checking (non-blocking)
- Integrates with Neovim's built-in diagnostics (
vim.diagnostic) - Diagnostic messages include top suggestions
- Virtual text shows the top suggestion inline (can be disabled)
- LSP-like code actions (
:LTCodeAction) with fallback to native LSP - Fix picker uses
vim.ui.select(works with Telescope, fzf-lua, snacks.nvim, etc.) - Configurable severity levels per issue type
You can run LanguageTool locally using Docker:
docker run --rm -p 8081:8010 erikvl87/languagetoolOr download and run the standalone server.
Run the test suite against a local LanguageTool server:
# 1. Generate API response fixtures (requires a running LT server)
mkdir -p tests/fixtures
printf 'since april\nteste text\nthis is an example with on error.\n' > tests/fixtures/sample.txt
printf 'since april\n' > tests/fixtures/single_line.txt
curl -sS -X POST -d 'language=en-US' -d 'level=picky' \
--data-urlencode 'text@tests/fixtures/sample.txt' \
'http://<language-tool-url>/v2/check' > tests/fixtures/sample.json
curl -sS -X POST -d 'language=en-US' -d 'level=picky' \
--data-urlencode 'text@tests/fixtures/single_line.txt' \
'http://<language-tool-url>/v2/check' > tests/fixtures/single_line.json
# 2. Run the tests
nvim --headless --cmd "set rtp+=." -c "luafile tests/test_plugin.lua"Tests use mock API responses — no server needed after fixture generation.