From 745892fbddea56040139108277e728b53fd8fc11 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Thu, 28 May 2020 03:03:21 +0000 Subject: CTAN sync 202005280303 --- support/texlab/src/rename/latex_cmd.rs | 128 +++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 support/texlab/src/rename/latex_cmd.rs (limited to 'support/texlab/src/rename/latex_cmd.rs') diff --git a/support/texlab/src/rename/latex_cmd.rs b/support/texlab/src/rename/latex_cmd.rs new file mode 100644 index 0000000000..4770c4c485 --- /dev/null +++ b/support/texlab/src/rename/latex_cmd.rs @@ -0,0 +1,128 @@ +use crate::{ + feature::{FeatureProvider, FeatureRequest}, + protocol::{ + Position, Range, RenameParams, TextDocumentPositionParams, TextEdit, WorkspaceEdit, + }, + syntax::{latex, SyntaxNode}, + workspace::DocumentContent, +}; +use async_trait::async_trait; +use std::collections::HashMap; + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] +pub struct LatexCommandPrepareRenameProvider; + +#[async_trait] +impl FeatureProvider for LatexCommandPrepareRenameProvider { + type Params = TextDocumentPositionParams; + type Output = Option; + + async fn execute<'a>(&'a self, req: &'a FeatureRequest) -> Self::Output { + let pos = req.params.position; + find_command(&req.current().content, pos).map(SyntaxNode::range) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)] +pub struct LatexCommandRenameProvider; + +#[async_trait] +impl FeatureProvider for LatexCommandRenameProvider { + type Params = RenameParams; + type Output = Option; + + async fn execute<'a>(&'a self, req: &'a FeatureRequest) -> Self::Output { + let pos = req.params.text_document_position.position; + let cmd_name = find_command(&req.current().content, pos)?.name.text(); + let mut changes = HashMap::new(); + for doc in req.related() { + if let DocumentContent::Latex(table) = &doc.content { + let edits = table + .commands + .iter() + .filter_map(|node| table.as_command(*node)) + .filter(|cmd| cmd.name.text() == cmd_name) + .map(|cmd| { + TextEdit::new(cmd.name.range(), format!("\\{}", req.params.new_name)) + }) + .collect(); + changes.insert(doc.uri.clone().into(), edits); + } + } + Some(WorkspaceEdit::new(changes)) + } +} + +fn find_command(content: &DocumentContent, pos: Position) -> Option<&latex::Command> { + if let DocumentContent::Latex(table) = &content { + table.as_command(table.find_command_by_short_name_range(pos)?) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{feature::FeatureTester, protocol::RangeExt}; + use indoc::indoc; + + #[tokio::test] + async fn command() { + let actual_edit = FeatureTester::new() + .file( + "foo.tex", + indoc!( + r#" + \include{bar.tex} + \baz + "# + ), + ) + .file("bar.tex", r#"\baz"#) + .main("foo.tex") + .position(1, 2) + .new_name("qux") + .test_rename(LatexCommandRenameProvider) + .await + .unwrap(); + + let mut expected_changes = HashMap::new(); + expected_changes.insert( + FeatureTester::uri("foo.tex").into(), + vec![TextEdit::new(Range::new_simple(1, 0, 1, 4), "\\qux".into())], + ); + expected_changes.insert( + FeatureTester::uri("bar.tex").into(), + vec![TextEdit::new(Range::new_simple(0, 0, 0, 4), "\\qux".into())], + ); + + assert_eq!(actual_edit, WorkspaceEdit::new(expected_changes)); + } + + #[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(LatexCommandRenameProvider) + .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(LatexCommandRenameProvider) + .await; + + assert_eq!(actual_edit, None); + } +} -- cgit v1.2.3