Zsh: univ_open: A Universal Directory/File Opener (no more bashrun)

UPDATE July 1, 2010: univ_open() has been updated here.

Like my previous post, the goal is to use a single alias to open up any kind of file or directory intelligently. I’ve decided to write a new post because of various improvements over the old code. For one, I’ve implemented everything in Zsh — now everything is much faster, especially for older systems. So now the components are: (1) a custom zsh function called univ_open and (2) some custom options in ~/.zshrc to complement univ_open.

Here is the new univ_open:

 1 # Author: Shinobu (https://zuttobenkyou.wordpress.com)
 2 # Date: December 2009
 3 # License: PUBLIC DOMAIN
 4 # Program Name: univ_open
 5 # Description: open up directories and files intelligently
 6 
 7 univ_open() {
 8     ls="ls -Ahs --color=auto"
 9     if [[ -z $@ ]]; then
10         # if we do not provide any arguments, go to the home directory
11         cd && ${=ls}
12     elif [[ ! -e $@ ]]; then
13         # go to the nearest valid parent directory if file does not exist; we
14         # use a while loop to find the closest valid directory, just in case
15         # the user gave a butchered-up path
16         d=$@:h
17         while [[ ! -d $d ]]
18         do
19             d=$d:h
20         done
21         cd $d && ${=ls}
22     elif [[ -d $@ ]]; then
23         cd $@ && ${=ls}
24     else
25         case $@:e:l in
26             (doc|odf|odt|rtf)
27                 soffice -writer $@ &>/dev/null & disown
28             ;;
29             (htm|html)
30                 firefox $@ &>/dev/null & disown
31             ;;
32             (pdf|ps)
33                 evince $@ &>/dev/null & disown
34             ;;
35             (bmp|gif|jpg|jpeg|png|svg|tiff)
36                 eog $@ &>/dev/null & disown
37             ;;
38             (psd|xcf)
39                 gimp $@ &>/dev/null & disown
40             ;;
41             (aac|flac|mp3|ogg|wav|wma)
42                 smplayer $@ &>/dev/null & disown
43             ;;
44             (mid|midi)
45                 timidity $@
46             ;;
47             (avi|flv|ogv|mkv|mov|mp4|mpg|mpeg|wmv)
48                 smplayer $@ &>/dev/null & disown
49             ;;
50             *)
51             vim $@
52             ;;
53         esac
54     fi
55 }

The basic operation of this function remains the same: if no arguments given, go to the home directory (this is cd‘s default behavior); if path is invalid, go to the nearest valid parent directory; if path is a valid directory, cd to it; otherwise, it must be a valid file, so open it up with a program based on the file’s extension, and use vim as the default program for unrecognized extensions (or files with no extensions). Again, filename extensions are lowercased to ensure that we are case-insensitive.

Some improvements over the old code: (1) univ_open now correctly handles messed-up, invalid directories by trying to find the closest valid parent directory — this is achieved with a simple while loop, and zsh’s neat little “:h” method to extract the parent directory (same functionality as the UNIX dirname utility); if there is not a single valid directory in the given path, then it will simply cd into the current directory (i.e., nothing happens); (2) the file extensions are handled much better depending on filetype — for commands that are GUI-based, we redirect its STDOUT and STDERR to /dev/null to silence any error messages, immediately background it with the “&” operator, and finally disown it so that we can continue other work from the same terminal where we used our alias from. Terminal-bound commands, such as timidity and vim, are left as-is.

The neat thing about this new version of univ_open is that this makes bashrun for me obsolete! I can do pretty much everything from the terminal as it is.

And now, the pertinent options in ~/.zshrc to complement our use of univ_open:

fpath=(~/.zsh/func $fpath) # add ~/.zsh/func to $fpath
autoload -U ~/.zsh/func/*(:t) # load all functions in ~/.zsh/func
zmodload zsh/complist
setopt auto_menu
unsetopt listambiguous
zstyle ':completion:*' menu select=1 _complete _ignored _approximate
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
bindkey -M menuselect '^M' .accept-line
LISTMAX=9999
alias d='univ_open' # alias to use univ_open()

auto_menu enables the menu selection system after pressing TAB. unsetopt listambiguous makes zsh automatically complete an ambiguous word to the nearest, partial-word match (combined with auto_menu, this makes it so that you only have to type TAB once, and only once, in all situations). The zstyle lines affect the style of how the menu is displayed. The bindkey portion makes the ENTER key execute the command when using the menu. (Note, ^M is a special character that represents a newline; in vim, you have to type CTRL-V, then CTRL-M to insert it). Finally, setting LISTMAX to a high number prevents zsh from asking “do you wish to see all N possibilities?”, unless N > 9999.

Happy zsh-ing!

UPDATE January 13, 2010: If you’re in a hurry, then you can put bindkey ‘\t’ menu-expand-or-complete to make it so that pressing TAB once brings up the menu and select the first item in that menu. (Or, if there is just 1 possibility, then to expand to that item).

UPDATE February 25, 2010: See my comment #1 below.