feat: built-in slash commands + Ctrl+Shift+Space default hotkey

This commit is contained in:
Felix Isaac Lim 2026-05-23 11:32:36 +08:00
parent 71a6447f98
commit 05dc259155
4 changed files with 49 additions and 7 deletions

View file

@ -79,7 +79,7 @@ export default class InlineAIChatPlugin extends Plugin {
cmEditor.dispatch({ effects });
}
},
hotkeys: [],
hotkeys: [{ modifiers: ["Ctrl", "Shift"], key: " " }],
});
this.addCommand({
id: "accept-tooltip",

View file

@ -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;
}

View file

@ -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");

View file

@ -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)