Skip to content

Commit

Permalink
Use language options in completion
Browse files Browse the repository at this point in the history
  • Loading branch information
pfoerster committed Jun 19, 2019
1 parent 11737cb commit da79979
Show file tree
Hide file tree
Showing 15 changed files with 164 additions and 105 deletions.
6 changes: 3 additions & 3 deletions src/completion/latex/argument_symbol.rs
@@ -1,5 +1,5 @@
use crate::completion::factory;
use crate::completion::latex::combinators;
use crate::completion::latex::combinators::{self, ArgumentLocation};
use crate::data::symbols::DATABASE;
use crate::feature::{FeatureProvider, FeatureRequest};
use futures_boxed::boxed;
Expand All @@ -18,9 +18,9 @@ impl FeatureProvider for LatexArgumentSymbolCompletionProvider {
let mut items = Vec::new();
for group in &DATABASE.arguments {
let command = format!("\\{}", group.command);
let command_names = &[command.as_ref()];
let location = ArgumentLocation::new(command.as_ref(), group.index);
items.append(
&mut combinators::argument(&request, command_names, group.index, async move |_| {
&mut combinators::argument(&request, std::iter::once(location), async move |_| {
let mut items = Vec::new();
for symbol in &group.arguments {
items.push(Arc::new(factory::create_argument_symbol(
Expand Down
10 changes: 7 additions & 3 deletions src/completion/latex/citation.rs
@@ -1,7 +1,6 @@
use crate::completion::factory;
use crate::completion::latex::combinators;
use crate::completion::latex::combinators::{self, ArgumentLocation};
use crate::feature::{FeatureProvider, FeatureRequest};
use crate::syntax::latex::CITATION_COMMANDS;
use crate::syntax::SyntaxTree;
use futures_boxed::boxed;
use lsp_types::{CompletionItem, CompletionParams};
Expand All @@ -16,7 +15,12 @@ impl FeatureProvider for LatexCitationCompletionProvider {

#[boxed]
async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
combinators::argument(request, CITATION_COMMANDS, 0, async move |_| {
let locations = request
.latex_language_options
.citation_commands()
.map(|cmd| ArgumentLocation::new(&cmd.name, cmd.index));

combinators::argument(request, locations, async move |_| {
let mut items = Vec::new();
for document in request.related_documents() {
if let SyntaxTree::Bibtex(tree) = &document.tree {
Expand Down
37 changes: 24 additions & 13 deletions src/completion/latex/color.rs
@@ -1,28 +1,39 @@
use crate::completion::factory;
use crate::completion::latex::combinators;
use crate::completion::latex::combinators::{self, ArgumentLocation};
use crate::feature::{FeatureProvider, FeatureRequest};
use futures_boxed::boxed;
use lsp_types::{CompletionItem, CompletionParams};
use std::borrow::Cow;
use std::sync::Arc;

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct LatexColorCompletionProvider;
#[derive(Debug, PartialEq, Clone)]
pub struct LatexColorCompletionProvider {
items: Vec<Arc<CompletionItem>>,
}

impl LatexColorCompletionProvider {
pub fn new() -> Self {
let items = COLOR_NAMES
.iter()
.map(|name| factory::create_color(Cow::from(*name)))
.map(Arc::new)
.collect();

Self { items }
}
}

impl FeatureProvider for LatexColorCompletionProvider {
type Params = CompletionParams;
type Output = Vec<Arc<CompletionItem>>;

#[boxed]
async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
combinators::argument(request, &COLOR_COMMANDS, 0, async move |_| {
COLOR_NAMES
.iter()
.map(|name| factory::create_color(Cow::from(*name)))
.map(Arc::new)
.collect()
})
.await
let locations = COLOR_COMMANDS
.iter()
.map(|cmd| ArgumentLocation::new(cmd, 0));

combinators::argument(request, locations, async move |_| self.items.clone()).await
}
}

Expand Down Expand Up @@ -134,7 +145,7 @@ mod tests {
#[test]
fn test_inside_color() {
let items = test_feature(
LatexColorCompletionProvider,
LatexColorCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.tex", "\\color{}")],
main_file: "foo.tex",
Expand All @@ -148,7 +159,7 @@ mod tests {
#[test]
fn test_outside_color() {
let items = test_feature(
LatexColorCompletionProvider,
LatexColorCompletionProvider::new(),
FeatureSpec {
files: vec![FeatureSpec::file("foo.tex", "\\color{}")],
main_file: "foo.tex",
Expand Down
43 changes: 17 additions & 26 deletions src/completion/latex/color_model.rs
@@ -1,5 +1,5 @@
use crate::completion::factory;
use crate::completion::latex::combinators;
use crate::completion::latex::combinators::{self, ArgumentLocation};
use crate::feature::{FeatureProvider, FeatureRequest};
use futures_boxed::boxed;
use lsp_types::{CompletionItem, CompletionParams};
Expand All @@ -21,26 +21,6 @@ impl LatexColorModelCompletionProvider {
.collect();
Self { items }
}

async fn execute_define_color<'a>(
&'a self,
request: &'a FeatureRequest<CompletionParams>,
) -> Vec<Arc<CompletionItem>> {
combinators::argument(&request, &COMMAND_NAMES[0..1], 1, async move |_| {
self.items.clone()
})
.await
}

async fn execute_define_color_set<'a>(
&'a self,
request: &'a FeatureRequest<CompletionParams>,
) -> Vec<Arc<CompletionItem>> {
combinators::argument(&request, &COMMAND_NAMES[1..2], 0, async move |_| {
self.items.clone()
})
.await
}
}

impl FeatureProvider for LatexColorModelCompletionProvider {
Expand All @@ -49,14 +29,25 @@ impl FeatureProvider for LatexColorModelCompletionProvider {

#[boxed]
async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
let mut items = Vec::new();
items.append(&mut self.execute_define_color(&request).await);
items.append(&mut self.execute_define_color_set(&request).await);
items
combinators::argument(
&request,
LOCATIONS.iter().map(|location| *location),
async move |_| self.items.clone(),
)
.await
}
}

const COMMAND_NAMES: &[&str] = &["\\definecolor", "\\definecolorset"];
const LOCATIONS: &[ArgumentLocation] = &[
ArgumentLocation {
name: "\\definecolor",
index: 1,
},
ArgumentLocation {
name: "\\definecolorset",
index: 0,
},
];

const MODEL_NAMES: &[&str] = &["gray", "rgb", "RGB", "HTML", "cmyk"];

Expand Down
79 changes: 49 additions & 30 deletions src/completion/latex/combinators.rs
Expand Up @@ -20,55 +20,70 @@ where
Vec::new()
}

pub async fn argument<'a, E, F>(
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct ArgumentLocation<'a> {
pub name: &'a str,
pub index: usize,
}

impl<'a> ArgumentLocation<'a> {
pub fn new(name: &'a str, index: usize) -> Self {
Self { name, index }
}
}

pub async fn argument<'a, I, E, F>(
request: &'a FeatureRequest<CompletionParams>,
command_names: &'a [&'a str],
argument_index: usize,
mut locations: I,
execute: E,
) -> Vec<Arc<CompletionItem>>
where
I: Iterator<Item = ArgumentLocation<'a>>,
E: FnOnce(Arc<LatexCommand>) -> F,
F: std::future::Future<Output = Vec<Arc<CompletionItem>>>,
{
let find_command = |nodes: &[LatexNode], node_index: usize| {
let mut find_command = |nodes: &[LatexNode], node_index: usize| {
if let LatexNode::Group(group) = &nodes[node_index] {
if let LatexNode::Command(command) = nodes[node_index + 1].clone() {
if command_names.contains(&command.name.text())
&& command.args.len() > argument_index
&& &command.args[argument_index] == group
{
return Some(command);
for location in locations.by_ref() {
if command.name.text() == location.name
&& command.args.len() > location.index
&& &command.args[location.index] == group
{
return Some((command, location.index));
}
}
}
}
None
};

let find_non_empty_command = |nodes: &[LatexNode]| {
if nodes.len() >= 3 {
if let LatexNode::Text(_) = nodes[0] {
return find_command(nodes, 1);
}
}
None
};

let find_empty_command = |nodes: &[LatexNode]| {
if nodes.len() >= 2 {
find_command(nodes, 0)
} else {
None
}
};

if let SyntaxTree::Latex(tree) = &request.document().tree {
let mut nodes = tree.find(request.params.position);
nodes.reverse();

let command = find_non_empty_command(&nodes).or_else(|| find_empty_command(&nodes));
let result1 = {
if nodes.len() >= 3 {
if let LatexNode::Text(_) = nodes[0] {
find_command(&nodes, 1)
} else {
None
}
} else {
None
}
};

let result2 = {
if nodes.len() >= 2 {
find_command(&nodes, 0)
} else {
None
}
};

if let Some(command) = command {
if command.args[argument_index]
if let Some((command, index)) = result1.or(result2) {
if command.args[index]
.range
.contains_exclusive(request.params.position)
{
Expand All @@ -87,5 +102,9 @@ where
E: FnOnce(Arc<LatexCommand>) -> F,
F: std::future::Future<Output = Vec<Arc<CompletionItem>>>,
{
argument(&request, &ENVIRONMENT_COMMANDS, 0, execute).await
let locations = request
.latex_language_options
.environment_commands()
.map(|cmd| ArgumentLocation::new(&cmd.name, cmd.index));
argument(request, locations, execute).await
}
3 changes: 1 addition & 2 deletions src/completion/latex/command_symbol.rs
@@ -1,5 +1,4 @@
use crate::completion::factory;
use crate::completion::factory::LatexComponentId;
use crate::completion::factory::{self, LatexComponentId};
use crate::completion::latex::combinators;
use crate::data::symbols::DATABASE;
use crate::feature::{FeatureProvider, FeatureRequest};
Expand Down
36 changes: 20 additions & 16 deletions src/completion/latex/import.rs
@@ -1,5 +1,6 @@
use crate::completion::factory;
use crate::completion::latex::combinators;
use crate::completion::latex::combinators::{self, ArgumentLocation};
use crate::data::language::LatexIncludeKind;
use crate::feature::{FeatureProvider, FeatureRequest};
use futures_boxed::boxed;
use lsp_types::{CompletionItem, CompletionParams};
Expand All @@ -10,47 +11,50 @@ use std::sync::Arc;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct LatexClassImportProvider;

impl LatexClassImportProvider {
const COMMANDS: &'static [&'static str] = &["\\documentclass"];
}

impl FeatureProvider for LatexClassImportProvider {
type Params = CompletionParams;
type Output = Vec<Arc<CompletionItem>>;

#[boxed]
async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
import(request, Self::COMMANDS, "cls", factory::create_class).await
import(request, LatexIncludeKind::Class, factory::create_class).await
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct LatexPackageImportProvider;

impl LatexPackageImportProvider {
const COMMANDS: &'static [&'static str] = &["\\usepackage"];
}

impl FeatureProvider for LatexPackageImportProvider {
type Params = CompletionParams;
type Output = Vec<Arc<CompletionItem>>;

#[boxed]
async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
import(request, Self::COMMANDS, "sty", factory::create_class).await
import(request, LatexIncludeKind::Package, factory::create_class).await
}
}

pub async fn import<'a, F>(
request: &'a FeatureRequest<CompletionParams>,
commands: &'a [&str],
extension: &'a str,
async fn import<F>(
request: &FeatureRequest<CompletionParams>,
kind: LatexIncludeKind,
factory: F,
) -> Vec<Arc<CompletionItem>>
where
F: Fn(Cow<'static, str>) -> CompletionItem,
{
combinators::argument(request, &commands, 0, async move |_| {
let extension = if kind == LatexIncludeKind::Package {
"sty"
} else {
"cls"
};

let locations = request
.latex_language_options
.include_commands()
.filter(|cmd| cmd.kind == kind)
.map(|cmd| ArgumentLocation::new(&cmd.name, cmd.index));

combinators::argument(request, locations, async move |_| {
request
.resolver
.files_by_name
Expand Down
5 changes: 3 additions & 2 deletions src/completion/latex/include.rs
@@ -1,5 +1,5 @@
use crate::completion::factory;
use crate::completion::latex::combinators;
use crate::completion::latex::combinators::{self, ArgumentLocation};
use crate::feature::{FeatureProvider, FeatureRequest};
use crate::syntax::latex::LatexCommand;
use futures_boxed::boxed;
Expand Down Expand Up @@ -28,7 +28,8 @@ impl FeatureProvider for LatexIncludeCompletionProvider {

#[boxed]
async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
combinators::argument(request, ALL_COMMANDS, 0, async move |command| {
let locations = ALL_COMMANDS.iter().map(|cmd| ArgumentLocation::new(cmd, 0));
combinators::argument(request, locations, async move |command| {
if !request.document().is_file() {
return Vec::new();
}
Expand Down
3 changes: 1 addition & 2 deletions src/completion/latex/kernel_command.rs
@@ -1,5 +1,4 @@
use crate::completion::factory;
use crate::completion::factory::LatexComponentId;
use crate::completion::factory::{self, LatexComponentId};
use crate::completion::latex::combinators;
use crate::data::kernel_primitives::KERNEL_COMMANDS;
use crate::feature::{FeatureProvider, FeatureRequest};
Expand Down

0 comments on commit da79979

Please sign in to comment.