This skill should be used when the user asks about "obsidian editor API", "obsidian edit note", "obsidian getSelection", "obsidian replaceSelection", "obsidian cursor", "obsidian Editor class", "obsidian MarkdownView", "obsidian insert text", "obsidian modify active file", "obsidian CodeMirror", "obsidian editorCallback", or needs help reading or modifying the active markdown editor in an Obsidian plugin.
From obsidian-devnpx claudepluginhub nthplusio/functional-claude --plugin obsidian-devThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Executes pre-written implementation plans: critically reviews, follows bite-sized steps exactly, runs verifications, tracks progress with checkpoints, uses git worktrees, stops on blockers.
Read and modify the active markdown editor via the Editor class.
import { Editor, MarkdownView } from 'obsidian';
this.addCommand({
id: 'my-editor-command',
name: 'My editor command',
editorCallback: (editor: Editor, view: MarkdownView) => {
// editor is directly available here
},
});
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
if (!view) {
new Notice('No active markdown editor');
return;
}
const editor = view.editor;
// Selected text
const selection = editor.getSelection();
// Cursor position
const cursor = editor.getCursor(); // { line: number, ch: number }
// Entire document
const content = editor.getValue();
// A specific line
const lineText = editor.getLine(lineNumber); // 0-indexed
// Number of lines
const lineCount = editor.lineCount();
// Replace selected text
editor.replaceSelection('replacement text');
// Insert at cursor
editor.replaceRange('inserted text', editor.getCursor());
// Insert at specific position
editor.replaceRange('text', { line: 5, ch: 0 });
// Replace a range
editor.replaceRange(
'new content',
{ line: 2, ch: 0 }, // from
{ line: 2, ch: 20 } // to
);
// Replace entire document
editor.setValue('entirely new content');
// Move cursor
editor.setCursor({ line: 0, ch: 0 });
// Set a selection
editor.setSelection(
{ line: 1, ch: 0 }, // anchor (start)
{ line: 1, ch: 10 } // head (end)
);
// Focus the editor
editor.focus();
editorCallback: (editor: Editor) => {
const sel = editor.getSelection();
if (sel) {
editor.replaceSelection(`**${sel}**`);
} else {
// No selection — insert at cursor
const cursor = editor.getCursor();
editor.replaceRange('**bold text**', cursor);
// Move cursor inside the markers
editor.setCursor({ line: cursor.line, ch: cursor.ch + 2 });
}
}
editorCallback: (editor: Editor) => {
const template = `## Section\n\n- Item 1\n- Item 2\n`;
const cursor = editor.getCursor();
editor.replaceRange(template, cursor);
}
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
if (view?.file) {
const file = view.file;
const content = view.editor.getValue();
// Now you have both the TFile metadata and the raw content
}
Obsidian uses CodeMirror 6 as the underlying editor, but the Editor abstraction ensures your plugin works across both CM6 and legacy desktop. Use the Obsidian Editor API rather than accessing the CodeMirror instance directly unless you need advanced features not exposed by Obsidian.
${CLAUDE_PLUGIN_ROOT}/skills/obsidian-dev/references/api-reference.md → Editor API section