//! Editor providers: implement [`Providers`] and register with //! `register_plugin!(T, providers)`, then declare the kinds and languages in //! `plugin.toml`: //! //! ```toml //! [[contributes.providers]] //! kinds = ["completion", "definition"] # also inline-completion, code-actions, line-markers //! languages = ["xml"] //! ``` //! //! They run on the editing path: answer within ~50 ms (later results are //! dropped; at 500 ms the call is interrupted). Inline completion may take //! longer (it may use the network) but is cancelled when the user types on. use crate::types::{Location, Position, Range, TextEdit}; /// The document a request is about. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct Document { pub path: String, pub language: String, pub version: u64, pub text: String, } /// Icon and sort group of a completion item. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum CompletionKind { Text, Method, Function, Constructor, Field, Variable, Class, Interface, Module, Property, Unit, Value, Enum, Keyword, Snippet, Color, File, Reference, Folder, EnumMember, Constant, Struct, Event, Operator, TypeParameter, } impl CompletionKind { /// The name the plugin API uses (`completion-item.kind`). pub fn as_str(self) -> &'static str { match self { Self::Text => "text", Self::Method => "method", Self::Function => "function", Self::Constructor => "constructor", Self::Field => "field", Self::Variable => "variable", Self::Class => "class", Self::Interface => "interface", Self::Module => "module", Self::Property => "property", Self::Unit => "unit", Self::Value => "value", Self::Enum => "enum", Self::Keyword => "keyword", Self::Snippet => "snippet", Self::Color => "color", Self::File => "file", Self::Reference => "reference", Self::Folder => "folder", Self::EnumMember => "enum-member", Self::Constant => "constant", Self::Struct => "struct", Self::Event => "event", Self::Operator => "operator", Self::TypeParameter => "type-parameter", } } } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CompletionItem { pub label: String, pub detail: Option, pub kind: Option, /// With `snippet`, tab stops and placeholders (`$1`, `${1:name}`, `$0`). pub insert_text: String, pub snippet: bool, /// Replaced on accept; `None`: the word at the caret. pub replace: Option, pub sort_text: Option, /// Matched against what was typed instead of `label`. pub filter_text: Option, /// Markdown. pub documentation: Option, /// Applied with the item elsewhere in the document (an import). pub additional_edits: Vec, } impl CompletionItem { pub fn new(label: &str, kind: CompletionKind) -> Self { Self { label: label.into(), detail: None, kind: Some(kind), insert_text: label.into(), snippet: false, replace: None, sort_text: None, filter_text: None, documentation: None, additional_edits: Vec::new(), } } } #[derive(Clone, Debug, PartialEq, Eq)] pub struct InlineSuggestion { pub insert_text: String, /// Replaced range; `None` inserts at the caret. pub replace: Option, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct CodeAction { pub title: String, /// `quickfix`, `refactor`, … pub kind: Option, pub preferred: bool, /// (absolute path, edits) per file. pub edits: Vec<(String, Vec)>, /// The plugin's own reference: with it and no `edits`, the edits come /// from [`Providers::resolve_code_action`] once the user picks the action. pub data: Option, } #[derive(Clone, Debug, PartialEq, Eq)] pub struct LineMarker { /// 0-based. pub line: u32, /// `navigate` (default), `implemented`, `implementing`, `run`. pub icon: Option, pub tooltip: String, /// Opened on click. pub target: Option, } /// What a plugin provides in the editor. Only the kinds declared in /// `plugin.toml` are ever called; the defaults return nothing. pub trait Providers { fn completion(&mut self, _doc: &Document, _at: Position, _trigger: Option<&str>) -> Vec { Vec::new() } fn inline_completion(&mut self, _doc: &Document, _at: Position) -> Option { None } fn code_actions(&mut self, _doc: &Document, _selection: Range) -> Vec { Vec::new() } /// The edits of an action [`Providers::code_actions`] returned with /// `data`, when the user picks it (the command budget applies, not 50 ms). fn resolve_code_action(&mut self, _doc: &Document, action: CodeAction) -> Result { Ok(action) } fn definition(&mut self, _doc: &Document, _at: Position) -> Vec { Vec::new() } fn line_markers(&mut self, _doc: &Document) -> Vec { Vec::new() } }