texlab/
distro.rs

1mod kpsewhich;
2mod miktex;
3mod texlive;
4
5use std::process::{Command, Stdio};
6
7use anyhow::Result;
8use derive_more::Display;
9use log::warn;
10
11pub use kpsewhich::Resolver;
12
13#[derive(Debug, PartialEq, Eq, Clone, Copy, Display)]
14pub enum DistributionKind {
15    #[display(fmt = "TeXLive")]
16    Texlive,
17    #[display(fmt = "MikTeX")]
18    Miktex,
19    #[display(fmt = "Tectonic")]
20    Tectonic,
21    #[display(fmt = "Unknown")]
22    Unknown,
23}
24
25#[derive(Debug, Clone)]
26pub struct Distribution {
27    pub kind: DistributionKind,
28    pub resolver: Resolver,
29}
30
31impl Distribution {
32    #[must_use]
33    pub fn detect() -> Self {
34        let kind = match Command::new("latex").arg("--version").output() {
35            Ok(output) => {
36                let stdout = String::from_utf8_lossy(&output.stdout);
37                if stdout.contains("TeX Live") {
38                    DistributionKind::Texlive
39                } else if stdout.contains("MiKTeX") {
40                    DistributionKind::Miktex
41                } else {
42                    DistributionKind::Unknown
43                }
44            }
45            Err(_) => {
46                if Command::new("tectonic")
47                    .arg("--version")
48                    .stdout(Stdio::null())
49                    .stderr(Stdio::null())
50                    .status()
51                    .is_ok()
52                {
53                    DistributionKind::Tectonic
54                } else {
55                    DistributionKind::Unknown
56                }
57            }
58        };
59
60        let resolver = match kind {
61            DistributionKind::Texlive => Self::load_resolver(texlive::load_resolver),
62            DistributionKind::Miktex => Self::load_resolver(miktex::load_resolver),
63            DistributionKind::Tectonic | DistributionKind::Unknown => Resolver::default(),
64        };
65        Self { kind, resolver }
66    }
67
68    fn load_resolver(loader: impl FnOnce() -> Result<Resolver>) -> Resolver {
69        match loader() {
70            Ok(resolver) => return resolver,
71            Err(why) => warn!("Failed to load resolver: {}", why),
72        };
73        Resolver::default()
74    }
75}