mirror of
https://github.com/tests-always-included/mo.git
synced 2024-12-18 16:27:52 +00:00
Moving delimiters and standalone to global vars
This commit is contained in:
parent
3a58ee390e
commit
d32b912472
368
mo
368
mo
@ -48,6 +48,7 @@
|
|||||||
#/ MO_ALLOW_FUNCTION_ARGUMENTS - When set to a non-empty value, this allows
|
#/ MO_ALLOW_FUNCTION_ARGUMENTS - When set to a non-empty value, this allows
|
||||||
#/ functions referenced in templates to receive additional options and
|
#/ functions referenced in templates to receive additional options and
|
||||||
#/ arguments.
|
#/ arguments.
|
||||||
|
#/ MO_CLOSE_DELIMITER - The string used when closing a tag. Defaults to "}}".
|
||||||
#/ MO_DEBUG - When set to a non-empty value, additional debug information is
|
#/ MO_DEBUG - When set to a non-empty value, additional debug information is
|
||||||
#/ written to stderr.
|
#/ written to stderr.
|
||||||
#/ MO_FUNCTION_ARGS - Arguments passed to the function.
|
#/ MO_FUNCTION_ARGS - Arguments passed to the function.
|
||||||
@ -59,8 +60,13 @@
|
|||||||
#/ variable will be aborted with an error.
|
#/ variable will be aborted with an error.
|
||||||
#/ MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" will
|
#/ MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" will
|
||||||
#/ be treated as an empty value for the purposes of conditionals.
|
#/ be treated as an empty value for the purposes of conditionals.
|
||||||
|
#/ MO_OPEN_DELIMITER - The string used when opening a tag. Defaults to "{{".
|
||||||
#/ MO_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a
|
#/ MO_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a
|
||||||
#/ help message.
|
#/ help message.
|
||||||
|
#/ MO_STANDALONE_CONTENT - The content that preceeded the current tag. When a
|
||||||
|
#/ standalone tag is encountered, this is checked to see if it only
|
||||||
|
#/ contains whitespace. If this and the whitespace condition after a tag is
|
||||||
|
#/ met, then this will be reset to $'\n'.
|
||||||
#/
|
#/
|
||||||
#/ Mo is under a MIT style licence with an additional non-advertising clause.
|
#/ Mo is under a MIT style licence with an additional non-advertising clause.
|
||||||
#/ See LICENSE.md for the full text.
|
#/ See LICENSE.md for the full text.
|
||||||
@ -167,8 +173,22 @@ mo() (
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
mo::debug "Debug enabled"
|
mo::debug "Debug enabled"
|
||||||
|
# shellcheck disable=SC2030
|
||||||
|
MO_OPEN_DELIMITER="${MO_OPEN_DELIMITER:-"{{"}"
|
||||||
|
# shellcheck disable=SC2030
|
||||||
|
MO_CLOSE_DELIMITER="${MO_CLOSE_DELIMITER:-"}}"}"
|
||||||
|
|
||||||
|
# The standalone content is a trick to make the standalone tag detection
|
||||||
|
# possible. When it's set to content with a newline and if the tag supports
|
||||||
|
# it, the standalone content check happens. This check ensures only
|
||||||
|
# whitespace is after the last newline up to the tag, and only whitespace
|
||||||
|
# is after the tag up to the next newline. If that is the case, remove
|
||||||
|
# whitespace and the trailing newline. By setting this to $'\n', we're
|
||||||
|
# saying we are at the beginning of content.
|
||||||
|
# shellcheck disable=SC2030
|
||||||
|
MO_STANDALONE_CONTENT=$'\n'
|
||||||
mo::content moContent "${moFiles[@]}" || return 1
|
mo::content moContent "${moFiles[@]}" || return 1
|
||||||
mo::parse moResult "$moContent" "" "" "{{" "}}" "" $'\n'
|
mo::parse moResult "$moContent" "" "" ""
|
||||||
echo -n "${moResult[0]}${moResult[1]}"
|
echo -n "${moResult[0]}${moResult[1]}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -181,7 +201,7 @@ mo() (
|
|||||||
mo::debug() {
|
mo::debug() {
|
||||||
# shellcheck disable=SC2031
|
# shellcheck disable=SC2031
|
||||||
if [[ -n "${MO_DEBUG:-}" ]]; then
|
if [[ -n "${MO_DEBUG:-}" ]]; then
|
||||||
echo "DEBUG: $1" >&2
|
echo "DEBUG ${FUNCNAME[1]:-?} - $1" >&2
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +239,7 @@ mo::usage() {
|
|||||||
# Internal: Fetches the content to parse into a variable. Can be a list of
|
# Internal: Fetches the content to parse into a variable. Can be a list of
|
||||||
# partials for files or the content from stdin.
|
# partials for files or the content from stdin.
|
||||||
#
|
#
|
||||||
# $1 - Target variable to store results
|
# $1 - Target variable to store results
|
||||||
# $2-@ - File names (optional), read from stdin otherwise
|
# $2-@ - File names (optional), read from stdin otherwise
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
@ -234,7 +254,8 @@ mo::content() {
|
|||||||
for moFilename in "$@"; do
|
for moFilename in "$@"; do
|
||||||
mo::debug "Using template to load content from file: $moFilename"
|
mo::debug "Using template to load content from file: $moFilename"
|
||||||
#: This is so relative paths work from inside template files
|
#: This is so relative paths work from inside template files
|
||||||
moContent="$moContent"'{{>'"$moFilename"'}}'
|
# shellcheck disable=SC2031
|
||||||
|
moContent="$moContent$MO_OPEN_DELIMITER>$moFilename$MO_CLOSE_DELIMITER"
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
mo::debug "Will read content from stdin"
|
mo::debug "Will read content from stdin"
|
||||||
@ -299,7 +320,7 @@ mo::indirect() {
|
|||||||
|
|
||||||
# Internal: Send an array as a variable up to caller of a function
|
# Internal: Send an array as a variable up to caller of a function
|
||||||
#
|
#
|
||||||
# $1 - Variable name
|
# $1 - Variable name
|
||||||
# $2-@ - Array elements
|
# $2-@ - Array elements
|
||||||
#
|
#
|
||||||
# Examples
|
# Examples
|
||||||
@ -344,14 +365,14 @@ mo::findString() {
|
|||||||
#
|
#
|
||||||
# $1 - Destination variable
|
# $1 - Destination variable
|
||||||
# $2 - String to split
|
# $2 - String to split
|
||||||
# $3 - Starting delimiter
|
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::split() {
|
mo::split() {
|
||||||
local moPos moResult
|
local moPos moResult
|
||||||
|
|
||||||
moResult=("$2")
|
moResult=("$2")
|
||||||
mo::findString moPos "${moResult[0]}" "$3"
|
# shellcheck disable=SC2031
|
||||||
|
mo::findString moPos "${moResult[0]}" "$MO_OPEN_DELIMITER"
|
||||||
|
|
||||||
if [[ "$moPos" -ne -1 ]]; then
|
if [[ "$moPos" -ne -1 ]]; then
|
||||||
# The first delimiter was found
|
# The first delimiter was found
|
||||||
@ -365,8 +386,8 @@ mo::split() {
|
|||||||
|
|
||||||
# Internal: Trim leading characters
|
# Internal: Trim leading characters
|
||||||
#
|
#
|
||||||
# $1 - Name of destination variable
|
# $1 - Name of destination variable
|
||||||
# $2 - The string
|
# $2 - The string
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::trim() {
|
mo::trim() {
|
||||||
@ -417,106 +438,91 @@ mo::chomp() {
|
|||||||
# $2 - Block of text to change
|
# $2 - Block of text to change
|
||||||
# $3 - Current name (the variable NAME for what {{.}} means)
|
# $3 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $4 - Current block name
|
# $4 - Current block name
|
||||||
# $5 - Open delimiter ("{{")
|
# $5 - Fast mode (skip to end of block) if non-empty
|
||||||
# $6 - Close delimiter ("}}")
|
|
||||||
# $7 - Fast mode (skip to end of block) if non-empty
|
|
||||||
# $8 - Starting standalone content hack
|
|
||||||
#
|
|
||||||
# The standalone content is a trick to make the standalone tag detection
|
|
||||||
# possible. When it's set to content with a newline and if the tag supports it,
|
|
||||||
# the standalone content check happens. This check ensures only whitespace is
|
|
||||||
# after the last newline up to the tag, and only whitespace is after the tag up
|
|
||||||
# to the next newline. If that is the case, remove whitespace and the trailing
|
|
||||||
# newline. By setting this to $'\n', we're saying we are at the beginning of
|
|
||||||
# content.
|
|
||||||
#
|
#
|
||||||
# Array has the following elements
|
# Array has the following elements
|
||||||
# [0] - Parsed content
|
# [0] - Parsed content
|
||||||
# [1] - Unparsed content after the closing tag
|
# [1] - Unparsed content after the closing tag
|
||||||
# [2] - Standalone content hack
|
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::parse() {
|
mo::parse() {
|
||||||
local moContent moCurrent moOpenDelimiter moCloseDelimiter moResult moSplit moParseChunk moFastMode moStandaloneContent moRemainder
|
local moContent moCurrent moResult moSplit moParseChunk moFastMode moRemainder
|
||||||
|
|
||||||
moContent=$2
|
moContent=$2
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moCurrentBlock=$4
|
moCurrentBlock=$4
|
||||||
moOpenDelimiter=$5
|
moFastMode=$5
|
||||||
moCloseDelimiter=$6
|
|
||||||
moFastMode=$7
|
|
||||||
moStandaloneContent=$8
|
|
||||||
moResult=""
|
moResult=""
|
||||||
moRemainder=""
|
moRemainder=""
|
||||||
mo::debug "Starting parse, current: $moCurrent, ending tag: $moCurrentBlock, fast: $moFastMode"
|
mo::debug "Starting parse, current: $moCurrent, ending tag: $moCurrentBlock, fast: $moFastMode"
|
||||||
|
|
||||||
while [[ "${#moContent}" -gt 0 ]]; do
|
while [[ "${#moContent}" -gt 0 ]]; do
|
||||||
# Both escaped and unescaped content are treated the same.
|
# Both escaped and unescaped content are treated the same.
|
||||||
mo::split moSplit "$moContent" "$moOpenDelimiter"
|
# shellcheck disable=SC2031
|
||||||
|
mo::split moSplit "$moContent" "$MO_OPEN_DELIMITER"
|
||||||
|
|
||||||
if [[ "${#moSplit[@]}" -gt 1 ]]; then
|
if [[ "${#moSplit[@]}" -gt 1 ]]; then
|
||||||
moResult="$moResult${moSplit[0]}"
|
moResult="$moResult${moSplit[0]}"
|
||||||
moStandaloneContent="$moStandaloneContent${moSplit[0]}"
|
# shellcheck disable=SC2031
|
||||||
|
MO_STANDALONE_CONTENT="$MO_STANDALONE_CONTENT${moSplit[0]}"
|
||||||
mo::trim moContent "${moSplit[1]}"
|
mo::trim moContent "${moSplit[1]}"
|
||||||
|
|
||||||
case $moContent in
|
case $moContent in
|
||||||
'#'*)
|
'#'*)
|
||||||
# Loop, if/then, or pass content through function
|
# Loop, if/then, or pass content through function
|
||||||
mo::parseBlock moParseChunk "$moResult" "$moContent" "$moCurrent" "$moOpenDelimiter" "$moCloseDelimiter" false "$moStandaloneContent"
|
mo::parseBlock moParseChunk "$moResult" "$moContent" "$moCurrent" false
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'>'*)
|
'>'*)
|
||||||
# Load partial - get name of file relative to cwd
|
# Load partial - get name of file relative to cwd
|
||||||
mo::parsePartial moParseChunk "$moResult" "$moContent" "$moCurrent" "$moCloseDelimiter" "$moFastMode" "$moStandaloneContent"
|
mo::parsePartial moParseChunk "$moResult" "$moContent" "$moCurrent" "$moFastMode"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'/'*)
|
'/'*)
|
||||||
# Closing tag
|
# Closing tag
|
||||||
mo::parseCloseTag moParseChunk "$moResult" "$moContent" "$moCurrent" "$moCloseDelimiter" "$moCurrentBlock" "$moStandaloneContent"
|
mo::parseCloseTag moParseChunk "$moResult" "$moContent" "$moCurrent" "$moCurrentBlock"
|
||||||
moRemainder=${moParseChunk[3]}
|
moRemainder=${moParseChunk[2]}
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'^'*)
|
'^'*)
|
||||||
# Display section if named thing does not exist
|
# Display section if named thing does not exist
|
||||||
mo::parseBlock moParseChunk "$moResult" "$moContent" "$moCurrent" "$moOpenDelimiter" "$moCloseDelimiter" true "$moStandaloneContent"
|
mo::parseBlock moParseChunk "$moResult" "$moContent" "$moCurrent" true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'!'*)
|
'!'*)
|
||||||
# Comment - ignore the tag content entirely
|
# Comment - ignore the tag content entirely
|
||||||
mo::parseComment moParseChunk "$moResult" "$moContent" "$moCloseDelimiter" "$moStandaloneContent"
|
mo::parseComment moParseChunk "$moResult" "$moContent"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'='*)
|
'='*)
|
||||||
# Change delimiters
|
# Change delimiters
|
||||||
# Any two non-whitespace sequences separated by whitespace.
|
# Any two non-whitespace sequences separated by whitespace.
|
||||||
mo::parseDelimiter moParseChunk "$moResult" "$moContent" "$moCloseDelimiter" "$moStandaloneContent"
|
mo::parseDelimiter moParseChunk "$moResult" "$moContent"
|
||||||
moOpenDelimiter=${moParseChunk[3]}
|
|
||||||
moCloseDelimiter=${moParseChunk[4]}
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'&'*)
|
'&'*)
|
||||||
# Unescaped - mo doesn't escape
|
# Unescaped - mo doesn't escape
|
||||||
moContent=${moContent#&}
|
moContent=${moContent#&}
|
||||||
mo::trim moContent "$moContent"
|
mo::trim moContent "$moContent"
|
||||||
mo::parseValue moParseChunk "$moResult" "$moContent" "$moCurrent" "$moOpenDelimiter" "$moCloseDelimiter" "$moFastMode"
|
mo::parseValue moParseChunk "$moResult" "$moContent" "$moCurrent" "$moFastMode"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
# Normal environment variable, string, subexpression,
|
# Normal environment variable, string, subexpression,
|
||||||
# current value, key, or function call
|
# current value, key, or function call
|
||||||
mo::parseValue moParseChunk "$moResult" "$moContent" "$moCurrent" "$moOpenDelimiter" "$moCloseDelimiter" "$moFastMode"
|
mo::parseValue moParseChunk "$moResult" "$moContent" "$moCurrent" "$moFastMode"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
moResult=${moParseChunk[0]}
|
moResult=${moParseChunk[0]}
|
||||||
moContent=${moParseChunk[1]}
|
moContent=${moParseChunk[1]}
|
||||||
moStandaloneContent=${moParseChunk[2]}
|
|
||||||
else
|
else
|
||||||
moResult="$moResult$moContent"
|
moResult="$moResult$moContent"
|
||||||
moContent=""
|
moContent=""
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
local "$1" && mo::indirectArray "$1" "$moResult" "$moRemainder" "$moStandaloneContent"
|
local "$1" && mo::indirectArray "$1" "$moResult" "$moRemainder"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -526,49 +532,40 @@ mo::parse() {
|
|||||||
# $2 - Previously parsed
|
# $2 - Previously parsed
|
||||||
# $3 - Content
|
# $3 - Content
|
||||||
# $4 - Current name (the variable NAME for what {{.}} means)
|
# $4 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $5 - Open delimiter
|
# $5 - Invert condition ("true" or "false")
|
||||||
# $6 - Close delimiter
|
|
||||||
# $7 - Invert condition ("true" or "false")
|
|
||||||
# $8 - Standalone content
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseBlock() {
|
mo::parseBlock() {
|
||||||
local moContent moCurrent moOpenDelimiter moCloseDelimiter moInvertBlock moArgs moParseResult moPrevious moStandaloneContent
|
local moContent moCurrent moInvertBlock moArgs moParseResult moPrevious
|
||||||
|
|
||||||
moPrevious=$2
|
moPrevious=$2
|
||||||
mo::trim moContent "${3:1}"
|
mo::trim moContent "${3:1}"
|
||||||
moCurrent=$4
|
moCurrent=$4
|
||||||
moOpenDelimiter=$5
|
moInvertBlock=$5
|
||||||
moCloseDelimiter=$6
|
mo::parseValueInner moArgs "$moContent" "$moCurrent"
|
||||||
moInvertBlock=$7
|
# shellcheck disable=SC2031
|
||||||
moStandaloneContent=$8
|
moContent="${moArgs[0]#$MO_CLOSE_DELIMITER}"
|
||||||
mo::parseValueInner moArgs "$moContent" "$moCurrent" "$moCloseDelimiter"
|
|
||||||
moContent="${moArgs[0]#$moCloseDelimiter}"
|
|
||||||
moArgs=("${moArgs[@]:1}")
|
moArgs=("${moArgs[@]:1}")
|
||||||
mo::debug "Parsing block: ${moArgs[*]}"
|
mo::debug "Parsing block: ${moArgs[*]}"
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moContent"; then
|
||||||
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
||||||
mo::standaloneProcessAfter moContent "$moContent"
|
mo::standaloneProcessAfter moContent "$moContent"
|
||||||
moStandaloneContent=$'\n'
|
|
||||||
else
|
|
||||||
moStandaloneContent=""
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${moArgs[0]}" == "NAME" ]] && mo::isFunction "${moArgs[1]}"; then
|
if [[ "${moArgs[0]}" == "NAME" ]] && mo::isFunction "${moArgs[1]}"; then
|
||||||
mo::parseBlockFunction moParseResult "$moContent" "$moCurrent" "$moOpenDelimiter" "$moCloseDelimiter" "$moInvertBlock" "$moStandaloneContent" "${moArgs[@]}"
|
mo::parseBlockFunction moParseResult "$moContent" "$moCurrent" "$moInvertBlock" "${moArgs[@]}"
|
||||||
elif [[ "${moArgs[0]}" == "NAME" ]] && mo::isArray "${moArgs[1]}"; then
|
elif [[ "${moArgs[0]}" == "NAME" ]] && mo::isArray "${moArgs[1]}"; then
|
||||||
mo::parseBlockArray moParseResult "$moContent" "$moCurrent" "$moOpenDelimiter" "$moCloseDelimiter" "$moInvertBlock" "$moStandaloneContent" "${moArgs[@]}"
|
mo::parseBlockArray moParseResult "$moContent" "$moCurrent" "$moInvertBlock" "${moArgs[@]}"
|
||||||
else
|
else
|
||||||
mo::parseBlockValue moParseResult "$moContent" "$moCurrent" "$moOpenDelimiter" "$moCloseDelimiter" "$moInvertBlock" "$moStandaloneContent" "${moArgs[@]}"
|
mo::parseBlockValue moParseResult "$moContent" "$moCurrent" "$moInvertBlock" "${moArgs[@]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local "$1" && mo::indirectArray "$1" "$moPrevious${moParseResult[0]}" "${moParseResult[1]}" "${moParseResult[2]}"
|
local "$1" && mo::indirectArray "$1" "$moPrevious${moParseResult[0]}" "${moParseResult[1]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -577,16 +574,12 @@ mo::parseBlock() {
|
|||||||
# $1 - Destination variable name, will be set to an array
|
# $1 - Destination variable name, will be set to an array
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Current name (the variable NAME for what {{.}} means)
|
# $3 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $4 - Open delimiter
|
# $5 - Invert condition ("true" or "false")
|
||||||
# $5 - Close delimiter
|
# $6-@ - The parsed arguments from inside the block tags
|
||||||
# $6 - Invert condition ("true" or "false")
|
|
||||||
# $7 - Standalone content
|
|
||||||
# $8-$* - The parsed arguments from inside the block tags
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseBlockFunction() {
|
mo::parseBlockFunction() {
|
||||||
@ -595,33 +588,29 @@ mo::parseBlockFunction() {
|
|||||||
moTarget=$1
|
moTarget=$1
|
||||||
moContent=$2
|
moContent=$2
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moOpenDelimiter=$4
|
moInvertBlock=$4
|
||||||
moCloseDelimiter=$5
|
shift 4
|
||||||
moInvertBlock=$6
|
|
||||||
moStandaloneContent=$7
|
|
||||||
shift 7
|
|
||||||
moArgs=(${@+"$@"})
|
moArgs=(${@+"$@"})
|
||||||
mo::debug "Parsing block function: ${moArgs[*]}"
|
mo::debug "Parsing block function: ${moArgs[*]}"
|
||||||
|
|
||||||
if [[ "$moInvertBlock" == "true" ]]; then
|
if [[ "$moInvertBlock" == "true" ]]; then
|
||||||
# The function exists and we're inverting the section, so skip the
|
# The function exists and we're inverting the section, so skip the
|
||||||
# block content.
|
# block content.
|
||||||
mo::parse moParseResult "$moContent" "$moCurrent" "${moArgs[1]}" "$moOpenDelimiter" "$moCloseDelimiter" "FAST-FUNCTION" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "$moCurrent" "${moArgs[1]}" "FAST-FUNCTION"
|
||||||
moResult=""
|
moResult=""
|
||||||
moContent="${moParseResult[1]}"
|
moContent="${moParseResult[1]}"
|
||||||
else
|
else
|
||||||
# Get contents of block after parsing
|
# Get contents of block after parsing
|
||||||
mo::parse moParseResult "$moContent" "$moCurrent" "${moArgs[1]}" "$moOpenDelimiter" "$moCloseDelimiter" "" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "$moCurrent" "${moArgs[1]}" ""
|
||||||
|
|
||||||
# Pass contents to function
|
# Pass contents to function
|
||||||
mo::evaluateFunction moResult "${moParseResult[0]}" "${moArgs[@]:1}"
|
mo::evaluateFunction moResult "${moParseResult[0]}" "${moArgs[@]:1}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
moContent=${moParseResult[1]}
|
moContent=${moParseResult[1]}
|
||||||
moStandaloneContent=${moParseResult[2]}
|
|
||||||
mo::debug "Done parsing block array: ${moArgs[*]}"
|
mo::debug "Done parsing block array: ${moArgs[*]}"
|
||||||
|
|
||||||
local "$moTarget" && mo::indirectArray "$moTarget" "$moResult" "$moContent" "$moStandaloneContent"
|
local "$moTarget" && mo::indirectArray "$moTarget" "$moResult" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -630,29 +619,22 @@ mo::parseBlockFunction() {
|
|||||||
# $1 - Destination variable name, will be set to an array
|
# $1 - Destination variable name, will be set to an array
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Current name (the variable NAME for what {{.}} means)
|
# $3 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $4 - Open delimiter
|
# $4 - Invert condition ("true" or "false")
|
||||||
# $5 - Close delimiter
|
# $5-@ - The parsed arguments from inside the block tags
|
||||||
# $6 - Invert condition ("true" or "false")
|
|
||||||
# $7 - Standalone content
|
|
||||||
# $8-$* - The parsed arguments from inside the block tags
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseBlockArray() {
|
mo::parseBlockArray() {
|
||||||
local moTarget moContent moCurrent moOpenDelimiter moCloseDelimiter moInvertBlock moArgs moParseResult moResult moStandaloneContent moArrayName moArrayIndexes moArrayIndex
|
local moTarget moContent moCurrent moInvertBlock moArgs moParseResult moResult moArrayName moArrayIndexes moArrayIndex
|
||||||
|
|
||||||
moTarget=$1
|
moTarget=$1
|
||||||
moContent=$2
|
moContent=$2
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moOpenDelimiter=$4
|
moInvertBlock=$4
|
||||||
moCloseDelimiter=$5
|
shift 4
|
||||||
moInvertBlock=$6
|
|
||||||
moStandaloneContent=$7
|
|
||||||
shift 7
|
|
||||||
moArgs=(${@+"$@"})
|
moArgs=(${@+"$@"})
|
||||||
mo::debug "Parsing block array: ${moArgs[*]}"
|
mo::debug "Parsing block array: ${moArgs[*]}"
|
||||||
moArrayName=${moArgs[1]}
|
moArrayName=${moArgs[1]}
|
||||||
@ -662,34 +644,33 @@ mo::parseBlockArray() {
|
|||||||
# No elements
|
# No elements
|
||||||
if [[ "$moInvertBlock" == "true" ]]; then
|
if [[ "$moInvertBlock" == "true" ]]; then
|
||||||
# Show the block
|
# Show the block
|
||||||
mo::parse moParseResult "$moContent" "$moArrayName" "$moArrayName" "$moOpenDelimiter" "$moCloseDelimiter" "" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "$moArrayName" "$moArrayName" ""
|
||||||
moResult=${moParseResult[0]}
|
moResult=${moParseResult[0]}
|
||||||
else
|
else
|
||||||
# Skip the block processing
|
# Skip the block processing
|
||||||
mo::parse moParseResult "$moContent" "$moArrayName" "$moArrayName" "$moOpenDelimiter" "$moCloseDelimiter" "FAST-EMPTY" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "$moArrayName" "$moArrayName" "FAST-EMPTY"
|
||||||
moResult=""
|
moResult=""
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ "$moInvertBlock" == "true" ]]; then
|
if [[ "$moInvertBlock" == "true" ]]; then
|
||||||
# Skip the block processing
|
# Skip the block processing
|
||||||
mo::parse moParseResult "$moContent" "$moArrayName" "$moArrayName" "$moOpenDelimiter" "$moCloseDelimiter" "FAST-EMPTY" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "$moArrayName" "$moArrayName" "FAST-EMPTY"
|
||||||
moResult=""
|
moResult=""
|
||||||
else
|
else
|
||||||
moResult=""
|
moResult=""
|
||||||
# Process for each element in the array
|
# Process for each element in the array
|
||||||
for moArrayIndex in "${moArrayIndexes[@]}"; do
|
for moArrayIndex in "${moArrayIndexes[@]}"; do
|
||||||
mo::debug "Iterate over array using element: $moArrayName.$moArrayIndex"
|
mo::debug "Iterate over array using element: $moArrayName.$moArrayIndex"
|
||||||
mo::parse moParseResult "$moContent" "$moArrayName.$moArrayIndex" "${moArgs[1]}" "$moOpenDelimiter" "$moCloseDelimiter" "" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "$moArrayName.$moArrayIndex" "${moArgs[1]}" ""
|
||||||
moResult="$moResult${moParseResult[0]}"
|
moResult="$moResult${moParseResult[0]}"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
moContent=${moParseResult[1]}
|
moContent=${moParseResult[1]}
|
||||||
moStandaloneContent=${moParseResult[2]}
|
|
||||||
mo::debug "Done parsing block array: ${moArgs[*]}"
|
mo::debug "Done parsing block array: ${moArgs[*]}"
|
||||||
|
|
||||||
local "$moTarget" && mo::indirectArray "$moTarget" "$moResult" "$moContent" "$moStandaloneContent"
|
local "$moTarget" && mo::indirectArray "$moTarget" "$moResult" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -698,29 +679,22 @@ mo::parseBlockArray() {
|
|||||||
# $1 - Destination variable name, will be set to an array
|
# $1 - Destination variable name, will be set to an array
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Current name (the variable NAME for what {{.}} means)
|
# $3 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $4 - Open delimiter
|
# $4 - Invert condition ("true" or "false")
|
||||||
# $5 - Close delimiter
|
# $5-@ - The parsed arguments from inside the block tags
|
||||||
# $6 - Invert condition ("true" or "false")
|
|
||||||
# $7 - Standalone content
|
|
||||||
# $8-$* - The parsed arguments from inside the block tags
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseBlockValue() {
|
mo::parseBlockValue() {
|
||||||
local moTarget moContent moCurrent moOpenDelimiter moCloseDelimiter moInvertBlock moArgs moParseResult moResult moStandaloneContent
|
local moTarget moContent moCurrent moInvertBlock moArgs moParseResult moResult
|
||||||
|
|
||||||
moTarget=$1
|
moTarget=$1
|
||||||
moContent=$2
|
moContent=$2
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moOpenDelimiter=$4
|
moInvertBlock=$4
|
||||||
moCloseDelimiter=$5
|
shift 4
|
||||||
moInvertBlock=$6
|
|
||||||
moStandaloneContent=$7
|
|
||||||
shift 7
|
|
||||||
moArgs=(${@+"$@"})
|
moArgs=(${@+"$@"})
|
||||||
mo::debug "Parsing block value: ${moArgs[*]}"
|
mo::debug "Parsing block value: ${moArgs[*]}"
|
||||||
|
|
||||||
@ -729,19 +703,18 @@ mo::parseBlockValue() {
|
|||||||
|
|
||||||
if mo::isTruthy "$moResult" "$moInvertBlock"; then
|
if mo::isTruthy "$moResult" "$moInvertBlock"; then
|
||||||
mo::debug "Block is truthy: $moResult"
|
mo::debug "Block is truthy: $moResult"
|
||||||
mo::parse moParseResult "$moContent" "${moArgs[1]}" "${moArgs[1]}" "$moOpenDelimiter" "$moCloseDelimiter" "" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "${moArgs[1]}" "${moArgs[1]}" ""
|
||||||
moResult="${moParseResult[0]}"
|
moResult="${moParseResult[0]}"
|
||||||
else
|
else
|
||||||
mo::debug "Block is falsy: $moResult"
|
mo::debug "Block is falsy: $moResult"
|
||||||
mo::parse moParseResult "$moContent" "${moArgs[1]}" "${moArgs[1]}" "$moOpenDelimiter" "$moCloseDelimiter" "FAST-FALSY" "$moStandaloneContent"
|
mo::parse moParseResult "$moContent" "${moArgs[1]}" "${moArgs[1]}" "FAST-FALSY"
|
||||||
moResult=""
|
moResult=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
moContent=${moParseResult[1]}
|
moContent=${moParseResult[1]}
|
||||||
moStandaloneContent=${moParseResult[2]}
|
|
||||||
mo::debug "Done parsing block value: ${moArgs[*]}"
|
mo::debug "Done parsing block value: ${moArgs[*]}"
|
||||||
|
|
||||||
local "$moTarget" && mo::indirectArray "$moTarget" "$moResult" "$moContent" "$moStandaloneContent"
|
local "$moTarget" && mo::indirectArray "$moTarget" "$moResult" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -751,14 +724,11 @@ mo::parseBlockValue() {
|
|||||||
# $2 - Previously parsed
|
# $2 - Previously parsed
|
||||||
# $3 - Content
|
# $3 - Content
|
||||||
# $4 - Current name (the variable NAME for what {{.}} means)
|
# $4 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $5 - Close delimiter for the current tag
|
# $5 - Fast mode (skip to end of block) if non-empty
|
||||||
# $6 - Fast mode (skip to end of block) if non-empty
|
|
||||||
# $7 - Standalone content
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
#
|
#
|
||||||
# Indentation will be applied to the entire partial's contents that are
|
# Indentation will be applied to the entire partial's contents that are
|
||||||
# returned. This indentation is based on the whitespace that ends the
|
# returned. This indentation is based on the whitespace that ends the
|
||||||
@ -766,19 +736,19 @@ mo::parseBlockValue() {
|
|||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parsePartial() {
|
mo::parsePartial() {
|
||||||
local moContent moCurrent moCloseDelimiter moFilename moResult moFastMode moPrevious moStandaloneContent moIndentation moN moR
|
local moContent moCurrent moFilename moResult moFastMode moPrevious moIndentation moN moR
|
||||||
|
|
||||||
moPrevious=$2
|
moPrevious=$2
|
||||||
mo::trim moContent "${3:1}"
|
mo::trim moContent "${3:1}"
|
||||||
moCurrent=$4
|
moCurrent=$4
|
||||||
moCloseDelimiter=$5
|
moFastMode=$5
|
||||||
moFastMode=$6
|
# shellcheck disable=SC2031
|
||||||
moStandaloneContent=$7
|
mo::chomp moFilename "${moContent%%"$MO_CLOSE_DELIMITER"*}"
|
||||||
mo::chomp moFilename "${moContent%%"$moCloseDelimiter"*}"
|
# shellcheck disable=SC2031
|
||||||
moContent="${moContent#*"$moCloseDelimiter"}"
|
moContent="${moContent#*"$MO_CLOSE_DELIMITER"}"
|
||||||
moIndentation=""
|
moIndentation=""
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moContent"; then
|
||||||
moN=$'\n'
|
moN=$'\n'
|
||||||
moR=$'\r'
|
moR=$'\r'
|
||||||
moIndentation="$moN${moPrevious//"$moR"/"$moN"}"
|
moIndentation="$moN${moPrevious//"$moR"/"$moN"}"
|
||||||
@ -786,9 +756,6 @@ mo::parsePartial() {
|
|||||||
mo::debug "Adding indentation to partial: '$moIndentation'"
|
mo::debug "Adding indentation to partial: '$moIndentation'"
|
||||||
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
||||||
mo::standaloneProcessAfter moContent "$moContent"
|
mo::standaloneProcessAfter moContent "$moContent"
|
||||||
moStandaloneContent=$'\n'
|
|
||||||
else
|
|
||||||
moStandaloneContent=""
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$moFastMode" ]]; then
|
if [[ -n "$moFastMode" ]]; then
|
||||||
@ -809,7 +776,13 @@ mo::parsePartial() {
|
|||||||
mo::indentLines moResult "$moResult" "$moIndentation"
|
mo::indentLines moResult "$moResult" "$moIndentation"
|
||||||
|
|
||||||
# Delimiters are reset when loading a new partial
|
# Delimiters are reset when loading a new partial
|
||||||
mo::parse moResult "$moResult" "$moCurrent" "" "{{" "}}" "" $'\n'
|
# shellcheck disable=SC2030
|
||||||
|
MO_OPEN_DELIMITER="{{"
|
||||||
|
# shellcheck disable=SC2030
|
||||||
|
MO_CLOSE_DELIMITER="}}"
|
||||||
|
# shellcheck disable=SC2030
|
||||||
|
MO_STANDALONE_CONTENT=""
|
||||||
|
mo::parse moResult "$moResult" "$moCurrent" "" ""
|
||||||
|
|
||||||
# Fix bash handling of subshells and keep trailing whitespace.
|
# Fix bash handling of subshells and keep trailing whitespace.
|
||||||
echo -n "${moResult[0]}${moResult[1]}."
|
echo -n "${moResult[0]}${moResult[1]}."
|
||||||
@ -824,7 +797,7 @@ mo::parsePartial() {
|
|||||||
moResult=${moResult%.}
|
moResult=${moResult%.}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local "$1" && mo::indirectArray "$1" "$moPrevious$moResult" "$moContent" "$moStandaloneContent"
|
local "$1" && mo::indirectArray "$1" "$moPrevious$moResult" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -834,36 +807,29 @@ mo::parsePartial() {
|
|||||||
# $2 - Previous content
|
# $2 - Previous content
|
||||||
# $3 - Content
|
# $3 - Content
|
||||||
# $4 - Current name (the variable NAME for what {{.}} means)
|
# $4 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $5 - Close delimiter for the current tag
|
# $5 - Current block being processed
|
||||||
# $6 - Current block being processed
|
|
||||||
# $7 - Standalone content
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text ($2)
|
# [0] = the result text ($2)
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter (nothing)
|
# [1] = remaining content to parse, excluding the closing delimiter (nothing)
|
||||||
# [2] = standalone content trick
|
|
||||||
# [3] = unparsed content outside of the block (the remainder)
|
# [3] = unparsed content outside of the block (the remainder)
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::parseCloseTag() {
|
mo::parseCloseTag() {
|
||||||
local moContent moArgs moCurrent moCloseDelimiter moCurrentBlock moPrevious moStandaloneContent
|
local moContent moArgs moCurrent moCurrentBlock moPrevious
|
||||||
|
|
||||||
moPrevious=$2
|
moPrevious=$2
|
||||||
mo::trim moContent "${3:1}"
|
mo::trim moContent "${3:1}"
|
||||||
moCurrent=$4
|
moCurrent=$4
|
||||||
moCloseDelimiter=$5
|
moCurrentBlock=$5
|
||||||
moCurrentBlock=$6
|
mo::parseValueInner moArgs "$moContent" "$moCurrent"
|
||||||
moStandaloneContent=$7
|
# shellcheck disable=SC2031
|
||||||
mo::parseValueInner moArgs "$moContent" "$moCurrent" "$moCloseDelimiter"
|
moContent="${moArgs[0]#"$MO_CLOSE_DELIMITER"}"
|
||||||
moContent="${moArgs[0]#$moCloseDelimiter}"
|
|
||||||
mo::debug "Closing tag: ${moArgs[2]}"
|
mo::debug "Closing tag: ${moArgs[2]}"
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moContent"; then
|
||||||
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
||||||
mo::standaloneProcessAfter moContent "$moContent"
|
mo::standaloneProcessAfter moContent "$moContent"
|
||||||
moStandaloneContent=$'\n'
|
|
||||||
else
|
|
||||||
moStandaloneContent=""
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$moCurrentBlock" ]] && [[ "${moArgs[2]}" != "$moCurrentBlock" ]]; then
|
if [[ -n "$moCurrentBlock" ]] && [[ "${moArgs[2]}" != "$moCurrentBlock" ]]; then
|
||||||
@ -872,7 +838,7 @@ mo::parseCloseTag() {
|
|||||||
mo::error "Unexpected close tag: ${moArgs[2]}"
|
mo::error "Unexpected close tag: ${moArgs[2]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local "$1" && mo::indirectArray "$1" "$moPrevious" "" "$moStandaloneContent" "$moContent"
|
local "$1" && mo::indirectArray "$1" "$moPrevious" "" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -881,34 +847,27 @@ mo::parseCloseTag() {
|
|||||||
# $1 - Destination variable name, will be set to an array
|
# $1 - Destination variable name, will be set to an array
|
||||||
# $2 - Previous content
|
# $2 - Previous content
|
||||||
# $3 - Content
|
# $3 - Content
|
||||||
# $4 - Close delimiter for the current tag
|
|
||||||
# $5 - Standalone content
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseComment() {
|
mo::parseComment() {
|
||||||
local moContent moCloseDelimiter moStandaloneContent moPrevious moContent moCloseDelimiter
|
local moContent moPrevious moContent
|
||||||
|
|
||||||
moPrevious=$2
|
moPrevious=$2
|
||||||
moContent=$3
|
moContent=$3
|
||||||
moCloseDelimiter=$4
|
# shellcheck disable=SC2031
|
||||||
moStandaloneContent=$5
|
moContent=${moContent#*"$MO_CLOSE_DELIMITER"}
|
||||||
moContent=${moContent#*"$moCloseDelimiter"}
|
|
||||||
mo::debug "Parsing comment"
|
mo::debug "Parsing comment"
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moContent"; then
|
||||||
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
||||||
mo::standaloneProcessAfter moContent "$moContent"
|
mo::standaloneProcessAfter moContent "$moContent"
|
||||||
moStandaloneContent=$'\n'
|
|
||||||
else
|
|
||||||
moStandaloneContent=""
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local "$1" && mo::indirectArray "$1" "$moPrevious" "$moContent" "$moStandaloneContent"
|
local "$1" && mo::indirectArray "$1" "$moPrevious" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -917,40 +876,35 @@ mo::parseComment() {
|
|||||||
# $1 - Destination variable name, will be set to an array
|
# $1 - Destination variable name, will be set to an array
|
||||||
# $2 - Previous content
|
# $2 - Previous content
|
||||||
# $3 - Content
|
# $3 - Content
|
||||||
# $4 - Close delimiter for the current tag
|
|
||||||
# $5 - Standalone content
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
# [3] = new open delimiter
|
|
||||||
# [4] = new close delimiter
|
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseDelimiter() {
|
mo::parseDelimiter() {
|
||||||
local moContent moCloseDelimiter moOpen moClose moPrevious moStandaloneContent
|
local moContent moOpen moClose moPrevious
|
||||||
|
|
||||||
moPrevious=$2
|
moPrevious=$2
|
||||||
mo::trim moContent "${3#=}"
|
mo::trim moContent "${3#=}"
|
||||||
moCloseDelimiter=$4
|
|
||||||
moStandaloneContent=$5
|
|
||||||
mo::chomp moOpen "$moContent"
|
mo::chomp moOpen "$moContent"
|
||||||
moContent=${moContent:${#moOpen}}
|
moContent=${moContent:${#moOpen}}
|
||||||
mo::trim moContent "$moContent"
|
mo::trim moContent "$moContent"
|
||||||
mo::chomp moClose "${moContent%%="$moCloseDelimiter"*}"
|
# shellcheck disable=SC2031
|
||||||
moContent=${moContent#*="$moCloseDelimiter"}
|
mo::chomp moClose "${moContent%%="$MO_CLOSE_DELIMITER"*}"
|
||||||
|
# shellcheck disable=SC2031
|
||||||
|
moContent=${moContent#*="$MO_CLOSE_DELIMITER"}
|
||||||
mo::debug "Parsing delimiters: $moOpen $moClose"
|
mo::debug "Parsing delimiters: $moOpen $moClose"
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moContent"; then
|
||||||
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
||||||
mo::standaloneProcessAfter moContent "$moContent"
|
mo::standaloneProcessAfter moContent "$moContent"
|
||||||
moStandaloneContent=$'\n'
|
|
||||||
else
|
|
||||||
moStandaloneContent=""
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local "$1" && mo::indirectArray "$1" "$moPrevious" "$moContent" "$moStandaloneContent" "$moOpen" "$moClose"
|
MO_OPEN_DELIMITER="$moOpen"
|
||||||
|
MO_CLOSE_DELIMITER="$moClose"
|
||||||
|
|
||||||
|
local "$1" && mo::indirectArray "$1" "$moPrevious" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -960,28 +914,23 @@ mo::parseDelimiter() {
|
|||||||
# $2 - Previous content
|
# $2 - Previous content
|
||||||
# $3 - Content
|
# $3 - Content
|
||||||
# $4 - Current name (the variable NAME for what {{.}} means)
|
# $4 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $5 - Open delimiter for the current tag
|
|
||||||
# $6 - Close delimiter for the current tag
|
|
||||||
# $7 - Fast mode (skip to end of block) if non-empty
|
# $7 - Fast mode (skip to end of block) if non-empty
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = the result text
|
# [0] = the result text
|
||||||
# [1] = remaining content to parse, excluding the closing delimiter
|
# [1] = remaining content to parse, excluding the closing delimiter
|
||||||
# [2] = standalone content trick
|
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseValue() {
|
mo::parseValue() {
|
||||||
local moContent moContentOriginal moOpenDelimiter moCurrent moCloseDelimiter moArgs moResult moFastMode moPrevious
|
local moContent moContentOriginal moCurrent moArgs moResult moFastMode moPrevious
|
||||||
|
|
||||||
moPrevious=$2
|
moPrevious=$2
|
||||||
moContentOriginal=$3
|
moContentOriginal=$3
|
||||||
moCurrent=$4
|
moCurrent=$4
|
||||||
moOpenDelimiter=$5
|
moFastMode=$5
|
||||||
moCloseDelimiter=$6
|
mo::trim moContent "${moContentOriginal#"$MO_OPEN_DELIMITER"}"
|
||||||
moFastMode=$7
|
|
||||||
mo::trim moContent "${moContentOriginal#"$moOpenDelimiter"}"
|
|
||||||
|
|
||||||
mo::parseValueInner moArgs "$moContent" "$moCurrent" "$moCloseDelimiter"
|
mo::parseValueInner moArgs "$moContent" "$moCurrent"
|
||||||
moContent=${moArgs[0]}
|
moContent=${moArgs[0]}
|
||||||
moArgs=("${moArgs[@]:1}")
|
moArgs=("${moArgs[@]:1}")
|
||||||
|
|
||||||
@ -991,13 +940,13 @@ mo::parseValue() {
|
|||||||
mo::evaluate moResult "$moCurrent" "${moArgs[@]}"
|
mo::evaluate moResult "$moCurrent" "${moArgs[@]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${moContent:0:${#moCloseDelimiter}}" != "$moCloseDelimiter" ]]; then
|
if [[ "${moContent:0:${#MO_CLOSE_DELIMITER}}" != "$MO_CLOSE_DELIMITER" ]]; then
|
||||||
mo::error "Did not find closing tag near: $moContentOriginal"
|
mo::error "Did not find closing tag near: $moContentOriginal"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
moContent=${moContent:${#moCloseDelimiter}}
|
moContent=${moContent:${#MO_CLOSE_DELIMITER}}
|
||||||
|
|
||||||
local "$1" && mo::indirectArray "$1" "$moPrevious$moResult" "$moContent" ""
|
local "$1" && mo::indirectArray "$1" "$moPrevious$moResult" "$moContent"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1006,23 +955,21 @@ mo::parseValue() {
|
|||||||
# $1 - Destination variable name, will be set to an array
|
# $1 - Destination variable name, will be set to an array
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Current name (the variable NAME for what {{.}} means)
|
# $3 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $4 - Close delimiter for the current tag
|
|
||||||
#
|
#
|
||||||
# The destination value will be an array
|
# The destination value will be an array
|
||||||
# [0] = remaining content to parse, including the closing delimiter
|
# [0] = remaining content to parse, including the closing delimiter
|
||||||
# [1-*] = a list of argument type, argument name/value
|
# [1-@] = a list of argument type, argument name/value
|
||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::parseValueInner() {
|
mo::parseValueInner() {
|
||||||
local moContent moCurrent moCloseDelimiter moArgs moArgResult moResult
|
local moContent moCurrent moArgs moArgResult moResult
|
||||||
|
|
||||||
moContent=$2
|
moContent=$2
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moCloseDelimiter=$4
|
|
||||||
moArgs=()
|
moArgs=()
|
||||||
|
|
||||||
while [[ "$moContent" != "$moCloseDelimiter"* ]] && [[ "$moContent" != "}"* ]] && [[ "$moContent" != ")"* ]] && [[ -n "$moContent" ]]; do
|
while [[ "$moContent" != "$MO_CLOSE_DELIMITER"* ]] && [[ "$moContent" != "}"* ]] && [[ "$moContent" != ")"* ]] && [[ -n "$moContent" ]]; do
|
||||||
mo::getArgument moArgResult "$moCurrent" "$moContent" "$moCloseDelimiter"
|
mo::getArgument moArgResult "$moCurrent" "$moContent"
|
||||||
moArgs=(${moArgs[@]+"${moArgs[@]}"} "${moArgResult[0]}" "${moArgResult[1]}")
|
moArgs=(${moArgs[@]+"${moArgs[@]}"} "${moArgResult[0]}" "${moArgResult[1]}")
|
||||||
mo::trim moContent "${moArgResult[2]}"
|
mo::trim moContent "${moArgResult[2]}"
|
||||||
done
|
done
|
||||||
@ -1037,7 +984,6 @@ mo::parseValueInner() {
|
|||||||
#
|
#
|
||||||
# $1 - Destination variable name. Will be an array.
|
# $1 - Destination variable name. Will be an array.
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Closing delimiter
|
|
||||||
#
|
#
|
||||||
# The array will have the following elements
|
# The array will have the following elements
|
||||||
# [0] = argument type, "NAME" or "VALUE"
|
# [0] = argument type, "NAME" or "VALUE"
|
||||||
@ -1046,19 +992,18 @@ mo::parseValueInner() {
|
|||||||
#
|
#
|
||||||
# Returns nothing
|
# Returns nothing
|
||||||
mo::getArgument() {
|
mo::getArgument() {
|
||||||
local moContent moCurrent moClosingDelimiter moArg
|
local moContent moCurrent moArg
|
||||||
|
|
||||||
moCurrent=$2
|
moCurrent=$2
|
||||||
moContent=$3
|
moContent=$3
|
||||||
moClosingDelimiter=$4
|
|
||||||
|
|
||||||
case "$moContent" in
|
case "$moContent" in
|
||||||
'{'*)
|
'{'*)
|
||||||
mo::getArgumentBrace moArg "$moContent" "$moCurrent" "$moClosingDelimiter"
|
mo::getArgumentBrace moArg "$moContent" "$moCurrent"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'('*)
|
'('*)
|
||||||
mo::getArgumentParenthesis moArg "$moContent" "$moCurrent" "$moClosingDelimiter"
|
mo::getArgumentParenthesis moArg "$moContent" "$moCurrent"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'"'*)
|
'"'*)
|
||||||
@ -1070,7 +1015,7 @@ mo::getArgument() {
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
mo::getArgumentDefault moArg "$moContent" "$moClosingDelimiter"
|
mo::getArgumentDefault moArg "$moContent"
|
||||||
esac
|
esac
|
||||||
|
|
||||||
mo::debug "Found argument: ${moArg[0]} ${moArg[1]}"
|
mo::debug "Found argument: ${moArg[0]} ${moArg[1]}"
|
||||||
@ -1084,7 +1029,6 @@ mo::getArgument() {
|
|||||||
# $1 - Destination variable name, an array with two elements
|
# $1 - Destination variable name, an array with two elements
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Current name (the variable NAME for what {{.}} means)
|
# $3 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $4 - Close delimiter for the current tag
|
|
||||||
#
|
#
|
||||||
# The array has the following elements.
|
# The array has the following elements.
|
||||||
# [0] = argument type, "NAME" or "VALUE"
|
# [0] = argument type, "NAME" or "VALUE"
|
||||||
@ -1093,12 +1037,11 @@ mo::getArgument() {
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::getArgumentBrace() {
|
mo::getArgumentBrace() {
|
||||||
local moResult moContent moCurrent moCloseDelimiter moArgs
|
local moResult moContent moCurrent moArgs
|
||||||
|
|
||||||
mo::trim moContent "${2:1}"
|
mo::trim moContent "${2:1}"
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moCloseDelimiter=$4
|
mo::parseValueInner moResult "$moContent" "$moCurrent"
|
||||||
mo::parseValueInner moResult "$moContent" "$moCurrent" "$moCloseDelimiter"
|
|
||||||
moContent="${moResult[0]}"
|
moContent="${moResult[0]}"
|
||||||
moArgs=("${moResult[@]:1}")
|
moArgs=("${moResult[@]:1}")
|
||||||
mo::evaluate moResult "$moCurrent" "${moArgs[@]}"
|
mo::evaluate moResult "$moCurrent" "${moArgs[@]}"
|
||||||
@ -1118,7 +1061,6 @@ mo::getArgumentBrace() {
|
|||||||
# $1 - Destination variable name, an array with two elements
|
# $1 - Destination variable name, an array with two elements
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Current name (the variable NAME for what {{.}} means)
|
# $3 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $4 - Close delimiter for the current tag
|
|
||||||
#
|
#
|
||||||
# The array has the following elements.
|
# The array has the following elements.
|
||||||
# [0] = argument type, "NAME" or "VALUE"
|
# [0] = argument type, "NAME" or "VALUE"
|
||||||
@ -1127,12 +1069,11 @@ mo::getArgumentBrace() {
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::getArgumentParenthesis() {
|
mo::getArgumentParenthesis() {
|
||||||
local moResult moContent moCurrent moCloseDelimiter
|
local moResult moContent moCurrent
|
||||||
|
|
||||||
mo::trim moContent "${2:1}"
|
mo::trim moContent "${2:1}"
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moCloseDelimiter=$4
|
mo::parseValueInner moResult "$moContent" "$moCurrent"
|
||||||
mo::parseValueInner moResult "$moContent" "$moCurrent" "$moCloseDelimiter"
|
|
||||||
moContent="${moResult[1]}"
|
moContent="${moResult[1]}"
|
||||||
|
|
||||||
if [[ "${moContent:0:1}" != ")" ]]; then
|
if [[ "${moContent:0:1}" != ")" ]]; then
|
||||||
@ -1237,7 +1178,6 @@ mo::getArgumentSingleQuote() {
|
|||||||
#
|
#
|
||||||
# $1 - Destination variable name, an array with two elements
|
# $1 - Destination variable name, an array with two elements
|
||||||
# $2 - Content
|
# $2 - Content
|
||||||
# $3 - Closing delimiter
|
|
||||||
#
|
#
|
||||||
# The array has the following elements.
|
# The array has the following elements.
|
||||||
# [0] = argument type, "NAME" or "VALUE"
|
# [0] = argument type, "NAME" or "VALUE"
|
||||||
@ -1249,7 +1189,7 @@ mo::getArgumentDefault() {
|
|||||||
local moTemp moContent
|
local moTemp moContent
|
||||||
|
|
||||||
moTemp=$2
|
moTemp=$2
|
||||||
mo::chomp moTemp "${moTemp%%"$3"*}"
|
mo::chomp moTemp "${moTemp%%"$MO_CLOSE_DELIMITER"*}"
|
||||||
moTemp=${moTemp%%)*}
|
moTemp=${moTemp%%)*}
|
||||||
moTemp=${moTemp%%\}*}
|
moTemp=${moTemp%%\}*}
|
||||||
moContent=${2:${#moTemp}}
|
moContent=${2:${#moTemp}}
|
||||||
@ -1408,7 +1348,7 @@ mo::isTruthy() {
|
|||||||
#
|
#
|
||||||
# $1 - Destination variable name
|
# $1 - Destination variable name
|
||||||
# $2 - Current name (the variable NAME for what {{.}} means)
|
# $2 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $3-$* - A list of argument types and argument name/value.
|
# $3-@ - A list of argument types and argument name/value.
|
||||||
#
|
#
|
||||||
# Sample call:
|
# Sample call:
|
||||||
#
|
#
|
||||||
@ -1439,7 +1379,7 @@ mo::evaluate() {
|
|||||||
#
|
#
|
||||||
# $1 - Destination variable name
|
# $1 - Destination variable name
|
||||||
# $2 - Current name (the variable NAME for what {{.}} means)
|
# $2 - Current name (the variable NAME for what {{.}} means)
|
||||||
# $3-$* - A list of argument types and argument name/value.
|
# $3-@ - A list of argument types and argument name/value.
|
||||||
#
|
#
|
||||||
# This assumes each value is separate from the rest. In contrast, mo::evaluate
|
# This assumes each value is separate from the rest. In contrast, mo::evaluate
|
||||||
# will pass all arguments to a function if the first value is a function.
|
# will pass all arguments to a function if the first value is a function.
|
||||||
@ -1618,7 +1558,7 @@ mo::findVariableName() {
|
|||||||
#
|
#
|
||||||
# $1 - Variable name to receive the joined content
|
# $1 - Variable name to receive the joined content
|
||||||
# $2 - Joiner
|
# $2 - Joiner
|
||||||
# $3-$* - Elements to join
|
# $3-@ - Elements to join
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::join() {
|
mo::join() {
|
||||||
@ -1642,7 +1582,7 @@ mo::join() {
|
|||||||
# $1 - Variable for output
|
# $1 - Variable for output
|
||||||
# $2 - Content to pass
|
# $2 - Content to pass
|
||||||
# $3 - Function to call
|
# $3 - Function to call
|
||||||
# $4-$* - Additional arguments as list of type, value/name
|
# $4-@ - Additional arguments as list of type, value/name
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::evaluateFunction() {
|
mo::evaluateFunction() {
|
||||||
@ -1692,8 +1632,7 @@ mo::evaluateFunction() {
|
|||||||
# it on a line. There must be a new line before (see the trick in mo::parse)
|
# it on a line. There must be a new line before (see the trick in mo::parse)
|
||||||
# and there must be a newline after or the end of a string
|
# and there must be a newline after or the end of a string
|
||||||
#
|
#
|
||||||
# $1 - Standalone content that was processed in this loop
|
# $1 - Content after the tag
|
||||||
# $2 - Content after the tag
|
|
||||||
#
|
#
|
||||||
# Returns 0 if this is a standalone tag, 1 otherwise.
|
# Returns 0 if this is a standalone tag, 1 otherwise.
|
||||||
mo::standaloneCheck() {
|
mo::standaloneCheck() {
|
||||||
@ -1704,7 +1643,11 @@ mo::standaloneCheck() {
|
|||||||
moT=$'\t'
|
moT=$'\t'
|
||||||
|
|
||||||
# Check the content before
|
# Check the content before
|
||||||
moContent=${1//"$moR"/"$moN"}
|
# shellcheck disable=SC2031
|
||||||
|
moContent=${MO_STANDALONE_CONTENT//"$moR"/"$moN"}
|
||||||
|
|
||||||
|
# By default, signal to the next check that this one failed
|
||||||
|
MO_STANDALONE_CONTENT=""
|
||||||
|
|
||||||
if [[ "$moContent" != *"$moN"* ]]; then
|
if [[ "$moContent" != *"$moN"* ]]; then
|
||||||
mo::debug "Not a standalone tag - no newline before"
|
mo::debug "Not a standalone tag - no newline before"
|
||||||
@ -1723,7 +1666,7 @@ mo::standaloneCheck() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check the content after
|
# Check the content after
|
||||||
moContent=${2//"$moR"/"$moN"}
|
moContent=${1//"$moR"/"$moN"}
|
||||||
moContent=${moContent%%"$moN"*}
|
moContent=${moContent%%"$moN"*}
|
||||||
moContent=${moContent//"$moT"/}
|
moContent=${moContent//"$moT"/}
|
||||||
moContent=${moContent// /}
|
moContent=${moContent// /}
|
||||||
@ -1734,6 +1677,9 @@ mo::standaloneCheck() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Signal to the next check that this tag removed content
|
||||||
|
MO_STANDALONE_CONTENT=$'\n'
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ Mo uses the following environment variables:
|
|||||||
MO_ALLOW_FUNCTION_ARGUMENTS - When set to a non-empty value, this allows
|
MO_ALLOW_FUNCTION_ARGUMENTS - When set to a non-empty value, this allows
|
||||||
functions referenced in templates to receive additional options and
|
functions referenced in templates to receive additional options and
|
||||||
arguments.
|
arguments.
|
||||||
|
MO_CLOSE_DELIMITER - The string used when closing a tag. Defaults to "}}".
|
||||||
MO_DEBUG - When set to a non-empty value, additional debug information is
|
MO_DEBUG - When set to a non-empty value, additional debug information is
|
||||||
written to stderr.
|
written to stderr.
|
||||||
MO_FUNCTION_ARGS - Arguments passed to the function.
|
MO_FUNCTION_ARGS - Arguments passed to the function.
|
||||||
@ -64,8 +65,13 @@ MO_FAIL_ON_UNSET - When set to a non-empty value, expansion of an unset env
|
|||||||
variable will be aborted with an error.
|
variable will be aborted with an error.
|
||||||
MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" will
|
MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" will
|
||||||
be treated as an empty value for the purposes of conditionals.
|
be treated as an empty value for the purposes of conditionals.
|
||||||
|
MO_OPEN_DELIMITER - The string used when opening a tag. Defaults to "{{".
|
||||||
MO_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a
|
MO_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a
|
||||||
help message.
|
help message.
|
||||||
|
MO_STANDALONE_CONTENT - The content that preceeded the current tag. When a
|
||||||
|
standalone tag is encountered, this is checked to see if it only
|
||||||
|
contains whitespace. If this and the whitespace condition after a tag is
|
||||||
|
met, then this will be reset to $'\n'.
|
||||||
|
|
||||||
Mo is under a MIT style licence with an additional non-advertising clause.
|
Mo is under a MIT style licence with an additional non-advertising clause.
|
||||||
See LICENSE.md for the full text.
|
See LICENSE.md for the full text.
|
||||||
|
@ -4,14 +4,14 @@ cd "${0%/*}" || exit 1
|
|||||||
|
|
||||||
export content=$'<\n->'
|
export content=$'<\n->'
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<'EOF'
|
||||||
\
|
\
|
||||||
{{>fixtures/standalone-indentation.partial}}
|
{{>fixtures/standalone-indentation.partial}}
|
||||||
/
|
/
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
expected() {
|
||||||
cat <<EOF
|
cat <<'EOF'
|
||||||
\
|
\
|
||||||
|
|
|
|
||||||
<
|
<
|
||||||
|
Loading…
Reference in New Issue
Block a user