Implemented reflow for plaintexts in the client itself

This commit is contained in:
Luxferre
2023-03-31 23:11:25 +03:00
parent 73b71d533f
commit 50da581db6
2 changed files with 40 additions and 3 deletions
+2 -1
View File
@@ -6,7 +6,7 @@
## What is it?
Bopher-NG is an ambitious attempt to write a full-featured Gopher client/browser in under 300 SLOC of pure Bash code. It started off as a really crude and unoptimized prototype developed right in [this blog post](https://chronovir.us/2023/03/28/I-wrote-a-browser/) for educational purposes.
Bopher-NG is an ambitious attempt to write a full-featured Gopher client/browser in under 350 SLOC of pure Bash code. It started off as a really crude and unoptimized prototype developed right in [this blog post](https://chronovir.us/2023/03/28/I-wrote-a-browser/) for educational purposes.
Improvements over the original Bopher from that post:
@@ -14,6 +14,7 @@ Improvements over the original Bopher from that post:
- smoother rendering and scrolling
- better edge-case stability (e.g. on macOS where using file descriptor 3 actually crashes everything)
- better Gophermap processing according to the RFC1436
- an actual text reflow when viewing plaintext documents with no hard wrapping
- multi-level navigation history (although you can only go back)
- status bar with currently opened resource name
- ability to accept `gopher://` URLs from the command line
+38 -2
View File
@@ -8,6 +8,7 @@
# - smoother rendering and scrolling
# - better edge-case stability
# - better Gophermap processing according to the RFC1436
# - an actual text reflow when viewing plaintext documents with no hard wrapping
# - multi-level navigation history (although you can only go back)
# - status bar with currently opened resource name
# - ability to accept gopher:// URLs from the command line
@@ -121,6 +122,38 @@ gmparse() { # args: line, curhost, curport
printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$action" "$desc" "$rhost" "$rport" "$sel" "$rtype" # output the final formatted line
}
phlow_lite() { # a single-parameter line reflow algorithm
local line="$1"
local TARGET_WIDTH="$2"
local reflowfmt="%-${TARGET_WIDTH}s\n"
local llen="${#line}" # get effective line length
if (( 0 == TARGET_WIDTH || llen < TARGET_WIDTH )); then # no need to run the logic for smaller lines or if TARGET_WIDTH is 0
printf "$reflowfmt" "$line"
return
fi
local lastws=0 # variable to track last whitespace
local cpos=0 # variable to track current position within the page line
local pagepos=0 # variable to track the position of new line start
local outbuf='' # temporary output buffer
local c='' # temporary character buffer
for ((i=0;i<llen;i++,cpos++)); do # start iterating over characters
if (( cpos >= TARGET_WIDTH )); then # we already exceeded the page width
(( lastws == 0 )) && lastws=$TARGET_WIDTH # no whitespace encountered here
printf "$reflowfmt" "${outbuf:0:$lastws}" # truncate the buffer
outbuf=''
pagepos=$(( pagepos + lastws ))
cpos=0
lastws=0
i=$pagepos # update current iteration index from the last valid whitespace
else # save the whitespace position if found
c="${line:i:1}" # get the current character
[[ "$c" == $'\x20' ]] && lastws="$cpos"
outbuf="${outbuf}${c}" # save the character itself
fi
done
[[ ! -z "$outbuf" ]] && printf "$reflowfmt" "$outbuf" # output the last unprocessed chunk
}
# convert AM line back to gopher:// URL
amtogopher() { # args: AM line
readarray -d $'\t' -t fields < <(printf '%s' "$1")
@@ -159,9 +192,13 @@ amclick() { # args: AM line[, forcedl], output: AM line(s)
gmparse "$line" "$rhost" "$rport"
done
elif [[ 'P' == "$action" ]]; then # plain text content (can be delimited with both CRLF or LF)
read -r TERMROWS TERMCOLS < <(stty size) # get current terminal size info
readarray -t lines -d $'\n' < <(gophetch "$rhost" "$rport" "$puresel" "$input") # split on LF
for line in "${lines[@]}"; do # iterate over every fetched line
printf 'E\t%s\n' "${line%%$'\r'}" # remove a trailing CR if it's there
readarray -t reflow_lines -d $'\n' < <(phlow_lite "${line%%$'\r'}" "$TERMCOLS") # remove a trailing CR if it's there
for rline in "${reflow_lines[@]}"; do
printf 'E\t%s\n' "$rline"
done
done
fi
}
@@ -309,7 +346,6 @@ readmouseinput() { # correctly read the remaining mouse input in semi-long mode
printf '%d %d %d %c\n' "$battr" "$mx" "$my" "$c"
}
# entry point code starts here
printf '%s' "$ALTBUFON$CLS" # enter ALTBUF mode and clear the screen