summaryrefslogtreecommitdiff
path: root/support/texlab/src/features
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-06-13 03:03:42 +0000
committerNorbert Preining <norbert@preining.info>2022-06-13 03:03:42 +0000
commitef6d63ded56fb892decaa8ab41d7deebbe670473 (patch)
tree9c8eccf2e633fcfe0ad512e5428222ce0707971e /support/texlab/src/features
parent86d0c4c6729cfb43e13fb29790810c3cc2521806 (diff)
CTAN sync 202206130303
Diffstat (limited to 'support/texlab/src/features')
-rw-r--r--support/texlab/src/features/build.rs4
-rw-r--r--support/texlab/src/features/completion.rs5
-rw-r--r--support/texlab/src/features/completion/acronym_ref.rs120
-rw-r--r--support/texlab/src/features/completion/argument.rs120
-rw-r--r--support/texlab/src/features/completion/begin_command.rs63
-rw-r--r--support/texlab/src/features/completion/citation.rs209
-rw-r--r--support/texlab/src/features/completion/color.rs83
-rw-r--r--support/texlab/src/features/completion/color_model.rs123
-rw-r--r--support/texlab/src/features/completion/component_command.rs144
-rw-r--r--support/texlab/src/features/completion/component_environment.rs147
-rw-r--r--support/texlab/src/features/completion/entry_type.rs200
-rw-r--r--support/texlab/src/features/completion/field.rs158
-rw-r--r--support/texlab/src/features/completion/glossary_ref.rs83
-rw-r--r--support/texlab/src/features/completion/import.rs129
-rw-r--r--support/texlab/src/features/completion/include.rs75
-rw-r--r--support/texlab/src/features/completion/label.rs103
-rw-r--r--support/texlab/src/features/completion/theorem.rs106
-rw-r--r--support/texlab/src/features/completion/tikz_library.rs123
-rw-r--r--support/texlab/src/features/completion/user_command.rs63
-rw-r--r--support/texlab/src/features/completion/user_environment.rs66
-rw-r--r--support/texlab/src/features/definition.rs47
-rw-r--r--support/texlab/src/features/definition/command.rs128
-rw-r--r--support/texlab/src/features/definition/document.rs132
-rw-r--r--support/texlab/src/features/definition/entry.rs109
-rw-r--r--support/texlab/src/features/definition/label.rs77
-rw-r--r--support/texlab/src/features/definition/string.rs159
-rw-r--r--support/texlab/src/features/execute_command.rs103
-rw-r--r--support/texlab/src/features/folding.rs172
-rw-r--r--support/texlab/src/features/formatting/bibtex_internal.rs134
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__command.snap8
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__concatenation.snap8
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__insert_braces.snap8
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__multiple_entries.snap9
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__parens.snap7
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__preamble.snap6
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__string.snap6
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__trailing_comma.snap8
-rw-r--r--support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__wrap_long_lines.snap10
-rw-r--r--support/texlab/src/features/highlight/label.rs68
-rw-r--r--support/texlab/src/features/hover.rs33
-rw-r--r--support/texlab/src/features/hover/citation.rs119
-rw-r--r--support/texlab/src/features/hover/component.rs96
-rw-r--r--support/texlab/src/features/hover/entry_type.rs123
-rw-r--r--support/texlab/src/features/hover/field.rs115
-rw-r--r--support/texlab/src/features/hover/label.rs74
-rw-r--r--support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_cite.snap25
-rw-r--r--support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_entry.snap25
-rw-r--r--support/texlab/src/features/hover/string_ref.rs140
-rw-r--r--support/texlab/src/features/link.rs120
-rw-r--r--support/texlab/src/features/link/include.rs33
-rw-r--r--support/texlab/src/features/reference.rs34
-rw-r--r--support/texlab/src/features/reference/entry.rs186
-rw-r--r--support/texlab/src/features/reference/label.rs181
-rw-r--r--support/texlab/src/features/reference/string.rs186
-rw-r--r--support/texlab/src/features/rename.rs48
-rw-r--r--support/texlab/src/features/rename/command.rs81
-rw-r--r--support/texlab/src/features/rename/entry.rs131
-rw-r--r--support/texlab/src/features/rename/label.rs122
-rw-r--r--support/texlab/src/features/symbol.rs5
59 files changed, 640 insertions, 4560 deletions
diff --git a/support/texlab/src/features/build.rs b/support/texlab/src/features/build.rs
index 7821fac43d..ae465590fc 100644
--- a/support/texlab/src/features/build.rs
+++ b/support/texlab/src/features/build.rs
@@ -84,7 +84,7 @@ impl<'a> ProgressReporter<'a> {
impl<'a> Drop for ProgressReporter<'a> {
fn drop(&mut self) {
if self.supports_progress {
- let _ = client::send_notification::<Progress>(
+ drop(client::send_notification::<Progress>(
&self.lsp_sender,
ProgressParams {
token: NumberOrString::String(self.token.to_string()),
@@ -92,7 +92,7 @@ impl<'a> Drop for ProgressReporter<'a> {
WorkDoneProgressEnd { message: None },
)),
},
- );
+ ));
}
}
}
diff --git a/support/texlab/src/features/completion.rs b/support/texlab/src/features/completion.rs
index 3b5187f8eb..3009b437e7 100644
--- a/support/texlab/src/features/completion.rs
+++ b/support/texlab/src/features/completion.rs
@@ -71,6 +71,7 @@ use super::{
pub const COMPLETION_LIMIT: usize = 50;
+#[must_use]
pub fn complete(request: FeatureRequest<CompletionParams>) -> Option<CompletionList> {
let mut items = Vec::new();
let context = CursorContext::new(request);
@@ -172,7 +173,6 @@ fn score(context: &CursorContext<CompletionParams>, items: &mut Vec<InternalComp
token.text().into()
}
}
- Cursor::Latex(_) => "".into(),
Cursor::Bibtex(token)
if matches!(
token.kind(),
@@ -185,8 +185,7 @@ fn score(context: &CursorContext<CompletionParams>, items: &mut Vec<InternalComp
{
token.text().into()
}
- Cursor::Bibtex(_) => "".into(),
- Cursor::Nothing => "".into(),
+ Cursor::Latex(_) | Cursor::Bibtex(_) | Cursor::Nothing => "".into(),
};
let file_pattern = pattern.split('/').last().unwrap();
diff --git a/support/texlab/src/features/completion/acronym_ref.rs b/support/texlab/src/features/completion/acronym_ref.rs
index 2bb931fde4..84cbd8bc23 100644
--- a/support/texlab/src/features/completion/acronym_ref.rs
+++ b/support/texlab/src/features/completion/acronym_ref.rs
@@ -30,123 +30,3 @@ pub fn complete_acronyms<'a>(
}
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_acronyms(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_acronyms(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\acrshort{f}")])
- .main("main.tex")
- .line(1)
- .character(11)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_acronyms(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(87.into(), 88.into()));
- }
- }
-
- #[test]
- fn test_empty() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\acrshort{}")])
- .main("main.tex")
- .line(1)
- .character(10)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_acronyms(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(87.into(), 87.into()));
- }
- }
-
- #[test]
- fn test_after_group() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\acrshort{}")])
- .main("main.tex")
- .line(1)
- .character(11)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_acronyms(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_open_brace() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\acrshort{f")])
- .main("main.tex")
- .line(1)
- .character(11)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_acronyms(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(87.into(), 88.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/argument.rs b/support/texlab/src/features/completion/argument.rs
index ded16b359e..3ba28f9dea 100644
--- a/support/texlab/src/features/completion/argument.rs
+++ b/support/texlab/src/features/completion/argument.rs
@@ -65,123 +65,3 @@ pub fn complete_arguments<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_arguments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_arguments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", r#"\mathbb{}\usepackage{amsfonts}"#)])
- .main("main.tex")
- .line(0)
- .character(8)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_arguments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(8.into(), 8.into()));
- }
- }
-
- #[test]
- fn test_latex_word() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", r#"\mathbb{foo}\usepackage{amsfonts}"#)])
- .main("main.tex")
- .line(0)
- .character(8)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_arguments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(8.into(), 11.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\mathbb{ \\usepackage{amsfonts}")])
- .main("main.tex")
- .line(0)
- .character(8)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_arguments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(8.into(), 8.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace_second() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\mathbb{}{\\usepackage{amsfonts}")])
- .main("main.tex")
- .line(0)
- .character(10)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_arguments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-}
diff --git a/support/texlab/src/features/completion/begin_command.rs b/support/texlab/src/features/completion/begin_command.rs
index b9b4f06117..699b06c067 100644
--- a/support/texlab/src/features/completion/begin_command.rs
+++ b/support/texlab/src/features/completion/begin_command.rs
@@ -16,66 +16,3 @@ pub fn complete_begin_command(
));
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_begin_command(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_begin_command(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\")])
- .main("main.tex")
- .line(0)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_begin_command(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 1.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/citation.rs b/support/texlab/src/features/completion/citation.rs
index 92b21f0ffc..e6436689d7 100644
--- a/support/texlab/src/features/completion/citation.rs
+++ b/support/texlab/src/features/completion/citation.rs
@@ -42,7 +42,7 @@ pub fn complete_citations<'a>(
.children()
.filter_map(bibtex::Entry::cast)
{
- if let Some(item) = make_item(document, entry, range) {
+ if let Some(item) = make_item(document, &entry, range) {
items.push(item);
}
}
@@ -61,7 +61,9 @@ fn check_citation(context: &CursorContext<CompletionParams>) -> Option<()> {
fn check_acronym(context: &CursorContext<CompletionParams>) -> Option<()> {
let token = context.cursor.as_latex()?;
- let pair = token.ancestors().find_map(latex::KeyValuePair::cast)?;
+ let pair = token
+ .parent_ancestors()
+ .find_map(latex::KeyValuePair::cast)?;
if pair.key()?.to_string() != "cite" {
return None;
}
@@ -70,16 +72,18 @@ fn check_acronym(context: &CursorContext<CompletionParams>) -> Option<()> {
Some(())
}
-fn make_item(
- document: &Document,
- entry: bibtex::Entry,
+fn make_item<'a>(
+ document: &'a Document,
+ entry: &bibtex::Entry,
range: TextRange,
-) -> Option<InternalCompletionItem> {
+) -> Option<InternalCompletionItem<'a>> {
let key = entry.name_token()?.to_string();
let ty = LANGUAGE_DATA
.find_entry_type(&entry.type_token()?.text()[1..])
- .map(|ty| Structure::Entry(ty.category))
- .unwrap_or_else(|| Structure::Entry(BibtexEntryTypeCategory::Misc));
+ .map_or_else(
+ || Structure::Entry(BibtexEntryTypeCategory::Misc),
+ |ty| Structure::Entry(ty.category),
+ );
let entry_code = entry.syntax().text().to_string();
let text = format!(
@@ -88,8 +92,8 @@ fn make_item(
WHITESPACE_REGEX
.replace_all(
&entry_code
- .replace('{', "")
- .replace('}', "")
+ .replace('{', " ")
+ .replace('}', " ")
.replace(',', " ")
.replace('=', " "),
" "
@@ -109,188 +113,3 @@ fn make_item(
}
static WHITESPACE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("\\s+").unwrap());
-
-#[cfg(test)]
-mod tests {
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple() {
- let request = FeatureTester::builder()
- .files(vec![
- ("main.tex", "\\addbibresource{main.bib}\n\\cite{}"),
- ("main.bib", "@article{foo,}"),
- ])
- .main("main.tex")
- .line(1)
- .character(6)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(32.into(), 32.into()));
- }
- }
-
- #[test]
- fn test_latex_two_words() {
- let request = FeatureTester::builder()
- .files(vec![
- ("main.tex", "\\addbibresource{main.bib}\n\\cite{foo}"),
- ("main.bib", "@article{foo bar,}"),
- ])
- .main("main.tex")
- .line(1)
- .character(6)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(32.into(), 35.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace() {
- let request = FeatureTester::builder()
- .files(vec![
- ("main.tex", "\\addbibresource{main.bib}\n\\cite{"),
- ("main.bib", "@article{foo,}"),
- ])
- .main("main.tex")
- .line(1)
- .character(6)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(32.into(), 32.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace_second() {
- let request = FeatureTester::builder()
- .files(vec![
- ("main.tex", "\\addbibresource{main.bib}\n\\cite{foo,a"),
- ("main.bib", "@article{foo,}"),
- ])
- .main("main.tex")
- .line(1)
- .character(10)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(36.into(), 37.into()));
- }
- }
-
- #[test]
- fn test_latex_acronym() {
- let request = FeatureTester::builder()
- .files(vec![
- (
- "main.tex",
- "\\addbibresource{main.bib}\n\\DeclareAcronym{foo}{cite={\n}}",
- ),
- ("main.bib", "@article{foo,}"),
- ])
- .main("main.tex")
- .line(2)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(54.into(), 54.into()));
- }
- }
-
- #[test]
- fn test_latex_acronym_two_words() {
- let request = FeatureTester::builder()
- .files(vec![
- (
- "main.tex",
- "\\addbibresource{main.bib}\n\\DeclareAcronym{foo}{cite={\na b}}",
- ),
- ("main.bib", "@article{foo,}"),
- ])
- .main("main.tex")
- .line(2)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_citations(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(54.into(), 57.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/color.rs b/support/texlab/src/features/completion/color.rs
index 1d241d2c94..a9a385c3c9 100644
--- a/support/texlab/src/features/completion/color.rs
+++ b/support/texlab/src/features/completion/color.rs
@@ -21,86 +21,3 @@ pub fn complete_colors<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_colors(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_colors(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\color{}")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_colors(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 7.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\color{")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_colors(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 7.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/color_model.rs b/support/texlab/src/features/completion/color_model.rs
index 2190b690ad..cd582d0031 100644
--- a/support/texlab/src/features/completion/color_model.rs
+++ b/support/texlab/src/features/completion/color_model.rs
@@ -41,126 +41,3 @@ fn check_color_definition_set(context: &CursorContext<CompletionParams>) -> Opti
.filter(|model| model.syntax().text_range() == group.syntax().text_range())?;
Some(range)
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_color_models(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_color_models(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_definition_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\definecolor{foo}{}")])
- .main("main.tex")
- .line(0)
- .character(18)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_color_models(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(18.into(), 18.into()));
- }
- }
-
- #[test]
- fn test_definition_open_brace() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\definecolor{foo}{")])
- .main("main.tex")
- .line(0)
- .character(18)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_color_models(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(18.into(), 18.into()));
- }
- }
-
- #[test]
- fn test_definition_set_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\definecolorset{}")])
- .main("main.tex")
- .line(0)
- .character(16)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_color_models(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(16.into(), 16.into()));
- }
- }
-
- #[test]
- fn test_definition_set_open_brace() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\definecolorset{")])
- .main("main.tex")
- .line(0)
- .character(16)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_color_models(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(16.into(), 16.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/component_command.rs b/support/texlab/src/features/completion/component_command.rs
index b93a782512..097b28633f 100644
--- a/support/texlab/src/features/completion/component_command.rs
+++ b/support/texlab/src/features/completion/component_command.rs
@@ -26,147 +26,3 @@ pub fn complete_component_commands<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_commands(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_commands(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\")])
- .main("main.tex")
- .line(0)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_commands(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 1.into()));
- }
- }
-
- #[test]
- fn test_latex_simple_before() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_commands(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple_package() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\\n\\usepackage{lipsum}")])
- .main("main.tex")
- .line(0)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_commands(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in &actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 1.into()));
- }
-
- assert!(actual_items
- .iter()
- .any(|item| item.data.label() == "lipsum"));
- }
-
- #[test]
- fn test_latex_simple_existing() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\foo")])
- .main("main.tex")
- .line(0)
- .character(2)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_commands(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 4.into()));
- }
- }
-
- #[test]
- fn test_bibtex_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@a{b,c={\\ }}")])
- .main("main.bib")
- .line(0)
- .character(9)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_commands(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(9.into(), 10.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/component_environment.rs b/support/texlab/src/features/completion/component_environment.rs
index 057e98e491..a9478694bb 100644
--- a/support/texlab/src/features/completion/component_environment.rs
+++ b/support/texlab/src/features/completion/component_environment.rs
@@ -24,150 +24,3 @@ pub fn complete_component_environments<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_environments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_environments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\begin{")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 7.into()));
- }
- }
-
- #[test]
- fn test_simple_end() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\begin{a}\n\\end{")])
- .main("main.tex")
- .line(1)
- .character(5)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(15.into(), 15.into()));
- }
- }
-
- #[test]
- fn test_simple_class() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\begin{}\n\\documentclass{article}")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in &actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 7.into()));
- }
-
- assert!(actual_items
- .iter()
- .any(|item| item.data.label() == "theindex"));
- }
-
- #[test]
- fn test_simple_existing() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\begin{d}")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 8.into()));
- }
- }
-
- #[test]
- fn test_command_definition() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\newcommand{\\foo}{\\begin{\nd}")])
- .main("main.tex")
- .line(1)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_component_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(26.into(), 27.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/entry_type.rs b/support/texlab/src/features/completion/entry_type.rs
index 06180dd8cc..519737ed08 100644
--- a/support/texlab/src/features/completion/entry_type.rs
+++ b/support/texlab/src/features/completion/entry_type.rs
@@ -13,7 +13,7 @@ pub fn complete_entry_types<'a>(
.cursor
.as_bibtex()
.filter(|token| token.kind() == bibtex::TYPE)
- .map(|token| token.text_range())
+ .map(bibtex::SyntaxToken::text_range)
.filter(|range| range.start() != context.offset)
.map(|range| TextRange::new(range.start() + TextSize::from(1), range.end()))?;
@@ -25,201 +25,3 @@ pub fn complete_entry_types<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_at_empty() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@")])
- .main("main.bib")
- .line(0)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 1.into()));
- }
- }
-
- #[test]
- fn test_before_preamble() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@preamble")])
- .main("main.bib")
- .line(0)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 9.into()));
- }
- }
-
- #[test]
- fn test_before_string() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@string")])
- .main("main.bib")
- .line(0)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 7.into()));
- }
- }
-
- #[test]
- fn test_before_article() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article")])
- .main("main.bib")
- .line(0)
- .character(1)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 8.into()));
- }
- }
-
- #[test]
- fn test_after_preamble() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@preamble{")])
- .main("main.bib")
- .line(0)
- .character(9)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 9.into()));
- }
- }
-
- #[test]
- fn test_after_string() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@string{")])
- .main("main.bib")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 7.into()));
- }
- }
-
- #[test]
- fn test_complete_entry() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, author = {foo}}")])
- .main("main.bib")
- .line(0)
- .character(3)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 8.into()));
- }
- }
-
- #[test]
- fn test_complete_entry_field() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, author = {foo}}")])
- .main("main.bib")
- .line(0)
- .character(17)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_entry_types(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-}
diff --git a/support/texlab/src/features/completion/field.rs b/support/texlab/src/features/completion/field.rs
index 051b8d69b5..4f386ed1b1 100644
--- a/support/texlab/src/features/completion/field.rs
+++ b/support/texlab/src/features/completion/field.rs
@@ -37,161 +37,3 @@ pub fn complete_fields<'a>(
}
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_entry_open() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo,")])
- .main("main.bib")
- .line(0)
- .character(13)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(13.into(), 13.into()));
- }
- }
-
- #[test]
- fn test_empty_entry_closed() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo,}")])
- .main("main.bib")
- .line(0)
- .character(13)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(13.into(), 13.into()));
- }
- }
-
- #[test]
- fn test_entry_field_name() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, a")])
- .main("main.bib")
- .line(0)
- .character(15)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(14.into(), 15.into()));
- }
- }
-
- #[test]
- fn test_entry_field_value() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, author = bar}")])
- .main("main.bib")
- .line(0)
- .character(24)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_entry_two_fields_name_closed() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, author = bar, baz}")])
- .main("main.bib")
- .line(0)
- .character(29)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(28.into(), 31.into()));
- }
- }
-
- #[test]
- fn test_entry_two_fields_name_open() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, author = bar, baz")])
- .main("main.bib")
- .line(0)
- .character(29)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_fields(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(28.into(), 31.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/glossary_ref.rs b/support/texlab/src/features/completion/glossary_ref.rs
index 6805108f16..6223079fdf 100644
--- a/support/texlab/src/features/completion/glossary_ref.rs
+++ b/support/texlab/src/features/completion/glossary_ref.rs
@@ -40,86 +40,3 @@ pub fn complete_glossary_entries<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_glossary_entries(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_glossary_entries(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\gls{f}")])
- .main("main.tex")
- .line(1)
- .character(6)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_glossary_entries(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(82.into(), 83.into()));
- }
- }
-
- #[test]
- fn test_open_brace() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\gls{f")])
- .main("main.tex")
- .line(1)
- .character(6)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_glossary_entries(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(82.into(), 83.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/import.rs b/support/texlab/src/features/completion/import.rs
index 6e3a8deeaa..9cb35b68a7 100644
--- a/support/texlab/src/features/completion/import.rs
+++ b/support/texlab/src/features/completion/import.rs
@@ -38,8 +38,7 @@ pub fn complete_imports<'a>(
file_names.insert(file_name);
let stem = &file_name[0..file_name.len() - 4];
let data = factory(stem.into());
- let item = InternalCompletionItem::new(range, data);
- items.push(item);
+ items.push(InternalCompletionItem::new(range, data));
}
let resolver = &context.request.workspace.environment.resolver;
@@ -50,132 +49,8 @@ pub fn complete_imports<'a>(
{
let stem = &file_name[0..file_name.len() - 4];
let data = factory(stem.into());
- let item = InternalCompletionItem::new(range, data);
- items.push(item);
+ items.push(InternalCompletionItem::new(range, data));
}
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_imports(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_imports(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple_package() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\usepackage{}")])
- .main("main.tex")
- .line(0)
- .character(12)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_imports(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(12.into(), 12.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace_package() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\usepackage{ \\foo")])
- .main("main.tex")
- .line(0)
- .character(12)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_imports(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(12.into(), 12.into()));
- }
- }
-
- #[test]
- fn test_latex_simple_class() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\documentclass{}")])
- .main("main.tex")
- .line(0)
- .character(15)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_imports(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(15.into(), 15.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace_class() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\documentclass{ \\foo")])
- .main("main.tex")
- .line(0)
- .character(15)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_imports(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(15.into(), 15.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/include.rs b/support/texlab/src/features/completion/include.rs
index 7f6767b89f..d851aca820 100644
--- a/support/texlab/src/features/completion/include.rs
+++ b/support/texlab/src/features/completion/include.rs
@@ -101,19 +101,21 @@ fn current_dir(
.options
.root_directory
.as_ref()
- .map(|root_directory| {
- context
- .request
- .workspace
- .environment
- .current_directory
- .join(root_directory)
- })
- .unwrap_or_else(|| {
- let mut path = context.request.main_document().uri.to_file_path().unwrap();
- path.pop();
- path
- });
+ .map_or_else(
+ || {
+ let mut path = context.request.main_document().uri.to_file_path().unwrap();
+ path.pop();
+ path
+ },
+ |root_directory| {
+ context
+ .request
+ .workspace
+ .environment
+ .current_directory
+ .join(root_directory)
+ },
+ );
path = PathBuf::from(path.to_str()?.replace('\\', "/"));
if !path_text.is_empty() {
@@ -133,8 +135,8 @@ fn is_included(file: &Path, allowed_extensions: &[&str]) -> bool {
allowed_extensions.is_empty()
|| file
.extension()
- .and_then(|ext| ext.to_str())
- .map(|ext| ext.to_lowercase())
+ .and_then(std::ffi::OsStr::to_str)
+ .map(str::to_lowercase)
.map(|ext| allowed_extensions.contains(&ext.as_str()))
.unwrap_or_default()
}
@@ -142,51 +144,10 @@ fn is_included(file: &Path, allowed_extensions: &[&str]) -> bool {
fn remove_extension(path: &mut PathBuf) {
if let Some(stem) = path
.file_stem()
- .and_then(|stem| stem.to_str())
+ .and_then(std::ffi::OsStr::to_str)
.map(ToOwned::to_owned)
{
path.pop();
path.push(stem);
}
}
-
-#[cfg(test)]
-mod tests {
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_includes(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_includes(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-}
diff --git a/support/texlab/src/features/completion/label.rs b/support/texlab/src/features/completion/label.rs
index e6c02db565..b662f98c8a 100644
--- a/support/texlab/src/features/completion/label.rs
+++ b/support/texlab/src/features/completion/label.rs
@@ -99,106 +99,3 @@ fn find_reference_range(context: &CursorContext<CompletionParams>) -> Option<(Te
latex::LabelReferenceRange::cast(group.syntax().parent()?)?;
Some((range, false))
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_labels(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_labels(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\ref{}\\label{foo}")])
- .main("main.tex")
- .line(0)
- .character(5)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_labels(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(5.into(), 5.into()));
- }
- }
-
- #[test]
- fn test_simple_range() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\crefrange{\n\\label{foo}")])
- .main("main.tex")
- .line(0)
- .character(11)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_labels(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(11.into(), 11.into()));
- }
- }
-
- #[test]
- fn test_multi_word() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\ref{foo}\\label{foo bar}")])
- .main("main.tex")
- .line(0)
- .character(8)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_labels(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(5.into(), 8.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/theorem.rs b/support/texlab/src/features/completion/theorem.rs
index 0945d1df51..65b511f7ad 100644
--- a/support/texlab/src/features/completion/theorem.rs
+++ b/support/texlab/src/features/completion/theorem.rs
@@ -25,109 +25,3 @@ pub fn complete_theorem_environments<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_theorem_environments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_theorem_environments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\begin{ \\newtheorem{lemma}{Lemma}")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_theorem_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 7.into()));
- }
- }
-
- #[test]
- fn test_simple_end() {
- let request = FeatureTester::builder()
- .files(vec![(
- "main.tex",
- "\\newtheorem{lemma}{Lemma}\\begin{a}\n\\end{",
- )])
- .main("main.tex")
- .line(1)
- .character(5)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_theorem_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(40.into(), 40.into()));
- }
- }
-
- #[test]
- fn test_simple_existing() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\begin{d}\\newtheorem{lemma}{Lemma}")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_theorem_environments(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 8.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/tikz_library.rs b/support/texlab/src/features/completion/tikz_library.rs
index 62d66782a3..bf15695722 100644
--- a/support/texlab/src/features/completion/tikz_library.rs
+++ b/support/texlab/src/features/completion/tikz_library.rs
@@ -31,126 +31,3 @@ pub fn complete_tikz_libraries<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_tikz_libraries(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_tikz_libraries(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple_pgf() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\usepgflibrary{}")])
- .main("main.tex")
- .line(0)
- .character(15)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_tikz_libraries(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(15.into(), 15.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace_pgf() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\usepgflibrary{")])
- .main("main.tex")
- .line(0)
- .character(15)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_tikz_libraries(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(15.into(), 15.into()));
- }
- }
-
- #[test]
- fn test_latex_simple_tikz() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\usetikzlibrary{}")])
- .main("main.tex")
- .line(0)
- .character(16)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_tikz_libraries(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(16.into(), 16.into()));
- }
- }
-
- #[test]
- fn test_latex_open_brace_tikz() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\usetikzlibrary{")])
- .main("main.tex")
- .line(0)
- .character(16)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_tikz_libraries(&context, &mut actual_items);
-
- assert!(!actual_items.is_empty());
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(16.into(), 16.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/user_command.rs b/support/texlab/src/features/completion/user_command.rs
index 8355025098..8c4d593bee 100644
--- a/support/texlab/src/features/completion/user_command.rs
+++ b/support/texlab/src/features/completion/user_command.rs
@@ -30,66 +30,3 @@ pub fn complete_user_commands<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_user_commands(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_user_commands(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "\\foo\\bar")])
- .main("main.tex")
- .line(0)
- .character(4)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_user_commands(&context, &mut actual_items);
-
- assert_eq!(actual_items.len(), 1);
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(1.into(), 4.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/completion/user_environment.rs b/support/texlab/src/features/completion/user_environment.rs
index 3db135865e..91dd5a9ea2 100644
--- a/support/texlab/src/features/completion/user_environment.rs
+++ b/support/texlab/src/features/completion/user_environment.rs
@@ -29,69 +29,3 @@ pub fn complete_user_environments<'a>(
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use rowan::TextRange;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_user_environments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_user_environments(&context, &mut actual_items);
-
- assert!(actual_items.is_empty());
- }
-
- #[test]
- fn test_latex_simple() {
- let request = FeatureTester::builder()
- .files(vec![(
- "main.tex",
- "\\begin{foo}\\end{foo} \\begin{bar}\\end{bar}",
- )])
- .main("main.tex")
- .line(0)
- .character(7)
- .build()
- .completion();
-
- let context = CursorContext::new(request);
- let mut actual_items = Vec::new();
- complete_user_environments(&context, &mut actual_items);
-
- assert_eq!(actual_items.len(), 1);
- for item in actual_items {
- assert_eq!(item.range, TextRange::new(7.into(), 10.into()));
- }
- }
-}
diff --git a/support/texlab/src/features/definition.rs b/support/texlab/src/features/definition.rs
index b54a2be9f0..20da72a142 100644
--- a/support/texlab/src/features/definition.rs
+++ b/support/texlab/src/features/definition.rs
@@ -4,7 +4,12 @@ mod entry;
mod label;
mod string;
-use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse};
+use std::sync::Arc;
+
+use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, LocationLink, Url};
+use rowan::TextRange;
+
+use crate::LineIndexExt;
use self::{
command::goto_command_definition, document::goto_document_definition,
@@ -18,10 +23,46 @@ pub fn goto_definition(
) -> Option<GotoDefinitionResponse> {
let context = CursorContext::new(request);
log::debug!("[Definition] Cursor: {:?}", context.cursor);
- let links = goto_command_definition(&context)
+
+ let origin_document = context.request.main_document();
+ let links: Vec<_> = goto_command_definition(&context)
.or_else(|| goto_document_definition(&context))
.or_else(|| goto_entry_definition(&context))
.or_else(|| goto_label_definition(&context))
- .or_else(|| goto_string_definition(&context))?;
+ .or_else(|| goto_string_definition(&context))?
+ .into_iter()
+ .map(|result| {
+ let origin_selection_range = Some(
+ origin_document
+ .line_index
+ .line_col_lsp_range(result.origin_selection_range),
+ );
+
+ let target_document = &context.request.workspace.documents_by_uri[&result.target_uri];
+ let target_uri = result.target_uri.as_ref().clone();
+ let target_range = target_document
+ .line_index
+ .line_col_lsp_range(result.target_range);
+ let target_selection_range = target_document
+ .line_index
+ .line_col_lsp_range(result.target_selection_range);
+
+ LocationLink {
+ origin_selection_range,
+ target_uri,
+ target_range,
+ target_selection_range,
+ }
+ })
+ .collect();
+
Some(GotoDefinitionResponse::Link(links))
}
+
+#[derive(Debug, Clone)]
+struct DefinitionResult {
+ origin_selection_range: TextRange,
+ target_uri: Arc<Url>,
+ target_range: TextRange,
+ target_selection_range: TextRange,
+}
diff --git a/support/texlab/src/features/definition/command.rs b/support/texlab/src/features/definition/command.rs
index 72cd4b5909..599c792dfd 100644
--- a/support/texlab/src/features/definition/command.rs
+++ b/support/texlab/src/features/definition/command.rs
@@ -1,123 +1,47 @@
-use lsp_types::{GotoDefinitionParams, LocationLink};
+use std::sync::Arc;
+
+use lsp_types::GotoDefinitionParams;
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::latex, LineIndexExt};
+use crate::{features::cursor::CursorContext, syntax::latex};
-pub fn goto_command_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<LocationLink>> {
- let main_document = context.request.main_document();
+use super::DefinitionResult;
+pub(super) fn goto_command_definition(
+ context: &CursorContext<GotoDefinitionParams>,
+) -> Option<Vec<DefinitionResult>> {
let name = context
.cursor
.as_latex()
.filter(|token| token.kind().is_command_name())?;
- let origin_selection_range = main_document
- .line_index
- .line_col_lsp_range(name.text_range());
+ let origin_selection_range = name.text_range();
for document in context.request.workspace.documents_by_uri.values() {
if let Some(data) = document.data.as_latex() {
- for node in latex::SyntaxNode::new_root(data.green.clone()).descendants() {
- if let Some(defintion) = latex::CommandDefinition::cast(node).filter(|def| {
+ let root = latex::SyntaxNode::new_root(data.green.clone());
+
+ if let Some(result) = root
+ .descendants()
+ .filter_map(latex::CommandDefinition::cast)
+ .filter(|def| {
def.name()
.and_then(|name| name.command())
.map_or(false, |node| node.text() == name.text())
- }) {
- let target_selection_range = document
- .line_index
- .line_col_lsp_range(defintion.name()?.command()?.text_range());
-
- let target_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&defintion));
-
- return Some(vec![LocationLink {
- origin_selection_range: Some(origin_selection_range),
- target_uri: document.uri.as_ref().clone(),
- target_range,
- target_selection_range,
- }]);
- }
+ })
+ .find_map(|def| {
+ Some(DefinitionResult {
+ origin_selection_range,
+ target_uri: Arc::clone(&document.uri),
+ target_range: latex::small_range(&def),
+ target_selection_range: def.name()?.command()?.text_range(),
+ })
+ })
+ {
+ return Some(vec![result]);
}
}
}
None
}
-
-#[cfg(test)]
-mod tests {
- use indoc::indoc;
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
-
- let actual_links = goto_command_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_command_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_command_definition() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.tex",
- indoc! {
- r#"
- \DeclareMathOperator{\foo}{foo}
- \foo
- "#
- },
- )])
- .main("main.tex")
- .line(1)
- .character(2)
- .build();
- let target_uri = tester.uri("main.tex").as_ref().clone();
-
- let request = tester.definition();
- let context = CursorContext::new(request);
- let actual_links = goto_command_definition(&context).unwrap();
-
- let expected_links = vec![LocationLink {
- origin_selection_range: Some(Range::new_simple(1, 0, 1, 4)),
- target_uri,
- target_range: Range::new_simple(0, 0, 0, 31),
- target_selection_range: Range::new_simple(0, 21, 0, 25),
- }];
-
- assert_eq!(actual_links, expected_links);
- }
-}
diff --git a/support/texlab/src/features/definition/document.rs b/support/texlab/src/features/definition/document.rs
index 2a93232cd7..1c09bbc88d 100644
--- a/support/texlab/src/features/definition/document.rs
+++ b/support/texlab/src/features/definition/document.rs
@@ -1,108 +1,40 @@
-use lsp_types::{GotoDefinitionParams, LocationLink, Range};
+use std::sync::Arc;
-use crate::{features::cursor::CursorContext, LineIndexExt, RangeExt};
+use lsp_types::GotoDefinitionParams;
+use rowan::TextRange;
-pub fn goto_document_definition(
+use crate::features::cursor::CursorContext;
+
+use super::DefinitionResult;
+
+pub(super) fn goto_document_definition(
context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<LocationLink>> {
- let main_document = context.request.main_document();
- if let Some(data) = main_document.data.as_latex() {
- for include in data
- .extras
- .explicit_links
- .iter()
- .filter(|link| link.stem_range.contains_inclusive(context.offset))
- {
- for target in &include.targets {
- if context
- .request
- .workspace
- .documents_by_uri
- .values()
- .any(|document| document.uri.as_ref() == target.as_ref())
- {
- return Some(vec![LocationLink {
- origin_selection_range: Some(
- main_document
- .line_index
- .line_col_lsp_range(include.stem_range),
- ),
- target_uri: target.as_ref().clone(),
- target_range: Range::new_simple(0, 0, 0, 0),
- target_selection_range: Range::new_simple(0, 0, 0, 0),
- }]);
- }
+) -> Option<Vec<DefinitionResult>> {
+ let data = context.request.main_document().data.as_latex()?;
+
+ for include in data
+ .extras
+ .explicit_links
+ .iter()
+ .filter(|link| link.stem_range.contains_inclusive(context.offset))
+ {
+ for target in &include.targets {
+ if context
+ .request
+ .workspace
+ .documents_by_uri
+ .values()
+ .any(|document| document.uri.as_ref() == target.as_ref())
+ {
+ return Some(vec![DefinitionResult {
+ origin_selection_range: include.stem_range,
+ target_uri: Arc::clone(target),
+ target_range: TextRange::default(),
+ target_selection_range: TextRange::default(),
+ }]);
}
}
}
- None
-}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_document_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_document_definition(&context);
-
- assert!(actual_links.is_none());
- }
- #[test]
- fn test_simple() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.tex", r#"\addbibresource{baz.bib}"#),
- ("bar.bib", r#"@article{foo, bar = {baz}}"#),
- ("baz.bib", r#"@article{foo, bar = {baz}}"#),
- ])
- .main("foo.tex")
- .line(0)
- .character(18)
- .build();
- let target_uri = tester.uri("baz.bib").as_ref().clone();
-
- let request = tester.definition();
- let context = CursorContext::new(request);
- let actual_links = goto_document_definition(&context).unwrap();
-
- let expected_links = vec![LocationLink {
- origin_selection_range: Some(Range::new_simple(0, 16, 0, 23)),
- target_uri,
- target_range: Range::new_simple(0, 0, 0, 0),
- target_selection_range: Range::new_simple(0, 0, 0, 0),
- }];
-
- assert_eq!(actual_links, expected_links);
- }
+ None
}
diff --git a/support/texlab/src/features/definition/entry.rs b/support/texlab/src/features/definition/entry.rs
index a1ae28705d..1dcd983af1 100644
--- a/support/texlab/src/features/definition/entry.rs
+++ b/support/texlab/src/features/definition/entry.rs
@@ -1,4 +1,6 @@
-use lsp_types::{GotoDefinitionParams, LocationLink};
+use std::sync::Arc;
+
+use lsp_types::GotoDefinitionParams;
use rowan::ast::AstNode;
use crate::{
@@ -7,14 +9,13 @@ use crate::{
bibtex::{self, HasName},
latex,
},
- LineIndexExt,
};
-pub fn goto_entry_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<LocationLink>> {
- let main_document = context.request.main_document();
+use super::DefinitionResult;
+pub(super) fn goto_entry_definition(
+ context: &CursorContext<GotoDefinitionParams>,
+) -> Option<Vec<DefinitionResult>> {
let word = context
.cursor
.as_latex()
@@ -24,9 +25,7 @@ pub fn goto_entry_definition(
latex::Citation::cast(key.syntax().parent()?.parent()?)?;
- let origin_selection_range = main_document
- .line_index
- .line_col_lsp_range(latex::small_range(&key));
+ let origin_selection_range = latex::small_range(&key);
for document in context.request.workspace.documents_by_uri.values() {
if let Some(data) = document.data.as_bibtex() {
@@ -35,15 +34,11 @@ pub fn goto_entry_definition(
.filter_map(bibtex::Entry::cast)
{
if let Some(key) = entry.name_token().filter(|k| k.text() == word.text()) {
- return Some(vec![LocationLink {
- origin_selection_range: Some(origin_selection_range),
- target_uri: document.uri.as_ref().clone(),
- target_selection_range: document
- .line_index
- .line_col_lsp_range(key.text_range()),
- target_range: document
- .line_index
- .line_col_lsp_range(entry.syntax().text_range()),
+ return Some(vec![DefinitionResult {
+ origin_selection_range,
+ target_uri: Arc::clone(&document.uri),
+ target_selection_range: key.text_range(),
+ target_range: entry.syntax().text_range(),
}]);
}
}
@@ -52,81 +47,3 @@ pub fn goto_entry_definition(
None
}
-
-#[cfg(test)]
-mod tests {
- use indoc::indoc;
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_entry_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_entry_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_simple() {
- let tester = FeatureTester::builder()
- .files(vec![
- (
- "foo.tex",
- indoc!(
- r#"
- \addbibresource{baz.bib}
- \cite{foo}
- "#
- ),
- ),
- ("bar.bib", r#"@article{foo, bar = {baz}}"#),
- ("baz.bib", r#"@article{foo, bar = {baz}}"#),
- ])
- .main("foo.tex")
- .line(1)
- .character(6)
- .build();
- let target_uri = tester.uri("baz.bib").as_ref().clone();
-
- let request = tester.definition();
- let context = CursorContext::new(request);
- let actual_links = goto_entry_definition(&context).unwrap();
-
- let expected_links = vec![LocationLink {
- origin_selection_range: Some(Range::new_simple(1, 6, 1, 9)),
- target_uri,
- target_range: Range::new_simple(0, 0, 0, 26),
- target_selection_range: Range::new_simple(0, 9, 0, 12),
- }];
-
- assert_eq!(actual_links, expected_links);
- }
-}
diff --git a/support/texlab/src/features/definition/label.rs b/support/texlab/src/features/definition/label.rs
index e5ccd49937..867e8a1076 100644
--- a/support/texlab/src/features/definition/label.rs
+++ b/support/texlab/src/features/definition/label.rs
@@ -1,39 +1,33 @@
-use lsp_types::{GotoDefinitionParams, LocationLink};
+use std::sync::Arc;
-use crate::{
- features::cursor::CursorContext, find_label_definition, render_label, syntax::latex,
- LineIndexExt,
-};
+use lsp_types::GotoDefinitionParams;
-pub fn goto_label_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<LocationLink>> {
- let main_document = context.request.main_document();
+use crate::{features::cursor::CursorContext, find_label_definition, render_label, syntax::latex};
+
+use super::DefinitionResult;
- let (name_text, name_range) = context
+pub(super) fn goto_label_definition(
+ context: &CursorContext<GotoDefinitionParams>,
+) -> Option<Vec<DefinitionResult>> {
+ let (name_text, origin_selection_range) = context
.find_label_name_key()
.or_else(|| context.find_label_name_command())?;
- let origin_selection_range = main_document.line_index.line_col_lsp_range(name_range);
-
for document in context.request.workspace.documents_by_uri.values() {
if let Some(data) = document.data.as_latex() {
- if let Some(definition) =
- find_label_definition(&latex::SyntaxNode::new_root(data.green.clone()), &name_text)
- {
+ let root = latex::SyntaxNode::new_root(data.green.clone());
+ if let Some(definition) = find_label_definition(&root, &name_text) {
let target_selection_range = latex::small_range(&definition.name()?.key()?);
let target_range =
render_label(&context.request.workspace, &name_text, Some(definition))
.map(|label| label.range)
.unwrap_or(target_selection_range);
- return Some(vec![LocationLink {
- origin_selection_range: Some(origin_selection_range),
- target_uri: document.uri.as_ref().clone(),
- target_range: document.line_index.line_col_lsp_range(target_range),
- target_selection_range: document
- .line_index
- .line_col_lsp_range(target_selection_range),
+ return Some(vec![DefinitionResult {
+ origin_selection_range,
+ target_uri: Arc::clone(&document.uri),
+ target_range,
+ target_selection_range,
}]);
}
}
@@ -41,42 +35,3 @@ pub fn goto_label_definition(
None
}
-
-#[cfg(test)]
-mod tests {
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_label_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_label_definition(&context);
-
- assert!(actual_links.is_none());
- }
-}
diff --git a/support/texlab/src/features/definition/string.rs b/support/texlab/src/features/definition/string.rs
index 09e00fdf92..c774e24e1d 100644
--- a/support/texlab/src/features/definition/string.rs
+++ b/support/texlab/src/features/definition/string.rs
@@ -1,15 +1,18 @@
-use lsp_types::{GotoDefinitionParams, LocationLink};
+use std::sync::Arc;
+
+use lsp_types::GotoDefinitionParams;
use rowan::ast::AstNode;
use crate::{
features::cursor::CursorContext,
syntax::bibtex::{self, HasName},
- LineIndexExt,
};
-pub fn goto_string_definition(
+use super::DefinitionResult;
+
+pub(super) fn goto_string_definition(
context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<LocationLink>> {
+) -> Option<Vec<DefinitionResult>> {
let main_document = context.request.main_document();
let data = main_document.data.as_bibtex()?;
@@ -20,157 +23,21 @@ pub fn goto_string_definition(
bibtex::Value::cast(key.parent()?)?;
- let origin_selection_range = main_document
- .line_index
- .line_col_lsp_range(key.text_range());
+ let origin_selection_range = key.text_range();
for string in bibtex::SyntaxNode::new_root(data.green.clone())
.children()
.filter_map(bibtex::StringDef::cast)
{
if let Some(string_name) = string.name_token().filter(|k| k.text() == key.text()) {
- return Some(vec![LocationLink {
- origin_selection_range: Some(origin_selection_range),
- target_uri: main_document.uri.as_ref().clone(),
- target_selection_range: main_document
- .line_index
- .line_col_lsp_range(string_name.text_range()),
- target_range: main_document
- .line_index
- .line_col_lsp_range(string.syntax().text_range()),
+ return Some(vec![DefinitionResult {
+ origin_selection_range,
+ target_uri: Arc::clone(&main_document.uri),
+ target_selection_range: string_name.text_range(),
+ target_range: string.syntax().text_range(),
}]);
}
}
None
}
-
-#[cfg(test)]
-mod tests {
- use indoc::indoc;
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_string_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .definition();
-
- let context = CursorContext::new(request);
- let actual_links = goto_string_definition(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_simple() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! {
- r#"
- @string{foo = {bar}}
- @article{bar, author = foo}
- "#
- },
- )])
- .main("main.bib")
- .line(1)
- .character(24)
- .build();
- let target_uri = tester.uri("main.bib").as_ref().clone();
-
- let request = tester.definition();
- let context = CursorContext::new(request);
- let actual_links = goto_string_definition(&context).unwrap();
-
- let expected_links = vec![LocationLink {
- origin_selection_range: Some(Range::new_simple(1, 23, 1, 26)),
- target_uri,
- target_range: Range::new_simple(0, 0, 0, 20),
- target_selection_range: Range::new_simple(0, 8, 0, 11),
- }];
-
- assert_eq!(actual_links, expected_links);
- }
-
- #[test]
- fn test_concat() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! {
- r#"
- @string{foo = {bar}}
- @article{bar, author = foo # "bar"}
- "#
- },
- )])
- .main("main.bib")
- .line(1)
- .character(24)
- .build();
- let target_uri = tester.uri("main.bib").as_ref().clone();
-
- let request = tester.definition();
- let context = CursorContext::new(request);
- let actual_links = goto_string_definition(&context).unwrap();
-
- let expected_links = vec![LocationLink {
- origin_selection_range: Some(Range::new_simple(1, 23, 1, 26)),
- target_uri,
- target_range: Range::new_simple(0, 0, 0, 20),
- target_selection_range: Range::new_simple(0, 8, 0, 11),
- }];
-
- assert_eq!(actual_links, expected_links);
- }
-
- #[test]
- fn test_field() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! {
- r#"
- @string{foo = {bar}}
- @article{bar, author = foo}
- "#
- },
- )])
- .main("main.bib")
- .line(1)
- .character(18)
- .build();
-
- let request = tester.definition();
- let context = CursorContext::new(request);
- let actual_links = goto_string_definition(&context);
-
- assert!(actual_links.is_none());
- }
-}
diff --git a/support/texlab/src/features/execute_command.rs b/support/texlab/src/features/execute_command.rs
new file mode 100644
index 0000000000..b1b89d4f50
--- /dev/null
+++ b/support/texlab/src/features/execute_command.rs
@@ -0,0 +1,103 @@
+use std::{path::PathBuf, process::Stdio, sync::Arc};
+
+use anyhow::Result;
+use lsp_types::{TextDocumentIdentifier, Url};
+
+use crate::Workspace;
+
+pub fn execute_command(
+ workspace: &Workspace,
+ name: &str,
+ args: Vec<serde_json::Value>,
+) -> Result<()> {
+ match name {
+ "texlab.cleanAuxiliary" => {
+ let params = args
+ .into_iter()
+ .next()
+ .ok_or_else(|| anyhow::anyhow!("texlab.cleanAuxiliary requires one argument"))?;
+
+ clean_output_files(workspace, CleanOptions::Auxiliary, params)?;
+ }
+ "texlab.cleanArtifacts" => {
+ let params = args
+ .into_iter()
+ .next()
+ .ok_or_else(|| anyhow::anyhow!("texlab.cleanArtifacts requires one argument"))?;
+
+ clean_output_files(workspace, CleanOptions::Artifacts, params)?;
+ }
+ _ => anyhow::bail!("Unknown command: {}", name),
+ }
+
+ Ok(())
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+enum CleanOptions {
+ Auxiliary,
+ Artifacts,
+}
+
+fn clean_output_files(
+ workspace: &Workspace,
+ options: CleanOptions,
+ params: serde_json::Value,
+) -> Result<()> {
+ let params: TextDocumentIdentifier = serde_json::from_value(params)?;
+
+ let uri = workspace
+ .find_parent(&params.uri)
+ .map(|document| document.uri)
+ .unwrap_or_else(|| Arc::new(params.uri));
+
+ if let Some(cx) = BuildContext::find(workspace, &uri) {
+ let flag = match options {
+ CleanOptions::Auxiliary => "-c",
+ CleanOptions::Artifacts => "-C",
+ };
+
+ std::process::Command::new("latexmk")
+ .arg(format!("-outdir={}", cx.output_dir.to_string_lossy()))
+ .arg(flag)
+ .arg(cx.input_file)
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()?;
+ }
+
+ Ok(())
+}
+
+struct BuildContext {
+ input_file: PathBuf,
+ output_dir: PathBuf,
+}
+
+impl BuildContext {
+ pub fn find(workspace: &Workspace, uri: &Url) -> Option<Self> {
+ if uri.scheme() != "file" {
+ return None;
+ }
+
+ let input_file = uri.to_file_path().ok()?;
+ let options = &workspace.environment.options;
+ let current_dir = &workspace.environment.current_directory;
+ let output_dir = match (
+ options.root_directory.as_ref(),
+ options.aux_directory.as_ref(),
+ ) {
+ (_, Some(aux_dir)) => current_dir.join(aux_dir),
+ (Some(root_dir), None) => current_dir.join(root_dir),
+ (None, None) => input_file.parent()?.to_path_buf(),
+ };
+
+ log::info!("Output = {:#?}", output_dir);
+
+ Some(Self {
+ input_file,
+ output_dir,
+ })
+ }
+}
diff --git a/support/texlab/src/features/folding.rs b/support/texlab/src/features/folding.rs
index cd1a48f1a8..71fb0bee6f 100644
--- a/support/texlab/src/features/folding.rs
+++ b/support/texlab/src/features/folding.rs
@@ -55,175 +55,3 @@ fn create_range(range: Range) -> FoldingRange {
kind: Some(FoldingRangeKind::Region),
}
}
-
-#[cfg(test)]
-mod tests {
- use indoc::indoc;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .build()
- .folding();
-
- let actual_foldings = find_foldings(request);
- assert!(actual_foldings.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .build()
- .folding();
-
- let actual_foldings = find_foldings(request);
- assert!(actual_foldings.is_empty());
- }
-
- #[test]
- fn test_latex() {
- let req = FeatureTester::builder()
- .files(vec![(
- "main.tex",
- indoc! {r#"
- \begin{document}
- \section{Foo}
- foo
- \subsection{Bar}
- bar
- \section{Baz}
- baz
- \section{Qux}
- \end{document}"# },
- )])
- .main("main.tex")
- .build()
- .folding();
-
- let mut actual_foldings = find_foldings(req);
- actual_foldings.sort_by_key(|folding| (folding.start_line, folding.start_character));
-
- assert_eq!(actual_foldings.len(), 5);
- assert_eq!(
- actual_foldings[0],
- FoldingRange {
- start_line: 0,
- start_character: Some(0),
- end_line: 8,
- end_character: Some(14),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- assert_eq!(
- actual_foldings[1],
- FoldingRange {
- start_line: 1,
- start_character: Some(4),
- end_line: 4,
- end_character: Some(7),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- assert_eq!(
- actual_foldings[2],
- FoldingRange {
- start_line: 3,
- start_character: Some(4),
- end_line: 4,
- end_character: Some(7),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- assert_eq!(
- actual_foldings[3],
- FoldingRange {
- start_line: 5,
- start_character: Some(4),
- end_line: 6,
- end_character: Some(7),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- assert_eq!(
- actual_foldings[4],
- FoldingRange {
- start_line: 7,
- start_character: Some(4),
- end_line: 7,
- end_character: Some(17),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- }
-
- #[test]
- fn test_bibtex() {
- let request = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! {r#"
- some junk
- here
-
- @article{foo,
- author = {bar},
- title = {baz}
- }
-
- @string{foo = "bar"}
-
- @comment{foo,
- author = {bar},
- title = {baz}
- }
-
- @preamble{"foo"}"# },
- )])
- .main("main.bib")
- .build()
- .folding();
-
- let mut actual_foldings = find_foldings(request);
- actual_foldings.sort_by_key(|folding| (folding.start_line, folding.start_character));
-
- assert_eq!(actual_foldings.len(), 3);
- assert_eq!(
- actual_foldings[0],
- FoldingRange {
- start_line: 3,
- start_character: Some(0),
- end_line: 6,
- end_character: Some(1),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- assert_eq!(
- actual_foldings[1],
- FoldingRange {
- start_line: 8,
- start_character: Some(0),
- end_line: 8,
- end_character: Some(20),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- assert_eq!(
- actual_foldings[2],
- FoldingRange {
- start_line: 15,
- start_character: Some(0),
- end_line: 15,
- end_character: Some(16),
- kind: Some(FoldingRangeKind::Region)
- }
- );
- }
-}
diff --git a/support/texlab/src/features/formatting/bibtex_internal.rs b/support/texlab/src/features/formatting/bibtex_internal.rs
index 58aaf0635d..2dcc507be9 100644
--- a/support/texlab/src/features/formatting/bibtex_internal.rs
+++ b/support/texlab/src/features/formatting/bibtex_internal.rs
@@ -213,137 +213,3 @@ impl<'a> Formatter<'a> {
}
}
}
-
-#[cfg(test)]
-mod tests {
- use insta::{assert_debug_snapshot, assert_display_snapshot};
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_wrap_long_lines() {
- let request = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- "@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}",
- )])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-
- #[test]
- fn test_multiple_entries() {
- let request = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- "@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}\n\n@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}",
- )])
- .main("main.bib")
- .build()
- .formatting();
-
- let mut edits = format_bibtex_internal(&request).unwrap();
- let edit2 = edits.pop().unwrap();
- let edit1 = edits.pop().unwrap();
-
- assert_debug_snapshot!((edit1.new_text, edit2.new_text));
- }
-
- #[test]
- fn test_trailing_comma() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, bar = baz}")])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-
- #[test]
- fn test_insert_braces() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, bar = baz,")])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-
- #[test]
- fn test_command() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, bar = \"\\baz\",}")])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-
- #[test]
- fn test_concatenation() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article{foo, bar = \"baz\" # \"qux\"}")])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-
- #[test]
- fn test_parens() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@article(foo,)")])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-
- #[test]
- fn test_string() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@string{foo=\"bar\"}")])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-
- #[test]
- fn test_preamble() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "@preamble{\n\"foo bar baz\"}")])
- .main("main.bib")
- .build()
- .formatting();
-
- let edit = format_bibtex_internal(&request).unwrap().pop().unwrap();
-
- assert_display_snapshot!(edit.new_text);
- }
-}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__command.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__command.snap
deleted file mode 100644
index 792e7be277..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__command.snap
+++ /dev/null
@@ -1,8 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@article{foo,
- bar = "\baz",
-}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__concatenation.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__concatenation.snap
deleted file mode 100644
index 8cd51dfa92..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__concatenation.snap
+++ /dev/null
@@ -1,8 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@article{foo,
- bar = "baz" # "qux",
-}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__insert_braces.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__insert_braces.snap
deleted file mode 100644
index 3be9b15e9d..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__insert_braces.snap
+++ /dev/null
@@ -1,8 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@article{foo,
- bar = baz,
-}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__multiple_entries.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__multiple_entries.snap
deleted file mode 100644
index 636b4b665c..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__multiple_entries.snap
+++ /dev/null
@@ -1,9 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: "(edit1.new_text, edit2.new_text)"
-
----
-(
- "@article{foo,\n\tbar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum\n\t dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,\n\t consectetur adipiscing elit.},\n}",
- "@article{foo,\n\tbar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum\n\t dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,\n\t consectetur adipiscing elit.},\n}",
-)
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__parens.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__parens.snap
deleted file mode 100644
index 5aff28cb5f..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__parens.snap
+++ /dev/null
@@ -1,7 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@article{foo,
-}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__preamble.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__preamble.snap
deleted file mode 100644
index 663569eb5b..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__preamble.snap
+++ /dev/null
@@ -1,6 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@preamble{"foo bar baz"}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__string.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__string.snap
deleted file mode 100644
index 6d37a69e8e..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__string.snap
+++ /dev/null
@@ -1,6 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@string{foo = "bar"}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__trailing_comma.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__trailing_comma.snap
deleted file mode 100644
index 3be9b15e9d..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__trailing_comma.snap
+++ /dev/null
@@ -1,8 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@article{foo,
- bar = baz,
-}
diff --git a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__wrap_long_lines.snap b/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__wrap_long_lines.snap
deleted file mode 100644
index 6c0ec724b5..0000000000
--- a/support/texlab/src/features/formatting/snapshots/texlab__features__formatting__bibtex_internal__tests__wrap_long_lines.snap
+++ /dev/null
@@ -1,10 +0,0 @@
----
-source: src/features/formatting/bibtex_internal.rs
-expression: edit.new_text
-
----
-@article{foo,
- bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum
- dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,
- consectetur adipiscing elit.},
-}
diff --git a/support/texlab/src/features/highlight/label.rs b/support/texlab/src/features/highlight/label.rs
index 3e8b95eac8..cb51abdd68 100644
--- a/support/texlab/src/features/highlight/label.rs
+++ b/support/texlab/src/features/highlight/label.rs
@@ -77,71 +77,3 @@ pub fn find_label_highlights(
Some(highlights)
}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .highlight();
- let context = CursorContext::new(request);
-
- let actual_links = find_label_highlights(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .highlight();
- let context = CursorContext::new(request);
-
- let actual_links = find_label_highlights(&context);
-
- assert!(actual_links.is_none());
- }
-
- #[test]
- fn test_label() {
- let tester = FeatureTester::builder()
- .files(vec![("main.tex", "\\label{foo}\n\\ref{foo}\\label{bar}")])
- .main("main.tex")
- .line(0)
- .character(7)
- .build();
- let request = tester.highlight();
- let context = CursorContext::new(request);
-
- let actual_highlights = find_label_highlights(&context).unwrap();
-
- let expected_highlights = vec![
- DocumentHighlight {
- range: Range::new_simple(0, 7, 0, 10),
- kind: Some(DocumentHighlightKind::WRITE),
- },
- DocumentHighlight {
- range: Range::new_simple(1, 5, 1, 8),
- kind: Some(DocumentHighlightKind::READ),
- },
- ];
-
- assert_eq!(actual_highlights, expected_highlights);
- }
-}
diff --git a/support/texlab/src/features/hover.rs b/support/texlab/src/features/hover.rs
index 7d349de0a3..8663f6256d 100644
--- a/support/texlab/src/features/hover.rs
+++ b/support/texlab/src/features/hover.rs
@@ -5,9 +5,13 @@ mod field;
mod label;
mod string_ref;
-use lsp_types::{Hover, HoverParams};
+use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent, MarkupKind};
+use rowan::TextRange;
-use crate::features::{cursor::CursorContext, hover::citation::find_citation_hover};
+use crate::{
+ features::{cursor::CursorContext, hover::citation::find_citation_hover},
+ LineIndexExt,
+};
use self::{
component::find_component_hover, entry_type::find_entry_type_hover, field::find_field_hover,
@@ -19,10 +23,31 @@ use super::FeatureRequest;
pub fn find_hover(request: FeatureRequest<HoverParams>) -> Option<Hover> {
let context = CursorContext::new(request);
log::debug!("[Hover] Cursor: {:?}", context.cursor);
- find_label_hover(&context)
+ let result = find_label_hover(&context)
.or_else(|| find_citation_hover(&context))
.or_else(|| find_component_hover(&context))
.or_else(|| find_string_reference_hover(&context))
.or_else(|| find_field_hover(&context))
- .or_else(|| find_entry_type_hover(&context))
+ .or_else(|| find_entry_type_hover(&context))?;
+
+ Some(Hover {
+ contents: HoverContents::Markup(MarkupContent {
+ kind: result.value_kind,
+ value: result.value,
+ }),
+ range: Some(
+ context
+ .request
+ .main_document()
+ .line_index
+ .line_col_lsp_range(result.range),
+ ),
+ })
+}
+
+#[derive(Debug, Clone)]
+struct HoverResult {
+ range: TextRange,
+ value: String,
+ value_kind: MarkupKind,
}
diff --git a/support/texlab/src/features/hover/citation.rs b/support/texlab/src/features/hover/citation.rs
index 4a0e3d2313..5e86019eee 100644
--- a/support/texlab/src/features/hover/citation.rs
+++ b/support/texlab/src/features/hover/citation.rs
@@ -1,121 +1,32 @@
-use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent, MarkupKind};
+use lsp_types::{HoverParams, MarkupKind};
use rowan::ast::AstNode;
-use crate::{citation, features::cursor::CursorContext, syntax::bibtex, LineIndexExt};
+use crate::{citation, features::cursor::CursorContext, syntax::bibtex};
-pub fn find_citation_hover(context: &CursorContext<HoverParams>) -> Option<Hover> {
- let main_document = context.request.main_document();
+use super::HoverResult;
- let (key_text, key_range) = context
+pub(super) fn find_citation_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
+ let (key, range) = context
.find_citation_key_word()
.or_else(|| context.find_citation_key_command())
.or_else(|| context.find_entry_key())?;
- let contents = context
+ let value = context
.request
.workspace
.documents_by_uri
.values()
.find_map(|document| {
- document.data.as_bibtex().and_then(|data| {
- let root = bibtex::SyntaxNode::new_root(data.green.clone());
- let root = bibtex::Root::cast(root)?;
- let entry = root.find_entry(&key_text)?;
-
- citation::render(&entry).map(|value| MarkupContent {
- kind: MarkupKind::Markdown,
- value,
- })
- })
+ let data = document.data.as_bibtex()?;
+ let root = bibtex::SyntaxNode::new_root(data.green.clone());
+ let root = bibtex::Root::cast(root)?;
+ let entry = root.find_entry(&key)?;
+ citation::render(&entry)
})?;
- Some(Hover {
- range: Some(main_document.line_index.line_col_lsp_range(key_range)),
- contents: HoverContents::Markup(contents),
+ Some(HoverResult {
+ range,
+ value,
+ value_kind: MarkupKind::Markdown,
})
}
-
-#[cfg(test)]
-mod tests {
- use insta::assert_debug_snapshot;
-
- use crate::features::testing::FeatureTester;
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_citation_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_citation_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_inside_cite() {
- let request = FeatureTester::builder()
- .files(vec![
- (
- "main.bib",
- "@article{foo, author = {Foo Bar}, title = {Baz Qux}, year = 1337}",
- ),
- ("main.tex", "\\addbibresource{main.bib}\n\\cite{foo}"),
- ])
- .main("main.tex")
- .line(1)
- .character(7)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_citation_hover(&context).unwrap();
-
- assert_debug_snapshot!(actual_hover);
- }
-
- #[test]
- fn test_inside_entry() {
- let request = FeatureTester::builder()
- .files(vec![
- (
- "main.bib",
- "@article{foo, author = {Foo Bar}, title = {Baz Qux}, year = 1337}",
- ),
- ("main.tex", "\\addbibresource{main.bib}\n\\cite{foo}"),
- ])
- .main("main.bib")
- .line(0)
- .character(11)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_citation_hover(&context).unwrap();
-
- assert_debug_snapshot!(actual_hover);
- }
-}
diff --git a/support/texlab/src/features/hover/component.rs b/support/texlab/src/features/hover/component.rs
index 7b7e6c6e02..737a99d3ea 100644
--- a/support/texlab/src/features/hover/component.rs
+++ b/support/texlab/src/features/hover/component.rs
@@ -1,97 +1,25 @@
-use lsp_types::{Hover, HoverContents, HoverParams};
+use lsp_types::{HoverParams, MarkupKind};
-use crate::{
- component_db::COMPONENT_DATABASE, features::cursor::CursorContext, syntax::latex, LineIndexExt,
-};
+use crate::{component_db::COMPONENT_DATABASE, features::cursor::CursorContext, syntax::latex};
-pub fn find_component_hover(context: &CursorContext<HoverParams>) -> Option<Hover> {
- let main_document = context.request.main_document();
- let data = main_document.data.as_latex()?;
+use super::HoverResult;
+
+pub(super) fn find_component_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
+ let data = context.request.main_document().data.as_latex()?;
for link in &data.extras.explicit_links {
if matches!(
link.kind,
latex::ExplicitLinkKind::Package | latex::ExplicitLinkKind::Class
) && link.stem_range.contains_inclusive(context.offset)
{
- let docs = COMPONENT_DATABASE.documentation(&link.stem)?;
- return Some(Hover {
- contents: HoverContents::Markup(docs),
- range: Some(main_document.line_index.line_col_lsp_range(link.stem_range)),
+ let value = COMPONENT_DATABASE.documentation(&link.stem)?.value;
+ return Some(HoverResult {
+ value,
+ value_kind: MarkupKind::PlainText,
+ range: link.stem_range,
});
}
}
- None
-}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_component_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_component_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
- #[test]
- fn test_known_package() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", r#"\usepackage{amsmath}"#)])
- .main("main.tex")
- .line(0)
- .character(15)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_component_hover(&context).unwrap();
-
- assert_eq!(actual_hover.range.unwrap(), Range::new_simple(0, 12, 0, 19));
- }
-
- #[test]
- fn test_unknown_class() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", r#"\documentclass{abcdefghijklmnop}"#)])
- .main("main.tex")
- .line(0)
- .character(20)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_component_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
+ None
}
diff --git a/support/texlab/src/features/hover/entry_type.rs b/support/texlab/src/features/hover/entry_type.rs
index ab36177ae8..41a561395c 100644
--- a/support/texlab/src/features/hover/entry_type.rs
+++ b/support/texlab/src/features/hover/entry_type.rs
@@ -1,124 +1,19 @@
-use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent};
+use lsp_types::{HoverParams, MarkupKind};
-use crate::{features::cursor::CursorContext, syntax::bibtex, LineIndexExt, LANGUAGE_DATA};
+use crate::{features::cursor::CursorContext, syntax::bibtex, LANGUAGE_DATA};
-pub fn find_entry_type_hover(context: &CursorContext<HoverParams>) -> Option<Hover> {
+use super::HoverResult;
+
+pub(super) fn find_entry_type_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
let name = context
.cursor
.as_bibtex()
.filter(|token| token.kind() == bibtex::TYPE)?;
let docs = LANGUAGE_DATA.entry_type_documentation(&name.text()[1..])?;
- Some(Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: lsp_types::MarkupKind::Markdown,
- value: docs.to_string(),
- }),
- range: Some(
- context
- .request
- .main_document()
- .line_index
- .line_col_lsp_range(name.text_range()),
- ),
+ Some(HoverResult {
+ range: name.text_range(),
+ value: docs.to_string(),
+ value_kind: MarkupKind::Markdown,
})
}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::{MarkupKind, Range};
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_entry_type_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_entry_type_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_known_entry_type() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", r#"@article{foo,}"#)])
- .main("main.bib")
- .line(0)
- .character(3)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_entry_type_hover(&context).unwrap();
-
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: LANGUAGE_DATA
- .entry_type_documentation("article")
- .unwrap()
- .into(),
- }),
- range: Some(Range::new_simple(0, 0, 0, 8)),
- };
- assert_eq!(actual_hover, expected_hover);
- }
-
- #[test]
- fn test_unknown_field() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", r#"@foo{bar,}"#)])
- .main("main.bib")
- .line(0)
- .character(3)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_entry_type_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_entry_key() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", r#"@article{foo,}"#)])
- .main("main.bib")
- .line(0)
- .character(11)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_entry_type_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-}
diff --git a/support/texlab/src/features/hover/field.rs b/support/texlab/src/features/hover/field.rs
index daa0c301cd..6102bd6b68 100644
--- a/support/texlab/src/features/hover/field.rs
+++ b/support/texlab/src/features/hover/field.rs
@@ -1,11 +1,11 @@
-use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent};
+use lsp_types::{HoverParams, MarkupKind};
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::bibtex, LineIndexExt, LANGUAGE_DATA};
+use crate::{features::cursor::CursorContext, syntax::bibtex, LANGUAGE_DATA};
-pub fn find_field_hover(context: &CursorContext<HoverParams>) -> Option<Hover> {
- let main_document = context.request.main_document();
+use super::HoverResult;
+pub(super) fn find_field_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
let name = context
.cursor
.as_bibtex()
@@ -14,108 +14,9 @@ pub fn find_field_hover(context: &CursorContext<HoverParams>) -> Option<Hover> {
bibtex::Field::cast(name.parent()?)?;
let docs = LANGUAGE_DATA.field_documentation(name.text())?;
- Some(Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: lsp_types::MarkupKind::Markdown,
- value: docs.to_string(),
- }),
- range: Some(
- main_document
- .line_index
- .line_col_lsp_range(name.text_range()),
- ),
+ Some(HoverResult {
+ range: name.text_range(),
+ value: docs.to_string(),
+ value_kind: MarkupKind::Markdown,
})
}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::{MarkupKind, Range};
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_field_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_field_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_known_field() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", r#"@article{foo, author = bar}"#)])
- .main("main.bib")
- .line(0)
- .character(15)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_field_hover(&context).unwrap();
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: LANGUAGE_DATA.field_documentation("author").unwrap().into(),
- }),
- range: Some(Range::new_simple(0, 14, 0, 20)),
- };
- assert_eq!(actual_hover, expected_hover);
- }
-
- #[test]
- fn test_unknown_field() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", r#"@article{foo, bar = baz}"#)])
- .main("main.bib")
- .line(0)
- .character(15)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_field_hover(&context);
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_entry_key() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", r#"@article{foo, author = bar}"#)])
- .main("main.bib")
- .line(0)
- .character(11)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_field_hover(&context);
- assert_eq!(actual_hover, None);
- }
-}
diff --git a/support/texlab/src/features/hover/label.rs b/support/texlab/src/features/hover/label.rs
index 1018c187c5..2f8489d769 100644
--- a/support/texlab/src/features/hover/label.rs
+++ b/support/texlab/src/features/hover/label.rs
@@ -1,75 +1,19 @@
-use lsp_types::{Hover, HoverContents, HoverParams};
+use lsp_types::{HoverParams, MarkupKind};
-use crate::{features::cursor::CursorContext, render_label, LineIndexExt};
+use crate::{features::cursor::CursorContext, render_label};
-pub fn find_label_hover(context: &CursorContext<HoverParams>) -> Option<Hover> {
- let main_document = context.request.main_document();
+use super::HoverResult;
- let (name_text, name_range) = context
+pub(super) fn find_label_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
+ let (name_text, range) = context
.find_label_name_key()
.or_else(|| context.find_label_name_command())?;
let label = render_label(&context.request.workspace, &name_text, None)?;
- Some(Hover {
- range: Some(main_document.line_index.line_col_lsp_range(name_range)),
- contents: HoverContents::Markup(label.documentation()),
+ Some(HoverResult {
+ range,
+ value: label.reference(),
+ value_kind: MarkupKind::PlainText,
})
}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_label_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_label_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_section() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", r#"\section{Foo}\label{sec:foo}"#)])
- .main("main.tex")
- .line(0)
- .character(23)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_label_hover(&context).unwrap();
-
- assert_eq!(actual_hover.range.unwrap(), Range::new_simple(0, 20, 0, 27));
- }
-}
diff --git a/support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_cite.snap b/support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_cite.snap
deleted file mode 100644
index 2bca88bbff..0000000000
--- a/support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_cite.snap
+++ /dev/null
@@ -1,25 +0,0 @@
----
-source: src/features/hover/citation.rs
-assertion_line: 97
-expression: actual_hover
----
-Hover {
- contents: Markup(
- MarkupContent {
- kind: Markdown,
- value: "F. Bar: \"Baz Qux\". (1337).",
- },
- ),
- range: Some(
- Range {
- start: Position {
- line: 1,
- character: 6,
- },
- end: Position {
- line: 1,
- character: 9,
- },
- },
- ),
-}
diff --git a/support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_entry.snap b/support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_entry.snap
deleted file mode 100644
index 73ac4b7b69..0000000000
--- a/support/texlab/src/features/hover/snapshots/texlab__features__hover__citation__tests__inside_entry.snap
+++ /dev/null
@@ -1,25 +0,0 @@
----
-source: src/features/hover/citation.rs
-assertion_line: 119
-expression: actual_hover
----
-Hover {
- contents: Markup(
- MarkupContent {
- kind: Markdown,
- value: "F. Bar: \"Baz Qux\". (1337).",
- },
- ),
- range: Some(
- Range {
- start: Position {
- line: 0,
- character: 9,
- },
- end: Position {
- line: 0,
- character: 12,
- },
- },
- ),
-}
diff --git a/support/texlab/src/features/hover/string_ref.rs b/support/texlab/src/features/hover/string_ref.rs
index f1df08e8ab..adccdd556c 100644
--- a/support/texlab/src/features/hover/string_ref.rs
+++ b/support/texlab/src/features/hover/string_ref.rs
@@ -1,21 +1,27 @@
-use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent, MarkupKind};
+use lsp_types::{HoverParams, MarkupKind};
use rowan::ast::AstNode;
use crate::{
+ citation::field::text::TextFieldData,
features::cursor::CursorContext,
syntax::bibtex::{self, HasName, HasValue},
- LineIndexExt,
};
-pub fn find_string_reference_hover(context: &CursorContext<HoverParams>) -> Option<Hover> {
- let main_document = context.request.main_document();
- let data = main_document.data.as_bibtex()?;
+use super::HoverResult;
- let key = context.cursor.as_bibtex().filter(|token| {
- let parent = token.parent().unwrap();
- (token.kind() == bibtex::NAME && bibtex::Value::can_cast(parent.kind()))
- || (token.kind() == bibtex::NAME && bibtex::StringDef::can_cast(parent.kind()))
- })?;
+pub(super) fn find_string_reference_hover(
+ context: &CursorContext<HoverParams>,
+) -> Option<HoverResult> {
+ let data = context.request.main_document().data.as_bibtex()?;
+
+ let name = context
+ .cursor
+ .as_bibtex()
+ .filter(|token| token.kind() == bibtex::NAME)
+ .filter(|token| {
+ let parent = token.parent().unwrap();
+ bibtex::Value::can_cast(parent.kind()) || bibtex::StringDef::can_cast(parent.kind())
+ })?;
for string in bibtex::SyntaxNode::new_root(data.green.clone())
.children()
@@ -23,118 +29,16 @@ pub fn find_string_reference_hover(context: &CursorContext<HoverParams>) -> Opti
{
if string
.name_token()
- .filter(|k| k.text() == key.text())
- .is_some()
+ .map_or(false, |token| token.text() == name.text())
{
- let value = string.value()?.syntax().text().to_string();
- return Some(Hover {
- range: Some(
- main_document
- .line_index
- .line_col_lsp_range(key.text_range()),
- ),
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::PlainText,
- value,
- }),
+ let value = TextFieldData::parse(&string.value()?)?.text;
+ return Some(HoverResult {
+ range: name.text_range(),
+ value,
+ value_kind: MarkupKind::PlainText,
});
}
}
None
}
-
-#[cfg(test)]
-mod tests {
- use indoc::indoc;
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_string_reference_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_string_reference_hover(&context);
-
- assert_eq!(actual_hover, None);
- }
-
- #[test]
- fn test_inside_reference() {
- let request = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! { r#"
- @string{foo = "Foo"}
- @string{bar = "Bar"}
- @article{baz, author = bar}
- "# },
- )])
- .main("main.bib")
- .line(2)
- .character(24)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_string_reference_hover(&context).unwrap();
-
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::PlainText,
- value: "\"Bar\"".into(),
- }),
- range: Some(Range::new_simple(2, 23, 2, 26)),
- };
-
- assert_eq!(actual_hover, expected_hover);
- }
-
- #[test]
- fn test_inside_field() {
- let request = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! { r#"
- @string{foo = "Foo"}
- @string{bar = "Bar"}
- @article{baz, author = bar}
- "# },
- )])
- .main("main.bib")
- .line(2)
- .character(20)
- .build()
- .hover();
-
- let context = CursorContext::new(request);
- let actual_hover = find_string_reference_hover(&context);
- assert_eq!(actual_hover, None);
- }
-}
diff --git a/support/texlab/src/features/link.rs b/support/texlab/src/features/link.rs
index 0a02f7819e..c4ce4413f5 100644
--- a/support/texlab/src/features/link.rs
+++ b/support/texlab/src/features/link.rs
@@ -1,107 +1,33 @@
-use lsp_types::{DocumentLink, DocumentLinkParams};
+mod include;
-use crate::LineIndexExt;
-
-use super::FeatureRequest;
-
-pub fn find_document_links(request: FeatureRequest<DocumentLinkParams>) -> Vec<DocumentLink> {
- let mut links = Vec::new();
- let main_document = request.main_document();
- if let Some(data) = main_document.data.as_latex() {
- for include in &data.extras.explicit_links {
- for target in &include.targets {
- if request
- .workspace
- .documents_by_uri
- .values()
- .any(|document| document.uri.as_ref() == target.as_ref())
- {
- links.push(DocumentLink {
- range: main_document
- .line_index
- .line_col_lsp_range(include.stem_range),
- target: Some(target.as_ref().clone()),
- tooltip: None,
- data: None,
- });
- break;
- }
- }
- }
- }
- links
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .build()
- .link();
+use std::sync::Arc;
- let items = find_document_links(request);
- assert!(items.is_empty());
- }
+use lsp_types::{DocumentLink, DocumentLinkParams, Url};
+use rowan::TextRange;
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .build()
- .link();
-
- let items = find_document_links(request);
- assert!(items.is_empty());
- }
+use crate::LineIndexExt;
- #[test]
- fn test_includes() {
- let tester = FeatureTester::builder()
- .files(vec![("foo.tex", r#"\input{bar.tex}"#), ("bar.tex", r#""#)])
- .main("foo.tex")
- .build();
- let target = tester.uri("bar.tex");
+use self::include::find_include_links;
- let actual_items = find_document_links(tester.link());
+use super::FeatureRequest;
- let expected_items = vec![DocumentLink {
- range: Range::new_simple(0, 7, 0, 14),
- target: Some(target.as_ref().clone()),
+pub fn find_document_links(request: FeatureRequest<DocumentLinkParams>) -> Vec<DocumentLink> {
+ let document = request.main_document();
+ let mut results = Vec::new();
+ find_include_links(&request, &mut results);
+ results
+ .into_iter()
+ .map(|result| DocumentLink {
+ range: document.line_index.line_col_lsp_range(result.range),
+ target: Some(result.target.as_ref().clone()),
tooltip: None,
data: None,
- }];
- assert_eq!(actual_items, expected_items);
- }
-
- #[test]
- fn test_imports() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.tex", r#"\import{bar/}{baz}"#),
- ("bar/baz.tex", r#""#),
- ])
- .main("foo.tex")
- .build();
- let target = tester.uri("bar/baz.tex");
-
- let actual_items = find_document_links(tester.link());
+ })
+ .collect()
+}
- let expected_items = vec![DocumentLink {
- range: Range::new_simple(0, 14, 0, 17),
- target: Some(target.as_ref().clone()),
- tooltip: None,
- data: None,
- }];
- assert_eq!(actual_items, expected_items);
- }
+#[derive(Debug, Clone)]
+struct LinkResult {
+ range: TextRange,
+ target: Arc<Url>,
}
diff --git a/support/texlab/src/features/link/include.rs b/support/texlab/src/features/link/include.rs
new file mode 100644
index 0000000000..b4d1804cce
--- /dev/null
+++ b/support/texlab/src/features/link/include.rs
@@ -0,0 +1,33 @@
+use std::sync::Arc;
+
+use lsp_types::DocumentLinkParams;
+
+use crate::features::FeatureRequest;
+
+use super::LinkResult;
+
+pub(super) fn find_include_links(
+ request: &FeatureRequest<DocumentLinkParams>,
+ results: &mut Vec<LinkResult>,
+) -> Option<()> {
+ let data = request.main_document().data.as_latex()?;
+
+ for include in &data.extras.explicit_links {
+ for target in &include.targets {
+ if request
+ .workspace
+ .documents_by_uri
+ .values()
+ .any(|document| document.uri.as_ref() == target.as_ref())
+ {
+ results.push(LinkResult {
+ range: include.stem_range,
+ target: Arc::clone(target),
+ });
+ break;
+ }
+ }
+ }
+
+ Some(())
+}
diff --git a/support/texlab/src/features/reference.rs b/support/texlab/src/features/reference.rs
index db48453b4e..f84a3f67d5 100644
--- a/support/texlab/src/features/reference.rs
+++ b/support/texlab/src/features/reference.rs
@@ -2,7 +2,12 @@ mod entry;
mod label;
mod string;
-use lsp_types::{Location, ReferenceParams};
+use std::sync::Arc;
+
+use lsp_types::{Location, ReferenceParams, Url};
+use rowan::TextRange;
+
+use crate::LineIndexExt;
use self::{
entry::find_entry_references, label::find_label_references, string::find_string_references,
@@ -10,12 +15,27 @@ use self::{
use super::{cursor::CursorContext, FeatureRequest};
-pub fn find_all_references(request: FeatureRequest<ReferenceParams>) -> Option<Vec<Location>> {
- let mut references = Vec::new();
+pub fn find_all_references(request: FeatureRequest<ReferenceParams>) -> Vec<Location> {
+ let mut results = Vec::new();
let context = CursorContext::new(request);
log::debug!("[References] Cursor: {:?}", context.cursor);
- find_label_references(&context, &mut references);
- find_entry_references(&context, &mut references);
- find_string_references(&context, &mut references);
- Some(references)
+ find_label_references(&context, &mut results);
+ find_entry_references(&context, &mut results);
+ find_string_references(&context, &mut results);
+
+ results
+ .into_iter()
+ .map(|result| Location {
+ uri: result.uri.as_ref().clone(),
+ range: context.request.workspace.documents_by_uri[&result.uri]
+ .line_index
+ .line_col_lsp_range(result.range),
+ })
+ .collect()
+}
+
+#[derive(Debug, Clone)]
+struct ReferenceResult {
+ uri: Arc<Url>,
+ range: TextRange,
}
diff --git a/support/texlab/src/features/reference/entry.rs b/support/texlab/src/features/reference/entry.rs
index f245b6eb8d..0144d2d074 100644
--- a/support/texlab/src/features/reference/entry.rs
+++ b/support/texlab/src/features/reference/entry.rs
@@ -1,4 +1,6 @@
-use lsp_types::{Location, ReferenceParams};
+use std::sync::Arc;
+
+use lsp_types::ReferenceParams;
use rowan::ast::AstNode;
use crate::{
@@ -7,12 +9,14 @@ use crate::{
bibtex::{self, HasName},
latex,
},
- DocumentData, LineIndexExt,
+ DocumentData,
};
-pub fn find_entry_references(
+use super::ReferenceResult;
+
+pub(super) fn find_entry_references(
context: &CursorContext<ReferenceParams>,
- references: &mut Vec<Location>,
+ results: &mut Vec<ReferenceResult>,
) -> Option<()> {
let (key_text, _) = context
.find_citation_key_word()
@@ -28,13 +32,10 @@ pub fn find_entry_references(
.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| latex::small_range(&key))
.for_each(|range| {
- references.push(Location::new(document.uri.as_ref().clone(), range));
+ let uri = Arc::clone(&document.uri);
+ results.push(ReferenceResult { uri, range });
});
}
DocumentData::Bibtex(data) if context.request.params.context.include_declaration => {
@@ -43,172 +44,15 @@ pub fn find_entry_references(
.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(|key| key.text_range())
.for_each(|range| {
- references.push(Location::new(document.uri.as_ref().clone(), range));
+ let uri = Arc::clone(&document.uri);
+ results.push(ReferenceResult { uri, range });
});
}
DocumentData::Bibtex(_) | DocumentData::BuildLog(_) => {}
}
}
- Some(())
-}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- fn sort_references(actual_references: &mut [Location]) {
- actual_references.sort_by(|a, b| {
- a.uri
- .cmp(&b.uri)
- .then_with(|| a.range.start.cmp(&b.range.start))
- });
- }
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .reference();
-
- let mut actual_references = Vec::new();
- let context = CursorContext::new(request);
- find_entry_references(&context, &mut actual_references);
-
- assert!(actual_references.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .reference();
-
- let mut actual_references = Vec::new();
- let context = CursorContext::new(request);
- find_entry_references(&context, &mut actual_references);
-
- assert!(actual_references.is_empty());
- }
- #[test]
- fn test_definition() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.bib", r#"@article{foo,}"#),
- ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#),
- ])
- .main("foo.bib")
- .line(0)
- .character(11)
- .build();
- let uri = tester.uri("bar.tex");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_entry_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![Location::new(
- uri.as_ref().clone(),
- Range::new_simple(0, 6, 0, 9),
- )];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_definition_include_declaration() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.bib", r#"@article{foo,}"#),
- ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#),
- ])
- .main("foo.bib")
- .line(0)
- .character(11)
- .include_declaration(true)
- .build();
- let uri1 = tester.uri("bar.tex");
- let uri2 = tester.uri("foo.bib");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_entry_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![
- Location::new(uri1.as_ref().clone(), Range::new_simple(0, 6, 0, 9)),
- Location::new(uri2.as_ref().clone(), Range::new_simple(0, 9, 0, 12)),
- ];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_reference() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.bib", r#"@article{foo,}"#),
- ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#),
- ])
- .main("bar.tex")
- .line(0)
- .character(8)
- .build();
- let uri = tester.uri("bar.tex");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_entry_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![Location::new(
- uri.as_ref().clone(),
- Range::new_simple(0, 6, 0, 9),
- )];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_reference_include_declaration() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.bib", r#"@article{foo,}"#),
- ("bar.tex", r#"\cite{foo}\addbibresource{foo.bib}"#),
- ])
- .main("bar.tex")
- .line(0)
- .character(6)
- .include_declaration(true)
- .build();
- let uri1 = tester.uri("foo.bib");
- let uri2 = tester.uri("bar.tex");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_entry_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![
- Location::new(uri2.as_ref().clone(), Range::new_simple(0, 6, 0, 9)),
- Location::new(uri1.as_ref().clone(), Range::new_simple(0, 9, 0, 12)),
- ];
- assert_eq!(actual_references, expected_references);
- }
+ Some(())
}
diff --git a/support/texlab/src/features/reference/label.rs b/support/texlab/src/features/reference/label.rs
index 2fc3efc398..3dadada08b 100644
--- a/support/texlab/src/features/reference/label.rs
+++ b/support/texlab/src/features/reference/label.rs
@@ -1,10 +1,14 @@
-use lsp_types::{Location, ReferenceParams};
+use std::sync::Arc;
-use crate::{features::cursor::CursorContext, LineIndexExt};
+use lsp_types::ReferenceParams;
-pub fn find_label_references(
+use crate::features::cursor::CursorContext;
+
+use super::ReferenceResult;
+
+pub(super) fn find_label_references(
context: &CursorContext<ReferenceParams>,
- references: &mut Vec<Location>,
+ results: &mut Vec<ReferenceResult>,
) -> Option<()> {
let (name_text, _) = context
.find_label_name_key()
@@ -21,174 +25,13 @@ pub fn find_label_references(
!name.is_definition || context.request.params.context.include_declaration
})
{
- references.push(Location::new(
- document.uri.as_ref().clone(),
- document.line_index.line_col_lsp_range(name.range),
- ));
+ results.push(ReferenceResult {
+ uri: Arc::clone(&document.uri),
+ range: name.range,
+ });
}
}
}
Some(())
}
-
-#[cfg(test)]
-mod tests {
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- fn sort_references(actual_references: &mut [Location]) {
- actual_references.sort_by(|a, b| {
- a.uri
- .cmp(&b.uri)
- .then_with(|| a.range.start.cmp(&b.range.start))
- });
- }
-
- #[test]
- fn test_definition() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.tex", r#"\label{foo}"#),
- ("bar.tex", r#"\ref{foo}\input{foo.tex}"#),
- ])
- .main("foo.tex")
- .line(0)
- .character(8)
- .build();
- let uri = tester.uri("bar.tex");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_label_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![Location::new(
- uri.as_ref().clone(),
- Range::new_simple(0, 5, 0, 8),
- )];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_definition_include_declaration() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.tex", r#"\label{foo}\input{bar.tex}"#),
- ("bar.tex", r#"\ref{foo}"#),
- ])
- .main("foo.tex")
- .line(0)
- .character(9)
- .include_declaration(true)
- .build();
- let uri1 = tester.uri("bar.tex");
- let uri2 = tester.uri("foo.tex");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_label_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![
- Location::new(uri1.as_ref().clone(), Range::new_simple(0, 5, 0, 8)),
- Location::new(uri2.as_ref().clone(), Range::new_simple(0, 7, 0, 10)),
- ];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_reference() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.tex", r#"\label{foo}\input{bar.tex}"#),
- ("bar.tex", r#"\ref{foo}"#),
- ("baz.tex", r#"\ref{foo}\input{bar.tex}"#),
- ])
- .main("bar.tex")
- .line(0)
- .character(7)
- .build();
- let uri1 = tester.uri("bar.tex");
- let uri2 = tester.uri("baz.tex");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_label_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![
- Location::new(uri1.as_ref().clone(), Range::new_simple(0, 5, 0, 8)),
- Location::new(uri2.as_ref().clone(), Range::new_simple(0, 5, 0, 8)),
- ];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_reference_include_declaration() {
- let tester = FeatureTester::builder()
- .files(vec![
- ("foo.tex", r#"\label{foo}"#),
- ("bar.tex", r#"\ref{foo}\input{foo.tex}"#),
- ])
- .main("bar.tex")
- .line(0)
- .character(7)
- .include_declaration(true)
- .build();
- let uri1 = tester.uri("bar.tex");
- let uri2 = tester.uri("foo.tex");
- let mut actual_references = Vec::new();
-
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_label_references(&context, &mut actual_references);
-
- sort_references(&mut actual_references);
- let expected_references = vec![
- Location::new(uri1.as_ref().clone(), Range::new_simple(0, 5, 0, 8)),
- Location::new(uri2.as_ref().clone(), Range::new_simple(0, 7, 0, 10)),
- ];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .reference();
- let mut actual_references = Vec::new();
-
- let context = CursorContext::new(request);
- find_label_references(&context, &mut actual_references);
-
- assert!(actual_references.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .reference();
- let mut actual_references = Vec::new();
-
- let context = CursorContext::new(request);
- find_label_references(&context, &mut actual_references);
-
- assert!(actual_references.is_empty());
- }
-}
diff --git a/support/texlab/src/features/reference/string.rs b/support/texlab/src/features/reference/string.rs
index c957244a53..c00cf93546 100644
--- a/support/texlab/src/features/reference/string.rs
+++ b/support/texlab/src/features/reference/string.rs
@@ -1,23 +1,26 @@
-use lsp_types::{Location, ReferenceParams};
+use std::sync::Arc;
+
+use lsp_types::ReferenceParams;
use rowan::ast::AstNode;
use crate::{
features::cursor::CursorContext,
syntax::bibtex::{self, HasName},
- LineIndexExt,
};
-pub fn find_string_references(
+use super::ReferenceResult;
+
+pub(super) fn find_string_references(
context: &CursorContext<ReferenceParams>,
- items: &mut Vec<Location>,
+ results: &mut Vec<ReferenceResult>,
) -> Option<()> {
let name_text = context
.cursor
.as_bibtex()
+ .filter(|token| token.kind() == bibtex::NAME)
.filter(|token| {
let parent = token.parent().unwrap();
- (token.kind() == bibtex::NAME && bibtex::Value::can_cast(parent.kind()))
- || (token.kind() == bibtex::NAME && bibtex::StringDef::can_cast(parent.kind()))
+ bibtex::Value::can_cast(parent.kind()) || bibtex::StringDef::can_cast(parent.kind())
})?
.text();
@@ -35,173 +38,12 @@ pub fn find_string_references(
.filter(|name| name.text() == name_text)
})
{
- items.push(Location::new(
- document.uri.as_ref().clone(),
- document.line_index.line_col_lsp_range(name.text_range()),
- ));
+ results.push(ReferenceResult {
+ uri: Arc::clone(&document.uri),
+ range: name.text_range(),
+ });
}
}
- Some(())
-}
-
-#[cfg(test)]
-mod tests {
- use indoc::indoc;
- use lsp_types::Range;
-
- use crate::{features::testing::FeatureTester, RangeExt};
-
- use super::*;
-
- #[test]
- fn test_definition() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! { r#"
- @string{foo = {Foo}}
- @string{bar = {Bar}}
- @article{baz, author = foo}
- "# },
- )])
- .main("main.bib")
- .line(2)
- .character(24)
- .build();
- let uri = tester.uri("main.bib");
-
- let mut actual_references = Vec::new();
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_string_references(&context, &mut actual_references);
-
- let expected_references = vec![Location::new(
- uri.as_ref().clone(),
- Range::new_simple(2, 23, 2, 26),
- )];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_definition_include_declaration() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! { r#"
- @string{foo = {Foo}}
- @string{bar = {Bar}}
- @article{baz, author = foo}
- "# },
- )])
- .main("main.bib")
- .line(2)
- .character(24)
- .include_declaration(true)
- .build();
- let uri = tester.uri("main.bib");
-
- let mut actual_references = Vec::new();
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_string_references(&context, &mut actual_references);
-
- let expected_references = vec![
- Location::new(uri.as_ref().clone(), Range::new_simple(0, 8, 0, 11)),
- Location::new(uri.as_ref().clone(), Range::new_simple(2, 23, 2, 26)),
- ];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_reference() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! { r#"
- @string{foo = {Foo}}
- @string{bar = {Bar}}
- @article{baz, author = foo}
- "# },
- )])
- .main("main.bib")
- .line(0)
- .character(10)
- .build();
- let uri = tester.uri("main.bib");
- let mut actual_references = Vec::new();
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_string_references(&context, &mut actual_references);
-
- let expected_references = vec![Location::new(
- uri.as_ref().clone(),
- Range::new_simple(2, 23, 2, 26),
- )];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_reference_include_declaration() {
- let tester = FeatureTester::builder()
- .files(vec![(
- "main.bib",
- indoc! { r#"
- @string{foo = {Foo}}
- @string{bar = {Bar}}
- @article{baz, author = foo}
- "# },
- )])
- .main("main.bib")
- .line(0)
- .character(10)
- .include_declaration(true)
- .build();
- let uri = tester.uri("main.bib");
-
- let mut actual_references = Vec::new();
- let request = tester.reference();
- let context = CursorContext::new(request);
- find_string_references(&context, &mut actual_references);
-
- let expected_references = vec![
- Location::new(uri.as_ref().clone(), Range::new_simple(0, 8, 0, 11)),
- Location::new(uri.as_ref().clone(), Range::new_simple(2, 23, 2, 26)),
- ];
- assert_eq!(actual_references, expected_references);
- }
-
- #[test]
- fn test_empty_latex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.tex", "")])
- .main("main.tex")
- .line(0)
- .character(0)
- .build()
- .reference();
-
- let mut actual_references = Vec::new();
- let context = CursorContext::new(request);
- find_string_references(&context, &mut actual_references);
-
- assert!(actual_references.is_empty());
- }
-
- #[test]
- fn test_empty_bibtex_document() {
- let request = FeatureTester::builder()
- .files(vec![("main.bib", "")])
- .main("main.bib")
- .line(0)
- .character(0)
- .build()
- .reference();
-
- let mut actual_references = Vec::new();
- let context = CursorContext::new(request);
- find_string_references(&context, &mut actual_references);
-
- assert!(actual_references.is_empty());
- }
+ Some(())
}
diff --git a/support/texlab/src/features/rename.rs b/support/texlab/src/features/rename.rs
index a9a6732d04..c21faf262e 100644
--- a/support/texlab/src/features/rename.rs
+++ b/support/texlab/src/features/rename.rs
@@ -2,7 +2,13 @@ mod command;
mod entry;
mod label;
-use lsp_types::{Range, RenameParams, TextDocumentPositionParams, WorkspaceEdit};
+use std::sync::Arc;
+
+use lsp_types::{Range, RenameParams, TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit};
+use rowan::TextRange;
+use rustc_hash::FxHashMap;
+
+use crate::LineIndexExt;
use self::{
command::{prepare_command_rename, rename_command},
@@ -14,14 +20,46 @@ use super::{cursor::CursorContext, FeatureRequest};
pub fn prepare_rename_all(request: FeatureRequest<TextDocumentPositionParams>) -> Option<Range> {
let context = CursorContext::new(request);
- prepare_entry_rename(&context)
+ let range = prepare_entry_rename(&context)
.or_else(|| prepare_label_rename(&context))
- .or_else(|| prepare_command_rename(&context))
+ .or_else(|| prepare_command_rename(&context))?;
+
+ let line_index = &context.request.main_document().line_index;
+ Some(line_index.line_col_lsp_range(range))
}
pub fn rename_all(request: FeatureRequest<RenameParams>) -> Option<WorkspaceEdit> {
let context = CursorContext::new(request);
- rename_entry(&context)
+ let result = rename_entry(&context)
.or_else(|| rename_label(&context))
- .or_else(|| rename_command(&context))
+ .or_else(|| rename_command(&context))?;
+
+ let changes = result
+ .changes
+ .into_iter()
+ .map(|(uri, old_edits)| {
+ let document = &context.request.workspace.documents_by_uri[&uri];
+ let new_edits = old_edits
+ .into_iter()
+ .map(|Indel { delete, insert }| {
+ TextEdit::new(document.line_index.line_col_lsp_range(delete), insert)
+ })
+ .collect();
+
+ (uri.as_ref().clone(), new_edits)
+ })
+ .collect();
+
+ Some(WorkspaceEdit::new(changes))
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+struct Indel {
+ delete: TextRange,
+ insert: String,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+struct RenameResult {
+ changes: FxHashMap<Arc<Url>, Vec<Indel>>,
}
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 })
}
diff --git a/support/texlab/src/features/symbol.rs b/support/texlab/src/features/symbol.rs
index 42b9d03d3f..24d599c3e1 100644
--- a/support/texlab/src/features/symbol.rs
+++ b/support/texlab/src/features/symbol.rs
@@ -14,10 +14,12 @@ use crate::{ClientCapabilitiesExt, Workspace};
use self::{
bibtex::find_bibtex_symbols, latex::find_latex_symbols, project_order::ProjectOrdering,
+ types::InternalSymbol,
};
use super::FeatureRequest;
+#[must_use]
pub fn find_document_symbols(req: FeatureRequest<DocumentSymbolParams>) -> DocumentSymbolResponse {
let mut buf = Vec::new();
find_latex_symbols(&req, &mut buf);
@@ -30,7 +32,7 @@ pub fn find_document_symbols(req: FeatureRequest<DocumentSymbolParams>) -> Docum
{
DocumentSymbolResponse::Nested(
buf.into_iter()
- .map(|symbol| symbol.into_document_symbol())
+ .map(InternalSymbol::into_document_symbol)
.collect(),
)
} else {
@@ -53,6 +55,7 @@ struct WorkspaceSymbol {
search_text: String,
}
+#[must_use]
pub fn find_workspace_symbols(
workspace: &Workspace,
params: &WorkspaceSymbolParams,