<commit_before>#!/bin/zsh

# find where we're being called from
if [[ -z "$ZBLOG_INSTALL_DIR" ]]; then
	ZBLOG_INSTALL_DIR=${0:h}

	if [[ "${ZBLOG_INSTALL_DIR:0:1}" != "/" && "${ZBLOG_INSTALL_DIR:0:1}" != "~" ]]; then
		ZBLOG_INSTALL_DIR=$PWD/$ZBLOG_INSTALL_DIR
	fi
fi

# find an editor and run it
function _zb_edit {
	local editor editors edited
	editors=(pico nano vim ed)
	editors=()

	if [[ ! -z $EDITOR && -x $(which $EDITOR) ]]; then
		_zb_synedit $EDITOR $1
		return 0
	fi

	print '$EDITOR not set or missing -- trying some defaults.'

	if ! _zb_synedit "$(which $editors > /dev/null | grep -m 1 /)" $1; then
		print 'Could not find an editor.'
		return 1
	fi
}

function _zb_synedit {
	[[ $1 = vim ]] && vim -c 'source $ZBLOG_INSTALL_DIR/syntax/zblog.vim' $2 && return 0
	[[ ! -z $1 ]] && $1 $2
}

# escape some things that could break links, titles, etc
function _zb_escape {
	sed "	s/&/\&amp;/g;
		s/\"/\&quot;/g;
		s/'/\&apos;/g;
		s/</\&lt;/g;
		s/>/\&gt;/g;"
}

# super short templating engine -- uses ZSH variable expansion, because it's fancy like that
function _zb_template {
	print -r -- "${(e)"$(<$ZBLOG_INSTALL_DIR/templates/themes/default/$1)"//\\/\\\\}"
}

# look up some help for a command
function _zb_help {
	local help
	help=${1:-main}
	[[ ! -f $ZBLOG_INSTALL_DIR/help/$help ]] && print "blog: No help for '$1'" || cat $ZBLOG_INSTALL_DIR/help/$help
}

function _zb_path {
	_zb_path=$1
}

function _zb_link {
	_zb_link=$1
	local slash=0 i=0 link

	while [[ $((i++)) -lt ${#_zb_path} ]]; do
		if [[ $_zb_link[0,$i] = $_zb_path[0,$i] && $_zb_link[$i] = / ]]; then
			slash=$i
			link=$_zb_path[$((i+1)),$((${#_zb_path}-1))]
			regexp-replace link '[^/]+' '..'
			link=${link:-.}$_zb_link[$i,${#_zb_link}]
		fi
	done

	print $link
}

function _zb_permalink {
	local post
	post=${1#*-}
	[[ ! -f $ZBWD/content/posts/$post ]] && return 0
	print -- $blog[root]/archives/$(date -d "$(_zb_field date $post)" +'%Y/%m/%d')/$(print $(_zb_field title $post) | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9.-]\+/-/ig; s/^-\|-$//g')/\
		| sed 's/\/\+/\//g;'
}

# parse zblog-format posts, or load post from cache
function _zb_parse_post {
	local postid headers preview body
	postid=${1#*-}
	file=$ZBWD/content/posts/$postid

	if [[ -f $ZBWD/content/cache/parser/$postid ]]; then
		eval $(<$ZBWD/content/cache/parser/$postid)
		return
	fi

	body=$(<$ZBWD/content/posts/$postid)
	headers=$body

	regexp-replace headers '\n-{4,}\n(\n|.)*' ''

	regexp-replace body '(\n|.)*\n-{4,}\n' ''
	regexp-replace body '\n' '<br>'$'\n'
	regexp-replace body '<br>\n~{4,}(<br>|\s)*$' ''

	preview=$body
	regexp-replace preview '\n~{4,}(<br>(\n|.)*|$)' ''

	regexp-replace body '<br>\n~{4,}(<br>|$)' '<br><br>'

	post=(
		'id'		$postid
		'title'		"$(_zb_field title $file)"
		'tags'		"$(_zb_field tags $file)"
		'date'		"$(_zb_field date $file)"
		'author'	"$(_zb_field author $file)"
		'preview'	"$preview"
		'body'		"$body"
		'permalink'	"$(_zb_permalink $postid)"
		'flags'		"$(_zb_field flags $file)"
	)


	# set post_preview to post_body if the preview is empty
	# TODO: create a short version if the preview does not exist
	post[preview]=${post[preview]:-$post[body]}

	(print 'post=('
	for key in ${(k)post}; do
		print -r -- ${(qq)key} ${(qq)post[$key]}
	done
	print ')') > $ZBWD/content/cache/parser/$postid
}

# check if a flag exists for a post
# returns 1 if flag not found, 0 if found
function _zb_flag {
	flag=$1
	flags=$2

	if [[ -z $flags || ${${(s/, /)flags}[(r)$1]} == $1 ]]; then
		return 1
	fi
}

# get the value of a field in a post's header
function _zb_field {
	local file p postid post
	p=$ZBWD/content/posts/
	file=$2
	postid=${2#*-}

	[[ $file[0,1] = '/' ]] && p=''

	if [[ ! -z $p && -f $ZBWD/content/cache/parser/$postid ]]; then
		typeset -A post
		eval $(<$ZBWD/content/cache/parser/$postid)
		print $post[$1]
		return
	fi

	headers=$(<$p/$file)
	regexp-replace headers '[\n\r]-{4,}[\n\r]([\r\n]|.)*' ''
	h=$headers
	regexp-replace headers '^(([\n\r]|.)*[\n\r])?('$1':.*)([\n\r]([\n\r]|.)*)?$' '$match[3]'

	if [[ $headers = $h ]]; then
		headers="$1:"
	fi

	case $1 in
		tags|flags) regexp-replace headers '\s*(,)\s*|\s+' '$match[1] '
		      regexp-replace headers '^'$1':\s*(.*)\s*' '$match[1]';;
		*)    regexp-replace headers '^'$1':\s*(.*)\s*' '$match[1]';;
	esac

	print $headers
}

# helpter to autofill a field if it's missing or empty
function _zb_fieldnx {
	[[ -z "$(grep -E "^$2:" /tmp/zblog.tmp.$$ -m 1)" ]] && \
		sed -i 's/^\(-\{4,\}\)/'"$2"': \n\1/;' /tmp/zblog.tmp.$$

	[[ -z "$(grep -E "^$2:$1" /tmp/zblog.tmp.$$ -m 1)" ]] && \
		sed -i "s/^$2:.\+$/$2: $3/;" /tmp/zblog.tmp.$$
}

# ftp wrapper
function _zb_ftp {
	autoload -U zfinit; zfinit
	if zfopen -1 "$blog[ftp_host]" "$blog[ftp_user]" "$blog[ftp_pass]"; then
		if [[ -z $(zfls $blog[ftp_root]) ]] && zfmkdir
		zfcd $blog[ftp_root]
		zfput -r $ZBWD/content/blog/*
		zfclose
	fi
}

function _zb_sftp {
}

function _zb_archives {
	zmodload zsh/mathfunc
	local i pages p loc
	loc=$1
	i=0
	pages=$((ceil(${#posts}.0 / blog[posts])))
	while [[ $i -lt $pages ]]; do
		p=${${i/#%0/}:+p$i/}

		page[previous]=${p:+/$loc/${${p/#%p1\//}:+p$((i-1))/}}
		page[next]=${${$((pages - i - 1))/#%0./}:+/$loc/p$((i+1))/}

		fragment[posts]=$(xargs cat <<< ${(F)posts[$(((i * $blog[posts]) + 1)),$(((i * $blog[posts]) + $blog[posts]))]})
		page[content]=$(_zb_template content_post.html)

		mkdir -p $ZBWD/content/blog/$loc/$p
		_zb_template layout.html > $ZBWD/content/blog/$loc/${p}index.html

		(( i++ ))
	done
}

function _zb_dotfile {
}

# magic happens here
# should really go the route of _zb_blog-<action>, and turn this into a bit of a wrapper/setup function
function blog {
	local version=0.3-Alpha

	local ZBLOG opt _blog blog zblog link links content postid input post posts fragment page tags archives _zb_path _zb_link count fname tagpath weight

	emulate -L zsh
	autoload -U regexp-replace
	setopt rematchpcre
	setopt nonomatch

	typeset -A blog
	typeset -A zblog
	typeset -A content
	typeset -A post
	typeset -A fragment
	typeset -A page
	typeset -U archives
	typeset -A count
	typeset -A links

	ZBWD="$ZBLOG_INSTALL_DIR"

	zblog=(
		config  $ZBWD/blog.conf
		content $ZBWD/content/blog
		version $version
	)

	blog=(<commit_msg>Change ZBWD to ~/.zblog instead of $ZBLOG_INSTALL_DIR<commit_after>#!/bin/zsh

# find where we're being called from
if [[ -z "$ZBLOG_INSTALL_DIR" ]]; then
	ZBLOG_INSTALL_DIR=${0:h}

	if [[ "${ZBLOG_INSTALL_DIR:0:1}" != "/" && "${ZBLOG_INSTALL_DIR:0:1}" != "~" ]]; then
		ZBLOG_INSTALL_DIR=$PWD/$ZBLOG_INSTALL_DIR
	fi
fi

# find an editor and run it
function _zb_edit {
	local editor editors edited
	editors=(pico nano vim ed)
	editors=()

	if [[ ! -z $EDITOR && -x $(which $EDITOR) ]]; then
		_zb_synedit $EDITOR $1
		return 0
	fi

	print '$EDITOR not set or missing -- trying some defaults.'

	if ! _zb_synedit "$(which $editors > /dev/null | grep -m 1 /)" $1; then
		print 'Could not find an editor.'
		return 1
	fi
}

function _zb_synedit {
	[[ $1 = vim ]] && vim -c 'source $ZBLOG_INSTALL_DIR/syntax/zblog.vim' $2 && return 0
	[[ ! -z $1 ]] && $1 $2
}

# escape some things that could break links, titles, etc
function _zb_escape {
	sed "	s/&/\&amp;/g;
		s/\"/\&quot;/g;
		s/'/\&apos;/g;
		s/</\&lt;/g;
		s/>/\&gt;/g;"
}

# super short templating engine -- uses ZSH variable expansion, because it's fancy like that
function _zb_template {
	print -r -- "${(e)"$(<$ZBLOG_INSTALL_DIR/templates/themes/default/$1)"//\\/\\\\}"
}

# look up some help for a command
function _zb_help {
	local help
	help=${1:-main}
	[[ ! -f $ZBLOG_INSTALL_DIR/help/$help ]] && print "blog: No help for '$1'" || cat $ZBLOG_INSTALL_DIR/help/$help
}

function _zb_path {
	_zb_path=$1
}

function _zb_link {
	_zb_link=$1
	local slash=0 i=0 link

	while [[ $((i++)) -lt ${#_zb_path} ]]; do
		if [[ $_zb_link[0,$i] = $_zb_path[0,$i] && $_zb_link[$i] = / ]]; then
			slash=$i
			link=$_zb_path[$((i+1)),$((${#_zb_path}-1))]
			regexp-replace link '[^/]+' '..'
			link=${link:-.}$_zb_link[$i,${#_zb_link}]
		fi
	done

	print $link
}

function _zb_permalink {
	local post
	post=${1#*-}
	[[ ! -f $ZBWD/content/posts/$post ]] && return 0
	print -- $blog[root]/archives/$(date -d "$(_zb_field date $post)" +'%Y/%m/%d')/$(print $(_zb_field title $post) | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9.-]\+/-/ig; s/^-\|-$//g')/\
		| sed 's/\/\+/\//g;'
}

# parse zblog-format posts, or load post from cache
function _zb_parse_post {
	local postid headers preview body
	postid=${1#*-}
	file=$ZBWD/content/posts/$postid

	if [[ -f $ZBWD/content/cache/parser/$postid ]]; then
		eval $(<$ZBWD/content/cache/parser/$postid)
		return
	fi

	body=$(<$ZBWD/content/posts/$postid)
	headers=$body

	regexp-replace headers '\n-{4,}\n(\n|.)*' ''

	regexp-replace body '(\n|.)*\n-{4,}\n' ''
	regexp-replace body '\n' '<br>'$'\n'
	regexp-replace body '<br>\n~{4,}(<br>|\s)*$' ''

	preview=$body
	regexp-replace preview '\n~{4,}(<br>(\n|.)*|$)' ''

	regexp-replace body '<br>\n~{4,}(<br>|$)' '<br><br>'

	post=(
		'id'		$postid
		'title'		"$(_zb_field title $file)"
		'tags'		"$(_zb_field tags $file)"
		'date'		"$(_zb_field date $file)"
		'author'	"$(_zb_field author $file)"
		'preview'	"$preview"
		'body'		"$body"
		'permalink'	"$(_zb_permalink $postid)"
		'flags'		"$(_zb_field flags $file)"
	)


	# set post_preview to post_body if the preview is empty
	# TODO: create a short version if the preview does not exist
	post[preview]=${post[preview]:-$post[body]}

	(print 'post=('
	for key in ${(k)post}; do
		print -r -- ${(qq)key} ${(qq)post[$key]}
	done
	print ')') > $ZBWD/content/cache/parser/$postid
}

# check if a flag exists for a post
# returns 1 if flag not found, 0 if found
function _zb_flag {
	flag=$1
	flags=$2

	if [[ -z $flags || ${${(s/, /)flags}[(r)$1]} == $1 ]]; then
		return 1
	fi
}

# get the value of a field in a post's header
function _zb_field {
	local file p postid post
	p=$ZBWD/content/posts/
	file=$2
	postid=${2#*-}

	[[ $file[0,1] = '/' ]] && p=''

	if [[ ! -z $p && -f $ZBWD/content/cache/parser/$postid ]]; then
		typeset -A post
		eval $(<$ZBWD/content/cache/parser/$postid)
		print $post[$1]
		return
	fi

	headers=$(<$p/$file)
	regexp-replace headers '[\n\r]-{4,}[\n\r]([\r\n]|.)*' ''
	h=$headers
	regexp-replace headers '^(([\n\r]|.)*[\n\r])?('$1':.*)([\n\r]([\n\r]|.)*)?$' '$match[3]'

	if [[ $headers = $h ]]; then
		headers="$1:"
	fi

	case $1 in
		tags|flags) regexp-replace headers '\s*(,)\s*|\s+' '$match[1] '
		      regexp-replace headers '^'$1':\s*(.*)\s*' '$match[1]';;
		*)    regexp-replace headers '^'$1':\s*(.*)\s*' '$match[1]';;
	esac

	print $headers
}

# helpter to autofill a field if it's missing or empty
function _zb_fieldnx {
	[[ -z "$(grep -E "^$2:" /tmp/zblog.tmp.$$ -m 1)" ]] && \
		sed -i 's/^\(-\{4,\}\)/'"$2"': \n\1/;' /tmp/zblog.tmp.$$

	[[ -z "$(grep -E "^$2:$1" /tmp/zblog.tmp.$$ -m 1)" ]] && \
		sed -i "s/^$2:.\+$/$2: $3/;" /tmp/zblog.tmp.$$
}

# ftp wrapper
function _zb_ftp {
	autoload -U zfinit; zfinit
	if zfopen -1 "$blog[ftp_host]" "$blog[ftp_user]" "$blog[ftp_pass]"; then
		if [[ -z $(zfls $blog[ftp_root]) ]] && zfmkdir
		zfcd $blog[ftp_root]
		zfput -r $ZBWD/content/blog/*
		zfclose
	fi
}

function _zb_sftp {
}

function _zb_archives {
	zmodload zsh/mathfunc
	local i pages p loc
	loc=$1
	i=0
	pages=$((ceil(${#posts}.0 / blog[posts])))
	while [[ $i -lt $pages ]]; do
		p=${${i/#%0/}:+p$i/}

		page[previous]=${p:+/$loc/${${p/#%p1\//}:+p$((i-1))/}}
		page[next]=${${$((pages - i - 1))/#%0./}:+/$loc/p$((i+1))/}

		fragment[posts]=$(xargs cat <<< ${(F)posts[$(((i * $blog[posts]) + 1)),$(((i * $blog[posts]) + $blog[posts]))]})
		page[content]=$(_zb_template content_post.html)

		mkdir -p $ZBWD/content/blog/$loc/$p
		_zb_template layout.html > $ZBWD/content/blog/$loc/${p}index.html

		(( i++ ))
	done
}

function _zb_dotfile {
}

# magic happens here
# should really go the route of _zb_blog-<action>, and turn this into a bit of a wrapper/setup function
function blog {
	local version=0.3-Alpha

	local ZBLOG opt _blog blog zblog link links content postid input post posts fragment page tags archives _zb_path _zb_link count fname tagpath weight

	emulate -L zsh
	autoload -U regexp-replace
	setopt rematchpcre
	setopt nonomatch

	typeset -A blog
	typeset -A zblog
	typeset -A content
	typeset -A post
	typeset -A fragment
	typeset -A page
	typeset -U archives
	typeset -A count
	typeset -A links

	#ZBWD="$ZBLOG_INSTALL_DIR"
	ZBWD=~/.zblog

	zblog=(
		config  $ZBWD/blog.conf
		content $ZBWD/content/blog
		version $version
	)

	blog=(
{'fraction_non_alphanumeric': 0.2265887626060509, 'fraction_numerical': 0.013286377461181368, 'mean_word_length': 3.5288147879666547, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2919361', 'n_tokens_mistral': 5629, 'n_tokens_neox': 5297, 'n_words': 1246}