mirror of
https://github.com/zensical/zensical.git
synced 2026-09-25 07:45:36 +00:00
fix: rebuild pages containing snippets on source changes (#950)
Signed-off-by: squidfunk <martin.donath@squidfunk.com>
This commit is contained in:
@@ -37,6 +37,7 @@ use pyo3::{
|
||||
pyfunction, pymodule, wrap_pyfunction, Bound, FromPyObject, PyResult,
|
||||
Python,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
use std::time::{Duration, Instant};
|
||||
@@ -57,9 +58,10 @@ mod workflow;
|
||||
|
||||
use compat::mkdocs::plugin::meta;
|
||||
use config::Config;
|
||||
use path::SourcePath;
|
||||
use server::{create_server, ServeOptions};
|
||||
use watcher::Watcher;
|
||||
use workflow::{create_workflow, Configuration, Input};
|
||||
use workflow::{create_workflow, has_snippets, Configuration, Input};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Enums
|
||||
@@ -272,6 +274,7 @@ fn run(config_file: &PathBuf, mode: Mode) -> PyResult<bool> {
|
||||
docs: config.docs_root().clone(),
|
||||
context: config.project.docs_dir.clone(),
|
||||
});
|
||||
let mut snippets = BTreeMap::new();
|
||||
|
||||
// Start the event loop. Each debounced watcher batch is admitted as one
|
||||
// source revision and fully settled before the next batch is accepted.
|
||||
@@ -284,6 +287,33 @@ fn run(config_file: &PathBuf, mode: Mode) -> PyResult<bool> {
|
||||
metadata.prepare(&changes).map_err(|error| {
|
||||
PyRuntimeError::new_err(format!("{error:#}"))
|
||||
})?;
|
||||
let mut dependents = BTreeMap::from_iter(dependents);
|
||||
|
||||
// Until snippet dependencies are tracked, rebuild every page
|
||||
// containing a marker whenever a source changes in serve mode
|
||||
if serve {
|
||||
dependents.extend(snippets.clone());
|
||||
for change in &changes {
|
||||
let key = match change {
|
||||
Change::Insert(key, _) | Change::Remove(key) => key,
|
||||
};
|
||||
|
||||
// Explicit changes win over retained page entries
|
||||
dependents.remove(key);
|
||||
snippets.remove(key);
|
||||
if let Change::Insert(_, source) = change
|
||||
&& key[0].context() == config.project.docs_dir
|
||||
&& let Ok(path) =
|
||||
key[0].location().parse::<SourcePath>()
|
||||
&& path.extension() == Some("md")
|
||||
&& !path.is_hidden()
|
||||
&& has_snippets(&fs::read_to_string(&**source)?)
|
||||
{
|
||||
snippets.insert(key.clone(), source.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut revision = input
|
||||
.begin()
|
||||
.map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
|
||||
|
||||
@@ -68,7 +68,7 @@ use cached::cached;
|
||||
|
||||
/// Regular expression to detect use of snippets
|
||||
static SNIPPET_RE: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"^[ \t]*-+8<-+").expect("invariant"));
|
||||
LazyLock::new(|| Regex::new(r"(?m)^[ \t]*-+8<-+").expect("invariant"));
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Structs
|
||||
@@ -445,6 +445,11 @@ fn route_markdown(
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns whether Markdown contains a snippet marker.
|
||||
pub fn has_snippets(data: &str) -> bool {
|
||||
SNIPPET_RE.is_match(data.strip_prefix('\u{FEFF}').unwrap_or(data))
|
||||
}
|
||||
|
||||
/// Create a stream to process routed Markdown files.
|
||||
fn process_markdown(
|
||||
config: &Config, plugins: &plugin::Settings,
|
||||
@@ -468,7 +473,7 @@ fn process_markdown(
|
||||
// Don't cache page if it inserts (pymdownx) snippets.
|
||||
// This is a hack while waiting for CommonMark (AST) and components,
|
||||
// as well as topic-based authoring functionality.
|
||||
if SNIPPET_RE.is_match(&data) {
|
||||
if has_snippets(&data) {
|
||||
render_markdown(id, route, data, plugins.clone(), resolved)
|
||||
} else {
|
||||
cached(
|
||||
|
||||
Reference in New Issue
Block a user