15d7f5e873
- 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>
53 lines
2.1 KiB
Rust
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)
|
|
}
|