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/jackTabsCode/zed-just, written by @jackTabsCode & @mattrobenolt. 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. The object is optional; omitted
keys keep their default behavior.
{
"formatting": {
"indentation": "\t"
},
"rules": {
"unused-variables": "off",
"unused-parameters": { "level": "warning" }
}
}Formatting is delegated to just --fmt --unstable --quiet. By default,
just-lsp lets just choose its normal indentation. Set
formatting.indentation to pass a custom indentation string through
--indentation:
{
"formatting": {
"indentation": " "
}
}Common values are "\t" for tabs and " " for two spaces.
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" }
}
}Rule codes are listed in docs/diagnostics.md.
Supported levels are:
| Level | Behavior |
|---|---|
error |
Report the rule as an error. |
warning |
Report the rule as a warning. |
information, info |
Report the rule as informational. |
hint |
Report the rule as a hint. |
off |
Suppress diagnostics from the rule. |
Rules that are not listed keep their default severity.
With Neovim's builtin LSP client, pass the same configuration through
init_options:
vim.lsp.config('just', {
init_options = {
formatting = {
indentation = '\t',
},
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:
just -f vendor/tree-sitter-just/justfile gen
cd vendor/tree-sitter-just && tree-sitter test
cargo testn.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.
