Files
notescraft/crates/blocks/src/insert.rs
T
Marcos Paulo 15d7f5e873 feat: editor blocks and lint, vault knowledge, calendar plugin, macOS menu
- notescraft-lint (rules, safe fixes, learned style) and notescraft-blocks (block model and edits); engine lint.* and block.* commands with CLI and MCP parity
- Lint tab, underlines, slash menu with preview in Source and Visual, block grip and menu, Settings > Editor and lint, Vim block keys
- Visual view: tables, note embeds, %% comments, wrapping property chips
- Vault knowledge (Related tab, assistant sources, Settings) and calendar plugin
- Sidebar top padding fixed, dot grid follows PaperCraft spacing, right-card tabs no longer cover the collapse button

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 12:36:00 -03:00

53 lines
2.1 KiB
Rust

//! Component inserts for the slash menu.
use super::{Edited, splice};
use crate::{Error, Result};
/// A component the slash menu can insert.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Component {
/// 2 column table with a header row and two body rows.
Table,
/// `> [!note]` callout.
Callout,
/// Fenced `calendar` block.
Calendar,
/// Fenced `mermaid` diagram.
Diagram,
/// Embed of a new `.draw` whiteboard.
Whiteboard,
/// Embed of the template note with this name.
Template(String),
}
/// Insert `component` at `offset`; the caret lands in the first editable place.
///
/// A newline is added before when `offset` is mid-line and after when text
/// follows on the same line.
///
/// # Errors
/// [`Error::Offset`] if `offset` is past the end, [`Error::CharBoundary`] if it splits a character.
pub fn insert_component(text: &str, offset: usize, component: &Component) -> Result<Edited> {
if offset > text.len() {
return Err(Error::Offset { offset, len: text.len() });
}
let (Some(head), Some(tail)) = (text.get(..offset), text.get(offset..)) else {
return Err(Error::CharBoundary { start: offset, end: offset });
};
let (snippet, caret_in) = match component {
Component::Table => ("| | |\n| --- | --- |\n| | |\n| | |".to_owned(), 2),
Component::Callout => ("> [!note]\n> ".to_owned(), "> [!note]\n> ".len()),
Component::Calendar => ("```calendar\n\n```".to_owned(), "```calendar\n".len()),
Component::Diagram => {
let s = "```mermaid\nflowchart TD\n A --> B\n```";
(s.to_owned(), s.len() - "\n```".len())
}
Component::Whiteboard => ("![[Untitled.draw]]".to_owned(), "![[Untitled".len()),
Component::Template(name) => (format!("![[{name}]]"), name.len() + 3),
};
let pre = if head.is_empty() || head.ends_with('\n') { "" } else { "\n" };
let post = if tail.is_empty() || tail.starts_with('\n') { "" } else { "\n" };
let caret = offset + pre.len() + caret_in;
splice(text, offset..offset, format!("{pre}{snippet}{post}"), caret)
}