aboutsummaryrefslogtreecommitdiff
path: root/stealvim
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2026-09-09 19:16:34 -0400
committerB. Watson <urchlay@slackware.uk>2026-09-09 19:16:34 -0400
commit40e37237bd6d94869bec344a359fa0208cf60375 (patch)
tree8add0f1c7592f14658556a9fced4651d203c03a3 /stealvim
parentc9b355ac004fb7913e4fabd02e274f3484b76ea8 (diff)
downloadmisc-scripts-40e37237bd6d94869bec344a359fa0208cf60375.tar.gz
stealvim: added
Diffstat (limited to 'stealvim')
-rwxr-xr-xstealvim98
1 files changed, 98 insertions, 0 deletions
diff --git a/stealvim b/stealvim
new file mode 100755
index 0000000..754b02d
--- /dev/null
+++ b/stealvim
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+SELF="$( basename $0 )"
+
+warn() {
+ echo "$SELF: $*" 1>&2
+}
+
+die() {
+ echo "$SELF: fatal: $*" 1>&2
+ exit 1
+}
+
+if [ "$1" = "-h" -o "$1" = "--help" -o "$2" != "" ]; then
+ cat <<EOF
+$SELF - take over a running vim instance via reptyr
+
+Usage: $SELF [<file>}
+
+With no argument, $SELF searches for .*.swp files in the current
+directory. If only one is found, the PID of the process that owns it
+is redirected to the current TTY by running "reptyr <pid>". If there
+are multiple .*.swp files, no process is redirected; instead the PIDs
+that own the files are printed to stderr.
+
+With a <file> argument, the vim process editing that file (if any)
+is passed to reptyr. The <file> can either be the actual file
+being edited, or the .*.swp file.
+
+Typical use case: you were editing a file remotely (via ssh), left
+yourself logged in and forgot to exit vim; now you're at the console
+or logged in from a different host and want to continue editing the
+same file.
+
+After "stealing" the vim process, it's best to write any changes
+and then exit vim immediately. To continue editing, run vim again.
+If you ignore this suggestion, things might or might not work OK
+depending on the terminal emulators in use, and/or the TERM setting.
+EOF
+fi
+
+[ "$( type -p reptyr )" = "" ] && \
+ die "reptyr not installed!"
+
+old=""
+
+for i in .*.swp; do
+ [ ! -e "$i" ] && die "no .*.swp files"
+
+ swppid="$( file $i | sed 's/.*, pid \([^,]*\),.*/\1/' )"
+
+ # If there's an argument and we found the matching .swp, use it.
+ if [ "$i" = "$1" -o "$i" = ".$1.swp" ]; then
+ pid=$swppid
+ break
+ fi
+
+ # If there's an argument and the current .swp file doesn't
+ # match, ignore this .swp.
+ [ "$1" != "" ] && continue
+
+ # If the .swp's PID is no longer running, ignore it.
+ if [ ! -d /proc/$swppid ]; then
+ warn "$i: PID $swppid no longer running"
+ continue
+ fi
+
+ # If we can't read the exe, it likely means it belongs to root,
+ # or anyway not the current user.
+ if [ ! -r /proc/$swppid/exe ]; then
+ warn "$i: PID $swppid doesn't belong to user $( whoami )"
+ continue
+ fi
+
+ # If the .swp's PID is running but it's not vim, the PID has been
+ # reused. ignore it. This works even if vim was called by a
+ # symlink (e.g. /usr/bin/vi => vim).
+ case "$( realpath /proc/$swppid/exe )" in
+ */vim) ;;
+ *) warn "$i: PID $swppid not a vim process"; continue ;;
+ esac
+
+ pid=$swppid
+ if [ "$old" != "" ] && [ "$pid" != "$old" ]; then
+ die "multiple vim PIDs: $old $pid"
+ exit 1
+ fi
+
+ old=$pid
+done
+
+if [ "$pid" = "" ]; then
+ msg="no vim PID found"
+ [ "$1" != "" ] && msg+=" for $1"
+ die $msg
+fi
+
+reptyr "$pid"