summaryrefslogtreecommitdiff
path: root/support/texlab/src/features/completion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/features/completion.rs')
-rw-r--r--support/texlab/src/features/completion.rs149
1 files changed, 74 insertions, 75 deletions
diff --git a/support/texlab/src/features/completion.rs b/support/texlab/src/features/completion.rs
index 2a3f4ea9af..3b5187f8eb 100644
--- a/support/texlab/src/features/completion.rs
+++ b/support/texlab/src/features/completion.rs
@@ -21,18 +21,20 @@ mod util;
use std::borrow::Cow;
-use cancellation::CancellationToken;
-use cstree::TextSize;
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
use itertools::Itertools;
use lsp_types::{
CompletionItem, CompletionList, CompletionParams, CompletionTextEdit, Documentation,
InsertTextFormat, MarkupContent, MarkupKind, TextEdit,
};
+use rowan::{ast::AstNode, TextSize};
use rustc_hash::FxHashSet;
use crate::{
- syntax::{bibtex, latex, CstNode},
+ syntax::{
+ bibtex::{self},
+ latex,
+ },
LineIndexExt,
};
@@ -69,39 +71,41 @@ use super::{
pub const COMPLETION_LIMIT: usize = 50;
-pub fn complete(
- request: FeatureRequest<CompletionParams>,
- cancellation_token: &CancellationToken,
-) -> Option<CompletionList> {
+pub fn complete(request: FeatureRequest<CompletionParams>) -> Option<CompletionList> {
let mut items = Vec::new();
let context = CursorContext::new(request);
log::debug!("[Completion] Cursor: {:?}", context.cursor);
- complete_entry_types(&context, &mut items, cancellation_token);
- complete_fields(&context, &mut items, cancellation_token);
- complete_arguments(&context, &mut items, cancellation_token);
- complete_citations(&context, &mut items, cancellation_token);
- complete_imports(&context, &mut items, cancellation_token);
- complete_colors(&context, &mut items, cancellation_token);
- complete_color_models(&context, &mut items, cancellation_token);
- complete_acronyms(&context, &mut items, cancellation_token);
- complete_glossary_entries(&context, &mut items, cancellation_token);
- complete_includes(&context, &mut items, cancellation_token);
- complete_labels(&context, &mut items, cancellation_token);
- complete_tikz_libraries(&context, &mut items, cancellation_token);
- complete_component_environments(&context, &mut items, cancellation_token);
- complete_theorem_environments(&context, &mut items, cancellation_token);
- complete_user_environments(&context, &mut items, cancellation_token);
- complete_begin_command(&context, &mut items, cancellation_token);
- complete_component_commands(&context, &mut items, cancellation_token);
- complete_user_commands(&context, &mut items, cancellation_token);
-
- cancellation_token.result().ok()?;
+ complete_entry_types(&context, &mut items);
+ complete_fields(&context, &mut items);
+ complete_arguments(&context, &mut items);
+ complete_citations(&context, &mut items);
+ complete_imports(&context, &mut items);
+ complete_colors(&context, &mut items);
+ complete_color_models(&context, &mut items);
+ complete_acronyms(&context, &mut items);
+ complete_glossary_entries(&context, &mut items);
+ complete_includes(&context, &mut items);
+ complete_labels(&context, &mut items);
+ complete_tikz_libraries(&context, &mut items);
+ complete_component_environments(&context, &mut items);
+ complete_theorem_environments(&context, &mut items);
+ complete_user_environments(&context, &mut items);
+ complete_begin_command(&context, &mut items);
+ complete_component_commands(&context, &mut items);
+ complete_user_commands(&context, &mut items);
let mut items = dedup(items);
preselect(&context, &mut items);
score(&context, &mut items);
- items.sort_by_key(|item| (!item.preselect, -item.score.unwrap_or(std::i64::MIN + 1)));
+ items.sort_by(|a, b| {
+ a.preselect
+ .cmp(&b.preselect)
+ .reverse()
+ .then_with(|| a.score.cmp(&b.score).reverse())
+ .then_with(|| a.data.label().cmp(b.data.label()))
+ });
+
let items: Vec<_> = items
.into_iter()
.take(COMPLETION_LIMIT)
@@ -113,14 +117,12 @@ pub fn complete(
let is_incomplete = if context
.request
- .context
+ .workspace
+ .environment
.client_info
- .lock()
- .unwrap()
.as_ref()
- .map(|info| info.name.as_str())
- .unwrap_or_default()
- == "Visual Studio Code"
+ .as_ref()
+ .map_or(false, |info| info.name.as_str() == "Visual Studio Code")
{
true
} else {
@@ -159,10 +161,10 @@ fn score(context: &CursorContext<CompletionParams>, items: &mut Vec<InternalComp
}
}
Cursor::Latex(token) if token.kind() == latex::WORD => {
- if let Some(key) = latex::Key::cast(token.parent()) {
+ if let Some(key) = token.parent().and_then(latex::Key::cast) {
key.words()
.take_while(|word| word.text_range() != token.text_range())
- .chain(std::iter::once(token))
+ .chain(std::iter::once(token.clone()))
.filter(|word| word.text_range().start() < context.offset)
.join(" ")
.into()
@@ -171,16 +173,17 @@ fn score(context: &CursorContext<CompletionParams>, items: &mut Vec<InternalComp
}
}
Cursor::Latex(_) => "".into(),
- Cursor::Bibtex(token) if token.kind().is_type() => token.text().into(),
- Cursor::Bibtex(token) if token.kind() == bibtex::WORD => {
- if let Some(key) = bibtex::Key::cast(token.parent()) {
- key.to_string().into()
- } else {
- token.text().into()
- }
- }
- Cursor::Bibtex(token) if token.kind() == bibtex::COMMAND_NAME => {
- token.text().trim_end().into()
+ Cursor::Bibtex(token)
+ if matches!(
+ token.kind(),
+ bibtex::TYPE
+ | bibtex::NAME
+ | bibtex::WORD
+ | bibtex::COMMAND_NAME
+ | bibtex::ACCENT_NAME
+ ) =>
+ {
+ token.text().into()
}
Cursor::Bibtex(_) => "".into(),
Cursor::Nothing => "".into(),
@@ -200,36 +203,32 @@ fn score(context: &CursorContext<CompletionParams>, items: &mut Vec<InternalComp
matcher.fuzzy_match(name, &pattern)
}
InternalCompletionItemData::BeginCommand => matcher.fuzzy_match("begin", &pattern[1..]),
- InternalCompletionItemData::Citation { key, .. } => matcher.fuzzy_match(&key, &pattern),
+ InternalCompletionItemData::Citation { key, .. } => matcher.fuzzy_match(key, &pattern),
InternalCompletionItemData::ComponentCommand { name, .. } => {
matcher.fuzzy_match(name, &pattern[1..])
}
InternalCompletionItemData::ComponentEnvironment { name, .. } => {
matcher.fuzzy_match(name, &pattern)
}
- InternalCompletionItemData::Class { name } => matcher.fuzzy_match(&name, &pattern),
- InternalCompletionItemData::Package { name } => matcher.fuzzy_match(&name, &pattern),
- InternalCompletionItemData::Color { name } => matcher.fuzzy_match(&name, &pattern),
- InternalCompletionItemData::ColorModel { name } => matcher.fuzzy_match(&name, &pattern),
- InternalCompletionItemData::Acronym { name } => matcher.fuzzy_match(&name, &pattern),
+ InternalCompletionItemData::Class { name } => matcher.fuzzy_match(name, &pattern),
+ InternalCompletionItemData::Package { name } => matcher.fuzzy_match(name, &pattern),
+ InternalCompletionItemData::Color { name } => matcher.fuzzy_match(name, &pattern),
+ InternalCompletionItemData::ColorModel { name } => matcher.fuzzy_match(name, &pattern),
+ InternalCompletionItemData::Acronym { name } => matcher.fuzzy_match(name, &pattern),
InternalCompletionItemData::GlossaryEntry { name } => {
- matcher.fuzzy_match(&name, &pattern)
+ matcher.fuzzy_match(name, &pattern)
}
- InternalCompletionItemData::File { name } => matcher.fuzzy_match(&name, file_pattern),
+ InternalCompletionItemData::File { name } => matcher.fuzzy_match(name, file_pattern),
InternalCompletionItemData::Directory { name } => {
- matcher.fuzzy_match(&name, file_pattern)
- }
- InternalCompletionItemData::Label { name, .. } => matcher.fuzzy_match(&name, &pattern),
- InternalCompletionItemData::UserCommand { name } => {
- matcher.fuzzy_match(&name, &pattern[1..])
+ matcher.fuzzy_match(name, file_pattern)
}
+ InternalCompletionItemData::Label { name, .. } => matcher.fuzzy_match(name, &pattern),
+ InternalCompletionItemData::UserCommand { name } => matcher.fuzzy_match(name, &pattern),
InternalCompletionItemData::UserEnvironment { name } => {
- matcher.fuzzy_match(&name, &pattern)
- }
- InternalCompletionItemData::PgfLibrary { name } => matcher.fuzzy_match(&name, &pattern),
- InternalCompletionItemData::TikzLibrary { name } => {
- matcher.fuzzy_match(&name, &pattern)
+ matcher.fuzzy_match(name, &pattern)
}
+ InternalCompletionItemData::PgfLibrary { name } => matcher.fuzzy_match(name, &pattern),
+ InternalCompletionItemData::TikzLibrary { name } => matcher.fuzzy_match(name, &pattern),
};
}
}
@@ -239,7 +238,7 @@ fn preselect(
items: &mut [InternalCompletionItem],
) -> Option<()> {
let name = context.cursor.as_latex()?;
- let group = latex::CurlyGroupWord::cast(name.parent())?;
+ let group = latex::CurlyGroupWord::cast(name.parent()?)?;
let end = latex::End::cast(group.syntax().parent()?)?;
let environment = latex::Environment::cast(end.syntax().parent()?)?;
let name = environment.begin()?.name()?.key()?.to_string();
@@ -308,17 +307,16 @@ fn convert_internal_items(
data: Some(serde_json::to_value(CompletionItemData::Argument).unwrap()),
text_edit: Some(CompletionTextEdit::Edit(text_edit)),
documentation: image
- .and_then(|image| image_documentation(&context.request, &name, image)),
+ .and_then(|image| image_documentation(&context.request, name, image)),
..CompletionItem::default()
}
}
InternalCompletionItemData::BeginCommand => {
if context
.request
- .context
+ .workspace
+ .environment
.client_capabilities
- .lock()
- .unwrap()
.text_document
.as_ref()
.and_then(|cap| cap.completion.as_ref())
@@ -379,7 +377,7 @@ fn convert_internal_items(
|glyph| format!("{}, {}", glyph, component_detail(file_names)),
);
let documentation =
- image.and_then(|img| image_documentation(&context.request, &name, img));
+ image.and_then(|img| image_documentation(&context.request, name, img));
let text_edit = TextEdit::new(range, name.to_string());
CompletionItem {
kind: Some(adjust_kind(
@@ -459,7 +457,7 @@ fn convert_internal_items(
InternalCompletionItemData::Acronym { name } => {
let text_edit = TextEdit::new(range, name.to_string());
CompletionItem {
- label: name.into(),
+ label: name,
kind: Some(adjust_kind(
&context.request,
Structure::GlossaryEntry.completion_kind(),
@@ -472,7 +470,7 @@ fn convert_internal_items(
InternalCompletionItemData::GlossaryEntry { name } => {
let text_edit = TextEdit::new(range, name.to_string());
CompletionItem {
- label: name.into(),
+ label: name,
kind: Some(adjust_kind(
&context.request,
Structure::GlossaryEntry.completion_kind(),
@@ -517,7 +515,7 @@ fn convert_internal_items(
} => {
let text_edit = TextEdit::new(range, name.to_string());
CompletionItem {
- label: name.into(),
+ label: name,
kind: Some(adjust_kind(&context.request, kind.completion_kind())),
detail: header,
documentation: footer.map(Documentation::String),
@@ -530,6 +528,7 @@ fn convert_internal_items(
}
InternalCompletionItemData::UserCommand { name } => {
let detail = "user-defined".into();
+ let name = &name[1..];
let text_edit = TextEdit::new(range, name.to_string());
CompletionItem {
kind: Some(adjust_kind(
@@ -543,7 +542,7 @@ fn convert_internal_items(
}
InternalCompletionItemData::UserEnvironment { name } => {
let detail = "user-defined".into();
- let text_edit = TextEdit::new(range, name.to_string());
+ let text_edit = TextEdit::new(range, name.clone());
CompletionItem {
kind: Some(adjust_kind(
&context.request,
@@ -551,7 +550,7 @@ fn convert_internal_items(
)),
data: Some(serde_json::to_value(CompletionItemData::Environment).unwrap()),
text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::new_simple(name.into(), detail)
+ ..CompletionItem::new_simple(name, detail)
}
}
InternalCompletionItemData::PgfLibrary { name } => {