#!/bin/sh # # gvimdiff: display highlighted differences between two files side-by-side in # gvim # # Note: This program uses the Unix trick of using its name to alter behavior. # If this file is called gvimdiff, it brings up the differences in gvim. # If it is called vimdiff, it brings up the differences in vim. If it is # called anything else, it fails with an error. If you need vimdiff, # create a symbolic or hard link from gvimdiff to vimdiff. # # Author: Gautam H. Mudunuri (gmudunuri@informatica.com) # # $Revision: 1.1 $ # # Get my name and verify it and determine whether to use vim/gvim progname=`basename $0` case "$progname" in vimdiff) vim_exe="vim" ;; gvimdiff) vim_exe="gvim" ;; *) echo >&2 "This program has an invalid name \"$progname\"" exit 1 ;; esac # Display usage and exit Usage() { # Options common to vimdiff and gvimdiff options="[ -s ]" options_desc="\ -s do not display identical lines -w width width of diff output (default is set for diffs of 80 column wide files)" # Add gvimdiff specific options [ $vim_exe = "gvim" ] && { options="$options [ -f font ] [ -n ] [ -w width ]" options_desc="\ -f font font to use for display -n do not create a wide window (useful if your display is not too wide) $options_desc" } # Display usage and exit echo >&2 "\ $progname: \ display highlighted differences between two files side-by-side in $vim_exe Usage: $progname $options arg1 arg2 Both the arguments must be file names OR one must be a file name and the other a directory name. If one of the arguments is a directory name, it refers to the file in that directory with the same name as the other argument. Options: $options_desc" exit 1 } # Parse commandline n_flag="n" s_flag="n" width= font= while getopts f:nsw: option do case "$option" in f) [ $vim_exe != "gvim" ] && Usage [ "$font" != "" ] && Usage font="$OPTARG" ;; n) [ $vim_exe != "gvim" ] && Usage n_flag="y" ;; s) s_flag="y" ;; w) [ "$width" != "" ] && Usage width="$OPTARG" ;; *) Usage ;; esac done shift `expr $OPTIND - 1` [ $# -eq 2 ] || Usage # Arguments must be files or directories arg1="$1" [ -f $arg1 -o -d $arg1 ] || { echo >&2 "$progname: $arg1 is not a valid file or directory" exit 1 } arg2="$2" [ -f $arg2 -o -d $arg2 ] || { echo >&2 "$progname: $arg2 is not a valid file or directory" exit 1 } # Both arguments cannot be directories [ -d "$arg1" -a -d "$arg2" ] && { echo >&2 "$progname: $arg1 and $arg2 are both directories" echo >&2 "Atleast one file must be specified" exit 1 } # If one argument is a directory, convert it to a filename using the other, # otherwise use it directly [ -d "$arg1" ] && file1="$arg1/`basename $arg2`" || file1="$arg1" [ -d "$arg2" ] && file2="$arg2/`basename $arg1`" || file2="$arg2" # Both files must be readable [ -r "$file1" ] || { echo >&2 "$progname: cannot open $file1 for reading" exit 1 } [ -r "$file2" ] || { echo >&2 "$progname: cannot open $file2 for reading" exit 1 } # Width not specified, use default for 80-column wide files and 9 character # sdiff "gutter". (169 = 2 * 80 + 9) [ "$width" = "" ] && width=169 # Validate width expr "$width" + 0 > /dev/null 2>&1 status="$?" [ $status -eq 0 -o $status -eq 1 ] || { echo >&2 "$progname: invalid width \"$width\"" exit 1 } [ $width -gt 0 ] || { echo >&2 "$progname: width $width cannot be zero or negative" exit 1 } [ $width -ge 49 ] || { echo >&2 "$progname: width $width is too small, should be atleast 29" exit 1 } [ $width -le 209 ] || { echo >&2 "$progname: width $width is too large, should be atmost 209" exit 1 } # Compute width per file, allowing 9 characters for the sdiff "gutter" file_width=`expr '(' $width - 9 ')' / 2` # Compute the range of the number of characters we can expect before the sdiff # separators |, < and >. This is range rather than a specific number because # the presence of tabs can shorten the length min_chars=`expr $file_width - 5` max_chars=`expr $file_width + 2` # Define Vim commands for manipulating the sdiff buffer buffercmds=" set ts=8 et noro retab set nomod ro nows " # Define Vim commands for sdiff syntax highlighting. We are going to define # our custom syntax that is not loaded through the standard syntax mechanism. # But we still need the standard colors to be defined. So turn syntax on to # get them and immediately turn it off syncmds=" syn on syn off syn match sdiffRemoved \"^.\{$min_chars,$max_chars} <\" syn match sdiffChanged \"^.\{$min_chars,$max_chars} | .*$\" syn match sdiffAdded \"^.\{$min_chars,$max_chars} > .*$\" hi link sdiffRemoved Comment hi link sdiffChanged PreProc hi link sdiffAdded Identifier let b:current_syntax = \"vimdiff\" " # Help commands (doesn't always work) helpcmd_next="\ echo 'Ctrl-N: Next Difference Line Ctrl-P: Previous Difference Line'\ " helpcmd_prev="\ echo 'Ctrl-P: Previous Difference Line Ctrl-N: Next Difference Line'\ " # Define Vim mappings to jump to next/previous difference mapcmds=" nmap /^.\{$min_chars,$max_chars} [<>\|]/e:$helpcmd_next nmap ?^.\{$min_chars,$max_chars} [<>\|]?e:$helpcmd_prev " # Collect vim commands to be run vimcmds=" set titlestring=\\$progname\\ \\$arg1\\ \\$arg2 set noml nows nowrap go=agrb ch=2 $buffercmds $syncmds $mapcmds execute \"normal gg0$max_chars|3l\" $helpcmd_next " # Set sdiff_flags flags sdiff_flags= [ "$s_flag" = "y" ] && sdiff_flags="$flags -s" # Set vim flags vim_flags="-R -N" [ "$font" != "" ] && vim_flags="$vim_flags -fn $font" [ $n_flag != "y" -a $vim_exe = "gvim" ] && { vim_flags="$vim_flags -geometry $width" } # Run the diff and display the output in gvim sdiff -w$width $sdiff_flags $file1 $file2 | $vim_exe $vim_flags -c "$vimcmds" -