Wednesday, May 31, 2006

purpose of the blog

If somebody comes across the blog, I want to make sure what people see here.

Another hard drive crashed, another non-backed-up $HOME died - and again I have to ressurect my .vimrc from ashes. Piece by piece. This becomes a habit.

With the blog I hope to record as much knowledge as possible, so next time creation of my .vimrc - full fledged, ready for production environment - wouldn't take as long as it takes now. There would be single place with all things I need. And it will be smaller than vim's online ":help"

P.S. Some people argued that I just need to save my up-to-date .vimrc somewhere on the net. But this is a way of Emacs users. I do not like NNN kilobytes of black magic everybody copied from Joe The Emacs Pro and nobody understand meaning of. I like to have things I (1) need and (2) understand. I do not like black magic.

Monday, May 29, 2006

VIM's buffers

Buffer is what VIM uses for holding all information related to a file open during editing session. One can think of buffer as file. The only case when buffer is not file - is when we started editing file and not yet saved it.

VIM keeps inactive files closed. Only file(s) currently displayed is(are) open. (You can have of course more than one file displayed with multiple windows).

":ls" lists all buffers. (Conveniently, common mistype ":sl" is call to function sleep with default to sleep for 1 second.)

":b1" - switch to buffer number 1 - will reopen first file open for editing in the vim session. If file in current buffer was modified, the command would fail.

":bd" deletes current buffer. Makes vim forget that it edited the file in the buffer. Buffer numbers are not reused. Trying later to switch to that buffer number will reopen the file. In other words, ":bd" only removes the buffer from output of command ":ls".

":b#" switches to previously open buffer. Something I use a lot. Similar to ":b1" command, but instead of literal buffer number it uses vim's shortcut '#' for previous active buffer. '%' is shortcut to currently active buffer and consequently ":b%" is nop, since there is nothing to be done to activate already active buffer.

So all of my .vimrc have the line:

map <F6> :b#<CR>

what allows me to work with two files very quickly: I just need to press F6 to go to second file.

Type ":help windows.txt" in VIM for more info.

P.S. The buffers is where VIM stores info about files to open, if more than single file was specified. If vim is called that way:
$ vim *.c
you would find all of .c files vim is to open by ":ls" command. Usual :next/:prev are used to browse thru all the files.

useful shortcuts

Something I use often in command mode.


close current file. closes vim is last file.

move to last stored position in edited file

list all symbols found in tags

go to first symbol found in tags. :tnext/:tprev/:tlast to browse all matching tags

find next occurence of symbol under cursor

find previous occurence of symbol under cursor

find matching opening/closing bracket

"go file" - open file with name of word under cursor

delete characted under cursor. Unlike <Delete> works on all terminals.

delete current line

go to the end of file

go to the beginning of file

Command mode with its simple shortcuts was saving my ass on numerous occasions. Broken terminals are still around. Even if another day all borken terminals get fixed, tools like busybox working over raw serial line will be with us for quite some time ;-)

restoring last edited position

The simple trick from vim's online help is used to send cursor to last edited line in the file upon reopening.

au BufReadPost * if line("'\"") > 0 &&
\ line("'\"") <= line("$") | exe "normal g'\"" | endif

Type in vim ":help :au" for more info.

Wednesday, May 24, 2006

C++ :: load counterpart file

Ever wondered how to load counterpart file? IOW, when you have open header file - automatically open corresponding c file.

That's what I use:

map <silent> <F7> :exec ":e ".(expand("%") =~ ".h$"
\ ? glob(substitute(expand("%"), ".h$", ".cpp", ""))
\ : substitute(expand("%"), "\\.cpp$", ".h", ""))<CR>

Hanged on <F7>. First we look if it's header file open. If header, then we replace .h with .cpp and try to ":e"dit that file. If it's not header, we presume it's cpp file and try to replace .cpp with .h and ":e"dit that file.

P.S. <silent> in :map ensures that command wouldn't be displayed during its execution.

prevent vim from going to replace mode

Simpliest trick on the block. Took me long time to figure out.

imap <Insert> <Nop>

And that's it. Now regardless of how many times you press Insert in command mode - or whether in insert mode already - you will be/remain in insert mode.

Of course, you still can go to replace mode by pressing R in command mode.

making vim and ctags real friends

When one has multiple working copies of the source code repository, managing tags can be quite a burden.

The following script from my .vimrc does the trick - it looks for tags file in the enclosing directories and adds first match to the vim's 'tags' variable. The script is also modified to take care of Win32 version of vim.

let tag_dir=getcwd()
if match(tag_dir, "^/") == 0
let end_dir='/'
while !filereadable(tag_dir."/tags") && tag_dir!=$HOME && tag_dir!=end_dir
let tag_dir = substitute(tag_dir, '/[^/]\+$', "", "")
if filereadable(tag_dir."/tags")
exe "set tags+=".tag_dir."/tags"
elseif match(tag_dir, "^[a-zA-Z]:[\\/]") == 0
let end_dir=tag_dir[0].tag_dir[1]
while !filereadable(tag_dir."\\tags") && tag_dir!=end_dir
let tag_dir = substitute(tag_dir, '\\[^\\]\+$', "", "")
if filereadable(tag_dir."\\tags")
exe "set tags+=".tag_dir."\\tags"

Lookup stops when root or home directory is reached.

First script checks to see if the system Unix or Win32: '/' as first character of pwd identifies Unix system (or CygWin). Then script check to see if there is "tags" file in the current working directory. If not found it strips from path one directory level and tries in loop again. Loop ends when "tags" file found or root/$HOME directory reached. If "tags" file was found script adds it to 'tags' vim variable.

Update: you can find newer version of my script here.

broken terminals - cure for the vim

Many times I have come across broken terminals screwing vim handling of shortcuts. Or vim just do not expect that some keys may produce such long sequences.

The most common sign - '--INSERT--' isn't displayed immedaitely after pressing insert key.

The cure is:

set notimeout
set ttimeout
set timeoutlen=100

Put that three lines into the beggining of the ~/.vimrc.

P.S. The tips is located in vim's excelent help system under the keyword "xterm-cursor-keys". Type that in vim - :help xterm-cursor-keys - to get there.