Reproduction steps
- Create a Vicinae snippet whose content is a local file URI, for example
file:///run/user/1000/, and give it a keyword trigger.
- Type that trigger in any text field. I used Zed and a browser address bar.
- The trigger is deleted and nothing is inserted in its place.
The same result without Vicinae, by driving the D-Bus method it uses:
gdbus call --session --dest org.gnome.Shell \
--object-path /org/gnome/Shell/Extensions/Clipboard \
--method org.gnome.Shell.Extensions.Clipboard.SetContent 'file:///run/user/1000/'
wl-paste --list-types # text/uri-list
wl-paste --type text/plain # Clipboard content is not available as requested type
Current vs. Expected behavior
Current: the clipboard carries a single text/uri-list offer, so an application that pastes text asks for text/plain, receives nothing, and inserts nothing.
Expected: text targets can still paste the string, the way they do when the same string is placed on the clipboard by wl-copy.
FileHandler.set() in core/clipboard/handlers/file-handler.js calls St.Clipboard.set_content with text/uri-list only, for both CLIPBOARD and PRIMARY. It is selected by matchesContent() via isFileUri() in utils/clipboard-utils.js, which returns true when every line of the content starts with file://. Since set_content replaces rather than adds, no text offer survives. The handler was introduced for #15, where file URIs offered as plain text prevented Electron and Chromium targets from recognising a file.
| clipboard set via |
resulting offers |
wl-copy 'file:///run/user/1000/' |
text/plain, text/plain;charset=utf-8, UTF8_STRING, STRING, TEXT |
SetContent 'file:///run/user/1000/' |
text/uri-list |
SetContent 'https://example.com' |
text/plain;charset=utf-8 |
SetContent 'x file:///run/user/1000/' |
text/plain;charset=utf-8 |
SetContent '/run/user/1000/' |
text/plain;charset=utf-8 |
Vicinae reaches this path because it expands snippets through the clipboard: it copies the expanded text, injects Ctrl+V, then restores the previous clipboard, and usesClipboard is hardcoded to true on Linux.
Vicinae server log for one expansion
vicinae: Snippet expansion: keyword="zen" app="dev.zed.Zed.desktop" terminal=false
vicinae: SNIPPET TRIGGERED: zen
vicinae: Deferring expansion until modifiers are released
vicinae: SNIPPET EMITTING (mods released): zen
vicinae: Received new clipboard selection with 1 offers (password= false )
vicinae: "text/uri-list" (size="23 bytes")
vicinae: Received new clipboard selection with 1 offers (password= false )
vicinae: "text/uri-list" (size="22 bytes")
vicinae: Received new clipboard selection with 1 offers (password= false )
vicinae: "text/plain" (size="18 bytes")
vicinae: SNIPPET UNDO: zen
The 22 byte payload is the snippet text file:///run/user/1000/, the 23 byte one includes the trailing space added by the word boundary option, and the 18 byte text/plain entry is the previous clipboard being restored.
Workaround in use
Storing the snippet without the scheme, /run/user/1000/ instead of file:///run/user/1000/, which no longer matches isFileUri and pastes as text. Address bars resolve absolute paths anyway.
Extension version and system specs
Extension 1.6.2
Vicinae 0.26.3
NixOS 26.11, kernel 7.1.8
GNOME Shell 50.4, Wayland
Reproduction steps
file:///run/user/1000/, and give it a keyword trigger.The same result without Vicinae, by driving the D-Bus method it uses:
Current vs. Expected behavior
Current: the clipboard carries a single
text/uri-listoffer, so an application that pastes text asks fortext/plain, receives nothing, and inserts nothing.Expected: text targets can still paste the string, the way they do when the same string is placed on the clipboard by
wl-copy.FileHandler.set()incore/clipboard/handlers/file-handler.jscallsSt.Clipboard.set_contentwithtext/uri-listonly, for both CLIPBOARD and PRIMARY. It is selected bymatchesContent()viaisFileUri()inutils/clipboard-utils.js, which returns true when every line of the content starts withfile://. Sinceset_contentreplaces rather than adds, no text offer survives. The handler was introduced for #15, where file URIs offered as plain text prevented Electron and Chromium targets from recognising a file.wl-copy 'file:///run/user/1000/'text/plain,text/plain;charset=utf-8,UTF8_STRING,STRING,TEXTSetContent 'file:///run/user/1000/'text/uri-listSetContent 'https://example.com'text/plain;charset=utf-8SetContent 'x file:///run/user/1000/'text/plain;charset=utf-8SetContent '/run/user/1000/'text/plain;charset=utf-8Vicinae reaches this path because it expands snippets through the clipboard: it copies the expanded text, injects Ctrl+V, then restores the previous clipboard, and
usesClipboardis hardcoded totrueon Linux.Vicinae server log for one expansion
The 22 byte payload is the snippet text
file:///run/user/1000/, the 23 byte one includes the trailing space added by the word boundary option, and the 18 bytetext/plainentry is the previous clipboard being restored.Workaround in use
Storing the snippet without the scheme,
/run/user/1000/instead offile:///run/user/1000/, which no longer matchesisFileUriand pastes as text. Address bars resolve absolute paths anyway.Extension version and system specs
Extension 1.6.2
Vicinae 0.26.3
NixOS 26.11, kernel 7.1.8
GNOME Shell 50.4, Wayland