diff options
Diffstat (limited to 'support/texlab/src/completion/latex/combinators.rs')
-rw-r--r-- | support/texlab/src/completion/latex/combinators.rs | 169 |
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()) } |