Search this site


Page 1 of 2  [next]

Metadata

Articles

Projects

Presentations

Flashback 2003: vim + screen trick

Matt Simmons suggested that this week be a flashback week. That's easy enough to do, so I'm doing one per year starting in 2003.

A common feature request of vim is to be able to split window and have a shell be there. Well, as it turns out, that's easy to do if you run vim inside screen (gvim not applicable here).

The original post details a simple vim keybinding that will split the screen and attach a shell and close the split when the shell exits.

August 2003: Neat vim/screen trick

However, I've got a better version now. You'll want this script, "screener.sh":

#!/bin/sh

screen -X split
screen -X focus down
screen -X screen sh -c "cd $PWD; $SHELL; screen -X remove"
Then in your .vimrc:
:map \s :silent !screener.sh<CR>
The new version mostly puts the screen invocations into a shell script. Another improvement is to change to $PWD so the new shell will be in the same working directory as vim started in.

Vim function to make g++ errors readable.

If you've ever used templates in C++, you've probably gone blind trying to read the compiler errors.
grokmatch.hpp:7: error: 'typedef class std::map<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, std::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char>
> >, std::allocator<std::pair<const std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > > >
GrokMatch<boost::xpressive::basic_regex<__gnu_cxx::__normal_iterator<const
char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >
> >::match_map_type' is private
I'm supposed to read all that crap? Especially since 99% of the data isn't useful in most cases. The following vim script sanitizes this output:
function! GPPErrorFilter()
  silent! %s/->/ARROW/g
  while search("<", "wc")
    let l:line = getline(".")
    let l:col = col(".")
    let l:char = l:line[l:col - 1]
    if l:char == "<"
      normal d%
    else
      break
    endif
  endwhile
  silent! %s/ARROW/->/g
  silent %!awk '/: In/ { print "---------------"; print }; \!/: In/ {print }'
endfunction
If I dump the output of make to a file (including stderr), and run the function while in vim, using ':call GPPErrorFilter()', the output turns into this:
g++ -g -I/usr/local/include -c -o main.o main.cpp
---------------
grokmatch.hpp: In function 'int main(int, char**)':
grokmatch.hpp:7: error: 'typedef class std::map GrokMatch::match_map_type' is private
main.cpp:43: error: within this context
make: *** [main.o] Error 1
So much better... Now i know I'm clearly trying to access a private typedef. Sanity++

Vim indentation

More than a year ago, I expressed some frustration about cindent in vim. My main complaints about it were that it made bad decisions about indentation on some languages that were not strictly C-syntax (perl, python, javascript).

Tonight I decided that I wanted to automate indenting to the closest '(' as in:

if (foo() and bar()
    and baz):
    ^ Want to indent to here, somehow, on command.
The 'cindent' feature of vim lets you configure this to happen automatically, but in some cases it won't indent properly: ie; a comment with a ( at the end of the line, for example, will screw it up.

I got tired of dealing with it, so I went back to autoindent, and I've been happier ever after. Fooling around tonight, I started working on a vim function to basically do exactly what I needed. An hour later, it was done. In the process, I wanted to confirm the default actions of ctrl+f in insert mode, which lead me to the cinkeys docs, which clued me that 'cindent' only autoindents on certain occaisions.

All of my time was wasted, it seems, after I figured out setting this option:

set cinkeys=!^F
Now cindent only activates when I hit ctrl+f. If I have both autoindent and cindent enabled, with this cinkeys setting, the default indentation behavior is exactly autoindent, and I can invoke cindent at will.

The following is now set in my .vimrc:

set autoindent
set cindent                     " Use c-style indentation
set cinkeys=!^F                 " Only indent when requested
set cinoptions=(0t0c1           " :help cinoptions-values

If you're interested in the vim script I wrote, which I no longer need, you can download it here: paren_indent.vim

Make vim's hlsearch behave like less(1)

Put this in your vimrc.
" Make hlsearch work like less(1)
set hlsearch
nnoremap <ESC>u :nohlsearch<CR>
hi Search ctermfg=black ctermbg=white

S5: web-based presentationware

I found some time tonight to convert one of my slideshows to S5. It's not fully done, but I have a working slideshow. It took about 5 lines of xslt different from the presenter.xsl stylesheet to turn my slideshow stuff into S5. I still need to learn about S5, but it seems to have many of the features I want - have I mentioned this before? ;)

It's *much* slower than xmlpresenter when switching slides. I can move at many slides-per-second with xmlpresenter and it takes 1-2 seconds to switch slides with S5. However, I'm not sure 'slides-per-second' is even a meaningful metric worth considering. Who does multiples slides in a second anyway? Still, I'm concerned for the overall speed of the software if switching slides takes a while.

my vim presentation in s5: presentations/s5/vim.html

Vim slides updated

Thanks to Sean Graham for pointing out a few typos and suggestions on the vim slides. Fixed!

I've finally got some small free time, so hopefully I'll have something productive coming out of tonight.

Vim Seminar posted

Today was my 2nd open-to-campus seminar at RIT. This time it was on how to use Vim. I made pretty handouts and stuff.

Slides can be found here: /presentations/vim

Note to self, use autoindent instead of cindent.

I use cindent in vim. cindent is very useful. However, it breaks a lot of the time, especially when not in C-style languages (perl, etc). It indents "how I want" 90% of the time, the other 10% it does it incorrectly or when I don't want it to so.

If I can find time tomorrow, I'd like to write a few magic-indentation keybindings so I can easily do certain kinds of indentation the way I want, and only when I want. Most of the time, autoindent is all I need anyway.

I'll post any scripts I come up with here when they're done.

Sexy vim "text objects" feature

Read about text objects in vim with :help text-objects

Text objects are basically direction macros for simple deletion/copy/changing. For instance, diB This will delete everything between the nearest { and closing }. That is:

static int update() {
	if (u) {
		printf("Update\n");
	} else {
		printf("No update\n";
	}
}
Paste the above code in vim. Put the cursor on the first printf (line 3) and, in command mode, do diB - undo that and try ciB. The d command will delete the code block, where as c will do the obvious and delete the code block and leave you in insert mode.

These text object direction things are quite neat. Again, check out the help page on it (:help text-objects). Neat little shortcuts.

Vim hack for Pyblosxom entry backdating

Hurray! I finally got around to hacking a little script for vim that will automatically track posting dates for pyblosxom entries. It does the following:
  1. For new entries, add '#mdate {currentdate}' on the 2nd line.
  2. For existing entries without '#mdate' metadata, it will look up the mdate of the current entry and append it in the form, '#mdate {mdate of file}'
  3. After you write (:w, :wq, etc), vim will look for #mdate metadata and turn the date into something touch(1) can use, then set the modification date of the file.
This seems to work pretty well, and is quite transparent to pyblosxom, since it sees lines beginning with #foo as "metadata" - so far so good. However, it does jump to the 2nd line of the file when you save, which is annoying (but fixable). I'll fix that later.

My "vim scripting"-fu is not strong, so there's probably a cleaner/fancier way to do this. Anyhoo, you'll need the following in your .vimrc:

" PyBlosxom stuff
augroup pyblosxom
	autocmd BufReadPost /home/jls/public_html/entries/*/*.txt call Pyblosxom_checkdate()
	autocmd BufNewFile /home/jls/public_html/entries/*/*.txt call Pyblosxom_putdate()
	autocmd BufWritePost /home/jls/public_html/entries/*/*.txt call Pyblosxom_fudgedate()
augroup end

function Pyblosxom_checkdate() 
	" Look in the file for '#mdate foo' metadata
	normal 1G
	let dateline = search("^#mdate")

	" If not found, append the mdate of the file to line 2
	if dateline < 1
		let dateline = 1
		let date = system("stat -f '#mdate %Sm' " . expand("%"))

		" Add the date to the file on line 1
		1put=date
	endif
endfunction

function Pyblosxom_putdate()
	let date=strftime("#mdate %b %e %H:%M:%S %Y")
	1put=date
	goto 1
endfunction

function Pyblosxom_fudgedate() 
	let l=search("^#mdate")
	let l=strpart(getline(l), 7)
	let cmd="date -j -f '%b %e %H:%M:%S %Y' '" . l . "' +%y%m%d%H%M"
	let touchtime=system(cmd)
	let touchcmd="touch -t '" . strpart(touchtime,0,strlen(touchtime)-1) . "' '" . expand("%") . "'"
	call system(touchcmd)
	e
endfunction