summaryrefslogtreecommitdiff
path: root/support/texlab/src/completion/latex/combinators.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/completion/latex/combinators.rs')
-rw-r--r--support/texlab/src/completion/latex/combinators.rs169
1 files changed, 80 insertions, 89 deletions
diff --git a/support/texlab/src/completion/latex/combinators.rs b/support/texlab/src/completion/latex/combinators.rs
index 74337f85b6..d8ef336421 100644
--- a/support/texlab/src/completion/latex/combinators.rs
+++ b/support/texlab/src/completion/latex/combinators.rs
@@ -1,9 +1,10 @@
-use crate::range::RangeExt;
-use crate::syntax::*;
-use crate::workspace::*;
-use lsp_types::*;
+use crate::{
+ feature::FeatureRequest,
+ protocol::{CompletionParams, Position, Range, RangeExt},
+ syntax::{latex, AstNodeIndex, SyntaxNode, LANGUAGE_DATA},
+ workspace::DocumentContent,
+};
use std::future::Future;
-use std::sync::Arc;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Parameter<'a> {
@@ -11,142 +12,132 @@ pub struct Parameter<'a> {
pub index: usize,
}
-impl<'a> Parameter<'a> {
- pub fn new(name: &'a str, index: usize) -> Self {
- Self { name, index }
- }
-}
-
-pub async fn command<E, F>(
- request: &FeatureRequest<CompletionParams>,
- execute: E,
-) -> Vec<CompletionItem>
+pub async fn command<E, F>(req: &FeatureRequest<CompletionParams>, execute: E)
where
- E: FnOnce(Arc<LatexCommand>) -> F,
- F: Future<Output = Vec<CompletionItem>>,
+ E: FnOnce(AstNodeIndex) -> F,
+ F: Future<Output = ()>,
{
- if let SyntaxTree::Latex(tree) = &request.document().tree {
- if let Some(command) =
- tree.find_command_by_name(request.params.text_document_position.position)
- {
- return execute(command).await;
+ if let DocumentContent::Latex(table) = &req.current().content {
+ let pos = req.params.text_document_position.position;
+ if let Some(cmd) = table.find_command_by_short_name_range(pos) {
+ execute(cmd).await;
}
}
- Vec::new()
}
-#[derive(Debug, PartialEq, Eq, Clone)]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct ArgumentContext<'a> {
pub parameter: Parameter<'a>,
- pub command: Arc<LatexCommand>,
+ pub node: AstNodeIndex,
pub range: Range,
}
pub async fn argument<'a, I, E, F>(
- request: &'a FeatureRequest<CompletionParams>,
+ req: &'a FeatureRequest<CompletionParams>,
mut parameters: I,
execute: E,
-) -> Vec<CompletionItem>
-where
+) where
I: Iterator<Item = Parameter<'a>>,
E: FnOnce(ArgumentContext<'a>) -> F,
- F: Future<Output = Vec<CompletionItem>>,
+ F: Future<Output = ()>,
{
- if let SyntaxTree::Latex(tree) = &request.document().tree {
- let position = request.params.text_document_position.position;
- if let Some(command) = find_command(tree, position) {
- for parameter in parameters.by_ref() {
- if command.name.text() != parameter.name {
- continue;
- }
-
- if let Some(args) = command.args.get(parameter.index) {
- if args.right.is_some() && !args.range().contains_exclusive(position) {
+ if let DocumentContent::Latex(table) = &req.current().content {
+ let pos = req.params.text_document_position.position;
+ if let Some(node) = find_command(&table, pos) {
+ let cmd = table.as_command(node).unwrap();
+ for parameter in parameters
+ .by_ref()
+ .filter(|param| param.name == &cmd.name.text()[1..])
+ {
+ if let Some(args_node) =
+ table.extract_group(node, latex::GroupKind::Group, parameter.index)
+ {
+ let args = table.as_group(args_node).unwrap();
+ if args.right.is_some() && !args.range().contains_exclusive(pos) {
continue;
}
- let mut range = None;
- for child in &args.children {
- if let LatexContent::Text(text) = &child {
- for word in &text.words {
- if word.range().contains(position) {
- range = Some(word.range());
- break;
- }
- }
- }
- }
- let text_range = range.unwrap_or_else(|| Range::new(position, position));
+ let range = table
+ .children(args_node)
+ .filter_map(|child| table.as_text(child))
+ .flat_map(|text| text.words.iter())
+ .map(|word| word.range())
+ .find(|range| range.contains(pos))
+ .unwrap_or_else(|| Range::new(pos, pos));
+
let context = ArgumentContext {
parameter,
- command: Arc::clone(&command),
- range: text_range,
+ node,
+ range,
};
- return execute(context).await;
+ execute(context).await;
+ return;
}
}
}
}
- Vec::new()
}
pub async fn argument_word<'a, I, E, F>(
- request: &'a FeatureRequest<CompletionParams>,
+ req: &'a FeatureRequest<CompletionParams>,
mut parameters: I,
execute: E,
-) -> Vec<CompletionItem>
-where
+) where
I: Iterator<Item = Parameter<'a>>,
- E: FnOnce(Arc<LatexCommand>, usize) -> F,
- F: Future<Output = Vec<CompletionItem>>,
+ E: FnOnce(AstNodeIndex, usize) -> F,
+ F: Future<Output = ()>,
{
- if let SyntaxTree::Latex(tree) = &request.document().tree {
- let position = request.params.text_document_position.position;
- if let Some(command) = find_command(tree, position) {
- for parameter in parameters.by_ref() {
- if command.name.text() != parameter.name {
- continue;
- }
-
- if let Some(args) = command.args.get(parameter.index) {
- if args.right.is_some() && !args.range().contains_exclusive(position) {
+ if let DocumentContent::Latex(table) = &req.current().content {
+ let pos = req.params.text_document_position.position;
+ if let Some(node) = find_command(&table, pos) {
+ let cmd = table.as_command(node).unwrap();
+ for parameter in parameters
+ .by_ref()
+ .filter(|param| param.name == &cmd.name.text()[1..])
+ {
+ if let Some(args_node) =
+ table.extract_group(node, latex::GroupKind::Group, parameter.index)
+ {
+ let args = table.as_group(args_node).unwrap();
+ if args.right.is_some() && !args.range().contains_exclusive(pos) {
continue;
}
- if !args.children.is_empty() && !command.has_word(parameter.index) {
+ if table.children(args_node).next().is_some()
+ && table
+ .extract_word(node, latex::GroupKind::Group, parameter.index)
+ .is_none()
+ {
continue;
}
- return execute(Arc::clone(&command), parameter.index).await;
+ execute(node, parameter.index).await;
+ return;
}
}
}
}
- Vec::new()
}
-pub async fn environment<'a, E, F>(
- request: &'a FeatureRequest<CompletionParams>,
- execute: E,
-) -> Vec<CompletionItem>
+pub async fn environment<'a, E, F>(req: &'a FeatureRequest<CompletionParams>, execute: E)
where
E: FnOnce(ArgumentContext<'a>) -> F,
- F: Future<Output = Vec<CompletionItem>>,
+ F: Future<Output = ()>,
{
let parameters = LANGUAGE_DATA
.environment_commands
.iter()
- .map(|cmd| Parameter::new(&cmd.name, cmd.index));
- argument(request, parameters, execute).await
+ .map(|cmd| Parameter {
+ name: &cmd.name[1..],
+ index: cmd.index,
+ });
+ argument(req, parameters, execute).await;
}
-fn find_command(tree: &LatexSyntaxTree, position: Position) -> Option<Arc<LatexCommand>> {
- let mut nodes = tree.find(position);
- nodes.reverse();
- for node in nodes {
- if let LatexNode::Command(command) = node {
- return Some(command);
- }
- }
- None
+fn find_command(table: &latex::SymbolTable, pos: Position) -> Option<AstNodeIndex> {
+ table
+ .find(pos)
+ .into_iter()
+ .rev()
+ .find(|node| table.as_command(*node).is_some())
}