Summary
The Snippet editor exposes a Cursor Position dynamic value ({cursor-position}), but using it does not move the caret after the snippet is pasted or expanded. The placeholder is removed from the inserted text, yet the caret remains at the end of the pasted snippet.
Reproduction
-
Create a snippet containing {cursor-position} in the middle of the text, for example:
Hello {cursor-position}world
-
Paste or expand the snippet into a text field.
-
Test targets observed:
- Obsidian editor
- Browser input fields
- SuperCmd's own input fields
Expected behavior
The inserted text should be:
and the caret should land between Hello and world, where {cursor-position} was placed.
Actual behavior
The inserted text becomes:
but the caret remains at the end of the inserted text:
So the placeholder is removed correctly, but it does not control the final caret position.
Technical notes
From a quick code inspection, this appears to be a partial implementation rather than a target-app-specific failure.
- The Snippet UI exposes
{cursor-position} as a dynamic value in SnippetManager.tsx.
resolveSnippetPlaceholders() handles cursor-position by returning an empty string.
renderSnippetById() returns only the final text string, so the caret target index is lost during rendering.
snippet-paste / snippet-paste-resolved then pass only that text to pasteTextToActiveApp().
pasteTextToActiveApp() writes the text to the clipboard and simulates paste (Cmd+V / native CGEvent path), which naturally leaves the caret at the end of the pasted text.
- The keyword auto-expansion path similarly renders the snippet to plain text, deletes the keyword, and pastes the resolved text without any post-paste caret adjustment.
In other words, {cursor-position} is currently treated as a zero-width text placeholder, not as metadata that survives rendering and drives caret placement after insertion.
Possible fix direction
The snippet renderer likely needs to return structured data, e.g.:
{
text: string,
cursorOffset?: number
}
Then paste/expand paths can:
- Paste the resolved text.
- If
cursorOffset is present, move the caret to that offset.
Potential implementation options:
- For SuperCmd/Electron-owned inputs: use DOM selection APIs such as
setSelectionRange() or contenteditable selection handling.
- For external macOS apps: attempt
AXSelectedTextRange via Accessibility after paste.
- As a fallback for plain text fields: send left-arrow key events for
text.length - cursorOffset positions after paste, though this may be less reliable for multi-line text, IME state, or apps with custom editors.
Environment
Observed in local testing on macOS with current SuperCmd source. The issue appears independent of a specific target app because the current snippet rendering path discards the cursor position before paste.
Summary
The Snippet editor exposes a Cursor Position dynamic value (
{cursor-position}), but using it does not move the caret after the snippet is pasted or expanded. The placeholder is removed from the inserted text, yet the caret remains at the end of the pasted snippet.Reproduction
Create a snippet containing
{cursor-position}in the middle of the text, for example:Paste or expand the snippet into a text field.
Test targets observed:
Expected behavior
The inserted text should be:
and the caret should land between
Helloandworld, where{cursor-position}was placed.Actual behavior
The inserted text becomes:
but the caret remains at the end of the inserted text:
So the placeholder is removed correctly, but it does not control the final caret position.
Technical notes
From a quick code inspection, this appears to be a partial implementation rather than a target-app-specific failure.
{cursor-position}as a dynamic value inSnippetManager.tsx.resolveSnippetPlaceholders()handlescursor-positionby returning an empty string.renderSnippetById()returns only the final text string, so the caret target index is lost during rendering.snippet-paste/snippet-paste-resolvedthen pass only that text topasteTextToActiveApp().pasteTextToActiveApp()writes the text to the clipboard and simulates paste (Cmd+V/ native CGEvent path), which naturally leaves the caret at the end of the pasted text.In other words,
{cursor-position}is currently treated as a zero-width text placeholder, not as metadata that survives rendering and drives caret placement after insertion.Possible fix direction
The snippet renderer likely needs to return structured data, e.g.:
Then paste/expand paths can:
cursorOffsetis present, move the caret to that offset.Potential implementation options:
setSelectionRange()or contenteditable selection handling.AXSelectedTextRangevia Accessibility after paste.text.length - cursorOffsetpositions after paste, though this may be less reliable for multi-line text, IME state, or apps with custom editors.Environment
Observed in local testing on macOS with current SuperCmd source. The issue appears independent of a specific target app because the current snippet rendering path discards the cursor position before paste.