mirror of
https://github.com/latex-lsp/texlab.git
synced 2025-08-04 02:39:21 +00:00
Improve performance of command completion
This commit is contained in:
parent
48b2e7b6b4
commit
7eb1adcf92
3 changed files with 123 additions and 86 deletions
|
@ -39,15 +39,15 @@ impl Into<serde_json::Value> for CompletionItemData {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum LatexComponentId<'a> {
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum LatexComponentId {
|
||||
User,
|
||||
Component(Vec<&'a str>),
|
||||
Component(&'static [String]),
|
||||
}
|
||||
|
||||
impl<'a> LatexComponentId<'a> {
|
||||
impl LatexComponentId {
|
||||
pub fn kernel() -> Self {
|
||||
LatexComponentId::Component(vec![])
|
||||
LatexComponentId::Component(&[])
|
||||
}
|
||||
|
||||
pub fn detail(&self) -> String {
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
use super::combinators;
|
||||
use crate::factory::{self, LatexComponentId};
|
||||
use crate::{
|
||||
factory::{self, LatexComponentId},
|
||||
quality::QualityEvaluator,
|
||||
COMPLETION_LIMIT,
|
||||
};
|
||||
use futures_boxed::boxed;
|
||||
use texlab_feature::{FeatureProvider, FeatureRequest};
|
||||
use texlab_protocol::{CompletionItem, CompletionParams, TextEdit};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CommandItem {
|
||||
id: LatexComponentId,
|
||||
name: &'static str,
|
||||
image: &'static Option<String>,
|
||||
glyph: &'static Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
|
||||
pub struct LatexComponentCommandCompletionProvider;
|
||||
|
||||
|
@ -17,25 +29,40 @@ impl FeatureProvider for LatexComponentCommandCompletionProvider {
|
|||
let table = req.current().content.as_latex().unwrap();
|
||||
let cmd = table.as_command(cmd_node).unwrap();
|
||||
let range = cmd.short_name_range();
|
||||
let mut items = Vec::new();
|
||||
req.view.components();
|
||||
for comp in req.view.components() {
|
||||
let file_names = comp.file_names.iter().map(AsRef::as_ref).collect();
|
||||
let id = LatexComponentId::Component(file_names);
|
||||
for cmd in &comp.commands {
|
||||
let text_edit = TextEdit::new(range, (&cmd.name).into());
|
||||
let item = factory::command(
|
||||
req,
|
||||
(&cmd.name).into(),
|
||||
cmd.image.as_ref().map(AsRef::as_ref),
|
||||
cmd.glyph.as_ref().map(AsRef::as_ref),
|
||||
text_edit,
|
||||
&id,
|
||||
);
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
let pos = req.params.text_document_position.position;
|
||||
let eval = QualityEvaluator::parse(req.current(), pos);
|
||||
|
||||
let mut items: Vec<_> = req
|
||||
.view
|
||||
.components()
|
||||
.into_iter()
|
||||
.flat_map(|comp| {
|
||||
comp.commands.iter().map(move |cmd| CommandItem {
|
||||
id: LatexComponentId::Component(&comp.file_names),
|
||||
name: &cmd.name,
|
||||
image: &cmd.image,
|
||||
glyph: &cmd.glyph,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
items.sort_by_key(|item| -eval.quality_of(item.name, &None));
|
||||
items
|
||||
.into_iter()
|
||||
.take(COMPLETION_LIMIT)
|
||||
.map(|item| {
|
||||
let text_edit = TextEdit::new(range, item.name.into());
|
||||
let new_item = factory::command(
|
||||
req,
|
||||
item.name.into(),
|
||||
item.image.as_ref().map(AsRef::as_ref),
|
||||
item.glyph.as_ref().map(AsRef::as_ref),
|
||||
text_edit,
|
||||
&item.id,
|
||||
);
|
||||
new_item
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
@ -52,8 +79,7 @@ impl FeatureProvider for LatexComponentEnvironmentCompletionProvider {
|
|||
combinators::environment(req, |ctx| async move {
|
||||
let mut items = Vec::new();
|
||||
for comp in req.view.components() {
|
||||
let file_names = comp.file_names.iter().map(AsRef::as_ref).collect();
|
||||
let id = LatexComponentId::Component(file_names);
|
||||
let id = LatexComponentId::Component(&comp.file_names);
|
||||
for env in &comp.environments {
|
||||
let text_edit = TextEdit::new(ctx.range, env.into());
|
||||
let item = factory::environment(req, env.into(), text_edit, &id);
|
||||
|
|
|
@ -4,40 +4,64 @@ use texlab_feature::{Document, DocumentContent, FeatureProvider, FeatureRequest}
|
|||
use texlab_protocol::{CompletionItem, CompletionParams, Position, RangeExt};
|
||||
use texlab_syntax::{bibtex, latex, SyntaxNode};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct OrderByQualityCompletionProvider<F>(pub F);
|
||||
|
||||
impl<F> FeatureProvider for OrderByQualityCompletionProvider<F>
|
||||
where
|
||||
F: FeatureProvider<Params = CompletionParams, Output = Vec<CompletionItem>> + Send + Sync,
|
||||
{
|
||||
type Params = CompletionParams;
|
||||
type Output = Vec<CompletionItem>;
|
||||
|
||||
#[boxed]
|
||||
async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
|
||||
let query = Self::query(req.current(), req.params.text_document_position.position);
|
||||
let mut items = self.0.execute(req).await;
|
||||
items.sort_by_key(|item| -Self::get_quality(&query, &item));
|
||||
items
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct QualityEvaluator<'a> {
|
||||
query: Option<Cow<'a, str>>,
|
||||
}
|
||||
|
||||
impl<F> OrderByQualityCompletionProvider<F> {
|
||||
fn query(doc: &Document, pos: Position) -> Option<Cow<str>> {
|
||||
impl<'a> QualityEvaluator<'a> {
|
||||
pub fn quality_of(&self, label: &str, preselect: &Option<bool>) -> i32 {
|
||||
if *preselect == Some(true) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
if let Some(query) = &self.query {
|
||||
if label == query {
|
||||
return 7;
|
||||
}
|
||||
|
||||
if label.to_lowercase() == query.to_lowercase() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
if label.starts_with(query.as_ref()) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
if label.to_lowercase().starts_with(&query.to_lowercase()) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
if label.contains(query.as_ref()) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
if label.to_lowercase().contains(&query.to_lowercase()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(doc: &'a Document, pos: Position) -> Self {
|
||||
Self {
|
||||
query: Self::parse_query(doc, pos),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_query(doc: &'a Document, pos: Position) -> Option<Cow<'a, str>> {
|
||||
match &doc.content {
|
||||
DocumentContent::Latex(table) => {
|
||||
fn command_query(cmd: &latex::Command) -> Cow<str> {
|
||||
cmd.name.text()[1..].to_owned().into()
|
||||
}
|
||||
|
||||
if let Some(node) = table.find_command_by_short_name_range(pos) {
|
||||
return Some(command_query(table.as_command(node).unwrap()));
|
||||
return Some(Self::command_query(table.as_command(node).unwrap()));
|
||||
}
|
||||
|
||||
match &table[table.find(pos).into_iter().last()?] {
|
||||
latex::Node::Root(_) | latex::Node::Group(_) => Some("".into()),
|
||||
latex::Node::Command(cmd) => Some(command_query(cmd)),
|
||||
latex::Node::Command(cmd) => Some(Self::command_query(cmd)),
|
||||
latex::Node::Text(text) => text
|
||||
.words
|
||||
.iter()
|
||||
|
@ -79,40 +103,27 @@ impl<F> OrderByQualityCompletionProvider<F> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_quality(query: &Option<Cow<str>>, item: &CompletionItem) -> i32 {
|
||||
if item.preselect == Some(true) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
let label = &item.label;
|
||||
if let Some(query) = query {
|
||||
if label == query {
|
||||
return 7;
|
||||
}
|
||||
|
||||
if label.to_lowercase() == query.to_lowercase() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
if label.starts_with(query.as_ref()) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
if label.to_lowercase().starts_with(&query.to_lowercase()) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
if label.contains(query.as_ref()) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
if label.to_lowercase().contains(&query.to_lowercase()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
fn command_query(cmd: &'a latex::Command) -> Cow<'a, str> {
|
||||
cmd.name.text()[1..].to_owned().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct OrderByQualityCompletionProvider<F>(pub F);
|
||||
|
||||
impl<F> FeatureProvider for OrderByQualityCompletionProvider<F>
|
||||
where
|
||||
F: FeatureProvider<Params = CompletionParams, Output = Vec<CompletionItem>> + Send + Sync,
|
||||
{
|
||||
type Params = CompletionParams;
|
||||
type Output = Vec<CompletionItem>;
|
||||
|
||||
#[boxed]
|
||||
async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
|
||||
let pos = req.params.text_document_position.position;
|
||||
let eval = QualityEvaluator::parse(req.current(), pos);
|
||||
let mut items = self.0.execute(req).await;
|
||||
items.sort_by_key(|item| -eval.quality_of(&item.label, &item.preselect));
|
||||
items
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue