notes2.sh/notes.sh

235 lines
3.6 KiB
Bash
Executable file

#!/usr/bin/env bash
set -e
DATE_FORMAT="%a, %d %b %Y %H:%M:%S %z"
BASEDIR=~/Notes
EDITOR="${EDITOR:-vim}"
if [ ! -d "$BASEDIR" ]; then
mkdir -p "$BASEDIR"
fi
die() {
echo "$@" 1>&2;
exit 1
}
uuid()
{
local N B T
for (( N=0; N < 16; ++N ))
do
B=$(( RANDOM%255 ))
if (( N == 6 ))
then
printf '4%x' $(( B%15 ))
elif (( N == 8 ))
then
local C='89ab'
printf '%c%x' ${C:$(( RANDOM%${#C} )):1} $(( B%15 ))
else
printf '%02x' $B
fi
for T in 3 5 7 9
do
if (( T == N ))
then
printf '-'
break
fi
done
done
echo
}
canonicalize() {
NAME="$1"
NAME="$(echo "$NAME" | tr '[:upper:]' '[:lower:]')"
NAME="$(echo "$NAME" | sed 's/[^a-z0-9]/_/g')"
echo "$NAME"
}
utc_timestamp() {
date -u +"%Y%m%d%H%M%S"
}
find_file_by_id() {
ID="$1"
{ grep -l -r -m1 "^X-Note-Id: $ID$" "$BASEDIR" || true; } | sort| head -1
}
assert_find_file_by_id() {
FILE="$(find_file_by_id "$1")"
if [ ! -f "$FILE" ]; then
die "Note with ID <$ID> not found"
fi
echo "$FILE"
}
list_entries() {
FILTER="\
BEGIN { \
message_id=0; \
subject=0; \
date=0; \
} \
match(\$0, /^X-Note-Id: .*$/) { \
if (message_id != 0) { \
if (subject !=0 && date != 0)\
print date, message_id, subject; \
subject = 0; \
date = 0; \
};\
message_id = substr(\$0, 12, RLENGTH-11); \
} \
match(\$0, /^Subject: .*$/) { \
if (subject != 0) { \
if (message_id != 0 && date != 0)\
print date, message_id, subject; \
message_id = 0; \
date = 0; \
}; \
subject = substr(\$0, 10, RLENGTH-9); \
} \
match(\$0, /^X-Date: .*$/) { \
if (date != 0) { \
if (message_id != 0 && subject != 0)\
print date, message_id, subject; \
subject = 0; \
message_id = 0; \
}; \
date = substr(\$0, 9, RLENGTH-8); \
} \
END { \
if (message_id != 0 && subject != 0 && date != 0)\
print date, message_id, subject;\
}\
"
grep -r -m 3 -h "^Subject:\|^X-Note-Id:\|^X-Date:" "$BASEDIR" --include="note.md" | awk "$FILTER" | sort | cut -d " " -f "2-"
}
new_entry() {
NAME="$1"
CANONICAL_NAME="$(canonicalize "$NAME")"
FULL_NAME="$(utc_timestamp)-$CANONICAL_NAME"
NOTE_ID="$(uuid)"
NOTE_DIR="$BASEDIR/$FULL_NAME"
NOTE_FILE="$NOTE_DIR/note.md"
mkdir -p "$NOTE_DIR"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
{
echo "X-Date: $TIMESTAMP"
echo "X-Note-Id: $NOTE_ID"
echo "Subject: $NAME"
echo
} >> "$NOTE_FILE"
$EDITOR "$NOTE_FILE"
}
edit_entry() {
ID="$1"
FILENAME="$(assert_find_file_by_id "$ID")"
echo "$FILENAME"
$EDITOR "$FILENAME"
}
export_note() {
ID="$1"
FILENAME="$(assert_find_file_by_id "$ID")"
DIR="$2"
if [ -z "$DIR" ]; then
cat "$FILENAME"
else
die "Directory export not implemented"
fi
}
fzf_entry() {
NAME="$1"
ID="$(echo "$2" | cut -d " " -f 1)"
if [ -z "$ID" ]; then
if [ ! -z "$NAME" ]; then
new_entry "$NAME"
fi
else
edit_entry "$ID"
fi
}
usage() {
echo "$0 {--new,--list,--edit,--fzf,--help}"
}
while (( "$#" )); do
case "$1" in
-n|--new)
shift
new_entry "$*"
exit 0
;;
-l|--list)
list_entries
exit 0
;;
-e|--edit)
if [ -z "$2" ]; then
exit 0
fi
edit_entry "$2"
exit 0
;;
-f|--fzf)
fzf_entry "$2" "$3"
exit 0
;;
-E|--export)
if [ -z "$2" ]; then
echo "Misssing arguments for $1"
exit 1
fi
export_note "$2" "$3"
exit 0
;;
-p|--preview)
if [ -z "$2" ]; then
echo "Misssing arguments for $1"
exit 1
fi
NOTE_ID="$(echo $2 | cut -d " " -f 1)"
export_note "$NOTE_ID" "" | fmt -s -w "$FZF_PREVIEW_COLUMNS"
exit 0
;;
-g|--graph)
get_graph
exit 0
;;
*)
usage
exit 1
;;
esac
done
usage
exit 1