From 69a85dacdce16b4b4efbb10e846201c341c69587 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Tue, 16 Dec 2025 17:47:12 +0100 Subject: [PATCH] Add bilingual Latin-German side-by-side display support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update TSV format to 8 columns: BookName, BookAbbr, BookNum, Chapter, Verse, Latin, German, FootnoteText - Add printverse_bilingual() function for side-by-side Latin/German display - Add language filter flags -g (German only) and -L (Latin only) - Add to_superscript_num() function to convert footnote numbers to Unicode superscripts - Update processline() to detect and route bilingual verses, German-only, Latin-only, introductions, and footnotes - Footnotes now display with superscript numbers (¹²³⁴⁵⁶⁷⁸⁹⁰) - Default mode shows Latin and German in two columns with | separator - Introductions and footnotes display full-width New flags: -g show only German (no Latin) -L show only Latin (no German) --- allioli.awk | 144 +++++++++++++++++++++++++++++++++++++++++++++++----- allioli.sh | 8 +++ 2 files changed, 139 insertions(+), 13 deletions(-) diff --git a/allioli.awk b/allioli.awk index 0c3f536..e92e2a2 100644 --- a/allioli.awk +++ b/allioli.awk @@ -177,6 +177,74 @@ function printverse(verse, word_count, characters_printed) { printf("\n") } +function printverse_bilingual(latin, german, latin_words, german_words, latin_count, german_count, latin_idx, german_idx, col_width, latin_chars, german_chars, latin_line, german_line) { + # Remove superscript footnote numbers if footnotes are disabled + if (ENVIRON["ALLIOLI_NOFOOTNOTES"] != "" && ENVIRON["ALLIOLI_NOFOOTNOTES"] != "0") { + gsub(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/, "", german) + } + + if (ENVIRON["ALLIOLI_NOLINEWRAP"] != "" && ENVIRON["ALLIOLI_NOLINEWRAP"] != "0") { + printf("%s | %s\n", latin, german) + return + } + + # Column width is half the total width, minus separators + col_width = int((MAX_WIDTH - 10) / 2) + + # Split into words + latin_count = split(latin, latin_words, " ") + german_count = split(german, german_words, " ") + + latin_idx = 1 + german_idx = 1 + latin_chars = 0 + german_chars = 0 + latin_line = "" + german_line = "" + + # Print both columns line by line + while (latin_idx <= latin_count || german_idx <= german_count) { + # Build Latin line + while (latin_idx <= latin_count) { + word = latin_words[latin_idx] + if (latin_chars + length(word) + (latin_chars > 0 ? 1 : 0) > col_width) { + break + } + if (latin_chars > 0) { + latin_line = latin_line " " + latin_chars++ + } + latin_line = latin_line word + latin_chars += length(word) + latin_idx++ + } + + # Build German line + while (german_idx <= german_count) { + word = german_words[german_idx] + if (german_chars + length(word) + (german_chars > 0 ? 1 : 0) > col_width) { + break + } + if (german_chars > 0) { + german_line = german_line " " + german_chars++ + } + german_line = german_line word + german_chars += length(word) + german_idx++ + } + + # Print the line with padding + printf("\t%-*s | %s\n", col_width, latin_line, german_line) + + # Reset for next line + latin_line = "" + german_line = "" + latin_chars = 0 + german_chars = 0 + } +} + function printintroductionpar(verse, word_count, characters_printed) { if (ENVIRON["ALLIOLI_NOLINEWRAP"] != "" && ENVIRON["ALLIOLI_NOLINEWRAP"] != "0") { printf("%s\n", verse) @@ -201,13 +269,37 @@ function printintroductionpar(verse, word_count, characters_printed) { printed_intrudction=1 } -function printfootnote(footnote_num, footnote, word_count, characters_printed) { +function to_superscript_num(num) { + # Convert a number to Unicode superscript + result = "" + len = length(num) + for (i = 1; i <= len; i++) { + digit = substr(num, i, 1) + if (digit == "0") result = result "⁰" + else if (digit == "1") result = result "¹" + else if (digit == "2") result = result "²" + else if (digit == "3") result = result "³" + else if (digit == "4") result = result "⁴" + else if (digit == "5") result = result "⁵" + else if (digit == "6") result = result "⁶" + else if (digit == "7") result = result "⁷" + else if (digit == "8") result = result "⁸" + else if (digit == "9") result = result "⁹" + else result = result digit + } + return result +} + +function printfootnote(footnote_num, footnote, word_count, characters_printed, sup_num) { if ( ENVIRON["ALLIOLI_NOFOOTNOTES"] != "" && ENVIRON["ALLIOLI_NOFOOTNOTES"] != "0"){ return } else{ + # Convert footnote number to superscript + sup_num = to_superscript_num(footnote_num) + if (ENVIRON["ALLIOLI_NOLINEWRAP"] != "" && ENVIRON["ALLIOLI_NOLINEWRAP"] != "0") { - printf("\t\t%s%s\n", footnote_num, footnote) + printf("\t\t%s%s\n", sup_num, footnote) return } @@ -215,12 +307,12 @@ function printfootnote(footnote_num, footnote, word_count, characters_printed for ( i=1; i <= MAX_WIDTH - length(footnote) - 1; i++){ printf(" ") } - printf("%s%s", footnote_num, footnote) + printf("%s%s", sup_num, footnote) } else{ word_count = split(footnote, words, " ") - printf("\n\t\t%s", footnote_num) - characters_printed=17 #account for indents at beginning of each multiline footnote (2 tabs + footnote_num) + printf("\n\t\t%s", sup_num) + characters_printed=17 #account for indents at beginning of each multiline footnote (2 tabs + sup_num) for (i = 1; i <= word_count; i++) { if (characters_printed + length(words[i]) + (characters_printed > 0 ? 1 : 0) > MAX_WIDTH - 8 ) { printf("\n\t") @@ -248,17 +340,43 @@ function processline() { print $1 last_book_printed = $2 } - # Check if this is a footnote (column 6 is a number) - if ($6 ~ /^[0-9]+$/) { - printfootnote($6, $7) + + # Determine line type based on column structure + # Column 6 = Latin, Column 7 = German or footnote number, Column 8 = footnote text + + # Check if this is a footnote (column 6 empty, column 7 is a number, column 8 has text) + if ($6 == "" && $7 ~ /^[0-9]+$/ && NF >= 8) { + printfootnote($7, $8) } - # Check if this is an introduction (chapter 0) - else if ($4 == 0){ + # Check if this is an introduction (chapter 0, column 6 empty, column 7 is text) + else if ($4 == 0 && $6 == ""){ printf("\t") - printintroductionpar($6) + printintroductionpar($7) } - # Regular verse - else { + # Bilingual verse (both column 6 and 7 have text) + else if ($6 != "" && $7 != "") { + # Check language filter flags + if (ENVIRON["ALLIOLI_ONLY_LATIN"] != "" && ENVIRON["ALLIOLI_ONLY_LATIN"] != "0") { + # Show only Latin + printf("%d:%d\t", $4, $5) + printverse($6) + } else if (ENVIRON["ALLIOLI_ONLY_GERMAN"] != "" && ENVIRON["ALLIOLI_ONLY_GERMAN"] != "0") { + # Show only German + printf("%d:%d\t", $4, $5) + printverse($7) + } else { + # Show both side-by-side + printf("%d:%d", $4, $5) + printverse_bilingual($6, $7) + } + } + # German-only verse (column 6 empty, column 7 has text, not a footnote) + else if ($6 == "" && $7 != "" && $7 !~ /^[0-9]+$/) { + printf("%d:%d\t", $4, $5) + printverse($7) + } + # Latin-only verse (column 6 has text, column 7 empty) - rare but handle it + else if ($6 != "" && $7 == "") { printf("%d:%d\t", $4, $5) printverse($6) } diff --git a/allioli.sh b/allioli.sh index 9a67527..ee6b0cb 100755 --- a/allioli.sh +++ b/allioli.sh @@ -23,6 +23,8 @@ show_help() { echo " -l list books" echo " -W no line wrap" echo " -F no footnotes" + echo " -g show only German (no Latin)" + echo " -L show only Latin (no German)" echo " -h show help" echo echo " Reference types:" @@ -68,6 +70,12 @@ while [ $# -gt 0 ]; do elif [ "$1" = "-F" ]; then export ALLIOLI_NOFOOTNOTES=1 shift + elif [ "$1" = "-g" ]; then + export ALLIOLI_ONLY_GERMAN=1 + shift + elif [ "$1" = "-L" ]; then + export ALLIOLI_ONLY_LATIN=1 + shift elif [ "$1" = "-h" ] || [ "$isFlag" -eq 1 ]; then show_help else