blob: 93821bf0e2b319ca131e6c33593fe4f9581c60ce (
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
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
167
168
169
170
171
172
173
174
175
176
177
178
|
#!/bin/sh -e
# sdn-install: integrate sdn with the shell, binding to M-o
# vim: set sw=2 ts=2 sts=2 et tw=80:
zsh() {
cat <<'EOF'
sdn-navigate () {
# optionally: zle zle-line-finish
while eval "`SDN=1 sdn "$BUFFER" "$CURSOR"`"
do
[ -z "$cd" ] || cd "$cd"
[ -z "$insert" ] || LBUFFER="$LBUFFER$insert "
[ -z "$helper" ] && break
# Workaround for "zsh: suspended (tty output)" when invoking
# helpers after the terminal has been resized while running sdn
command true
/bin/sh -c "$helper" </dev/tty || break
done
# optionally: zle zle-line-init
zle reset-prompt
}
zle -N sdn-navigate
bindkey '\eo' sdn-navigate
EOF
}
bash() {
cat <<'EOF'
# We can't make the shell update the prompt on directory changes
# since there's no way to invoke `prompt_again()` from a `bind -x`
# handler but we can work around it by submitting a blank line.
sdn-cursor () {
if [[ $BASH_VERSINFO -lt 5 ]]
then echo -n "$SDN_L" | wc -m
else echo "$SDN_P"
fi
}
sdn-navigate () {
SDN_L=$READLINE_LINE SDN_P=$READLINE_POINT
READLINE_LINE=
while eval "`SDN=1 sdn "$SDN_L" "$(sdn-cursor)"`"
do
[[ -z $cd ]] || cd "$cd"
[[ -z $insert ]] || {
SDN_L="${SDN_L:0:$SDN_P}$insert ${SDN_L:$SDN_P}"
((SDN_P=SDN_P+${#insert}+1))
}
[[ -z $helper ]] && break
/bin/sh -c "$helper" || break
done
}
sdn-restore () {
READLINE_LINE=$SDN_L READLINE_POINT=$SDN_P
unset SDN_L SDN_P
}
# These never occur in UTF-8: \300-\301 \365-\367 \370-\377
bind -x '"\300": sdn-navigate'
bind -x '"\301": sdn-restore'
bind '"\eo": "\300\C-m\301"'
EOF
}
fish() {
cat <<'EOF'
function sdn-navigate
set --local IFS
set --local buffer (commandline)
set --local cursor (commandline --cursor)
while eval (SDN=1 sdn $buffer $cursor | \
string replace -ar '^(.*?)=' 'set --$1 ')
test -z "$cd" || cd "$cd"
test -z "$insert" || commandline --insert "$insert "
test -z "$helper" && break
/bin/sh -c "$helper" || break
end
commandline --function repaint
end
bind \eo sdn-navigate
EOF
}
elvish() {
cat <<'EOF'
edit:insert:binding[Alt-o] = {
use str
local:reesc = [posix]{ str:replace "'\\''" "''" $posix }
local:posix = [cmd]{ /bin/sh -c $cmd </dev/tty >/dev/tty 2>&1 }
# XXX: the -dot is not a stable API, and may hence break soon
# https://elv.sh/ref/builtin.html#do-not-use-functions-and-variables
local:buffer = $edit:current-command
local:cursor = (str:to-codepoints $buffer[0..$edit:-dot] | count)
local:ns = (ns [&])
while ?(eval ($reesc (E:SDN=1 sdn $buffer $cursor |
sed 's/^local //' | slurp)) &ns=$ns) {
if (not-eq $ns[cd] "") { cd $ns[cd] }
if (not-eq $ns[insert] "") { edit:insert-at-dot $ns[insert]" " }
if (or (eq $ns[helper] "") (not ?($posix $ns[helper]))) { break }
}
edit:redraw &full=$true
}
EOF
}
shell= path=
while getopts s:f:h opt
do
case $opt in
s) shell=$OPTARG;;
f) path=$OPTARG;;
*) echo "Usage: $0 [-s SHELL] [-f RCPATH | -]"; exit 2
esac
done
# Figure out the shell to integrate with
login=$(basename "$SHELL")
actual=$(ps -p $$ -o ppid= | xargs ps -o comm= -p)
if [ -z "$shell" ]
then
if [ "$login" != "$actual" ]
then
echo "Conflict between login ($login) and invoking ($actual) shell."
echo "Specify the shell with the -s option."
exit 1
fi
shell=$actual
fi
# Figure out the default initialisation file
case "$shell" in
zsh|bash)
rc=~/.${shell}rc;;
fish)
rc=${XDG_CONFIG_HOME:-$HOME/.config}/fish/conf.d/sdn.fish;;
elvish)
rc=~/.elvish/rc.elv;;
*)
echo "$shell is not supported."
exit 1
esac
# Just print out the snippet if requested
if [ "$path" = "-" ]
then
$shell
exit 0
fi
# Finally append to or update the appropriate file
b="# sdn-install begin"
e="# sdn-install end"
[ -z "$path" ] && path=$rc
mkdir -p "$(dirname "$path")"
touch "$path"
if ! grep -q "^$b" "$path" 2>/dev/null || ! grep -q "^$e" "$path" 2>/dev/null
then
printf "\n$b\n%s\n$e\n" "$($shell)" >> "$path"
echo "The snippet has been added to $path"
exit 0
fi
# POSIX-compliant in-place sed, trying to retain permissions here
temp=$path.sdn.new
cp -p -- "$path" "$temp"
sed < "$path" > "$temp" "/^$b/,/^$e/c\\
$b\\
$($shell | sed 's/\\/&&/g; s/$/\\/')
$e"
mv -- "$temp" "$path"
echo "The snippet in $path has been updated."
|