From 05dc2591554d5ca919f42e5050ba6055cc89d5c2 Mon Sep 17 00:00:00 2001 From: Felix Isaac Lim <38658663+FelixIsaac@users.noreply.github.com> Date: Sat, 23 May 2026 11:32:36 +0800 Subject: [PATCH] feat: built-in slash commands + Ctrl+Shift+Space default hotkey --- src/main.ts | 2 +- src/modules/commands/parser.ts | 7 +++--- src/modules/commands/source.ts | 41 ++++++++++++++++++++++++++++++++-- src/settings.ts | 6 ++++- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/main.ts b/src/main.ts index a125996..6f98a57 100644 --- a/src/main.ts +++ b/src/main.ts @@ -79,7 +79,7 @@ export default class InlineAIChatPlugin extends Plugin { cmEditor.dispatch({ effects }); } }, - hotkeys: [], + hotkeys: [{ modifiers: ["Ctrl", "Shift"], key: " " }], }); this.addCommand({ id: "accept-tooltip", diff --git a/src/modules/commands/parser.ts b/src/modules/commands/parser.ts index 5057279..e5af489 100644 --- a/src/modules/commands/parser.ts +++ b/src/modules/commands/parser.ts @@ -1,15 +1,16 @@ -import { SlashCommand } from "./source"; +import { SlashCommand, BUILT_IN_COMMANDS } from "./source"; export function parseCommand( userInput: string, prefix: string, customCommands: SlashCommand[], ): string { - for (const command of customCommands) { + const allCommands = [...BUILT_IN_COMMANDS, ...customCommands]; + for (const command of allCommands) { const commandPattern = `${prefix}${command.keyword}`; if (userInput.includes(commandPattern)) { return userInput.replace(commandPattern, command.prompt); } } - return userInput; // Return original text if no command matches + return userInput; } diff --git a/src/modules/commands/source.ts b/src/modules/commands/source.ts index 99410fa..6842d7b 100644 --- a/src/modules/commands/source.ts +++ b/src/modules/commands/source.ts @@ -17,6 +17,41 @@ export interface SlashCommand { prompt: string; } +export const BUILT_IN_COMMANDS: SlashCommand[] = [ + { + keyword: "fix", + prompt: "Fix grammar, spelling, and punctuation. Keep the original meaning and style. Output only the corrected text.", + }, + { + keyword: "shorter", + prompt: "Make this text more concise. Remove filler words and redundancy. Keep all key information. Output only the shortened text.", + }, + { + keyword: "longer", + prompt: "Expand this text with more detail, examples, or explanation. Keep the same tone. Output only the expanded text.", + }, + { + keyword: "formal", + prompt: "Rewrite this text in a formal, professional tone. Output only the rewritten text.", + }, + { + keyword: "casual", + prompt: "Rewrite this text in a friendly, casual tone. Output only the rewritten text.", + }, + { + keyword: "bullets", + prompt: "Convert this text into a clear bullet-point list using Obsidian markdown. Output only the bullet list.", + }, + { + keyword: "summarize", + prompt: "Write a concise summary of this text in 2-3 sentences. Output only the summary.", + }, + { + keyword: "continue", + prompt: "Continue writing from where this text ends, matching the tone and style. Output only the continuation — do not repeat existing text.", + }, +]; + // Factory function that creates a completion source with custom parameters function createSlashCommandSource( options: { @@ -28,12 +63,13 @@ function createSlashCommandSource( }, ) { const { prefix, customCommands } = options; + const allCommands = [...BUILT_IN_COMMANDS, ...customCommands]; return (context: CompletionContext) => { let word = context.matchBefore(new RegExp(`^\\${prefix}\\w*`)); if (!word || (word.from == word.to && !context.explicit)) return null; return { from: word.from + 1, - options: customCommands.map((cmd) => ({ + options: allCommands.map((cmd) => ({ label: cmd.keyword, type: undefined, detail: cmd.prompt, @@ -82,7 +118,8 @@ export function createSlashCommandHighlighter({ } buildDecorations(view: EditorView) { - const keywords = customCommands + const allCommands = [...BUILT_IN_COMMANDS, ...customCommands]; + const keywords = allCommands .map((cmd) => cmd.keyword) .join("|"); const regexp = new RegExp(`\\${prefix}(${keywords})\\b`, "g"); diff --git a/src/settings.ts b/src/settings.ts index 9a0aa84..1f2d9d4 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,7 +1,7 @@ import { App, PluginSettingTab, Setting, Notice } from "obsidian"; import MyPlugin from "./main"; import { cursorPrompt, selectionPrompt } from "./default_prompts"; -import { SlashCommand } from "./modules/commands/source"; +import { SlashCommand, BUILT_IN_COMMANDS } from "./modules/commands/source"; import { startCodexOAuthFlow } from "./codex-auth"; // Interface for the settings @@ -414,6 +414,10 @@ export class InlineAISettingsTab extends PluginSettingTab { containerEl.createEl("p", { text: "Add your own custom commands. Triggered with the prefix defined in the Command Prefix setting.", }); + containerEl.createEl("p", { + text: `Built-in: ${BUILT_IN_COMMANDS.map((c) => this.plugin.settings.commandPrefix + c.keyword).join(" • ")}`, + cls: "setting-item-description", + }); // Command Prefix setting new Setting(containerEl)