-
-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathe
More file actions
executable file
·166 lines (143 loc) · 5.03 KB
/
Copy pathe
File metadata and controls
executable file
·166 lines (143 loc) · 5.03 KB
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env bash
# e - Custom EDITOR provider
# Uses nvim, fallback to vim, fallback to vi
#
# Supported environment variables:
# - E_DEBUG=true enable debug logging
# Use a tab-scoped socket inside WezTerm so each tab gets its own nvim
# instance; panes within the same tab share it. Falls back to a single
# global socket for non-WezTerm terminals.
#
# $WEZ_TAB_ID is a cache zsh/wezterm.zsh keeps warm to save a fork. Validate
# rather than trust it -- it is inherited, so it can arrive stale (a tmux
# server started in another tab) or hand-set. wez-tab-id is the authority
# whenever it is missing or junk.
__nvim_state="${XDG_STATE_HOME:-${HOME}/.local/state}/nvim"
_t="${WEZ_TAB_ID:-}"
case "$_t" in
"" | *[!0-9]*) _t=$(wez-tab-id) ;;
esac
case "$_t" in
"" | *[!0-9]*) __server="${__nvim_state}/nvim.sock" ;;
*) __server="${__nvim_state}/nvim-tab-${_t}.sock" ;;
esac
unset _t __nvim_state
log() {
echo "[e] ${1}"
}
# Set once this invocation is the one that started the server. Only the owner
# may remove the socket: closing a single pane HUPs that pane alone, and the
# nvim sharing this tab's socket may still be running in another one.
__owns_server=""
# Signals that can leave the socket behind, i.e. kill nvim without letting it
# run VimLeavePre. HUP is the tab/terminal going away, which is the common
# one. Note nvim runs the tty in raw mode, so Ctrl-C while it is up is a
# keystroke rather than a signal -- INT mostly lands on the script itself,
# e.g. during the headless --remote-expr calls below.
on_signal() {
local signal="$1"
# -S so a signal can never take out something that isn't our socket
[ -n "$__owns_server" ] && [ -S "$__server" ] && {
log "Received SIG${signal}, removing ${__server}"
rm -f "$__server"
}
local orphans
orphans=$(
# pgrep does NOT return all results
# shellcheck disable=2009
ps -U "${USER:-$(id -un)}" -ww -o args= | grep -v grep | grep language-server
)
[[ -n $orphans ]] && {
log "Possible orphan language server processes:"
log "${orphans}"
}
# re-raise so we die from the signal and callers see the usual 128+n status
trap - "$signal"
kill -s "$signal" $$
}
main() {
wez-clean-socks
! command -v nvim >/dev/null && {
local fallback
fallback="vim"
! command -v vim >/dev/null && fallback="vi"
[[ "$E_DEBUG" != "" ]] && log "Use fallback editor ${fallback}"
"$fallback" "$@"
return
}
local first="$1"
local existing
local running
# pgrep does NOT return all results. -ww because the socket path sits at the
# end of a long command line -- macOS ps never truncated it in testing, even
# on a narrow tty, but Linux procps is not so reliably unlimited
# shellcheck disable=2009
running=$(
ps -U "${USER:-$(id -un)}" -ww -o args= | grep -v grep | grep -F "$__server"
)
if [ -z "$running" ]; then
[[ "$E_DEBUG" != "" ]] && log "Not running"
# this happens if my neovim crashes/killed without VimLeavePre
if [ -S "$__server" ]; then
[[ "$E_DEBUG" != "" ]] && log "Removing dead ${__server}"
rm -f "$__server"
elif [ -e "$__server" ]; then
# not ours to delete -- nvim --listen will fail and say why
log "Not a socket, leaving alone: ${__server}"
fi
else
# remote-expr outputs to /dev/stderr for some reason
# 0.9.0 needs headless https://github.com/neovim/neovim/issues/22970
# @TODO detect multiple instances and pick correct server
# https://github.com/neovim/neovim/issues/21600
existing=$(nvim \
--headless \
--server "$__server" \
--remote-expr "execute('echo v:servername')" \
2>&1 | xargs)
[[ "$E_DEBUG" != "" ]] && log "Found running $existing"
fi
# New server, empty
[ "$existing" != "$__server" ] && [ -z "$first" ] && {
[[ "$E_DEBUG" != "" ]] && log "New server ${__server} with empty file"
__owns_server=1
nvim --listen "$__server" +enew
return
}
typeset -a files=()
for file in "$@"; do
# don't prepend PWD for absolute paths
case "$file" in
/*) ;;
*) file="$(pwd)/${file}" ;;
esac
files+=("$file")
done
# New server with files
[ "$existing" != "$__server" ] && {
[[ "$E_DEBUG" != "" ]] &&
log "New server ${__server} (did not match ${existing}) with ${files[*]}"
__owns_server=1
nvim --listen "$__server" "${files[@]}"
return
}
# ==========================================================================
# use existing server
# ==========================================================================
# 0.9.0 needs headless https://github.com/neovim/neovim/issues/22970
nvim \
--headless \
--server "$__server" \
--remote-expr "execute('DKOExternal')"
if [ -z "$first" ]; then
[[ "$E_DEBUG" != "" ]] && log "No file given, surface existing server"
nvim --server "$__server" --remote-send '<C-\><C-N><Cmd>e<CR>'
return
fi
[[ "$E_DEBUG" != "" ]] && log "Use server ${__server} with ${files[*]}"
nvim --server "$__server" --remote-silent "${files[@]}"
}
trap 'on_signal INT' INT
trap 'on_signal HUP' HUP
trap 'on_signal TERM' TERM
main "$@"