1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
use std::{
env,
ffi::OsStr,
fs,
path::{Path, PathBuf},
process::Command,
};
use anyhow::Result;
use rustc_hash::FxHashMap;
use smol_str::SmolStr;
use crate::DocumentLanguage;
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct Resolver {
pub files_by_name: FxHashMap<SmolStr, PathBuf>,
}
impl Resolver {
#[must_use]
pub fn new(files_by_name: FxHashMap<SmolStr, PathBuf>) -> Self {
Self { files_by_name }
}
}
pub fn parse_database(
root_directories: &[PathBuf],
mut reader: impl FnMut(&Path) -> Result<Vec<PathBuf>>,
) -> Result<Resolver> {
let mut files_by_name = FxHashMap::default();
for directory in root_directories {
for path in reader(directory)? {
if DocumentLanguage::by_path(&path).is_some() {
if let Some(path) = make_absolute(root_directories, &path) {
if let Some(name) = path.file_name().and_then(OsStr::to_str).map(Into::into) {
files_by_name.insert(name, path);
}
}
}
}
}
Ok(Resolver::new(files_by_name))
}
fn make_absolute(root_directories: &[PathBuf], relative_path: &Path) -> Option<PathBuf> {
for dir in root_directories.iter().rev() {
if let Ok(path) = fs::canonicalize(dir.join(&relative_path)) {
return Some(path);
}
}
None
}
pub fn root_directories() -> Result<Vec<PathBuf>> {
let texmf = run(&["-var-value", "TEXMF"])?;
let expand_arg = format!("--expand-braces={}", texmf);
let expanded = run(&[&expand_arg])?;
let directories = env::split_paths(&expanded.replace('!', ""))
.filter(|path| path.exists())
.collect();
Ok(directories)
}
fn run(args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> Result<String> {
let output = Command::new("kpsewhich").args(args).output()?;
let result = String::from_utf8(output.stdout)?
.lines()
.next()
.unwrap()
.into();
Ok(result)
}
|