about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCase Duckworth2020-05-30 16:00:12 -0500
committerCase Duckworth2020-05-30 16:00:12 -0500
commit8a8c5deaf3e1680ba91ae663496db18880bb7ba8 (patch)
tree0f796078f2c57792f47a2e976c921392b0774239
parentArchive (diff)
downloadbollux-8a8c5deaf3e1680ba91ae663496db18880bb7ba8.tar.gz
bollux-8a8c5deaf3e1680ba91ae663496db18880bb7ba8.zip
Update typesetting of text/gemini
-rwxr-xr-xbollux217
-rw-r--r--typeset_gemini.sh172
2 files changed, 152 insertions, 237 deletions
diff --git a/bollux b/bollux index 87c35fb..6f121b0 100755 --- a/bollux +++ b/bollux
@@ -104,6 +104,7 @@ bollux_config() {
104 log debug "Can't load config file '$BOLLUX_CONFIG'." 104 log debug "Can't load config file '$BOLLUX_CONFIG'."
105 fi 105 fi
106 106
107 ## behavior
107 : "${BOLLUX_DOWNDIR:=.}" # where to save downloads 108 : "${BOLLUX_DOWNDIR:=.}" # where to save downloads
108 : "${BOLLUX_LOGLEVEL:=3}" # log level 109 : "${BOLLUX_LOGLEVEL:=3}" # log level
109 : "${BOLLUX_MAXREDIR:=5}" # max redirects 110 : "${BOLLUX_MAXREDIR:=5}" # max redirects
@@ -112,6 +113,20 @@ bollux_config() {
112 : "${BOLLUX_LESSKEY:=/tmp/bollux-lesskey}" # where to store binds 113 : "${BOLLUX_LESSKEY:=/tmp/bollux-lesskey}" # where to store binds
113 : "${BOLLUX_PAGESRC:=/tmp/bollux-src}" # where to save the page source 114 : "${BOLLUX_PAGESRC:=/tmp/bollux-src}" # where to save the page source
114 : "${BOLLUX_URL:=}" # start url 115 : "${BOLLUX_URL:=}" # start url
116 ## typesetting
117 : "${T_MARGIN:=4}" # left and right margin
118 : "${T_WIDTH:=0}" # width of the viewport -- 0 = get term width
119 # colors -- these will be wrapped in \e[ __ m
120 C_RESET='\e[0m' # reset
121 : "${C_SIGIL:=35}" # sigil (=>, #, ##, ###, *, ```)
122 : "${C_LINK_NUMBER:=1}" # link number
123 : "${C_LINK_TITLE:=4}" # link title
124 : "${C_LINK_URL:=36}" # link URL
125 : "${C_HEADER1:=1;4}" # header 1 formatting
126 : "${C_HEADER2:=1}" # header 2 formatting
127 : "${C_HEADER3:=3}" # header 3 formatting
128 : "${C_LIST:=0}" # list formatting
129 : "${C_PRE:=0}" # preformatted text formatting
115} 130}
116 131
117prompt() { 132prompt() {
@@ -399,74 +414,146 @@ mklesskey() {
399} 414}
400 415
401normalize_crlf() { 416normalize_crlf() {
402 while read -r line; do 417 while IFS= read -r; do
403 printf '%s\n' "${line//$'\r'?($'\n')/}" 418 printf '%s\n' "${REPLY//$'\r'?($'\n')/}"
404 done 419 done
405} 420}
406 421
407typeset_gemini() { 422typeset_gemini() {
408 gawk ' 423 local pre=false
409 BEGIN { 424 local ln=0 # link number
410 pre = 0 425
411 margin = margin ? margin : 4 426 if ((T_WIDTH == 0)); then
412 txs = "" 427 shopt -s checkwinsize
413 lns = "\033[1m" 428 (
414 lus = "\033[36m" 429 :
415 lts = "\033[4m" 430 :
416 pfs = "" 431 ) # XXX this doesn't work!?
417 h1s = "\033[1;4m" 432 log d "LINES=$LINES; COLUMNS=$COLUMNS"
418 h2s = "\033[1m" 433 T_WIDTH=$COLUMNS
419 h3s = "\033[3m" 434 fi
420 lis = "" 435
421 res = "\033[0m" 436 WIDTH=$((T_WIDTH - (T_MARGIN * 2)))
422 ms = "\033[35m" 437 ((WIDTH < 0)) && WIDTH=80 # default if dumb
423 } 438
424 /```/ { 439 log d "T_WIDTH=$T_WIDTH"
425 pre = ! pre 440 log d "WIDTH=$WIDTH"
426 next 441
427 } 442 while IFS= read -r; do
428 pre { 443 case "$REPLY" in
429 mark = "```" 444 '```')
430 fmt = pfs "%s" res 445 if $pre; then
431 text = $0 446 pre=false
432 } 447 else
433 /^#/ { 448 pre=true
434 match($0, /#+/) 449 fi
435 mark = substr($0, RSTART, RLENGTH) 450 continue
436 sub(/#+[[:space:]]*/, "", $0) 451 ;;
437 level = length(mark) 452 =\>*)
438 if (level == 1) { 453 : $((ln += 1))
439 fmt = h1s "%s" res 454 gemini_link "$REPLY" $pre "$ln"
440 } else if (level == 2) { 455 ;;
441 fmt = h2s "%s" res 456 \#*) gemini_header "$REPLY" $pre ;;
442 } else { 457 \**) gemini_list "$REPLY" $pre ;;
443 fmt = h3s "%s" res 458 *) gemini_text "$REPLY" $pre ;;
444 } 459 esac
445 } 460 done
446 /^=>/ { 461}
447 mark = "=>" 462
448 sub(/=>[[:space:]]*/, "", $0) 463gemini_link() {
449 desc = $1 464 local re="^(=>)[[:blank:]]*([^[:blank:]]+)[[:blank:]]*(.*)"
450 text = "" 465 local s t a l # sigil, text, annotation(url), line
451 for (w = 2; w <= NF; w++) { 466 if ! ${2-false} && [[ "$1" =~ $re ]]; then
452 text = text (text ? " " : "") $w 467 s="${BASH_REMATCH[1]}"
453 } 468 a="${BASH_REMATCH[2]}"
454 fmt = lns "[" (++ln) "]" res " " lts "%s" res "\t" lus "%s" res 469 t="${BASH_REMATCH[3]}"
455 } 470 if [[ -z "$t" ]]; then
456 /^\*[[:space:]]/ { 471 t="$a"
457 mark = "*" 472 a=
458 sub(/\*[[:space:]]*/, "", $0) 473 fi
459 fmt = lis "%s" res 474
460 } 475 printf "\e[${C_SIGIL}m%-${T_MARGIN}s${C_RESET}" "$s"
461 { 476 printf -v l "\e[${C_LINK_NUMBER}m[%d]${C_RESET} \
462 mark = mark ? mark : mark 477 \e[${C_LINK_TITLE}m%s${C_RESET} \
463 fmt = fmt ? fmt : "%s" 478 \e[${C_LINK_URL}m%s${C_RESET}\n" \
464 text = text ? text : $0 479 "$3" "$t" "$a"
465 desc = desc ? desc : "" 480 fold_line "$WIDTH" "$l"
466 printf ms "%" (margin-1) "s " res fmt "\n", mark, text, desc 481 else
467 mark = fmt = text = desc = "" 482 gemini_pre "$1"
468 } 483 fi
469 ' 484}
485
486gemini_header() {
487 local re="^(#+)[[:blank:]]*(.*)"
488 local s t a l # sigil, text, annotation(lvl), line
489 if ! ${2-false} && [[ "$1" =~ $re ]]; then
490 s="${BASH_REMATCH[1]}"
491 a="${#BASH_REMATCH[1]}"
492 t="${BASH_REMATCH[2]}"
493 local hdrfmt
494 hdrfmt="$(eval echo "\$C_HEADER$a")"
495
496 printf "\e[${C_SIGIL}m%$((T_MARGIN - 1))s ${C_RESET}" "$s"
497 printf -v l "\e[${hdrfmt}m%s${C_RESET}\n" "$t"
498 fold_line "$WIDTH" "$l"
499 else
500 gemini_pre "$1"
501 fi
502}
503
504gemini_list() {
505 local re="^(\*)[[:blank:]]*(.*)"
506 local s t a l # sigil, text, annotation(n/a), line
507 if ! ${2-false} && [[ "$1" =~ $re ]]; then
508 s="${BASH_REMATCH[1]}"
509 t="${BASH_REMATCH[2]}"
510
511 printf "\e[${C_SIGIL}m%-${T_MARGIN}s" "$s"
512 printf -v l "\e[${C_LIST}m%s${C_RESET}\n" "$t"
513 fold_line "$WIDTH" "$l"
514 else
515 gemini_pre "$1"
516 fi
517}
518
519gemini_text() {
520 if ! ${2-false}; then
521 printf "%${T_MARGIN}s" ' '
522 fold_line "$WIDTH" "$1"
523 else
524 gemini_pre "$1"
525 fi
526}
527
528gemini_pre() {
529 printf "\e[${C_SIGIL}m%-${T_MARGIN}s" '```'
530 printf "\e[${C_PRE}m%s${C_RESET}\n" "$1"
531}
532
533fold_line() { # fold_line WIDTH TEXT
534 local width="$1"
535 local margin="${2%%[![:space:]]*}"
536 if [[ "$margin" ]]; then
537 margin="${#margin}"
538 else
539 margin="$T_MARGIN"
540 fi
541 local ll=0 wl plain
542 # shellcheck disable=2086
543 set -- $2 # TODO: is this the best way?
544
545 for word; do
546 plain="${word//$'\x1b'\[*([0-9;])m/}"
547 wl=$((${#plain} + 1))
548 if (((ll + wl) >= width)); then
549 printf "\n%${margin}s" ' '
550 ll=$wl
551 else
552 ll=$((ll + wl))
553 fi
554 printf '%s ' "$word"
555 done
556 printf '\n'
470} 557}
471 558
472handle_keypress() { 559handle_keypress() {
@@ -500,7 +587,7 @@ select_url() {
500} 587}
501 588
502extract_links() { 589extract_links() {
503 gawk -F$'\t' ' 590 gawk '
504 /^=>/ { 591 /^=>/ {
505 sub(/=>[[:space:]]*/,"") 592 sub(/=>[[:space:]]*/,"")
506 if ($2) 593 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 @@
1typeset_gemini() {
2 local pre=false
3 local ln=0
4
5 while read -r line; do
6 case "$line" in
7 '```')
8 flip pre
9 continue
10 ;;
11 =\>*)
12 : $((ln += 1))
13 gemini_link "$line" $pre
14 ;;
15 \#*) gemini_header "$line" $pre ;;
16 \**) gemini_list "$line" $pre ;;
17 *) gemini_text "$line" $pre ;;
18 esac
19 done
20}
21
22gemini_link() {
23 local re="^(=>)[[:blank:]]*([^[:blank:]]+)[[:blank:]]*(.*)"
24 local s t a # sigil, text, annotation(url)
25 if ! ${2-false} && [[ "$1" =~ $re ]]; then
26 s="${BASH_REMATCH[1]}"
27 t="${BASH_REMATCH[3]}"
28 a="${BASH_REMATCH[2]}"
29
30 printf "$C_SIGIL%-${MARGIN}s" "$s"
31 fold_line "$WIDTH" "$(printf "$C_LINK_TITLE%s $C_LINK_URL%s$C_RESET\n" \
32 "$t" "$a")"
33 else
34 gemini_pre "$1"
35 fi
36}
37
38gemini_header() {
39 local re="^(#+)[[:blank:]]*(.*)"
40 local s t a # sigil, text, annotation(lvl)
41 if ! ${2-false} && [[ "$1" =~ $re ]]; then
42 s="${BASH_REMATCH[1]}"
43 a="${#BASH_REMATCH[1]}"
44 t="${BASH_REMATCH[2]}"
45
46 local hdrfmt
47 hdrfmt="$(eval echo "\$C_HEADER$a")"
48 printf "$C_SIGIL%-${MARGIN}s$hdrfmt%s$C_RESET\n" \
49 "$s" "$(fold_line "$WIDTH" "$t")"
50 else
51 gemini_pre "$1"
52 fi
53}
54
55gemini_list() {
56 local re="^(\*)[[:blank:]]*(.*)"
57 local s t a # sigil, text, annotation(n/a)
58 if ! ${2-false} && [[ "$1" =~ $re ]]; then
59 s="${BASH_REMATCH[1]}"
60 t="${BASH_REMATCH[2]}"
61
62 printf "$C_SIGIL%-${MARGIN}s$C_LIST%s$C_RESET\n" \
63 "$s" "$(fold_line "$WIDTH" "$t")"
64 else
65 gemini_pre "$1"
66 fi
67}
68
69gemini_text() {
70 printf "%${MARGIN}s" ' '
71 if ! ${2-false}; then
72 fold_line "$WIDTH" "$1"
73 else
74 gemini_pre "$1"
75 fi
76}
77
78gemini_pre() {
79 printf "%${MARGIN}s%s" ' ' "$1"
80}
81
82flip() { # flip NAME
83 [[ "${!1}" == true || "${!1}" == false ]] || return 1
84
85 if "${!1}"; then
86 eval "$1=false"
87 else
88 eval "$1=true"
89 fi
90}
91
92fold_line() { # fold_line WIDTH TEXT
93 local width="$1"
94 local ll=0 wl plain
95 # shellcheck disable=2086
96 # TODO: determine if this is the best way to do it
97 set -- $2
98
99 for word; do
100 plain="${word//$'\x1b'\[*([0-9;])m/}"
101 wl=$((${#plain} + 1))
102 if (((ll + wl) >= width)); then
103 printf "\n%${MARGIN}s" ' '
104 ll=$wl
105 else
106 ll=$((ll + wl))
107 fi
108 printf '%s ' "$word"
109 done
110 printf '\n'
111}
112
113# just here for reference
114strip() { # strip control sequences
115 # https://stackoverflow.com/a/55872518
116 shopt -s extglob
117 while IFS='' read -r x; do
118 # remove colors
119 echo "${x//$'\x1b'\[*([0-9;])m/}"
120 done
121}
122
123test() {
124 MARGIN=4
125 WIDTH=60
126 #shopt -s checkwinsize; (:;:)
127 #WIDTH="$((COLUMNS - (MARGIN*2)))"
128 C_LINK_TITLE=$'\e[34m'
129 C_LINK_URL=$'\e[31m'
130 C_RESET=$'\e[0m'
131 typeset_gemini <<-'EOF'
132 # Project Gemini
133
134 ## Overview
135
136 Gemini is a new internet protocol which:
137
138 * Is heavier than gopher
139 * Is lighter than the web
140 * Will not replace either
141 * Strives for maximum power to weight ratio
142 * Takes user privacy very seriously
143
144 ## Resources
145
146 => docs/ Gemini documentation
147 => software/ Gemini software
148 => servers/ Known Gemini servers
149 => https://lists.orbitalfox.eu/listinfo/gemini Gemini mailing list
150 => gemini://gemini.conman.org/test/torture/ Gemini client torture test
151
152 ## Web proxies
153
154 => https://portal.mozz.us/?url=gemini%3A%2F%2Fgemini.circumlunar.space%2F&fmt=fixed Gemini-to-web proxy service
155 => https://proxy.vulpes.one/gemini/gemini.circumlunar.space Another Gemini-to-web proxy service
156
157 ## Search engines
158
159 => gemini://gus.guru/ Gemini Universal Search engine
160 => gemini://houston.coder.town Houston search engine
161
162 ## Geminispace aggregators (experimental!)
163
164 => capcom/ CAPCOM
165 => gemini://rawtext.club:1965/~sloum/spacewalk.gmi Spacewalk
166
167 ## Free Gemini hosting
168
169 => users/ Users with Gemini content on this server
170 EOF
171}
172test