diff --git a/catmd.sh b/catmd.sh index c682b90..c498f01 100755 --- a/catmd.sh +++ b/catmd.sh @@ -11,12 +11,12 @@ DEBUG=: rex_emptyline='^$' rex_nonemptyline='^([[:blank:]]*)([[:graph:]]+.*)' 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="$rex_list_start" rex_codeblock='^[[:blank:]]*(```)(.*)' rex_codeinline_start='([^`]*)(`{1,2})(.*)' -rex_codeinline_space='(^[[:blank:]]{4})(.*)' +rex_codeinline_space='(^[[:blank:]]{4})([[:blank:]]*)(.*)' rex_codeinline1='([^`]*)(`)(.*)' rex_codeinline2='(``)(.*)$' # first part of $line: ${line%"${BASH_REMATCH[0]}"} rex_codeinline="$rex_codeinline_start" @@ -27,8 +27,12 @@ rex_emphasis="$rex_emphasis_start" rex_link='([^[]*\[+)([^]]*)(\]+ *[\([])([^]\)]*)([]\)].*)' rex_autolink='([^<]*<)([^>]*)(>)(.*)' +TEXT_INDENT=0 +LIST_INDENT_LAST= LINE_INDENT= -LINE_INDENT_LEVEL=0 +LINE_INDENT_N= +LINE_EMPTY_N= + PARSE_STATE=0 PARSE_FIX=0 FIX_STATE=0 @@ -84,8 +88,12 @@ parseline() { case "$PARSE_STATE" in 0) ## Empty line ## if [[ "$tocheck" =~ $rex_emptyline ]]; then + ((LINE_EMPTY_N++)) # End quote [ $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 echo -ne "$FO_RESET" @@ -95,41 +103,68 @@ parseline() { fall || break;; 1) ## Non empty line ## if [[ "$tocheck" =~ $rex_nonemptyline ]]; then - # Detect indent TODO detect levels of indent - local tab=$(printf '\t') - case "${BASH_REMATCH[1]}" 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 + LINE_INDENT_N=${#BASH_REMATCH[1]} + LINE_INDENT="${BASH_REMATCH[1]}" + LINE_EMPTY_N=0 # 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" flag_list=0 + indent_list= + LIST_INDENT_LAST= fi fi fall || break;; 2) ## List ## 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++)) + rex_list="$rex_list_level" + local indent= [ $flag_list -gt 1 ] && indent="$LINE_INDENT" #"${BASH_REMATCH[1]}" printf "%s%b%s%b" "$indent" "$FO_LISTITEM" "${BASH_REMATCH[2]}" "$FO_RESET" tocheck="${BASH_REMATCH[3]}" line="$tocheck" 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" continue + elif [ $flag_list -ne 0 ] && [ $LINE_INDENT_N -le 1 ] && [ $TEXT_INDENT -ne 0 ]; then + printf "%-${TEXT_INDENT}s" " " fi fall || break ;; @@ -163,15 +198,40 @@ parseline() { fi fi 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 isfix; then local lazym="${tocheck%"${BASH_REMATCH[0]}"}" 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]}" 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]}" fi rex_codeinline="$rex_codeinline_start" @@ -187,18 +247,13 @@ parseline() { fix fi 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 # Open inline block at end of line + format_suffix="$FO_RESET" fall || break fi fall;; - 7) ## Inline emphasis start + 8) ## Inline emphasis start if [[ "$tocheck" =~ $rex_emphasis ]]; then local fo_emphasis=$FO_EMPHASIS1 if isfix; then @@ -220,11 +275,8 @@ parseline() { fall || break fi fall;; - 8) ## Links within one line ## + 9) ## Links within one line ## 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}" \ "${BASH_REMATCH[4]}" "${FO_RESET}" tocheck="${BASH_REMATCH[5]}" @@ -235,11 +287,8 @@ parseline() { fall || break fi fall;; - 9) ## Auto-links within one line ## + 10) ## Auto-links within one line ## 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]}" tocheck="${BASH_REMATCH[4]}" line="$tocheck"