Skip to main content

Ecosystem

Trait Ecosystem 

Source
pub trait Ecosystem:
    Send
    + Sync
    + Sealed {
Show 21 methods // Required methods fn id(&self) -> &'static str; fn display_name(&self) -> &'static str; fn manifest_filenames(&self) -> &[&'static str]; fn parse_manifest<'a>( &'a self, content: &'a str, uri: &'a Uri, ) -> BoxFuture<'a, Result<Box<dyn ParseResult>>>; fn registry(&self) -> Arc<dyn Registry>; fn formatter(&self) -> &dyn EcosystemFormatter; fn generate_completions<'a>( &'a self, parse_result: &'a dyn ParseResult, position: Position, content: &'a str, freshness: FreshnessSettings, ) -> BoxFuture<'a, Completions>; fn as_any(&self) -> &dyn Any; // Provided methods fn manifest_extensions(&self) -> &[&'static str] { ... } fn manifest_patterns(&self) -> &[&'static str] { ... } fn manifest_directory_patterns(&self) -> &[(&'static str, &'static str)] { ... } fn lockfile_filenames(&self) -> &[&'static str] { ... } fn watched_config_filenames(&self) -> &[&'static str] { ... } fn lockfile_provider(&self) -> Option<Arc<dyn LockFileProvider>> { ... } fn generate_inlay_hints<'a>( &'a self, parse_result: &'a dyn ParseResult, versions: VersionData<'a>, loading_state: LoadingState, config: &'a EcosystemConfig, ) -> BoxFuture<'a, Vec<InlayHint>> { ... } fn generate_hover<'a>( &'a self, parse_result: &'a dyn ParseResult, position: Position, versions: VersionData<'a>, freshness: FreshnessSettings, ) -> BoxFuture<'a, Option<Hover>> { ... } fn generate_code_actions<'a>( &'a self, parse_result: &'a dyn ParseResult, position: Position, uri: &'a Uri, versions: VersionData<'a>, content: &'a str, ) -> BoxFuture<'a, Vec<CodeAction>> { ... } fn generate_diagnostics<'a>( &'a self, parse_result: &'a dyn ParseResult, versions: VersionData<'a>, uri: &'a Uri, freshness: FreshnessSettings, severities: DiagnosticSeverities, ) -> BoxFuture<'a, Vec<Diagnostic>> { ... } fn generate_document_links( &self, _parse_result: &dyn ParseResult, _uri: &Uri, ) -> Vec<DocumentLink> { ... } fn generate_code_lenses<'a>( &'a self, parse_result: &'a dyn ParseResult, content: &'a str, versions: VersionData<'a>, uri: &'a Uri, command_id: &'a str, ) -> BoxFuture<'a, Vec<CodeLens>> { ... } fn package_search_is_incomplete(&self) -> bool { ... }
}
Expand description

Main trait that all ecosystem implementations must implement.

Each ecosystem (Cargo, npm, PyPI, etc.) provides its own implementation. This trait defines the contract for parsing manifests, fetching registry data, and generating LSP responses.

§Type Erasure

This trait uses Box<dyn Trait> instead of associated types to allow runtime polymorphism and dynamic ecosystem registration.

§Examples

use deps_core::{Ecosystem, ParseResult, Registry, EcosystemConfig, PackageName, ConcreteVersion};
use deps_core::completion::Completions;
use deps_core::lsp_helpers::{
    DiagnosticMessages, DiagnosticPolicy, EcosystemFormatter, OsvNaming, PackageNaming,
    PackageRendering, RequirementResolution, SourcePolicy,
};
use std::sync::Arc;
use std::any::Any;
use tower_lsp_server::ls_types::{Uri, CompletionItem, Position};

struct MyFormatter;
impl PackageNaming for MyFormatter {}
impl PackageRendering for MyFormatter {
    fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String { version.to_string() }
    fn package_url(&self, name: &PackageName) -> String { format!("https://example.com/{name}") }
}
impl RequirementResolution for MyFormatter {}
impl DiagnosticMessages for MyFormatter {}
impl DiagnosticPolicy for MyFormatter {}
impl SourcePolicy for MyFormatter {}
impl OsvNaming for MyFormatter {}

struct MyEcosystem {
    registry: Arc<dyn Registry>,
    formatter: MyFormatter,
}

impl deps_core::ecosystem::private::Sealed for MyEcosystem {}

impl Ecosystem for MyEcosystem {
    fn id(&self) -> &'static str { "my-ecosystem" }
    fn display_name(&self) -> &'static str { "My Ecosystem" }
    fn manifest_filenames(&self) -> &[&'static str] { &["my-manifest.toml"] }

    fn parse_manifest<'a>(
        &'a self,
        _content: &'a str,
        _uri: &'a Uri,
    ) -> deps_core::ecosystem::BoxFuture<'a, deps_core::error::Result<Box<dyn ParseResult>>> {
        Box::pin(async move { todo!() })
    }

    fn registry(&self) -> Arc<dyn Registry> { self.registry.clone() }

    fn formatter(&self) -> &dyn EcosystemFormatter { &self.formatter }

    fn generate_completions<'a>(
        &'a self,
        _parse_result: &'a dyn ParseResult,
        _position: Position,
        _content: &'a str,
        _freshness: deps_core::FreshnessSettings,
    ) -> deps_core::ecosystem::BoxFuture<'a, Completions> {
        Box::pin(async move { Completions::default() })
    }

    fn as_any(&self) -> &dyn Any { self }
}

Required Methods§

Source

fn id(&self) -> &'static str

Unique identifier (e.g., “cargo”, “npm”, “pypi”)

This identifier is used for ecosystem registration and routing.

Source

fn display_name(&self) -> &'static str

Human-readable name (e.g., “Cargo (Rust)”, “npm (JavaScript)”)

This name is displayed in diagnostic messages and logs.

Source

fn manifest_filenames(&self) -> &[&'static str]

Manifest filenames this ecosystem handles (e.g., [“Cargo.toml”])

The ecosystem registry uses these filenames to route file URIs to the appropriate ecosystem implementation.

Source

fn parse_manifest<'a>( &'a self, content: &'a str, uri: &'a Uri, ) -> BoxFuture<'a, Result<Box<dyn ParseResult>>>

Parse a manifest file and return parsed result

§Arguments
  • content - Raw file content
  • uri - Document URI for position tracking
§Errors

Returns error if manifest cannot be parsed

Source

fn registry(&self) -> Arc<dyn Registry>

Get the registry client for this ecosystem

The registry provides version lookup and package search capabilities.

Source

fn formatter(&self) -> &dyn EcosystemFormatter

Get the ecosystem-specific formatter for LSP response generation.

The formatter handles version comparison, package URLs, and text formatting. Override this to customize LSP response generation.

Source

fn generate_completions<'a>( &'a self, parse_result: &'a dyn ParseResult, position: Position, content: &'a str, freshness: FreshnessSettings, ) -> BoxFuture<'a, Completions>

Generate completions for a position.

Provides autocomplete suggestions for package names and versions.

freshness.enabled gates whether version completion items carry a relative-age label_details suffix (issue #145); implementations that delegate to crate::completion::complete_versions_generic get this for free by threading freshness through.

The returned Completions::is_incomplete must reflect this specific call (the completion context actually served), not a static worst case for the ecosystem as a whole (#427): a package-name search over an unranked, truncated index should report true, while a version completion or any other exhaustive context in the same manifest must report false, even for an ecosystem where some contexts are incomplete and others are not.

Source

fn as_any(&self) -> &dyn Any

Support for downcasting to concrete ecosystem type

This allows ecosystem-specific operations when needed.

Provided Methods§

Source

fn manifest_extensions(&self) -> &[&'static str]

File extensions this ecosystem handles when the manifest basename is not fixed (e.g. [".csproj", ".fsproj"] for NuGet project files).

Consulted by crate::EcosystemRegistry::get_for_filename only after an exact manifest_filenames match fails. Empty by default, indicating this ecosystem is routed solely by exact filename.

Source

fn manifest_patterns(&self) -> &[&'static str]

Basename glob patterns this ecosystem handles, each containing exactly one * wildcard (e.g. ["requirements*.txt"]).

Consulted by crate::EcosystemRegistry::get_for_filename as a third routing stage, tried after an exact manifest_filenames match fails and before manifest_extensions — for basenames that are neither fixed nor identified by extension alone (e.g. requirements.txt, requirements-dev.txt). Empty by default. Matching is case-sensitive, unlike the extension stage: these patterns target canonically-lowercase filenames (pip, Renovate and Dependabot all treat requirements.txt as lowercase), whereas the extension stage exists specifically for Windows/MSBuild project files whose case genuinely varies.

Source

fn manifest_directory_patterns(&self) -> &[(&'static str, &'static str)]

(directory_path, file_suffix) pairs identifying a file solely by its containing directory path and suffix. directory_path may be a single segment (e.g. [("requirements", ".txt")] for Python’s requirements/base.txt split-file layout) or multiple /-joined segments (e.g. [(".github/workflows", ".yml")] for GitHub Actions workflow files) — either way it is matched against the tail of the file’s directory path on segment boundaries, not just the immediate parent, so a multi-segment pattern matches regardless of how many ancestor directories precede it. Used when the basename alone carries no ecosystem signal.

Consulted by crate::EcosystemRegistry::get_for_uri only, after both manifest_patterns and manifest_extensions miss on the basename — it needs the full path, so it is never reachable from crate::EcosystemRegistry::get_for_filename. Empty by default.

Source

fn lockfile_filenames(&self) -> &[&'static str]

Lock file filenames this ecosystem uses (e.g., [“Cargo.lock”])

Used for file watching - LSP will monitor changes to these files and refresh UI when they change. Returns empty slice if ecosystem doesn’t use lock files.

§Default Implementation

Returns empty slice by default, indicating no lock files are used.

Source

fn watched_config_filenames(&self) -> &[&'static str]

Non-lockfile config filenames this ecosystem resolves during Self::parse_manifest (e.g. ["pnpm-workspace.yaml", ".npmrc"] for npm’s catalog and registry resolution), whose values end up baked into a manifest’s ParseResult rather than looked up separately the way a Self::lockfile_provider is.

Used for file watching alongside Self::lockfile_filenames — LSP monitors changes to these files too, but reacts by fully re-parsing every open document of this ecosystem (not merely refreshing cached resolved versions, since the value isn’t kept separately from the parse result to refresh in place). Returns empty slice by default.

Source

fn lockfile_provider(&self) -> Option<Arc<dyn LockFileProvider>>

Get the lock file provider for this ecosystem.

Returns None if the ecosystem doesn’t support lock files. Lock files provide resolved dependency versions without network requests.

Source

fn generate_inlay_hints<'a>( &'a self, parse_result: &'a dyn ParseResult, versions: VersionData<'a>, loading_state: LoadingState, config: &'a EcosystemConfig, ) -> BoxFuture<'a, Vec<InlayHint>>

Generate inlay hints for the document.

Default implementation delegates to lsp_helpers::generate_inlay_hints using self.formatter(). Override only if custom behavior is needed.

Source

fn generate_hover<'a>( &'a self, parse_result: &'a dyn ParseResult, position: Position, versions: VersionData<'a>, freshness: FreshnessSettings, ) -> BoxFuture<'a, Option<Hover>>

Generate hover information for a position.

Default implementation delegates to lsp_helpers::generate_hover using self.formatter() and self.registry().

Source

fn generate_code_actions<'a>( &'a self, parse_result: &'a dyn ParseResult, position: Position, uri: &'a Uri, versions: VersionData<'a>, content: &'a str, ) -> BoxFuture<'a, Vec<CodeAction>>

Generate code actions for a position.

Default implementation delegates to lsp_helpers::generate_code_actions using self.formatter() and self.registry(). versions carries the same OSV scan results generate_hover and generate_diagnostics use, so a vulnerable dependency at position gets a “fix vulnerability” quickfix alongside the plain version-update actions. content is the manifest source, needed to guard against rewriting a version_range that no longer slices to its declared requirement text (see lsp_helpers::literal_span_matches).

Source

fn generate_diagnostics<'a>( &'a self, parse_result: &'a dyn ParseResult, versions: VersionData<'a>, uri: &'a Uri, freshness: FreshnessSettings, severities: DiagnosticSeverities, ) -> BoxFuture<'a, Vec<Diagnostic>>

Generate diagnostics for the document.

Default implementation delegates to lsp_helpers::generate_diagnostics_from_cache using self.formatter().

Generate textDocument/documentLink targets for the document.

A document link is a clickable reference from a byte range in this manifest to another resource — e.g. a -r other.txt / -c constraints.txt reference inside a pip requirements file, resolved to the absolute file it points at. Purely local (no registry access), so unlike the other generate_* methods this is synchronous rather than a BoxFuture. Empty by default: most ecosystems’ manifest formats have no such intra-file-graph references.

Source

fn generate_code_lenses<'a>( &'a self, parse_result: &'a dyn ParseResult, content: &'a str, versions: VersionData<'a>, uri: &'a Uri, command_id: &'a str, ) -> BoxFuture<'a, Vec<CodeLens>>

Generate the “Update N outdated dependencies” code lens for the document.

Default implementation delegates to lsp_helpers::generate_code_lenses using self.formatter(). Override only if custom behavior is needed.

Source

fn package_search_is_incomplete(&self) -> bool

Whether this ecosystem’s package-name search may return a truncated view of a larger candidate set (see e.g. PypiRegistry::search’s doc comment).

generate_completions already reports this precisely per call via Completions::is_incomplete whenever a real completion context is available. This method exists only for the two deps-lsp code paths that cannot compute that precise per-call signal because no context has been resolved yet:

  • the raw-text fallback search (fallback_completion), which always performs a package-name lookup via crate::Registry::search regardless of what completion context (or lack thereof) triggered it;
  • the document-not-loaded early return, before any ParseResult — and so any completion context — exists to call generate_completions with.

Unlike the ecosystem-wide completions_are_incomplete() flag this method superseded (#419, removed in #427), it never gates the primary generate_completions response — only these two context-less fallbacks. Default false preserves existing behavior for every ecosystem whose package-name search is always exhaustive.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§