Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

emacs style completion in ksh93

1 réponse
Avatar
Cyrille Lefevre
hi,

this should be rewritten using a state machine, but, for instance, this
satisfy my needs...

handle tab => complete => list [=> esc # => select]
handle esc [ # ~ and esc [[ # as key binding
handle esc # as numeric prefix

ksh93 d (dtksh) vs. ksh93 q/s :

* esc [ # ~ is received as esc [, then #, then ~ under ksh93 d (dtksh)
while it is received as esc [ # ~ under ksh93 q/s
* .sh.edtext is always empty under ksh93 d (dtksh)
so hitting DEL (^D) at first pos does nothing
* esc [[ # is received as esc [[, then # under both ksh93 d/q/s
* cd /path/to esc = esc # esc = is buggy under ksh93 d
admit that the first esc = propose 1) lib/ 2) lib, then
esc 2 esc = replace /path/to by lib/ instead of /path/to/lib/

#!/bin/echo error: only source
#ident @(#) $Header:
/package/cvs/exploitation/util/san/libksh/Attic/ksh93rc,v 1.1.2.4
2007/02/19 17:29:50 cle Exp $
# [[ ${SECONDS} = *[.,]* ]] && . ./.ksh93rc

comp=(
ff=$'\f'
tab=$'\t'
list=$'\E='
comp=$'\E\E'
integer count=0
esc=$'\E'
ednum=
tilde='~'
esc2=$'\E\[\['
edchar=
eof=$'\004'
map=( []= )
)

function comp_emacs {
#printf "<%q-%q:%q:%q>" "${.sh.edchar}" "${.sh.edcol}"
"${#.sh.edtext}" "${.sh.edtext}"
if [[ ${.sh.edchar} == ${comp.tab} ]]; then
if [[ -n ${comp.ednum} ]]; then
comp.count=1
fi
if (( ++comp.count == 1 )); then
.sh.edchar=${comp.comp}; return
elif (( comp.count > 1 )); then
.sh.edchar=${comp.ednum}${comp.list}
comp.ednum=; return
fi
# notreached
elif [[ ${.sh.edchar} != ${comp.ff} ]]
comp.count=0
# fallthrough
fi
if [[ ${.sh.edchar} == ${comp.esc}[0-9] ]]; then
typeset ednum=${comp.ednum}
comp.ednum=${.sh.edchar}
.sh.edchar=${ednum}${comp.edchar}
comp.edchar=; return
elif [[ ${.sh.edchar} == [0-9] ]]; then
# dtksh hack
if [[ -n ${comp.edchar} ]]; then
comp.edchar=${comp.edchar}${.sh.edchar}
.sh.edchar=; return
elif [[ -n ${comp.ednum} ]]; then
comp.ednum=${comp.ednum}${.sh.edchar}
.sh.edchar=; return
fi
# fallthrough
elif [[ ${.sh.edchar} = [A-E] ]]; then
# cygwin hack
if [[ -n ${comp.edchar} ]]; then
.sh.edchar=${comp.edchar}${.sh.edchar}
# fallthrough
fi
fi
# dtksh hack
if [[ ${.sh.edchar} == ${comp.tilde} ]]; then
if [[ -n ${comp.edchar} ]]; then
typeset edmap=${comp.map[${comp.edchar}${comp.tilde}]}
if [[ ${edmap} != ${comp.eof} ]] || \
(( .sh.edcol || ( ! .sh.edcol && ${#.sh.edtext} ) )); then
.sh.edchar=${comp.ednum}${edmap}
comp.ednum= comp.edchar=; return
elif [[ ${edmap} == ${comp.eof} ]] && (( ! .sh.edcol )); then
.sh.edchar=
comp.ednum= comp.edchar=; return
fi
# fallthrough
fi
# cygwin hack
elif [[ ${.sh.edchar} == "${comp.esc2}" ]]; then
comp.edchar=${.sh.edchar}
.sh.edchar=; return
elif [[ -n ${comp.map[${.sh.edchar}]} ]]; then
typeset edmap=${comp.map[${.sh.edchar}]}
if [[ ${edmap} != ${comp.eof} ]] || \
(( .sh.edcol || ( ! .sh.edcol && ${#.sh.edtext} ) )); then
.sh.edchar=${comp.ednum}${edmap}
comp.ednum=; return
elif [[ ${edmap} == ${comp.eof} ]] && (( ! .sh.edcol )); then
.sh.edchar=
comp.ednum=; return
fi
# fallthrough
# dtksh hack
elif [[ -n ${comp.map[${.sh.edchar}${comp.tilde}]} ]]; then
comp.edchar=${.sh.edchar}
.sh.edchar=; return
fi
.sh.edchar=${comp.ednum}${.sh.edchar}
comp.ednum=; return
}
trap comp_emacs KEYBD
function keybind {
typeset c= act=a
while getopts pu c; do act=${c}; done
shift OPTIND-1
case ${act} in
a)
while (( $# > 1 )); do
comp.map[$(printf "$1")]=$(printf "$2")
shift 2
done
;;
p)
for c in ${!comp.map[@]}; do
printf "%-8q => %q\n" "${c}" "${comp.map[${c}]}"
done
;;
u)
if (( $# > 0 )); then
for c; do
unset ${comp.map[$(printf "${c}")]}
done
else
unset comp.map
comp.map=( []= )
fi
;;
esac
}
keybind "\E[A" "\020" "\E[B" "\016" "\E[C" "\006" "\E[D" "\002"
keybind "\EOA" "\020" "\EOB" "\016" "\EOC" "\006" "\EOD" "\002"
keybind "\E[2~" " " "\E[3~" "\004" "\E[1~" "\001" "\E[4~" "\005"
keybind "\E[L" " " "\177" "\004" "\E[H" "\001" "\E[F" "\005"
keybind "\E[5~" "\Eb" "\E[6~" "\Ef" "\E[I" "\Eb" "\E[G" "\Ef"
keybind "\E[11~" "\001man " "\E[[A" "\001man " "\EOP" "\001man "
#keybind -p

Regards, Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%nospam@laposte.net.invalid
supprimer "%nospam% et ".invalid" pour me repondre.
remove "%nospam" and ".invalid" to answer me.

1 réponse

Avatar
bsh
Cyrille Lefevre wrote:
this should be rewritten using a state machine...


Oh no you shouldn't! Or perhaps I should instead say that,
having had much experience in writing state machines, they
are always problematic to debug and maintain. Their use is
almost always a case of having not used the appropriate
software tool, or justified by the primacy of execution speed.

function comp_emacs {


Thank you! I wish that I could show you my own keybind
example implementing generalized autocompletion, but it's
stuck on another machine's harddrive. It's almost as
complex, and (if I understand your code sufficiently) shows
a design variation that allows binding of (multiple) keystrokes
to the output of a user-specified function. I've attempted a
different algorithm to map character sequences utilizing
hashes with a base 64 numerical radix, instead of the usual
associative array technique, which has limitations, but is
very fast.

I wonder, was this code written in regard to the issue
described in:
https://mailman.research.att.com/pipermail/ast-users/2004q1/000457.html

Obviously, you have seen DGK's keybind example, but
for those in C.U.S. who wish a demonstration example,
see:
http://www.kornshell.com/examples/keybind

A question: have you done GUI coding on dtksh?

Once again, thanks for submitting your code to C.U.S.
I thought _someone_ should respond to this contribution,
but I wanted to resolve the problem of the above keybind
URL being temporarily unavailable, before I posted.

=Brian