Perform operation on entire buffer, without changing the cursor position - vim

Consider a scenario, when you are editing a C file in vim. & you have used a mix of spaces & tabss. & you need to convert all of them to spaces.
There is a utility, called expand, which performs this task intelligently & it's a preferred way than s/\t/<4 spaces>/g. We can use this command in vim using :%!expand -t4. Typically, I map a function key, say F11 for this.
Similarly, we can use any other command in vim.
The problem is when you run any such operation on entire buffer, the cursor position changes & can be irritating at times.
Hence, the question is, how to perform an operation on entire buffer, without changing cursor position?

The cursor position can be restored by using the latest jump mark:
``
If you also want to maintain the exact window view, use winsaveview() / winrestview().
The anwolib - Yet another vim library has a handy :KeepView command for that:
:KeepView %!expand -t4

For such a case, we can use marks (e.g. mA). The mapping would be:
:nmap <F11> mZ:%!expand -t4<CR>`Z
However, there is still a catch. The screen scroll position may change, when operating on entire buffer.
This can be handled by using 2 marks as below:
:nmap <F11> mZHmY:%!expand -t4<CR>'Yzt`Z
Explanation:
Mark current position. (mZ)
Go to top of screen. (H)
Mark this line. (mY)
Run your filter. (:%!expand -t4)
Go to line Y. ('Y)
Make it top of screen. (zt)
Go to your mark. (`Z)
Now, when you press the mapped key, F11, the filter runs on the buffer & the cursor remains at its proper location.

you can just:
:your expand cmd|norm! ``
you can map it to <F11> if you like. but better use nnoremap
I just saw you mentioned in your question:
Similarly, we can use any other command in vim
If you want to do that, the reliable solution would be wrap the "any other command" in a function, and before/after the main logic, save/restore the cursor position. Because "any other command" could change the (back tick) mark, even the marks you defined.

Related

Which mark to use

I'm going through http://learnvimscriptthehardway.stevelosh.com/chapters/04.html
and the exercise wants me to make in normal mode upcase the current word.
I did:
nnoremap <c-u> mmgUaw`m<esc>
and I'm using a mark (the m mark) to prevent the cursor from moving.
I don't like this solution because what should be a purely functional change ends up changing the global state of vim (by setting up a mark).
Is there a better way to do this, or is there a mark (or a set of marks) that should only be used by commands/mappings and not interactively (because commands/mappings change it/them)?
This is the best I came up with:
nnoremap <c-u> i<esc>guiw`^
to utilize the last position of the cursor in insert mode.
The example from the Vim help uses the s register itself, so your approach isn't necessarily a bad one (i.e. if the mapping is just for your own use then you can just pick a register you don't use for anything else).
Having said that, the special backtick (`) register might be better here, since it's local to the buffer and is meant to store the most recent jump point anyway.

How to efficiently add parentheses or a string in vim?

In traditional text editors, whenever I needed to open a string or parentheses and type something between it I used to do:
Type () or ""
Press left
Type in what I need
Press right
But in vim (that is if I followed the vim way) the process becomes quite tedious as I have to enter the normal mode to move a whole bunch of times:
Type () or ""
Press <ESC>
Press i
Type what I need
Press <ESC>
Press l
Press a
If it is not a good practice to use the arrow keys at any time, is there a more efficient way of doing this kind of task in vim?
It is actually quite easy to automatically append those closing characters in a mapping, and put your cursor where you want it. The trick is to do that, without also messing up the undo/redo/repeat actions. The problem is that cursor movement commands in insert mode will break the "undo sequence" so that any change you make after moving the cursor is undone separately from changes made before moving the cursor.
Warning: the following information may become dated
There are plenty of plugins available to automatically append these characters (see the partial list at the Vim wiki page for appending closing characters), and prior to Vim 7.4, some of them even had complicated workarounds for keeping the undo sequence intact. Unfortunately, they all relied on a bug in Vim that got fixed in version 7.4 for this.
A patch is available to add a cursor movement that does not break undo, so if you want to compile Vim yourself, you can grab that patch and use mappings like the following (no plugin required!) to do what you want:
inoremap ( ()<C-G>U<Left>
inoremap <expr> ) strpart(getline('.'), col('.')-1, 1) == ")" ? "\<C-G>U\<Right>" : ")"
These mappings will insert "()" when you type an opening (, placing the cursor in between the parentheses. When you type ')' and there is already a closing ')' after the cursor, Vim will skip over the parenthesis instead of inserting a new one. Cursor movement is preceded by <C-G>U which is the feature the aforementioned patch adds, allowing the following cursor movement to not break the undo sequence (as long as the movement is all in a single line).
As of Vim 7.4.663, this patch has still not been officially included.
No. Doing it in Vim is exactly the same as in your "traditional" editor:
Type () or ""
Press left
Type in what you need
Press right
But… why don't you type the opening character, what you want inside the pair and then the closing character?
Type ( or "
Type what you need
Type ) or "
Too simple?
I think using arrow keys to move around is bad practice in normal mode but in your case; moving one space while in insert mode, I would hazard to say using the arrow keys is probably best practice.
That being said if you are dead set on avoiding them you could use <i_ctrl-o>.
:help i_ctrl_o
CTRL-O execute one command, return to Insert mode *i_CTRL-O*
So, while in insert mode, you could type: ()<ctrl-o>h<xxx><ctrl-o>l, where <xxx> is whatever you want in the brackets.
Unfortunately that doesn't work if you cursor is on the last character of the line, which if you are typing it most likely is.
To solve that problem do :set virtualedit+=onemore or add it to your ~/.vimrc file.
Note that this solution is more keystrokes than simply using the arrow keys but you don't need to move your hands away from the home row so it may be faster anyway.

Multiple selections in VIM

Is it possible to select multiple non-consecutive lines (or sections) in VIM's visual mode? If so, how?
No, this is not possible without plugins.
But you can copy multiple lines into the same buffer, if that solves your problem.
To start the 'Accumulation Buffer':
mark a section to copy in visual mode,
press "a to operate on the buffer a with the next command and
yank it as usual (y).
To add to that buffer:
mark the next section and
press "A (capitalizing the buffer name means "do not overwrite the buffer, append to it instead")
and yank again using y.
You can then paste the accumulated buffer a at any time using "ap.
You have to install the multiselect plugin to get this capability. Find it here: http://www.vim.org/scripts/script.php?script_id=953
A more up-to-date answer is this plugin.
(disclaimer: I personally don't actually use it, it interferes too much with the rest of my vim setup. If your vim is relatively clean and you are moving over from sublime, this may certainly be your cup of tea.)
I would also like to point out the record/replay functionality of vim (the q key). Quite often recording is also unnecessary, I can do the tasks normally done with sublime's multi-select by doing it iteratively (e.g. search for something, perform the fix on the first instance of it, and then subsequent repeats are achieved by hitting n and N to move around and . to repeat the edit operation).
I do have my , comma key nnoremap'd to #q, this repeats the sequence that is recorded by pressing qq (record into q register).

Simple Vim commands you wish you'd known earlier [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I'm learning new commands in Vim all the time, but I'm sure everyone learns something new once in a while. I just recently learned about this:
zz, zt, zb - position cursor at middle, top, or bottom of screen
What are some other useful or elegant commands you wish you'd learned ages ago?
I really wish I'd known that you can use Ctrl+C instead of Esc to switch out of insert mode. That's been a real productivity boost for me.
The most recent "wow" trick that I learnt is a method of doing complicated search-and-replace. Quite often in the past, I've had a really complicated regexp to do substitutions on and it's not worked. There is a better way:
:set incsearch " I have this in .vimrc
/my complicated regexp " Highlighted as you enter characters
:%s//replace with this/ " You don't have to type it again
The "trick" here (for want of a better word) is the way that you can use the search to create the regexp (and 'incsearch' highlights it as you enter characters) and then use an empty pattern in the substitution: the empty pattern defaults to the last search pattern.
Example:
/blue\(\d\+\)
:%s//red\1/
Equivalent to:
:%s/blue\(\d\+\)/red\1/
See:
:help 'incsearch'
:help :substitute
I created this reference of my most used command for a friend of mine:
select v
select row(s) SHIFT + v
select blocks (columns) CTRL + v
indent selected text >
unindent selected text <
list buffers :ls
open buffer :bN (N = buffer number)
print :hardcopy
open a file :e /path/to/file.txt
:e C:\Path\To\File.txt
sort selected rows :sort
search for word under cursor *
open file under cursor gf
(absolute path or relative)
format selected code =
select contents of entire file ggVG
convert selected text to uppercase U
convert selected text to lowercase u
invert case of selected text ~
convert tabs to spaces :retab
start recording a macro qX (X = key to assign macro to)
stop recording a macro q
playback macro #X (X = key macro was assigned to)
replay previously played macro * ##
auto-complete a word you are typing ** CTRL + n
bookmark current place in file mX (X = key to assign bookmark to)
jump to bookmark `X (X = key bookmark was assigned to
` = back tick/tilde key)
show all bookmarks :marks
delete a bookmark :delm X (X = key bookmark to delete)
delete all bookmarks :delm!
split screen horizontally :split
split screen vertically :vsplit
navigating split screens CTRL + w + j = move down a screen
CTRL + w + k = move up a screen
CTRL + w + h = move left a screen
CTRL + w + l = move right a screen
close all other split screens :only
* - As with other commands in vi, you can playback a macro any number of times.
The following command would playback the macro assigned to the key `w' 100
times: 100#w
** - Vim uses words that exist in your current buffer and any other buffer you may have open for auto-complete suggestions.
gi switches to insertion mode, placing the cursor at the same location it was previously.
:q!
I wish I knew that before I started vi for the first time.
^X-F completes using filenames from the current directory. No more copying/pasting from the terminal or painful double checking.
^X-P completes using words in the current file
:set scrollbind forces one buffer to scroll alongside another. e.g. split your window into two vertical panes. Load one file in each (perhaps different versions of the same file). Do :set scrollbind in each. Now when you scroll in one, both panes will scroll together. Ideal for comparing files.
You can use a whole set of commands to change text inside brackets / parentheses / quotation marks/ tags. It's super useful to avoid having to find the start and finish of the group. Try ci(, ci{, ci<, ci", ci', ct depending on what kind of object you want to change. And the ca(, ca{, ... variants delete the brackets / quotation marks as well.
Easy to remember: change inside a bracketed statement / change a bracketed statement.
The asterisk key, *, will search for the word under the cursor.
[+Tab will take you to the definition of a C function that's under your cursor. (It doesn't always work, though.)
Don't press Esc ever. See this answer to learn why. As mentioned above, Ctrl + C is a better alternative. I strongly suggest mapping your Caps Lock key to escape.
If you're editing a Ctags compatible language, using a tags file and :ta, Ctrl + ], etc. is a great way to navigate the code, even across multiple files. Also, Ctrl + N and Ctrl + P completion using the tags file is a great way to cut down on keystrokes.
If you're editing a line that is wrapped because it's wider than your buffer, you can move up/down using gk and gj.
Try to focus on effective use of the motion commands before you learn bad habits. Things like using 'dt' or 'd3w' instead of pressing x a bunch of times. Basically, any time that you find yourself pressing the same key repeatedly, there's probably a better/faster/more concise way of accomplishing the same thing.
Some of my latest additions to my Vim brainstore:
^wi: Jump to the tag under the cursor by splitting the window.
cib/ciB: Change the text inside the current set of parenthesis () or braces {}, respectively.
:set listchars=tab:>-,trail:_ list: Show tabs/trailing spaces visually different from other spaces. It helps a lot with Python coding.
ZZ (works like :wq)
And about the cursor position: I found that a cursor which always stays in the middle of screen is cool -
set scrolloff=9999
gv starts visual mode and automatically selects what you previously had selected.
:shell to launch a shell console from Vim. Useful when for example you want to test a script without quitting Vim. Simply hit ^d when you done with the shell console, and then you come back to Vim and your edited file.
This always cheers me up:
:help 42
vimcryption
vim -x filename.txt
You will be asked for a passphrase, edit and save. Now whenever you open the file in vi again you will have to enter the password to view.
Build and debug your code from within Vim!
Configuration
Not much, really. You need a Makefile in the current directory.
To Compile
While you're in Vim, type :make to invoke a shell and build your program. Don't worry when the output scrolls by; just press Enter when it's finished to return to Vim.
The Magic
Back within Vim, you have the following commands at your disposal:
:cl lists the errors, warnings, and other messages.
:cc displays the current error/warning message at the bottom of the screen and jumps to the offending line in your code.
:cc n jumps to the nth message.
:cn advances to the next message.
:cp jumps to the previous message.
There are more; if you're interested, type :help :cc from within Vim.
Press % when the cursor is on a quote, parenthesis, bracket, or brace to find its match.
^P and ^N
Complete previous (^P) or next (^N) text.
^O and ^I
Go to previous (^O - "O" for old) location or to the next (^I - "I" just near to "O").
When you perform searches, edit files, etc., you can navigate through these "jumps" forward and back.
Marks
Press ma (m- mark, a - name of mark). Later to return to the position, type `a.
^r^w to paste the word under the cursor in command mode.
It is really useful when using grep or replace commands.
Until [character] (t). It is useful for any command which accepts a range. My favorite is ct; or ct) which deletes everything up to the trailing semicolon / closing parentheses and then places you in insert mode.
Also, G and gg are useful (Go to bottom and top respectively).
^y will copy the character above the cursor.
Typing a line number followed by gg will take you to that line.
I wish I'd known basic visual block mode stuff earlier. Even if you don't use Vim for anything else, it can be a big time saver to open up a file in Vim just for some block operations. I'm quite sure I wasted a ton of time doing this kind of thing manually.
Examples I've found particularly useful, when, say, refactoring lists of symbolic constant names consistently:
Enter Visual Block mode (Ctrl + Q for me on Windows instead of Ctrl + V)
Move the cursor to highlight the desired block.
Then, I whatever text and press Esc to have the text inserted in front of the block on every line.
Use A instead of I to have the text inserted after the block on every line.
Also - simply toggling the case of a visual selection with ~ can be a big time saver.
And simply deleting columns, too, with d of course.
q<letter> - records a macro.
and
#<same-letter> - plays it back.
These are by far the most useful commands in Vim since you can have the computer do a whole lot of work for you, and you don't even have to write a program or anything.
Opening multiple files using tabs
:tabe filepath
Navigating between open files
gt and gT or :tabn and :tabp
Save the open session so that you can get back to your list of open files later
:mksession session_file_name.vim
Open a created session
vim -S session_file_name.vim
Close all files at once
:qa
Another command I learned recently
autocmd
It allows you to run a command on an event, so you could for example run the command make when you save a file using something like:
:autocmd BufWritePost *.cpp :make
qx will start recording keystrokes. You can do pretty much any editing task and Vim remembers it. Hit q again when you're finished, and press #x to replay your keystrokes. This is great for repetitive edits which are too complex to write a mapping for. You can have many recordings by using a character other than x.
I would have to say that one of my favorites is putting the help window in a new tab:
:tab help <help_topic>
This opens up help in a new tab and, as somebody that loves Vim tabs, this is ridiculously useful.
:x #(Save and Quit a File)
Same as :wq or ZZ
cw
Change word - deletes the word under the cursor and puts you in insert mode to type a new one. Of course this works with other movement keys, so you can do things like c$ to change to the end of the line.
f + character
Finds the next occurrence of the character on the current line. So you can do vft to select all the text up to the next "t" on the current line. It's another movement key, so it works with other commands too.
:b [any portion of a buffer name] to switch buffers. So if you have two buffers, "somefile1.txt", and "someotherfile2.txt", you can switch to the second with simply ":b 2.t<enter>". It also supports tab completion, although it's not required.
Speaking of tab completion, the setting :set wildmode=full wildmenu is also very helpful. It enables complete tab completion for command-mode, as well as a very helpful ncurses-style menu of all the possible matches when using it.

Vim keep cursor location while scrolling

Is there a way to keep the cusror location off-screen in Vim / gVim while scrolling? Similar to many Windows editors.
I know about marks, and do use them. I also know the '.' mark (last edit location), But looking for other ideas.
I'm asking this because sometimes i want to keep the cursor at some location, scroll to another place using the mouse-wheel, and then just press an arow key or something to get me back to that location.
No. vim is a console application, so it doesn't really make sense to have the cursour off-screen (it's possible, but would just be confusing)
An alternative solution, to paraphrase posts from this thread from comp.editors:
Ctrl+o goes to the previous cursor location, Ctrl+i goes to the next (like undo/redo for motions)
Marks seem like the other solution..
Also, use marks. Marks are named by letters. For instance typing ma remembers
the current location under mark a. To jump to the line containing mark a,
type 'a. To the exact location use `a.
Lower-case-letter marks are per-file. Upper-case-letter marks are global;
`A will switch to the file containing mark A, to the exact location.
Basically ma, move around, then `a to jump back.
Another option which Paul suggested,
gi command switches Vim to Insert mode and places cursor in the same position as where Insert mode was stopped last time.
Why don't you split the window, look at what you wanted to look at, and then close the split?
:split
or
:vsplit (if you want to split vertically)
The only similar behavior that I've found in Vim:
zt or zENTER "scroll the screen down as far as possible without moving the cursor"
zb "scroll as far up as possible".
Ctrl+E "scroll one line down, if possible"
Ctrl+Y"scroll one line up, if possible"
Sometimes you can avoid jumping to marks before entering text — gi command switches Vim to Insert mode and places cursor in the same position as where Insert mode was stopped last time.
Google says that the cursor (and therefore current line) must be visible in Vi, so you'll have to use marks.
Also very useful are the '' (2x single quotes) and `` (2x back quotes).
The former jumps back to the line you were prior to the last jump (for instance, a page down).
The latter jumps back to the line and column you were prior to the last jump.

Resources