This is a language server for shell scripts.
A language server is a program that provides "language intelligence" features to text editors and any other compatible tools (clients).
It communicates with clients over stdin
/stdout
using the Language Server
Protocol, which is
based on JSON-RPC.
- Go to definition
- Hover documentation
- Find and highlight references
- Rename variables and functions
- Complete variable, function, and command names
- Scoped local variables and parameters
- Diagnostics (errors, warnings, hints)
- Additional diagnostics and code actions through Shellcheck integration
- Document and range formatting through shfmt integration
- Intelligent
man
andhelp
integration based on the active shell - Code actions
- Insert full command path
- Insert Shellcheck directives
- Apply Shellcheck fixes
- Document symbols
- Enhanced syntax highlighting with semantic tokens
- Annotations
- Inlay hints:
- Parameter annotation indices
- Signature help
- Module directives
- Highlight Shellcheck directives
- Dynamically register capabilities on configuration change
- Completion:
- Paths
- Command arguments
- Comment directives
- Code actions:
- Inline environment variables
- Change shebang based on usage
Annotations are written with special comments that begin with ##@
. They can
be used by the language server for various purposes, such as improved hover
documentation and signature help.
Provide a general description of the next function or variable.
Provide a description of the current function parameter or script parameter.
The first annotation applies to $1
, the second one to $2
, and so on.
The server provides inlay hints that label the annotations with their corresponding parameter indices.
Apply previous param
annotations to the script instead of the next function.
##@ desc Write the number of entries in the given directory to stdout
##@ param Directory path
example () {
ls -a -- "$1" | wc -l
}
The server can be configured with the workspace/didChangeConfiguration
notification or the initialize
request with the initializationOptions
field.
For example, to set shell.defaultShell
to "bash"
and leave other options to
their default values, use the following JSON object:
{
"shell": {
"defaultShell": "bash"
}
}
Supported configuration options are listed below:
- type:
string
- default:
"sh"
- description: The shell dialect to use when a document has no shebang.
- type:
boolean
- default:
true
- description: Whether to enable Shellcheck integration.
- type:
boolean
- default:
true
- description: Whether to fall back to POSIX shell when Shellcheck does not support the current document's shell dialect.
- type:
string[]
- default:
[]
- description: Additional command line arguments to be passed to
shellcheck
.
- type:
boolean
- default:
true
- description: Whether to enable Shfmt integration.
- type:
boolean
- default:
true
- description: Whether to fall back to POSIX shell when Shfmt does not support the current document's shell dialect.
- type:
string[]
- default:
[]
- description: Additional command line arguments to be passed to
shfmt
.
- type:
boolean
- default:
true
- description: Whether to enable
help
integration.
- type:
boolean
- default:
true
- description: Whether to enable
man
integration.
- type:
string[]
- default:
[]
- description: Additional command line arguments to be passed to
man
.
- type:
string[]
- default: The server's
$PATH
. - description: Directory paths to be used for executable discovery.
- type:
boolean
- default:
true
- description: Whether the server should inspect its environment variables. When this is set to
true
, environment variable names can be provided as completions.
- type:
boolean
- default:
true
- description: Whether the server should be aware of executables available through the
PATH
environment variable.
shell-language-server
depends on serde +
serde_json for JSON serialization and
deserialization.
To build the executable, run cargo build --release
. The executable will be
placed at target/release/shell-language-server
.
These instructions assume shell-language-server
has been installed locally
and can be run without specifying its absolute path.
No plugins needed. You can customize client behavior and key bindings with the
LspAttach event. Place the
following Lua snippet in your Neovim configuration file to automatically start
shell-language-server
when you open a shell script:
vim.api.nvim_create_autocmd('FileType', {
callback = function ()
vim.lsp.start({
name = 'shell-language-server',
cmd = { 'shell-language-server' },
})
end,
pattern = 'sh',
group = vim.api.nvim_create_augroup('shell-language-server', { clear = true }),
desc = 'Automatically start shell-language-server',
})