diff --git a/notestorm b/notestorm new file mode 100755 index 0000000..cf8eaec --- /dev/null +++ b/notestorm @@ -0,0 +1,226 @@ +#!/bin/bash +# notestorm +# Description: Easily take and read notes from the CLI. +# +# Copyright 2019, F123 Consulting, +# Copyright 2019, Storm Dragon, +# +# This is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this package; see the file COPYING. If not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. +# +#--code-- + +# the gettext essentials +export TEXTDOMAIN=notestorm +export TEXTDOMAINDIR=/usr/share/locale +source gettext.sh + +# Log writing function +log() { + # Usage: command | log for just stdout. + # Or command |& log for stderr and stdout. + while read -r line ; do + echo "$line" | tee -a "$logFile" &> /dev/null + done +} + +# Log file name is ~/.cache/scriptname +logFile="${HOME}/.cache/${0##*/}" + + +# Functions section + +infobox() { + # Returns: None + # Shows the provided message on the screen with no buttons. + local continue + dialog --infobox "$*" 10 80 + read -n1 -t $messageTimeout continue +} + +yesno() { + # Returns: Yes or No + # Args: Question to user. + # Called in if $(yesno) == "Yes" + # Or variable=$(yesno) + dialog --backtitle "$(gettext "Press 'Enter' for \"yes\" or 'Escape' for \"no\".")" --yesno "$*" 10 80 --stdout + if [[ $? -eq 0 ]]; then + echo "Yes" + else + echo "No" + fi +} + +menulist() { + # Args: Tag, description. + # returns: selected tag + dialog --backtitle "$(gettext "Use the up and down arrow keys to find the option you want, then press enter to select it.")" \ + --cancel-label "Exit" \ + --extra-button \ + --extra-label "Edit" \ + --help-button \ + --help-label "Delete" \ + --ok-label "View" \ + --no-tags \ + --menu "$(gettext "Please select one")" 0 0 0 $@ --stdout +} + +add_note() { + # Notes are named based on number of seconds since 1970. + # If the note exists it is incremented until the name is available. + local noteName=$(date '+%s') + while [ -f "${xdgPath}/notestorm/notes/${noteName}.md" ]; do + ((noteName++)) + done + $editor "${xdgPath}/notestorm/notes/${noteName}.md" + if [ -f "${xdgPath}/notestorm/notes/${noteName}.md" ]; then + infobox "Note added." + else + infobox "Note canceled." + fi +} + +delete_note() { + local text="$(head -1 "$1")" + local answer="$(yesno "$(gettext "Really delete note starting with text") \"$text\"?")" + if [ "$answer" == "Yes" ]; then + rm -f "$1" + infobox "$(gettext "Note deleted.")" + else + infobox "$(gettext "Action canceled.")" + fi +} + +display_note() { + markdown "$1" | eval "$pager" +} + +edit_note() { + local oldMd5="$(md5sum "$1")" + $editor "$1" + local newMd5="$(md5sum "$1")" + if [ "$oldMd5" != "$newMd5" ]; then + infobox "$(gettext "Changes saved.")" + else + infobox "$(gettext "Changes discarded.")" + fi +} + +# Configuration section +# Available arguments in both long and short versions stored in associative array. +declare -A argList=( + [n]="new") +# Make the args a continuous string. +short="${!argList[*]}" +short="${short// /}" +long="${argList[*]}" +long="${long// /}" +editor="${EDITOR:-nano}" +messageTimeout=${messageTimeout:-1} +# Set pager +if command -v w3m &> /dev/null ; then + pager="w3m -T text/html" +elif command -v elinks &> /dev/null ; then + pager="elinks -force-html" +elif command -v lynx &> /dev/null ; then + pager="lynx -force_html" +else + pager="${PAGER:-more}" +fi +xdgPath="${XDG_CONFIG_HOME:-$HOME/.config}" +#set up the notes directory +mkdir -p "${xdgPath}/notestorm/notes" +# Keep track of the number of arguments passed to the program. +argNum=$# +# Settings to improve accessibility of dialog. +export DIALOGOPTS='--insecure --no-lines --visit-items' +# Dialog custom configuration file +export DIALOGRC="${xdgPath}/notestorm/dialogrc" +# Generate dialogrc if it does not exist. +if ! [ -e "$DIALOGRC" ]; then + dialog --create-rc "$DIALOGRC" + # Add keybindings to dialogrc + echo >> "$DIALOGRC" + echo "# Edit keybinding" >> "$DIALOGRC" + echo "bindkey menu ~E EXTRA" >> "$DIALOGRC" +fi + + +# Code section + +if ! options=$(getopt -o "$short" -l "$long" -n "notestorm" -- "$@"); then + gettext -e "Usage: notestorm launch interactive session.\n" + gettext -e -- "-n or --new add a new note without opening an interactive session.\n" + echo + gettext -e "You can use markdown syntax in notes.\n" + gettext -e "Notes are named numerically. they can be renamed and will still show up so long as they end with a .md extension.\n" + gettext "Notes are saved in " + echo "${xdgPath}/notestorm/notes" + exit 1 +fi + +eval set -- "$options" + +while [ $# -gt 0 ]; do + case "$1" in + "-n"|"--new") add_note;; + esac + shift +done + +# If there were args, the program was controled by those and we do not need the menu. +if [ $argNum -gt 0 ]; then + exit 0 +fi + +while [ "$action" != "exit" ]; do + # Get a list of notes + mapfile -t notes < <(find "$xdgPath/notestorm/notes" -type f -iname '*.md') + # Generate the note menu: + unset noteMenu + declare -a noteMenu + for i in "${notes[@]}" ; do + noteMenu+=("$i") + noteMenu+=("$(head -1 "${i}")") + done + + # Create menu of actions and notes. + ifs="$IFS" + IFS=$'\n' + action="$(menulist \ + "add_note" "$(gettext "New note")" \ + "${noteMenu[@]}" \ + "exit" "$(gettext "Exit")")" + dialogCode=$? + IFS="$ifs" + + if [ -z "$action" ]; then + action="exit" + fi + + # Run selected action + case "${action}" in + "add_note") add_note;; + "exit") exit 0;; + *) + case $dialogCode in + 0) display_note "${action}";; + 2) delete_note "${action#HELP }";; + 3) edit_note "${action}";; + esac;; + esac +done + +exit 0