From c6c97ab7bd6c18016b81246305295b247b8d19a6 Mon Sep 17 00:00:00 2001
From: Thiago de Arruda <tpadilha84@gmail.com>
Date: Tue, 29 Oct 2013 05:42:03 -0300
Subject: [PATCH] Got basic completions working, need to ignore

cases like 'kill name<tab>' which should replace the word
---
 autosuggestions.zsh        | 47 ++++++++------------------------------
 completion-client.zsh      | 47 +++++++++++++++++++++++---------------
 completion-server-init.zsh |  6 ++++-
 completion-server.zsh      | 39 +++++++++++++++++++------------
 4 files changed, 68 insertions(+), 71 deletions(-)

diff --git a/autosuggestions.zsh b/autosuggestions.zsh
index fb5ffe6..e82dfd3 100644
--- a/autosuggestions.zsh
+++ b/autosuggestions.zsh
@@ -8,30 +8,12 @@
 # ```
 zmodload zsh/net/socket
 
-AUTOSUGGEST_SERVER_SCRIPT="${0:a:h}/completion-server.zsh"
+source "${0:a:h}/completion-client.zsh"
 
-# function {
-# 	[[ -n $ZLE_DISABLE_AUTOSUGGEST ]] && return
-# 	setopt local_options no_hup
-
-# 	local server_dir="/tmp/zsh-autosuggest-$USER"
-# 	local pid_file="$server_dir/pid"
-# 	local socket_path="$server_dir/socket"
-
-# 	if ! [[ -S $socket_path && -r $pid_file ]] || ! kill -0 $(<$pid_file) &>/dev/null; then
-# 		# start server
-# 		zsh $AUTOSUGGEST_SERVER_SCRIPT $server_dir $pid_file $socket_path &!
-# 	fi
-
-# 	integer remaining_tries=10
-# 	# wait until the process is listening
-# 	while ! [[ -d $server_dir && -r $pid_file ]] || ! kill -0 $(<$pid_file) &> /dev/null; do
-# 		(( --remaining_tries )) || break
-# 		sleep 0.3
-# 	done
-
-# 	ZLE_AUTOSUGGEST_SOCKET=$socket_path
-# }
+function {
+	[[ -n $ZLE_DISABLE_AUTOSUGGEST ]] && return
+	autosuggest-ensure-server
+}
 
 ZLE_AUTOSUGGEST_PAUSE_WIDGETS=(
 vi-cmd-mode vi-backward-char backward-char backward-word beginning-of-line
@@ -169,25 +151,14 @@ paused-autosuggest-self-insert() {
 	fi
 }
 
-autosuggest-first-completion() {
-	zsocket $ZLE_AUTOSUGGEST_SOCKET &>/dev/null || return 1
-	local connection=$REPLY
-	local completion
-	print -u $connection $LBUFFER
-	while read -u $connection completion; do
-		RBUFFER=" $completion"
-		break
-	done
-	exec {connection}>&-
+autosuggest-get-completion() {
+	local suggestion=$(autosuggest-first-completion $LBUFFER)
+	RBUFFER="$suggestion"
 }
 
 show-suggestion() {
 	[[ -n $ZLE_DISABLE_AUTOSUGGEST || $LBUFFER == '' ]] && return
-	# TODO need a way to reset HISTNO so .history-beginning-search-backward
-	# will always retrieve the last matching history entry
-	# unset HISTNO
-	zle .history-beginning-search-backward || autosuggest-first-completion\
-		|| RBUFFER=''
+	zle .history-beginning-search-backward || autosuggest-get-completion
 	highlight-suggested-text
 }
 
diff --git a/completion-client.zsh b/completion-client.zsh
index 9439bd9..8edef1a 100755
--- a/completion-client.zsh
+++ b/completion-client.zsh
@@ -1,25 +1,36 @@
 #!/usr/bin/env zsh
-# Helper script for debugging the completion server
 zmodload zsh/net/socket
-setopt no_hup
+
 AUTOSUGGEST_SERVER_SCRIPT="${0:a:h}/completion-server.zsh"
 
-server_dir="/tmp/zsh-autosuggest-$USER"
-pid_file="$server_dir/pid"
-socket_path="$server_dir/socket"
+autosuggest-ensure-server() {
+	setopt local_options no_hup
+	local server_dir="/tmp/zsh-autosuggest-$USER"
+	local pid_file="$server_dir/pid"
+	local socket_path="$server_dir/socket"
 
-[[ -S $socket_path && -r $pid_file ]] && kill -0 $(<$pid_file) &> /dev/null ||\
-	zsh $AUTOSUGGEST_SERVER_SCRIPT $server_dir $pid_file $socket_path &!
+	[[ -S $socket_path && -r $pid_file ]] && \
+	 	kill -0 $(<$pid_file) &> /dev/null || \
+	 	zsh $AUTOSUGGEST_SERVER_SCRIPT $server_dir $pid_file $socket_path &!
 
-# wait until the process is listening
-while ! [[ -d $server_dir && -r $pid_file ]] || ! kill -0 $(<$pid_file) &> /dev/null; do
-	sleep 0.3
-done
+	integer remaining_tries=10
+	# wait until the process is listening
+	while ! [[ -d $server_dir && -r $pid_file ]] ||\
+	 	! kill -0 $(<$pid_file) &> /dev/null && (( --remaining_tries )); do
+		sleep 0.3
+	done
+	ZLE_AUTOSUGGEST_SOCKET=$socket_path
+}
 
-zsocket $socket_path
-connection=$REPLY
-print -u $connection vi
-while read -u $connection completion; do
-	print $completion
-done
-exec {connection}>&-
+
+autosuggest-first-completion() {
+	zsocket $ZLE_AUTOSUGGEST_SOCKET &>/dev/null || return 1
+	local connection=$REPLY
+	local completion
+	print -u $connection $1
+	while read -u $connection completion; do
+		print ${completion}
+	done
+	# close fd
+	exec {connection}>&-
+}
diff --git a/completion-server-init.zsh b/completion-server-init.zsh
index f5c59da..33939ac 100644
--- a/completion-server-init.zsh
+++ b/completion-server-init.zsh
@@ -1,6 +1,7 @@
 # Based on:
 # https://github.com/Valodim/zsh-capture-completion/blob/master/.zshrc
 
+ZLE_DISABLE_AUTOSUGGEST=1
 # no prompt!
 PROMPT=
 
@@ -38,6 +39,10 @@ zstyle ':completion:*' insert-tab false
 zstyle ':completion:*' list-separator ''
 # dont use matchers
 zstyle -d ':completion:*' matcher-list
+# dont format
+zstyle -d ':completion:*' format
+# no color formatting
+zstyle -d ':completion:*' list-colors
 
 # we use zparseopts
 zmodload zsh/zutil
@@ -96,7 +101,6 @@ compadd () {
 	# this is the point where we have all matches in $__hits and all
 	# descriptions in $__dscr!
 
-	__hits=(${(O)__hits})
 	# display all matches
 	local dsuf dscr
 	for i in {1..$#__hits}; do
diff --git a/completion-server.zsh b/completion-server.zsh
index cb1a4fb..15d0856 100755
--- a/completion-server.zsh
+++ b/completion-server.zsh
@@ -2,7 +2,9 @@
 # Based on:
 # https://github.com/Valodim/zsh-capture-completion/blob/master/capture.zsh
 
+# close stdio
 exec &> /dev/null
+exec < /dev/null
 
 zmodload zsh/zpty
 zmodload zsh/net/socket
@@ -13,37 +15,30 @@ zpty z ZLE_DISABLE_AUTOSUGGEST=1 zsh -i
 # Source the init script
 zpty -w z "source '${0:a:h}/completion-server-init.zsh'"
 
+# read all completions and return the longest match
 read-to-null() {
-	connection=$1
-	integer consumed=0
 	while zpty -r z chunk; do
 		[[ $chunk == *$'\0'* ]] && break
-		(( consumed++ )) && continue
-		if [[ -n $connection ]]; then
-			print -n -u $connection $chunk
-		else
-			print -n $chunk &> /dev/null
-		fi
+		print -n $chunk
 	done
 }
 
 # wait for ok from shell
-read-to-null
+read-to-null &> /dev/null
 
-# listen on an unix domain socket
+# listen on a socket for completion requests
 server_dir=$1
 pid_file=$2
 socket_path=$3
 
 
 cleanup() {
-	rm -f $socket_path
-	rm -f $pid_file
+	rm -f $socket_path $pid_file
 }
 
 trap cleanup TERM INT HUP EXIT
 
-mkdir $server_dir &> /dev/null
+mkdir -m 700 $server_dir &> /dev/null
 
 while ! zsocket -l $socket_path; do
 	if [[ ! -r $pid_file ]] || ! kill -0 $(<$pid_file) &> /dev/null; then
@@ -61,10 +56,26 @@ while zsocket -a $server &> /dev/null; do
 	connection=$REPLY
 	# connection accepted, read the request and send response
 	while read -u $connection prefix &> /dev/null; do
+		# 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
-		read-to-null $connection
+		local current=''
+		# read completions one by one, storing the longest match
+		read-to-null | while read line; do
+			(( $#line > $#current )) && current=$line
+		done
+		# send the longest completion back to the client, strip the last
+		# non-printable character
+		if (( $#current )); then
+			local last_word=${${(z)prefix}[-1]}
+			print -u $connection ${current:$#last_word:-1}
+		else
+			print -u $connection ''
+		fi
+		# close fd
 		exec {connection}>&-
+		# clear input buffer
 		zpty -w z $'\n'
 	done
 done