$EDITOR wrapper for use with cscope and screen(1)

I often have a screen(1) session running with a cscope in window 0, and I want every file I edit from cscope to start in its own window with control returning to cscope immediately. I use a wrapper around my $EDITOR that does this. It’s quite simple.

This way I can search for things with cscope, pick a result, switch back to window 0, pick another, and so on, without blocking cscope.

The script, formatted with VIM’s TOhtml command, follows.


#!/bin/ksh

# Makes for safer scripting
set -o noglob
OIFS="$IFS"
IFS=
PATH=/usr/bin:/bin:$PATH

# This script is to be used as the value of $EDITOR for cscope in a
# screen(1) session.  Selecting a file to edit should then cause a new
# screen window to open with the user’s preferred editor running in it
# to edit the selected file, all the while the script exits so that
# control can return to cscope.  This way the user can start many
# concurrent edits from one cscope session.

# Figure out what the real $EDITOR was intended to be from the current
# setting of $EDITOR or from this program’s name, removing any leading
# ‘s’ (since this program is "svim" or "s<whatever>").
#
# For example, calling this script "svim" causes it to start VIM;
# calling it "semacs" would cause it to start Emacs.
editor=${EDITOR:-$0}
editor=${editor##*/}
editor=${editor#s}
: ${editor:=vim}
export EDITOR=$editor

roeditor=${ROEDITOR:-view}

# Not in screen?  Punt.
[[ -z "$STY" ]] && exec "$editor" "$@"

# Find out if the parent is cscope
function is_parent_cscope {
    local IFS
    IFS="$OIFS"
    clear
    if [[ -f /proc/self/attr/current ]]; then
        # Linux fast path
        read pid comm j ppid j < /proc/self/stat
        read j comm j ppid j < /proc/$ppid/stat
        [[ "$comm" != *cscope* ]] && read j comm j j < /proc/$ppid/stat
        [[ "$comm" = *cscope* ]] && return 0
    elif [[ -f /kernel/genunix ]]; then
        # Solaris fast path
        ptree | grep cscope > /dev/null 2>&1 && return 0
    else
        # Slow path
        comm="$(ps -o comm= -p $PPID)"
    fi
    [[ "$comm" = *cscope* ]] && return 0
    return 1
}

# Don’t try to start a new window _unless_ it was cscope that spawned us
# (the script appears to exit immediately, which causes many tools that
# spawn $EDITOR to think the user did not change the file at all).  If
# other tools like cscope could benefit from this behavior just add them
# here:
if ! is_parent_cscope; then
        exec $editor "$@"
        printf Failed to exec $EDITOR (%s) "$EDITOR" 1>&2
        exit 1
fi

# I often edit/view the same file from cscope in the same screen.  I
# don’t want to be prompted by VIM on the second, third, .., nth
# viewing.  This code decides whether to edit the file read-only.
use_roeditor=false
if [[ $EDITOR = vim ]]; then
    files=0
    for arg in "$@"; do
        [[ "$arg" = -* || "$arg" = [+]]] && continue
        ((files++))
        [[ "$arg" = */* && -f "${arg%/*}/.${arg##*/}.swp" ]] && use_roeditor=true
        [[ "$arg" != */* && -f ".${arg}.swp" ]] && use_roeditor=true
        # cscope doesn’t have us edit more than one file at a time
        ((files > 1)) && use_roeditor=false
    done
fi

$use_roeditor && editor=$roeditor

# Figure out the title for the new screen(1) window
for arg in "$@"do
        [[ "$arg" = -* || "$arg" = [+]]] && continue
        title="${SVIM_TITLE_PREFIX}${arg##*/}"
        break
done

# Start $EDITOR in a new screen window if we’re in a screen session.
# Note that screen in this mode will use IPC to ask the master screen
# process to start the new window, then the client screen process will
# exit, and since we exec it, we exit too.
[[ -n "$STY" && $# -gt 0 ]] && exec screen -h 1 -t "$title" "$editor" -X "$@"

# Fallback on not using screen
exec $editor "$@"
printf Failed to exec $EDITOR (%s) "$EDITOR" 1>&2
exit 1

~ by nico on October 11, 2011.

Leave a Reply

Your email address will not be published. Required fields are marked *