# Yank to clipboard in fish shell's vi mode

URL: https://joaocosta.dev/blog/17
Published: 2025-09-30 · 3 min read

I don't really use/like vim's killring, so I usually just send all yanks (copies) to the system's clipboard (and paste from it as well). Vi mode in fish shell does not support using the system clipboard, so I wrote a small config for that.

## The problem

When using vi mode in fish shell, you have access to vim-like normal, visual, etc. modes. When you use yank and paste vim keybindings, e.g. `yy` in normal mode (yank line), the contents are inserted/pulled from the killring: basically a list of the things you've yanked that's only accessible within the current fish shell prompt. It's not even accessible from cli programs you open in that session. I want these keybindings to use the system clipboard instead.

## The solution

Fish has a variable that exposes the content of the killring: `$fish_killring`. This is a list using 1-based indexing (unlike many programming languages). The latest copied element is always at index 1, e.g. `echo $fish_killring[1]`. This makes it easy to write a function to yank to the clipboard:

```fish
# ~/.config/fish/functions/yank_to_clipboard.fish

function yank_to_clipboard -d "Insert latest killring entry into the system clipboard"
    printf "%s" "$fish_killring[1]" | fish_clipboard_copy
end
```

Afterwards, we just need to adjust the preset vi mode keybindings. In my system, these preset keybindings are stored in `/usr/share/fish/functions/fish_vi_key_bindings.fish`. I've taken the ones that deal with yanking and pasting, and tweaked them by calling `yank_to_clipboard` before all yanks and always pasting from the system's clipboard:

```fish
# ~/.config/fish/functions/fish_user_key_bindings.fish

function fish_user_key_bindings
    # make vi mode yanks copy to clipboard
    bind yy kill-whole-line yank_to_clipboard yank
    bind Y kill-whole-line yank_to_clipboard yank
    bind y,\$ kill-line yank_to_clipboard yank
    bind y,\^ backward-kill-line yank_to_clipboard yank
    bind y,0 backward-kill-line yank_to_clipboard yank
    bind y,w kill-word yank_to_clipboard yank
    bind y,W kill-bigword yank_to_clipboard yank
    bind y,i,w forward-single-char forward-single-char backward-word kill-word yank_to_clipboard yank
    bind y,i,W forward-single-char forward-single-char backward-bigword kill-bigword yank_to_clipboard yank
    bind y,a,w forward-single-char forward-single-char backward-word kill-word yank_to_clipboard yank
    bind y,a,W forward-single-char forward-single-char backward-bigword kill-bigword yank_to_clipboard yank
    bind y,e kill-word yank_to_clipboard yank
    bind y,E kill-bigword yank_to_clipboard yank
    bind y,b backward-kill-word yank_to_clipboard yank
    bind y,B backward-kill-bigword yank_to_clipboard yank
    bind y,g,e backward-kill-word yank_to_clipboard yank
    bind y,g,E backward-kill-bigword yank_to_clipboard yank
    bind y,f begin-selection forward-jump kill-selection yank_to_clipboard yank end-selection
    bind y,t begin-selection forward-jump-till kill-selection yank_to_clipboard yank end-selection
    bind y,F begin-selection backward-jump kill-selection yank_to_clipboard yank end-selection
    bind y,T begin-selection backward-jump-till kill-selection yank_to_clipboard yank end-selection
    bind y,h backward-char begin-selection kill-selection yank_to_clipboard yank end-selection
    bind y,l begin-selection kill-selection yank_to_clipboard yank end-selection
    bind y,i,b jump-till-matching-bracket and jump-till-matching-bracket and begin-selection jump-till-matching-bracket kill-selection yank_to_clipboard yank end-selection
    bind y,a,b jump-to-matching-bracket and jump-to-matching-bracket and begin-selection jump-to-matching-bracket kill-selection yank_to_clipboard yank end-selection
    bind y,i backward-jump-till and repeat-jump-reverse and begin-selection repeat-jump kill-selection yank_to_clipboard yank end-selection
    bind y,a backward-jump and repeat-jump-reverse and begin-selection repeat-jump kill-selection yank_to_clipboard yank end-selection
    bind -M visual -m default y kill-selection yank_to_clipboard yank end-selection repaint-mode

	# use system clipboard for vi mode pastes
    bind -s p 'set -g fish_cursor_end_mode exclusive' forward-char 'set -g fish_cursor_end_mode inclusive' fish_clipboard_paste
    bind -s P fish_clipboard_paste
end
```

Fish will load these functions when necessary, so you just need to put them in the right place (`~/.config/fish/functions`).

## Conclusion

After I found out about the `$fish_killring` variable, it was quite easy to fix my problem. Remember to restart your shell or source your config after making these changes. Hope you get some use out of it too.

Stay safe :P
