From 1e1cfb167545aa34c100a1e148ede04b42fabcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20F=C3=B6rster?= Date: Sat, 8 Jun 2019 18:44:51 +0200 Subject: [PATCH] Use TeX dist package manager to resolve files --- Cargo.lock | 1 - Cargo.toml | 1 - src/action.rs | 2 +- src/completion/latex/import.rs | 41 ++++--- src/distribution/ini.rs | 193 +++++++++++++++++++++++++++++++++ src/distribution/miktex.rs | 57 ++++++++++ src/distribution/mod.rs | 89 +++++++++++++++ src/distribution/texlive.rs | 8 ++ src/feature.rs | 22 ++-- src/lib.rs | 2 +- src/resolver/miktex.rs | 85 --------------- src/resolver/mod.rs | 97 ----------------- src/resolver/texlive.rs | 36 ------ src/server.rs | 32 +++--- 14 files changed, 401 insertions(+), 265 deletions(-) create mode 100644 src/distribution/ini.rs create mode 100644 src/distribution/miktex.rs create mode 100644 src/distribution/mod.rs create mode 100644 src/distribution/texlive.rs delete mode 100644 src/resolver/miktex.rs delete mode 100644 src/resolver/mod.rs delete mode 100644 src/resolver/texlive.rs diff --git a/Cargo.lock b/Cargo.lock index 1eaeb931d..b3b879697 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1647,7 +1647,6 @@ dependencies = [ name = "texlab" version = "0.1.0" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "copy_dir 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index cfb25ee17..156a394df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ members = ["./jsonrpc", "./jsonrpc_derive"] [dependencies] bytes = "0.4.12" -byteorder = "1" clap = "2.33" copy_dir = "0.1.2" futures-boxed = { path = "futures_boxed" } diff --git a/src/action.rs b/src/action.rs index cb48ba267..176dd6c6a 100644 --- a/src/action.rs +++ b/src/action.rs @@ -6,7 +6,7 @@ use std::sync::Mutex; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Action { RegisterCapabilities, - LoadResolver, + LoadDistribution, ResolveIncludes, PublishDiagnostics, RunLinter(Uri), diff --git a/src/completion/latex/import.rs b/src/completion/latex/import.rs index 90f3cff0c..7d2d0caca 100644 --- a/src/completion/latex/import.rs +++ b/src/completion/latex/import.rs @@ -52,13 +52,13 @@ where { LatexCombinators::argument(request, &commands, 0, async move |_| { request - .resolver - .files_by_name - .values() + .distribution + .packages + .iter() + .flat_map(|package| &package.run_files) .filter(|file| file.extension().and_then(OsStr::to_str) == Some(extension)) - .flat_map(|file| file.file_stem().unwrap().to_str()) - .map(|name| factory(Cow::from(name.to_owned()))) - .map(Arc::new) + .map(|file| file.file_stem().unwrap().to_str().unwrap()) + .map(|name| Arc::new(factory(Cow::from(name.to_owned())))) .collect() }) .await @@ -67,18 +67,27 @@ where #[cfg(test)] mod tests { use super::*; + use crate::distribution::{PackageManifest, TexDistribution}; use crate::feature::{test_feature, FeatureSpec}; - use crate::resolver::TexResolver; use lsp_types::Position; - use std::collections::HashMap; - use std::ffi::OsString; use std::path::PathBuf; - fn create_resolver() -> TexResolver { - let mut files_by_name = HashMap::new(); - files_by_name.insert(OsString::from("foo.sty"), PathBuf::from("./foo.sty")); - files_by_name.insert(OsString::from("bar.cls"), PathBuf::from("./bar.cls")); - TexResolver { files_by_name } + fn create_distribution() -> TexDistribution { + let packages = vec![ + PackageManifest { + run_files: vec![PathBuf::from("./foo.sty")], + ..PackageManifest::default() + }, + PackageManifest { + run_files: vec![PathBuf::from("./bar.cls")], + ..PackageManifest::default() + }, + ]; + + TexDistribution { + packages, + ..TexDistribution::default() + } } #[test] @@ -89,7 +98,7 @@ mod tests { files: vec![FeatureSpec::file("foo.tex", "\\documentclass{}")], main_file: "foo.tex", position: Position::new(0, 15), - resolver: create_resolver(), + distribution: create_distribution(), ..FeatureSpec::default() }, ); @@ -106,7 +115,7 @@ mod tests { files: vec![FeatureSpec::file("foo.tex", "\\usepackage{}")], main_file: "foo.tex", position: Position::new(0, 12), - resolver: create_resolver(), + distribution: create_distribution(), ..FeatureSpec::default() }, ); diff --git a/src/distribution/ini.rs b/src/distribution/ini.rs new file mode 100644 index 000000000..932fb3716 --- /dev/null +++ b/src/distribution/ini.rs @@ -0,0 +1,193 @@ +use std::collections::HashMap; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Value<'a> { + String(&'a str), + Array(Vec<&'a str>), +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Section<'a> { + pub name: &'a str, + pub entries: HashMap<&'a str, Value<'a>>, +} + +impl<'a> Section<'a> { + pub fn get_string_value(&self, key: &str) -> Option<&str> { + match &self.entries.get(key)? { + Value::String(value) => Some(value), + Value::Array(_) => None, + } + } + + pub fn get_array_value(&self, key: &str) -> Option<&Vec<&str>> { + match &self.entries.get(key)? { + Value::String(_) => None, + Value::Array(values) => Some(values), + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Ini<'a> { + pub sections: Vec>, +} + +pub mod parser { + use super::*; + use nom::branch::alt; + use nom::bytes::complete::{tag, take_till1}; + use nom::character::complete::{multispace1, not_line_ending}; + use nom::combinator::{map, opt}; + use nom::multi::{fold_many0, many0, many1}; + use nom::IResult; + + pub fn parse(input: &str) -> IResult<&str, Ini> { + let (input, _) = trivia(input)?; + let (input, sections) = many0(section)(input)?; + Ok((input, Ini { sections })) + } + + fn section(input: &str) -> IResult<&str, Section> { + let (input, _) = tag("[")(input)?; + let (input, name) = ident(input)?; + let (input, _) = tag("]")(input)?; + let (input, _) = trivia(input)?; + let (input, entries) = many1(entry)(input)?; + let (input, _) = trivia(input)?; + Ok(( + input, + Section { + name, + entries: entries.into_iter().collect(), + }, + )) + } + + fn entry(input: &str) -> IResult<&str, (&str, Value)> { + let (input, key) = ident(input)?; + let (input, is_array) = map(opt(tag("[]")), |x| x.is_some())(input)?; + let (input, _) = tag("=")(input)?; + let (input, value) = not_line_ending(input)?; + let (input, _) = trivia(input)?; + + let (input, value) = if is_array { + let add_to_vec = |mut acc: Vec<_>, item| { + acc.push(item); + acc + }; + + let (input, values) = fold_many0(array_value(key), vec![value], add_to_vec)(input)?; + (input, Value::Array(values)) + } else { + (input, Value::String(value)) + }; + + Ok((input, (key, value))) + } + + fn array_value(key: &str) -> impl Fn(&str) -> IResult<&str, &str> + '_ { + move |input: &str| { + let (input, _) = tag(key)(input)?; + let (input, _) = tag("[]")(input)?; + let (input, _) = tag("=")(input)?; + let (input, value) = not_line_ending(input)?; + let (input, _) = trivia(input)?; + Ok((input, value)) + } + } + + fn ident(input: &str) -> IResult<&str, &str> { + take_till1(|c| ";[]=\r\n".contains(c))(input) + } + + fn trivia(input: &str) -> IResult<&str, ()> { + map(many0(alt((multispace1, comment))), |_| ())(input) + } + + fn comment(input: &str) -> IResult<&str, &str> { + let (input, _) = tag(";")(input)?; + not_line_ending(input) + } + + #[cfg(test)] + mod tests { + use super::*; + + #[test] + fn test_parse_comment() { + let (input, result) = comment(";foo").unwrap(); + assert!(input.is_empty()); + assert_eq!(result, "foo"); + } + + #[test] + fn test_parse_trivia() { + let (input, _) = trivia(";foo\r\n \r\n").unwrap(); + assert!(input.is_empty()); + } + + #[test] + fn test_parse_ident() { + let id = "_foo-bar"; + let (input, result) = ident(id).unwrap(); + assert!(input.is_empty()); + assert_eq!(result, id); + } + + #[test] + fn test_parse_entry_string() { + let input = format!("foo=[bar]\r\n"); + let (input, (key, value)) = entry(&input).unwrap(); + assert!(input.is_empty()); + assert_eq!(key, "foo"); + match value { + Value::String(value) => assert_eq!(value, "[bar]"), + Value::Array(_) => panic!("Expected String"), + }; + } + + #[test] + fn test_parse_entry_array() { + let input = format!("foo[]=bar\r\n"); + let (input, (key, value)) = entry(&input).unwrap(); + assert!(input.is_empty()); + assert_eq!(key, "foo"); + match value { + Value::String(_) => panic!("Expected Array"), + Value::Array(values) => { + assert_eq!(values.len(), 1); + assert_eq!(values[0], "bar"); + } + }; + } + + #[test] + fn test_parse_section() { + let (input, result) = section("[foo]\r\nfoo[]=bar\r\nfoo[]=baz\r\nbaz=\r\n").unwrap(); + assert!(input.is_empty()); + assert_eq!(result.entries.len(), 2); + assert!(result.entries.contains_key("foo")); + assert!(result.entries.contains_key("baz")); + + match &result.entries["foo"] { + Value::String(_) => { + panic!("Expected Array"); + } + Value::Array(values) => { + assert_eq!(values.len(), 2); + assert_eq!(values[0], "bar"); + assert_eq!(values[1], "baz"); + } + }; + } + + #[test] + fn test_parse() { + let (input, result) = + parse(";foo\r\n[foo]\r\nfoo=bar\r\n[bar]\r\nbar=baz\r\n").unwrap(); + assert!(input.is_empty()); + assert_eq!(result.sections.len(), 2); + } + } +} diff --git a/src/distribution/miktex.rs b/src/distribution/miktex.rs new file mode 100644 index 000000000..eeafe6555 --- /dev/null +++ b/src/distribution/miktex.rs @@ -0,0 +1,57 @@ +use super::ini; +use super::*; +use std::fs; +use std::path::Path; + +pub const DATABASE_PATH: &str = "miktex/config/package-manifests.ini"; +const INSTALLED_PATH: &str = "miktex/config/packages.ini"; + +pub fn read_database(file: &Path, root_dir: &Path) -> Option> { + let manifests = fs::read_to_string(&file).ok()?; + let (_, manifests) = ini::parser::parse(&manifests).ok()?; + + let installed = fs::read_to_string(&root_dir.join(INSTALLED_PATH)).ok()?; + let (_, installed) = ini::parser::parse(&installed).ok()?; + + let packages = manifests + .sections + .into_iter() + .filter(|x| !x.name.starts_with('_')) + .flat_map(|x| read_manifest(&x, &installed, root_dir)) + .collect(); + + Some(packages) +} + +fn read_manifest( + section: &ini::Section, + installed: &ini::Ini, + root_dir: &Path, +) -> Option { + let name = section.name.to_owned(); + let title = section.get_string_value("title")?.to_owned(); + let description = section + .get_array_value("description") + .and_then(|x| x.first()) + .map(|x| x.to_string()); + let doc_files = section + .get_array_value("doc")? + .iter() + .map(|x| root_dir.join(x)) + .collect(); + let run_files = section + .get_array_value("run")? + .iter() + .map(|x| root_dir.join(x)) + .collect(); + let is_installed = installed.sections.iter().any(|x| x.name == name); + + Some(PackageManifest { + name, + title, + description, + doc_files, + run_files, + is_installed, + }) +} diff --git a/src/distribution/mod.rs b/src/distribution/mod.rs new file mode 100644 index 000000000..db738090f --- /dev/null +++ b/src/distribution/mod.rs @@ -0,0 +1,89 @@ +use std::path::{Path, PathBuf}; +use std::process::Command; + +mod ini; +mod miktex; +mod texlive; + +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub struct PackageManifest { + pub name: String, + pub title: String, + pub description: Option, + pub doc_files: Vec, + pub run_files: Vec, + pub is_installed: bool, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum TexDistributionKind { + Texlive, + Miktex, +} + +impl Default for TexDistributionKind { + fn default() -> Self { + TexDistributionKind::Texlive + } +} + +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub struct TexDistribution { + pub kind: TexDistributionKind, + pub packages: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Error { + KpsewhichNotFound, + UnsupportedTexDistribution, + CorruptPackageDatabase, +} + +pub type Result = std::result::Result; + +impl TexDistribution { + pub fn load() -> Result { + let root_dir = Self::query_path_variable("TEXMFDIST")?; + let (file, kind) = Self::find_database(&root_dir)?; + let packages = match kind { + TexDistributionKind::Texlive => texlive::read_database(&file, &root_dir), + TexDistributionKind::Miktex => miktex::read_database(&file, &root_dir), + } + .ok_or(Error::CorruptPackageDatabase)?; + + Ok(Self { kind, packages }) + } + + fn query_path_variable(var: &str) -> Result { + let output = Command::new("kpsewhich") + .args(&["-var-value", var]) + .output() + .map_err(|_| Error::KpsewhichNotFound)?; + + let path = PathBuf::from( + String::from_utf8(output.stdout) + .expect("Could not decode output from kpsewhich") + .lines() + .nth(0) + .expect("Invalid output from kpsewhich") + .to_owned(), + ); + + Ok(path) + } + + fn find_database(directory: &Path) -> Result<(PathBuf, TexDistributionKind)> { + let texlive_file = directory.join(texlive::DATABASE_PATH); + if texlive_file.is_file() { + return Ok((texlive_file, TexDistributionKind::Texlive)); + } + + let miktex_file = directory.join(miktex::DATABASE_PATH); + if miktex_file.is_file() { + return Ok((miktex_file, TexDistributionKind::Miktex)); + } + + Err(Error::UnsupportedTexDistribution) + } +} diff --git a/src/distribution/texlive.rs b/src/distribution/texlive.rs new file mode 100644 index 000000000..a441c6471 --- /dev/null +++ b/src/distribution/texlive.rs @@ -0,0 +1,8 @@ +use super::*; +use std::path::Path; + +pub const DATABASE_PATH: &str = "../tlpkg/texlive.tlpdb"; + +pub fn read_database(file: &Path, root_dir: &Path) -> Option> { + unimplemented!() +} diff --git a/src/feature.rs b/src/feature.rs index aa2d7779d..551491e4b 100644 --- a/src/feature.rs +++ b/src/feature.rs @@ -1,5 +1,5 @@ use crate::data::completion::LatexComponentDatabase; -use crate::resolver::TexResolver; +use crate::distribution::TexDistribution; #[cfg(test)] use crate::workspace::WorkspaceBuilder; use crate::workspace::{Document, Workspace}; @@ -16,7 +16,7 @@ pub struct FeatureRequest

{ pub workspace: Arc, pub document: Arc, pub related_documents: Vec>, - pub resolver: Arc, + pub distribution: Arc, pub component_database: Arc, } @@ -25,7 +25,7 @@ impl

FeatureRequest

{ params: P, workspace: Arc, document: Arc, - resolver: Arc, + distribution: Arc, component_database: Arc, ) -> Self { let related_documents = workspace.related_documents(&document.uri); @@ -34,7 +34,7 @@ impl

FeatureRequest

{ workspace, document, related_documents, - resolver, + distribution, component_database, } } @@ -126,7 +126,7 @@ pub struct FeatureSpec { pub main_file: &'static str, pub position: Position, pub new_name: &'static str, - pub resolver: TexResolver, + pub distribution: TexDistribution, pub component_database: LatexComponentDatabase, } @@ -167,7 +167,7 @@ impl Into> for FeatureSpec { params, workspace, document, - Arc::new(self.resolver), + Arc::new(self.distribution), Arc::new(self.component_database), ) } @@ -186,7 +186,7 @@ impl Into> for FeatureSpec { params, workspace, document, - Arc::new(self.resolver), + Arc::new(self.distribution), Arc::new(self.component_database), ) } @@ -203,7 +203,7 @@ impl Into> for FeatureSpec { params, workspace, document, - Arc::new(self.resolver), + Arc::new(self.distribution), Arc::new(self.component_database), ) } @@ -220,7 +220,7 @@ impl Into> for FeatureSpec { params, workspace, document, - Arc::new(self.resolver), + Arc::new(self.distribution), Arc::new(self.component_database), ) } @@ -241,7 +241,7 @@ impl Into> for FeatureSpec { params, workspace, document, - Arc::new(self.resolver), + Arc::new(self.distribution), Arc::new(self.component_database), ) } @@ -260,7 +260,7 @@ impl Into> for FeatureSpec { params, workspace, document, - Arc::new(self.resolver), + Arc::new(self.distribution), Arc::new(self.component_database), ) } diff --git a/src/lib.rs b/src/lib.rs index f8eb1eeeb..9e42b44dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub mod completion; pub mod data; pub mod definition; pub mod diagnostics; +pub mod distribution; pub mod feature; pub mod folding; pub mod formatting; @@ -17,7 +18,6 @@ pub mod hover; pub mod link; pub mod reference; pub mod rename; -pub mod resolver; pub mod scenario; pub mod server; pub mod syntax; diff --git a/src/resolver/miktex.rs b/src/resolver/miktex.rs deleted file mode 100644 index bbd6ab828..000000000 --- a/src/resolver/miktex.rs +++ /dev/null @@ -1,85 +0,0 @@ -use super::{Error, Result}; -use byteorder::{LittleEndian, ReadBytesExt}; -use lazy_static::lazy_static; -use regex::Regex; -use std::fs; -use std::io; -use std::io::Cursor; -use std::path::{Path, PathBuf}; - -pub const DATABASE_PATH: &str = "miktex/data/le"; -const FNDB_SIGNATURE: u32 = 0x42444e46; -const FNDB_WORD_SIZE: usize = 4; -const FNDB_TABLE_POINTER_OFFSET: usize = 4 * FNDB_WORD_SIZE; -const FNDB_TABLE_SIZE_OFFSET: usize = 6 * FNDB_WORD_SIZE; -const FNDB_ENTRY_SIZE: usize = 4 * FNDB_WORD_SIZE; - -lazy_static! { - static ref FNDB_REGEX: Regex = Regex::new(r#".*\.fndb-\d+"#).unwrap(); -} - -pub fn read_database(directory: &Path, root_directories: &[PathBuf]) -> Result> { - let database_directory = directory.join(DATABASE_PATH); - if !database_directory.exists() { - return Ok(Vec::new()); - } - - let mut database = Vec::new(); - let files = fs::read_dir(database_directory) - .expect("Could not traverse database directory") - .filter_map(|x| x.ok()) - .filter(|x| FNDB_REGEX.is_match(x.file_name().to_str().unwrap())); - - for file in files { - let bytes = fs::read(file.path()).expect("Could not read fndb file"); - database.extend( - parse_database(root_directories, &bytes).map_err(|_| Error::CorruptFileDatabase)?, - ); - } - - Ok(database) -} - -fn parse_database(root_directories: &[PathBuf], bytes: &[u8]) -> io::Result> { - let mut reader = Cursor::new(bytes); - if reader.read_u32::()? != FNDB_SIGNATURE { - return Err(io::Error::from(io::ErrorKind::InvalidData)); - } - - reader.set_position(FNDB_TABLE_POINTER_OFFSET as u64); - let table_address = reader.read_u32::()?; - - reader.set_position(FNDB_TABLE_SIZE_OFFSET as u64); - let table_size = reader.read_u32::()?; - - let mut files = Vec::new(); - for i in 0..table_size { - let offset = table_address + i * FNDB_ENTRY_SIZE as u32; - reader.set_position(offset as u64); - let file_name_offset = reader.read_u32::()? as usize; - let directory_offset = reader.read_u32::()? as usize; - let file_name = read_string(bytes, file_name_offset)?; - let directory = read_string(bytes, directory_offset)?; - - for root_directory in root_directories { - let file = root_directory.join(directory).join(file_name); - if file.is_file() { - files.push(file.canonicalize().unwrap()); - } - } - } - - Ok(files) -} - -fn read_string(bytes: &[u8], offset: usize) -> io::Result<&str> { - let mut byte = bytes[offset]; - let mut length = 0; - while byte != 0x00 { - length += 1; - byte = bytes[offset + length]; - } - - std::str::from_utf8(&bytes[offset..offset + length]) - .map_err(|_| io::Error::from(io::ErrorKind::InvalidData)) -} diff --git a/src/resolver/mod.rs b/src/resolver/mod.rs deleted file mode 100644 index 4568f9041..000000000 --- a/src/resolver/mod.rs +++ /dev/null @@ -1,97 +0,0 @@ -use lazy_static::lazy_static; -use std::collections::HashMap; -use std::env; -use std::ffi::OsString; -use std::path::PathBuf; -use std::process::Command; -use std::sync::Arc; - -mod miktex; -mod texlive; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Error { - KpsewhichNotFound, - UnsupportedTexDistribution, - CorruptFileDatabase, -} - -pub type Result = std::result::Result; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum TexDistributionKind { - Texlive, - Miktex, -} - -lazy_static! { - pub static ref TEX_RESOLVER: Result> = TexResolver::load().map(Arc::new); -} - -#[derive(Debug, PartialEq, Eq, Clone, Default)] -pub struct TexResolver { - pub files_by_name: HashMap, -} - -impl TexResolver { - fn load() -> Result { - let directories = Self::find_root_directories()?; - let kind = Self::detect_distribution(&directories)?; - let files_by_name = Self::read_database(&directories, kind)?; - Ok(Self { files_by_name }) - } - - fn find_root_directories() -> Result> { - let texmf = Self::run_kpsewhich(&["-var-value", "TEXMF"])?; - let expanded = Self::run_kpsewhich(&[&format!("--expand-braces={}", texmf)])?; - let directories = env::split_paths(&expanded.replace("!", "")) - .filter(|x| x.exists()) - .collect(); - Ok(directories) - } - - fn run_kpsewhich(args: &[&str]) -> Result { - let output = Command::new("kpsewhich") - .args(args) - .output() - .map_err(|_| Error::KpsewhichNotFound)?; - Ok(String::from_utf8(output.stdout) - .expect("Could not decode output from kpsewhich") - .lines() - .nth(0) - .expect("Invalid output from kpsewhich") - .to_owned()) - } - - fn detect_distribution(directories: &[PathBuf]) -> Result { - for directory in directories { - if directory.join(texlive::DATABASE_PATH).exists() { - return Ok(TexDistributionKind::Texlive); - } else if directory.join(miktex::DATABASE_PATH).exists() { - return Ok(TexDistributionKind::Miktex); - } - } - - Err(Error::UnsupportedTexDistribution) - } - - fn read_database( - root_directories: &[PathBuf], - kind: TexDistributionKind, - ) -> Result> { - let mut files_by_name = HashMap::new(); - for directory in root_directories { - let database = match kind { - TexDistributionKind::Texlive => texlive::read_database(&directory), - TexDistributionKind::Miktex => miktex::read_database(&directory, root_directories), - }?; - - for file in database { - let name = file.file_name().unwrap().to_owned(); - files_by_name.insert(name, file); - } - } - - Ok(files_by_name) - } -} diff --git a/src/resolver/texlive.rs b/src/resolver/texlive.rs deleted file mode 100644 index c7da2a9ce..000000000 --- a/src/resolver/texlive.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::{Error, Result}; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; -use std::str::Lines; - -pub const DATABASE_PATH: &'static str = "ls-R"; - -pub fn read_database(directory: &Path) -> Result> { - let file = directory.join(DATABASE_PATH); - if !file.is_file() { - return Ok(Vec::new()); - } - - let text = fs::read_to_string(file).expect("Could not read ls-R file"); - parse_database(&directory, text.lines()).map_err(|_| Error::CorruptFileDatabase) -} - -fn parse_database(root_directory: &Path, lines: Lines) -> io::Result> { - let mut files = Vec::new(); - let mut directory = PathBuf::new(); - - for line in lines.filter(|x| !x.trim().is_empty() && !x.starts_with('%')) { - if line.ends_with(':') { - let path = &line[..line.len() - 1]; - directory = root_directory.join(path); - } else { - let file = directory.join(line).canonicalize()?; - if file.is_file() { - files.push(file); - } - } - } - - Ok(files) -} diff --git a/src/server.rs b/src/server.rs index e9e4980bf..31e57d3ad 100644 --- a/src/server.rs +++ b/src/server.rs @@ -8,6 +8,8 @@ use crate::data::completion::LatexComponentDatabase; use crate::data::component::ComponentDocumentation; use crate::definition::DefinitionProvider; use crate::diagnostics::{DiagnosticsManager, LatexLintOptions}; +use crate::distribution; +use crate::distribution::TexDistribution; use crate::feature::{FeatureProvider, FeatureRequest}; use crate::folding::FoldingProvider; use crate::formatting::bibtex; @@ -18,8 +20,6 @@ use crate::link::LinkProvider; use crate::reference::ReferenceProvider; use crate::rename::RenameProvider; use crate::request; -use crate::resolver; -use crate::resolver::{TexResolver, TEX_RESOLVER}; use crate::syntax::bibtex::BibtexDeclaration; use crate::syntax::text::SyntaxNode; use crate::syntax::SyntaxTree; @@ -42,7 +42,7 @@ pub struct LatexLspServer { workspace_manager: WorkspaceManager, action_manager: ActionMananger, diagnostics_manager: Mutex, - resolver: Mutex>, + distribution: Mutex>, completion_provider: CompletionProvider, definition_provider: DefinitionProvider, folding_provider: FoldingProvider, @@ -61,7 +61,7 @@ impl LatexLspServer { workspace_manager: WorkspaceManager::default(), action_manager: ActionMananger::default(), diagnostics_manager: Mutex::new(DiagnosticsManager::default()), - resolver: Mutex::new(Arc::new(TexResolver::default())), + distribution: Mutex::new(Arc::new(TexDistribution::default())), completion_provider: CompletionProvider::new(), definition_provider: DefinitionProvider::new(), folding_provider: FoldingProvider::new(), @@ -134,7 +134,7 @@ impl LatexLspServer { #[jsonrpc_method("initialized", kind = "notification")] pub fn initialized(&self, _params: InitializedParams) { self.action_manager.push(Action::RegisterCapabilities); - self.action_manager.push(Action::LoadResolver); + self.action_manager.push(Action::LoadDistribution); self.action_manager.push(Action::ResolveIncludes); self.action_manager.push(Action::PublishDiagnostics); } @@ -390,25 +390,25 @@ impl jsonrpc::ActionHandler for LatexLspSe ); } } - Action::LoadResolver => { - match &*TEX_RESOLVER { + Action::LoadDistribution => { + match TexDistribution::load() { Ok(res) => { - let mut resolver = self.resolver.lock().await; - *resolver = Arc::clone(&res); + let mut distribution = self.distribution.lock().await; + *distribution = Arc::new(res); } Err(why) => { let message = match why { - resolver::Error::KpsewhichNotFound => { + distribution::Error::KpsewhichNotFound => { "An error occurred while executing `kpsewhich`.\ Please make sure that your distribution is in your PATH \ environment variable and provides the `kpsewhich` tool." } - resolver::Error::UnsupportedTexDistribution => { + distribution::Error::UnsupportedTexDistribution => { "Your TeX distribution is not supported." } - resolver::Error::CorruptFileDatabase => { - "The file database of your TeX distribution seems \ - to be corrupt. Please rebuild it and try again." + distribution::Error::CorruptPackageDatabase => { + "The package database of your TeX distribution seems \ + to be corrupt. Please reinstall your distribution." } }; @@ -469,14 +469,14 @@ impl jsonrpc::ActionHandler for LatexLspSe macro_rules! request { ($server:expr, $params:expr) => {{ let workspace = $server.workspace_manager.get(); - let resolver = $server.resolver.lock().await; + let distribution = $server.distribution.lock().await; if let Some(document) = workspace.find(&$params.text_document.uri) { Ok(FeatureRequest::new( $params, workspace, document, - Arc::clone(&resolver), + Arc::clone(&distribution), Arc::new(LatexComponentDatabase::default()), )) } else {