diff --git a/CHANGELOG.md b/CHANGELOG.md index 82efa7c0..389ade58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Report diagnostics for unused BibTeX entries and undefined citations - Report diagnostics for duplicate BibTeX entries - Report diagnostics for duplicate labels +- Add `texlab.build.auxDirectory` and `texlab.build.logDirectory` settings ([#906](https://github.com/latex-lsp/texlab/issues/906)) + +### Deprecated + +- Deprecate `texlab.auxDirectory` in favor of `texlab.build.auxDirectory` ### Fixed - Fix parsing paths with `|` ([#568](https://github.com/latex-lsp/texlab/issues/568)) - Fix parsing LaTeX identifiers with `=` ([#568](https://github.com/latex-lsp/texlab/issues/568)) +- Fix search path for aux files when using `\include` instead of `\input` ([[#906](https://github.com/latex-lsp/texlab/issues/906)) ## [5.7.0] - 2023-06-07 diff --git a/crates/base-db/src/config.rs b/crates/base-db/src/config.rs index 0ffd78c6..36063b47 100644 --- a/crates/base-db/src/config.rs +++ b/crates/base-db/src/config.rs @@ -22,7 +22,8 @@ pub struct BuildConfig { pub args: Vec, pub on_save: bool, pub forward_search_after: bool, - pub output_dir: String, + pub aux_dir: String, + pub log_dir: String, pub output_filename: Option, } @@ -112,7 +113,8 @@ impl Default for BuildConfig { .collect(), on_save: false, forward_search_after: false, - output_dir: String::from("."), + aux_dir: String::from("."), + log_dir: String::from("."), output_filename: None, } } diff --git a/crates/base-db/src/data.rs b/crates/base-db/src/data.rs index dac0b49a..64313c0e 100644 --- a/crates/base-db/src/data.rs +++ b/crates/base-db/src/data.rs @@ -25,13 +25,13 @@ pub struct BibtexFieldType<'a> { impl<'a> BibtexEntryType<'a> { pub fn find(name: &str) -> Option { BIBTEX_ENTRY_TYPES.iter().find(|ty| ty.name.eq_ignore_ascii_case(name)).copied() - } + } } impl<'a> BibtexFieldType<'a> { pub fn find(name: &str) -> Option { BIBTEX_FIELD_TYPES.iter().find(|ty| ty.name.eq_ignore_ascii_case(name)).copied() - } + } } diff --git a/crates/base-db/src/graph.rs b/crates/base-db/src/graph.rs index 5e727d2b..3e718afd 100644 --- a/crates/base-db/src/graph.rs +++ b/crates/base-db/src/graph.rs @@ -48,15 +48,18 @@ impl<'a> Graph<'a> { while let Some((source, base_dir)) = stack.pop() { let index = graph.edges.len(); - graph.explicit_edges(source, &base_dir); + graph.add_explicit_edges(source, &base_dir); for edge in &graph.edges[index..] { - let Some(weight) = edge.weight.as_ref() else { continue }; + let Some(weight) = edge.weight.as_ref() else { + continue; + }; + if visited.insert(&edge.target.uri) { stack.push((edge.target, weight.new_base_dir.clone())); } } - graph.implicit_edges(source, &base_dir); + graph.add_implicit_edges(source, &base_dir); } graph @@ -68,19 +71,17 @@ impl<'a> Graph<'a> { .unique_by(|document| &document.uri) } - fn explicit_edges(&mut self, source: &'a Document, base_dir: &Url) { - let DocumentData::Tex(data) = &source.data else { return }; + fn add_explicit_edges(&mut self, source: &'a Document, base_dir: &Url) { + let DocumentData::Tex(data) = &source.data else { + return; + }; + for link in &data.semantics.links { - self.explicit_edge(source, base_dir, link); + self.add_link(source, base_dir, link); } } - fn explicit_edge( - &mut self, - source: &'a Document, - base_dir: &Url, - link: &'a semantics::tex::Link, - ) { + fn add_link(&mut self, source: &'a Document, base_dir: &Url, link: &'a semantics::tex::Link) { let home_dir = HOME_DIR.as_deref(); let stem = &link.path.text; @@ -130,15 +131,20 @@ impl<'a> Graph<'a> { } } - fn implicit_edges(&mut self, source: &'a Document, base_dir: &Url) { - let uri = source.uri.as_str(); - if source.language == Language::Tex && !uri.ends_with(".aux") { - self.implicit_edge(source, base_dir, "log"); - self.implicit_edge(source, base_dir, "aux"); + fn add_implicit_edges(&mut self, source: &'a Document, base_dir: &Url) { + if source.language == Language::Tex { + let config = &self.workspace.config().build; + let aux_dir = self.workspace.output_dir(base_dir, config.aux_dir.clone()); + let log_dir = self.workspace.output_dir(base_dir, config.log_dir.clone()); + + self.add_artifact(source, &aux_dir, "aux"); + self.add_artifact(source, base_dir, "aux"); + self.add_artifact(source, &log_dir, "log"); + self.add_artifact(source, base_dir, "log"); } } - fn implicit_edge(&mut self, source: &'a Document, base_dir: &Url, extension: &str) { + fn add_artifact(&mut self, source: &'a Document, base_dir: &Url, extension: &str) { let mut path = PathBuf::from( percent_decode_str(source.uri.path()) .decode_utf8_lossy() @@ -146,9 +152,13 @@ impl<'a> Graph<'a> { ); path.set_extension(extension); - let Some(target_uri) = path.file_name() + let Some(target_uri) = path + .file_name() .and_then(OsStr::to_str) - .and_then(|name| self.workspace.output_dir(base_dir).join(name).ok()) else { return }; + .and_then(|name| base_dir.join(name).ok()) + else { + return; + }; match self.workspace.lookup(&target_uri) { Some(target) => { diff --git a/crates/base-db/src/workspace.rs b/crates/base-db/src/workspace.rs index 15d29de8..9308c240 100644 --- a/crates/base-db/src/workspace.rs +++ b/crates/base-db/src/workspace.rs @@ -109,9 +109,22 @@ impl Workspace { self.iter() .filter(|document| document.uri.scheme() == "file") .flat_map(|document| { - let dir1 = self.output_dir(&self.current_dir(&document.dir)); - let dir2 = &document.dir; - [dir1.to_file_path(), dir2.to_file_path()] + let dir1 = self.output_dir( + &self.current_dir(&document.dir), + self.config.build.aux_dir.clone(), + ); + + let dir2 = self.output_dir( + &self.current_dir(&document.dir), + self.config.build.log_dir.clone(), + ); + + let dir3 = &document.dir; + [ + dir1.to_file_path(), + dir2.to_file_path(), + dir3.to_file_path(), + ] }) .flatten() .for_each(|path| { @@ -135,8 +148,8 @@ impl Workspace { .unwrap_or_else(|| base_dir.clone()) } - pub fn output_dir(&self, base_dir: &Url) -> Url { - let mut path = self.config.build.output_dir.clone(); + pub fn output_dir(&self, base_dir: &Url, relative_path: String) -> Url { + let mut path = relative_path; if !path.ends_with('/') { path.push('/'); } @@ -168,7 +181,9 @@ impl Workspace { pub fn parents(&self, child: &Document) -> FxHashSet<&Document> { self.iter() .filter(|document| { - let DocumentData::Tex(data) = &document.data else { return false }; + let DocumentData::Tex(data) = &document.data else { + return false; + }; data.semantics.can_be_root }) .filter(|parent| { @@ -264,14 +279,18 @@ impl Workspace { continue; } - let Ok(entries) = std::fs::read_dir(dir) else { continue }; + let Ok(entries) = std::fs::read_dir(dir) else { + continue; + }; for file in entries .flatten() .filter(|entry| entry.file_type().map_or(false, |type_| type_.is_file())) .map(|entry| entry.path()) { - let Some(lang) = Language::from_path(&file) else { continue }; + let Some(lang) = Language::from_path(&file) else { + continue; + }; if !matches!(lang, Language::Tex | Language::Root | Language::Tectonic) { continue; } diff --git a/crates/commands/src/clean.rs b/crates/commands/src/clean.rs index 391be79c..d6c3977f 100644 --- a/crates/commands/src/clean.rs +++ b/crates/commands/src/clean.rs @@ -22,7 +22,10 @@ impl CleanCommand { }; let dir = workspace.current_dir(&document.dir); - let dir = workspace.output_dir(&dir).to_file_path().unwrap(); + let dir = workspace + .output_dir(&dir, workspace.config().build.log_dir.clone()) + .to_file_path() + .unwrap(); let flag = match target { CleanTarget::Auxiliary => "-c", diff --git a/crates/commands/src/fwd_search.rs b/crates/commands/src/fwd_search.rs index 3669a289..153e1245 100644 --- a/crates/commands/src/fwd_search.rs +++ b/crates/commands/src/fwd_search.rs @@ -59,7 +59,10 @@ impl ForwardSearch { } let dir = workspace.current_dir(&parent.dir); - let dir = workspace.output_dir(&dir).to_file_path().unwrap(); + let dir = workspace + .output_dir(&dir, workspace.config().build.log_dir.clone()) + .to_file_path() + .unwrap(); let Some(tex_path) = &child.path else { return Err(ForwardSearchError::InvalidPath(child.uri.clone())); @@ -67,11 +70,12 @@ impl ForwardSearch { let override_path = workspace.config().build.output_filename.as_deref(); - let Some(pdf_path) = override_path.or(parent.path.as_deref()) + let Some(pdf_path) = override_path + .or(parent.path.as_deref()) .and_then(Path::file_stem) .and_then(OsStr::to_str) - .map(|stem| dir.join(format!("{stem}.pdf"))) else - { + .map(|stem| dir.join(format!("{stem}.pdf"))) + else { return Err(ForwardSearchError::InvalidPath(parent.uri.clone())); }; diff --git a/crates/texlab/src/server/options.rs b/crates/texlab/src/server/options.rs index af20c313..ddf20f0a 100644 --- a/crates/texlab/src/server/options.rs +++ b/crates/texlab/src/server/options.rs @@ -69,6 +69,8 @@ pub struct BuildOptions { pub args: Option>, pub on_save: bool, pub forward_search_after: bool, + pub aux_directory: Option, + pub log_directory: Option, pub filename: Option, } @@ -155,7 +157,19 @@ impl From for Config { config.build.args = value.build.args.unwrap_or(config.build.args); config.build.on_save = value.build.on_save; config.build.forward_search_after = value.build.forward_search_after; - config.build.output_dir = value.aux_directory.unwrap_or_else(|| String::from(".")); + + config.build.aux_dir = value + .build + .aux_directory + .or_else(|| value.aux_directory.clone()) + .unwrap_or_else(|| String::from(".")); + + config.build.log_dir = value + .build + .log_directory + .or_else(|| value.aux_directory) + .unwrap_or_else(|| String::from(".")); + config.build.output_filename = value.build.filename.map(PathBuf::from); config.diagnostics.allowed_patterns = value