Implemented reflow for plaintexts in the client itself
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user