一键导入
pine-richtext
Use when building Rust/WASM rich-text editors with the Pine document model, schema setup, markdown round-trips, or table extensions
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when building Rust/WASM rich-text editors with the Pine document model, schema setup, markdown round-trips, or table extensions
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when turning a Claude Design (or any mockup/design) into a well-structured pocopine app — choosing app architecture (a store plus layout/leaf components), translating inline styles into Pine Stylekit, wiring icons and resizable regions, and verifying the result.
Use when working with the pocopine Pine icons feature — the `icon!` proc macro for compile-time Rust SVG embedding, or the `<pine-icon>` template primitive with `register_icons!` for tree-shaking-friendly template rendering.
Use when building styles with Pine Stylekit, the Pocopine-native utility-CSS compiler, or working with @theme tokens and CSS generation in Rust/WASM projects
Use when building enter/leave transitions, layout animations, stagger effects, or spring-physics motion in pocopine components
Use when implementing authentication in pocopine apps — JWT verification, credentials, OAuth providers, session management, or guards
Use when defining background jobs, enqueueing work, configuring workers, or troubleshooting job execution in pocopine apps
| name | pine-richtext |
| description | Use when building Rust/WASM rich-text editors with the Pine document model, schema setup, markdown round-trips, or table extensions |
Pine-richtext is a Rust-native rich-text document model, transform engine, and editor state layer ported from ProseMirror. It provides a schema-based type system, atomic transforms (replace, mark, wrap, lift), undo/redo via the history plugin, and markdown I/O via extension-supplied emitters and parse rules. The optional view feature adds a browser DOM editor surface and Pocopine component integration.
Schema — type system declaring node specs, mark specs, and content expressions (e.g., content("paragraph+")). Built via RuntimeBuilder::new().with(extensions).build().Node — immutable tree node with type_name(), attrs(), content(), marks(). Fragments use Arc<Vec<Node>> for cheap cloning.Fragment — ordered list of child nodes. Mutations via push(), replace_child() trigger copy-on-write.Mark — inline formatting (strong, em, link, code, custom). Added/removed atomically across ranges.Slice — tree fragment with open_start / open_end describing partially-open contexts (used in paste, wrap, lift).ResolvedPos — position + full path through tree depths. Built via doc.resolve(pos)?, exposes parent(), index(depth), before(depth), after(depth).Transform::replace(from, to, slice) — core primitive: delete [from..to], insert slice. Runs through a fitter chain that auto-wraps/unwraps to match schema.Transform::mark(from, to, mark, add) — add or remove a mark across a range.Transform::attr(pos, attr, value) — set a node attribute.Transform::wrap(from, to, node_type, attrs) — wrap range in a block. Decomposes to ReplaceAroundStep for mapping stability.Transform::lift(from, to, depth) — lift range out of its ancestors up to depth. Splits wrappers at each level.Step — immutable instruction: Replace, ReplaceAround, AddMark, RemoveMark, Attr, DocAttr. Serializes to JSON for wire transfer.StepMap & Mapping — position tracking across a chain of steps. Used for undo/redo and collaboration.EditorState — document + selection + transaction history. Built via EditorStateConfig::new(schema).Selection — text range or node selection. Stable across mapping.Transaction — mutable builder; collects steps, applies them on state.apply(tr).Plugin — per-state hook for metadata (history, decoration, input rules). Registered via extension.RichTextExtension::markdown_node_emitters() — map custom node types to NodeEmitter closures. Each emitter receives &Node, parent, index, and EventSink to push pulldown_cmark::Events.RichTextExtension::markdown_parse_rules() — vector of MarkdownParseRule. Each rule claims a ParseMatch (a pulldown_cmark::Tag or Event::* variant) and maps to ParseMapping:
ParseMapping::Block — open a container builder (e.g., table, blockquote).ParseMapping::Mark — push an inline mark for the scope.ParseMapping::LeafNode — emit an atomic leaf (e.g., image, horizontal rule).ParseMapping::Custom — escape hatch callback for contextual logic (e.g., task-list marker flagging).ParseSink — mutable handle passed to Custom callbacks; provides set_current_item_attr(), flag_enclosing_list_as_task(), schema access.EventSink — mutable handle passed to NodeEmitter; provides push(event), render_content(node), render_node(node, parent, index).Tables are opt-in via a TablesExtension implementing the markdown C4 contract. Schema nodes:
table — top-level block. Attr alignments: Vec<Option<Alignment>> stores per-column alignment (left/center/right/default).table_row — direct child of table. Contains cells only.table_header_cell — first row's cells (rendered <th>).table_cell — body-row cells (rendered <td>).Commands: insert_table { rows, cols }, insert_row_above, insert_row_below, insert_column_left, insert_column_right, delete_row, delete_column, delete_table. Key bindings: Tab advances cell (appends row at end), Shift-Tab retreats, Enter inserts hard break (cells are inline-only).
Markdown: Tables serialize/parse as GFM |---| pipe-format. No rowspan/colspan. Alignment stored in table attrs, rendered via style="text-align:..." per cell.
// /home/zempare-mambisi/RustProjects/pocopine/examples/richtext/src/lib.rs (lines 20-26)
use pine_richtext::extensions::{
CoreMarksExtension, MarkdownShortcutsExtension, SmartTypographyExtension, TaskListExtension,
};
use pine_richtext::runtime::{self, RuntimeBuilder};
let doc_runtime = RuntimeBuilder::new()
.name("doc")
.with(CoreNodesExtension)
.with(ListsExtension)
.with(TaskListExtension::new())
.with(CoreInlineExtension)
.with(CoreMarksExtension)
.with(HistoryExtension)
.build();
runtime::registry::register("doc", doc_runtime);
// /home/zempare-mambski/RustProjects/pocopine/crates/pine-richtext/src/extensions/task_list.rs (lines 142–172)
fn markdown_node_emitters(&self) -> Vec<(String, NodeEmitter)> {
vec![
(
"task_item".into(),
Arc::new(|node, _parent, _index, sink: &mut EventSink<'_>| {
let checked = node.attrs()
.get("checked")
.and_then(|v| v.as_bool())
.unwrap_or(false);
sink.push(MdEvent::Start(MdTag::Item));
sink.push(MdEvent::TaskListMarker(checked)); // GFM [ ] or [x]
sink.render_content(node);
sink.push(MdEvent::End(MdTagEnd::Item));
}),
),
]
}
// RFC 079 example (conceptual; not yet implemented in examples)
fn markdown_parse_rules(&self) -> Vec<MarkdownParseRule> {
vec![
MarkdownParseRule {
matches: ParseMatch::Tag(TagKind::Table),
maps_to: ParseMapping::Block {
node_type: "table".into(),
get_attrs: Some(Arc::new(|event| {
let mut attrs = Attrs::new();
if let Event::Start(Tag::Table(alignments)) = event {
let v: Vec<Value> = alignments.iter()
.map(|a| alignment_to_json(a))
.collect();
attrs.insert("alignments".into(), json!(v));
}
attrs
})),
},
},
]
}
// /home/zempare-mambski/RustProjects/pocopine/examples/richtext/src/lib.rs (lines 127–135)
pub fn wrap_in_blockquote(&mut self) {
self.with_editor(|e| {
e.dispatch(CommandRequest::WrapIn {
node_type: "blockquote".into(),
attrs: Attrs::new(),
})
});
}
Arc<Vec<Node>>: clones are refcount bumps, not deep copies. Preserve this invariant; removing Arc regresses benchmarks ~20,000×.MarkSpec::new("em") auto-excludes other "em" marks. Call .excludes("") to allow stacking.Table parse rule, GFM pipe-table markdown is silently dropped and treated as plain text. Enable tables via extension.NodeSpec { defining_for_content: true } (blockquote, code_block, list_item) preserve their structure on paste instead of unwrapping. Don't set this flag unless semantically necessary.parse(serialize(doc)) must equal the original doc. Non-GFM markdown features (merged cells, nested blocks in table cells, captions) cannot round-trip.crates/pine-richtext — model, transform, state, extensions, markdown, history, view./rfcs/rfc-079-pine-richtext-tables-extension.md — schema, commands, key bindings, markdown emit/parse, DOM rendering for tables.crates/pine-richtext/docs/ARCHITECTURE.md — ResolvedPos, Fragment refcount trick, replace pipeline, step mapping, wrap/lift, mark exclusion, defining-context merge.crates/pine-richtext/docs/extensions.md — runtime builder, extension contract, node-view components, backward compatibility.examples/richtext — kitchen-sink demo with two runtimes (doc editor + minimal comment box), toolbar commands, markdown import/export, task-list custom element.