Support carets in matchregex snippets

pull/719/head
Zef Hemel 2024-02-24 09:08:10 +01:00
parent 0cf36a0acf
commit d5f1ba6583
3 changed files with 75 additions and 34 deletions

View File

@ -110,6 +110,7 @@ export async function insertSnippetTemplate(slashCompletion: SlashCompletion) {
if (snippetTemplate.match || snippetTemplate.matchRegex) { if (snippetTemplate.match || snippetTemplate.matchRegex) {
const pageText = await editor.getText(); const pageText = await editor.getText();
// Regex matching mode // Regex matching mode
const matchRegex = new RegExp( const matchRegex = new RegExp(
(snippetTemplate.match || snippetTemplate.matchRegex)!, (snippetTemplate.match || snippetTemplate.matchRegex)!,
@ -119,21 +120,41 @@ export async function insertSnippetTemplate(slashCompletion: SlashCompletion) {
while (startOfLine > 0 && pageText[startOfLine - 1] !== "\n") { while (startOfLine > 0 && pageText[startOfLine - 1] !== "\n") {
startOfLine--; startOfLine--;
} }
let currentLine = pageText.slice(startOfLine, cursorPos); let endOfLine = cursorPos;
while (endOfLine < pageText.length && pageText[endOfLine] !== "\n") {
endOfLine++;
}
let currentLine = pageText.slice(startOfLine, endOfLine);
const caretParts = replacementText.split("|^|");
const emptyLine = !currentLine; const emptyLine = !currentLine;
currentLine = currentLine.replace(matchRegex, replacementText); currentLine = currentLine.replace(matchRegex, caretParts[0]);
let newSelection = emptyLine
? {
anchor: startOfLine + currentLine.length,
}
: undefined;
if (caretParts.length === 2) {
// The semantics of a caret in a replacement are:
// 1. It's a caret, so we need to move the cursor there
// 2. It's a placeholder, so we need to remove it
// 3. Any text after the caret should be inserted after the caret
const caretPos = currentLine.length;
// Now add the text after the caret
currentLine += caretParts[1];
newSelection = {
anchor: startOfLine + caretPos,
};
}
await editor.dispatch({ await editor.dispatch({
changes: { changes: {
from: startOfLine, from: startOfLine,
to: cursorPos, to: endOfLine,
insert: currentLine, insert: currentLine,
}, },
selection: emptyLine selection: newSelection,
? {
anchor: startOfLine + currentLine.length,
}
: undefined,
}); });
} else { } else {
const carretPos = replacementText.indexOf("|^|"); const carretPos = replacementText.indexOf("|^|");

View File

@ -20,6 +20,7 @@ _These features are not yet properly released, you need to use [the edge builds]
* There are also two very notable new plugs you may be interested in trying: * There are also two very notable new plugs you may be interested in trying:
* [[Plugs/TreeView]]: a sidebar showing (and allowing you to manipulate) your spaces folder tree (at long last) * [[Plugs/TreeView]]: a sidebar showing (and allowing you to manipulate) your spaces folder tree (at long last)
* [[Plugs/AI]]: various clever AI integrations (supporting many different LLMs, including locally hosted ones) * [[Plugs/AI]]: various clever AI integrations (supporting many different LLMs, including locally hosted ones)
* [[Snippets]] using `matchRegex` can now use the `|^|` caret to wrap text around the replacement, see the [[Snippets#Examples]]
* [[Space Script]] is now indexed in templates too (so you can put space script in template tagged pages) * [[Space Script]] is now indexed in templates too (so you can put space script in template tagged pages)
* Changed the signature of `silverbullet.registerFunction` to make the first argument an object, see [[Space Script#Custom functions]]. Old string-based scripts still work, for backwards compatibility. * Changed the signature of `silverbullet.registerFunction` to make the first argument an object, see [[Space Script#Custom functions]]. Old string-based scripts still work, for backwards compatibility.
* The [[Functions#replace(str, match, replacement)]] function now supports multiple replacements * The [[Functions#replace(str, match, replacement)]] function now supports multiple replacements

View File

@ -8,45 +8,64 @@ You define a snippet by creating a [[Templates|template]] with a `hooks.snippet`
* `command`: expose the snippet as a [[Commands|command]]. * `command`: expose the snippet as a [[Commands|command]].
* `key`: Bind the snippet to a keyboard shortcut (note: this requires to _also_ specify the `command` configuration). * `key`: Bind the snippet to a keyboard shortcut (note: this requires to _also_ specify the `command` configuration).
* `mac`: Bind the snippet to a Mac-specific keyboard shortcut. * `mac`: Bind the snippet to a Mac-specific keyboard shortcut.
* `matchRegex` (advanced use only): match the current line against a regular expression, and replace the match with the templates body. * `matchRegex` (advanced use only): match the _current line_ against a regular expression, and replace the match with the templates body. If a caret placeholder (`|^|`) appears in the templates body, the replacement body _before_ the caret will be the replacement of the matchRegex match, and the part _after_ that carret will be appended to the end of the line. This enables text wrapping behavior, see the example below.
* `insertAt`: by default a snippet is inserted at the cursor position, but alternatively it can be inserted at: `line-start`, `line-end`, `page-start` or `page-end`. * `insertAt`: by default a snippet is inserted at the cursor position, but alternatively it can be inserted at: `line-start`, `line-end`, `page-start` or `page-end`.
Minimal example: # Frontmatter
---
tags: template
hooks.snippet:
slashCommand: meeting-notes
---
## Meeting notes for {{today}}!
|^|
## Frontmatter
A templates [[Frontmatter]] is interpreted by SilverBullets [[Templates|template]] engine and removed when instantiated. However, to inject frontmatter after instantiation, you can use the `frontmatter` attribute. A templates [[Frontmatter]] is interpreted by SilverBullets [[Templates|template]] engine and removed when instantiated. However, to inject frontmatter after instantiation, you can use the `frontmatter` attribute.
Example: Example:
--- ```
tags: template ---
hooks.snippet.slashCommand: meeting-notes tags: template
frontmatter: | hooks.snippet.slashCommand: meeting-notes
date: {{today}} frontmatter: |
--- date: {{today}}
## Meeting notes for {{today}}! ---
## Meeting notes for {{today}}!
|^| |^|
```
Which will expand into e.g. Which will expand into e.g.
--- ```
date: 2023-11-11 ---
--- date: 2023-11-11
## Meeting notes for 2023-11-11 ---
## Meeting notes for 2023-11-11
. .
```
When the page already contained frontmatter before inserting the snippet, it will be augmented with the additional frontmatter specified by the template. When the page already contained frontmatter before inserting the snippet, it will be augmented with the additional frontmatter specified by the template.
# Examples
A minimal example using a caret placeholder (to position the cursor after snippet insertion):
```
---
tags: template
hooks.snippet.slashCommand: meeting-notes
---
## Meeting notes for {{today}}!
|^|
```
A more advanced example using `matchRegex`: a variant of the [[Library/Core/Snippet/Task]] template which adds a `creationDate` [[Attributes|attribute]] at the end:
```
---
tags: template
description: Make this a task with a creation date
hooks.snippet:
slashCommand: task-created
matchRegex: "^(\\s*)[\\-\\*]?\\s*(\\[[ xX]\\])?\\s*"
---
$1* [ ] |^| [creationDate: {{today}}]
```
# Use # Use
A snippet can be _triggered_ via the specified `slashCommand` via `/slashCommand` or via {[Open Command Palette]} and/or its associate key bindings when `command`, `key`/`mac` are specified. A snippet can be _triggered_ via the specified `slashCommand` via `/slashCommand` or via {[Open Command Palette]} and/or its associate key bindings when `command`, `key`/`mac` are specified.