aboutsummaryrefslogtreecommitdiff
path: root/stealvim
blob: 754b02df74c2b2daed4a2bae2cdabfd12262aafd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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"