ExAthena.Lsp.Client (ExAthena v0.7.1)

Copy Markdown View Source

GenServer wrapping a stdio Port that speaks JSON-RPC 2.0 (LSP framing).

Lifecycle

  1. start_link/1 opens the OS process port and sends the LSP initialize request via handle_continue/2. The GenServer is immediately callable — requests received before initialization completes are queued and replayed once initialized is confirmed.
  2. request/4 sends a JSON-RPC request and awaits the reply (default 30 s). Multiple concurrent callers are safe — replies are correlated by id.
  3. notify/3 sends a one-way notification (no reply expected).
  4. diagnostics/2 returns cached textDocument/publishDiagnostics payloads for a given URI (populated by push notifications from the server).
  5. stop/2 sends the LSP shutdown + exit sequence, then waits for the port to close.

Telemetry

  • [:ex_athena, :lsp, :spawn] — discrete event with %{system_time: ...} measurements and %{language: atom, root: binary, binary: binary, pid: pid, phase: :started | :stopped | :crashed} metadata. Emitted exactly once per phase transition. :crashed is emitted only from terminate/2; the port :exit_status handler does not double-emit.
  • [:ex_athena, :lsp, :request, :start | :stop] — span around each JSON-RPC request/response cycle, metadata %{method: binary, language: atom, root: binary}.

Assumptions

LSP servers must not interleave non-JSON-RPC bytes in stdout in normal operation. Servers should use --log-file flags to avoid mixing stderr with the JSON-RPC stream.

Summary

Functions

Returns a specification to start this module under a supervisor.

Return cached diagnostics for the given uri.

Send a JSON-RPC notification (no reply).

Send a JSON-RPC request and await the response.

Start a client for the given LSP server.

Initiate a graceful LSP shutdown and wait up to timeout ms.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

diagnostics(pid, uri)

@spec diagnostics(pid(), String.t()) :: [map()]

Return cached diagnostics for the given uri.

notify(pid, method, params \\ %{})

@spec notify(pid(), String.t(), map()) :: :ok

Send a JSON-RPC notification (no reply).

request(pid, method, params \\ %{}, timeout \\ 30000)

@spec request(pid(), String.t(), map(), non_neg_integer()) ::
  {:ok, term()} | {:error, term()}

Send a JSON-RPC request and await the response.

Returns {:ok, result} or {:error, reason}. On timeout returns {:error, :timeout}.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Start a client for the given LSP server.

Options:

  • :binary (required) — absolute path to the server executable.
  • :args (required) — list of additional CLI args.
  • :root_uri (required) — file:///abs/path workspace root.
  • :root (required) — plain filesystem root path (for telemetry/registry).
  • :language (required) — language atom (for telemetry).
  • :name (optional) — GenServer name (via-tuple for Registry).

stop(pid, timeout \\ 30000)

@spec stop(pid(), non_neg_integer()) :: :ok

Initiate a graceful LSP shutdown and wait up to timeout ms.