Support for paragraph and code block indentation inside list elements

This commit is contained in:
2022-03-06 21:27:56 +01:00
parent dd426b16d5
commit a9ac8a5d1e

127
catmd.sh
View File

@@ -11,12 +11,12 @@ DEBUG=:
rex_emptyline='^$' rex_emptyline='^$'
rex_nonemptyline='^([[:blank:]]*)([[:graph:]]+.*)' rex_nonemptyline='^([[:blank:]]*)([[:graph:]]+.*)'
rex_header='^[[:blank:]]*(#+)[[:blank:]]*(.*)' rex_header='^[[:blank:]]*(#+)[[:blank:]]*(.*)'
rex_list_start='^([[:blank:]]{0,1})([*+-]{1} +|[[:digit:]]+\.)(.*)'; flag_list=0 rex_list_start='^([[:blank:]]{0,1})([*+-]{1} +|[[:digit:]]+\.)(.*)'; flag_list=0; indent_list=
rex_list_level='^([[:blank:]]{2,})([*+-]{1} +|[[:digit:]]+\.)(.*)' rex_list_level='^([[:blank:]]{2,})([*+-]{1} +|[[:digit:]]+\.)(.*)'
rex_list="$rex_list_start" rex_list="$rex_list_start"
rex_codeblock='^[[:blank:]]*(```)(.*)' rex_codeblock='^[[:blank:]]*(```)(.*)'
rex_codeinline_start='([^`]*)(`{1,2})(.*)' rex_codeinline_start='([^`]*)(`{1,2})(.*)'
rex_codeinline_space='(^[[:blank:]]{4})(.*)' rex_codeinline_space='(^[[:blank:]]{4})([[:blank:]]*)(.*)'
rex_codeinline1='([^`]*)(`)(.*)' rex_codeinline1='([^`]*)(`)(.*)'
rex_codeinline2='(``)(.*)$' # first part of $line: ${line%"${BASH_REMATCH[0]}"} rex_codeinline2='(``)(.*)$' # first part of $line: ${line%"${BASH_REMATCH[0]}"}
rex_codeinline="$rex_codeinline_start" rex_codeinline="$rex_codeinline_start"
@@ -27,8 +27,12 @@ rex_emphasis="$rex_emphasis_start"
rex_link='([^[]*\[+)([^]]*)(\]+ *[\([])([^]\)]*)([]\)].*)' rex_link='([^[]*\[+)([^]]*)(\]+ *[\([])([^]\)]*)([]\)].*)'
rex_autolink='([^<]*<)([^>]*)(>)(.*)' rex_autolink='([^<]*<)([^>]*)(>)(.*)'
TEXT_INDENT=0
LIST_INDENT_LAST=
LINE_INDENT= LINE_INDENT=
LINE_INDENT_LEVEL=0 LINE_INDENT_N=
LINE_EMPTY_N=
PARSE_STATE=0 PARSE_STATE=0
PARSE_FIX=0 PARSE_FIX=0
FIX_STATE=0 FIX_STATE=0
@@ -84,9 +88,13 @@ parseline() {
case "$PARSE_STATE" in case "$PARSE_STATE" in
0) ## Empty line ## 0) ## Empty line ##
if [[ "$tocheck" =~ $rex_emptyline ]]; then if [[ "$tocheck" =~ $rex_emptyline ]]; then
((LINE_EMPTY_N++))
# End quote # End quote
[ $flag_quote -ne 0 ] && flag_quote=0 && unfix [ $flag_quote -ne 0 ] && flag_quote=0 && unfix
# End text indent
[ $TEXT_INDENT -ne 0 ] && TEXT_INDENT=0
# TODO? Catch rouge formates with empty lines outside codeblocks # TODO? Catch rouge formates with empty lines outside codeblocks
echo -ne "$FO_RESET" echo -ne "$FO_RESET"
format_prefix="" format_prefix=""
@@ -95,41 +103,68 @@ parseline() {
fall || break;; fall || break;;
1) ## Non empty line ## 1) ## Non empty line ##
if [[ "$tocheck" =~ $rex_nonemptyline ]]; then if [[ "$tocheck" =~ $rex_nonemptyline ]]; then
# Detect indent TODO detect levels of indent LINE_INDENT_N=${#BASH_REMATCH[1]}
local tab=$(printf '\t') LINE_INDENT="${BASH_REMATCH[1]}"
case "${BASH_REMATCH[1]}" in LINE_EMPTY_N=0
"${tab}${tab}")
LINE_INDENT="${BASH_REMATCH[1]}"
$DEBUG -n "2t]";;
' ')
LINE_INDENT="${BASH_REMATCH[1]}"
$DEBUG -n "4s]";;
' ')
LINE_INDENT="${BASH_REMATCH[1]}"
$DEBUG -n "2s]";;
*)
LINE_INDENT=
esac
# List ending # List ending
if [ $flag_list -ne 0 ] && [ -z "$LINE_INDENT" ]; then if [ $flag_list -ne 0 ] && [ $LINE_INDENT_N -le 1 ] && [ $TEXT_INDENT -eq 0 ]; then
rex_list="$rex_list_start" rex_list="$rex_list_start"
flag_list=0 flag_list=0
indent_list=
LIST_INDENT_LAST=
fi fi
fi fi
fall || break;; fall || break;;
2) ## List ## 2) ## List ##
if [[ "$tocheck" =~ $rex_list ]]; then if [[ "$tocheck" =~ $rex_list ]]; then
local indent=
indent_list[$flag_list]="$LINE_INDENT"
LIST_INDENT_LAST="$LINE_INDENT"
if (($flag_list > 0 )); then
local level=$((${#LINE_INDENT} - ${#indent_list[$flag_list - 1]}))
#echo -n $level
#if (($level > 1 )); then
# echo -n ">]"
#elif (($level < -1 )); then
# echo -n "<]"
#else
# echo -n "=]"
#fi
fi
# Detect indent TODO detect levels of indent
#local tab=$(printf '\t')
#case "$LINE_INDENT" in
# "${tab}${tab}")
# LINE_INDENT="${BASH_REMATCH[1]}"
# $DEBUG -n "2t]";;
# ' ')
# LINE_INDENT="${BASH_REMATCH[1]}"
# $DEBUG -n "4s]";;
# ' ')
# LINE_INDENT="${BASH_REMATCH[1]}"
# $DEBUG -n "2s]";;
# *)
# LINE_INDENT=
#esac
((flag_list++)) ((flag_list++))
rex_list="$rex_list_level" rex_list="$rex_list_level"
local indent=
[ $flag_list -gt 1 ] && indent="$LINE_INDENT" #"${BASH_REMATCH[1]}" [ $flag_list -gt 1 ] && indent="$LINE_INDENT" #"${BASH_REMATCH[1]}"
printf "%s%b%s%b" "$indent" "$FO_LISTITEM" "${BASH_REMATCH[2]}" "$FO_RESET" printf "%s%b%s%b" "$indent" "$FO_LISTITEM" "${BASH_REMATCH[2]}" "$FO_RESET"
tocheck="${BASH_REMATCH[3]}" tocheck="${BASH_REMATCH[3]}"
line="$tocheck" line="$tocheck"
elif [[ "$tocheck" =~ $rex_list_start ]]; then elif [[ "$tocheck" =~ $rex_list_start ]]; then
flag_list=1 # Start of new list
flag_list=0
indent_list=
LIST_INDENT_LAST=
rex_list="$rex_list_start" rex_list="$rex_list_start"
continue continue
elif [ $flag_list -ne 0 ] && [ $LINE_INDENT_N -le 1 ] && [ $TEXT_INDENT -ne 0 ]; then
printf "%-${TEXT_INDENT}s" " "
fi fi
fall || break fall || break
;; ;;
@@ -163,15 +198,40 @@ parseline() {
fi fi
fi fi
fall || break;; fall || break;;
6) ## Inline code blocks ## 6) ## Code block started with spaces
if [[ "$tocheck" =~ $rex_codeinline_space ]]; then
if [ $LINE_INDENT_N -eq 4 ] && [ $flag_list -ne 0 ]; then
# First line of text paragraph inside a list item
# signaling indentation for the following lines
TEXT_INDENT=$LINE_INDENT_N
else
# Code block started with 4 spaces TODO 2 tabs
if [ $flag_list -ne 0 ] && [ $LINE_INDENT_N -ge 8 ]; then
# Indent code line according to list level
printf "%-4s%s" " " "$LIST_INDENT_LAST"
# Remove 4 leading spaces
printf "%b%s" "$FO_CODEBLOCK" "${BASH_REMATCH[2]#' '}"
else
# Print code related spaces
printf "%b%s" "$FO_CODEBLOCK" "${BASH_REMATCH[2]}"
fi
format_suffix="$FO_RESET"
printf "%b%s" "$FO_CODEBLOCK" "${BASH_REMATCH[3]}"
line=
unfix
fi
fi
fall || break;;
7) ## Inline code blocks ##
if [[ "$tocheck" =~ $rex_codeinline ]]; then if [[ "$tocheck" =~ $rex_codeinline ]]; then
if isfix; then if isfix; then
local lazym="${tocheck%"${BASH_REMATCH[0]}"}" local lazym="${tocheck%"${BASH_REMATCH[0]}"}"
if [ -z "$lazym" ]; then if [ -z "$lazym" ]; then
printf "%s%b" "${BASH_REMATCH[1]}${BASH_REMATCH[2]}" "${FO_RESET}" printf "%b%s%b" "$FO_CODEBLOCK" "${BASH_REMATCH[1]}${BASH_REMATCH[2]}" "${FO_RESET}"
tocheck="${BASH_REMATCH[3]}" tocheck="${BASH_REMATCH[3]}"
else else
printf "%s%b" "${lazym}${BASH_REMATCH[1]}" "${FO_RESET}" printf "%b%s%b" "$FO_CODEBLOCK" "${lazym}${BASH_REMATCH[1]}" "${FO_RESET}"
tocheck="${BASH_REMATCH[2]}" tocheck="${BASH_REMATCH[2]}"
fi fi
rex_codeinline="$rex_codeinline_start" rex_codeinline="$rex_codeinline_start"
@@ -187,18 +247,13 @@ parseline() {
fix fix
fi fi
line="$tocheck" line="$tocheck"
elif [[ "$tocheck" =~ $rex_codeinline_space ]]; then
# TODO check for list indentation
format_suffix="$FO_RESET"
printf "%b%s" "$FO_CODEBLOCK" "${BASH_REMATCH[2]}"
line=
break
elif isfix; then elif isfix; then
# Open inline block at end of line # Open inline block at end of line
format_suffix="$FO_RESET"
fall || break fall || break
fi fi
fall;; fall;;
7) ## Inline emphasis start 8) ## Inline emphasis start
if [[ "$tocheck" =~ $rex_emphasis ]]; then if [[ "$tocheck" =~ $rex_emphasis ]]; then
local fo_emphasis=$FO_EMPHASIS1 local fo_emphasis=$FO_EMPHASIS1
if isfix; then if isfix; then
@@ -220,11 +275,8 @@ parseline() {
fall || break fall || break
fi fi
fall;; fall;;
8) ## Links within one line ## 9) ## Links within one line ##
if [[ "$tocheck" =~ $rex_link ]]; then if [[ "$tocheck" =~ $rex_link ]]; then
#echo -n "m]"
#echo "${BASH_REMATCH[0]}"
#echo "${BASH_REMATCH[1]} ! ${BASH_REMATCH[2]} ! ${BASH_REMATCH[3]} ! ${BASH_REMATCH[4]} ! ${BASH_REMATCH[5]}"
printf "%s%b%s%b%s%b%s%b%s" "${BASH_REMATCH[1]}" "${FO_LINKTEXT}" "${BASH_REMATCH[2]}" "${FO_RESET}" "${BASH_REMATCH[3]}" "${FO_LINKURL}" \ printf "%s%b%s%b%s%b%s%b%s" "${BASH_REMATCH[1]}" "${FO_LINKTEXT}" "${BASH_REMATCH[2]}" "${FO_RESET}" "${BASH_REMATCH[3]}" "${FO_LINKURL}" \
"${BASH_REMATCH[4]}" "${FO_RESET}" "${BASH_REMATCH[4]}" "${FO_RESET}"
tocheck="${BASH_REMATCH[5]}" tocheck="${BASH_REMATCH[5]}"
@@ -235,11 +287,8 @@ parseline() {
fall || break fall || break
fi fi
fall;; fall;;
9) ## Auto-links within one line ## 10) ## Auto-links within one line ##
if [[ "$tocheck" =~ $rex_autolink ]]; then if [[ "$tocheck" =~ $rex_autolink ]]; then
#echo -n "m]"
#echo "${BASH_REMATCH[0]}"
#echo "${BASH_REMATCH[1]} ! ${BASH_REMATCH[2]} ! ${BASH_REMATCH[3]} ! ${BASH_REMATCH[4]} ! ${BASH_REMATCH[5]}"
printf "%s%b%s%b%s" "${BASH_REMATCH[1]}" "${FO_LINKURL}" "${BASH_REMATCH[2]}" "${FO_RESET}" "${BASH_REMATCH[3]}" printf "%s%b%s%b%s" "${BASH_REMATCH[1]}" "${FO_LINKURL}" "${BASH_REMATCH[2]}" "${FO_RESET}" "${BASH_REMATCH[3]}"
tocheck="${BASH_REMATCH[4]}" tocheck="${BASH_REMATCH[4]}"
line="$tocheck" line="$tocheck"