From: Steven Baltakatei Sandoval Date: Wed, 17 Jul 2024 03:51:20 +0000 (+0000) Subject: feat(user/mw_create_subpage_navlinks.sh):Handle deep subpage paths X-Git-Url: https://zdv2.bktei.com/gitweb/BK-2020-03.git/commitdiff_plain/4f51959a8c300e9436864e8bd1bc50b53a942c81?hp=670c5ae4201367f8ad4b6257e3a79cdef313a760 feat(user/mw_create_subpage_navlinks.sh):Handle deep subpage paths --- diff --git a/unitproc/bkt-get_path_hierarchy_level b/unitproc/bkt-get_path_hierarchy_level index a76cb1f..7e03981 100755 --- a/unitproc/bkt-get_path_hierarchy_level +++ b/unitproc/bkt-get_path_hierarchy_level @@ -32,12 +32,12 @@ get_path_hierarchy_level() { # Append to output output+=("$level"); - #declare -p flag_root level; + #declare -p flag_root level; # debug ((n++)); done; # Print output printf "%s\n" "${output[@]}"; -}; +}; # return hierarchy level of lines as integers # Test the function with the provided lines printf "\n\n========Test 1========\n" diff --git a/user/mw_create_subpage_navlinks.sh b/user/mw_create_subpage_navlinks.sh index de37365..5cdf74a 100755 --- a/user/mw_create_subpage_navlinks.sh +++ b/user/mw_create_subpage_navlinks.sh @@ -3,8 +3,8 @@ # Input: file text file with list of chapters # stdin text with list of chapters # Output: [[../Chapter 4|Next]], [[../Chapter 2|Previous]], [[../|Up]] -# Version: 0.0.1 -# Attrib: Steven Baltakatei Sandoval. (2024-01-29). reboil.com +# Version: 0.1.0 +# Attrib: Steven Baltakatei Sandoval. (2024-07-17). reboil.com # License: GPLv3+ yell() { echo "$0: $*" >&2; } # print script path and all args to stderr @@ -63,6 +63,129 @@ read_stdin() { return 0; }; # read stdin to stdout lines +get_path_fork_level() { + # Desc: Get fork level from two paths + # Input: arg1 str path + # arg2 str path + # Output: stdout int fork level + # Version: 0.0.1 + local path1="$1"; + local path2="$2"; + + # Squeeze multiple slashes and remove trailing slashes + path1="$(echo "$path1" | tr -s '/' | sed 's:/*$::' )"; + path2="$(echo "$path2" | tr -s '/' | sed 's:/*$::' )"; + + # Check for mixed absolute/relative paths + if [[ "$path1" =~ ^/ ]] && [[ "$path2" =~ ^/ ]]; then + flag_root=true; + # Remove initial / + path1="$(echo "$path1" | sed -e 's:^/::' )"; + path2="$(echo "$path2" | sed -e 's:^/::' )"; + elif [[ ! "$path1" =~ ^/ ]] && [[ ! "$path2" =~ ^/ ]]; then + flag_root=false; + else + declare -p path1 path2 flag_root; + echo "FATAL:Mixed relative and absolute paths not supported." 1>&2; + return 1; + fi; + + # Save path as arrays with `/` as element delimiter + local IFS='/'; + read -ra parts1 <<< "$path1"; + read -ra parts2 <<< "$path2"; + + # Get fork level by counting identical path elements from rootside + local fork_level=0; + for (( i=0; i<${#parts1[@]} && i<${#parts2[@]}; i++ )); do + if [[ "${parts1[i]}" != "${parts2[i]}" ]]; then break; fi; + ((fork_level++)); + done; + + echo "$fork_level"; + #declare -p path1 path2 flag_root parts1 parts2 fork_level; # debug + return 0; +}; # Get fork level int from two paths +prune_path_rootside() { + # Desc: Prunes a path from the root-side to a specified prune level. + # Input: arg1 str path + # arg2 int prune level (0-indexed) + # Depends: GNU sed 4.8 + # Version: 0.0.1 + local path="$1"; + local prune_level="$2"; + + # Check for absolute or relative path + if [[ "$path" =~ ^/ ]]; then + flag_root=true; + # Remove initial / + path="$(echo "$path" | sed -e 's:^/::' )"; + else + flag_root=false; + fi; + + # Save path as array with `/` as element delimiter + local IFS='/'; + read -ra parts <<< "$path"; + + # Assemble pruned path from prune_level + local pruned_path=""; + for (( i=prune_level; i<${#parts[@]}; i++ )); do + pruned_path+="${parts[i]}/"; + done; + + # Trim trailing `/` delimiter + pruned_path=$(echo "$pruned_path" | sed 's:/*$::'); + + # Restore initial / if appropriate + if [[ "$flag_root" == "true" ]] && [[ "$prune_level" -eq 0 ]]; then + pruned_path=/"$pruned_path"; + fi; + + # Output pruned path + echo "$pruned_path"; + #declare -p path prune_level parts pruned_path && printf "========\n"; # debug + return 0; +}; # prune path rootside to int specified level +get_path_hierarchy_level() { + # Desc: Outputs hierarchy level of input paths + # Example: $ cat lines.txt | get_path_hierarchy_level + # Input: stdin str lines with /-delimited paths + # Output: stdout int hierarchy level of each path + # Version: 0.0.1 + + local line level; + local flag_root; + local -a output; + + n=0; + while read -r line; do + # Check for mixed absolute/relative paths. + if [[ $n -le 0 ]] && [[ "$line" =~ ^/ ]]; then + flag_root=true; + else + flag_root=false; + fi; + if { [[ "$flag_root" == "true" ]] && [[ ! "$line" =~ ^/ ]]; } || \ + { [[ "$flag_root" == "false" ]] && [[ "$line" =~ ^/ ]]; } then + echo "FATAL:Mixed relative and absolute paths not supported." 1>&2; return 1; + fi; + + # Squeeze multiple slashes and remove trailing slashes + line="$(echo "$line" | tr -s '/' | sed 's:/*$::' )"; + + # Count the number of slashes to determine hierarchy level + level="$(echo "$line" | awk -F'/' '{print NF-1}' )"; + if [[ "$flag_root" == "true" ]]; then ((level--)); fi; + + # Append to output + output+=("$level"); + #declare -p flag_root level; # debug + ((n++)); + done; + # Print output + printf "%s\n" "${output[@]}"; +}; # return hierarchy level of lines as integers validate_subpage_list() { # Desc: Check for illegal characters in subpage titles # Input: stdin unvalidated subpage list @@ -97,18 +220,27 @@ validate_subpage_list() { echo "FATAL:Error reading stdin." 1>&2; return 1; }; }; generate_wikicode() { + # Desc: Generates navigational link wikicode for subpages # Input: stdin validated subpage list # Output: stdout wikicode - local lprev lnext; + # Depends: get_path_fork_level() + # prune_path_rootside() + # get_path_hierarchy_level() n=0; while read -r line; do #yell "$n:Processing line:$line"; # debug + # Advance input lines lprev="$lcurr"; lcurr="$lnext"; lnext="$line"; #declare -p lprev lcurr lnext; # debug + # Update hierarchy tracker states + lprev_hier="$lcurr_hier"; + lcurr_hier="$lnext_hier"; + lnext_hier="$(echo "$lnext" | get_path_hierarchy_level)"; + # Skip first iteration if [[ "$n" -eq 0 ]]; then # yell "$n:DEBUG:Skipping first iteration."; # debug @@ -116,30 +248,42 @@ generate_wikicode() { #printf -- "----\n" 1>&2; # debug continue; fi; - # Handle first valid input set - # yell "$n:DEBUG:Handling first valid input set."; # debug - if [[ "$n" -eq 1 ]]; then - printf "[[../%s|Next]], [[../|Up]]\n" \ - "$lnext"; - #printf -- "----\n" 1>&2; # debug - ((n++)); continue; fi; - - # Handle middle lines - # yell "$n:DEBUG:Handling middle lines."; # debug - printf "[[../%s|Next]], [[../%s|Previous]], [[../|Up]]\n" \ - "$lnext" "$lprev"; - ((n++)); - #printf -- "----\n" 1>&2; # debug - done; + # Get path fork levels + fork_level_next="$(get_path_fork_level "$lcurr" "$lnext")"; + fork_level_prev="$(get_path_fork_level "$lcurr" "$lprev")"; - # Handle last line - lprev="$lcurr"; - lcurr="$lnext"; - lnext="$line"; - printf "[[../%s|Previous]], [[../|Up]]\n" \ - "$lprev"; - ((n++)); -}; + # Count relative ups needed (`../`) + relups_next="$((lcurr_hier - fork_level_next + 1))"; + relups_prev="$((lcurr_hier - fork_level_prev + 1))"; + + # Initialize Next and Prev links with relative ups to fork. + link_next=""; + for (( i=0; i&2; + fi; + + #declare -p n lprev lcurr lnext lprev_hier lcurr_hier lnext_hier; # debug + #declare -p fork_level_next fork_level_prev relups_next relups_prev; # debug + #declare -p link_next link_prev; # debug + ((n++)); + done < <(read_stdin); # read stdin plus one more blank line +}; # Generate wikicode from validated subpage lines main() { read_input "$@" | validate_subpage_list | generate_wikicode; }; # main program