summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2024-08-15 22:29:55 -0400
committerAndrew Cady <d@jerkface.net>2024-08-15 22:29:55 -0400
commitccd87834aac9fc6ec851b7f49c56265f4bf8284a (patch)
tree1ee61a3871f71833b5a4d35ccfcdce8b45640350
parent09e63caacf9955af03536ff200f6580aafe68764 (diff)
replace "cat -v" with pure bash implementation
-rwxr-xr-xtwopane.bash105
1 files changed, 71 insertions, 34 deletions
diff --git a/twopane.bash b/twopane.bash
index bec96b9..39a6bfb 100755
--- a/twopane.bash
+++ b/twopane.bash
@@ -32,6 +32,7 @@ save_file()
32{ 32{
33 cat > "$TWOPANE"/"${1:?$0: Error: filename cannot be empty string}" 33 cat > "$TWOPANE"/"${1:?$0: Error: filename cannot be empty string}"
34} 34}
35
35save_screenrc() 36save_screenrc()
36{ 37{
37 save_file screenrc"${1:+.$1}" 38 save_file screenrc"${1:+.$1}"
@@ -156,7 +157,7 @@ disconnect()
156{ 157{
157 if [ $# = 2 ] 158 if [ $# = 2 ]
158 then 159 then
159 declare -n std0="$1" std1="$2" 160 declare -i -n std0="$1" std1="$2"
160 eval "exec $std0<&- $std1>&-" 161 eval "exec $std0<&- $std1>&-"
161 unset std0 std1 162 unset std0 std1
162 fi 163 fi
@@ -228,12 +229,12 @@ forward()
228 # the other pane's terminal. Uppercase $STDIN/$STDOUT are the 229 # the other pane's terminal. Uppercase $STDIN/$STDOUT are the
229 # real stdin/stdout of this function, connected to the lower 230 # real stdin/stdout of this function, connected to the lower
230 # pane's terminal. Socat here merges inputs from both sources. 231 # pane's terminal. Socat here merges inputs from both sources.
232 exec {STDIN}<&0 {STDOUT}>&1 {STDERR}>&2
231 233
232 # The input is put out raw back over the socket. The input is 234 # The input is put out raw back over the socket. The input is
233 # copied to stdout after being filtered (to display control 235 # copied to stdout after being filtered (to display control
234 # characters with carrot-encoding like '^[' etc). 236 # characters with carrot-encoding like '^[' etc).
235 exec {STDIN}<&0 {STDOUT}>&1 {STDERR}>&2 237 exec {TEE}> >(tee >(output_filter >&$STDOUT) >&$stdout)
236 exec {TEE}> >(tee >(output_filter | soft_cursor >&$STDOUT) >&$stdout)
237 stty=cfmakeraw,opost=1,onlcr=1 238 stty=cfmakeraw,opost=1,onlcr=1
238 { 239 {
239 socat FD:$STDIN,$stty!!STDOUT - <&$stdin >&$TEE 2>&$STDERR & 240 socat FD:$STDIN,$stty!!STDOUT - <&$stdin >&$TEE 2>&$STDERR &
@@ -304,34 +305,79 @@ focus()
304 305
305output_filter() 306output_filter()
306{ 307{
307 exec {OUTPUT_FILTER}> >(exec cat -v) 308 tokenize | colorize | soft_cursor
308 while read -r -N1 309}
310
311# if (show_nonprinting) {
312# while (true)
313# {
314# if (ch >= 32) {
315# if (ch < 127) *bpout++ = ch;
316# else if (ch == 127) {*bpout++ = '^'; *bpout++ = '?';}
317# else {
318# *bpout++ = 'M';
319# *bpout++ = '-';
320# if (ch >= 128 + 32) {
321# if (ch < 128 + 127) *bpout++ = ch - 128;
322# else {*bpout++ = '^'; *bpout++ = '?';}}
323# else {*bpout++ = '^'; *bpout++ = ch - 128 + 64;}}}
324# else if (ch == '\t' && !show_tabs) *bpout++ = '\t';
325# else if (ch == '\n') {newlines = -1; break;}
326# else {*bpout++ = '^'; *bpout++ = ch + 64;}
327# ch = *bpin++;}}
328
329chr()
330{
331 declare -i n="$*"
332 printf "\\$(printf %o "$n")"
333}
334
335colorize()
336{
337 while read -r
309 do 338 do
310 case "$REPLY" in 339 case "$REPLY" in
311 # Encode literal '^' as escape. This allows 340 \\[0-7][0-7][0-7] ) ;;
312 # a '^' in the output to be interpreted 341 * )
313 # unambiguously as a control sequence later 342 printf '%s\n' "$REPLY"
314 # downstream, where it will be displayed in
315 # bold.
316 '^' )
317 echo -n $'\e'
318 continue
319 ;;
320 $'\t' )
321 echo -n '^I'
322 continue 343 continue
323 ;; 344 ;;
324 $'\n' )
325 echo -n '^J'
326 continue
327 ;;
328 esac 345 esac
329 # Add unicode support to cat through bash primitives! 346 declare -i c=8#"${REPLY#?}"
347 if (( c > 128 + 127 ))
348 then
349 :
350 elif (( c > 128 + 32 ))
351 then
352 printf -v REPLY "M-$(chr c - 128)"
353 elif (( c > 127 ))
354 then
355 printf -v REPLY "M-^$(chr c - 128 + 64)"
356 elif (( c < 32 ))
357 then
358 printf -v REPLY "^$(chr c + 64)"
359 fi
360 printf $'\e[1m%s\e[m\n' "$REPLY"
361 done
362}
363
364tokenize()
365{
366 while read -r -N1
367 do
330 if [[ "$REPLY" =~ [[:print:]] ]] 368 if [[ "$REPLY" =~ [[:print:]] ]]
331 then 369 then
332 printf '%s' "$REPLY" 370 # Output one printable character per line. It may be a
371 # multibyte unicode character.
372 printf '%s\n' "$REPLY"
373 continue
333 else 374 else
334 printf '%s' "$REPLY" >&${OUTPUT_FILTER} 375 # If it is a non-printable, then we output a
376 # multi-character line. In this case we colorize it
377 # later so that it won't be confused with multiple
378 # printable characters.
379 printf '\\%.3o\n' "'$REPLY"
380 continue
335 fi 381 fi
336 done 382 done
337} 383}
@@ -342,16 +388,7 @@ soft_cursor()
342 REPLY= 388 REPLY=
343 while printf "$FMT" "$REPLY" $(( 101 + RANDOM % 7 )) 389 while printf "$FMT" "$REPLY" $(( 101 + RANDOM % 7 ))
344 do 390 do
345 read -r -N1 || break 391 read -r || break
346 case "$REPLY" in
347 '^' )
348 read -r -N1 || break
349 REPLY=$'\e[1m^'$REPLY$'\e[m'
350 ;;
351 $'\e' )
352 REPLY='^'
353 ;;
354 esac
355 done 392 done
356} 393}
357 394