From 8a8c5deaf3e1680ba91ae663496db18880bb7ba8 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Sat, 30 May 2020 16:00:12 -0500 Subject: [PATCH] Update typesetting of text/gemini --- bollux | 217 ++++++++++++++++++++++++++++++++-------------- typeset_gemini.sh | 172 ------------------------------------ 2 files changed, 152 insertions(+), 237 deletions(-) delete mode 100644 typeset_gemini.sh diff --git a/bollux b/bollux index 87c35fb..6f121b0 100755 --- a/bollux +++ b/bollux @@ -104,6 +104,7 @@ bollux_config() { log debug "Can't load config file '$BOLLUX_CONFIG'." fi + ## behavior : "${BOLLUX_DOWNDIR:=.}" # where to save downloads : "${BOLLUX_LOGLEVEL:=3}" # log level : "${BOLLUX_MAXREDIR:=5}" # max redirects @@ -112,6 +113,20 @@ bollux_config() { : "${BOLLUX_LESSKEY:=/tmp/bollux-lesskey}" # where to store binds : "${BOLLUX_PAGESRC:=/tmp/bollux-src}" # where to save the page source : "${BOLLUX_URL:=}" # start url + ## typesetting + : "${T_MARGIN:=4}" # left and right margin + : "${T_WIDTH:=0}" # width of the viewport -- 0 = get term width + # colors -- these will be wrapped in \e[ __ m + C_RESET='\e[0m' # reset + : "${C_SIGIL:=35}" # sigil (=>, #, ##, ###, *, ```) + : "${C_LINK_NUMBER:=1}" # link number + : "${C_LINK_TITLE:=4}" # link title + : "${C_LINK_URL:=36}" # link URL + : "${C_HEADER1:=1;4}" # header 1 formatting + : "${C_HEADER2:=1}" # header 2 formatting + : "${C_HEADER3:=3}" # header 3 formatting + : "${C_LIST:=0}" # list formatting + : "${C_PRE:=0}" # preformatted text formatting } prompt() { @@ -399,74 +414,146 @@ mklesskey() { } normalize_crlf() { - while read -r line; do - printf '%s\n' "${line//$'\r'?($'\n')/}" + while IFS= read -r; do + printf '%s\n' "${REPLY//$'\r'?($'\n')/}" done } typeset_gemini() { - gawk ' - BEGIN { - pre = 0 - margin = margin ? margin : 4 - txs = "" - lns = "\033[1m" - lus = "\033[36m" - lts = "\033[4m" - pfs = "" - h1s = "\033[1;4m" - h2s = "\033[1m" - h3s = "\033[3m" - lis = "" - res = "\033[0m" - ms = "\033[35m" - } - /```/ { - pre = ! pre - next - } - pre { - mark = "```" - fmt = pfs "%s" res - text = $0 - } - /^#/ { - match($0, /#+/) - mark = substr($0, RSTART, RLENGTH) - sub(/#+[[:space:]]*/, "", $0) - level = length(mark) - if (level == 1) { - fmt = h1s "%s" res - } else if (level == 2) { - fmt = h2s "%s" res - } else { - fmt = h3s "%s" res - } - } - /^=>/ { - mark = "=>" - sub(/=>[[:space:]]*/, "", $0) - desc = $1 - text = "" - for (w = 2; w <= NF; w++) { - text = text (text ? " " : "") $w - } - fmt = lns "[" (++ln) "]" res " " lts "%s" res "\t" lus "%s" res - } - /^\*[[:space:]]/ { - mark = "*" - sub(/\*[[:space:]]*/, "", $0) - fmt = lis "%s" res - } - { - mark = mark ? mark : mark - fmt = fmt ? fmt : "%s" - text = text ? text : $0 - desc = desc ? desc : "" - printf ms "%" (margin-1) "s " res fmt "\n", mark, text, desc - mark = fmt = text = desc = "" - } - ' + local pre=false + local ln=0 # link number + + if ((T_WIDTH == 0)); then + shopt -s checkwinsize + ( + : + : + ) # XXX this doesn't work!? + log d "LINES=$LINES; COLUMNS=$COLUMNS" + T_WIDTH=$COLUMNS + fi + + WIDTH=$((T_WIDTH - (T_MARGIN * 2))) + ((WIDTH < 0)) && WIDTH=80 # default if dumb + + log d "T_WIDTH=$T_WIDTH" + log d "WIDTH=$WIDTH" + + while IFS= read -r; do + case "$REPLY" in + '```') + if $pre; then + pre=false + else + pre=true + fi + continue + ;; + =\>*) + : $((ln += 1)) + gemini_link "$REPLY" $pre "$ln" + ;; + \#*) gemini_header "$REPLY" $pre ;; + \**) gemini_list "$REPLY" $pre ;; + *) gemini_text "$REPLY" $pre ;; + esac + done +} + +gemini_link() { + local re="^(=>)[[:blank:]]*([^[:blank:]]+)[[:blank:]]*(.*)" + local s t a l # sigil, text, annotation(url), line + if ! ${2-false} && [[ "$1" =~ $re ]]; then + s="${BASH_REMATCH[1]}" + a="${BASH_REMATCH[2]}" + t="${BASH_REMATCH[3]}" + if [[ -z "$t" ]]; then + t="$a" + a= + fi + + printf "\e[${C_SIGIL}m%-${T_MARGIN}s${C_RESET}" "$s" + printf -v l "\e[${C_LINK_NUMBER}m[%d]${C_RESET} \ + \e[${C_LINK_TITLE}m%s${C_RESET} \ + \e[${C_LINK_URL}m%s${C_RESET}\n" \ + "$3" "$t" "$a" + fold_line "$WIDTH" "$l" + else + gemini_pre "$1" + fi +} + +gemini_header() { + local re="^(#+)[[:blank:]]*(.*)" + local s t a l # sigil, text, annotation(lvl), line + if ! ${2-false} && [[ "$1" =~ $re ]]; then + s="${BASH_REMATCH[1]}" + a="${#BASH_REMATCH[1]}" + t="${BASH_REMATCH[2]}" + local hdrfmt + hdrfmt="$(eval echo "\$C_HEADER$a")" + + printf "\e[${C_SIGIL}m%$((T_MARGIN - 1))s ${C_RESET}" "$s" + printf -v l "\e[${hdrfmt}m%s${C_RESET}\n" "$t" + fold_line "$WIDTH" "$l" + else + gemini_pre "$1" + fi +} + +gemini_list() { + local re="^(\*)[[:blank:]]*(.*)" + local s t a l # sigil, text, annotation(n/a), line + if ! ${2-false} && [[ "$1" =~ $re ]]; then + s="${BASH_REMATCH[1]}" + t="${BASH_REMATCH[2]}" + + printf "\e[${C_SIGIL}m%-${T_MARGIN}s" "$s" + printf -v l "\e[${C_LIST}m%s${C_RESET}\n" "$t" + fold_line "$WIDTH" "$l" + else + gemini_pre "$1" + fi +} + +gemini_text() { + if ! ${2-false}; then + printf "%${T_MARGIN}s" ' ' + fold_line "$WIDTH" "$1" + else + gemini_pre "$1" + fi +} + +gemini_pre() { + printf "\e[${C_SIGIL}m%-${T_MARGIN}s" '```' + printf "\e[${C_PRE}m%s${C_RESET}\n" "$1" +} + +fold_line() { # fold_line WIDTH TEXT + local width="$1" + local margin="${2%%[![:space:]]*}" + if [[ "$margin" ]]; then + margin="${#margin}" + else + margin="$T_MARGIN" + fi + local ll=0 wl plain + # shellcheck disable=2086 + set -- $2 # TODO: is this the best way? + + for word; do + plain="${word//$'\x1b'\[*([0-9;])m/}" + wl=$((${#plain} + 1)) + if (((ll + wl) >= width)); then + printf "\n%${margin}s" ' ' + ll=$wl + else + ll=$((ll + wl)) + fi + printf '%s ' "$word" + done + printf '\n' } handle_keypress() { @@ -500,7 +587,7 @@ select_url() { } extract_links() { - gawk -F$'\t' ' + gawk ' /^=>/ { sub(/=>[[:space:]]*/,"") if ($2) diff --git a/typeset_gemini.sh b/typeset_gemini.sh deleted file mode 100644 index 2f9abbc..0000000 --- a/typeset_gemini.sh +++ /dev/null @@ -1,172 +0,0 @@ -typeset_gemini() { - local pre=false - local ln=0 - - while read -r line; do - case "$line" in - '```') - flip pre - continue - ;; - =\>*) - : $((ln += 1)) - gemini_link "$line" $pre - ;; - \#*) gemini_header "$line" $pre ;; - \**) gemini_list "$line" $pre ;; - *) gemini_text "$line" $pre ;; - esac - done -} - -gemini_link() { - local re="^(=>)[[:blank:]]*([^[:blank:]]+)[[:blank:]]*(.*)" - local s t a # sigil, text, annotation(url) - if ! ${2-false} && [[ "$1" =~ $re ]]; then - s="${BASH_REMATCH[1]}" - t="${BASH_REMATCH[3]}" - a="${BASH_REMATCH[2]}" - - printf "$C_SIGIL%-${MARGIN}s" "$s" - fold_line "$WIDTH" "$(printf "$C_LINK_TITLE%s $C_LINK_URL%s$C_RESET\n" \ - "$t" "$a")" - else - gemini_pre "$1" - fi -} - -gemini_header() { - local re="^(#+)[[:blank:]]*(.*)" - local s t a # sigil, text, annotation(lvl) - if ! ${2-false} && [[ "$1" =~ $re ]]; then - s="${BASH_REMATCH[1]}" - a="${#BASH_REMATCH[1]}" - t="${BASH_REMATCH[2]}" - - local hdrfmt - hdrfmt="$(eval echo "\$C_HEADER$a")" - printf "$C_SIGIL%-${MARGIN}s$hdrfmt%s$C_RESET\n" \ - "$s" "$(fold_line "$WIDTH" "$t")" - else - gemini_pre "$1" - fi -} - -gemini_list() { - local re="^(\*)[[:blank:]]*(.*)" - local s t a # sigil, text, annotation(n/a) - if ! ${2-false} && [[ "$1" =~ $re ]]; then - s="${BASH_REMATCH[1]}" - t="${BASH_REMATCH[2]}" - - printf "$C_SIGIL%-${MARGIN}s$C_LIST%s$C_RESET\n" \ - "$s" "$(fold_line "$WIDTH" "$t")" - else - gemini_pre "$1" - fi -} - -gemini_text() { - printf "%${MARGIN}s" ' ' - if ! ${2-false}; then - fold_line "$WIDTH" "$1" - else - gemini_pre "$1" - fi -} - -gemini_pre() { - printf "%${MARGIN}s%s" ' ' "$1" -} - -flip() { # flip NAME - [[ "${!1}" == true || "${!1}" == false ]] || return 1 - - if "${!1}"; then - eval "$1=false" - else - eval "$1=true" - fi -} - -fold_line() { # fold_line WIDTH TEXT - local width="$1" - local ll=0 wl plain - # shellcheck disable=2086 - # TODO: determine if this is the best way to do it - set -- $2 - - for word; do - plain="${word//$'\x1b'\[*([0-9;])m/}" - wl=$((${#plain} + 1)) - if (((ll + wl) >= width)); then - printf "\n%${MARGIN}s" ' ' - ll=$wl - else - ll=$((ll + wl)) - fi - printf '%s ' "$word" - done - printf '\n' -} - -# just here for reference -strip() { # strip control sequences - # https://stackoverflow.com/a/55872518 - shopt -s extglob - while IFS='' read -r x; do - # remove colors - echo "${x//$'\x1b'\[*([0-9;])m/}" - done -} - -test() { - MARGIN=4 - WIDTH=60 - #shopt -s checkwinsize; (:;:) - #WIDTH="$((COLUMNS - (MARGIN*2)))" - C_LINK_TITLE=$'\e[34m' - C_LINK_URL=$'\e[31m' - C_RESET=$'\e[0m' - typeset_gemini <<-'EOF' - # Project Gemini - - ## Overview - - Gemini is a new internet protocol which: - - * Is heavier than gopher - * Is lighter than the web - * Will not replace either - * Strives for maximum power to weight ratio - * Takes user privacy very seriously - - ## Resources - - => docs/ Gemini documentation - => software/ Gemini software - => servers/ Known Gemini servers - => https://lists.orbitalfox.eu/listinfo/gemini Gemini mailing list - => gemini://gemini.conman.org/test/torture/ Gemini client torture test - - ## Web proxies - - => https://portal.mozz.us/?url=gemini%3A%2F%2Fgemini.circumlunar.space%2F&fmt=fixed Gemini-to-web proxy service - => https://proxy.vulpes.one/gemini/gemini.circumlunar.space Another Gemini-to-web proxy service - - ## Search engines - - => gemini://gus.guru/ Gemini Universal Search engine - => gemini://houston.coder.town Houston search engine - - ## Geminispace aggregators (experimental!) - - => capcom/ CAPCOM - => gemini://rawtext.club:1965/~sloum/spacewalk.gmi Spacewalk - - ## Free Gemini hosting - - => users/ Users with Gemini content on this server - EOF -} -test -- 2.20.1