How do you yank X number of characters in vim? - vim

I know I can cut 5 characters in vim by typing 5x, and I often use this to copy and paste text by doing 5xu then pasting them somewhere else.
I am lazy and would rather just yank the 5 characters so I don't have to undo the cut action.
How can I do this?

Yank supports standard movement commands. Use y5l (<- that's a lowercase L)
And if you want to yank 5 characters backwards, use y5h.
Now, if you're feeling really lazy, remap this particular sequence to a key-combination, like so:
:nnoremap <C-l> y5l
In this case, "yank 5 to the right" gets mapped to Ctrl+L (lowercase L).
If you'd like, you can also use Space instead of L to yank characters in the forward direction (examples: ySpace for a single character or 5ySpace for 5). Some people may find it to be quicker or easier than hitting L.

This is complementing the answer of voithos:
You can also use 5ySpace or y5Space (ty #hauleth for suggestion)
This is useful for me especially when I want to yank just one character:
ySpace
Is easier (for me at least) to find and hit Space than l.

Found this post because I too wanted to yank x number characters without cutting and learned this while testing.
There may be times when is easier to look for certain characters than to count the number of characters to yank.
Enter the motions t and T.
Think ytx as yank forward to character x
Think yTx as yank backward to character x

y5 will do it. yy yanks lines, y yanks characters.

Related

In Vi/Vim, how do I copy a substring inside a line

I have a dictionary in my config file.
candidates = {'morpheus':(3,1), 'trinity':(3,1), 'neo':(3,1), 'switch':(3,1)}
I can highlight with my mouse one k/v pair (e.g. 'neo':(3,1)) to copy and paste if I needed add more k/v pairs to the dictionary but is there a way using vi keyboard commands to yank from the current cursor to the next comma or space to grab the 'neo':(3,1) k/v pair?
I know there's yw for yank word but in this case, vi stops at the punctuation marks and doesn't grab what I want. I think I can also yank characters to the left or right of the cursor but I don't want to count characters if I can help it.
Is there a way to tell vi to yank from the current cursor position to the next space or the next ) character?
yw, which is actually "yank to next word" rather than "yank word", is not to be taken as a single command. It really is two commands: an operator, y, followed by a motion, w. This is pretty important because understanding that operator+motion model allows you to freely compose very expressive editing commands.
In this case, you can move the cursor to the closing ) with f) or 2t,, which gives you the two following commands:
yf)
y2t,
See :help f, :help t, and the user manual's introduction of the operator+motion model: :help 04.1.
Yank to the next space (excluding space) yt (Note the space at the end, the character yanking to)
Yank to the second space (excluding space) y2t
Yank to the next space (including space) yf
Yank to end of line y$
Yank everything inside of current '...' yi'

the command y3s to copy three lines in Normal Mode in Vim

According to Vim's Verb, Noun, and Modifier logic the command y3s should potentially copy three sentences, but in my version of Vim it doesn't do that. I am wondering if there is a reason for it. Looking up online it seems like there are other ways to copy a specific number of sentences, but I am curious why this approach doesn't work. Thanks!
Several misconceptions here. First, there is a difference between motions and text objects.
A motion (:help navigation) is a command that changes the position of the cursor: l for right, j for down, ) for sentence forward, 2Fx backward to before-previous x in the same line, /foo/e+2<CR> forward to 2 characters after the end of next foo, w start of next word. Commands whose argument is a motion operate on the text span from the current position to the new motion-specified position. dw thus deletes from current position to the start of the next word.
A text object (:help text-objects) specifies a semantic unit of text; it typically consists of two keypresses, the first of which is i (inside, inner) or a (a, an, around). i" inside double quotes, a( around parenthesis, is inner sentence (i.e. without spaces around it), 2aw twice a word. Thus daw delete around this word (including the space), or simpler, delete a word.
The difference is clear: if you are in the middle of a word, e.g. Some peng|uins fly (with | representing the cursor), dw gives you Some peng|fly (deleting from cursor to start of the next word), while daw gives you Some |fly (deleting the entire word penguins, along with the next space because of the "around" modifier). diw would give you Some | fly (not including the space into the deletion).
As you'll note, "sentence" has a different mapping in text motions (( sentence backward, ) sentence forward) and text objects (is inner sentence, as a sentence). Meanwhile, ( as a text object, equivalently to ) and b, is everything inside, or around, parentheses; and s as a text motion does not exist by default.
Thus, y2s is not a known mapping, since you are deleting by motion (no i or a), and there is no motion s; it will not do anything.
You can use y2), which would yank about a sentence and a half (i.e. from cursor to the start of the second next sentence); or you can use y2as to yank the current sentence and the next sentence and a space after it; or y2is for the same except without that last space; but you cannot use y2s. (You can also write all of those as 2y), 2yas, 2yis.)
In y2y (or equivalently 2yy), the second y is the duplication of the operator. It is almost a rule in Vim that the motion equal to the operator is a line: yy yank a line, dd delete a line, gqgq (or gqq) reformat a line, == filter a line, gugu (or guu) uppercase a line etc. The reason is a simple convenience: lines are what we operate on most frequently, and it's hard to make a faster incantation than the same key pressed twice. Thus, the second y by itself does not have a meaning: it signifies that the first y is working on lines (thus y2y or 2yy yank two lines).
The whole :help motion.txt page is a very useful read, I heartily recommend it.
If you want to copy 3 lines, you should do y3y, not y3s. y stands for Yank or copy.
Update,
#Amadan 's answer has more explanation and also for why y3y works.
Simpley 3Y will do, where Y will yank a line and 3 will repeat it 3 times. In Vim there are no sentences, only lines, words, and characters.

How do I remove the last six characters of every line in Vim?

I have the following characters being repeated at the end of every line:
^[[00m
How can I remove them from each line using the Vim editor?
When I give the command :%s/^[[00m//g, it doesn't work.
You could use :%s/.\{6}$// to literally delete 6 characters off the end of each line.
The : starts ex mode which lets you execute a command. % is a range that specifies that this command should operate on the whole file. The s stands for substitute and is followed by a pattern and replace string in the format s/pattern/replacement/. Our pattern in this case is .\{6}$ which means match any character (.) exactly 6 times (\{6}) followed by the end of the line ($) and replace it with our replacement string, which is nothing. Therefore, as I said above, this matches the last 6 characters of every line and replaces them with nothing.
I would use the global command.
Try this:
:g/$/norm $xxxxxx
or even:
:g/$/norm $5Xx
I think the key to this problem is to keep it generic and not specific to the characters you are trying to delete. That way the technique you learn will be applicable to many other situations.
Assuming this is an ANSI escape sequence, the ^[ stands for a single <Esc> character. You have to enter it by pressing Ctrl + V (or Ctrl + Q) on many Windows Vim installations), followed by Esc. Notice how this is then highlighted in a slightly different color, too.
It's easy enough to replace the last six characters of every line being agnostic to what those characters are, but it leaves considerable room for error so I wouldn't recommend it. Also, if ^[ is an escape character, you're really looking for five characters.
Escape code
Using ga on the character ^[ you can determine whether it's an escape code, in which case the status bar would display
<^[> 27, Hex 1b, Octal 033
Assuming it is, you can replace everything using
:%s/\%x1b\[00m$//gc
With \%x1b coming from the hex value above. Note also that you have to escape the bracket ([) because it's a reserved character in Vim regex. $ makes sure it occurs at the end of a line, and the /gc flags will make it global and confirm each replacement (you can press a to replace all).
Not escape code
It's a simple matter of escaping then. You can use either of the two below:
:%s/\^\[\[00m$//gc
:%s/\V^[[00m\$//gc
If they are all aligning, you can do a visual-block selection and delete it then.
Otherwise, if you have a sequence unknown how to input, you can visually select it by pressing v, then mark and yank it y (per default into register "). Then you type :%s/<C-R>"//g to delete it.
Note:
<C-R>" puts the content of register " at the cursor position.
If you yanked it into another register, say "ay (yank to register a - the piglatin yank, as I call it) and forgot where you put it, you can look at the contents of your registers with :reg.
<C-R> is Vim speak for Ctrl+R
This seems to work fine when the line is more than 5 chars long:
:perldo $_ = substr $_, 0, -5
but when the line is 5 or less chars long it does nothing.
Maybe there is a easy way in perl to delete the last 5 chars of a string, but I don't really know it:)
Use this to delete:
:%s/^[[00m//gc

How to jump to a specific character in vim?

How can I jump to the next character X in vim?
I frequently use, e.g., dt: or ct: to delete/change everything up until a colon (or some other character).
Is there any short key combo to simply move my cursor position to that character?
You can type f<character> to put the cursor on the next character and F<character> for the previous one.
t and f work without a command as well, so to move to colon use f: and to move to right before colon use t:
If you do a search for that character with /, you can then hit n to move to the next occurrence of it.
Maybe you are just searching for a pure vim combination but EasyMotion is a plugin that worth trying. HTH. :)

Command to surround a character with spaces in vim

I am trying to use vim properly - to aid me I've mapped my arrow keys to "" so that I am forced to use {hjlk} to move around.
This is causing me a problem when I want to just surround a character with spaces, eg:
"2+3" is better formatted "2 + 3"
Previously I would have put my cursor over the + and typed:
i[space][arrow-right][space][Esc]
That's 5 presses.
To do this without the arrow I seem to need to put the cursor over the + and go:
i[space][Esc]lli[space][Esc]
That's 8 presses.
I can convert the "li" into an "a" which reduces it to 7 presses:
i[space][Esc]la[space][Esc]
Short of writing this into a macro is there a better way of doing it? Is there some magic vim command which will allow me to do it in less than even 5 presses - and some way to generalise it so that I can do it to entire words or symbols, eg if I want to convert 3==4 to 3 == 4?
Personally, I think it makes most sense to destroy what you want to surround, and then repaste it.
c w "" ESC P
Obviously, you can replace both the object and the quotes with whatever you like. To change just one character + to be [space]+[space], you would do
s [space] [space] ESC P
on the +
The first thing that jumps to mind after reading just the title is surround.vim which is an excellent script to do all kinds of useful things along the lines of what you've described.
To solve your specific problem, I would probably position the cursor on the + and:
s[space]+[space][esc]
To change 3==4 into 3 == 4, I might position the cursor on the first =, and:
i[space][esc]ww.
i have been wondering about this as well. i tried with surround.vim, but the naive approach
S<space>
(after making a visual selection) does not work since the space is already taken up as a modifier for adding space to other surrounding character pairs. S<space><cr> adds a ^M in the output. Ss almost works but inserts a space only before.
after asking at tpope/surround.vim on github:
S<space><space>
in visual mode works. alternatively, from normal mode, ysl<space><space> works for a single character
Hah! I've been trying to figure out how to surround a block in spaces for quite a while and I finally found the right combination.
Using surround.vim you say surround selector space space.
So for this specific case I would use visual mode (a good trick for operating on single characters under the cursor BTW) thus: "vs " <- four key presses!
I also have a habit of typing things like argument lists without spaces. With this technique you can just navigate to the second argument using w and say "vws " to visually select a word and surround with spaces.
I prefer visual select mode generally. Also the alternate surround syntax "ysw " excludes the word final comma that is caught by "vw".
You could create a macro with one of the described actions and call it everytime you need it (Like amphetamachine proposed while I was writing) or you could simply search & replace:
:%s/\(\d\)\(+\|-\)\(\d\)/\1 \2 \3/g
You probably have to execute this command two times because it will only find every second occurence of +/-.
EDIT:
This will replace everything without the need to be called twice:
:%s/\d\#<=+\|-\d\#=/ \0 /g
Try positioning your cursor over the '+' and typing this:
q1i[space][right arrow][space][left arrow][esc]q
This will record a quick macro in slot 1 that you can re-use whenever you feel like it, that will surround the character under the cursor with spaces. You can re-call it with #1.
There is also the more versatile one:
q1ea[space][esc]bi[space][right arrow][esc]q
Which will surround the word under the cursor ("==" counts as a word) with spaces when you hit #1.
You could set up a mapping like this (press enter in visual mode to wrap spaces):
:vnoremap <CR> <ESC>`<i<SPACE><ESC>`>la<SPACE><ESC>h
This method allows you to use . to repeat the command at the next +.
Put your cursor over the + and type:
s[SPACE][CTRL-R]"[SPACE][ESC]
I know this is and old thread, but this might be useful to someone. I've found that the map (map it to anything else you want!)
noremap <leader>ss diwi<SPACE><C-R>"<SPACE><ESC>B
works ok both for turning 'a+b' into 'a + b' (when used over the '+' char) and for turning 'a==b' into 'a == b' (when used over either the first or the second '=' sign).
I hope it's useful to someone.

Resources