Mercury CLI
Documentation

Code

Language servers

Mercury's LSP tool speaks to the language servers of the workspace. Its read operations answer symbol questions from the compiler's knowledge. Its write operations refactor with that knowledge instead of text search, and every write goes through the same permissions, journaled commit walk, file-history snapshot, change receipt and read-before-edit rule as the Edit tool.

Language services

  • TypeScript and JavaScript: The built-in mercury-ts sidecar drives the project's own typescript package.
  • Python, C/C++, GDScript and C#: Built-in language-service lanes serve these languages.
  • Additional servers: An extension or MERCURY_LSP_SERVERS adds servers.
  • Read operations: Definitions, references, hover, symbols, call hierarchy and diagnostics.

The TypeScript sidecar finds the nearest tsconfig.json or jsconfig.json above a file. A jsconfig.json project is analyzed whole, so a rename in one JavaScript file reaches the others. A file under neither lands in an inferred project that holds only the files the session has opened.

Refactor operations

  • rename: Renames the symbol at filePath, line and character to newName at every location the service reports: the declaration, imports and re-exports, JSX tags and attributes, and JavaScript files in the same project. A comment or a string that contains the name is never a reference.
  • moveSymbol: Moves the top-level function, class, interface, type, enum or variable declaration named at filePath, line and character to targetPath, creating the file when it does not exist and appending when it does, with every import rewritten by the compiler. TypeScript and JavaScript only.
  • pathRename: Moves the file or directory at filePath to newPath with the import edits of every server that claims the file, as one transaction. A directory move claims through the extensions of the files it contains.
  • codeActions: Lists the quick fixes, refactors and source actions the service offers at a position or range, each with a stable identifier beginning ca- derived from what the action is.
  • organizeImports: The code action of kind source.organizeImports. It changes only the import block.
  • fixDiagnostic: Reads the diagnostics at a position, offers the fixes, applies the sole candidate and reports the error count before and after.

Preview a refactor

To preview a refactor, follow these steps:

  1. Call LSP with the operation and its parameters, leaving apply unset.

The tool returns each edit as data: the file, the one-based start and end line and character, the text before and the text after. The edits field of the tool output carries them, and a plan token beginning lsp- digests the exact edit set over the exact file contents. Nothing is written.

Apply a previewed refactor

To apply a previewed refactor, follow these steps:

  1. Repeat the operation with apply: true and the returned plan.

The tool recomputes the edits against the current files, writes exactly the previewed set, and reports the post-apply diagnostics.

The apply refuses when any touched file changed since the dry run, because the token no longer matches. Without plan, the apply writes only files the session has read as they stand now: a full Read whose content matches, a windowed Read covering the touched lines, or lines shown by a content search. A touched file the session has not read refuses the whole apply, names the files and their lines, and points at the dry run. A refused apply writes nothing. After an apply, the read state of every written file is refreshed, the editor is notified and the servers are re-synced.

Rename checks

The TypeScript sidecar checks a rename with the compiler before the edits are offered. The new name must be an identifier and not a reserved word. A rename that would introduce a compiler error, or would change which symbol a name refers to, is refused with the compiler's message and position. A rename the service itself refuses, such as a library symbol or an unresolved identifier, is refused with the service's reason.

A moveSymbol position must identify the declaration's name. Refused by name: a position inside a body, a statement that is not a declaration, a target that is the source, a directory, or a file of another language. The server of another language lane answers that it does not offer a symbol move.

Code-action selection

  • kind: Filters the list to quickfix, refactor or a sub-kind such as refactor.extract, or to the whole-file source actions source.organizeImports, source.addMissingImports, source.removeUnusedImports and source.removeUnused. Source actions are offered only when asked for by kind.
  • actionId: Without apply, previews that action's edits and plan.
  • apply: true: Writes the action named by actionId, or the one action left by kind when the kind leaves exactly one.

A command-only action, one that would run code on the server, is refused. A refactor that would create a file is refused in favor of moveSymbol.

Search and edit by syntax, Edits and change transactions, Debugger and tests, Extensions