diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3553fa8 --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1696078222, + "narHash": "sha256-QBqNSFSPitmvpF2SPqTXbPKo7Wr3kv7cY4zjhCTsHRU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4f393e78df6fe1986f24b018e60264e89b5c8de", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..a6393c4 --- /dev/null +++ b/flake.nix @@ -0,0 +1,53 @@ +{ + description = "Nix notes.sh dev environment"; + + # Flake inputs + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + # Flake outputs + outputs = { self, nixpkgs }: + let + # Systems supported + allSystems = [ + "x86_64-linux" # 64-bit Intel/AMD Linux + "aarch64-linux" # 64-bit ARM Linux + "x86_64-darwin" # 64-bit Intel macOS + "aarch64-darwin" # 64-bit ARM macOS + ]; + + # Helper to provide system-specific attributes + forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f { + pkgs = import nixpkgs { inherit system; }; + }); + + make_package = pkgs: pkgs.stdenv.mkDerivation { + name = "notes-sh"; + src = self; + nativeBuildInputs = [pkgs.makeWrapper]; + installPhase = '' + mkdir -p $out/bin + cp notes.sh $out/bin + ''; + + postFixup = '' + wrapProgram $out/bin/notes.sh \ + --prefix PATH : ${pkgs.lib.makeBinPath (with pkgs; [ gawk findutils gnused coreutils])} + ''; + }; + in + { + devShells = forAllSystems ({ pkgs }: { + default = pkgs.mkShell { + packages = with pkgs; [ + fzf + ]; + }; + }); + packages = forAllSystems({ pkgs }: rec {notes-sh = make_package pkgs; default=notes-sh;}); + overlays.default = final: prev: { + notes-sh = make_package prev; + }; + }; +} diff --git a/notes.sh b/notes.sh index 2ad4654..153b6b2 100755 --- a/notes.sh +++ b/notes.sh @@ -4,13 +4,13 @@ # # Copyright (c) 2021, Konstantin Nazarov # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. -# +# # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. @@ -35,17 +35,17 @@ CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/notes.sh" EDITOR="${EDITOR:-vim}" if [ -n "$NOTES_SH_BASEDIR" ]; then - BASEDIR="$NOTES_SH_BASEDIR" + BASEDIR="$NOTES_SH_BASEDIR" fi if [ ! -d "$BASEDIR" ]; then - mkdir -p "$BASEDIR"/{tmp,new,cur} + mkdir -p "$BASEDIR"/{tmp,new,cur} fi die() { - echo "$@" 1>&2; - exit 1 + echo "$@" 1>&2; + exit 1 } uuid() @@ -81,528 +81,528 @@ uuid() } utc_timestamp() { - date -u +"%Y-%m-%dT%H:%M:%SZ" + date -u +"%Y-%m-%dT%H:%M:%SZ" } gen_boundary() { - for (( N=0; N < 32; ++N )) - do - B=$(( RANDOM%255 )) - printf '%02x' $B - done - echo + for (( N=0; N < 32; ++N )) + do + B=$(( RANDOM%255 )) + printf '%02x' $B + done + echo } yesno() { - PROMPT="$1" - DEFAULT="$2" + PROMPT="$1" + DEFAULT="$2" - if [[ "$DEFAULT" == "y" ]]; then - read -p "$PROMPT [Y/n] " -r CHOICE - if [[ "$CHOICE" =~ ^[Nn]$ ]]; then - echo "n" - else - echo "y" - fi - else - read -p "$PROMPT [y/N] " -r CHOICE - if [[ "$CHOICE" =~ ^[Yy]$ ]]; then - echo "y" - else - echo "n" - fi - fi + if [[ "$DEFAULT" == "y" ]]; then + read -p "$PROMPT [Y/n] " -r CHOICE + if [[ "$CHOICE" =~ ^[Nn]$ ]]; then + echo "n" + else + echo "y" + fi + else + read -p "$PROMPT [y/N] " -r CHOICE + if [[ "$CHOICE" =~ ^[Yy]$ ]]; then + echo "y" + else + echo "n" + fi + fi } get_headers() { - HEADERS_FILE="$1" - - FILTER="\ - { \ - if (\$0~/^$/) {exit} \ - if (\$0!~/^[^ ]*: .*$/) {exit} \ - print \$0 \ - } \ - " - awk "$FILTER" "$HEADERS_FILE" + HEADERS_FILE="$1" + + FILTER="\ + { \ + if (\$0~/^$/) {exit} \ + if (\$0!~/^[^ ]*: .*$/) {exit} \ + print \$0 \ + } \ + " + awk "$FILTER" "$HEADERS_FILE" } get_body() { - BODY_FILE="$1" - - FILTER="\ - { \ - if (body==1) {\ - print \$0; - }\ - if (\$0~/^$/) {body=1} \ - if (\$0!~/^[^ ]*: .*$/ && body != 1) {\ - body=1; - print \$0; - } \ - } \ - " - awk "$FILTER" "$BODY_FILE" + BODY_FILE="$1" + + FILTER="\ + { \ + if (body==1) {\ + print \$0; + }\ + if (\$0~/^$/) {body=1} \ + if (\$0!~/^[^ ]*: .*$/ && body != 1) {\ + body=1; + print \$0; + } \ + } \ + " + awk "$FILTER" "$BODY_FILE" } get_header() { - FILE="$1" - HEADER="$2" - grep -m1 "^${HEADER}: " < "$FILE" | sed -n "s/^${HEADER}: \(.*\)$/\1/p" + FILE="$1" + HEADER="$2" + grep -m1 "^${HEADER}: " < "$FILE" | sed -n "s/^${HEADER}: \(.*\)$/\1/p" } find_file_by_id() { - ID="$1" + ID="$1" - { grep -l -r -m1 "^X-Note-Id: $ID$" "$BASEDIR" || true; } | sort| head -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")" + FILE="$(find_file_by_id "$1")" - if [ ! -f "$FILE" ]; then - die "Note with ID <$ID> not found" - fi + if [ ! -f "$FILE" ]; then + die "Note with ID <$ID> not found" + fi - echo "$FILE" + echo "$FILE" } find_files_by_id() { - ID="$1" - grep -l -r -m 1 "^X-Note-Id: $ID$" "$BASEDIR" || true + ID="$1" + grep -l -r -m 1 "^X-Note-Id: $ID$" "$BASEDIR" || true } get_part() { - FILE="$1" - BOUNDARY="$2" - NUM="$3" - FILTER="\ - BEGIN { \ - rec=0; \ - body=0; \ - } \ - { \ - if (\$0==\"--$BOUNDARY\" || \$0==\"--$BOUNDARY--\") { \ - if (body == 0) { \ - body=1; \ - } \ - rec=rec+1; \ - } \ - else if (body == 1 && rec==$NUM) { \ - print \$0 \ - } \ - }" + FILE="$1" + BOUNDARY="$2" + NUM="$3" + FILTER="\ + BEGIN { \ + rec=0; \ + body=0; \ + } \ + { \ + if (\$0==\"--$BOUNDARY\" || \$0==\"--$BOUNDARY--\") { \ + if (body == 0) { \ + body=1; \ + } \ + rec=rec+1; \ + } \ + else if (body == 1 && rec==$NUM) { \ + print \$0 \ + } \ + }" - awk "$FILTER" "$FILE" + awk "$FILTER" "$FILE" } unpack_part() { - FILE="$1" - DIR="$2" - MIME_TYPE=$(get_header "$FILE" Content-Type) - DISPOSITION=$(get_header "$FILE" Content-Disposition) + FILE="$1" + DIR="$2" + MIME_TYPE=$(get_header "$FILE" Content-Type) + DISPOSITION=$(get_header "$FILE" Content-Disposition) - if [[ $DISPOSITION == *"attachment"* ]]; then - ENCODING=$(get_header "$FILE" Content-Transfer-Encoding) - FILENAME=$(echo "$DISPOSITION" | \ - sed -n 's/^.*filename="\{0,1\}\([^"]*\)"\{0,1\}$/\1/p') - FILTER="\ - { \ - if (body==1) {print \$0}\ - if (\$0~/^$/) {body=1} \ - } \ - " - - if [[ $ENCODING == *"base64"* ]]; then - awk "$FILTER" "$FILE" | base64 --decode >> "$DIR/$FILENAME" - else - awk "$FILTER" "$FILE" >> "$DIR/$FILENAME" - fi - elif [[ $MIME_TYPE == *"text/plain"* ]]; then - FILTER="\ - { \ - if (body==1) {print \$0}\ - if (\$0~/^$/) {body=1} \ - } \ - " - awk "$FILTER" "$FILE" >> "$DIR/note.md" - elif [[ $MIME_TYPE == *"multipart/mixed"* ]]; then - BOUNDARY=$(echo "$MIME_TYPE" | sed -n 's/^.*boundary="\(.*\)"$/\1/p') - i=1 - while true; do - TMP=$(mktemp "$DIR/tmp.XXXXXXXX") - get_part "$FILE" "$BOUNDARY" "$i" > "$TMP" - ((i++)) - if [ ! -s "$TMP" ]; then - rm "$TMP" - break - fi - #cat "$TMP" - (unpack_part "$TMP" "$DIR") - rm "$TMP" - done - elif [[ $MIME_TYPE == *"multipart/related"* ]]; then - echo "multipart/related not yet supported" - exit 1 - fi + if [[ $DISPOSITION == *"attachment"* ]]; then + ENCODING=$(get_header "$FILE" Content-Transfer-Encoding) + FILENAME=$(echo "$DISPOSITION" | \ + sed -n 's/^.*filename="\{0,1\}\([^"]*\)"\{0,1\}$/\1/p') + FILTER="\ + { \ + if (body==1) {print \$0}\ + if (\$0~/^$/) {body=1} \ + } \ + " + + if [[ $ENCODING == *"base64"* ]]; then + awk "$FILTER" "$FILE" | base64 --decode >> "$DIR/$FILENAME" + else + awk "$FILTER" "$FILE" >> "$DIR/$FILENAME" + fi + elif [[ $MIME_TYPE == *"text/plain"* ]]; then + FILTER="\ + { \ + if (body==1) {print \$0}\ + if (\$0~/^$/) {body=1} \ + } \ + " + awk "$FILTER" "$FILE" >> "$DIR/note.md" + elif [[ $MIME_TYPE == *"multipart/mixed"* ]]; then + BOUNDARY=$(echo "$MIME_TYPE" | sed -n 's/^.*boundary="\(.*\)"$/\1/p') + i=1 + while true; do + TMP=$(mktemp "$DIR/tmp.XXXXXXXX") + get_part "$FILE" "$BOUNDARY" "$i" > "$TMP" + ((i++)) + if [ ! -s "$TMP" ]; then + rm "$TMP" + break + fi + #cat "$TMP" + (unpack_part "$TMP" "$DIR") + rm "$TMP" + done + elif [[ $MIME_TYPE == *"multipart/related"* ]]; then + echo "multipart/related not yet supported" + exit 1 + fi } unpack_mime() { - FILE="$1" - DIR="$2" + FILE="$1" + DIR="$2" - get_headers "$FILE" | grep -v "^Content-Type\|^Content-Disposition\|^Date\|^MIME-Version" >> "$DIR/note.md" - echo "" >> "$DIR/note.md" + get_headers "$FILE" | grep -v "^Content-Type\|^Content-Disposition\|^Date\|^MIME-Version" >> "$DIR/note.md" + echo "" >> "$DIR/note.md" - TMP=$(mktemp "$DIR/tmp.XXXXXXXX") - cat "$FILE" > "$TMP" + TMP=$(mktemp "$DIR/tmp.XXXXXXXX") + cat "$FILE" > "$TMP" - (unpack_part "$TMP" "$DIR") - rm "$TMP" + (unpack_part "$TMP" "$DIR") + rm "$TMP" } pack_part() { - PART_FILE="$1" - CONTENT_TYPE="$(file -b --mime-type "$PART_FILE")" - echo "Content-Disposition: attachment; filename=\"$(basename "$PART_FILE")\"" + PART_FILE="$1" + CONTENT_TYPE="$(file -b --mime-type "$PART_FILE")" + echo "Content-Disposition: attachment; filename=\"$(basename "$PART_FILE")\"" - if [[ "$CONTENT_TYPE" =~ "text/" ]]; then - echo "Content-Type: text/plain" - echo - cat "$PART_FILE" - else - echo "Content-Type: $CONTENT_TYPE" - echo "Content-Transfer-Encoding: base64" - echo - base64 | fold -w 76 < "$PART_FILE" - fi + if [[ "$CONTENT_TYPE" =~ "text/" ]]; then + echo "Content-Type: text/plain" + echo + cat "$PART_FILE" + else + echo "Content-Type: $CONTENT_TYPE" + echo "Content-Transfer-Encoding: base64" + echo + base64 | fold -w 76 < "$PART_FILE" + fi } pack_mime() { - DIR="$1" - FILE="$2" - FILE_COUNT="$(find "$DIR/" -type f | wc -l | tr -d " ")" - MIME_TIMESTAMP=$(LC_ALL="en_US.UTF-8" date "+$DATE_FORMAT") + DIR="$1" + FILE="$2" + FILE_COUNT="$(find "$DIR/" -type f | wc -l | tr -d " ")" + MIME_TIMESTAMP=$(LC_ALL="en_US.UTF-8" date "+$DATE_FORMAT") - if [[ "$FILE_COUNT" == "1" ]]; then - { - echo "MIME-Version: 1.0" - echo "Date: $MIME_TIMESTAMP" - echo "Content-Type: text/plain; charset=utf-8" - echo "Content-Disposition: inline" - cat "$DIR/note.md" - } >> "$FILE" - return - fi + if [[ "$FILE_COUNT" == "1" ]]; then + { + echo "MIME-Version: 1.0" + echo "Date: $MIME_TIMESTAMP" + echo "Content-Type: text/plain; charset=utf-8" + echo "Content-Disposition: inline" + cat "$DIR/note.md" + } >> "$FILE" + return + fi - BOUNDARY="$(gen_boundary)" - { - echo "MIME-Version: 1.0" - echo "Date: $MIME_TIMESTAMP" - echo "Content-Type: multipart/mixed; boundary=\"$BOUNDARY\"" - get_headers "$DIR/note.md" - echo - echo "--$BOUNDARY" - echo "Content-Type: text/plain; charset=utf-8" - echo "Content-Disposition: inline" - echo - get_body "$DIR/note.md" - } >> "$FILE" + BOUNDARY="$(gen_boundary)" + { + echo "MIME-Version: 1.0" + echo "Date: $MIME_TIMESTAMP" + echo "Content-Type: multipart/mixed; boundary=\"$BOUNDARY\"" + get_headers "$DIR/note.md" + echo + echo "--$BOUNDARY" + echo "Content-Type: text/plain; charset=utf-8" + echo "Content-Disposition: inline" + echo + get_body "$DIR/note.md" + } >> "$FILE" - find "$DIR/" -type f ! -name 'note.md' | while read -r FN - do - { - echo "--$BOUNDARY" - pack_part "$FN" - } >> "$FILE" - done - echo "--$BOUNDARY--" >> "$FILE" + find "$DIR/" -type f ! -name 'note.md' | while read -r FN + do + { + echo "--$BOUNDARY" + pack_part "$FN" + } >> "$FILE" + done + echo "--$BOUNDARY--" >> "$FILE" } input_note() { - INP="$1" - OUTP="$2" + INP="$1" + OUTP="$2" - DIR="$(mktemp -d)" - ENTRY_FILE="$DIR/note.md" - MIME_TIMESTAMP=$(LC_ALL="en_US.UTF-8" date "+$DATE_FORMAT") - UTC_TIMESTAMP=$(utc_timestamp) + DIR="$(mktemp -d)" + ENTRY_FILE="$DIR/note.md" + MIME_TIMESTAMP=$(LC_ALL="en_US.UTF-8" date "+$DATE_FORMAT") + UTC_TIMESTAMP=$(utc_timestamp) - if [ -n "$INP" ] && [ ! -f "$INP" ] && [ ! -d "$INP" ]; then - die "File or directory doesn't exist: $INP" - fi + if [ -n "$INP" ] && [ ! -f "$INP" ] && [ ! -d "$INP" ]; then + die "File or directory doesn't exist: $INP" + fi - if [ -f "$INP" ]; then - { - get_headers "$INP" - echo "" - get_body "$INP" - } >> "$DIR/note.md" - elif [ -d "$INP" ]; then - if [ ! -f "$INP/note.md" ]; then - die "File doesn't exist: $INP/note.md" - fi - cp -n "$INP"/* "$DIR/" || true - elif [ -t 0 ]; then - cat > "$ENTRY_FILE" <<- EOF - X-Date: $UTC_TIMESTAMP - X-Note-Id: $(uuid) - Subject: - EOF - OLD_DIR="$(pwd)" - cd "$DIR" - "$EDITOR" "$ENTRY_FILE" - cd "$OLD_DIR" - else - while read -r line ; do - echo "$line" >> "$ENTRY_FILE" - done - fi - MERGED_ENTRY_FILE="$(mktemp)" + if [ -f "$INP" ]; then + { + get_headers "$INP" + echo "" + get_body "$INP" + } >> "$DIR/note.md" + elif [ -d "$INP" ]; then + if [ ! -f "$INP/note.md" ]; then + die "File doesn't exist: $INP/note.md" + fi + cp -n "$INP"/* "$DIR/" || true + elif [ -t 0 ]; then + cat > "$ENTRY_FILE" <<- EOF +X-Date: $UTC_TIMESTAMP +X-Note-Id: $(uuid) +Subject: +EOF + OLD_DIR="$(pwd)" + cd "$DIR" + $EDITOR "$ENTRY_FILE" + cd "$OLD_DIR" + else + while read -r line ; do + echo "$line" >> "$ENTRY_FILE" + done + fi + MERGED_ENTRY_FILE="$(mktemp)" - HEADERS=$(get_headers "$ENTRY_FILE") - { - echo "$HEADERS" | grep -q "^X-Date:" || echo "X-Date: $UTC_TIMESTAMP" - echo "$HEADERS" | grep -q "^X-Note-Id:" || echo "X-Note-Id: $(uuid)" - echo "$HEADERS" - echo "$HEADERS" | grep -q "^Subject:" || echo "Subject: " - echo "" - get_body "$ENTRY_FILE" - } > "$MERGED_ENTRY_FILE" + HEADERS=$(get_headers "$ENTRY_FILE") + { + echo "$HEADERS" | grep -q "^X-Date:" || echo "X-Date: $UTC_TIMESTAMP" + echo "$HEADERS" | grep -q "^X-Note-Id:" || echo "X-Note-Id: $(uuid)" + echo "$HEADERS" + echo "$HEADERS" | grep -q "^Subject:" || echo "Subject: " + echo "" + get_body "$ENTRY_FILE" + } > "$MERGED_ENTRY_FILE" - mv "$MERGED_ENTRY_FILE" "$ENTRY_FILE" + mv "$MERGED_ENTRY_FILE" "$ENTRY_FILE" - pack_mime "$DIR" "$OUTP" + pack_mime "$DIR" "$OUTP" - rm -rf "$DIR" + rm -rf "$DIR" } remove_notes_by_id() { - ID="$1" + ID="$1" - find_files_by_id "$ID" | while read -r FN - do - rm "$FN" - done + find_files_by_id "$ID" | while read -r FN + do + rm "$FN" + done } notes_equal() { - NOTE1="$1" - NOTE2="$2" + NOTE1="$1" + NOTE2="$2" - MIME_TYPE1=$(get_header "$NOTE1" Content-Type) - MIME_TYPE2=$(get_header "$NOTE2" Content-Type) - BOUNDARY1=$(echo "$MIME_TYPE1" | sed -n 's/^.*boundary="\(.*\)"$/\1/p') - BOUNDARY2=$(echo "$MIME_TYPE2" | sed -n 's/^.*boundary="\(.*\)"$/\1/p') + MIME_TYPE1=$(get_header "$NOTE1" Content-Type) + MIME_TYPE2=$(get_header "$NOTE2" Content-Type) + BOUNDARY1=$(echo "$MIME_TYPE1" | sed -n 's/^.*boundary="\(.*\)"$/\1/p') + BOUNDARY2=$(echo "$MIME_TYPE2" | sed -n 's/^.*boundary="\(.*\)"$/\1/p') - FILTER1="^Date:" - FILTER2="^Date:" + FILTER1="^Date:" + FILTER2="^Date:" - if [ -n "$BOUNDARY1" ]; then - FILTER1="^Date:\|$BOUNDARY1" - fi + if [ -n "$BOUNDARY1" ]; then + FILTER1="^Date:\|$BOUNDARY1" + fi - if [ -n "$BOUNDARY2" ]; then - FILTER2="^Date:\|$BOUNDARY2" - fi + if [ -n "$BOUNDARY2" ]; then + FILTER2="^Date:\|$BOUNDARY2" + fi - NOTE1_S="$(mktemp)" + NOTE1_S="$(mktemp)" - grep -v "$FILTER1" "$NOTE1" > "$NOTE1_S" + grep -v "$FILTER1" "$NOTE1" > "$NOTE1_S" - if grep -v "$FILTER2" "$NOTE2" | cmp -s "$NOTE1_S"; then - rm "$NOTE1_S" - return 0 - else - rm "$NOTE1_S" - return 1 - fi + if grep -v "$FILTER2" "$NOTE2" | cmp -s "$NOTE1_S"; then + rm "$NOTE1_S" + return 0 + else + rm "$NOTE1_S" + return 1 + fi } new_entry() { - OUTP="$(mktemp)" - input_note "$1" "$OUTP" + OUTP="$(mktemp)" + input_note "$1" "$OUTP" - if [ ! -s "$OUTP" ]; then - rm "$OUTP" - return - fi + if [ ! -s "$OUTP" ]; then + rm "$OUTP" + return + fi - NOTE_ID="$(get_header "$OUTP" X-Note-Id)" + NOTE_ID="$(get_header "$OUTP" X-Note-Id)" - OLD_NOTE="$(find_file_by_id "$NOTE_ID")" - if [ -n "$OLD_NOTE" ] && notes_equal "$OLD_NOTE" "$OUTP"; then - return - fi + OLD_NOTE="$(find_file_by_id "$NOTE_ID")" + if [ -n "$OLD_NOTE" ] && notes_equal "$OLD_NOTE" "$OUTP"; then + return + fi - remove_notes_by_id "$NOTE_ID" + remove_notes_by_id "$NOTE_ID" - UNIX_TIMESTAMP=$(date "+%s") - HOSTNAME=$(hostname -s) - FILENAME="$UNIX_TIMESTAMP.${PID}_1.${HOSTNAME}:2,S" - mv "$OUTP" "$BASEDIR/cur/$FILENAME" + UNIX_TIMESTAMP=$(date "+%s") + HOSTNAME=$(hostname -s) + FILENAME="$UNIX_TIMESTAMP.${PID}_1.${HOSTNAME}:2,S" + mv "$OUTP" "$BASEDIR/cur/$FILENAME" } edit_entry() { - ID="$1" - FILENAME="$(assert_find_file_by_id "$ID")" + ID="$1" + FILENAME="$(assert_find_file_by_id "$ID")" - DIR="$CACHE_DIR/$ID" + DIR="$CACHE_DIR/$ID" - if [ -d "$DIR" ] && [ -f "$DIR/note.md" ]; then - RESUME_EDITING=$(yesno "Unsaved changes found for this note. Resume editing?" y) - fi + if [ -d "$DIR" ] && [ -f "$DIR/note.md" ]; then + RESUME_EDITING=$(yesno "Unsaved changes found for this note. Resume editing?" y) + fi - if [ "$RESUME_EDITING" != "y" ]; then - rm -rf "$DIR" - mkdir -p "$DIR" - unpack_mime "$FILENAME" "$DIR" - fi + if [ "$RESUME_EDITING" != "y" ]; then + rm -rf "$DIR" + mkdir -p "$DIR" + unpack_mime "$FILENAME" "$DIR" + fi - OLD_DIR="$(pwd)" - cd "$DIR" - if ! "$EDITOR" "$DIR/note.md"; then - die "Editor returned non-zero exit code. Leaving the note untouched." - fi - cd "$OLD_DIR" + OLD_DIR="$(pwd)" + cd "$DIR" + if ! $EDITOR "$DIR/note.md"; then + die "Editor returned non-zero exit code. Leaving the note untouched." + fi + cd "$OLD_DIR" - UNIX_TIMESTAMP=$(date "+%s") - HOSTNAME=$(hostname -s) + UNIX_TIMESTAMP=$(date "+%s") + HOSTNAME=$(hostname -s) - RESULT=$(mktemp) - pack_mime "$DIR" "$RESULT" + RESULT=$(mktemp) + pack_mime "$DIR" "$RESULT" - if ! notes_equal "$RESULT" "$FILENAME"; then - DEST_FILENAME="$UNIX_TIMESTAMP.${PID}_1.${HOSTNAME}:2,S" - mv "$RESULT" "$BASEDIR/cur/$DEST_FILENAME" - rm "$FILENAME" - fi - rm -rf "$DIR" + if ! notes_equal "$RESULT" "$FILENAME"; then + DEST_FILENAME="$UNIX_TIMESTAMP.${PID}_1.${HOSTNAME}:2,S" + mv "$RESULT" "$BASEDIR/cur/$DEST_FILENAME" + rm "$FILENAME" + fi + rm -rf "$DIR" } 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;\ - }\ - " + 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 -h "^Subject:\|^X-Note-Id:\|^X-Date:" "$BASEDIR" | awk "$FILTER" | sort | cut -d " " -f "2-" } export_note() { - ID="$1" - FILENAME="$(assert_find_file_by_id "$ID")" + ID="$1" + FILENAME="$(assert_find_file_by_id "$ID")" - DIR="$2" - if [ -z "$DIR" ]; then - DIR="$(mktemp -d)" - unpack_mime "$FILENAME" "$DIR" + DIR="$2" + if [ -z "$DIR" ]; then + DIR="$(mktemp -d)" + unpack_mime "$FILENAME" "$DIR" - cat "$DIR/note.md" - rm -rf "$DIR" - else - unpack_mime "$FILENAME" "$DIR" - fi + cat "$DIR/note.md" + rm -rf "$DIR" + else + unpack_mime "$FILENAME" "$DIR" + fi } get_raw_graph() { - UUID_RE="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" - FILTER="\ - BEGIN { \ - message_id=0; \ - subject=0; \ - } \ - match(\$0, /^X-Note-Id: .*$/) { \ - if (message_id != 0) { \ - if (subject !=0)\ - print \"node\", message_id, subject; \ - subject = 0 \ - };\ - message_id = substr(\$0, 12, RLENGTH-11) \ - } \ - match(\$0, /^Subject: .*$/) { \ - if (subject != 0) { \ - if (message_id != 0)\ - print \"node\", message_id, subject; \ - message_id = 0 \ - }; \ - subject = substr(\$0, 10, RLENGTH-9) \ - } \ - match(\$0, /^note:\/\/.*$/) { \ - link_to = substr(\$0, 8, RLENGTH-7); \ - if (subject != 0 && message_id != 0) { \ - print \"link\", message_id, link_to; \ - }; \ - } \ - END { \ - if (message_id != 0 && subject != 0)\ - print \"node\", message_id, subject;\ - }\ - " - grep -E -i -o -r -h "^X-Note-Id: $UUID_RE|^Subject.*$|note://$UUID_RE" \ - "$BASEDIR"/cur | awk "$FILTER" + UUID_RE="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + FILTER="\ + BEGIN { \ + message_id=0; \ + subject=0; \ + } \ + match(\$0, /^X-Note-Id: .*$/) { \ + if (message_id != 0) { \ + if (subject !=0)\ + print \"node\", message_id, subject; \ + subject = 0 \ + };\ + message_id = substr(\$0, 12, RLENGTH-11) \ + } \ + match(\$0, /^Subject: .*$/) { \ + if (subject != 0) { \ + if (message_id != 0)\ + print \"node\", message_id, subject; \ + message_id = 0 \ + }; \ + subject = substr(\$0, 10, RLENGTH-9) \ + } \ + match(\$0, /^note:\/\/.*$/) { \ + link_to = substr(\$0, 8, RLENGTH-7); \ + if (subject != 0 && message_id != 0) { \ + print \"link\", message_id, link_to; \ + }; \ + } \ + END { \ + if (message_id != 0 && subject != 0)\ + print \"node\", message_id, subject;\ + }\ + " + grep -E -i -o -r -h "^X-Note-Id: $UUID_RE|^Subject.*$|note://$UUID_RE" \ + "$BASEDIR"/cur | awk "$FILTER" } get_graph() { - UUIDLEN=36 - FILTER="\ - BEGIN { \ - print \"graph notes {\" \ - } \ - {\ - if (\$1 == \"node\") {\ - printf \" \\\"%s\\\" \", \$2;\ - printf \"[label=\\\"%s\\\"]\", substr(\$0, $UUIDLEN + 7, length(\$0) - $UUIDLEN - 5);\ - printf \";\\n\";\ - }\ - if (\$1 == \"link\") {\ - printf \" \\\"%s\\\" -- \\\"%s\\\";\\n\", \$2, \$3;\ - }\ - }\ - END { \ - print \"}\" \ - } \ - " - get_raw_graph | sort -r | sed 's/"/\\"/g' | awk "$FILTER" + UUIDLEN=36 + FILTER="\ + BEGIN { \ + print \"graph notes {\" \ + } \ + {\ + if (\$1 == \"node\") {\ + printf \" \\\"%s\\\" \", \$2;\ + printf \"[label=\\\"%s\\\"]\", substr(\$0, $UUIDLEN + 7, length(\$0) - $UUIDLEN - 5);\ + printf \";\\n\";\ + }\ + if (\$1 == \"link\") {\ + printf \" \\\"%s\\\" -- \\\"%s\\\";\\n\", \$2, \$3;\ + }\ + }\ + END { \ + print \"}\" \ + } \ + " + get_raw_graph | sort -r | sed 's/"/\\"/g' | awk "$FILTER" } usage() { @@ -627,18 +627,18 @@ while (( "$#" )); do edit_entry "$2" exit 0 ;; - -E|--export) + -E|--export) if [ -z "$2" ]; then echo "Misssing arguments for $1" exit 1 fi - export_note "$2" "$3" - exit 0 - ;; - -g|--graph) - get_graph - exit 0 - ;; + export_note "$2" "$3" + exit 0 + ;; + -g|--graph) + get_graph + exit 0 + ;; *) usage exit 1