Skip to main content

Translator

Struct Translator 

Source
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

Source

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.

Source

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.

Source

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

Source

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.

Source

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.

Source

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

Source

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.

Source

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.

Source

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).

Source

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.

Source

pub fn handle_server_logs( cache: &NotificationCache, limit: usize, min_level: Option<String>, ) -> Result<ServerLogsResult>

Handle server logs request.

§Errors

Returns an error if the min_level parameter is invalid.

Source

pub fn handle_server_messages( cache: &NotificationCache, limit: usize, ) -> Result<ServerMessagesResult>

Handle server messages request.

§Errors

This method does not return errors.

Source§

impl Translator

Source

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.

Source

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.

Source

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

Source

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.

Source

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.

Source

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.

Source

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.

Source

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

Source

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.

Source

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

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn clear_expected_servers(&self)

Clear the expected-servers set (e.g. after background init failed).

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn register_server(&self, id: impl Into<ServerId>, server: LspServer)

Register an LSP server under its routing identity.

Source

pub fn open_document_paths(&self) -> Vec<PathBuf>

Snapshot of currently open document paths, used for MCP resource listing.

Source

pub fn is_document_open(&self, path: &Path) -> bool

Whether a document is currently tracked as open.

Trait Implementations§

Source§

impl Debug for Translator

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Translator

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more