dimarts, de novembre 30, 2010

:w !bash

When working with several files in a folder, one often wishes it would be great if one could rename all those files with a couple of good old editor commands. This is how I do this in Windows with gvim for Windows and cygwin bash. The basic idea is suggested in the vim help system (:he rename-files). Basically the process amount to:
1) Creating a buffer with a list of all the files to rename, one per line
2) Using the native editing capabilities of vim to change these lines into shell commands; each line contains a rename (shell) command
3) Issuing :w !bash to pipe the buffer to the shell

In order to be able to this with cygwin bash, a minimal configuration is suggested in a number of sites:


" http://vim.wikia.com/wiki/Use_cygwin_shell
set shell=D:\foo\cygwin\bin\bash
set shellcmdflag=--login\ -c
set shellxquote=\"

Problem:

1. if --login is used to invoke the shell, it opens in the home directory, not in the current file's directory.

2. if --login is not used, it opens in the current file's directory, but /etc/profile is not read.

In the second case, the cygwin $PATH (/usr/local/bin:usr/bin:bin) is not appended to the Windows %PATH%. As a consequence, only internal commands can be passed to the shell (pwd, cd, etc) but not a program name, since the shell is unable to find the executable. This means that something line :.!bash will fail.

Solution:

The best solution I came up to is a slight modification of the variant of this tip given in http://www.mail-archive.com/vim@vim.org/msg02138.html.
The idea is to use .bashrc to set the path when necessary instead of modifying /etc/profile as suggested here. Since .bashrc is source for non-login shells, do not use --login. Bash will then open in the file's directory (or whatever the current directory happens to be, that is, :pwd). In order to have the path correctly set only when vim requires it, set an environment variable from .vimrc when calling the shell and check its value in .bashrc; if the variable is set, then set the path as in /etc/profile (of course you could set the path directly in .vimrc, but this is would be out of sync if you happen to change something in cygwin or in vim; in other words, it would not be portable).

In .vimrc:

set shell=D:\\cygwin\bin\bash
let $BASH_ENV = '~/.bashrc'
let $FROMVIM = 'X'

In .bashrc:

if [ -n "$FROMVIM" ]; then
PATH="/usr/local/bin:/usr/bin:/bin:$PATH"
fi


By the way: you might want to change the file format of the vim buffer from dos to unix (:se ff=unix) if cygwin is expecting this. Otherwise you'll get a non-printable "\r" appended to each file name.