add: article link prepend
This commit is contained in:
parent
9f4d18863e
commit
a757f69e82
3 changed files with 59 additions and 8 deletions
20
prepends/article_link.typ
Normal file
20
prepends/article_link.typ
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#let article_link(path) = {
|
||||||
|
let file-path = path + "index.typ"
|
||||||
|
|
||||||
|
let content = read(file-path)
|
||||||
|
|
||||||
|
let title = none
|
||||||
|
for line in content.split("\n") {
|
||||||
|
let trimmed = line.trim()
|
||||||
|
if trimmed.starts-with("= ") {
|
||||||
|
title = trimmed.slice(2).trim()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if title == none {
|
||||||
|
panic("No level-1 heading found in " + file-path)
|
||||||
|
}
|
||||||
|
|
||||||
|
link(path)[#title]
|
||||||
|
}
|
||||||
46
src/lib.rs
46
src/lib.rs
|
|
@ -2,7 +2,7 @@ mod plugin;
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub use plugin::{concat_plugin_sources, embedded_prepend_source, list_embedded_plugin_ids};
|
pub use plugin::{concat_plugin_sources, embedded_prepend_source, list_embedded_plugin_ids};
|
||||||
|
|
||||||
|
|
@ -12,6 +12,17 @@ use typst::syntax::Source;
|
||||||
use typst_as_lib::{typst_kit_options::TypstKitFontOptions, TypstAsLibError, TypstEngine};
|
use typst_as_lib::{typst_kit_options::TypstKitFontOptions, TypstAsLibError, TypstEngine};
|
||||||
use typst_html::{HtmlAttr, HtmlDocument, HtmlElement, HtmlNode};
|
use typst_html::{HtmlAttr, HtmlDocument, HtmlElement, HtmlNode};
|
||||||
|
|
||||||
|
fn article_main_vpath(article_dir: &Path, root_dir: &Path) -> String {
|
||||||
|
let article = fs::canonicalize(article_dir).unwrap_or_else(|_| article_dir.to_path_buf());
|
||||||
|
let root = fs::canonicalize(root_dir).unwrap_or_else(|_| root_dir.to_path_buf());
|
||||||
|
let rel = article
|
||||||
|
.strip_prefix(&root)
|
||||||
|
.unwrap_or(article.as_path());
|
||||||
|
rel.join("index.typ")
|
||||||
|
.to_string_lossy()
|
||||||
|
.replace('\\', "/")
|
||||||
|
}
|
||||||
|
|
||||||
fn format_typst_compile_error(
|
fn format_typst_compile_error(
|
||||||
err: TypstAsLibError,
|
err: TypstAsLibError,
|
||||||
full_source: &str,
|
full_source: &str,
|
||||||
|
|
@ -66,19 +77,20 @@ fn format_typst_compile_error(
|
||||||
fn compile_source(
|
fn compile_source(
|
||||||
full_source: &str,
|
full_source: &str,
|
||||||
index_byte_start: usize,
|
index_byte_start: usize,
|
||||||
base_dir: &PathBuf,
|
vfs_root: &PathBuf,
|
||||||
|
main_vpath: &str,
|
||||||
include_title: bool,
|
include_title: bool,
|
||||||
) -> Result<(String, String), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(String, String), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let index_source = &full_source[index_byte_start..];
|
let index_source = &full_source[index_byte_start..];
|
||||||
|
|
||||||
let engine = TypstEngine::builder()
|
let engine = TypstEngine::builder()
|
||||||
.main_file(full_source.to_string())
|
.main_file((main_vpath, full_source.to_string()))
|
||||||
.search_fonts_with(
|
.search_fonts_with(
|
||||||
TypstKitFontOptions::default()
|
TypstKitFontOptions::default()
|
||||||
.include_system_fonts(false)
|
.include_system_fonts(false)
|
||||||
.include_embedded_fonts(true),
|
.include_embedded_fonts(true),
|
||||||
)
|
)
|
||||||
.with_file_system_resolver(base_dir)
|
.with_file_system_resolver(vfs_root)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut doc: HtmlDocument = engine
|
let mut doc: HtmlDocument = engine
|
||||||
|
|
@ -158,6 +170,7 @@ pub fn render_direct(
|
||||||
full_source.as_str(),
|
full_source.as_str(),
|
||||||
index_byte_start,
|
index_byte_start,
|
||||||
base_dir,
|
base_dir,
|
||||||
|
"index.typ",
|
||||||
include_title,
|
include_title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -167,6 +180,7 @@ pub fn render_direct(
|
||||||
/// `outline.html` in the same directory.
|
/// `outline.html` in the same directory.
|
||||||
pub fn compile_article(
|
pub fn compile_article(
|
||||||
article_dir: &PathBuf,
|
article_dir: &PathBuf,
|
||||||
|
root_dir: &PathBuf,
|
||||||
prepend: &Option<PathBuf>,
|
prepend: &Option<PathBuf>,
|
||||||
plugins: &[impl AsRef<str>],
|
plugins: &[impl AsRef<str>],
|
||||||
include_title: bool,
|
include_title: bool,
|
||||||
|
|
@ -177,6 +191,7 @@ pub fn compile_article(
|
||||||
let outline_file = article_dir.join("outline.html");
|
let outline_file = article_dir.join("outline.html");
|
||||||
|
|
||||||
let plugin_block = concat_plugin_sources(plugins)?;
|
let plugin_block = concat_plugin_sources(plugins)?;
|
||||||
|
let main_vpath = article_main_vpath(article_dir, root_dir);
|
||||||
|
|
||||||
let user_prepend = if let Some(prepend_file) = prepend {
|
let user_prepend = if let Some(prepend_file) = prepend {
|
||||||
fs::read_to_string(prepend_file).map_err(|e| {
|
fs::read_to_string(prepend_file).map_err(|e| {
|
||||||
|
|
@ -205,7 +220,8 @@ pub fn compile_article(
|
||||||
let (index_html, outline_html) = compile_source(
|
let (index_html, outline_html) = compile_source(
|
||||||
full_source.as_str(),
|
full_source.as_str(),
|
||||||
index_byte_start,
|
index_byte_start,
|
||||||
article_dir,
|
root_dir,
|
||||||
|
&main_vpath,
|
||||||
include_title,
|
include_title,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -338,15 +354,29 @@ pub fn compile_all(
|
||||||
plugins: &[impl AsRef<str>],
|
plugins: &[impl AsRef<str>],
|
||||||
include_title_in_outline: bool,
|
include_title_in_outline: bool,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
for entry in fs::read_dir(root_dir)? {
|
info!("compiling all files at dir {:?}", root_dir);
|
||||||
|
let res = compile_all_at(root_dir, root_dir, prepend, plugins, include_title_in_outline);
|
||||||
|
info!("done");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_all_at(
|
||||||
|
scan_dir: &PathBuf,
|
||||||
|
root_dir: &PathBuf,
|
||||||
|
prepend: &Option<PathBuf>,
|
||||||
|
plugins: &[impl AsRef<str>],
|
||||||
|
include_title_in_outline: bool,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
for entry in fs::read_dir(scan_dir)? {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
compile_all(&path, prepend, plugins, include_title_in_outline)?;
|
compile_all_at(&path, root_dir, prepend, plugins, include_title_in_outline)?;
|
||||||
} else if path.file_name().is_some_and(|n| n == "index.typ") {
|
} else if path.file_name().is_some_and(|n| n == "index.typ") {
|
||||||
let dir = path.parent().unwrap().to_path_buf();
|
let dir = path.parent().unwrap().to_path_buf();
|
||||||
if let Err(e) = compile_article(&dir, prepend, plugins, include_title_in_outline) {
|
if let Err(e) = compile_article(&dir, root_dir, prepend, plugins, include_title_in_outline)
|
||||||
|
{
|
||||||
error!("{e}");
|
error!("{e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ fn main() {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
compile_article(
|
compile_article(
|
||||||
|
&args.dir,
|
||||||
&args.dir,
|
&args.dir,
|
||||||
&args.prepend,
|
&args.prepend,
|
||||||
&args.plugin,
|
&args.plugin,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue