diff options
Diffstat (limited to 'support/texlab/src/features/rename')
-rw-r--r-- | support/texlab/src/features/rename/command.rs | 81 | ||||
-rw-r--r-- | support/texlab/src/features/rename/entry.rs | 131 | ||||
-rw-r--r-- | support/texlab/src/features/rename/label.rs | 122 |
3 files changed, 79 insertions, 255 deletions
diff --git a/support/texlab/src/features/rename/command.rs b/support/texlab/src/features/rename/command.rs index e0677f443e..aaa08f8cb4 100644 --- a/support/texlab/src/features/rename/command.rs +++ b/support/texlab/src/features/rename/command.rs @@ -1,88 +1,45 @@ -use std::collections::HashMap; +use std::sync::Arc; -use lsp_types::{Range, RenameParams, TextEdit, WorkspaceEdit}; +use lsp_types::RenameParams; use rowan::{TextRange, TextSize}; +use rustc_hash::FxHashMap; use crate::{ features::cursor::{CursorContext, HasPosition}, syntax::latex, - LineIndexExt, }; -pub fn prepare_command_rename<P: HasPosition>(context: &CursorContext<P>) -> Option<Range> { - Some( - context - .request - .main_document() - .line_index - .line_col_lsp_range(context.cursor.command_range(context.offset)?), - ) +use super::{Indel, RenameResult}; + +pub(super) fn prepare_command_rename<P: HasPosition>( + context: &CursorContext<P>, +) -> Option<TextRange> { + context.cursor.command_range(context.offset) } -pub fn rename_command(context: &CursorContext<RenameParams>) -> Option<WorkspaceEdit> { +pub(super) fn rename_command(context: &CursorContext<RenameParams>) -> Option<RenameResult> { prepare_command_rename(context)?; let name = context.cursor.as_latex()?.text(); - let mut changes = HashMap::new(); + let mut changes = FxHashMap::default(); for document in context.request.workspace.documents_by_uri.values() { if let Some(data) = document.data.as_latex() { - let edits = latex::SyntaxNode::new_root(data.green.clone()) + let root = latex::SyntaxNode::new_root(data.green.clone()); + let edits = root .descendants_with_tokens() .filter_map(|element| element.into_token()) .filter(|token| token.kind().is_command_name() && token.text() == name) .map(|token| { let range = token.text_range(); - let range = document.line_index.line_col_lsp_range(TextRange::new( - range.start() + TextSize::from(1), - range.end(), - )); - TextEdit::new(range, context.request.params.new_name.clone()) + Indel { + delete: TextRange::new(range.start() + TextSize::from(1), range.end()), + insert: context.request.params.new_name.clone(), + } }) .collect(); - changes.insert(document.uri.as_ref().clone(), edits); + changes.insert(Arc::clone(&document.uri), edits); } } - Some(WorkspaceEdit::new(changes)) -} - -#[cfg(test)] -mod tests { - use crate::{features::testing::FeatureTester, RangeExt}; - - use super::*; - - #[test] - fn test_command() { - let tester = FeatureTester::builder() - .files(vec![ - ("foo.tex", r#"\baz\include{bar.tex}"#), - ("bar.tex", r#"\baz"#), - ]) - .main("foo.tex") - .line(0) - .character(2) - .new_name("qux") - .build(); - - let uri1 = tester.uri("foo.tex"); - let uri2 = tester.uri("bar.tex"); - let req = tester.rename(); - - let context = CursorContext::new(req); - let actual_edit = rename_command(&context).unwrap(); - - let mut expected_changes = HashMap::new(); - expected_changes.insert( - uri1.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(0, 1, 0, 4), "qux".into())], - ); - expected_changes.insert( - uri2.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(0, 1, 0, 4), "qux".into())], - ); - let expected_edit = WorkspaceEdit::new(expected_changes); - - assert_eq!(actual_edit, expected_edit); - } + Some(RenameResult { changes }) } diff --git a/support/texlab/src/features/rename/entry.rs b/support/texlab/src/features/rename/entry.rs index 4861b63570..6eac79030b 100644 --- a/support/texlab/src/features/rename/entry.rs +++ b/support/texlab/src/features/rename/entry.rs @@ -1,7 +1,8 @@ -use std::collections::HashMap; +use std::sync::Arc; -use lsp_types::{Range, RenameParams, TextEdit, WorkspaceEdit}; -use rowan::ast::AstNode; +use lsp_types::RenameParams; +use rowan::{ast::AstNode, TextRange}; +use rustc_hash::FxHashMap; use crate::{ features::cursor::{CursorContext, HasPosition}, @@ -9,139 +10,63 @@ use crate::{ bibtex::{self, HasName}, latex, }, - DocumentData, LineIndexExt, + DocumentData, }; -pub fn prepare_entry_rename<P: HasPosition>(context: &CursorContext<P>) -> Option<Range> { +use super::{Indel, RenameResult}; + +pub(super) fn prepare_entry_rename<P: HasPosition>( + context: &CursorContext<P>, +) -> Option<TextRange> { let (_, range) = context .find_citation_key_word() .or_else(|| context.find_entry_key())?; - Some( - context - .request - .main_document() - .line_index - .line_col_lsp_range(range), - ) + Some(range) } -pub fn rename_entry(context: &CursorContext<RenameParams>) -> Option<WorkspaceEdit> { +pub(super) fn rename_entry(context: &CursorContext<RenameParams>) -> Option<RenameResult> { prepare_entry_rename(context)?; let (key_text, _) = context .find_citation_key_word() .or_else(|| context.find_entry_key())?; - let mut changes = HashMap::new(); + let mut changes = FxHashMap::default(); for document in context.request.workspace.documents_by_uri.values() { + let uri = Arc::clone(&document.uri); match &document.data { DocumentData::Latex(data) => { - let edits: Vec<_> = latex::SyntaxNode::new_root(data.green.clone()) + let root = latex::SyntaxNode::new_root(data.green.clone()); + let edits: Vec<_> = root .descendants() .filter_map(latex::Citation::cast) .filter_map(|citation| citation.key_list()) .flat_map(|keys| keys.keys()) .filter(|key| key.to_string() == key_text) - .map(|key| { - document - .line_index - .line_col_lsp_range(latex::small_range(&key)) + .map(|key| Indel { + delete: latex::small_range(&key), + insert: context.request.params.new_name.clone(), }) - .map(|range| TextEdit::new(range, context.request.params.new_name.clone())) .collect(); - changes.insert(document.uri.as_ref().clone(), edits); + changes.insert(uri, edits); } DocumentData::Bibtex(data) => { - let edits: Vec<_> = bibtex::SyntaxNode::new_root(data.green.clone()) + let root = bibtex::SyntaxNode::new_root(data.green.clone()); + let edits: Vec<_> = root .descendants() .filter_map(bibtex::Entry::cast) .filter_map(|entry| entry.name_token()) .filter(|key| key.text() == key_text) - .map(|key| document.line_index.line_col_lsp_range(key.text_range())) - .map(|range| TextEdit::new(range, context.request.params.new_name.clone())) + .map(|key| Indel { + delete: key.text_range(), + insert: context.request.params.new_name.clone(), + }) .collect(); - changes.insert(document.uri.as_ref().clone(), edits); + changes.insert(uri, edits); } DocumentData::BuildLog(_) => {} } } - Some(WorkspaceEdit::new(changes)) -} - -#[cfg(test)] -mod tests { - use lsp_types::TextEdit; - - use crate::{features::testing::FeatureTester, RangeExt}; - - use super::*; - - #[test] - fn test_entry() { - let tester = FeatureTester::builder() - .files(vec![ - ("main.bib", r#"@article{foo, bar = baz}"#), - ("main.tex", "\\addbibresource{main.bib}\n\\cite{foo}"), - ]) - .main("main.bib") - .line(0) - .character(9) - .new_name("qux") - .build(); - - let uri1 = tester.uri("main.bib"); - let uri2 = tester.uri("main.tex"); - let request = tester.rename(); - - let context = CursorContext::new(request); - let actual_edit = rename_entry(&context).unwrap(); - - let mut expected_changes = HashMap::new(); - expected_changes.insert( - uri1.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(0, 9, 0, 12), "qux".into())], - ); - expected_changes.insert( - uri2.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(1, 6, 1, 9), "qux".into())], - ); - let expected_edit = WorkspaceEdit::new(expected_changes); - - assert_eq!(actual_edit, expected_edit); - } - - #[test] - fn test_citation() { - let tester = FeatureTester::builder() - .files(vec![ - ("main.bib", r#"@article{foo, bar = baz}"#), - ("main.tex", "\\addbibresource{main.bib}\n\\cite{foo}"), - ]) - .main("main.tex") - .line(1) - .character(6) - .new_name("qux") - .build(); - - let uri1 = tester.uri("main.bib"); - let uri2 = tester.uri("main.tex"); - let request = tester.rename(); - - let context = CursorContext::new(request); - let actual_edit = rename_entry(&context).unwrap(); - - let mut expected_changes = HashMap::new(); - expected_changes.insert( - uri1.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(0, 9, 0, 12), "qux".into())], - ); - expected_changes.insert( - uri2.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(1, 6, 1, 9), "qux".into())], - ); - let expected_edit = WorkspaceEdit::new(expected_changes); - - assert_eq!(actual_edit, expected_edit); - } + Some(RenameResult { changes }) } diff --git a/support/texlab/src/features/rename/label.rs b/support/texlab/src/features/rename/label.rs index f24b86810b..30a99c3b36 100644 --- a/support/texlab/src/features/rename/label.rs +++ b/support/texlab/src/features/rename/label.rs @@ -1,31 +1,28 @@ -use std::collections::HashMap; +use std::sync::Arc; -use lsp_types::{Range, RenameParams, TextEdit, WorkspaceEdit}; -use rowan::ast::AstNode; +use lsp_types::RenameParams; +use rowan::{ast::AstNode, TextRange}; +use rustc_hash::FxHashMap; use crate::{ features::cursor::{CursorContext, HasPosition}, syntax::latex, - LineIndexExt, }; -pub fn prepare_label_rename<P: HasPosition>(context: &CursorContext<P>) -> Option<Range> { - let (_, range) = context.find_label_name_key()?; +use super::{Indel, RenameResult}; - Some( - context - .request - .main_document() - .line_index - .line_col_lsp_range(range), - ) +pub(super) fn prepare_label_rename<P: HasPosition>( + context: &CursorContext<P>, +) -> Option<TextRange> { + let (_, range) = context.find_label_name_key()?; + Some(range) } -pub fn rename_label(context: &CursorContext<RenameParams>) -> Option<WorkspaceEdit> { +pub(super) fn rename_label(context: &CursorContext<RenameParams>) -> Option<RenameResult> { prepare_label_rename(context)?; let (name_text, _) = context.find_label_name_key()?; - let mut changes = HashMap::new(); + let mut changes = FxHashMap::default(); for document in context.request.workspace.documents_by_uri.values() { if let Some(data) = document.data.as_latex() { let mut edits = Vec::new(); @@ -34,16 +31,12 @@ pub fn rename_label(context: &CursorContext<RenameParams>) -> Option<WorkspaceEd .and_then(|label| label.name()) .and_then(|name| name.key()) .filter(|name| name.to_string() == name_text) - .map(|name| { - document - .line_index - .line_col_lsp_range(latex::small_range(&name)) - }) + .map(|name| latex::small_range(&name)) { - edits.push(TextEdit::new( - range, - context.request.params.new_name.clone(), - )); + edits.push(Indel { + delete: range, + insert: context.request.params.new_name.clone(), + }); } latex::LabelReference::cast(node.clone()) @@ -51,16 +44,11 @@ pub fn rename_label(context: &CursorContext<RenameParams>) -> Option<WorkspaceEd .into_iter() .flat_map(|label| label.keys()) .filter(|name| name.to_string() == name_text) - .map(|name| { - document - .line_index - .line_col_lsp_range(latex::small_range(&name)) - }) - .for_each(|range| { - edits.push(TextEdit::new( - range, - context.request.params.new_name.clone(), - )); + .for_each(|name| { + edits.push(Indel { + delete: latex::small_range(&name), + insert: context.request.params.new_name.clone(), + }); }); if let Some(label) = latex::LabelReferenceRange::cast(node.clone()) { @@ -69,12 +57,10 @@ pub fn rename_label(context: &CursorContext<RenameParams>) -> Option<WorkspaceEd .and_then(|name| name.key()) .filter(|name| name.to_string() == name_text) { - edits.push(TextEdit::new( - document - .line_index - .line_col_lsp_range(latex::small_range(&name1)), - context.request.params.new_name.clone(), - )); + edits.push(Indel { + delete: latex::small_range(&name1), + insert: context.request.params.new_name.clone(), + }); } if let Some(name2) = label @@ -82,61 +68,17 @@ pub fn rename_label(context: &CursorContext<RenameParams>) -> Option<WorkspaceEd .and_then(|name| name.key()) .filter(|name| name.to_string() == name_text) { - edits.push(TextEdit::new( - document - .line_index - .line_col_lsp_range(latex::small_range(&name2)), - context.request.params.new_name.clone(), - )); + edits.push(Indel { + delete: latex::small_range(&name2), + insert: context.request.params.new_name.clone(), + }); } } } - changes.insert(document.uri.as_ref().clone(), edits); + changes.insert(Arc::clone(&document.uri), edits); } } - Some(WorkspaceEdit::new(changes)) -} - -#[cfg(test)] -mod tests { - use crate::{features::testing::FeatureTester, RangeExt}; - - use super::*; - - #[test] - fn test_label() { - let tester = FeatureTester::builder() - .files(vec![ - ("foo.tex", r#"\label{foo}\include{bar}"#), - ("bar.tex", r#"\ref{foo}"#), - ("baz.tex", r#"\ref{foo}"#), - ]) - .main("foo.tex") - .line(0) - .character(7) - .new_name("bar") - .build(); - - let uri1 = tester.uri("foo.tex"); - let uri2 = tester.uri("bar.tex"); - let request = tester.rename(); - - let context = CursorContext::new(request); - let actual_edit = rename_label(&context).unwrap(); - - let mut expected_changes = HashMap::new(); - expected_changes.insert( - uri1.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(0, 7, 0, 10), "bar".into())], - ); - expected_changes.insert( - uri2.as_ref().clone(), - vec![TextEdit::new(Range::new_simple(0, 5, 0, 8), "bar".into())], - ); - let expected_edit = WorkspaceEdit::new(expected_changes); - - assert_eq!(actual_edit, expected_edit); - } + Some(RenameResult { changes }) } |