use super::{Document, DocumentView, Workspace, WorkspaceBuilder}; use futures_boxed::boxed; use lsp_types::*; use std::sync::Arc; pub struct FeatureRequest

{ pub params: P, pub view: DocumentView, pub client_capabilities: Arc, pub distribution: Arc>, } impl

FeatureRequest

{ pub fn workspace(&self) -> &Workspace { &self.view.workspace } pub fn document(&self) -> &Document { &self.view.document } pub fn related_documents(&self) -> &[Arc] { &self.view.related_documents } } pub trait FeatureProvider { type Params; type Output; #[boxed] async fn execute<'a>(&'a self, request: &'a FeatureRequest) -> Self::Output; } type ListProvider = Box> + Send + Sync>; #[derive(Default)] pub struct ConcatProvider { providers: Vec>, } impl ConcatProvider { pub fn new(providers: Vec>) -> Self { Self { providers } } } impl FeatureProvider for ConcatProvider where P: Send + Sync, O: Send + Sync, { type Params = P; type Output = Vec; #[boxed] async fn execute<'a>(&'a self, request: &'a FeatureRequest

) -> Vec { let mut items = Vec::new(); for provider in &self.providers { items.append(&mut provider.execute(request).await); } items } } type OptionProvider = Box> + Send + Sync>; #[derive(Default)] pub struct ChoiceProvider { providers: Vec>, } impl ChoiceProvider { pub fn new(providers: Vec>) -> Self { Self { providers } } } impl FeatureProvider for ChoiceProvider where P: Send + Sync, O: Send + Sync, { type Params = P; type Output = Option; #[boxed] async fn execute<'a>(&'a self, request: &'a FeatureRequest

) -> Option { for provider in &self.providers { let item = provider.execute(request).await; if item.is_some() { return item; } } None } } #[derive(Debug, PartialEq, Eq, Clone)] pub struct FeatureSpecFile { name: &'static str, text: &'static str, } pub struct FeatureSpec { pub files: Vec, pub main_file: &'static str, pub position: Position, pub new_name: &'static str, pub include_declaration: bool, pub client_capabilities: ClientCapabilities, pub distribution: Box, } impl Default for FeatureSpec { fn default() -> Self { Self { files: Vec::new(), main_file: "", position: Position::new(0, 0), new_name: "", include_declaration: false, client_capabilities: ClientCapabilities::default(), distribution: Box::new(tex::Unknown::default()), } } } impl FeatureSpec { pub fn file(name: &'static str, text: &'static str) -> FeatureSpecFile { FeatureSpecFile { name, text } } pub fn uri(name: &str) -> Url { let path = std::env::temp_dir().join(name); Url::from_file_path(path).unwrap() } fn identifier(&self) -> TextDocumentIdentifier { let uri = Self::uri(self.main_file); TextDocumentIdentifier::new(uri) } fn view(&self) -> DocumentView { let mut builder = WorkspaceBuilder::new(); for file in &self.files { builder.document(file.name, file.text); } let workspace = builder.workspace; let main_uri = Self::uri(self.main_file); let main_document = workspace.find(&main_uri.into()).unwrap(); DocumentView::new(Arc::new(workspace), main_document) } fn request(self, params: T) -> FeatureRequest { FeatureRequest { params, view: self.view(), client_capabilities: Arc::new(self.client_capabilities), distribution: Arc::new(self.distribution), } } } impl Into> for FeatureSpec { fn into(self) -> FeatureRequest { let params = TextDocumentPositionParams::new(self.identifier(), self.position); self.request(params) } } impl Into> for FeatureSpec { fn into(self) -> FeatureRequest { let params = CompletionParams { text_document_position: TextDocumentPositionParams::new( self.identifier(), self.position, ), context: None, }; self.request(params) } } impl Into> for FeatureSpec { fn into(self) -> FeatureRequest { let params = FoldingRangeParams { text_document: self.identifier(), }; self.request(params) } } impl Into> for FeatureSpec { fn into(self) -> FeatureRequest { let params = DocumentLinkParams { text_document: self.identifier(), }; self.request(params) } } impl Into> for FeatureSpec { fn into(self) -> FeatureRequest { let params = ReferenceParams { text_document_position: TextDocumentPositionParams::new( self.identifier(), self.position, ), context: ReferenceContext { include_declaration: self.include_declaration, }, }; self.request(params) } } impl Into> for FeatureSpec { fn into(self) -> FeatureRequest { let params = RenameParams { text_document_position: TextDocumentPositionParams::new( self.identifier(), self.position, ), new_name: self.new_name.to_owned(), }; self.request(params) } } impl Into> for FeatureSpec { fn into(self) -> FeatureRequest { let params = DocumentSymbolParams { text_document: self.identifier(), }; self.request(params) } } pub fn test_feature(provider: F, spec: S) -> O where F: FeatureProvider, S: Into>, { futures::executor::block_on(provider.execute(&spec.into())) }