From 1410b97aeb647f1c86865dc35a6c0b23130620ec Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Tue, 21 Jul 2026 23:25:11 +0200 Subject: [PATCH] Reopen published code only for content changes. --- README.md | 2 +- crates/bds-core/src/engine/script.rs | 146 +++++++++++++++++++++++-- crates/bds-core/src/engine/template.rs | 137 ++++++++++++++++++++--- specs/script.allium | 7 +- specs/template.allium | 7 +- 5 files changed, 273 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b62af9b..3de7ce6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The project is under active development. Core blogging workflows are broadly ava - Post and translation authoring with change-aware draft/published/archive lifecycle, file-backed change discard, canonical draft reopening after manual translation edits, non-disruptive automatic translation, desktop archive/unarchive actions, in-place published-frontmatter updates, metadata, tags, categories, live link/backlink graphs, media, and batch gallery-image import. - Media import, thumbnails, metadata translations, filters, validation, post assignment, and sequential drag-and-drop insertion into post editors. - WordPress WXR migration with saved analyses, HTML-to-Markdown and shortcode conversion, conflict/taxonomy review, recoverable 500-item execution batches, media-parent linking, progress reporting, and optional AI-assisted taxonomy mapping. -- Post, Liquid template, and Lua script editing with dedicated syntax highlighting, explicit syntax-check feedback, normalized collision-safe template/script slug changes, reference-safe template renames, and publish-time enforcement of the bDS2 Liquid tag/filter/operator subset, using a custom Ropey/Syntect/Cosmic Text editor and the documented, bDS2-signature-compatible project-scoped [`bds` host API](docs/scripting/API_REFERENCE.md) across utilities, rendered macros, and Blogmark transforms, including airplane-gated Git sync. +- Post, Liquid template, and Lua script editing with dedicated syntax highlighting, explicit syntax-check feedback, change-aware published/draft lifecycle, normalized collision-safe template/script slug changes, reference-safe template renames, and publish-time enforcement of the bDS2 Liquid tag/filter/operator subset, using a custom Ropey/Syntect/Cosmic Text editor and the documented, bDS2-signature-compatible project-scoped [`bds` host API](docs/scripting/API_REFERENCE.md) across utilities, rendered macros, and Blogmark transforms, including airplane-gated Git sync. - SQLite and filesystem persistence with frontmatter, relationship-safe media sidecars, rebuild, metadata diff/repair, stale post-path cleanup on republish, bDS2-compatible checksums and NFD slug generation, and FTS5 search. - Optional on-device multilingual semantic search and similar-post tag suggestions backed by a persistent USearch index, plus always-available partial-name tag autocomplete and duplicate-post review in the desktop workspace. - Read-only in-app browsers in the Help menu for the bundled global `DOCUMENTATION.md`, the generated Lua API reference with public types and runnable examples, the [CLI/server/TUI documentation](CLI.md), and the [MCP server documentation](MCP.md), with safe GFM rendering and confirmed external links. diff --git a/crates/bds-core/src/engine/script.rs b/crates/bds-core/src/engine/script.rs index 6b5cade..89e32e0 100644 --- a/crates/bds-core/src/engine/script.rs +++ b/crates/bds-core/src/engine/script.rs @@ -81,6 +81,15 @@ pub fn update_script( } let original_slug = script.slug.clone(); let original_file_path = script.file_path.clone(); + let was_published = script.status == ScriptStatus::Published; + let effective_content = script.content.clone().unwrap_or_else(|| { + if original_file_path.is_empty() { + String::new() + } else { + read_published_script_body(data_dir, &original_file_path) + } + }); + let content_changed = content.is_some_and(|new_content| new_content != effective_content); if let Some(requested_slug) = slug { let slug = slugify(requested_slug); @@ -112,17 +121,18 @@ pub fn update_script( } let slug_changed = script.slug != original_slug; - let published_body = if slug_changed && !original_file_path.is_empty() { - Some(read_published_script_body(data_dir, &original_file_path)) + let published_body = if !original_file_path.is_empty() + && (slug_changed || (was_published && !content_changed)) + { + Some(effective_content) } else { None }; - if published_body.is_some() { + if slug_changed && published_body.is_some() { script.file_path = script_file_path(&script.slug); } - // If published, transition back to draft on edit - if script.status == ScriptStatus::Published { + if was_published && content_changed { script.status = ScriptStatus::Draft; } @@ -137,17 +147,34 @@ pub fn update_script( } /// Save script content (editor save). Updates DB, bumps version. -pub fn save_script(conn: &Connection, script_id: &str, content: &str) -> EngineResult