pub struct Translator { /* private fields */ }Expand description
Translator handles MCP tool calls by converting them to LSP requests.
All fields use interior mutability so Translator can be shared via a
plain Arc<Translator> with no outer lock: every LSP tool call would
otherwise serialize behind a single mutex for its entire round trip
(including the LSP request timeout), which is the root cause fixed here.
Each field is locked independently and only for the short, synchronous
section that touches it. In particular, the actual LSP request/response
round trip (client.request(...)) always runs with no lock held.
document_tracker is no exception: DocumentTracker locks its own state
per-path internally (see its docs), so prepare_document’s call into
ensure_open never holds a lock shared across unrelated paths or
languages while it does that document’s disk I/O and
textDocument/didOpen/didChange notify.
Implementations§
Source§impl Translator
impl Translator
Sourcepub async fn handle_completions(
&self,
file_path: String,
line: u32,
character: u32,
trigger: Option<String>,
) -> Result<CompletionsResult>
pub async fn handle_completions( &self, file_path: String, line: u32, character: u32, trigger: Option<String>, ) -> Result<CompletionsResult>
Handle completions request.
§Errors
Returns an error if trigger exceeds the maximum allowed length,
the LSP request fails, the file cannot be opened, or the routed
server does not advertise completionProvider support.
Sourcepub async fn handle_signature_help(
&self,
file_path: String,
line: u32,
character: u32,
) -> Result<SignatureHelpResult>
pub async fn handle_signature_help( &self, file_path: String, line: u32, character: u32, ) -> Result<SignatureHelpResult>
Handle signature help request (textDocument/signatureHelp).
Returns parameter signatures and documentation while typing a function call.
context is omitted (None) — the server infers trigger state from position.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise signatureHelpProvider support.
Sourcepub async fn handle_inlay_hints(
&self,
file_path: String,
start_line: u32,
start_character: u32,
end_line: u32,
end_character: u32,
) -> Result<InlayHintsResult>
pub async fn handle_inlay_hints( &self, file_path: String, start_line: u32, start_character: u32, end_line: u32, end_character: u32, ) -> Result<InlayHintsResult>
Handle inlay hints request (textDocument/inlayHint).
Returns inferred type and parameter annotations the editor would render inline. Output positions are in MCP 1-based form.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise inlayHintProvider support.
Source§impl Translator
impl Translator
Sourcepub async fn handle_call_hierarchy_prepare(
&self,
file_path: String,
line: u32,
character: u32,
) -> Result<CallHierarchyPrepareResult>
pub async fn handle_call_hierarchy_prepare( &self, file_path: String, line: u32, character: u32, ) -> Result<CallHierarchyPrepareResult>
Handle call hierarchy prepare request.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise callHierarchyProvider support.
Sourcepub async fn handle_incoming_calls(
&self,
item: Value,
) -> Result<IncomingCallsResult>
pub async fn handle_incoming_calls( &self, item: Value, ) -> Result<IncomingCallsResult>
Handle incoming calls request.
§Errors
Returns an error if the LSP request fails, the item is invalid, or the
routed server does not advertise callHierarchyProvider support.
Sourcepub async fn handle_outgoing_calls(
&self,
item: Value,
) -> Result<OutgoingCallsResult>
pub async fn handle_outgoing_calls( &self, item: Value, ) -> Result<OutgoingCallsResult>
Handle outgoing calls request.
§Errors
Returns an error if the LSP request fails, the item is invalid, or the
routed server does not advertise callHierarchyProvider support.
Source§impl Translator
impl Translator
Sourcepub fn cached_diagnostics_uri(
workspace_roots: &[PathBuf],
file_path: &str,
) -> Result<String>
pub fn cached_diagnostics_uri( workspace_roots: &[PathBuf], file_path: &str, ) -> Result<String>
Resolve the LSP-side cache key (URI string) for a cached-diagnostics lookup.
Split out from the cache read itself so callers (e.g. the
get_cached_diagnostics MCP tool) can do the path canonicalize() and
workspace-boundary check before taking the NotificationCache lock —
that lock is also needed by diagnostics_pump to store incoming
notifications, so nothing that isn’t a plain map lookup should run
while it’s held.
§Errors
Returns an error if the path is invalid or outside workspace boundaries.
Sourcepub async fn handle_diagnostics(
&self,
file_path: String,
notification_cache: &Mutex<NotificationCache>,
) -> Result<DiagnosticsResult>
pub async fn handle_diagnostics( &self, file_path: String, notification_cache: &Mutex<NotificationCache>, ) -> Result<DiagnosticsResult>
Handle diagnostics request.
Merges the LSP pull-model response (textDocument/diagnostic) with
whatever is already cached from textDocument/publishDiagnostics push
notifications for the same file, so this returns the same diagnostics
get_cached_diagnostics would for the file at the same point in time
(see #244 — rust-analyzer’s pull endpoint omits flycheck/clippy-sourced
diagnostics, and empirically also some native ones, that are only ever
delivered via the push path). If the pull request itself fails (e.g. a
push-only server answering -32601, or a timeout), a non-empty cache
entry is returned as a cache-only result instead of propagating the
error, since the cache is not required to be fresher than the pull
response to be useful here.
The cache is read only after the pull request settles (success or
failure) and held only for the lookup itself — never across the LSP
round-trip — matching the lock-ordering discipline documented on
cached_diagnostics_uri. Like get_cached_diagnostics, the cache is
treated as eventually consistent: a cached entry may reflect a
slightly older document version than the fresh pull result if an edit
landed inside the server’s flycheck debounce window.
§Errors
Returns an error if the LSP pull request fails and the cache holds no diagnostics for the file either, or if the file cannot be opened.
Sourcepub async fn diagnostics_from_cache_entry(
diag_info: Option<&DiagnosticInfo>,
encoding: PositionEncoding,
tracker: &Arc<DocumentTracker>,
) -> DiagnosticsResult
pub async fn diagnostics_from_cache_entry( diag_info: Option<&DiagnosticInfo>, encoding: PositionEncoding, tracker: &Arc<DocumentTracker>, ) -> DiagnosticsResult
Convert a cached diagnostics entry into the MCP-facing result shape.
Takes an already-cloned Option<&DiagnosticInfo> (out of the
NotificationCache lock) rather than the cache itself, so this
mapping — which is not a bounded operation for a large diagnostics set
— never runs while the cache is locked.
encoding is the negotiated encoding of the server that published
these diagnostics; pass PositionEncoding::Utf16 when no live server
context is available (e.g. a cache-only read with no resolved owner).
Sourcepub async fn merge_diagnostics(
pull: DiagnosticsResult,
diag_info: Option<&DiagnosticInfo>,
encoding: PositionEncoding,
tracker: &Arc<DocumentTracker>,
) -> DiagnosticsResult
pub async fn merge_diagnostics( pull: DiagnosticsResult, diag_info: Option<&DiagnosticInfo>, encoding: PositionEncoding, tracker: &Arc<DocumentTracker>, ) -> DiagnosticsResult
Merge push-model diagnostics from the notification cache into a
pull-model (textDocument/diagnostic) result.
rust-analyzer’s pull endpoint omits diagnostics that are only ever
delivered via textDocument/publishDiagnostics push notifications —
not just flycheck/clippy lints, but empirically (verified against a
live rust-analyzer 1.97.1 session, see #244) some native diagnostics
too. Those are cached separately in NotificationCache.
Where the same logical problem is reported through both paths, the
two representations were observed to differ in both range and
rendered message. Captured example, a “not all trait items
implemented” (E0046) error for one impl block: pull reported range
(96,7)-(96,12) (the trait name) with message “not all trait items
implemented, missing: fn hello”; the push notification for the same
error reported range (95,1)-(95,32) (the impl block) with message
“not all trait items implemented, missing: hello\nmissing hello
in implementation” — same code/severity, adjacent but distinct
ranges, different message text. Exact field equality never dedups
cases like that.
Given that, a cache entry is treated as a duplicate of a pull entry
when both carry a code, the (severity, code) pair matches, and
the two ranges are either overlapping or start within
DUPLICATE_RANGE_PROXIMITY_LINES lines of each other — close
enough to be the same underlying model divergence, not two distinct
occurrences of the same error class (e.g. two unrelated E0308
mismatches at different call sites in one file, one caught only
natively and one only by flycheck). Diagnostics with no code fall
back to full-field equality, since there is no cheaper stable
identity available for them.
Output is sorted by (start.line, start.character) so merged
cache-only entries don’t land out of document order after the
pull-model ones.
Sourcepub fn handle_server_logs(
cache: &NotificationCache,
limit: usize,
min_level: Option<String>,
) -> Result<ServerLogsResult>
pub fn handle_server_logs( cache: &NotificationCache, limit: usize, min_level: Option<String>, ) -> Result<ServerLogsResult>
Sourcepub fn handle_server_messages(
cache: &NotificationCache,
limit: usize,
) -> Result<ServerMessagesResult>
pub fn handle_server_messages( cache: &NotificationCache, limit: usize, ) -> Result<ServerMessagesResult>
Source§impl Translator
impl Translator
Sourcepub async fn handle_rename(
&self,
file_path: String,
line: u32,
character: u32,
new_name: String,
) -> Result<RenameResult>
pub async fn handle_rename( &self, file_path: String, line: u32, character: u32, new_name: String, ) -> Result<RenameResult>
Handle rename request.
§Errors
Returns an error if new_name exceeds the maximum allowed length,
the LSP request fails, the file cannot be opened, or the routed
server does not advertise renameProvider support.
Sourcepub async fn handle_format_document(
&self,
file_path: String,
tab_size: u32,
insert_spaces: bool,
) -> Result<FormatDocumentResult>
pub async fn handle_format_document( &self, file_path: String, tab_size: u32, insert_spaces: bool, ) -> Result<FormatDocumentResult>
Handle format document request.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise documentFormattingProvider support.
Sourcepub async fn handle_code_actions(
&self,
file_path: String,
start_line: u32,
start_character: u32,
end_line: u32,
end_character: u32,
kind_filter: Option<String>,
) -> Result<CodeActionsResult>
pub async fn handle_code_actions( &self, file_path: String, start_line: u32, start_character: u32, end_line: u32, end_character: u32, kind_filter: Option<String>, ) -> Result<CodeActionsResult>
Handle code actions request.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise codeActionProvider support.
Source§impl Translator
impl Translator
Sourcepub async fn handle_hover(
&self,
file_path: String,
line: u32,
character: u32,
) -> Result<HoverResult>
pub async fn handle_hover( &self, file_path: String, line: u32, character: u32, ) -> Result<HoverResult>
Handle hover request.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise hoverProvider support.
Sourcepub async fn handle_definition(
&self,
file_path: String,
line: u32,
character: u32,
) -> Result<DefinitionResult>
pub async fn handle_definition( &self, file_path: String, line: u32, character: u32, ) -> Result<DefinitionResult>
Handle definition request.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise definitionProvider support.
Sourcepub async fn handle_references(
&self,
file_path: String,
line: u32,
character: u32,
include_declaration: bool,
) -> Result<ReferencesResult>
pub async fn handle_references( &self, file_path: String, line: u32, character: u32, include_declaration: bool, ) -> Result<ReferencesResult>
Handle references request.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise referencesProvider support.
Sourcepub async fn handle_implementation(
&self,
file_path: String,
line: u32,
character: u32,
) -> Result<LocationsResult>
pub async fn handle_implementation( &self, file_path: String, line: u32, character: u32, ) -> Result<LocationsResult>
Handle go-to-implementation request (textDocument/implementation).
Returns the locations of trait method or interface member implementations.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise implementationProvider support.
Sourcepub async fn handle_type_definition(
&self,
file_path: String,
line: u32,
character: u32,
) -> Result<LocationsResult>
pub async fn handle_type_definition( &self, file_path: String, line: u32, character: u32, ) -> Result<LocationsResult>
Handle go-to-type-definition request (textDocument/typeDefinition).
Returns the type definition location of the expression at position. Distinct from go-to-definition for variable bindings where definition and type differ.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise typeDefinitionProvider support.
Source§impl Translator
impl Translator
Sourcepub async fn handle_document_symbols(
&self,
file_path: String,
) -> Result<DocumentSymbolsResult>
pub async fn handle_document_symbols( &self, file_path: String, ) -> Result<DocumentSymbolsResult>
Handle document symbols request.
§Errors
Returns an error if the LSP request fails, the file cannot be opened,
or the routed server does not advertise documentSymbolProvider support.
Sourcepub async fn handle_workspace_symbol(
&self,
query: String,
kind_filter: Option<String>,
limit: u32,
) -> Result<WorkspaceSymbolResult>
pub async fn handle_workspace_symbol( &self, query: String, kind_filter: Option<String>, limit: u32, ) -> Result<WorkspaceSymbolResult>
Handle workspace symbol search.
§Errors
Returns an error if the LSP request fails, no server is configured, or
the routed server does not advertise workspaceSymbolProvider support.
Source§impl Translator
impl Translator
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new translator.
Starts with an empty router: nothing is routable until Self::with_router
installs one, which matches having no servers registered.
Sourcepub fn set_workspace_roots(&mut self, roots: Vec<PathBuf>)
pub fn set_workspace_roots(&mut self, roots: Vec<PathBuf>)
Set the workspace roots for path validation.
Only called during single-owner setup, before the translator is
shared, so this replaces the Arc wholesale rather than locking.
Sourcepub fn with_notification_cache(
self,
cache: Arc<Mutex<NotificationCache>>,
) -> Self
pub fn with_notification_cache( self, cache: Arc<Mutex<NotificationCache>>, ) -> Self
Give the translator a handle to the shared diagnostics cache, so the respawn path can invalidate a respawned server’s stale entries.
Only called during single-owner setup (mirrors Self::with_router),
before the translator is shared – serve_with passes the same
Arc<Mutex<NotificationCache>> used by the notification pump tasks.
Sourcepub fn set_expected_servers(&self, servers: HashSet<ServerId>)
pub fn set_expected_servers(&self, servers: HashSet<ServerId>)
Mark the set of servers that are expected (configured + applicable) but may still be initializing in the background.
Sourcepub fn clear_expected_servers(&self)
pub fn clear_expected_servers(&self)
Clear the expected-servers set (e.g. after background init failed).
Sourcepub fn with_router(self, router: ToolRouter) -> Self
pub fn with_router(self, router: ToolRouter) -> Self
Install the per-tool routing table built from the applicable configs.
Only called during single-owner setup, before the translator is
shared, so this replaces the Arc-wrapped router wholesale.
Sourcepub fn rebind_router(&self, registered: &HashSet<ServerId>)
pub fn rebind_router(&self, registered: &HashSet<ServerId>)
Rebind the routing table to the set of servers that actually
registered, dropping or redirecting routes to servers that failed to
spawn. See ToolRouter::rebind_to_registered for the full semantics.
Sourcepub fn is_diagnostics_route(&self, language_id: &str, id: &ServerId) -> bool
pub fn is_diagnostics_route(&self, language_id: &str, id: &ServerId) -> bool
Whether id is the server the router currently resolves
ToolKind::Diagnostics to for language_id.
Purpose-built for register_servers, which needs this to compute the
diagnostics-cache filter passed into each pump task, without exposing
the router’s lock guard outside this module.
Sourcepub fn with_extensions(self, extension_map: HashMap<String, String>) -> Self
pub fn with_extensions(self, extension_map: HashMap<String, String>) -> Self
Configure custom file extension mappings.
This method sets the extension map and updates the document tracker to use the same mappings for language detection.
Only called during single-owner setup, before the translator is
shared, so this replaces the Arc-wrapped fields wholesale.
Sourcepub fn with_resource_limits(self, limits: ResourceLimits) -> Self
pub fn with_resource_limits(self, limits: ResourceLimits) -> Self
Configure resource limits (max open documents, max file size) for the document tracker.
Only called during single-owner setup, before the translator is
shared. This builder and Self::with_extensions may be called in
either order – each rebuilds document_tracker from both of
self.resource_limits/self.extension_map’s current values,
instead of one of them starting fresh from
ResourceLimits::default()/an empty extension map, which previously
meant whichever builder ran last silently discarded the other’s
effect.
Sourcepub fn register_client(&self, id: impl Into<ServerId>, client: LspClient)
pub fn register_client(&self, id: impl Into<ServerId>, client: LspClient)
Register an LSP client under its routing identity.
Only called once per server, from register_servers during initial
background init. The respawn path does not reuse this method: it
needs the previous client back (to fail its pending requests) and
must also reset document_tracker for the swapped-in server, neither
of which this method does.
Sourcepub fn register_server(&self, id: impl Into<ServerId>, server: LspServer)
pub fn register_server(&self, id: impl Into<ServerId>, server: LspServer)
Register an LSP server under its routing identity.
Sourcepub fn open_document_paths(&self) -> Vec<PathBuf>
pub fn open_document_paths(&self) -> Vec<PathBuf>
Snapshot of currently open document paths, used for MCP resource listing.
Sourcepub fn is_document_open(&self, path: &Path) -> bool
pub fn is_document_open(&self, path: &Path) -> bool
Whether a document is currently tracked as open.