text-editor
A simple text editor demonstrating file operations and UI integration.
Overview
This example shows:
- File open/save dialogs
- Full file system access patterns
- Clipboard read/write
- Context menus
- Window title updates
Features
- Open and save text files
- Standard edit operations (cut, copy, paste)
- File change detection (unsaved indicator)
- Right-click context menu
Running
forge dev examples/text-editorCapabilities
[capabilities.fs]read = ["~/*", "./*"] # Home directory and current directorywrite = ["~/*", "./*"]
[capabilities.sys]clipboard = truenotifications = true
[capabilities.channels]allowed = ["*"]Key Patterns
File Dialogs
import { showOpenDialog, showSaveDialog } from "runtime:window";import { readTextFile, writeTextFile } from "runtime:fs";
// Open fileconst result = await showOpenDialog({ title: "Open File", filters: [ { name: "Text Files", extensions: ["txt", "md"] }, { name: "All Files", extensions: ["*"] } ]});
if (result.filePaths.length > 0) { const content = await readTextFile(result.filePaths[0]); // Update editor...}
// Save fileconst saveResult = await showSaveDialog({ title: "Save File", defaultPath: currentFile || "untitled.txt"});
if (saveResult.filePath) { await writeTextFile(saveResult.filePath, editorContent);}Window Title
import { setWindowTitle } from "runtime:window";
// Show filename and unsaved indicatorconst title = `Forge Editor - ${filename}${hasChanges ? " *" : ""}`;await setWindowTitle(windowId, title);Clipboard
import { readClipboard, writeClipboard } from "runtime:sys";
// Cutconst selected = getSelection();await writeClipboard(selected);deleteSelection();
// Pasteconst text = await readClipboard();insertText(text);Context Menu
import { showContextMenu } from "runtime:window";
document.addEventListener("contextmenu", async (e) => { e.preventDefault();
const action = await showContextMenu({ items: [ { id: "cut", label: "Cut", accelerator: "Cmd+X" }, { id: "copy", label: "Copy", accelerator: "Cmd+C" }, { id: "paste", label: "Paste", accelerator: "Cmd+V" }, { type: "separator" }, { id: "selectAll", label: "Select All", accelerator: "Cmd+A" } ] });
handleAction(action);});File Access Patterns
The capability read = ["~/*", "./*"] means:
~/*- Any file in user’s home directory./*- Any file in the app’s working directory
For production, consider narrower patterns like:
read = ["~/Documents/*", "~/Desktop/*"]write = ["~/Documents/*"]