summaryrefslogtreecommitdiff
path: root/support/texlab/src/features.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/features.rs')
-rw-r--r--support/texlab/src/features.rs272
1 files changed, 272 insertions, 0 deletions
diff --git a/support/texlab/src/features.rs b/support/texlab/src/features.rs
new file mode 100644
index 0000000000..09743c0035
--- /dev/null
+++ b/support/texlab/src/features.rs
@@ -0,0 +1,272 @@
+mod build;
+#[cfg(feature = "completion")]
+mod completion;
+mod cursor;
+mod definition;
+mod folding;
+mod formatting;
+mod forward_search;
+mod highlight;
+mod hover;
+mod link;
+mod lsp_kinds;
+mod reference;
+mod rename;
+#[cfg(feature = "semantic")]
+mod semantic;
+mod symbol;
+
+use std::sync::Arc;
+
+use crate::{Document, ServerContext, Workspace, WorkspaceSubset};
+
+#[cfg(feature = "completion")]
+pub use self::completion::{complete, CompletionItemData, COMPLETION_LIMIT};
+#[cfg(feature = "semantic")]
+pub use self::semantic::{find_semantic_tokens_range, legend};
+pub use self::{
+ build::{build_document, BuildParams, BuildResult, BuildStatus},
+ definition::goto_definition,
+ folding::find_foldings,
+ formatting::format_source_code,
+ forward_search::{execute_forward_search, ForwardSearchResult, ForwardSearchStatus},
+ highlight::find_document_highlights,
+ hover::find_hover,
+ link::find_document_links,
+ reference::find_all_references,
+ rename::{prepare_rename_all, rename_all},
+ symbol::{find_document_symbols, find_workspace_symbols},
+};
+
+#[derive(Clone)]
+pub struct FeatureRequest<P> {
+ pub context: Arc<ServerContext>,
+ pub params: P,
+ pub workspace: Arc<dyn Workspace>,
+ pub subset: WorkspaceSubset,
+}
+
+impl<P> FeatureRequest<P> {
+ pub fn main_document(&self) -> &Document {
+ &self.subset.documents[0]
+ }
+}
+
+#[cfg(test)]
+mod testing {
+ use std::{path::PathBuf, sync::Arc};
+
+ use lsp_types::{
+ ClientCapabilities, ClientInfo, CompletionParams, DocumentFormattingParams,
+ DocumentHighlightParams, DocumentLinkParams, FoldingRangeParams, FormattingOptions,
+ GotoDefinitionParams, HoverParams, PartialResultParams, Position, ReferenceContext,
+ ReferenceParams, RenameParams, TextDocumentIdentifier, TextDocumentPositionParams,
+ WorkDoneProgressParams,
+ };
+ use typed_builder::TypedBuilder;
+
+ use crate::{
+ create_workspace_fast, distro::Resolver, DocumentLanguage, Options, ServerContext, Uri,
+ Workspace, WorkspaceSource,
+ };
+
+ use super::*;
+
+ #[derive(Debug, Clone, TypedBuilder)]
+ pub struct FeatureTester<'a> {
+ main: &'a str,
+
+ files: Vec<(&'a str, &'a str)>,
+
+ #[builder(default)]
+ line: u32,
+
+ #[builder(default)]
+ character: u32,
+
+ #[builder(default)]
+ new_name: &'a str,
+
+ #[builder(default)]
+ include_declaration: bool,
+
+ #[builder(default)]
+ client_capabilities: ClientCapabilities,
+
+ #[builder(default)]
+ client_info: Option<ClientInfo>,
+
+ #[builder(default)]
+ resolver: Resolver,
+
+ #[builder(default=std::env::temp_dir())]
+ current_directory: PathBuf,
+
+ #[builder(default, setter(strip_option))]
+ root_directory: Option<PathBuf>,
+
+ #[builder(default, setter(strip_option))]
+ aux_directory: Option<PathBuf>,
+ }
+
+ impl<'a> FeatureTester<'a> {
+ pub fn uri(&self, name: &str) -> Arc<Uri> {
+ let path = self.current_directory.join(name);
+ Arc::new(Uri::from_file_path(path).unwrap())
+ }
+
+ fn options(&self) -> Options {
+ let mut options = Options::default();
+ options.aux_directory = self.aux_directory.clone();
+ options.root_directory = self.root_directory.clone();
+ options
+ }
+
+ fn identifier(&self) -> TextDocumentIdentifier {
+ let uri = self.uri(&self.main);
+ TextDocumentIdentifier::new(uri.as_ref().clone().into())
+ }
+
+ fn context(&self) -> Arc<ServerContext> {
+ let cx = ServerContext::new(self.current_directory.clone());
+ *cx.client_capabilities.lock().unwrap() = self.client_capabilities.clone();
+ *cx.client_info.lock().unwrap() = self.client_info.clone();
+ *cx.options.write().unwrap() = self.options();
+ *cx.resolver.lock().unwrap() = self.resolver.clone();
+ Arc::new(cx)
+ }
+
+ fn workspace(&self, cx: Arc<ServerContext>) -> Arc<dyn Workspace> {
+ let workspace = create_workspace_fast(cx).unwrap();
+ for (name, source_code) in &self.files {
+ let uri = self.uri(name);
+ let path = uri.to_file_path().unwrap();
+ let language = DocumentLanguage::by_path(&path).expect("unknown document language");
+ workspace.open(
+ uri,
+ source_code.trim().to_string(),
+ language,
+ WorkspaceSource::Client,
+ );
+ }
+ Arc::new(workspace)
+ }
+
+ fn request<P>(&self, params: P) -> FeatureRequest<P> {
+ let cx = self.context();
+ let workspace = self.workspace(Arc::clone(&cx));
+ let subset = workspace.subset(self.uri(self.main)).unwrap();
+ FeatureRequest {
+ context: cx,
+ workspace,
+ subset,
+ params,
+ }
+ }
+
+ pub fn link(self) -> FeatureRequest<DocumentLinkParams> {
+ let text_document = self.identifier();
+ let params = DocumentLinkParams {
+ text_document,
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ partial_result_params: PartialResultParams::default(),
+ };
+ self.request(params)
+ }
+
+ pub fn folding(self) -> FeatureRequest<FoldingRangeParams> {
+ let text_document = self.identifier();
+ let params = FoldingRangeParams {
+ text_document,
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ partial_result_params: PartialResultParams::default(),
+ };
+ self.request(params)
+ }
+
+ pub fn reference(self) -> FeatureRequest<ReferenceParams> {
+ let params = ReferenceParams {
+ text_document_position: TextDocumentPositionParams::new(
+ self.identifier(),
+ Position::new(self.line, self.character),
+ ),
+ context: ReferenceContext {
+ include_declaration: self.include_declaration,
+ },
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ partial_result_params: PartialResultParams::default(),
+ };
+ self.request(params)
+ }
+
+ pub fn hover(self) -> FeatureRequest<HoverParams> {
+ let params = HoverParams {
+ text_document_position_params: TextDocumentPositionParams::new(
+ self.identifier(),
+ Position::new(self.line, self.character),
+ ),
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ };
+ self.request(params)
+ }
+
+ pub fn completion(self) -> FeatureRequest<CompletionParams> {
+ let params = CompletionParams {
+ text_document_position: TextDocumentPositionParams::new(
+ self.identifier(),
+ Position::new(self.line, self.character),
+ ),
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ partial_result_params: PartialResultParams::default(),
+ context: None,
+ };
+
+ self.request(params)
+ }
+
+ pub fn definition(self) -> FeatureRequest<GotoDefinitionParams> {
+ let params = GotoDefinitionParams {
+ text_document_position_params: TextDocumentPositionParams::new(
+ self.identifier(),
+ Position::new(self.line, self.character),
+ ),
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ partial_result_params: PartialResultParams::default(),
+ };
+ self.request(params)
+ }
+
+ pub fn rename(self) -> FeatureRequest<RenameParams> {
+ let params = RenameParams {
+ text_document_position: TextDocumentPositionParams::new(
+ self.identifier(),
+ Position::new(self.line, self.character),
+ ),
+ new_name: self.new_name.to_string(),
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ };
+ self.request(params)
+ }
+
+ pub fn formatting(self) -> FeatureRequest<DocumentFormattingParams> {
+ let params = DocumentFormattingParams {
+ text_document: self.identifier(),
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ options: FormattingOptions::default(),
+ };
+ self.request(params)
+ }
+
+ pub fn highlight(self) -> FeatureRequest<DocumentHighlightParams> {
+ let params = DocumentHighlightParams {
+ text_document_position_params: TextDocumentPositionParams::new(
+ self.identifier(),
+ Position::new(self.line, self.character),
+ ),
+ work_done_progress_params: WorkDoneProgressParams::default(),
+ partial_result_params: PartialResultParams::default(),
+ };
+ self.request(params)
+ }
+ }
+}