diff options
Diffstat (limited to 'support/texlab/src/rename/latex_label.rs')
-rw-r--r-- | support/texlab/src/rename/latex_label.rs | 181 |
1 files changed, 97 insertions, 84 deletions
diff --git a/support/texlab/src/rename/latex_label.rs b/support/texlab/src/rename/latex_label.rs index 1cf5e3ea9d..27e0f9b224 100644 --- a/support/texlab/src/rename/latex_label.rs +++ b/support/texlab/src/rename/latex_label.rs @@ -1,67 +1,64 @@ -use crate::range::RangeExt; -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::*; +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{ + Position, Range, RangeExt, RenameParams, TextDocumentPositionParams, TextEdit, + WorkspaceEdit, + }, + syntax::{Span, SyntaxNode}, + workspace::DocumentContent, +}; +use async_trait::async_trait; use std::collections::HashMap; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct LatexLabelPrepareRenameProvider; +#[async_trait] impl FeatureProvider for LatexLabelPrepareRenameProvider { type Params = TextDocumentPositionParams; type Output = Option<Range>; - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<TextDocumentPositionParams>, - ) -> Option<Range> { - find_label(&request.document().tree, request.params.position).map(Span::range) + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + let pos = req.params.position; + find_label(&req.current().content, pos).map(Span::range) } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] pub struct LatexLabelRenameProvider; +#[async_trait] impl FeatureProvider for LatexLabelRenameProvider { type Params = RenameParams; type Output = Option<WorkspaceEdit>; - #[boxed] - async fn execute<'a>( - &'a self, - request: &'a FeatureRequest<RenameParams>, - ) -> Option<WorkspaceEdit> { - let name = find_label( - &request.document().tree, - request.params.text_document_position.position, - )?; + async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output { + let pos = req.params.text_document_position.position; + let name = find_label(&req.current().content, pos)?; let mut changes = HashMap::new(); - for document in request.related_documents() { - if let SyntaxTree::Latex(tree) = &document.tree { - let edits = tree - .structure + for doc in req.related() { + if let DocumentContent::Latex(table) = &doc.content { + let edits = table .labels .iter() - .flat_map(LatexLabel::names) + .flat_map(|label| label.names(&table)) .filter(|label| label.text() == name.text) - .map(|label| TextEdit::new(label.range(), request.params.new_name.clone())) + .map(|label| TextEdit::new(label.range(), req.params.new_name.clone())) .collect(); - changes.insert(document.uri.clone().into(), edits); + changes.insert(doc.uri.clone().into(), edits); } } Some(WorkspaceEdit::new(changes)) } } -fn find_label(tree: &SyntaxTree, position: Position) -> Option<&Span> { - if let SyntaxTree::Latex(tree) = tree { - tree.structure +fn find_label(content: &DocumentContent, pos: Position) -> Option<&Span> { + if let DocumentContent::Latex(table) = content { + table .labels .iter() - .flat_map(LatexLabel::names) - .find(|label| label.range().contains(position)) + .flat_map(|label| label.names(&table)) + .find(|label| label.range().contains(pos)) .map(|label| &label.span) } else { None @@ -71,63 +68,79 @@ fn find_label(tree: &SyntaxTree, position: Position) -> Option<&Span> { #[cfg(test)] mod tests { use super::*; - use lsp_types::{Position, Range}; - - #[test] - fn test_label() { - let edit = test_feature( - LatexLabelRenameProvider, - FeatureSpec { - files: vec![ - FeatureSpec::file("foo.tex", "\\label{foo}\n\\include{bar}"), - FeatureSpec::file("bar.tex", "\\ref{foo}"), - FeatureSpec::file("baz.tex", "\\ref{foo}"), - ], - main_file: "foo.tex", - position: Position::new(0, 7), - new_name: "bar", - ..FeatureSpec::default() - }, - ); - let mut changes = HashMap::new(); - changes.insert( - FeatureSpec::uri("foo.tex"), + use crate::feature::FeatureTester; + use indoc::indoc; + + #[tokio::test] + async fn label() { + let actual_edit = FeatureTester::new() + .file( + "foo.tex", + indoc!( + r#" + \label{foo} + \include{bar} + "# + ), + ) + .file("bar.tex", r#"\ref{foo}"#) + .file("baz.tex", r#"\ref{foo}"#) + .main("foo.tex") + .position(0, 7) + .new_name("bar") + .test_rename(LatexLabelRenameProvider) + .await + .unwrap(); + + let mut expected_changes = HashMap::new(); + expected_changes.insert( + FeatureTester::uri("foo.tex").into(), vec![TextEdit::new(Range::new_simple(0, 7, 0, 10), "bar".into())], ); - changes.insert( - FeatureSpec::uri("bar.tex"), + expected_changes.insert( + FeatureTester::uri("bar.tex").into(), vec![TextEdit::new(Range::new_simple(0, 5, 0, 8), "bar".into())], ); - assert_eq!(edit, Some(WorkspaceEdit::new(changes))); + + assert_eq!(actual_edit, WorkspaceEdit::new(expected_changes)); } - #[test] - fn test_command_args() { - let edit = test_feature( - LatexLabelRenameProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\foo{bar}")], - main_file: "foo.tex", - position: Position::new(0, 5), - new_name: "baz", - ..FeatureSpec::default() - }, - ); - assert_eq!(edit, None); + #[tokio::test] + async fn command_args() { + let actual_edit = FeatureTester::new() + .file("main.tex", r#"\foo{bar}"#) + .main("main.tex") + .position(0, 5) + .new_name("baz") + .test_rename(LatexLabelRenameProvider) + .await; + + assert_eq!(actual_edit, None); } - #[test] - fn test_bibtex() { - let edit = test_feature( - LatexLabelRenameProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.bib", "")], - main_file: "foo.bib", - position: Position::new(0, 0), - new_name: "baz", - ..FeatureSpec::default() - }, - ); - assert_eq!(edit, None); + #[tokio::test] + async fn empty_latex_document() { + let actual_edit = FeatureTester::new() + .file("main.tex", "") + .main("main.tex") + .position(0, 0) + .new_name("") + .test_rename(LatexLabelRenameProvider) + .await; + + assert_eq!(actual_edit, None); + } + + #[tokio::test] + async fn empty_bibtex_document() { + let actual_edit = FeatureTester::new() + .file("main.bib", "") + .main("main.bib") + .position(0, 0) + .new_name("") + .test_rename(LatexLabelRenameProvider) + .await; + + assert_eq!(actual_edit, None); } } |