Context sensitive slashCommands (with onlyContexts and exceptContexts)
parent
236b2a7fdd
commit
a28c3fd5b8
|
@ -53,8 +53,10 @@ export type SlashCommandDef = {
|
|||
name: string;
|
||||
description?: string;
|
||||
boost?: number;
|
||||
// Parent AST nodes in which this slash command is available
|
||||
contexts?: string[];
|
||||
// Parent AST nodes in which this slash command is available, defaults to everywhere
|
||||
onlyContexts?: string[];
|
||||
// Parent AST nodes in which this slash command is not available
|
||||
exceptContexts?: string[];
|
||||
};
|
||||
export type SlashCommandHookT = {
|
||||
slashCommand?: SlashCommandDef;
|
||||
|
|
|
@ -29,20 +29,37 @@ export async function snippetSlashComplete(
|
|||
// where hooks.snippet.slashCommand exists
|
||||
filter: ["attr", ["attr", ["attr", "hooks"], "snippet"], "slashCommand"],
|
||||
}, 5);
|
||||
return {
|
||||
options: allTemplates.map((template) => {
|
||||
const snippetTemplate = template.hooks!.snippet!;
|
||||
const options: SlashCompletionOption[] = [];
|
||||
for (const template of allTemplates) {
|
||||
const snippetTemplate = template.hooks!.snippet!;
|
||||
|
||||
return {
|
||||
label: snippetTemplate.slashCommand,
|
||||
detail: template.description,
|
||||
order: snippetTemplate.order || 0,
|
||||
templatePage: template.ref,
|
||||
pageName: completeEvent.pageName,
|
||||
invoke: "template.insertSnippetTemplate",
|
||||
};
|
||||
}),
|
||||
};
|
||||
if (
|
||||
snippetTemplate.onlyContexts && !snippetTemplate.onlyContexts.some(
|
||||
(context) =>
|
||||
completeEvent.parentNodes.some((node) => node.startsWith(context)),
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
snippetTemplate.exceptContexts && snippetTemplate.exceptContexts.some(
|
||||
(context) =>
|
||||
completeEvent.parentNodes.some((node) => node.startsWith(context)),
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
options.push({
|
||||
label: snippetTemplate.slashCommand,
|
||||
detail: template.description,
|
||||
order: snippetTemplate.order || 0,
|
||||
templatePage: template.ref,
|
||||
pageName: completeEvent.pageName,
|
||||
invoke: "template.insertSnippetTemplate",
|
||||
});
|
||||
}
|
||||
return { options };
|
||||
}
|
||||
|
||||
export async function insertSnippetTemplate(
|
||||
|
|
|
@ -31,6 +31,8 @@ export type SnippetConfig = CommandConfig & {
|
|||
// Deprecated: use matchRegex instead (for backwards compatibility)
|
||||
match?: string;
|
||||
insertAt?: "cursor" | "line-start" | "line-end" | "page-start" | "page-end"; // defaults to cursor
|
||||
onlyContexts?: string[];
|
||||
exceptContexts?: string[];
|
||||
};
|
||||
|
||||
export type WidgetConfig = {
|
||||
|
@ -97,6 +99,12 @@ export const SnippetConfigSchema: JSONSchemaType<SnippetConfig> = {
|
|||
order: { type: "number", nullable: true },
|
||||
matchRegex: { type: "string", nullable: true },
|
||||
match: { type: "string", nullable: true },
|
||||
onlyContexts: { type: "array", items: { type: "string" }, nullable: true },
|
||||
exceptContexts: {
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
nullable: true,
|
||||
},
|
||||
insertAt: {
|
||||
type: "string",
|
||||
enum: [
|
||||
|
|
|
@ -110,10 +110,16 @@ export class SlashCommandHook implements Hook<SlashCommandHookT> {
|
|||
|
||||
// Check if the slash command is available in the current context
|
||||
const parentNodes = this.editor.extractParentNodes(ctx.state, currentNode);
|
||||
// console.log("Parent nodes", parentNodes);
|
||||
for (const def of this.slashCommands.values()) {
|
||||
if (
|
||||
def.slashCommand.contexts && !def.slashCommand.contexts.some(
|
||||
def.slashCommand.onlyContexts && !def.slashCommand.onlyContexts.some(
|
||||
(context) => parentNodes.some((node) => node.startsWith(context)),
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
def.slashCommand.exceptContexts && def.slashCommand.exceptContexts.some(
|
||||
(context) => parentNodes.some((node) => node.startsWith(context)),
|
||||
)
|
||||
) {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
description: Insert a fenced code block
|
||||
tags: template
|
||||
hooks.snippet.slashCommand: code
|
||||
hooks.snippet:
|
||||
slashCommand: code
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
```|^|
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ tags: template
|
|||
hooks.snippet:
|
||||
slashCommand: "#each"
|
||||
order: 10
|
||||
onlyContexts:
|
||||
- FencedCode:template
|
||||
---
|
||||
{{escapeDirective("#each |^|")}}
|
||||
|
||||
|
|
|
@ -4,5 +4,7 @@ description: Make this a level 1 heading
|
|||
hooks.snippet:
|
||||
slashCommand: h1
|
||||
matchRegex: "^#*\\s*"
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
#
|
|
@ -4,5 +4,7 @@ description: Make this a level 2 heading
|
|||
hooks.snippet:
|
||||
slashCommand: h2
|
||||
matchRegex: "^#*\\s*"
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
##
|
|
@ -4,5 +4,7 @@ description: Make this a level 3 heading
|
|||
hooks.snippet:
|
||||
slashCommand: h3
|
||||
matchRegex: "^#*\\s*"
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
###
|
|
@ -4,5 +4,7 @@ description: Make this a level 4 heading
|
|||
hooks.snippet:
|
||||
slashCommand: h4
|
||||
matchRegex: "^#*\\s*"
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
####
|
|
@ -1,6 +1,9 @@
|
|||
---
|
||||
tags: template
|
||||
description: Insert a horizontal rule
|
||||
hooks.snippet.slashCommand: hr
|
||||
hooks.snippet:
|
||||
slashCommand: hr
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
---
|
||||
|
|
|
@ -4,6 +4,9 @@ tags: template
|
|||
hooks.snippet:
|
||||
slashCommand: "#if"
|
||||
order: 10
|
||||
onlyContexts:
|
||||
- FencedCode:template
|
||||
|
||||
---
|
||||
{{escapeDirective("#if |^|")}}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ tags: template
|
|||
hooks.snippet:
|
||||
slashCommand: "#if-else"
|
||||
order: 10
|
||||
onlyContexts:
|
||||
- FencedCode:template
|
||||
---
|
||||
{{escapeDirective("#if |^|")}}
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
tags: template
|
||||
description: Add a live preview of a page
|
||||
hooks.snippet.slashCommand: include-page
|
||||
hooks.snippet:
|
||||
slashCommand: include-page
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
```include
|
||||
raw: "[[|^|]]"
|
||||
|
|
|
@ -6,5 +6,7 @@ hooks.snippet:
|
|||
matchRegex: "^(\\s*)[\\-\\*]?\\s*"
|
||||
command: "Text: Turn into a bullet item"
|
||||
key: "Ctrl-q i"
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
$1*
|
|
@ -4,6 +4,8 @@ tags: template
|
|||
hooks.snippet:
|
||||
slashCommand: "#let"
|
||||
order: 10
|
||||
onlyContexts:
|
||||
- FencedCode:template
|
||||
---
|
||||
{{escapeDirective("#let @|^| = ")}}
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
description: Insert a live query
|
||||
tags: template
|
||||
hooks.snippet.slashCommand: query
|
||||
hooks.snippet:
|
||||
slashCommand: query
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
```query
|
||||
|^|
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
tags: template
|
||||
description: Insert a table
|
||||
hooks.snippet.slashCommand: table
|
||||
hooks.snippet:
|
||||
slashCommand: table
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
| Header A | Header B |
|
||||
|----------|----------|
|
||||
|
|
|
@ -6,5 +6,7 @@ hooks.snippet:
|
|||
matchRegex: "^(\\s*)[\\-\\*]?\\s*(\\[[ xX]\\])?\\s*"
|
||||
command: "Text: Turn into task"
|
||||
key: "Ctrl-q t"
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
$1* [ ]
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
description: Insert a template
|
||||
tags: template
|
||||
hooks.snippet.slashCommand: "template"
|
||||
hooks.snippet:
|
||||
slashCommand: "template"
|
||||
exceptContexts:
|
||||
- FencedCode
|
||||
---
|
||||
```template
|
||||
|^|
|
||||
|
|
Loading…
Reference in New Issue