texlab 4.1.0

LaTeX Language Server
Documentation
mod kpsewhich;
mod miktex;
mod texlive;

use std::process::{Command, Stdio};

use anyhow::Result;
use derive_more::Display;
use log::warn;

pub use kpsewhich::Resolver;

#[derive(Debug, PartialEq, Eq, Clone, Copy, Display)]
pub enum DistributionKind {
    #[display(fmt = "TeXLive")]
    Texlive,
    #[display(fmt = "MikTeX")]
    Miktex,
    #[display(fmt = "Tectonic")]
    Tectonic,
    #[display(fmt = "Unknown")]
    Unknown,
}

#[derive(Debug, Clone)]
pub struct Distribution {
    pub kind: DistributionKind,
    pub resolver: Resolver,
}

impl Distribution {
    #[must_use]
    pub fn detect() -> Self {
        let kind = match Command::new("latex").arg("--version").output() {
            Ok(output) => {
                let stdout = String::from_utf8_lossy(&output.stdout);
                if stdout.contains("TeX Live") {
                    DistributionKind::Texlive
                } else if stdout.contains("MiKTeX") {
                    DistributionKind::Miktex
                } else {
                    DistributionKind::Unknown
                }
            }
            Err(_) => {
                if Command::new("tectonic")
                    .arg("--version")
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .status()
                    .is_ok()
                {
                    DistributionKind::Tectonic
                } else {
                    DistributionKind::Unknown
                }
            }
        };

        let resolver = match kind {
            DistributionKind::Texlive => Self::load_resolver(texlive::load_resolver),
            DistributionKind::Miktex => Self::load_resolver(miktex::load_resolver),
            DistributionKind::Tectonic | DistributionKind::Unknown => Resolver::default(),
        };
        Self { kind, resolver }
    }

    fn load_resolver(loader: impl FnOnce() -> Result<Resolver>) -> Resolver {
        match loader() {
            Ok(resolver) => return resolver,
            Err(why) => warn!("Failed to load resolver: {}", why),
        };
        Resolver::default()
    }
}