summaryrefslogtreecommitdiff
path: root/support/texlab/crates/completion/src
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/crates/completion/src')
-rw-r--r--support/texlab/crates/completion/src/lib.rs29
-rw-r--r--support/texlab/crates/completion/src/providers.rs6
-rw-r--r--support/texlab/crates/completion/src/providers/command.rs17
-rw-r--r--support/texlab/crates/completion/src/providers/include.rs11
-rw-r--r--support/texlab/crates/completion/src/providers/label_def.rs60
-rw-r--r--support/texlab/crates/completion/src/providers/label_ref.rs (renamed from support/texlab/crates/completion/src/providers/label.rs)2
-rw-r--r--support/texlab/crates/completion/src/tests.rs57
-rw-r--r--support/texlab/crates/completion/src/util/builder.rs1
8 files changed, 156 insertions, 27 deletions
diff --git a/support/texlab/crates/completion/src/lib.rs b/support/texlab/crates/completion/src/lib.rs
index 6acec28d49..7fc5bba174 100644
--- a/support/texlab/crates/completion/src/lib.rs
+++ b/support/texlab/crates/completion/src/lib.rs
@@ -45,6 +45,7 @@ impl<'a> CompletionItem<'a> {
#[derive(Debug, PartialEq, Eq)]
pub enum CompletionItemData<'a> {
Command(CommandData<'a>),
+ CommandLikeDelimiter(&'a str, &'a str),
BeginEnvironment,
Citation(CitationData<'a>),
Environment(EnvironmentData<'a>),
@@ -66,6 +67,7 @@ impl<'a> CompletionItemData<'a> {
pub fn label<'b: 'a>(&'b self) -> &'a str {
match self {
Self::Command(data) => data.name,
+ Self::CommandLikeDelimiter(left, _) => left,
Self::BeginEnvironment => "begin",
Self::Citation(data) => &data.entry.name.text,
Self::Environment(data) => data.name,
@@ -83,6 +85,30 @@ impl<'a> CompletionItemData<'a> {
Self::TikzLibrary(name) => name,
}
}
+
+ /// Returns a number that can be used to sort the completion items further before resorting to the label.
+ /// This is useful for making snippets more visible.
+ pub fn sort_index(&self) -> u8 {
+ match self {
+ Self::Command(_) => 1,
+ Self::CommandLikeDelimiter(_, _) => 0,
+ Self::BeginEnvironment => 1,
+ Self::Citation(_) => 1,
+ Self::Environment(_) => 1,
+ Self::GlossaryEntry(_) => 1,
+ Self::Label(_) => 1,
+ Self::Color(_) => 1,
+ Self::ColorModel(_) => 1,
+ Self::File(_) => 1,
+ Self::Directory(_) => 1,
+ Self::Argument(_) => 1,
+ Self::Package(_) => 1,
+ Self::DocumentClass(_) => 1,
+ Self::EntryType(_) => 1,
+ Self::Field(_) => 1,
+ Self::TikzLibrary(_) => 1,
+ }
+ }
}
#[derive(PartialEq, Eq)]
@@ -171,7 +197,8 @@ pub fn complete<'a>(params: &'a CompletionParams<'a>) -> CompletionResult<'a> {
providers::complete_citations(params, &mut builder);
providers::complete_acronyms(params, &mut builder);
providers::complete_glossaries(params, &mut builder);
- providers::complete_labels(params, &mut builder);
+ providers::complete_label_references(params, &mut builder);
+ providers::complete_label_definitions(params, &mut builder);
providers::complete_colors(params, &mut builder);
providers::complete_color_models(params, &mut builder);
providers::complete_includes(params, &mut builder);
diff --git a/support/texlab/crates/completion/src/providers.rs b/support/texlab/crates/completion/src/providers.rs
index 5160c85d85..dc60907f2e 100644
--- a/support/texlab/crates/completion/src/providers.rs
+++ b/support/texlab/crates/completion/src/providers.rs
@@ -9,7 +9,8 @@ mod field;
mod glossary;
mod import;
mod include;
-mod label;
+mod label_def;
+mod label_ref;
mod tikz_library;
pub use argument::complete_arguments;
@@ -23,5 +24,6 @@ pub use field::complete_fields;
pub use glossary::{complete_acronyms, complete_glossaries};
pub use import::complete_imports;
pub use include::complete_includes;
-pub use label::complete_labels;
+pub use label_def::complete_label_definitions;
+pub use label_ref::complete_label_references;
pub use tikz_library::complete_tikz_libraries;
diff --git a/support/texlab/crates/completion/src/providers/command.rs b/support/texlab/crates/completion/src/providers/command.rs
index ddbf8bc206..f404d42ab3 100644
--- a/support/texlab/crates/completion/src/providers/command.rs
+++ b/support/texlab/crates/completion/src/providers/command.rs
@@ -7,6 +7,8 @@ use crate::{
CommandData, CompletionItem, CompletionItemData, CompletionParams,
};
+static DELIMITERS: &[(&str, &str)] = &[("(", ")"), ("[", "]"), ("{", "\\}")];
+
pub fn complete_commands<'a>(
params: &'a CompletionParams<'a>,
builder: &mut CompletionBuilder<'a>,
@@ -20,6 +22,7 @@ pub fn complete_commands<'a>(
});
proc.add_begin_snippet();
+ proc.add_delimiters();
proc.add_library();
proc.add_user();
Some(())
@@ -39,6 +42,20 @@ impl<'a, 'b> Processor<'a, 'b> {
Some(())
}
+ pub fn add_delimiters(&mut self) {
+ for (left, right) in DELIMITERS {
+ let Some(score) = self.0.builder.matcher.score(&left, &self.0.cursor.text) else {
+ continue;
+ };
+
+ let data = CompletionItemData::CommandLikeDelimiter(left, right);
+ self.0
+ .builder
+ .items
+ .push(CompletionItem::new_simple(score, self.0.cursor.range, data));
+ }
+ }
+
pub fn add_library(&mut self) -> Option<()> {
for package in included_packages(&self.0.params.feature) {
let commands_with_score = package.commands.iter().filter_map(|command| {
diff --git a/support/texlab/crates/completion/src/providers/include.rs b/support/texlab/crates/completion/src/providers/include.rs
index f8bb55dfeb..6246624733 100644
--- a/support/texlab/crates/completion/src/providers/include.rs
+++ b/support/texlab/crates/completion/src/providers/include.rs
@@ -3,7 +3,10 @@ use std::{
path::{Path, PathBuf},
};
-use base_db::{DocumentData, FeatureParams};
+use base_db::{
+ deps::{self, ProjectRoot},
+ DocumentData, FeatureParams,
+};
use rowan::{ast::AstNode, TextLen, TextRange};
use syntax::latex;
@@ -112,13 +115,13 @@ fn current_dir(
graphics_path: Option<&str>,
) -> Option<PathBuf> {
let workspace = &params.workspace;
- let parent = workspace
- .parents(params.document)
+ let parent = deps::parents(&workspace, params.document)
.iter()
.next()
.map_or(params.document, Clone::clone);
- let path = workspace.current_dir(&parent.dir).to_file_path().ok()?;
+ let root = ProjectRoot::walk_and_find(workspace, &parent.dir);
+ let path = root.src_dir.to_file_path().ok()?;
let mut path = PathBuf::from(path.to_str()?.replace('\\', "/"));
diff --git a/support/texlab/crates/completion/src/providers/label_def.rs b/support/texlab/crates/completion/src/providers/label_def.rs
new file mode 100644
index 0000000000..a8966ed62f
--- /dev/null
+++ b/support/texlab/crates/completion/src/providers/label_def.rs
@@ -0,0 +1,60 @@
+use base_db::{
+ semantics::{
+ tex::{Label, LabelKind},
+ Span,
+ },
+ util::queries::Object,
+};
+use rowan::ast::AstNode;
+use rustc_hash::FxHashSet;
+use syntax::latex;
+
+use crate::{
+ util::{find_curly_group_word, CompletionBuilder},
+ CompletionParams,
+};
+
+pub fn complete_label_definitions<'a>(
+ params: &'a CompletionParams<'a>,
+ builder: &mut CompletionBuilder<'a>,
+) -> Option<()> {
+ let cursor = find_definition(params)?;
+
+ let label_defs: FxHashSet<&str> = Label::find_all(&params.feature.project)
+ .filter(|(_, label)| label.kind == LabelKind::Definition)
+ .map(|(_, label)| label.name_text())
+ .collect();
+
+ let label_refs: FxHashSet<&str> = Label::find_all(&params.feature.project)
+ .filter(|(_, label)| label.kind == LabelKind::Reference)
+ .map(|(_, label)| label.name_text())
+ .collect();
+
+ for label in label_refs.difference(&label_defs) {
+ let Some(score) = builder.matcher.score(label, &cursor.text) else {
+ continue;
+ };
+
+ let data = crate::LabelData {
+ name: label,
+ header: None,
+ footer: None,
+ object: None,
+ keywords: label.to_string(),
+ };
+
+ builder.items.push(crate::CompletionItem::new_simple(
+ score,
+ cursor.range,
+ crate::CompletionItemData::Label(data),
+ ));
+ }
+
+ Some(())
+}
+
+fn find_definition(params: &CompletionParams) -> Option<Span> {
+ let (cursor, group) = find_curly_group_word(params)?;
+ latex::LabelDefinition::cast(group.syntax().parent()?)?;
+ Some(cursor)
+}
diff --git a/support/texlab/crates/completion/src/providers/label.rs b/support/texlab/crates/completion/src/providers/label_ref.rs
index 8af2873457..6f71ae3241 100644
--- a/support/texlab/crates/completion/src/providers/label.rs
+++ b/support/texlab/crates/completion/src/providers/label_ref.rs
@@ -11,7 +11,7 @@ use crate::{
CompletionItem, CompletionItemData, CompletionParams,
};
-pub fn complete_labels<'a>(
+pub fn complete_label_references<'a>(
params: &'a CompletionParams<'a>,
builder: &mut CompletionBuilder<'a>,
) -> Option<()> {
diff --git a/support/texlab/crates/completion/src/tests.rs b/support/texlab/crates/completion/src/tests.rs
index 84cd06447b..f41c9f5e6b 100644
--- a/support/texlab/crates/completion/src/tests.rs
+++ b/support/texlab/crates/completion/src/tests.rs
@@ -726,40 +726,34 @@ fn component_command_simple() {
%! main.tex
\
|"#,
- expect![[r##"
+ expect![[r#"
[
- Command(
- CommandData {
- name: "!",
- package: [],
- },
+ CommandLikeDelimiter(
+ "(",
+ ")",
),
- Command(
- CommandData {
- name: "\"",
- package: [],
- },
+ CommandLikeDelimiter(
+ "[",
+ "]",
),
- Command(
- CommandData {
- name: "#",
- package: [],
- },
+ CommandLikeDelimiter(
+ "{",
+ "\\}",
),
Command(
CommandData {
- name: "$",
+ name: "!",
package: [],
},
),
Command(
CommandData {
- name: "%",
+ name: "\"",
package: [],
},
),
]
- "##]],
+ "#]],
);
}
@@ -1613,6 +1607,31 @@ Lorem ipsum dolor sit amet.
}
#[test]
+fn label_undefined() {
+ check(
+ r#"
+%! foo.tex
+\label{f}
+ |
+ ^
+\ref{foo}"#,
+ expect![[r#"
+ [
+ Label(
+ LabelData {
+ name: "foo",
+ header: None,
+ footer: None,
+ object: None,
+ keywords: "foo",
+ },
+ ),
+ ]
+ "#]],
+ );
+}
+
+#[test]
fn theorem_begin() {
check(
r#"
diff --git a/support/texlab/crates/completion/src/util/builder.rs b/support/texlab/crates/completion/src/util/builder.rs
index 4ae0818e58..d219a5f2b1 100644
--- a/support/texlab/crates/completion/src/util/builder.rs
+++ b/support/texlab/crates/completion/src/util/builder.rs
@@ -32,6 +32,7 @@ impl<'a> CompletionBuilder<'a> {
b.preselect
.cmp(&a.preselect)
.then_with(|| b.score.cmp(&a.score))
+ .then_with(|| a.data.sort_index().cmp(&b.data.sort_index()))
.then_with(|| a.data.label().cmp(b.data.label()))
});