Files
dotwryn/setup/filesystem/write-managed-block.zsh
T

102 lines
2.7 KiB
Bash
Raw Normal View History

2026-09-21 06:48:49 -06:00
#####################################################################
setup.filesystem.write-managed-block() {
# replaces (or appends) a dotwryn-managed block in a file, taking the
# block body from stdin, so that every run refreshes the block rather
# than appending another copy of it
#
# callers should use a "<<-" heredoc: it strips leading TABS (letting
# the body stay indented with its caller) but leaves SPACES alone, so
# indent the block's own nesting with spaces to keep it in the output
#
# "--one-line" trades the begin/end banner for a trailing comment on
# the line itself, which suits a one-line entry like an rc source
local file tag
local comment='#'
local one_line=false
local _s _p
while [[ "${#}" -gt 0 ]]
do
_s=1
case "${1}" in
( --comment ) _s=2
comment="${2}"
;;
( --tag ) _s=2
tag="${2}"
;;
( --one-line )
one_line=true
;;
( * )
case "$((_p+=1))" in
( 1 ) file="${1}" ;;
( * ) echo.error "write-managed-block: unexpected argument '${1}'" ;;
esac
;;
esac
shift "${_s}"
done
unset _s _p
[[ "${file}" ]] \
|| echo.error 'write-managed-block: no file given' \
|| return 1
# a single file can carry several managed blocks, so each one has to be
# named to know which of them it owns
[[ "${tag}" ]] \
|| echo.error "write-managed-block: no --tag given for '${file}'" \
|| return 1
local body="$(cat)"
[[ "${one_line}" == false ]] || [[ "${body}" != *$'\n'* ]] \
|| echo.error "write-managed-block: --one-line needs a single-line body for '${file}'" \
|| return 1
mkdir -p -- "${file:h}"
touch -- "${file}"
local -a lines block
lines=("${(@f)$(<"${file}")}")
[[ -s "${file}" ]] || lines=()
# an existing block is replaced where it sits, so anything the user
# wrote around it keeps its position
local begin_index end_index
case "${one_line}" in
( true )
local marker="${comment} managed by dotwryn setup (${tag})"
block=("${body} ${marker}")
# "(b)" keeps the tag's parentheses literal rather than glob
begin_index="${lines[(i)*${(b)marker}]}"
end_index="${begin_index}"
;;
( false )
local begin="${comment} >>> managed by dotwryn setup (${tag}) >>>"
local end="${comment} <<< managed by dotwryn setup (${tag}) <<<"
block=("${begin}" "${(@f)body}" "${end}")
begin_index="${lines[(ie)${begin}]}"
end_index="${lines[(ie)${end}]}"
[[ "${end_index}" -le "${#lines[@]}" ]] || end_index="${#lines[@]}"
;;
esac
if [[ "${begin_index}" -gt "${#lines[@]}" ]]
then
lines+=("${block[@]}")
else
lines=(
"${lines[@]:0:$((begin_index - 1))}"
"${block[@]}"
"${lines[@]:${end_index}}"
)
fi
print -l -- "${lines[@]}" > "${file}"
}