A new project to make it easy to manage notes from the command line. This does more than jot and serves a different purpose. Initial commit.
This commit is contained in:
226
notestorm
Executable file
226
notestorm
Executable file
@@ -0,0 +1,226 @@
|
||||
#!/bin/bash
|
||||
# notestorm
|
||||
# Description: Easily take and read notes from the CLI.
|
||||
#
|
||||
# Copyright 2019, F123 Consulting, <information@f123.org>
|
||||
# Copyright 2019, Storm Dragon, <storm_dragon@linux-a11y.org>
|
||||
#
|
||||
# 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
|
||||
Reference in New Issue
Block a user