diff options
author | Andrew Cady <d@jerkface.net> | 2024-08-20 21:18:44 -0400 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2024-08-20 21:18:44 -0400 |
commit | 62440f41b97fbe85787bb015c9f52bf7e329b97c (patch) | |
tree | 5cbc3fcd0f7c4062d8def07b50bccfd37d316f0c /src/twopane.bash | |
parent | bd3d815e9c3757414b50225ba2c427ab8ff298e7 (diff) |
many changes basically working
the problem is that when the top pane sends
SIGUSR1 it does not quit the bottom in the
right order and an extra character ends up
being read from the terminal in the bottom
before a write error signals the end of
the connection. Our signal of termination
from the top is not reaching the right pid,
the pid of the socat inside of the
read_char needs to be reached by SIGUSR1,
instead of $$ the outermost shell,
where killing the job in job control should
be enough to break the connection to the
tty, it remains probably as long as socat
remains running, we need to kill the whole
process group of read-tty when killing the
main process or when it exits
Diffstat (limited to 'src/twopane.bash')
-rwxr-xr-x | src/twopane.bash | 295 |
1 files changed, 138 insertions, 157 deletions
diff --git a/src/twopane.bash b/src/twopane.bash index f496701..4c3ec62 100755 --- a/src/twopane.bash +++ b/src/twopane.bash | |||
@@ -6,6 +6,8 @@ set -f | |||
6 | set -o pipefail | 6 | set -o pipefail |
7 | shopt -s lastpipe | 7 | shopt -s lastpipe |
8 | 8 | ||
9 | . read_chars.bash | ||
10 | |||
9 | BOT_SIZE=8 | 11 | BOT_SIZE=8 |
10 | BOT_TITLE=input | 12 | BOT_TITLE=input |
11 | 13 | ||
@@ -59,6 +61,10 @@ msgminwait 0 | |||
59 | # More is needed. Xterm? | 61 | # More is needed. Xterm? |
60 | nonblock on | 62 | nonblock on |
61 | 63 | ||
64 | # Enable mouse focus | ||
65 | defmousetrack on | ||
66 | mousetrack on | ||
67 | |||
62 | caption string '%t' | 68 | caption string '%t' |
63 | layout new | 69 | layout new |
64 | split | 70 | split |
@@ -99,7 +105,7 @@ start_screen_pane() | |||
99 | TOP_TITLE="Command: ${*@Q}" | 105 | TOP_TITLE="Command: ${*@Q}" |
100 | screen -X focus top | 106 | screen -X focus top |
101 | screen -X screen -ln -t "$TOP_TITLE" 1 "$@" | 107 | screen -X screen -ln -t "$TOP_TITLE" 1 "$@" |
102 | screen -p "$pane" -X exec .!. sh -c 'exec socat UNIX-LISTEN:"$TWOPANE"/socket STDIN,cfmakeraw!!STDOUT' | 108 | screen -p "$pane" -X exec .!. bash -c 'exec -a top-tty-forward socat UNIX-LISTEN:"$TWOPANE"/socket STDIN,cfmakeraw!!STDOUT' |
103 | } | 109 | } |
104 | 110 | ||
105 | restart_screen_pane() | 111 | restart_screen_pane() |
@@ -108,50 +114,65 @@ restart_screen_pane() | |||
108 | start_screen_pane "$@" | 114 | start_screen_pane "$@" |
109 | } | 115 | } |
110 | 116 | ||
111 | # Start SOCAT if necessary. | 117 | connect_coproc() |
112 | # Connect the running SOCAT to file descriptors. | 118 | { |
113 | # Optionally assign the file descriptors to the specified variables. | 119 | declare -n coproc="$1" |
114 | # Optionally assign the socat PID to the specified variable. | 120 | shift |
115 | # | 121 | declare -g -n std1="${!coproc}_STDOUT" |
116 | # The copied file descriptors (unlike the original coprocess file | 122 | declare -g -n std0="${!coproc}_STDIN" |
117 | # descriptors, in ${SOCAT[0]} and ${SOCAT[1]}) can be passed to external | 123 | declare -g -n opid="${!coproc}_PID" |
118 | # processes (e.g.: other socat(1) instances) and used in subshells. | 124 | |
125 | if [ $# = 0 ] | ||
126 | then | ||
127 | set -- "${!coproc}" | ||
128 | fi | ||
129 | if ! [ "$opid" ] | ||
130 | then | ||
131 | local STDERR | ||
132 | { | ||
133 | coproc "${!coproc}" \ | ||
134 | { | ||
135 | "$@" | ||
136 | } 2>&$STDERR {STDERR}>&- | ||
137 | } {STDERR}>&2 2>/dev/null | ||
138 | i "${!opid}=$opid" | ||
139 | x disown | ||
140 | fi | ||
141 | # The copied file descriptors (unlike the original coprocess | ||
142 | # file descriptors, in ${coproc[0]} and ${coproc[1]}) can be | ||
143 | # passed to external processes (e.g.: socat(1) instances) and | ||
144 | # used in subshells. | ||
145 | { | ||
146 | exec {std0}<&0 {std1}>&1 | ||
147 | } <&${coproc[0]} >&${coproc[1]} | ||
148 | } | ||
149 | |||
150 | disconnect_coproc() | ||
151 | { | ||
152 | if [ $# = 1 ] | ||
153 | then | ||
154 | declare -n coproc="$1" | ||
155 | declare -g -n std1="${!coproc}_STDOUT" | ||
156 | declare -g -n std0="${!coproc}_STDIN" | ||
157 | declare -g -n pid="${!coproc}_PID" | ||
158 | [ "$std0" -a "$std1" ] || return | ||
159 | exec {std0}<&- {std1}>&- | ||
160 | unset std0 std1 | ||
161 | x kill "$pid" | ||
162 | x wait -f "$pid" | ||
163 | fi | ||
164 | } | ||
165 | |||
119 | connect() | 166 | connect() |
120 | { | 167 | { |
121 | case $# in | 168 | connect_coproc SOCAT |
122 | 3 ) | 169 | i "SOCAT_PID=$SOCAT_PID" |
123 | declare -n pid="$1" std0="$2" std1="$3" | ||
124 | shift 3 | ||
125 | ;; | ||
126 | 2 ) | ||
127 | local pid | ||
128 | declare -n std0="$1" std1="$2" | ||
129 | shift 2 | ||
130 | ;; | ||
131 | 0 ) | ||
132 | local pid std0 std1 | ||
133 | ;; | ||
134 | * ) | ||
135 | return 1 | ||
136 | ;; | ||
137 | esac | ||
138 | [ "${SOCAT[0]}" ] || socat_coproc | ||
139 | pid=${SOCAT_PID} | ||
140 | exec {std0}<&${SOCAT[0]} {std1}>&${SOCAT[1]} | ||
141 | } | 170 | } |
142 | 171 | ||
143 | socat_coproc() | 172 | disconnect() |
144 | { | 173 | { |
145 | set -m | 174 | i "SOCAT_STDIN=$SOCAT_STDIN SOCAT_STDOUT=$SOCAT_STDOUT SOCAT_PID=$SOCAT_PID" |
146 | local STDERR | 175 | x disconnect_coproc SOCAT |
147 | exec {STDERR}>&2 | ||
148 | { | ||
149 | coproc SOCAT { | ||
150 | socat - UNIX-CONNECT:"$TWOPANE"/socket,forever | ||
151 | kill -USR1 $$ | ||
152 | } 2>&$STDERR {STDERR}>&- | ||
153 | } 2>/dev/null | ||
154 | disown | ||
155 | } | 176 | } |
156 | 177 | ||
157 | sendc() | 178 | sendc() |
@@ -166,17 +187,6 @@ send() | |||
166 | printf '%s\n' "$*" >&${SOCAT[1]} | 187 | printf '%s\n' "$*" >&${SOCAT[1]} |
167 | } | 188 | } |
168 | 189 | ||
169 | disconnect() | ||
170 | { | ||
171 | if [ $# = 2 ] | ||
172 | then | ||
173 | declare -i -n std0="$1" std1="$2" | ||
174 | exec {std0}<&- {std1}>&- | ||
175 | unset std0 std1 | ||
176 | fi | ||
177 | wait -f "$SOCAT_PID" 2>/dev/null | ||
178 | } | ||
179 | |||
180 | restart() | 190 | restart() |
181 | { | 191 | { |
182 | start "$@" | 192 | start "$@" |
@@ -187,78 +197,11 @@ start() | |||
187 | foreground "$@" | 197 | foreground "$@" |
188 | } | 198 | } |
189 | 199 | ||
190 | foreground_loop() | 200 | check_tty_reader() |
191 | { | ||
192 | while true | ||
193 | do | ||
194 | start_screen_pane "$@" | ||
195 | connect stdin stdout | ||
196 | forward | ||
197 | disconnect stdin stdout | ||
198 | |||
199 | case "$TOP_EXIT" in | ||
200 | restart ) | ||
201 | continue ;; | ||
202 | quit ) | ||
203 | exit ;; | ||
204 | prompt | * ) | ||
205 | focus bottom | ||
206 | break | ||
207 | ;; | ||
208 | esac | ||
209 | done | ||
210 | } | ||
211 | |||
212 | forwarding() | ||
213 | { | ||
214 | [ "$FORWARD_PID" ] || return | ||
215 | FORWARD_JOBSPEC=$(jobs -sl | pid_to_jobspec "$FORWARD_PID") | ||
216 | [ "$FORWARD_JOBSPEC" ] | ||
217 | } | ||
218 | |||
219 | forward() | ||
220 | { | ||
221 | declare -g FORWARD_PID | ||
222 | if ! check_screen_pane | ||
223 | then | ||
224 | echo "$0: Warning: Nothing to forward. Starting anew." >&2 | ||
225 | background "$@" | ||
226 | elif forwarding | ||
227 | then | ||
228 | resume_forward | ||
229 | return | ||
230 | fi | ||
231 | |||
232 | focus top | ||
233 | old_stty=$(stty -g) | ||
234 | # Lowercase $stdin/$stdout are the SOCAT coprocess connected to | ||
235 | # the other pane's terminal. Uppercase $STDIN/$STDOUT are the | ||
236 | # real stdin/stdout of this function, connected to the lower | ||
237 | # pane's terminal. Socat here merges inputs from both sources. | ||
238 | exec {STDIN}<&0 {STDOUT}>&1 {STDERR}>&2 | ||
239 | |||
240 | # The input is put out raw back over the socket. The input is | ||
241 | # copied to stdout after being filtered (to display control | ||
242 | # characters with carrot-encoding like '^[' etc). | ||
243 | exec {TEE}> >(tee >(output_filter >&$STDOUT) >&$stdout) | ||
244 | stty=cfmakeraw,opost=1,onlcr=1 | ||
245 | { | ||
246 | socat FD:$STDIN,$stty!!STDOUT - <&$stdin >&$TEE 2>&$STDERR & | ||
247 | } 2>/dev/null | ||
248 | FORWARD_PID=$! | ||
249 | printf '%s\n' "#!/bin/bash" "kill -TSTP $!" "screen -X focus bottom" > "$TWOPANE"/unforward | ||
250 | chmod +x "$TWOPANE"/unforward | ||
251 | fg >/dev/null | ||
252 | stty "$old_stty" | ||
253 | focus bottom | ||
254 | echo | ||
255 | } | ||
256 | |||
257 | cfmakeraw() | ||
258 | { | 201 | { |
259 | cmd=(stty -ignbrk -brkint -parmrk -istrip -inlcr -igncr -icrnl | 202 | [ "$TTY_READER_PID" ] || return |
260 | -ixon -opost -echo -echonl -icanon -isig -iexten -parenb cs8) | 203 | TTY_READER_JOBSPEC=$(jobs -sl | pid_to_jobspec "$TTY_READER_PID") |
261 | "${cmd[@]}" "$@" | 204 | [ "$TTY_READER_JOBSPEC" ] |
262 | } | 205 | } |
263 | 206 | ||
264 | pid_to_jobspec() | 207 | pid_to_jobspec() |
@@ -274,59 +217,90 @@ pid_to_jobspec() | |||
274 | false | 217 | false |
275 | } | 218 | } |
276 | 219 | ||
277 | resume_forward() | 220 | tty_forward() |
278 | { | 221 | { |
279 | old_stty=$(stty -g) | 222 | declare -i -n pid="$1" |
280 | cfmakeraw opost onlcr | 223 | read-tty |
281 | focus top | 224 | x kill $pid 2>/dev/null |
282 | fg "$FORWARD_JOBSPEC" >/dev/null | ||
283 | stty "$old_stty" | ||
284 | focus bottom | ||
285 | } | 225 | } |
286 | 226 | ||
287 | tty_forward() | 227 | SOCAT() |
288 | { | 228 | { |
289 | read-tty | 229 | (exec -a bottom-tty-forward socat - UNIX-CONNECT:"$TWOPANE"/socket,forever) |
230 | x kill -USR1 $$ | ||
231 | } | ||
232 | |||
233 | echosend() | ||
234 | { | ||
235 | declare -n fd="$1" | ||
236 | declare -n pid="${!fd}_PID" | ||
237 | if ! [ "$fd" ] | ||
238 | then | ||
239 | connect_coproc SOCAT | ||
240 | i "SOCAT_PID=$SOCAT_PID" | ||
241 | exec {fd}> >( | ||
242 | (exec -a echosend socat - fd:${SOCAT_STDIN?e}!!-) | | ||
243 | tee >(output_filter) >&${SOCAT_STDOUT?e} | ||
244 | ) | ||
245 | pid=$! | ||
246 | fi | ||
247 | } | ||
248 | |||
249 | quiet_bg() | ||
250 | { | ||
251 | local STDERR | ||
252 | { | ||
253 | eval "$(printf '%q ' "$@") & 2>&\$STDERR {STDERR}>&-" | ||
254 | } {STDERR}>&2 2>/dev/null | ||
290 | } | 255 | } |
291 | 256 | ||
292 | background() | 257 | background() |
293 | { | 258 | { |
294 | old_stty=$(stty -g) | ||
295 | start_screen_pane "$@" | 259 | start_screen_pane "$@" |
296 | focus bottom | 260 | focus bottom |
297 | connect stdin stdout | 261 | echosend ECHOSEND |
298 | #stty tostop | ||
299 | exec {BOTTOM_PANE}> >(trap 'echo SIG >&2' SIGTTOU SIGTTIN SIGTSTP; output_filter) | ||
300 | BOTTOM_PANE_PID=$! | ||
301 | exec {BOTH_PANES}> >(trap 'echo TTOU >&2' SIGTTOU; ptee 1 $BOTTOM_PANE >&$stdout) | ||
302 | exec {NET_MERGE}> >(exec {STDIN}<&0; exec -a merge_reader socat FD:$STDIN!!STDOUT - <&$stdin >&$BOTH_PANES) | ||
303 | local STDERR | ||
304 | exec {STDERR}>&2 | ||
305 | { | 262 | { |
306 | exec 2>&$STDERR {STDERR}>&- | 263 | tty_forward ECHOSEND_PID & |
307 | tty_forward & | 264 | } >&$ECHOSEND |
308 | } >&$NET_MERGE 2>/dev/null | ||
309 | TTY_READER_PID=$! | 265 | TTY_READER_PID=$! |
310 | printf '%s\n' "#!/bin/bash" "kill -TSTP $TTY_READER_PID" "screen -X focus bottom" > "$TWOPANE"/unforward | 266 | printf '%s\n' \ |
267 | "#!/bin/bash" \ | ||
268 | "kill -TSTP $TTY_READER_PID" \ | ||
269 | "screen -X focus bottom" \ | ||
270 | > "$TWOPANE"/unforward | ||
311 | chmod +x "$TWOPANE"/unforward | 271 | chmod +x "$TWOPANE"/unforward |
312 | #"$TWOPANE"/unforward | ||
313 | } | 272 | } |
314 | 273 | ||
315 | foreground() | 274 | foreground() |
316 | { | 275 | { |
317 | if ! jobs -p %tty_forward >/dev/null 2>&1 | 276 | check_tty_reader || background |
318 | then | ||
319 | background | ||
320 | else | ||
321 | old_stty=$(stty -g) | ||
322 | fi | ||
323 | cfmakeraw opost onlcr | ||
324 | focus top | 277 | focus top |
325 | fg %tty_forward | 278 | fg %tty_forward >/dev/null |
326 | stty "$old_stty" | 279 | #disconnect |
327 | focus bottom | 280 | focus bottom |
328 | } | 281 | } |
329 | 282 | ||
283 | foreground_loop() | ||
284 | { | ||
285 | while true | ||
286 | do | ||
287 | foreground | ||
288 | x kill %tty_forward 2>/dev/null | ||
289 | case "$TOP_EXIT" in | ||
290 | restart ) | ||
291 | x kill -INT $TTY_READER_PID $ECHOSEND_PID | ||
292 | start_screen_pane "$@" | ||
293 | continue ;; | ||
294 | quit ) | ||
295 | exit ;; | ||
296 | prompt | * ) | ||
297 | x kill -INT $TTY_READER_PID $ECHOSEND_PID | ||
298 | break | ||
299 | ;; | ||
300 | esac | ||
301 | done | ||
302 | } | ||
303 | |||
330 | twopane() | 304 | twopane() |
331 | { | 305 | { |
332 | start "$@" | 306 | start "$@" |
@@ -378,7 +352,7 @@ colorize() | |||
378 | then | 352 | then |
379 | printf -v REPLY "^$(chr c + 64)" | 353 | printf -v REPLY "^$(chr c + 64)" |
380 | fi | 354 | fi |
381 | printf $'\e[1m%s\e[m\n' "$REPLY" | 355 | printf $'\e[106m%s\e[m\n' "$REPLY" |
382 | done | 356 | done |
383 | } | 357 | } |
384 | 358 | ||
@@ -411,15 +385,22 @@ soft_cursor() | |||
411 | while printf "$FMT" "$REPLY" "$color" | 385 | while printf "$FMT" "$REPLY" "$color" |
412 | do | 386 | do |
413 | read -r || break | 387 | read -r || break |
414 | let '++color <= 107' || color=101 | 388 | let '++color <= 105' || color=101 |
415 | done | 389 | done |
416 | } | 390 | } |
417 | 391 | ||
392 | resize() | ||
393 | { | ||
394 | screen -X resize "$@" | ||
395 | } | ||
396 | |||
418 | our_bashrc_main() | 397 | our_bashrc_main() |
419 | { | 398 | { |
399 | set -m | ||
420 | set -f | 400 | set -f |
421 | set -o pipefail | 401 | set -o pipefail |
422 | trap "screen -X quit" EXIT | 402 | #trap 'focus bottom; resize 90%; read -p "Exit> "; quit' EXIT |
403 | #trap 'echo USR1 >&2; focus bottom; x kill -INT %tty_forward $TTY_READER_PID $ECHOSEND_PID' USR1 | ||
423 | export PS1="$BOT_TITLE\\\$ " | 404 | export PS1="$BOT_TITLE\\\$ " |
424 | } | 405 | } |
425 | 406 | ||