diff options
Diffstat (limited to 'support/texlab/crates/base-db/src/deps/root.rs')
-rw-r--r-- | support/texlab/crates/base-db/src/deps/root.rs | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/support/texlab/crates/base-db/src/deps/root.rs b/support/texlab/crates/base-db/src/deps/root.rs new file mode 100644 index 0000000000..7e2266e68c --- /dev/null +++ b/support/texlab/crates/base-db/src/deps/root.rs @@ -0,0 +1,157 @@ +use url::Url; + +use crate::{DocumentData, Workspace}; + +#[derive(PartialEq, Eq, Clone, Hash)] +pub struct ProjectRoot { + pub compile_dir: Url, + pub src_dir: Url, + pub aux_dir: Url, + pub log_dir: Url, + pub pdf_dir: Url, + pub additional_files: Vec<Url>, +} + +impl ProjectRoot { + pub fn walk_and_find(workspace: &Workspace, dir: &Url) -> Self { + let mut current = dir.clone(); + loop { + let root = Self::from_rootfile(workspace, ¤t) + .or_else(|| Self::from_tectonic(workspace, ¤t)) + .or_else(|| Self::from_latexmkrc(workspace, ¤t)); + + if let Some(root) = root { + break root; + } + + let Ok(parent) = current.join("..") else { + break Self::from_config(workspace, &dir); + }; + + if current == parent { + break Self::from_config(workspace, &dir); + } + + current = parent; + } + } + + pub fn from_tectonic(workspace: &Workspace, dir: &Url) -> Option<Self> { + let exists = workspace + .iter() + .filter(|document| document.dir == *dir) + .any(|document| matches!(document.data, DocumentData::Tectonic)); + + if !exists { + return None; + } + + let compile_dir = dir.clone(); + let src_dir = dir.join("src/").unwrap(); + let out_dir = dir.join("build/").unwrap(); + let aux_dir = out_dir.clone(); + let log_dir = out_dir.clone(); + let pdf_dir = out_dir; + let additional_files = vec![ + src_dir.join("_preamble.tex").unwrap(), + src_dir.join("_postamble.tex").unwrap(), + ]; + + Some(Self { + compile_dir, + src_dir, + aux_dir, + log_dir, + pdf_dir, + additional_files, + }) + } + + pub fn from_latexmkrc(workspace: &Workspace, dir: &Url) -> Option<Self> { + let rcfile = workspace + .iter() + .filter(|document| document.dir == *dir) + .find_map(|document| document.data.as_latexmkrc())?; + + let compile_dir = dir.clone(); + let src_dir = dir.clone(); + let aux_dir = rcfile + .aux_dir + .as_ref() + .and_then(|path| append_dir(dir, path).ok()) + .unwrap_or_else(|| dir.clone()); + + let out_dir = rcfile + .out_dir + .as_ref() + .and_then(|path| append_dir(dir, path).ok()) + .unwrap_or_else(|| dir.clone()); + + let log_dir = out_dir.clone(); + let pdf_dir = out_dir; + let additional_files = vec![]; + + Some(Self { + compile_dir, + src_dir, + aux_dir, + log_dir, + pdf_dir, + additional_files, + }) + } + + pub fn from_rootfile(workspace: &Workspace, dir: &Url) -> Option<Self> { + let exists = workspace + .iter() + .filter(|document| document.dir == *dir) + .any(|document| matches!(document.data, DocumentData::Root)); + + if !exists { + return None; + } + + Some(Self::from_config(workspace, dir)) + } + + pub fn from_config(workspace: &Workspace, dir: &Url) -> Self { + let compile_dir = dir.clone(); + let src_dir = dir.clone(); + let config = workspace.config(); + let aux_dir = append_dir(dir, &config.build.aux_dir).unwrap_or_else(|_| dir.clone()); + let log_dir = append_dir(dir, &config.build.log_dir).unwrap_or_else(|_| dir.clone()); + let pdf_dir = append_dir(dir, &config.build.pdf_dir).unwrap_or_else(|_| dir.clone()); + let additional_files = vec![]; + + Self { + compile_dir, + src_dir, + aux_dir, + log_dir, + pdf_dir, + additional_files, + } + } +} + +fn append_dir(dir: &Url, path: &str) -> Result<Url, url::ParseError> { + let mut path = String::from(path); + if !path.ends_with('/') { + path.push('/'); + } + + dir.join(&path) +} + +impl std::fmt::Debug for ProjectRoot { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ProjectRoot") + .field("compile_dir", &self.compile_dir.as_str()) + .field("src_dir", &self.src_dir.as_str()) + .field("aux_dir", &self.aux_dir.as_str()) + .field("log_dir", &self.log_dir.as_str()) + .field("pdf_dir", &self.pdf_dir.as_str()) + .field("additional_files", &self.additional_files) + .finish() + } +} |