1 Commits

Author SHA1 Message Date
fa8154fc21 build(make): follow GNU install dir conventions 2025-01-25 13:33:26 +01:00
7 changed files with 73 additions and 234 deletions

View File

@@ -12,11 +12,4 @@ Initial release.
- Edit, list todo notes by any date format understood by `date(1)` - Edit, list todo notes by any date format understood by `date(1)`
- Write custom template programs to generate content for newly created notes - Write custom template programs to generate content for newly created notes
## v0.2.0
### Added
- Builtin templates for the markdown and xit formats (`.md` and `.xit`
extensions); the templates carry over open tasks from previous agenda notes
[changelog.md]: https://changelog.md/ [changelog.md]: https://changelog.md/

View File

@@ -1,24 +1,45 @@
PREFIX := /usr/local SHELL = /bin/sh
./agenda.1.gz: ./agenda.1 # See the following link regarding GNU Makefile conventions.
gzip -fk ./agenda.1 # https://www.gnu.org/software/make/manual/html_node/Makefile-Conventions.html
# This seems stupid. Isn't install a coreutil anyways?
# INSTALL := install
# INSTALL_PROGRAM := $(INSTALL)
# INSTALL_DATA := ${INSTALL} -m 644
# Variables for installation directories.
# https://www.gnu.org/software/make/manual/html_node/Directory-Variables.html
DESTDIR :=
prefix := /usr/local
exec_prefix := $(prefix)
bindir := $(exec_prefix)/bin
datarootdir := $(prefix)/share
datadir := $(datarootdir)
# libdir := $(prefix)/lib
mandir := $(datarootdir)/man
man1dir := $(mandir)/man1
.PHONY: all
all: ./agenda.1.gz
.PHONY: install .PHONY: install
install: ./agenda.1.gz install: ./agenda.1.gz
install -m 755 -D ./agenda $(PREFIX)/bin/agenda install -m 755 -D ./agenda $(DESTDIR)$(bindir)/agenda
mkdir -p $(PREFIX)/share/agenda/templates install -m 644 -D ./agenda.1.gz $(DESTDIR)$(man1dir)/agenda.1.gz
install -m 755 ./templates/* $(PREFIX)/share/agenda/templates install -m 644 -D ./completion.bash $(DESTDIR)$(datarootdir)/bash-completion/completions/agenda
install -m 644 -D ./agenda.1.gz $(PREFIX)/share/man/man1/agenda.1.gz
install -m 644 -D ./completion.bash $(PREFIX)/share/bash-completion/completions/agenda
.PHONY: uninstall .PHONY: uninstall
uninstall: uninstall:
$(RM) $(PREFIX)/bin/agenda rm -f $(DESTDIR)$(bindir)/agenda
$(RM) $(PREFIX)/share/agenda/templates/* rm -f $(DESTDIR)$(man1dir)/agenda.1.gz
$(RM) $(PREFIX)/share/man/man1/agenda.1.gz rm -f $(DESTDIR)$(datarootdir)/bash-completion/completions/agenda
$(RM) $(PREFIX)/share/bash-completion/completions/agenda
rmdir $(PREFIX)/share/agenda/templates $(PREFIX)/share/agenda
.PHONY: clean .PHONY: clean
clean: clean:
$(RM) ./agenda.1.gz rm -f ./agenda.1.gz
./agenda.1.gz: ./agenda.1
gzip -fk ./agenda.1

59
agenda
View File

@@ -17,9 +17,6 @@ AGENDA_EDITOR=${AGENDA_EDITOR:-${VISUAL:-${EDITOR:-vi}}}
# #
AGENDA_DIR=${AGENDA_DIR:-} AGENDA_DIR=${AGENDA_DIR:-}
# Location of additional files of an agenda installation.
AGENDA_DATA_DIRS=${AGENDA_DATA_DIRS:-}
# The default `-e` option. # The default `-e` option.
AGENDA_EXTENSION=${AGENDA_EXTENSION:-"md"} AGENDA_EXTENSION=${AGENDA_EXTENSION:-"md"}
@@ -27,10 +24,7 @@ AGENDA_EXTENSION=${AGENDA_EXTENSION:-"md"}
AGENDA_DEFAULT=${AGENDA_DEFAULT:-"agenda"} AGENDA_DEFAULT=${AGENDA_DEFAULT:-"agenda"}
# Command that provides the initial contents of new agenda files. # Command that provides the initial contents of new agenda files.
# AGENDA_TEMPLATE=${AGENDA_TEMPLATE:-"__agenda_default_template"}
# If this is null AGENDA_PATH is searched for an executable in the template
# subdirectory with the same name as AGENDA_EXTENSION.
AGENDA_TEMPLATE=${AGENDA_TEMPLATE:-}
__usage() { __usage() {
fold -s <<-USAGE fold -s <<-USAGE
@@ -62,15 +56,7 @@ __main() {
"--version") __version && return ;; "--version") __version && return ;;
esac esac
if [ -z "$AGENDA_DATA_DIRS" ]; then
# FIXME: As per spec only absolute paths should be accepted!
AGENDA_DATA_DIRS="${XDG_CONFIG_HOME:-"$HOME/.config"}/agenda"
AGENDA_DATA_DIRS="$AGENDA_DATA_DIRS:/usr/local/share/agenda"
AGENDA_DATA_DIRS="$AGENDA_DATA_DIRS:/usr/share/agenda"
fi
if [ -z "$AGENDA_DIR" ]; then if [ -z "$AGENDA_DIR" ]; then
# FIXME: As per spec only absolute paths should be accepted!
AGENDA_DIR="${XDG_DATA_HOME:-"$HOME/.local/share"}/agenda" AGENDA_DIR="${XDG_DATA_HOME:-"$HOME/.local/share"}/agenda"
fi fi
@@ -305,7 +291,6 @@ __list() {
fi fi
done < <( done < <(
# Sort the paths by basename. # Sort the paths by basename.
# TODO: Inline the prefix functions and explain this.
find "$dir" -type f \ find "$dir" -type f \
| __agenda_sort_prefix \ | __agenda_sort_prefix \
| sort \ | sort \
@@ -327,18 +312,7 @@ __agenda_create() {
tmp_err=$(mktemp) tmp_err=$(mktemp)
if [ "$backlog" = "no" ]; then if [ "$backlog" = "no" ]; then
# Search for a template program if the AGENDA_TEMPLATE variable is empty. # Capture exit code of the template command.
if [ -z "$AGENDA_TEMPLATE" ]; then
AGENDA_TEMPLATE=$(
__agenda_get_template_path "$AGENDA_EXTENSION" ||
__agenda_get_template_path "default" ||
true
)
fi
# If a template program is set, attempt to use it to create the new agenda
# note file.
if [ -n "$AGENDA_TEMPLATE" ]; then
local code local code
set +e set +e
"$AGENDA_TEMPLATE" > "$tmp" 2> "$tmp_err" "$AGENDA_TEMPLATE" > "$tmp" 2> "$tmp_err"
@@ -360,15 +334,25 @@ __agenda_create() {
echo "${0##*/}: cannot create '$file': template error" >&2 echo "${0##*/}: cannot create '$file': template error" >&2
return $code return $code
fi fi
else
touch "$tmp"
fi
fi fi
mkdir -p "${file%/*}" mkdir -p "${file%/*}"
mv "$tmp" "$file" mv "$tmp" "$file"
} }
__agenda_default_template() {
case $AGENDA_EXTENSION in
"md")
printf "# %s %s\n\n- [ ] " "$AGENDA_NAME" "$AGENDA_DATE"
;;
"txt"|"xit"|"")
printf "%s %s\n[ ] " "$AGENDA_NAME" "$AGENDA_DATE"
;;
*)
;;
esac
}
__agenda_last() { __agenda_last() {
local file=$1 name=$2 local file=$1 name=$2
@@ -391,19 +375,6 @@ __agenda_last() {
echo "${last:-}" echo "${last:-}"
} }
__agenda_get_template_path() {
local template=$1
local IFS=":" path
for path in $AGENDA_DATA_DIRS; do
if [ -x "$path/templates/$template" ]; then
AGENDA_TEMPLATE="$path/templates/$template"
return
fi
done
return 1
}
# https://stackoverflow.com/a/49035906 # https://stackoverflow.com/a/49035906
__slugify() { __slugify() {
echo "$1" \ echo "$1" \

View File

@@ -1,4 +1,4 @@
.TH AGENDA 1 "2024-06-07" "agenda 0.2.0" .TH AGENDA 1 "2024-06-07" "agenda 0.1.0"
\#============================================================================= \#=============================================================================
.SH NAME .SH NAME
agenda \- Manage daily tasks and notes in any plain text format. agenda \- Manage daily tasks and notes in any plain text format.
@@ -107,26 +107,7 @@ The editor process has access to certain environment variables.
\fBAGENDA_DIR\fP \fBAGENDA_DIR\fP
.RS 4 .RS 4
The home of all agenda note files read and written by agenda. If this is empty The home of all agenda note files read and written by agenda. If this is empty
\fBXDG_DATA_HOME\fP\fI/agenda\fP will be used. `${XDG_DATA_HOME:-"$HOME/.local/share"}/agenda` will be used.
.PP
.RE
\#
\fBAGENDA_DATA_DIRS\fP
.RS 4
Colon delimited Paths to additional files that come with an agenda installation
and custom overrides. Currently only used for template programs (located in the
\fItemplate/\fP sub-directory). If a file is searched in these paths the first file
that is found is used.
.nr PI 2n
If this variable is not set or empty it is set to include (in order)
.IP \[bu]
\fBXDG_CONFIG_HOME\fP\fI/agenda\fP
.IP \[bu]
\fI/usr/local/share/agenda\fP
.IP \[bu]
\fI/usr/share/agenda\fP
.PP .PP
.RE .RE
\# \#
@@ -146,14 +127,10 @@ The default agenda name if the \fI-t\fP option is omitted. This falls back to
\# \#
\fBAGENDA_TEMPLATE\fP \fBAGENDA_TEMPLATE\fP
.RS 4 .RS 4
If this variable is not empty the value is interpreted as a command and If this is not empty the value is interpreted as a command and executed when
executed when creating a new agenda note with the \fI-c\fP flag. Any std output creating a new agenda note with the \fI-c\fP flag. Any std output of the
of the command is written to the new file. The template process has access to command is written to the new file. The template process has access to certain
certain environment variables. environment variables.
.PP
If this variable is unset or empty \fBAGENDA_DATA_DIRS\fP is searched for an
executable in the \fItemplates\fP sub-directory that is named either like the
corresponding extension or "default".
.sp 1 .sp 1
The following example will copy the last agenda note to The following example will copy the last agenda note to
the new agenda note file. the new agenda note file.
@@ -176,10 +153,6 @@ Note however that this example is specific to \fBbash(1)\fP, since only bash
can export functions this way. In general you should write your template as a can export functions this way. In general you should write your template as a
script, save it, and set it as executable. script, save it, and set it as executable.
.PP .PP
To set/override a template for a certain extension (e.g. markdown), save the
program to one of the \fBAGENDA_DATA_DIRS\fP, e.g.
\fI\fBXDG_CONFIG_HOME\fP/agenda/templates/md\fP.
.PP
\#----------------------------------------------------------------------------- \#-----------------------------------------------------------------------------
.SS "Templates and editor" .SS "Templates and editor"
The template command and editor processes have access to certain environment The template command and editor processes have access to certain environment
@@ -215,21 +188,6 @@ The file path of the agenda note.
The last agenda file. Can be empty if no previous agenda note exists. The last agenda file. Can be empty if no previous agenda note exists.
.PP .PP
.RE .RE
.SS "Other"
\#
\fBXDG_CONFIG_HOME\fP
.RS 4
The default user configuration path. If this is not set the default of
\fBHOME\fP\fI/.config\fP is assumed.
.PP
.RE
\#
\fBXDG_DATA_HOME\fP
.RS 4
The default user data path. If this is not set the default of
\fBHOME\fP\fI/.local/share\fP is assumed.
.PP
.RE
\#============================================================================= \#=============================================================================
.SH "SEE ALSO" .SH "SEE ALSO"
\fBdate(1)\fP \fBdate(1)\fP

View File

@@ -1,6 +0,0 @@
#!/bin/sh
set -eu
type agenda >/dev/null
# Capitalize the title.
echo "$AGENDA_NAME $AGENDA_DATE" | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}'

View File

@@ -1,42 +0,0 @@
#!/bin/sh
set -eu
type agenda >/dev/null
if [ "${AGENDA_EXTENSION:-}" != "md" ]; then
exit
fi
# Capitalize the title.
echo "$AGENDA_NAME $AGENDA_DATE" | awk '{print "# "toupper(substr($0,0,1))tolower(substr($0,2))}'
echo
if [ -n "${AGENDA_IS_BACKLOG:-}" ]; then
exit
fi
# Carry over open tasks from the last agenda markdown file.
if [ -e "$AGENDA_LAST" ] && [ "${AGENDA_LAST#*.}" = "md" ]; then
while IFS= read -r REPLY; do
case ${state:-} in
"open_task")
case $REPLY in
"- [ ] "*|" "*)
# Append indented lines to open tasks.
echo "$REPLY"
;;
*)
unset state
;;
esac
;;
*)
case $REPLY in
"[ ] "*|"[@] "*|"[?] "*)
state="open_task"
echo "$REPLY"
;;
esac
;;
esac
done < "$AGENDA_LAST"
fi

View File

@@ -1,56 +0,0 @@
#!/bin/sh
set -eu
type agenda >/dev/null
if [ "${AGENDA_EXTENSION:-}" != "xit" ]; then
exit
fi
# Capitalize the title.
echo "$AGENDA_NAME $AGENDA_DATE" | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}'
if [ -n "${AGENDA_IS_BACKLOG:-}" ]; then
exit
fi
# Carry over open tasks from the last agenda xit file.
if [ -e "$AGENDA_LAST" ] && [ "${AGENDA_LAST#*.}" = "xit" ]; then
line=0
while IFS= read -r REPLY; do
line=$(( line + 1 ))
case ${state:-} in
"open_task")
case $REPLY in
"[ ] "*|"[@] "*|"[?] "*|" "*)
# Append indented lines to open tasks.
echo "$REPLY"
;;
*)
unset state
;;
esac
;;
*)
case $REPLY in
"[ ] "*|"[@] "*|"[?] "*)
# Carry over group heading with open tasks.
if [ -n "${header:-}" ]; then
echo
echo "$header"
unset header
fi
state="open_task"
echo "$REPLY"
;;
[a-z]*|[A-Z]*)
# Skip the first heading (assumed to be the generated
# title of the agenda note).
if [ $line -gt 1 ]; then
header=$REPLY
fi
;;
esac
;;
esac
done < "$AGENDA_LAST"
fi