mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
parent
847b710480
commit
72dd792106
@ -72,6 +72,10 @@ pub struct CompileCommand {
|
||||
#[clap(required_if_eq("input", "-"), value_parser = ValueParser::new(output_value_parser))]
|
||||
pub output: Option<Output>,
|
||||
|
||||
/// Output a Makefile rule describing the current compilation
|
||||
#[clap(long = "make-deps", value_name = "PATH")]
|
||||
pub make_deps: Option<PathBuf>,
|
||||
|
||||
/// The format of the output file, inferred from the extension by default
|
||||
#[arg(long = "format", short = 'f')]
|
||||
pub format: Option<OutputFormat>,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use chrono::{Datelike, Timelike};
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
@ -118,6 +118,8 @@ pub fn compile_once(
|
||||
print_diagnostics(world, &[], &warnings, command.common.diagnostic_format)
|
||||
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
||||
|
||||
write_make_deps(world, command)?;
|
||||
|
||||
if let Some(open) = command.open.take() {
|
||||
if let Output::Path(file) = command.output() {
|
||||
open_file(open.as_deref(), &file)?;
|
||||
@ -335,6 +337,84 @@ impl ExportCache {
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a Makefile rule describing the relationship between the output and
|
||||
/// its dependencies to the path specified by the --make-deps argument, if it
|
||||
/// was provided.
|
||||
fn write_make_deps(world: &mut SystemWorld, command: &CompileCommand) -> StrResult<()> {
|
||||
let Some(ref make_deps_path) = command.make_deps else { return Ok(()) };
|
||||
let Output::Path(output_path) = command.output() else {
|
||||
bail!("failed to create make dependencies file because output was stdout")
|
||||
};
|
||||
let Ok(output_path) = output_path.into_os_string().into_string() else {
|
||||
bail!("failed to create make dependencies file because output path was not valid unicode")
|
||||
};
|
||||
|
||||
// Based on `munge` in libcpp/mkdeps.cc from the GCC source code. This isn't
|
||||
// perfect as some special characters can't be escaped.
|
||||
fn munge(s: &str) -> String {
|
||||
let mut res = String::with_capacity(s.len());
|
||||
let mut slashes = 0;
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'\\' => slashes += 1,
|
||||
'$' => {
|
||||
res.push('$');
|
||||
slashes = 0;
|
||||
}
|
||||
' ' | '\t' => {
|
||||
// `munge`'s source contains a comment here that says: "A
|
||||
// space or tab preceded by 2N+1 backslashes represents N
|
||||
// backslashes followed by space..."
|
||||
for _ in 0..slashes + 1 {
|
||||
res.push('\\');
|
||||
}
|
||||
slashes = 0;
|
||||
}
|
||||
'#' => {
|
||||
res.push('\\');
|
||||
slashes = 0;
|
||||
}
|
||||
_ => slashes = 0,
|
||||
};
|
||||
res.push(c);
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn write(
|
||||
make_deps_path: &Path,
|
||||
output_path: String,
|
||||
root: PathBuf,
|
||||
dependencies: impl Iterator<Item = PathBuf>,
|
||||
) -> io::Result<()> {
|
||||
let mut file = File::create(make_deps_path)?;
|
||||
|
||||
file.write_all(munge(&output_path).as_bytes())?;
|
||||
file.write_all(b":")?;
|
||||
for dependency in dependencies {
|
||||
let Some(dependency) =
|
||||
dependency.strip_prefix(&root).unwrap_or(&dependency).to_str()
|
||||
else {
|
||||
// Silently skip paths that aren't valid unicode so we still
|
||||
// produce a rule that will work for the other paths that can be
|
||||
// processed.
|
||||
continue;
|
||||
};
|
||||
|
||||
file.write_all(b" ")?;
|
||||
file.write_all(munge(dependency).as_bytes())?;
|
||||
}
|
||||
file.write_all(b"\n")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
write(make_deps_path, output_path, world.root().to_owned(), world.dependencies())
|
||||
.map_err(|err| {
|
||||
eco_format!("failed to create make dependencies file due to IO error ({err})")
|
||||
})
|
||||
}
|
||||
|
||||
/// Opens the given file using:
|
||||
/// - The default file viewer if `open` is `None`.
|
||||
/// - The given viewer provided by `open` if it is `Some`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user