Skip to main content
Skip to main content

Language Server & VSCode Extension

argsh logo

argsh includes a Language Server Protocol (LSP) implementation and VSCode extension that provides IDE support for argsh-specific syntax. Works alongside shellcheck — argsh handles framework-specific validation, shellcheck handles general bash.

Features

Diagnostics

The language server validates your argsh scripts in real-time. Each diagnostic has a code (AG001–AG010) that can be suppressed.

CodeSeverityDescription
AG001ErrorArgs entry missing description
AG002ErrorUsage entry missing description
AG003ErrorInvalid field spec (bad modifier)
AG004WarningMissing local variable declaration for args field
AG005ErrorArgs declared but :args never called
AG006ErrorUsage declared but :usage never called
AG007WarningUsage target function not found (searched imports)
AG008WarningDuplicate flag name
AG009WarningDuplicate short alias
AG010WarningCommand resolves to bare function (not namespaced)
AG011WarningTrailing | with no short alias (e.g. 'flag|')
AG012HintLocal variable shadows parent scope args field

Suppressing diagnostics

Like shellcheck, add comments to suppress specific diagnostics:

# argsh disable=AG004
local -a args=('port|p:~int' "Port") # no local port needed

# argsh disable=AG007,AG010 # suppress multiple codes

echo "hello" # argsh disable=AG004 # inline suppression

# argsh disable-file=AG007 # suppress for entire file

Completions

Context-aware completions trigger automatically:

ContextTriggerSuggestions
Inside args=(...) after :::+, :~int, :~float, :!, :#
After :~~int, float, file, boolean, string, custom to:: types
Inside usage=(...) after @@readonly, destructive, json, idempotent, openworld
After :--Function names in the file and imports
After importspacestring, array, fmt, error, is, to, ...
After is::, to::, etc.::Library functions (e.g. is::array, to::int)

Custom to:: validator functions defined in your file are automatically suggested as types.

Help Preview

Hover over any function to see its generated help text:

  • Flag table with types, aliases, and descriptions
  • Array types shown as type[]
  • Subcommand list for :usage functions
  • Summary counts (flags, required, subcommands)

Hover over the args or usage keyword to see all defined entries in a table.

Hover over a usage entry to see the target function's full help with its flags and subcommands.

Hover over :~typename to see type documentation (built-in or custom validator info).

Hover over '-' group separators to see the section heading.

Code Lens

Clickable indicators above functions showing:

  • Branch icon for :usage dispatchers / leaf icon for :args functions
  • argsh: N params, M flags (R required) · K subcommands · ← parent
  • Click to open the script preview

Script Preview

Use Ctrl+Shift+A or the command palette to open a dashboard:

  • Command tree with all nested subcommands
  • Flag details per command (with type[] for arrays)
  • MCP tools with proper tool names and annotation badges
  • Export links to MCP JSON, YAML, and JSON

Go to Definition

Ctrl+Click on:

  • A usage entry command name — jumps to the target function
  • A :-func::name mapping — jumps to the explicit target
  • :~typename — jumps to the to::typename() function
  • import module — opens the imported file
  • Works across files (follows import and source argsh up to configurable depth)

Auto Formatter

Aligns args and usage array entries so descriptions start at the same column:

# Before
'port|p:~int' "Port number"
'verbose|v:+' "Verbose output"
'config|c' "Config file path"

# After (formatted)
'port|p:~int' "Port number"
'verbose|v:+' "Verbose output"
'config|c' "Config file path"

Triggered via:

  • Shift+Alt+F (format document)
  • argsh: Format argsh Arrays in command palette
  • Automatically on save (configurable)

Command Tree Panel

A tree view in the bottom panel showing the command hierarchy:

  • Functions with branch/leaf icons
  • Args entries as field children, usage entries as command children
  • Active function highlighted in green based on cursor position
  • Click to navigate to function

Document Symbols

The sidebar outline shows the function hierarchy with :: namespace nesting.

Export Commands

CommandDescription
argsh: Export MCP JSONMCP tool schema in JSON
argsh: Export YAMLDocgen YAML output
argsh: Export JSONDocgen JSON output

Each opens in a new editor tab.

Installation

From Source

# Build the LSP binary
cargo build --release --manifest-path crates/argsh-lsp/Cargo.toml

# Set up the binary for the extension
mkdir -p vscode-argsh/bin
cp crates/argsh-lsp/target/release/argsh-lsp vscode-argsh/bin/

# Install the VSCode extension
cd vscode-argsh && npm install && npm run compile

Then in VSCode: Ctrl+Shift+P → "Developer: Install Extension from Location..." → select vscode-argsh/.

Configuration

SettingDefaultDescription
argsh.lsp.enabledtrueEnable the language server
argsh.lsp.path""Path to argsh-lsp binary (auto-detected if empty)
argsh.commandTree.enabledtrueShow the command tree panel
argsh.codeLens.enabledtrueShow flag/subcommand counts above functions
argsh.formatOnSavetrueAuto-format argsh arrays on save
argsh.resolveDepth2Max depth for cross-file import resolution (0–5)

Other Editors

Neovim (nvim-lspconfig)

local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')

configs.argsh = {
default_config = {
cmd = { 'argsh-lsp' },
filetypes = { 'sh', 'bash' },
root_dir = lspconfig.util.find_git_ancestor,
settings = {},
},
}

lspconfig.argsh.setup({})

Helix

Add to ~/.config/helix/languages.toml:

[[language]]
name = "bash"
language-servers = ["bash-language-server", "argsh-lsp"]

[language-server.argsh-lsp]
command = "argsh-lsp"

Architecture

crates/argsh-syntax/  — shared parsing library (pure Rust, no FFI)
crates/argsh-lsp/LSP server (tower-lsp)
vscode-argsh/ — VSCode extension (TypeScript)

The LSP server communicates over stdio and works with any LSP-compatible editor (VSCode, Windsurf, Neovim, Helix, Emacs).

Test Coverage

  • argsh-syntax: 92 unit tests (field parsing, usage parsing, document analysis, scope chains)
  • argsh-lsp: 37 tests (6 format unit + 31 integration over stdio)
Was this section helpful?