Skip to content

Instantly share code, notes, and snippets.

@smoser
Last active January 18, 2019 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smoser/1ee3f2b223717625c5f4 to your computer and use it in GitHub Desktop.
Save smoser/1ee3f2b223717625c5f4 to your computer and use it in GitHub Desktop.
xvim: run 'vim' in a new gnome-terminal. optionally block until exit (useful with pentadactyl)

xvim

When I want to run vim in a new terminal, I prefer vim inside gnome-terminal rather than gvim. Thats easily enough accomplished with

gnome-terminal --execute vim "$@"

However, sometimes you want to block until vim is done. One example of this is pentadactl's editor (invoked with ctrl-i) older versions of gnome-terminal had --disable-factory, that would block until the command executed returned. Newer versions have dropped that functionality, so we have to come up with another way.

Usage of this program is simple enough:

xvim [block] [vim-arguments]
  This will invoke vim in a gnome-terminal with the provided arguments.

  If the first argument is 'block' then it will not return until vim exits.
  Otherwise it will return immediately.

The implementation is generic enough to support running any command inside a terminal and waiting for the return, but as implemented now only vim is run.

To use in pentadactl, put this program in your path, and put the following in ~/.pentadactlrc:

set editor='xvim block -f +<line> +"sil! call cursor(0, <column>)" <file>'

Usage through desktop 'open file' dialog.

To add this to the dialog of things (like firefox) that look for an application to open, do the following, which is modelled after /usr/share/applications/vim.desktop:

$ cat > ~/.local/share/applications/xvim.desktop <<EOF
[Desktop Entry]
Name=xvim
GenericName=Text Editor
GenericName[de]=Texteditor
Comment=Edit text files
TryExec=xvim
Exec=xvim %F
Type=Application
Keywords=Text;editor;
Icon=gvim
Categories=Utility;TextEditor;
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;application/octet-stream;

EOF
#!/bin/sh
# https://gist.github.com/1ee3f2b223717625c5f4
FIFO=""
BACKUP_DIR="$HOME/t/xvim-backups"
KIDPID=""
error() { echo "$@" 1>&2; }
fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
gtx() {
gnome-terminal -- "$@"
}
killcheck() {
local pid
for pid in "$@"; do
[ ! -d "/proc/$pid" ] || kill "$pid"
done
}
block_cleanup() {
[ -z "$FIFO" ] || rm -f "$FIFO"
[ -z "$KIDPID" ] || killcheck "$kidpid"
}
Usage() {
cat <<EOF
${0##*/} [block] [vim-arguments]
This will invoke vim in a gnome-terminal with the provided arguments.
If the first argument is 'block' then it will not return until vim exits.
Otherwise it will return immediately.
EOF
}
[ "$1" = "--help" -o "$1" = "-h" ] && { Usage; exit 0; }
echo "$0" "$@" >> ~/t/xvim.log
if [ "$1" = "ret-fifo" ]; then
# invoked in "ret-fifo" mode
fifo="$2"
shift 2 || fail "bad usage, no fifo"
# run vim, wait for exit, and write return code to fifo
doexit() {
echo $RET >&3;
kill 0 # kill the whole process group to get the 'vim' pid.
}
RET=1
# open file handle 3 for writing and then remove fifo for cleanliness
exec 3> "$fifo" || fail "failed open $fifo"
trap "doexit" EXIT
echo "$$" >&3
rm -f "$fifo" || fail "failed rm $fifo"
"$@"
RET=$?
exit $RET
elif [ "$1" = "block" -o "$1" = "--block" ]; then
# first argument is 'block', so do our trick.
shift
echo "$*" >> /tmp/my.log
backup=false
if [ "$1" = "--backup" ]; then
# pentadactyl deletes the file after writing, so back one up.
[ -d "$BACKUP_DIR" ] || mkdir -p "$BACKUP_DIR" ||
fail "failed to create $BACKUP_DIR"
shift
backup=true
fi
# find the filename to be edited.
fname=""
for i in "$@"; do
case "$i" in
-*) :;;
*) fname="$i";;
esac
done
# this naming convention is insecure and could be DOS'd
trap block_cleanup INT QUIT
fifo="${TMPDIR:-/tmp}/${0##*/}.$$.fifo"
mkfifo "--mode=600" "$fifo" || fail "failed mkfifo"
FIFO="$fifo"
exec 3<>"$fifo" # opening just for read blocks on a fifo
gtx "$0" ret-fifo "$fifo" vim "$@"
read kidpid <&3
KIDPID="$kidpid"
read ret <&3
if $backup; then
[ -f "$fname" ] || echo "WARNING: file '$fname' did not exist" 1>&2
basename="${fname##*/}"
i=0
while [ $i -lt 100 ] && i=$(($i+1)); do
target=$(printf "%s/%03d-%s" "${BACKUP_DIR}" "$i" "$basename")
[ -f "$target" ] || break
done
cp "$fname" "$target"
fi
exit $ret
else
gtx vim "$@"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment