Softcode in Your Editor
If you write softcode in files rather than straight into the game, the SharpMUSH Language Server gives your editor the same understanding of softcode the game has. It works with any editor that supports the Language Server Protocol (LSP), including VS Code, Neovim and Emacs. The portal’s built-in softcode editor uses the same analysis.
The offline stdio server described below only reads your code. It never connects to a game, needs no database, and changes nothing. Remote mode, at the end, connects to a game instead.
What the offline server does
Section titled “What the offline server does”- Error checking as you type, with the exact place and a message.
- Completion for function names (with their arguments), command names (with their switches),
substitutions such as
%#,%!and%N, and q- and v-registers. - Hover help: a function’s arguments, a command’s switches and locks, and what a substitution means.
- Argument hints while you type a function call, marking which arguments are optional, and the names of arguments shown inline.
- Go to definition for attributes set with
&attributeor@set, and find all uses of an attribute, function or object. - Quick fixes, such as closing a parenthesis or correcting a misspelled function name.
- An outline of the attributes, function calls and commands in a file, and a search across all your files.
- Renaming an attribute everywhere it is used.
- Formatting: trailing spaces removed, spacing around operators and after commands made consistent.
- Highlighting that knows the difference between built-in and custom functions, object references, substitutions, registers and commands.
It works on files ending in .mush or .mu (commands, one per line), .mushfn or .fun (a
function) and .mushcmd (a command list).
Getting the language server
Section titled “Getting the language server”The language server is part of the SharpMUSH source code. Follow Develop SharpMUSH to get the code and the .NET SDK, then build it:
dotnet build SharpMUSH.LanguageServer/SharpMUSH.LanguageServer.csprojYour editor starts it for you. It talks to the editor over standard input and output, so you never run it by hand except to test it:
dotnet run --project SharpMUSH.LanguageServer/SharpMUSH.LanguageServer.csprojIt writes a log file each day, named lsp-server followed by the date, in ~/.local/share/SharpMUSH/
on Linux, ~/Library/Application Support/SharpMUSH/ on macOS, or %LOCALAPPDATA%\SharpMUSH\ on
Windows. Look there first if your editor shows no errors or completions.
VS Code
Section titled “VS Code”VS Code needs a small extension that starts the server. The SharpMUSH source includes a working
example in SharpMUSH.LanguageServer/vscode-extension-example. The parts that matter:
-
Declare the language in the extension’s
package.json, so.mushand.mufiles are recognised:{"name": "sharpmush","displayName": "SharpMUSH Language Support","engines": { "vscode": "^1.75.0" },"activationEvents": ["onLanguage:mush"],"main": "./out/extension.js","contributes": {"languages": [{"id": "mush","extensions": [".mush", ".mu", ".mushfn", ".fun", ".mushcmd"],"aliases": ["MUSH", "mush"]}]},"dependencies": { "vscode-languageclient": "^8.1.0" }} -
Start the server from the extension, pointing at the built
SharpMUSH.LanguageServer.dll(here copied or linked into aserverfolder in the extension):import * as path from 'path';import { workspace, ExtensionContext } from 'vscode';import { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node';let client: LanguageClient;export function activate(context: ExtensionContext) {const serverPath = context.asAbsolutePath(path.join('server', 'SharpMUSH.LanguageServer.dll'));const serverOptions: ServerOptions = {run: { command: 'dotnet', args: [serverPath] },debug: { command: 'dotnet', args: [serverPath] }};const clientOptions: LanguageClientOptions = {documentSelector: [{ scheme: 'file', language: 'mush' }],synchronize: { fileEvents: workspace.createFileSystemWatcher('**/*.{mush,mu,mushfn,fun,mushcmd}') }};client = new LanguageClient('sharpmush', 'SharpMUSH Language Server', serverOptions, clientOptions);client.start();}export function deactivate() {return client?.stop();} -
Build and install it. In the extension’s folder, with Node.js installed:
Terminal window npm installnpm run compilenpm run packageThis makes a
.vsixfile. In VS Code, open the Extensions view, choose Install from VSIX… from its…menu, and pick the file.
Neovim
Section titled “Neovim”With nvim-lspconfig, define the server once and turn it on for .mush and .mu files:
local lspconfig = require('lspconfig')local configs = require('lspconfig.configs')
if not configs.sharpmush then configs.sharpmush = { default_config = { cmd = { 'dotnet', 'run', '--project', '/path/to/SharpMUSH.LanguageServer/SharpMUSH.LanguageServer.csproj' }, filetypes = { 'mush' }, root_dir = function(fname) return lspconfig.util.find_git_ancestor(fname) or vim.fn.getcwd() end, settings = {}, }, }end
lspconfig.sharpmush.setup{}
vim.filetype.add({ extension = { mush = 'mush', mu = 'mush', },})With lsp-mode:
(require 'lsp-mode)
(add-to-list 'lsp-language-id-configuration '(mush-mode . "mush"))
(lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection '("dotnet" "run" "--project" "/path/to/SharpMUSH.LanguageServer/SharpMUSH.LanguageServer.csproj")) :major-modes '(mush-mode) :server-id 'sharpmush-ls))
(add-to-list 'auto-mode-alist '("\\.mush\\'" . mush-mode))(add-to-list 'auto-mode-alist '("\\.mu\\'" . mush-mode))For other editors
Section titled “For other editors”Any LSP client can use it: start dotnet with the built SharpMUSH.LanguageServer.dll (or
dotnet run --project …) as a standard input/output server for .mush, .mu, .mushfn, .fun and .mushcmd files. It supports
these LSP requests: document open, change, close and save; diagnostics; semantic tokens (whole file
and range); completion; hover; definition; references; code actions; signature help; document
symbols; rename; formatting; workspace symbols; and inlay hints.
Remote mode
Section titled “Remote mode”The optional remote LSP plugin offers diagnostics, completion, hover and signature help using metadata filtered for your authenticated character. An ordinary editor launches SharpMUSH.LspBridge over stdio; the bridge connects to the game’s authenticated WebSocket endpoint. Remote analysis supports .mush and .mu (commands per line), .mushfn and .fun (function), and .mushcmd (command list). Positions use UTF-16.
Remote LSP does not offer the broader offline feature list below: formatting, rename, definitions and references are outside its initial scope. It does not synchronize attributes, execute code or read the server filesystem. Connections do not resume documents automatically. Overload can explicitly close a connection when synchronization diagnostics cannot be admitted. After a restart or explicit close, reconnect, initialize a fresh session and reopen documents. An analysis deadline instead produces an analysis-timeout warning, preserves the session/document and retries on the next edit.
See Remote MCP and LSP Analysis for turning the remote LSP on, its endpoint and protocol, and its limits. MCP serves AI analysis clients; LSP serves editors.
Build the bridge with the same .NET 11 SDK as the server:
dotnet build SharpMUSH.LspBridge/SharpMUSH.LspBridge.csprojPublish SharpMUSH.LspBridge for your client environment if distributing it separately. Configure your editor to launch the bridge rather than the offline server:
dotnet /path/to/SharpMUSH.LspBridge.dll --endpoint wss://game.example/lspProvide the character’s name and password through the child environment variables
SHARPMUSH_LSP_CHARACTER and SHARPMUSH_LSP_PASSWORD, preferably injected from editor SecretStorage.
Do not put passwords in settings JSON, URLs, arguments, logs or committed files. The bridge accepts
only WSS endpoints without userinfo/query/fragment and verifies TLS normally; there is no insecure
certificate bypass. It uses Content-Length framed UTF-8 LSP on stdio, translating to the WS protocol.
Logging is stderr only. Bridge/connection loss exits; client restart opens a fresh authenticated
session and must initialize/reopen documents. The bridge needs the .NET 11 runtime. Browser WebSocket clients
cannot supply arbitrary Basic headers; no browser-ticket/query-token mechanism is provided.
The VS Code desktop example has explicit offline/remote modes, all five extensions, endpoint-bound SecretStorage-driven remote launch and a strict tsconfig. Packaging it needs Node 22 or newer. The portal’s built-in editor does not use the remote LSP.