mirror of
https://github.com/typst/typst
synced 2025-06-28 00:03:17 +08:00
Put HTTP server behind on-by-default feature flag (#5532)
This commit is contained in:
parent
8e4f5f21e0
commit
caa72f4ec2
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -64,6 +64,7 @@ jobs:
|
||||
components: clippy, rustfmt
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: cargo clippy --workspace --all-targets --all-features
|
||||
- run: cargo clippy --workspace --all-targets --no-default-features
|
||||
- run: cargo fmt --check --all
|
||||
- run: cargo doc --workspace --no-deps
|
||||
|
||||
|
@ -50,7 +50,7 @@ shell-escape = { workspace = true }
|
||||
sigpipe = { workspace = true }
|
||||
tar = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tiny_http = { workspace = true }
|
||||
tiny_http = { workspace = true, optional = true }
|
||||
toml = { workspace = true }
|
||||
ureq = { workspace = true }
|
||||
xz2 = { workspace = true, optional = true }
|
||||
@ -65,11 +65,14 @@ color-print = { workspace = true }
|
||||
semver = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["embed-fonts"]
|
||||
default = ["embed-fonts", "http-server"]
|
||||
|
||||
# Embeds some fonts into the binary, see typst-kit
|
||||
embed-fonts = ["typst-kit/embed-fonts"]
|
||||
|
||||
# Enables the built-in HTTP server for `typst watch` and HTML export.
|
||||
http-server = ["dep:tiny_http"]
|
||||
|
||||
# Permits the CLI to update itself without a package manager.
|
||||
self-update = ["dep:self-replace", "dep:xz2", "dep:zip"]
|
||||
|
||||
|
@ -98,20 +98,10 @@ pub struct WatchCommand {
|
||||
#[clap(flatten)]
|
||||
pub args: CompileArgs,
|
||||
|
||||
/// Disables the built-in HTTP server for HTML export.
|
||||
#[clap(long)]
|
||||
pub no_serve: bool,
|
||||
|
||||
/// Disables the injected live reload script for HTML export. The HTML that
|
||||
/// is written to disk isn't affected either way.
|
||||
#[clap(long)]
|
||||
pub no_reload: bool,
|
||||
|
||||
/// The port where HTML is served.
|
||||
///
|
||||
/// Defaults to the first free port in the range 3000-3005.
|
||||
#[clap(long)]
|
||||
pub port: Option<u16>,
|
||||
/// Arguments for the HTTP server.
|
||||
#[cfg(feature = "http-server")]
|
||||
#[clap(flatten)]
|
||||
pub server: ServerArgs,
|
||||
}
|
||||
|
||||
/// Initializes a new project from a template.
|
||||
@ -354,7 +344,7 @@ pub struct PackageArgs {
|
||||
pub package_cache_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Common arguments to customize available fonts
|
||||
/// Common arguments to customize available fonts.
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
pub struct FontArgs {
|
||||
/// Adds additional directories that are recursively searched for fonts.
|
||||
@ -375,6 +365,26 @@ pub struct FontArgs {
|
||||
pub ignore_system_fonts: bool,
|
||||
}
|
||||
|
||||
/// Arguments for the HTTP server.
|
||||
#[cfg(feature = "http-server")]
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
pub struct ServerArgs {
|
||||
/// Disables the built-in HTTP server for HTML export.
|
||||
#[clap(long)]
|
||||
pub no_serve: bool,
|
||||
|
||||
/// Disables the injected live reload script for HTML export. The HTML that
|
||||
/// is written to disk isn't affected either way.
|
||||
#[clap(long)]
|
||||
pub no_reload: bool,
|
||||
|
||||
/// The port where HTML is served.
|
||||
///
|
||||
/// Defaults to the first free port in the range 3000-3005.
|
||||
#[clap(long)]
|
||||
pub port: Option<u16>,
|
||||
}
|
||||
|
||||
macro_rules! display_possible_values {
|
||||
($ty:ty) => {
|
||||
impl Display for $ty {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::ffi::OsString;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -23,6 +23,7 @@ use crate::args::{
|
||||
CompileArgs, CompileCommand, DiagnosticFormat, Input, Output, OutputFormat,
|
||||
PdfStandard, WatchCommand,
|
||||
};
|
||||
#[cfg(feature = "http-server")]
|
||||
use crate::server::HtmlServer;
|
||||
use crate::timings::Timer;
|
||||
|
||||
@ -72,6 +73,7 @@ pub struct CompileConfig {
|
||||
/// watch` sessions with images.
|
||||
pub export_cache: ExportCache,
|
||||
/// Server for `typst watch` to HTML.
|
||||
#[cfg(feature = "http-server")]
|
||||
pub server: Option<HtmlServer>,
|
||||
}
|
||||
|
||||
@ -139,17 +141,18 @@ impl CompileConfig {
|
||||
PdfStandards::new(&list)?
|
||||
};
|
||||
|
||||
let mut server = None;
|
||||
let mut watching = false;
|
||||
if let Some(command) = watch {
|
||||
watching = true;
|
||||
if output_format == OutputFormat::Html && !command.no_serve {
|
||||
server = Some(HtmlServer::new(&input, command.port, !command.no_reload)?);
|
||||
#[cfg(feature = "http-server")]
|
||||
let server = match watch {
|
||||
Some(command)
|
||||
if output_format == OutputFormat::Html && !command.server.no_serve =>
|
||||
{
|
||||
Some(HtmlServer::new(&input, &command.server)?)
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
watching,
|
||||
watching: watch.is_some(),
|
||||
input,
|
||||
output,
|
||||
output_format,
|
||||
@ -161,6 +164,7 @@ impl CompileConfig {
|
||||
diagnostic_format: args.process.diagnostic_format,
|
||||
open: args.open.clone(),
|
||||
export_cache: ExportCache::new(),
|
||||
#[cfg(feature = "http-server")]
|
||||
server,
|
||||
})
|
||||
}
|
||||
@ -241,6 +245,7 @@ fn export_html(document: &HtmlDocument, config: &CompileConfig) -> SourceResult<
|
||||
let html = typst_html::html(document)?;
|
||||
let result = config.output.write(html.as_bytes());
|
||||
|
||||
#[cfg(feature = "http-server")]
|
||||
if let Some(server) = &config.server {
|
||||
server.update(html);
|
||||
}
|
||||
@ -556,30 +561,37 @@ fn write_make_deps(world: &mut SystemWorld, config: &CompileConfig) -> StrResult
|
||||
})
|
||||
}
|
||||
|
||||
/// Opens the output if desired, with:
|
||||
/// - The default file viewer if `open` is `None`.
|
||||
/// - The given viewer provided by `open` if it is `Some`.
|
||||
///
|
||||
/// If the file could not be opened, an error is returned.
|
||||
/// Opens the output if desired.
|
||||
fn open_output(config: &mut CompileConfig) -> StrResult<()> {
|
||||
let Some(open) = config.open.take() else { return Ok(()) };
|
||||
let Some(viewer) = config.open.take() else { return Ok(()) };
|
||||
|
||||
let path = if let Some(server) = &config.server {
|
||||
OsString::from(format!("http://{}", server.addr()))
|
||||
} else if let Output::Path(path) = &config.output {
|
||||
// Some resource openers require the path to be canonicalized.
|
||||
path.canonicalize()
|
||||
.map_err(|err| eco_format!("failed to canonicalize path ({err})"))?
|
||||
.into_os_string()
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
#[cfg(feature = "http-server")]
|
||||
if let Some(server) = &config.server {
|
||||
let url = format!("http://{}", server.addr());
|
||||
return open_path(OsStr::new(&url), viewer.as_deref());
|
||||
}
|
||||
|
||||
if let Some(app) = &open {
|
||||
open::with_detached(&path, app)
|
||||
.map_err(|err| eco_format!("failed to open file with {} ({})", app, err))
|
||||
// Can't open stdout.
|
||||
let Output::Path(path) = &config.output else { return Ok(()) };
|
||||
|
||||
// Some resource openers require the path to be canonicalized.
|
||||
let path = path
|
||||
.canonicalize()
|
||||
.map_err(|err| eco_format!("failed to canonicalize path ({err})"))?;
|
||||
|
||||
open_path(path.as_os_str(), viewer.as_deref())
|
||||
}
|
||||
|
||||
/// Opens the given file using:
|
||||
///
|
||||
/// - The default file viewer if `app` is `None`.
|
||||
/// - The given viewer provided by `app` if it is `Some`.
|
||||
fn open_path(path: &OsStr, viewer: Option<&str>) -> StrResult<()> {
|
||||
if let Some(viewer) = viewer {
|
||||
open::with_detached(path, viewer)
|
||||
.map_err(|err| eco_format!("failed to open file with {} ({})", viewer, err))
|
||||
} else {
|
||||
open::that_detached(&path).map_err(|err| {
|
||||
open::that_detached(path).map_err(|err| {
|
||||
let openers = open::commands(path)
|
||||
.iter()
|
||||
.map(|command| command.get_program().to_string_lossy())
|
||||
|
@ -6,6 +6,7 @@ mod greet;
|
||||
mod init;
|
||||
mod package;
|
||||
mod query;
|
||||
#[cfg(feature = "http-server")]
|
||||
mod server;
|
||||
mod terminal;
|
||||
mod timings;
|
||||
|
@ -7,7 +7,7 @@ use parking_lot::{Condvar, Mutex, MutexGuard};
|
||||
use tiny_http::{Header, Request, Response, StatusCode};
|
||||
use typst::diag::{bail, StrResult};
|
||||
|
||||
use crate::args::Input;
|
||||
use crate::args::{Input, ServerArgs};
|
||||
|
||||
/// Serves HTML with live reload.
|
||||
pub struct HtmlServer {
|
||||
@ -17,8 +17,9 @@ pub struct HtmlServer {
|
||||
|
||||
impl HtmlServer {
|
||||
/// Create a new HTTP server that serves live HTML.
|
||||
pub fn new(input: &Input, port: Option<u16>, reload: bool) -> StrResult<Self> {
|
||||
let (addr, server) = start_server(port)?;
|
||||
pub fn new(input: &Input, args: &ServerArgs) -> StrResult<Self> {
|
||||
let reload = !args.no_reload;
|
||||
let (addr, server) = start_server(args.port)?;
|
||||
|
||||
let placeholder = PLACEHOLDER_HTML.replace("{INPUT}", &input.to_string());
|
||||
let bucket = Arc::new(Bucket::new(placeholder));
|
||||
|
@ -293,6 +293,7 @@ impl Status {
|
||||
out.reset()?;
|
||||
writeln!(out, " {}", config.output)?;
|
||||
|
||||
#[cfg(feature = "http-server")]
|
||||
if let Some(server) = &config.server {
|
||||
out.set_color(&color)?;
|
||||
write!(out, "serving at")?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user