Skip to content

Instantly share code, notes, and snippets.

@antonkratz
Last active May 29, 2025 00:07
Show Gist options
  • Save antonkratz/ebfcefdb5fdf266631e4985d65535322 to your computer and use it in GitHub Desktop.
Save antonkratz/ebfcefdb5fdf266631e4985d65535322 to your computer and use it in GitHub Desktop.
The essence of how copying and pasting works in vim.

Introduction

In bash, use vimtutor to learn the basics of using vim. This text assumes that you already know the basics.

Copy and paste with VIM across instances, SSH-borders, different clipboards

Use registers for copying and pasting WITHIN one vim instance

Vim saves text in registers. Selecting text and pressing y copies (yanks) text into a register, and pressing p pastes (puts) it.

You can see the register contents with :reg.

Named registers: there are named registers a-z.

Typing "ay will yank the current selection into named register a, and typing "ap will paste text from named register a.

Uppercase appends: typing "Ay will append the current selection to the contents of register a.

Also see

:help registers
There are ten types of registers:			*registers* *E354*
1. The unnamed register ""
2. 10 numbered registers "0 to "9
3. The small delete register "-
4. 26 named registers "a to "z or "A to "Z
5. three read-only registers ":, "., "%
6. alternate buffer register "#
7. the expression register "=
8. The selection and drop registers "*, "+ and "~ 
9. The black hole register "_
10. Last search pattern register "/

Registers are spaces in memory that can only be accessed by that instance of vim. This means that it is not possible to copy and paste text out of one vim into another vim, or into some bash, firefox or any program! Also, you cannot paste text from other vim instances or other software into vim using this mechanism! Then how can I copy and paste between vim instances, and between vim and other software?

Use the X clipboard to copy and paste IN AND OUT OF vim!

The answer is via the X clipboard. The X clipboard is the "normal" way of copying and pasting with ctrl-c, or by opening a context menu and selecting copy/cut/paste. A quick refresher on the X clipboard:

In X there are three clipboards: PRIMARY, SECONDARY and CLIPBOARD.

PRIMARY is the text that is currently selected by highlighting. This applies to text that is highlighted in vim visual mode, as well as "normal" highlighting in any program.

SECONDARY is obscure, apparently never used, and can be ignored in this context.

CLIPBOARD is what we normally understand under "the clipboard".

The key point here is that the CLIPBOARD clipboard can be read from and written to in the + (plus) register! And also that the PRIMARY clipboard can read from the * (star) register!

This way vim can interact with the X clipboard, and it is possible to copy in and out of vim.

Use the xclip command in your bash shell to inspect what is in the PRIMARY and CLIPBOARD clipoards. Copy some text (it should now be in CLIPBOARD and, for the time being, in PRIMARY), highlight some other text (it should now be in PRIMARY, while the contents of CLIPBOARD are untouched), and run these commands in bash to understand what is going on:

xclip -o -selection primary
xclip -o -selection clipboard

Connect with ssh -X to remote machines to share the X clipoard

Section title already explains everything.

Now if you have vim running under GNU screen on a remote machine (with ssh -X), you have a problem!

You have logged into a remote machine with ssh -X and started GNU screen there; a vim is running within that GNU screen. Consider that this a vim running on a remote machine. If you try to move text between vim and the X clipboard using the + and * registers, this will use the X clipboards of the remote machine! The solution is to use X export when connecting to the remote machine in the first place. You can now happily copy and paste between the remote instance of vim and local software using the + and * registers.

However, this does not survive a re-connect!

Suppose you detach GNU screen, log out, log back in, re-attach GNU screen. The DISPLAY variable of the environment within GNU screen is inherited from the "outer" environment of the remote machine when creating the GNU screen instance. However, now that you have logged out and back in, the outer DISPLAY variable probably has changed.

Solution 1

Therefore, first in the outer environment figure out what DISPLAY is:

echo $DISPLAY

And then inside GNU screen set it accordingly:

export DISPLAY=:N.0

This still has problems! Suppose a vim was running all the time within GNU screen. There is no way to set the DISPLAY variable for that one. But it's better than nothing.

Solution 2

Applying patch 8.1.1307 should introduce the command :xrestore and thereby address this issue. See:

vim+screen: X11 server change disables X11 copy/paste #3649 vim/vim#3649

new command :xrestore to restore X11 connection after X11 server restart #844 vim/vim#844

patch 8.1.1307: cannot reconnect to the X server after it restarted https://github.com/vim/vim/commit/d4aa83af1d691fdabbc8e6aab36db2c96ea4d4b6

Pasting into the search field with ctrl+r followed by the register

If you are on the vim command line, for example you typed / to start a search. Now you want to paste a text to start the search. The problem is that you cannot paste, because if you type, say, p, it does not paste but inserts the character p. The solution is to use ctrl+r and the address of the register from which you want to paste. Remember that the default register is called ".

Copy followed by multiple paste operations: The 0 register always contains the last yanked text

One operation you often want to do: you yank some text, you make a visual selection of some other text and paste, thereby overwriting that text. Now you want to make another visual selection, and paste again. But this does not overwrite with the text selected first, but with the last overwritten text! This is because by pasting, you deleted the second text. The solution is the 0 register. The 0 register always contains the last yanked text.

Install gvim to have the +xterm_clipboard feature in bash-vim , which is what you want

First, install vim with sudo apt -y install vim. This is the "Huge version without GUI". However it lacks xclipboard support. When using this version, you will encounter many unnecessary pain points. To include xclipboard support, install gvim on top of it: sudo apt -y install vim-gtk3. So this is not to have gvim (though gvim is sometimes nice to have), but to enable the +xterm_clipboard in bash-vim!

How to check if you have xclipboard support or not. Run vim --version. Look for a line that includes the string Features included (+) or not (-):. After that line comes a block with the included and not-included features. You want to have +xterm_clipboard.

Block select

You can block select text with ctrl+g. Extremely useful.

GNU screen has its own internal copy and paste mechanism

You are very likely running vim inside a GNU screen session. Sometimes it is the easiest and fastest to just use the GNU screen copy and paste mechanism. Ctrl+A [ to enter copy mode: movements like in vi, start and end pasting with space; and paste with Ctrl+A ].

Viewing things in the current buffer

A sane way of displaying the last line, even if it is wrapped

Often you will have wrapped lines. If a wrapped line flows out of the current terminal viewport, the entire line dissappears! This is disorienting and weird. A much saner way is to display what can be displayed:

set display=lastline

I want to specifiy the syntax highlighting regardless of the filename extension

Input file is named readme.txt but syntactically is a BASH script:

:set syntax=sh.

Moving around in the current buffer

Arrow keys in insert mode print A, B, C, D instead of moving the cursor

The solution is :set nocompatible.

File and buffer management

Easier switching between buffers

Typically, you would rotate forward and backwards between buffers using :bn (next buffer) and :bp (previous buffer). However, these are five keystrokes! Shift-:-b-n-Enter. Ideally, I want to switch between buffers as easily as I do between screens in XFCE. In XFCE, I switch between screen just by using control-F1, control-F2... directly addressing the screen. I do not know how to set up s/th like this in vim yet. But what is already a large improvement:

:nnoremap <F5> :buffers<CR>:buffer<Space>

Now, just by hitting F5 I can select the buffer from a list!

What is the path of the file which I have in this buffer?

1 Ctrl-g

Build-in file system explorer

:Explore

Close the explorer with bdel (buffer delete).

Addendum: Other vim stuff

You can compile, build, install vim without being superuser/root

This is desirable if you are using vim on a remote server where you are not superuser/root; such machines typically have ancient vim installations, you probably want your own vim.

git clone https://github.com/vim/vim
cd vim
./configure --prefix=/cellar/users/kratz/vim81
make
make install

After this is done, do the relevant modifications to the PATH and EDITOR variables, and alias.

alias vi=/cellar/users/kratz/Downloads/vim/src/vim
git config --global core.editor "/cellar/users/kratz/Downloads/vim/src/vim"

Typing really fast by typing less

Abbreviation expansion

The key to producing very large amounts of text is not to type faster, but to type less. This is extremely powerful:

:abbr dge differential gene expression
:abbr sfe The Encyclopedia of Science Fiction

Expansion will be triggered if the abbreviation is followed by a non-alphanumeric character. :ab lists defined abbreviations.

Completion

Ctrl-n completes based on the next similar word. Ctrl-p with the previous one.

About cheat sheets

I also have a large cheat sheet for vim. The best cheat sheet is the one you make yourself.

Navigating

Scrolling

ctrl + e scrolling down without moving the cursor

ctrl + y scrolling up without moving the cursor

Navigating code with ctags

Sometime you look at a function call in a source code file and you want to jump to the definition of that function. vi does not understand this. Typically you would have to search for that function name. A solution is to make a ctags file: ctags -R . This generates a tags file. Now, in vim put your cursor over the function of interest. With ctrl + ] you can jump to the definition of the function, and with ctrl + T you can jump back - the same way you navigate the vim help. Of course, you have to generate a new tags file after substantial changes to the code.

Windows

Synchronously scrolling two (or more) windows

In both windows:set scrollbind

set noscrollbind to disentangle.

Tabs

Tabs are one way of organizing window layouts.

Spellchecking

set spell activates spellchecking and set nospell deactivates it. While spellchecking, z= to show a list of correct word suggestions and zg to add the current word (the word under the cursor) to the dictionary.

Spellchecking does not use the dictionary file, therefore works even in the absence of a dictionary.

set spell spelllang=en_us or et spell spelllang=de (German) to select the spellchecking language.

Thesaurus - helps with composing text

A thesaurus is lists words with a similar meaning to a given word. The idea of thesaurus based text replacement is, you are in insert mode and it ctrl+x ctrl+t and get a pop up with thesaurus entries. For this to work you need a thesaurus file and tell vim where it is, for example I put this into my vimrc: set thesaurus+=/home/kratz/vim_wordnet_thesaurus.txt

The thesaurus file is meant to list words with the same or similar meanings in one line, separated by space. A problem with the basic (not plugin-based) thesaurus functionality of vim is that it assumes that single words are substituted by single words, which is not always true. "black death" is a valid synonym for "plague", but a thesaurus entry "black death plague" does not work as intended because it suggests "black" as a synonym for "plague".

I do not know a good thesaurus file. One possibility is to download WordNet from Stanford and parse it to make a thesaurus file. For example using the python script dl_thesaurus.py included with this text.

I am using these versions

  • Ubuntu 24.04.2 LTS
  • VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Apr 01 2025 20:12:31)
# This script downloads WordNet (via NLTK), extracts synonyms, and writes a Vim-compatible thesaurus file.
import os
from nltk.corpus import wordnet as wn
import nltk
from collections import defaultdict
# Ensure WordNet is downloaded
nltk.download('wordnet')
nltk.download('omw-1.4')
# Dictionary to hold synonyms
thesaurus = defaultdict(set)
# Loop through all synsets and extract synonyms
for synset in wn.all_synsets():
lemmas = synset.lemmas()
words = set(lemma.name().replace('_', ' ') for lemma in lemmas)
for word in words:
thesaurus[word].update(words - {word})
# Write to a Vim-compatible thesaurus file
output_file = os.path.expanduser("~/vim_wordnet_thesaurus.txt")
with open(output_file, 'w', encoding='utf-8') as f:
for word, synonyms in sorted(thesaurus.items()):
if synonyms:
f.write(f"{word} {' '.join(sorted(synonyms))}\n")
print(f"Vim-compatible thesaurus file written to: {output_file}")
import re
def slugify(text):
text = text.strip().lower()
text = re.sub(r'[^\w\s-]', '', text) # remove punctuation
text = re.sub(r'\s+', '-', text) # spaces to hyphens
return text
def generate_toc(file_path):
toc = []
with open(file_path, 'r') as f:
for line in f:
match = re.match(r'^(#{1,6})\s+(.*)', line)
if match:
level = len(match.group(1))
header = match.group(2).strip()
anchor = slugify(header)
toc.append(f'{" " * (level - 1)}- [{header}](#{anchor})')
return '\n'.join(toc)
print(generate_toc('akvimnotes.md'))

Comments are disabled for this gist.