mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Add more environment control parameters to CLI (#4227)
Co-authored-by: PgBiel <9021226+PgBiel@users.noreply.github.com> Co-authored-by: Tulio Martins <tulioml240@gmail.com> Co-authored-by: PepinhoJp <pepinho.jp@gmail.com>
This commit is contained in:
parent
753213c40a
commit
cc3e9c8602
@ -131,6 +131,10 @@ pub struct InitCommand {
|
|||||||
|
|
||||||
/// The project directory, defaults to the template's name
|
/// The project directory, defaults to the template's name
|
||||||
pub dir: Option<String>,
|
pub dir: Option<String>,
|
||||||
|
|
||||||
|
/// Arguments related to storage of packages in the system
|
||||||
|
#[clap(flatten)]
|
||||||
|
pub package_storage_args: PackageStorageArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes an input file to extract provided metadata
|
/// Processes an input file to extract provided metadata
|
||||||
@ -187,14 +191,9 @@ pub struct SharedArgs {
|
|||||||
)]
|
)]
|
||||||
pub inputs: Vec<(String, String)>,
|
pub inputs: Vec<(String, String)>,
|
||||||
|
|
||||||
/// Adds additional directories to search for fonts
|
/// Common font arguments
|
||||||
#[clap(
|
#[clap(flatten)]
|
||||||
long = "font-path",
|
pub font_args: FontArgs,
|
||||||
env = "TYPST_FONT_PATHS",
|
|
||||||
value_name = "DIR",
|
|
||||||
value_delimiter = ENV_PATH_SEP,
|
|
||||||
)]
|
|
||||||
pub font_paths: Vec<PathBuf>,
|
|
||||||
|
|
||||||
/// The document's creation date formatted as a UNIX timestamp.
|
/// The document's creation date formatted as a UNIX timestamp.
|
||||||
///
|
///
|
||||||
@ -214,6 +213,26 @@ pub struct SharedArgs {
|
|||||||
value_parser = clap::value_parser!(DiagnosticFormat)
|
value_parser = clap::value_parser!(DiagnosticFormat)
|
||||||
)]
|
)]
|
||||||
pub diagnostic_format: DiagnosticFormat,
|
pub diagnostic_format: DiagnosticFormat,
|
||||||
|
|
||||||
|
/// Arguments related to storage of packages in the system
|
||||||
|
#[clap(flatten)]
|
||||||
|
pub package_storage_args: PackageStorageArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arguments related to where packages are stored in the system.
|
||||||
|
#[derive(Debug, Clone, Args)]
|
||||||
|
pub struct PackageStorageArgs {
|
||||||
|
/// Custom path to local packages, defaults to system-dependent location
|
||||||
|
#[clap(long = "package-path", env = "TYPST_PACKAGE_PATH", value_name = "DIR")]
|
||||||
|
pub package_path: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Custom path to package cache, defaults to system-dependent location
|
||||||
|
#[clap(
|
||||||
|
long = "package-cache-path",
|
||||||
|
env = "TYPST_PACKAGE_CACHE_PATH",
|
||||||
|
value_name = "DIR"
|
||||||
|
)]
|
||||||
|
pub package_cache_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a UNIX timestamp according to <https://reproducible-builds.org/specs/source-date-epoch/>
|
/// Parses a UNIX timestamp according to <https://reproducible-builds.org/specs/source-date-epoch/>
|
||||||
@ -343,6 +362,18 @@ fn parse_page_number(value: &str) -> Result<NonZeroUsize, &'static str> {
|
|||||||
/// Lists all discovered fonts in system and custom font paths
|
/// Lists all discovered fonts in system and custom font paths
|
||||||
#[derive(Debug, Clone, Parser)]
|
#[derive(Debug, Clone, Parser)]
|
||||||
pub struct FontsCommand {
|
pub struct FontsCommand {
|
||||||
|
/// Common font arguments
|
||||||
|
#[clap(flatten)]
|
||||||
|
pub font_args: FontArgs,
|
||||||
|
|
||||||
|
/// Also lists style variants of each font family
|
||||||
|
#[arg(long)]
|
||||||
|
pub variants: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Common arguments to customize available fonts
|
||||||
|
#[derive(Debug, Clone, Parser)]
|
||||||
|
pub struct FontArgs {
|
||||||
/// Adds additional directories to search for fonts
|
/// Adds additional directories to search for fonts
|
||||||
#[clap(
|
#[clap(
|
||||||
long = "font-path",
|
long = "font-path",
|
||||||
@ -352,9 +383,10 @@ pub struct FontsCommand {
|
|||||||
)]
|
)]
|
||||||
pub font_paths: Vec<PathBuf>,
|
pub font_paths: Vec<PathBuf>,
|
||||||
|
|
||||||
/// Also lists style variants of each font family
|
/// Ensures system fonts won't be searched, unless explicitly included via
|
||||||
|
/// `--font-path`
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub variants: bool,
|
pub ignore_system_fonts: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which format to use for diagnostics.
|
/// Which format to use for diagnostics.
|
||||||
@ -385,8 +417,18 @@ pub struct UpdateCommand {
|
|||||||
|
|
||||||
/// Reverts to the version from before the last update (only possible if
|
/// Reverts to the version from before the last update (only possible if
|
||||||
/// `typst update` has previously ran)
|
/// `typst update` has previously ran)
|
||||||
#[clap(long, default_value_t = false, exclusive = true)]
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_t = false,
|
||||||
|
conflicts_with = "version",
|
||||||
|
conflicts_with = "force"
|
||||||
|
)]
|
||||||
pub revert: bool,
|
pub revert: bool,
|
||||||
|
|
||||||
|
/// Custom path to the backup file created on update and used by `--revert`,
|
||||||
|
/// defaults to system-dependent location
|
||||||
|
#[clap(long = "backup-path", env = "TYPST_UPDATE_BACKUP_PATH", value_name = "FILE")]
|
||||||
|
pub backup_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which format to use for the generated output file.
|
/// Which format to use for the generated output file.
|
||||||
|
@ -12,7 +12,7 @@ use crate::args::FontsCommand;
|
|||||||
/// Execute a font listing command.
|
/// Execute a font listing command.
|
||||||
pub fn fonts(command: &FontsCommand) -> StrResult<()> {
|
pub fn fonts(command: &FontsCommand) -> StrResult<()> {
|
||||||
let mut searcher = FontSearcher::new();
|
let mut searcher = FontSearcher::new();
|
||||||
searcher.search(&command.font_paths);
|
searcher.search(&command.font_args.font_paths, command.font_args.ignore_system_fonts);
|
||||||
|
|
||||||
for (name, infos) in searcher.book.families() {
|
for (name, infos) in searcher.book.families() {
|
||||||
println!("{name}");
|
println!("{name}");
|
||||||
@ -66,7 +66,7 @@ impl FontSearcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Search everything that is available.
|
/// Search everything that is available.
|
||||||
pub fn search(&mut self, font_paths: &[PathBuf]) {
|
pub fn search(&mut self, font_paths: &[PathBuf], ignore_system_fonts: bool) {
|
||||||
let mut db = Database::new();
|
let mut db = Database::new();
|
||||||
|
|
||||||
// Font paths have highest priority.
|
// Font paths have highest priority.
|
||||||
@ -74,8 +74,10 @@ impl FontSearcher {
|
|||||||
db.load_fonts_dir(path);
|
db.load_fonts_dir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// System fonts have second priority.
|
if !ignore_system_fonts {
|
||||||
db.load_system_fonts();
|
// System fonts have second priority.
|
||||||
|
db.load_system_fonts();
|
||||||
|
}
|
||||||
|
|
||||||
for face in db.faces() {
|
for face in db.faces() {
|
||||||
let path = match &face.source {
|
let path = match &face.source {
|
||||||
|
@ -10,9 +10,12 @@ use typst::syntax::package::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::args::InitCommand;
|
use crate::args::InitCommand;
|
||||||
|
use crate::package::PackageStorage;
|
||||||
|
|
||||||
/// Execute an initialization command.
|
/// Execute an initialization command.
|
||||||
pub fn init(command: &InitCommand) -> StrResult<()> {
|
pub fn init(command: &InitCommand) -> StrResult<()> {
|
||||||
|
let package_storage = PackageStorage::from_args(&command.package_storage_args);
|
||||||
|
|
||||||
// Parse the package specification. If the user didn't specify the version,
|
// Parse the package specification. If the user didn't specify the version,
|
||||||
// we try to figure it out automatically by downloading the package index
|
// we try to figure it out automatically by downloading the package index
|
||||||
// or searching the disk.
|
// or searching the disk.
|
||||||
@ -20,12 +23,12 @@ pub fn init(command: &InitCommand) -> StrResult<()> {
|
|||||||
// Try to parse without version, but prefer the error message of the
|
// Try to parse without version, but prefer the error message of the
|
||||||
// normal package spec parsing if it fails.
|
// normal package spec parsing if it fails.
|
||||||
let spec: VersionlessPackageSpec = command.template.parse().map_err(|_| err)?;
|
let spec: VersionlessPackageSpec = command.template.parse().map_err(|_| err)?;
|
||||||
let version = crate::package::determine_latest_version(&spec)?;
|
let version = package_storage.determine_latest_version(&spec)?;
|
||||||
StrResult::Ok(spec.at(version))
|
StrResult::Ok(spec.at(version))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Find or download the package.
|
// Find or download the package.
|
||||||
let package_path = crate::package::prepare_package(&spec)?;
|
let package_path = package_storage.prepare_package(&spec)?;
|
||||||
|
|
||||||
// Parse the manifest.
|
// Parse the manifest.
|
||||||
let manifest = parse_manifest(&package_path)?;
|
let manifest = parse_manifest(&package_path)?;
|
||||||
|
@ -2,6 +2,7 @@ use std::fs;
|
|||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use crate::args::PackageStorageArgs;
|
||||||
use codespan_reporting::term::{self, termcolor};
|
use codespan_reporting::term::{self, termcolor};
|
||||||
use ecow::eco_format;
|
use ecow::eco_format;
|
||||||
use termcolor::WriteColor;
|
use termcolor::WriteColor;
|
||||||
@ -14,64 +15,83 @@ use crate::download::{download, download_with_progress};
|
|||||||
use crate::terminal;
|
use crate::terminal;
|
||||||
|
|
||||||
const HOST: &str = "https://packages.typst.org";
|
const HOST: &str = "https://packages.typst.org";
|
||||||
|
const DEFAULT_PACKAGES_SUBDIR: &str = "typst/packages";
|
||||||
|
|
||||||
/// Make a package available in the on-disk cache.
|
/// Holds information about where packages should be stored.
|
||||||
pub fn prepare_package(spec: &PackageSpec) -> PackageResult<PathBuf> {
|
pub struct PackageStorage {
|
||||||
let subdir =
|
pub package_cache_path: Option<PathBuf>,
|
||||||
format!("typst/packages/{}/{}/{}", spec.namespace, spec.name, spec.version);
|
pub package_path: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(data_dir) = dirs::data_dir() {
|
impl PackageStorage {
|
||||||
let dir = data_dir.join(&subdir);
|
pub fn from_args(args: &PackageStorageArgs) -> Self {
|
||||||
if dir.exists() {
|
let package_cache_path = args.package_cache_path.clone().or_else(|| {
|
||||||
return Ok(dir);
|
dirs::cache_dir().map(|cache_dir| cache_dir.join(DEFAULT_PACKAGES_SUBDIR))
|
||||||
}
|
});
|
||||||
|
let package_path = args.package_path.clone().or_else(|| {
|
||||||
|
dirs::data_dir().map(|data_dir| data_dir.join(DEFAULT_PACKAGES_SUBDIR))
|
||||||
|
});
|
||||||
|
Self { package_cache_path, package_path }
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(cache_dir) = dirs::cache_dir() {
|
/// Make a package available in the on-disk cache.
|
||||||
let dir = cache_dir.join(&subdir);
|
pub fn prepare_package(&self, spec: &PackageSpec) -> PackageResult<PathBuf> {
|
||||||
if dir.exists() {
|
let subdir = format!("{}/{}/{}", spec.namespace, spec.name, spec.version);
|
||||||
return Ok(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download from network if it doesn't exist yet.
|
if let Some(packages_dir) = &self.package_path {
|
||||||
if spec.namespace == "preview" {
|
let dir = packages_dir.join(&subdir);
|
||||||
download_package(spec, &dir)?;
|
|
||||||
if dir.exists() {
|
if dir.exists() {
|
||||||
return Ok(dir);
|
return Ok(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(cache_dir) = &self.package_cache_path {
|
||||||
|
let dir = cache_dir.join(&subdir);
|
||||||
|
if dir.exists() {
|
||||||
|
return Ok(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download from network if it doesn't exist yet.
|
||||||
|
if spec.namespace == "preview" {
|
||||||
|
download_package(spec, &dir)?;
|
||||||
|
if dir.exists() {
|
||||||
|
return Ok(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(PackageError::NotFound(spec.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(PackageError::NotFound(spec.clone()))
|
/// Try to determine the latest version of a package.
|
||||||
}
|
pub fn determine_latest_version(
|
||||||
|
&self,
|
||||||
/// Try to determine the latest version of a package.
|
spec: &VersionlessPackageSpec,
|
||||||
pub fn determine_latest_version(
|
) -> StrResult<PackageVersion> {
|
||||||
spec: &VersionlessPackageSpec,
|
if spec.namespace == "preview" {
|
||||||
) -> StrResult<PackageVersion> {
|
// For `@preview`, download the package index and find the latest
|
||||||
if spec.namespace == "preview" {
|
// version.
|
||||||
// For `@preview`, download the package index and find the latest
|
download_index()?
|
||||||
// version.
|
.iter()
|
||||||
download_index()?
|
.filter(|package| package.name == spec.name)
|
||||||
.iter()
|
.map(|package| package.version)
|
||||||
.filter(|package| package.name == spec.name)
|
.max()
|
||||||
.map(|package| package.version)
|
.ok_or_else(|| eco_format!("failed to find package {spec}"))
|
||||||
.max()
|
} else {
|
||||||
.ok_or_else(|| eco_format!("failed to find package {spec}"))
|
// For other namespaces, search locally. We only search in the data
|
||||||
} else {
|
// directory and not the cache directory, because the latter is not
|
||||||
// For other namespaces, search locally. We only search in the data
|
// intended for storage of local packages.
|
||||||
// directory and not the cache directory, because the latter is not
|
let subdir = format!("{}/{}", spec.namespace, spec.name);
|
||||||
// intended for storage of local packages.
|
self.package_path
|
||||||
let subdir = format!("typst/packages/{}/{}", spec.namespace, spec.name);
|
.iter()
|
||||||
dirs::data_dir()
|
.flat_map(|dir| std::fs::read_dir(dir.join(&subdir)).ok())
|
||||||
.into_iter()
|
.flatten()
|
||||||
.flat_map(|dir| std::fs::read_dir(dir.join(&subdir)).ok())
|
.filter_map(|entry| entry.ok())
|
||||||
.flatten()
|
.map(|entry| entry.path())
|
||||||
.filter_map(|entry| entry.ok())
|
.filter_map(|path| path.file_name()?.to_string_lossy().parse().ok())
|
||||||
.map(|entry| entry.path())
|
.max()
|
||||||
.filter_map(|path| path.file_name()?.to_string_lossy().parse().ok())
|
.ok_or_else(|| eco_format!("please specify the desired version"))
|
||||||
.max()
|
}
|
||||||
.ok_or_else(|| eco_format!("please specify the desired version"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,14 @@ pub fn update(command: &UpdateCommand) -> StrResult<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let backup_path = backup_path()?;
|
// Full path to the backup file.
|
||||||
|
let backup_path = command.backup_path.clone().map(Ok).unwrap_or_else(backup_path)?;
|
||||||
|
|
||||||
|
if let Some(backup_dir) = backup_path.parent() {
|
||||||
|
fs::create_dir_all(backup_dir)
|
||||||
|
.map_err(|err| eco_format!("failed to create backup directory ({err})"))?;
|
||||||
|
}
|
||||||
|
|
||||||
if command.revert {
|
if command.revert {
|
||||||
if !backup_path.exists() {
|
if !backup_path.exists() {
|
||||||
bail!(
|
bail!(
|
||||||
@ -213,14 +220,19 @@ fn update_needed(release: &Release) -> StrResult<bool> {
|
|||||||
Ok(new_tag > current_tag)
|
Ok(new_tag > current_tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Path to a potential backup file.
|
/// Path to a potential backup file in the system.
|
||||||
///
|
///
|
||||||
/// The backup will be placed in one of the following directories, depending on
|
/// The backup will be placed as `typst_backup.part` in one of the following
|
||||||
/// the platform:
|
/// directories, depending on the platform:
|
||||||
/// - `$XDG_STATE_HOME` or `~/.local/state` on Linux
|
/// - `$XDG_STATE_HOME` or `~/.local/state` on Linux
|
||||||
/// - `$XDG_DATA_HOME` or `~/.local/share` if the above path isn't available
|
/// - `$XDG_DATA_HOME` or `~/.local/share` if the above path isn't available
|
||||||
/// - `~/Library/Application Support` on macOS
|
/// - `~/Library/Application Support` on macOS
|
||||||
/// - `%APPDATA%` on Windows
|
/// - `%APPDATA%` on Windows
|
||||||
|
///
|
||||||
|
/// If a custom backup path is provided via the environment variable
|
||||||
|
/// `TYPST_UPDATE_BACKUP_PATH`, it will be used instead of the default
|
||||||
|
/// directories determined by the platform. In that case, this function
|
||||||
|
/// shouldn't be called.
|
||||||
fn backup_path() -> StrResult<PathBuf> {
|
fn backup_path() -> StrResult<PathBuf> {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
let root_backup_dir = dirs::state_dir()
|
let root_backup_dir = dirs::state_dir()
|
||||||
@ -231,10 +243,5 @@ fn backup_path() -> StrResult<PathBuf> {
|
|||||||
let root_backup_dir =
|
let root_backup_dir =
|
||||||
dirs::data_dir().ok_or("unable to locate local data directory")?;
|
dirs::data_dir().ok_or("unable to locate local data directory")?;
|
||||||
|
|
||||||
let backup_dir = root_backup_dir.join("typst");
|
Ok(root_backup_dir.join("typst").join("typst_backup.part"))
|
||||||
|
|
||||||
fs::create_dir_all(&backup_dir)
|
|
||||||
.map_err(|err| eco_format!("failed to create backup directory ({err})"))?;
|
|
||||||
|
|
||||||
Ok(backup_dir.join("typst_backup.part"))
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ use typst_timing::{timed, TimingScope};
|
|||||||
use crate::args::{Input, SharedArgs};
|
use crate::args::{Input, SharedArgs};
|
||||||
use crate::compile::ExportCache;
|
use crate::compile::ExportCache;
|
||||||
use crate::fonts::{FontSearcher, FontSlot};
|
use crate::fonts::{FontSearcher, FontSlot};
|
||||||
|
use crate::package::PackageStorage;
|
||||||
|
|
||||||
/// Static `FileId` allocated for stdin.
|
/// Static `FileId` allocated for stdin.
|
||||||
/// This is to ensure that a file is read in the correct way.
|
/// This is to ensure that a file is read in the correct way.
|
||||||
@ -41,6 +42,8 @@ pub struct SystemWorld {
|
|||||||
fonts: Vec<FontSlot>,
|
fonts: Vec<FontSlot>,
|
||||||
/// Maps file ids to source files and buffers.
|
/// Maps file ids to source files and buffers.
|
||||||
slots: Mutex<HashMap<FileId, FileSlot>>,
|
slots: Mutex<HashMap<FileId, FileSlot>>,
|
||||||
|
/// Holds information about where packages are stored.
|
||||||
|
package_storage: PackageStorage,
|
||||||
/// The current datetime if requested. This is stored here to ensure it is
|
/// The current datetime if requested. This is stored here to ensure it is
|
||||||
/// always the same within one compilation.
|
/// always the same within one compilation.
|
||||||
/// Reset between compilations if not [`Now::Fixed`].
|
/// Reset between compilations if not [`Now::Fixed`].
|
||||||
@ -103,13 +106,16 @@ impl SystemWorld {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut searcher = FontSearcher::new();
|
let mut searcher = FontSearcher::new();
|
||||||
searcher.search(&command.font_paths);
|
searcher
|
||||||
|
.search(&command.font_args.font_paths, command.font_args.ignore_system_fonts);
|
||||||
|
|
||||||
let now = match command.creation_timestamp {
|
let now = match command.creation_timestamp {
|
||||||
Some(time) => Now::Fixed(time),
|
Some(time) => Now::Fixed(time),
|
||||||
None => Now::System(OnceLock::new()),
|
None => Now::System(OnceLock::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let package_storage = PackageStorage::from_args(&command.package_storage_args);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
workdir: std::env::current_dir().ok(),
|
workdir: std::env::current_dir().ok(),
|
||||||
root,
|
root,
|
||||||
@ -118,6 +124,7 @@ impl SystemWorld {
|
|||||||
book: LazyHash::new(searcher.book),
|
book: LazyHash::new(searcher.book),
|
||||||
fonts: searcher.fonts,
|
fonts: searcher.fonts,
|
||||||
slots: Mutex::new(HashMap::new()),
|
slots: Mutex::new(HashMap::new()),
|
||||||
|
package_storage,
|
||||||
now,
|
now,
|
||||||
export_cache: ExportCache::new(),
|
export_cache: ExportCache::new(),
|
||||||
})
|
})
|
||||||
@ -144,7 +151,9 @@ impl SystemWorld {
|
|||||||
.get_mut()
|
.get_mut()
|
||||||
.values()
|
.values()
|
||||||
.filter(|slot| slot.accessed())
|
.filter(|slot| slot.accessed())
|
||||||
.filter_map(|slot| system_path(&self.root, slot.id).ok())
|
.filter_map(|slot| {
|
||||||
|
system_path(&self.root, slot.id, &self.package_storage).ok()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the compilation state in preparation of a new compilation.
|
/// Reset the compilation state in preparation of a new compilation.
|
||||||
@ -183,11 +192,11 @@ impl World for SystemWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn source(&self, id: FileId) -> FileResult<Source> {
|
fn source(&self, id: FileId) -> FileResult<Source> {
|
||||||
self.slot(id, |slot| slot.source(&self.root))
|
self.slot(id, |slot| slot.source(&self.root, &self.package_storage))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self, id: FileId) -> FileResult<Bytes> {
|
fn file(&self, id: FileId) -> FileResult<Bytes> {
|
||||||
self.slot(id, |slot| slot.file(&self.root))
|
self.slot(id, |slot| slot.file(&self.root, &self.package_storage))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn font(&self, index: usize) -> Option<Font> {
|
fn font(&self, index: usize) -> Option<Font> {
|
||||||
@ -259,9 +268,13 @@ impl FileSlot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the source for this file.
|
/// Retrieve the source for this file.
|
||||||
fn source(&mut self, project_root: &Path) -> FileResult<Source> {
|
fn source(
|
||||||
|
&mut self,
|
||||||
|
project_root: &Path,
|
||||||
|
package_storage: &PackageStorage,
|
||||||
|
) -> FileResult<Source> {
|
||||||
self.source.get_or_init(
|
self.source.get_or_init(
|
||||||
|| read(self.id, project_root),
|
|| read(self.id, project_root, package_storage),
|
||||||
|data, prev| {
|
|data, prev| {
|
||||||
let name = if prev.is_some() { "reparsing file" } else { "parsing file" };
|
let name = if prev.is_some() { "reparsing file" } else { "parsing file" };
|
||||||
let _scope = TimingScope::new(name, None);
|
let _scope = TimingScope::new(name, None);
|
||||||
@ -277,9 +290,15 @@ impl FileSlot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the file's bytes.
|
/// Retrieve the file's bytes.
|
||||||
fn file(&mut self, project_root: &Path) -> FileResult<Bytes> {
|
fn file(
|
||||||
self.file
|
&mut self,
|
||||||
.get_or_init(|| read(self.id, project_root), |data, _| Ok(data.into()))
|
project_root: &Path,
|
||||||
|
package_storage: &PackageStorage,
|
||||||
|
) -> FileResult<Bytes> {
|
||||||
|
self.file.get_or_init(
|
||||||
|
|| read(self.id, project_root, package_storage),
|
||||||
|
|data, _| Ok(data.into()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,13 +363,17 @@ impl<T: Clone> SlotCell<T> {
|
|||||||
|
|
||||||
/// Resolves the path of a file id on the system, downloading a package if
|
/// Resolves the path of a file id on the system, downloading a package if
|
||||||
/// necessary.
|
/// necessary.
|
||||||
fn system_path(project_root: &Path, id: FileId) -> FileResult<PathBuf> {
|
fn system_path(
|
||||||
|
project_root: &Path,
|
||||||
|
id: FileId,
|
||||||
|
package_storage: &PackageStorage,
|
||||||
|
) -> FileResult<PathBuf> {
|
||||||
// Determine the root path relative to which the file path
|
// Determine the root path relative to which the file path
|
||||||
// will be resolved.
|
// will be resolved.
|
||||||
let buf;
|
let buf;
|
||||||
let mut root = project_root;
|
let mut root = project_root;
|
||||||
if let Some(spec) = id.package() {
|
if let Some(spec) = id.package() {
|
||||||
buf = crate::package::prepare_package(spec)?;
|
buf = package_storage.prepare_package(spec)?;
|
||||||
root = &buf;
|
root = &buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,11 +386,15 @@ fn system_path(project_root: &Path, id: FileId) -> FileResult<PathBuf> {
|
|||||||
///
|
///
|
||||||
/// If the ID represents stdin it will read from standard input,
|
/// If the ID represents stdin it will read from standard input,
|
||||||
/// otherwise it gets the file path of the ID and reads the file from disk.
|
/// otherwise it gets the file path of the ID and reads the file from disk.
|
||||||
fn read(id: FileId, project_root: &Path) -> FileResult<Vec<u8>> {
|
fn read(
|
||||||
|
id: FileId,
|
||||||
|
project_root: &Path,
|
||||||
|
package_storage: &PackageStorage,
|
||||||
|
) -> FileResult<Vec<u8>> {
|
||||||
if id == *STDIN_ID {
|
if id == *STDIN_ID {
|
||||||
read_from_stdin()
|
read_from_stdin()
|
||||||
} else {
|
} else {
|
||||||
read_from_disk(&system_path(project_root, id)?)
|
read_from_disk(&system_path(project_root, id, package_storage)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,8 @@ pub struct TextElem {
|
|||||||
/// variable to add directories that should be scanned for fonts. The
|
/// variable to add directories that should be scanned for fonts. The
|
||||||
/// priority is: `--font-paths` > system fonts > embedded fonts. Run
|
/// priority is: `--font-paths` > system fonts > embedded fonts. Run
|
||||||
/// `typst fonts` to see the fonts that Typst has discovered on your
|
/// `typst fonts` to see the fonts that Typst has discovered on your
|
||||||
/// system.
|
/// system. Note that you can pass the `--ignore-system-fonts` parameter
|
||||||
|
/// to the CLI to ensure Typst won't search for system fonts.
|
||||||
///
|
///
|
||||||
/// ```example
|
/// ```example
|
||||||
/// #set text(font: "PT Sans")
|
/// #set text(font: "PT Sans")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user