5e8020aa38
Editor previews (colour swatches, arrows, embeds), the 18 obsidian-basics tasks (find and replace with regex, back/forward, auto-pair, footnotes, folding, search operators, split view, PDF/audio/ video embeds, spelling, drag and drop, pinned tabs, settings) and round 2: ```query blocks, stacked tabs, pop-out windows, tasks ticked inside embeds, text around an embed, embeds that follow edits, block menu shortcut. New crates: notescraft-regex (linear-time engine) and notescraft-syntax. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
94 lines
4.3 KiB
Rust
94 lines
4.3 KiB
Rust
//! The `block.*` commands: list, move, duplicate, delete and turn into, each one edit on disk.
|
|
|
|
mod common;
|
|
|
|
use common::{on_disk, seed, temp_vault};
|
|
use notescraft_engine::{Registry, Session, register_core};
|
|
use serde_json::{Value, json};
|
|
|
|
const NOTE: &str = "# Title\n\nFirst para\n\nSecond para\n";
|
|
|
|
fn setup(name: &str) -> (Registry<Session>, Session, common::TempVault) {
|
|
let vault = temp_vault(name);
|
|
seed(vault.path(), &[("n.md", NOTE)]);
|
|
let mut registry = Registry::new();
|
|
register_core(&mut registry).expect("register");
|
|
let session = Session::open(vault.path()).expect("open");
|
|
(registry, session, vault)
|
|
}
|
|
|
|
fn run(registry: &Registry<Session>, session: &mut Session, id: &str, params: &Value) -> Value {
|
|
registry.run(id, session, params).unwrap_or_else(|error| panic!("{id}: {error:?}"))
|
|
}
|
|
|
|
#[test]
|
|
fn list_reports_every_top_level_block() {
|
|
let (registry, mut session, _vault) = setup("block-list");
|
|
let result = run(®istry, &mut session, "block.list", &json!({ "path": "n.md" }));
|
|
assert_eq!(result["blocks"].as_array().expect("blocks").len(), 3);
|
|
}
|
|
|
|
#[test]
|
|
fn move_swaps_with_the_neighbour_and_is_undone_by_moving_back() {
|
|
let (registry, mut session, vault) = setup("block-move");
|
|
run(®istry, &mut session, "block.move", &json!({ "path": "n.md", "index": 2, "direction": "up" }));
|
|
assert_eq!(on_disk(vault.path(), "n.md"), "# Title\n\nSecond para\n\nFirst para\n");
|
|
run(®istry, &mut session, "block.move", &json!({ "path": "n.md", "index": 1, "direction": "down" }));
|
|
assert_eq!(on_disk(vault.path(), "n.md"), NOTE);
|
|
}
|
|
|
|
#[test]
|
|
fn duplicate_delete_and_turn_into_change_one_block() {
|
|
let (registry, mut session, vault) = setup("block-edit");
|
|
run(®istry, &mut session, "block.turn_into", &json!({ "path": "n.md", "index": 1, "target": "heading2" }));
|
|
assert!(on_disk(vault.path(), "n.md").contains("## First para"));
|
|
run(®istry, &mut session, "block.duplicate", &json!({ "path": "n.md", "index": 2 }));
|
|
assert_eq!(on_disk(vault.path(), "n.md").matches("Second para").count(), 2);
|
|
run(®istry, &mut session, "block.delete", &json!({ "path": "n.md", "index": 3 }));
|
|
assert_eq!(on_disk(vault.path(), "n.md").matches("Second para").count(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn hostile_input_is_refused_not_applied() {
|
|
let (registry, mut session, vault) = setup("block-hostile");
|
|
for params in [
|
|
json!({ "path": "n.md", "index": 99, "direction": "up" }),
|
|
json!({ "path": "n.md", "index": 0, "direction": "left" }),
|
|
json!({ "path": "../x.md", "index": 0, "direction": "up" }),
|
|
] {
|
|
assert!(registry.run("block.move", &mut session, ¶ms).is_err(), "{params}");
|
|
}
|
|
assert!(registry.run("block.turn_into", &mut session, &json!({ "path": "n.md", "index": 1, "target": "heading9" })).is_err());
|
|
assert_eq!(on_disk(vault.path(), "n.md"), NOTE);
|
|
}
|
|
|
|
const JSON_NOTE: &str = "# T\n\n```json\n{\"b\":1,\"a\":[1e5]}\n```\n";
|
|
|
|
#[test]
|
|
fn json_format_and_minify_rewrite_only_the_block_body() {
|
|
let vault = temp_vault("json-block");
|
|
seed(vault.path(), &[("j.md", JSON_NOTE)]);
|
|
let mut registry = Registry::new();
|
|
register_core(&mut registry).expect("register");
|
|
let mut session = Session::open(vault.path()).expect("open");
|
|
let result = run(®istry, &mut session, "json.format_block", &json!({ "path": "j.md", "index": 1 }));
|
|
assert_eq!(result["changed"], json!(true));
|
|
assert_eq!(on_disk(vault.path(), "j.md"), "# T\n\n```json\n{\n \"b\": 1,\n \"a\": [\n 1e5\n ]\n}\n```\n");
|
|
run(®istry, &mut session, "json.minify_block", &json!({ "path": "j.md", "index": 1 }));
|
|
assert_eq!(on_disk(vault.path(), "j.md"), JSON_NOTE);
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_json_is_an_error_and_the_note_is_untouched() {
|
|
let vault = temp_vault("json-invalid");
|
|
let broken = "```json\n{\"a\":\n```\n";
|
|
seed(vault.path(), &[("j.md", broken), ("p.md", "plain\n")]);
|
|
let mut registry = Registry::new();
|
|
register_core(&mut registry).expect("register");
|
|
let mut session = Session::open(vault.path()).expect("open");
|
|
assert!(registry.run("json.format_block", &mut session, &json!({ "path": "j.md", "index": 0 })).is_err());
|
|
assert_eq!(on_disk(vault.path(), "j.md"), broken);
|
|
assert!(registry.run("json.format_block", &mut session, &json!({ "path": "p.md", "index": 0 })).is_err());
|
|
assert_eq!(on_disk(vault.path(), "p.md"), "plain\n");
|
|
}
|