just-lsp is a server implementation of the
language server protocol
for just, the command runner.
just-lsp brings rich editor support to your justfiles, including:
-
Completions for recipe names, variables, and all builtins: attributes, constants, functions, and settings.
-
Hover docs for whatever's under your cursor: recipe definitions, parameter declarations, variable assignments, and the full builtin reference.
-
Jump to definition for recipes, aliases, parameters, assignments, and builtin constants.
-
Diagnostics on every change, catching syntax errors, unknown recipes, bad dependencies, indentation issues, and more. See
docs/diagnostics.mdfor the full list of rules. -
Rename and find references for recipes, aliases, variables, and parameters, scope-aware so refactors don't accidentally rewrite unrelated identifiers.
-
Run any recipe directly from your editor via a code action, with optional argument prompting before
justis invoked. -
Semantic highlighting, folding, and formatting via
just --fmt --unstable.
If you need help with just-lsp please feel free to open an issue or ping me on
Discord. Feature requests and bug reports are
always welcome!
just-lsp should run on any system, including Linux, MacOS, and the BSDs.
The easiest way to install it is by using cargo, the Rust package manager:
cargo install just-lspOtherwise, see below for the complete package list:
| Package Manager | Package | Command |
|---|---|---|
| Cargo | just-lsp | cargo install just-lsp |
| Homebrew | terror/tap/just-lsp | brew install terror/tap/just-lsp |
| Operating System | Package Manager | Package | Command |
|---|---|---|---|
| Arch | pacman | just-lsp | pacman -S just-lsp |
You can also install the server via mason, the Neovim plugin that allows you to easily manage external editor tooling such as LSP servers, DAP servers, etc.
Simply invoke :Mason in your editor, and find just-lsp in the dropdown to
install it.
Pre-built binaries for Linux, MacOS, and Windows can be found on the releases page.
Running just-lsp with no arguments starts the language server over
stdin/stdout.
The analyze subcommand runs the diagnostic engine on a justfile and prints any
warnings or errors to stderr, without starting the language server:
just-lsp analyze [PATH]When PATH is omitted it searches the current directory and its ancestors for a
file named justfile. The exit code is non-zero if any error-severity
diagnostic is found.
just-lsp can be used with any LSP client, this section documents integration
with some of the more popular ones.
nvim-lspconfig exposes its server definitions to the builtin
vim.lsp.config API, so the
old require('lspconfig').just.setup() pattern is deprecated. With Nvim 0.11.3+
and the latest nvim-lspconfig installed, enabling just-lsp looks like:
vim.lsp.enable('just')If you need to override the default command, capabilities, or hooks, define (or extend) the config before enabling it:
vim.lsp.config('just', {
cmd = { '/path/to/just-lsp' }, -- only needed when the binary is not on $PATH
on_attach = function(client, bufnr)
-- add your mappings or buffer-local options
end,
capabilities = require('cmp_nvim_lsp').default_capabilities(),
})
vim.lsp.enable('just')vim.lsp.config automatically merges your overrides with the upstream config
shipped inside nvim-lspconfig's lsp/just.lua.
capabilities describe what features your client supports (completion snippets,
folding ranges, etc.). The helper from cmp-nvim-lsp augments the defaults so
completion-related capabilities line up with nvim-cmp. If you do not use
nvim-cmp, you can omit the field or build your own table.
A third-party Visual Studio Code extension is maintained over at https://github.com/nefrob/vscode-just, written by @nefrob. Follow the instructions in that repository to get it setup on your system.
A third-party Zed extension is maintained over at https://github.com/sectore/zed-just-ls, written by @sectore. Follow the instructions in that repository to get it setup on your system.
just-lsp accepts configuration through the LSP initializationOptions object,
sent from your editor when the server starts.
Individual diagnostic rules can be configured under the rules key. Each rule
is keyed by its code (see docs/diagnostics.md) and
accepts either a level string or a table with a level field:
{
"rules": {
"unused-variables": "off",
"unused-parameters": { "level": "error" }
}
}Supported levels are error, warning, information (or info), hint, and
off. Setting a rule to off suppresses it entirely; any other level overrides
the rule's default severity. Rules that are not listed retain their default
behavior.
Pass the configuration table via the init_options field:
vim.lsp.config('just', {
init_options = {
rules = {
['unused-variables'] = 'off',
['unused-parameters'] = { level = 'warning' },
},
},
})
vim.lsp.enable('just')I use Neovim to work on this project, and I load the development build of this server to test out my changes instantly. This section describes a development setup using Neovim as the LSP client, for other clients you would need to look up their respective documentation.
First, clone the repository and build the project:
git clone https://github.com/terror/just-lsp
cd just-lsp
cargo build
Add this to your editor configuration:
local dev_cmd = '/path/to/just-lsp/target/debug/just-lsp'
local on_attach = function(client, bufnr)
-- Add your implementation here
end
local capabilities = require('cmp_nvim_lsp').default_capabilities()
vim.lsp.config('just_dev', {
cmd = { dev_cmd },
filetypes = { 'just' },
root_dir = function(fname)
return vim.fs.root(fname, { '.git', 'justfile' })
end,
on_attach = on_attach,
capabilities = capabilities,
})
vim.lsp.enable('just_dev')This uses a separate config name (just_dev) so you can switch between the
local development build and the stock just config. Replace dev_cmd with the
absolute path to your freshly built binary.
on_attach is a function that gets called after an LSP client attaches to a
buffer,
mine
just sets up a few mappings:
local on_attach = function(client, bufnr)
-- ...
map('n', '<leader>ar', '<cmd>lua vim.lsp.buf.rename()<CR>')
map('n', '<leader>s', '<cmd>lua vim.lsp.buf.format({ async = true })<CR>')
-- ...
endAs in the basic example above, we use cmp_nvim_lsp.default_capabilities() so
that the dev build inherits completion-related capabilities from nvim-cmp.
Swap in your own table if you use a different completion plugin.
n.b. This setup requires the nvim-lspconfig plugin (and optionally cmp-nvim-lsp for the capabilities helper).
just-lsp vendors the
tree-sitter-just
parser in vendor/tree-sitter-just. After changing the grammar or query files,
rebuild and test the parser with the following commands:
`cd vendor/tree-sitter-just && npx tree-sitter generate`
`cd vendor/tree-sitter-just && npx tree-sitter test`
`cargo test`n.b. just update-parser will run all of the above for you.
The generate step updates the parser artifacts under
vendor/tree-sitter-just/src/. Commit those files together with any updated
corpora in vendor/tree-sitter-just/test/corpus so downstream tooling sees your
changes.
Check out just, the command runner.
