forked from zsh-users/zsh-autosuggestions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
completion-server.zsh
executable file
·128 lines (107 loc) · 2.86 KB
/
completion-server.zsh
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
#!/usr/bin/env zsh
# Based on:
# https://github.com/Valodim/zsh-capture-completion/blob/master/capture.zsh
# read everything until a line containing the byte 0 is found
read-to-null() {
while zpty -r z chunk; do
[[ $chunk == *$'\0'* ]] && break
[[ $chunk != $'\1'* ]] && continue # ignore what doesnt start with '1'
print -n - ${chunk:1}
done
}
accept-connection() {
zsocket -a $server
fds[$REPLY]=1
print "connection accepted, fd: $REPLY" >&2
}
handle-request() {
local connection=$1 current line
integer read_something=0
print "request received from fd $connection"
while read -u $connection prefix &> /dev/null; do
read_something=1
# send the prefix to be completed followed by a TAB to force
# completion
zpty -w -n z $prefix$'\t'
zpty -r z chunk &> /dev/null # read empty line before completions
current=''
# read completions one by one, storing the longest match
read-to-null | while IFS= read -r line; do
(( $#line > $#current )) && current=$line
done
# send the longest completion back to the client, strip the last
# non-printable character
if (( $#current )); then
print -u $connection - $prefix$'\2'${current:0:-1}
else
print -u $connection ''
fi
# clear input buffer
zpty -w z $'\n'
break # handle more requests/return to zselect
done
if ! (( read_something )); then
print "connection with fd $connection closed" >&2
unset fds[$connection]
exec {connection}>&- # free the file descriptor
fi
}
if [[ -n $ZLE_AUTOSUGGEST_SERVER_LOG ]]; then
exec >> "$HOME/.autosuggest-server.log"
else
exec > /dev/null
fi
if [[ -n $ZLE_AUTOSUGGEST_SERVER_LOG_ERRORS ]]; then
exec 2>> "$HOME/.autosuggest-server-errors.log"
else
exec 2> /dev/null
fi
exec < /dev/null
zmodload zsh/zpty
zmodload zsh/zselect
zmodload zsh/net/socket
setopt noglob
print "autosuggestion server started, pid: $$" >&2
# Start an interactive zsh connected to a zpty
zpty z ZLE_DISABLE_AUTOSUGGEST=1 zsh -i
print 'interactive shell started'
# Source the init script
zpty -w z "source '${0:a:h}/completion-server-init.zsh'"
# wait for ok from shell
read-to-null &> /dev/null
print 'interactive shell ready'
# listen on a socket for completion requests
server_dir=$1
pid_file=$2
socket_path=$3
cleanup() {
print 'removing socket and pid file...'
rm -f $socket_path $pid_file
print "autosuggestion server stopped, pid: $$"
exit
}
trap cleanup TERM INT HUP EXIT
mkdir -m 700 $server_dir
while ! zsocket -l $socket_path; do
if [[ ! -r $pid_file ]] || ! kill -0 $(<$pid_file); then
rm -f $socket_path
else
exit 1
fi
print "will retry listening on '$socket_path'"
done
server=$REPLY
print "server listening on '$socket_path'"
print $$ > $pid_file
typeset -A fds ready
fds[$server]=1
while zselect -A ready ${(k)fds}; do
queue=(${(k)ready})
for fd in $queue; do
if (( fd == server )); then
accept-connection
else
handle-request $fd
fi
done
done