From 745892fbddea56040139108277e728b53fd8fc11 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Thu, 28 May 2020 03:03:21 +0000 Subject: CTAN sync 202005280303 --- support/texlab/src/completion/latex/include.rs | 190 +++++++++++++------------ 1 file changed, 97 insertions(+), 93 deletions(-) (limited to 'support/texlab/src/completion/latex/include.rs') diff --git a/support/texlab/src/completion/latex/include.rs b/support/texlab/src/completion/latex/include.rs index 2f4090b3f3..1a8555d07c 100644 --- a/support/texlab/src/completion/latex/include.rs +++ b/support/texlab/src/completion/latex/include.rs @@ -1,129 +1,133 @@ use super::combinators::{self, Parameter}; -use crate::completion::factory; -use crate::range::RangeExt; -use crate::syntax::*; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::{CompletionItem, CompletionParams, Range, TextEdit}; +use crate::{ + completion::types::{Item, ItemData}, + feature::FeatureRequest, + protocol::{CompletionParams, Range, RangeExt}, + syntax::{latex, AstNodeIndex, SyntaxNode, LANGUAGE_DATA}, +}; use std::path::{Path, PathBuf}; -use walkdir::WalkDir; +use tokio::fs; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct LatexIncludeCompletionProvider; +pub async fn complete_latex_includes<'a>( + req: &'a FeatureRequest, + items: &mut Vec>, +) { + let parameters = LANGUAGE_DATA.include_commands.iter().map(|cmd| Parameter { + name: &cmd.name[1..], + index: cmd.index, + }); -impl FeatureProvider for LatexIncludeCompletionProvider { - type Params = CompletionParams; - type Output = Vec; + combinators::argument_word(req, parameters, |cmd_node, index| async move { + if !req.current().is_file() { + return; + } - #[boxed] - async fn execute<'a>(&'a self, request: &'a FeatureRequest) -> Self::Output { - let parameters = LANGUAGE_DATA - .include_commands - .iter() - .map(|cmd| Parameter::new(&cmd.name, cmd.index)); + make_items(req, items, cmd_node, index).await; + }) + .await; +} - combinators::argument_word(request, parameters, |command, index| { - async move { - if !request.document().is_file() { - return Vec::new(); - } +async fn make_items<'a>( + req: &'a FeatureRequest, + items: &mut Vec>, + cmd_node: AstNodeIndex, + index: usize, +) -> Option<()> { + let table = req.current().content.as_latex()?; + let pos = req.params.text_document_position.position; + let path_word = table.extract_word(cmd_node, latex::GroupKind::Group, index); + let name_range = match path_word { + Some(path_word) => Range::new_simple( + path_word.start().line, + path_word.end().character - path_word.text().split('/').last()?.chars().count() as u64, + path_word.end().line, + path_word.end().character, + ), + None => Range::new(pos, pos), + }; - let position = request.params.text_document_position.position; - let mut items = Vec::new(); - let path_word = command.extract_word(index); - let name_range = match path_word { - Some(path_word) => Range::new_simple( - path_word.start().line, - path_word.end().character - - path_word.text().split('/').last().unwrap().chars().count() as u64, - path_word.end().line, - path_word.end().character, - ), - None => Range::new(position, position), - }; - let directory = current_directory(&request, &command); + let cmd = table.as_command(cmd_node)?; + let current_dir = current_dir(req, table, cmd_node)?; + let mut entries = fs::read_dir(current_dir).await.ok()?; + while let Some(entry) = entries.next_entry().await.ok()? { + let mut path = entry.path(); - for entry in WalkDir::new(directory) - .min_depth(1) - .max_depth(1) - .follow_links(false) - .into_iter() - .filter_map(std::result::Result::ok) - { - if entry.file_type().is_file() && is_included(&command, &entry.path()) { - let mut path = entry.into_path(); - let include_extension = LANGUAGE_DATA - .include_commands - .iter() - .find(|cmd| command.name.text() == cmd.name) - .unwrap() - .include_extension; + let file_type = entry.file_type().await.ok()?; + if file_type.is_file() && is_included(&cmd, &path) { + let include_extension = LANGUAGE_DATA + .include_commands + .iter() + .find(|c| cmd.name.text() == c.name)? + .include_extension; - if !include_extension { - remove_extension(&mut path); - } - let text_edit = make_text_edit(name_range, &path); - items.push(factory::file(request, &path, text_edit)); - } else if entry.file_type().is_dir() { - let path = entry.into_path(); - let text_edit = make_text_edit(name_range, &path); - items.push(factory::folder(request, &path, text_edit)); - } - } - items + if !include_extension { + remove_extension(&mut path); } - }) - .await + let name = path.file_name().unwrap().to_string_lossy().into_owned(); + let item = Item::new(name_range, ItemData::File { name }); + items.push(item); + } else if file_type.is_dir() { + let name = path.file_name().unwrap().to_string_lossy().into_owned(); + let item = Item::new(name_range, ItemData::Directory { name }); + items.push(item); + } } + Some(()) } -fn current_directory( - request: &FeatureRequest, - command: &LatexCommand, -) -> PathBuf { - let mut path = request.document().uri.to_file_path().unwrap(); - path = PathBuf::from(path.to_string_lossy().into_owned().replace('\\', "/")); +fn current_dir( + req: &FeatureRequest, + table: &latex::SymbolTable, + cmd_node: AstNodeIndex, +) -> Option { + let mut path = req + .options + .latex + .as_ref() + .and_then(|latex| latex.root_directory.as_ref()) + .map_or_else( + || { + let mut path = req.current().uri.to_file_path().unwrap(); + path.pop(); + path + }, + Clone::clone, + ); - path.pop(); - if let Some(include) = command.extract_word(0) { + path = PathBuf::from(path.to_str()?.replace('\\', "/")); + if let Some(include) = table.extract_word(cmd_node, latex::GroupKind::Group, 0) { path.push(include.text()); if !include.text().ends_with('/') { path.pop(); } } - path + Some(path) } -fn is_included(command: &LatexCommand, file: &Path) -> bool { +fn is_included(cmd: &latex::Command, file: &Path) -> bool { if let Some(allowed_extensions) = LANGUAGE_DATA .include_commands .iter() - .find(|cmd| command.name.text() == cmd.name) - .unwrap() - .kind - .extensions() + .find(|c| c.name == cmd.name.text()) + .and_then(|c| c.kind.extensions()) { file.extension() - .map(|extension| extension.to_string_lossy().to_lowercase()) - .map(|extension| allowed_extensions.contains(&extension.as_str())) - .unwrap_or(false) + .and_then(|ext| ext.to_str()) + .map(|ext| ext.to_lowercase()) + .map(|ext| allowed_extensions.contains(&ext.as_str())) + .unwrap_or_default() } else { true } } fn remove_extension(path: &mut PathBuf) { - let stem = path + if let Some(stem) = path .file_stem() - .map(|stem| stem.to_string_lossy().into_owned()); - - if let Some(stem) = stem { + .and_then(|stem| stem.to_str()) + .map(ToOwned::to_owned) + { path.pop(); - path.push(PathBuf::from(stem)); + path.push(stem); } } - -fn make_text_edit(range: Range, path: &Path) -> TextEdit { - let text = path.file_name().unwrap().to_string_lossy().into_owned(); - TextEdit::new(range, text) -} -- cgit v1.2.3