Skip to content

Instantly share code, notes, and snippets.

@eneuhauser
Last active June 4, 2020 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eneuhauser/2d5ab02cac5f5febbf5d37045e2174a7 to your computer and use it in GitHub Desktop.
Save eneuhauser/2d5ab02cac5f5febbf5d37045e2174a7 to your computer and use it in GitHub Desktop.
Notable CLI

Installation

  1. Put these in a $DOTFILES/zsh/functions folder
  2. Make sure completions is loaded in your ZSH
  3. Add functions path to the fpath in ~/.zshenv
  4. Autoload the functions in your ~/.zshrc
# ~/.zshenv
fpath=(
  $DOTFILES/zsh/functions
  $fpath
)
autoload -U compinit && compinit
# ~/.zshrc
if [[ -d $DOTFILES/zsh/functions ]]; then
  for func in $DOTFILES/zsh/functions/*(:t); autoload -U $func
fi
#compdef n
function _list_cmds {
local -a cmdlist
cmdlist=('tags:lists current tags' '-h:displays usage')
_describe -t note-commands 'note commands' cmdlist
}
function _list_tags {
local -a taglist
taglist=($(n tags))
_describe -t n-tags 'current tags' taglist
}
local _notes="$NOTES_DIR"
if [[ "$_notes" == "" ]]; then
[[ -e "$HOME/.notable.json" ]] && _notes=`grep "\"cwd\"" "$HOME/.notable.json" | awk '{print $2}' | sed -n "s/[,\"]//pg"`
[[ "$_notes" == "" ]] && _notes="$HOME/.notable"
_notes="$_notes/notes"
fi
_arguments -n : \
"1:cmd: _alternative 'opt:options:_list_cmds' 'src:existing notebook/file:_files -W \"$_notes\"'" \
'-d[prepends current date to the filename and title]' \
'-t[outputs details instead of creating file for testing]' \
'*:tag:_list_tags' && return 0
usage() {
echo "SYNOPSIS"
echo " Supports creating/opening a notable file in vim using either a file"
echo " name style or a todo.txt style. If the file exists, the existing"
echo " file will be opened."
echo ""
echo "FILENAME STYLE"
echo " n file-name # Creates a new note in the _Inbox notebook"
echo " n Example/file-name # Creates a new note in the Example notebook"
echo " n Example/file-name tag1 parent/tag2 -d # Full example"
echo ""
echo "TODO.TXT STYLE"
echo " n \"File Name\" # Creates a new note in the _Inbox notebook"
echo " n \"File Name @Example\" # Creates a new note in the Example notebook"
echo " n \"File Name +tag1 +parent/tag2 @Example\" -d # Full example"
echo ""
echo "DESCRIPTION"
echo " tags Lists current tags"
echo " -d Prepends current date to the filename and title"
echo " -t Outputs details instead of creating file for testing"
echo " -h Displays usage information"
}
local _input="$1"
local _file=''
local _path=''
local _nb=''
local _tags=''
local _title=''
local _help=false
local _ts=false
local _debug=false
[[ "$1" = "-h" ]] && _help=true
for i in "${@:2}"; do
if [ "$i" = '-d' ]; then
_ts=true
elif [ "$i" = '-t' ]; then
_debug=true
elif [ "$i" = '-h' ]; then
_help=true
else
_tags="$_tags, $i"
fi
done
local _notes="$NOTES_DIR"
if [[ "$_notes" = "" ]]; then
[[ -e "$HOME/.notable.json" ]] && _notes=`grep "\"cwd\"" "$HOME/.notable.json" | awk '{print $2}' | sed -n "s/[,\"]//pg"`
[[ "$_notes" = "" ]] && _notes="$HOME/.notable"
_notes="$_notes/notes"
fi
if [ ! -e "$_notes" ]; then
echo "Base notes directory '$_notes' does not exist."
[[ "$_help" != "true" ]] && return 129
fi
if [ "$#" -eq 0 ]; then
cd "$_notes"
return 129
fi
_path="$_notes/$_input"
[[ ! -e "$_path" ]] && _path="$_path.md"
if [ -e "$_path" ]; then
(cd "$_notes" && vim $_path)
return 129
fi
if [ "$_help" = "true" ]; then
usage
return 129
fi
if [ "$_input" = 'tags' ]; then
grep -r '^tags:' $_notes | sed -n "s/^.*\[\(.*\)\]/\1/p" | sed -n "s/,\s*/\n/pg" | grep -v "Notebooks/" | sort -u
return 129
fi
# Tests
# n test-note
# n test-note.md
# n test-note tag1
# n test-note.md tag1 parent/child
# n Test/test-note
# n Test/test-note.md
# n Test/test-note.md tag1 tag2
# n Test/test-note.md tag1 tag2 -d
parseFileName() {
_file=${_input##*/} # get after last slash
_file=${_file%".md"} # strip extension
_nb=${_input%/*} # get up to last slash
[[ "$_nb" = "$_input" ]] && _nb=_Inbox
_title=`echo "$_file" | sed 's/-/ /g; s/.*/\L&/; s/[a-z]*/\u&/g'` # convert snake-case to Title Case
_tags="Notebooks/$_nb$_tags"
}
# Tests
# n "My Title"
# n "My Title @Test"
# n "My Title +tag"
# n "My Title +parent/child +tag @Test"
# n "My Title @Test +parent/child"
parseTodoTxt() {
_nb="${_input#*@}" # get string starting with @
if [ "$_nb" = "$_input" ]; then # no @ symbol
_nb=_Inbox
_title="$_input"
else
_nb=${_nb%% *} # get to first space
_title="${_input// @$_nb/}" # removes the notebook
fi
_tags=" +${_title#*+}" # get from first +
[[ "$_tags" = " +$_title" ]] && _tags="" # no pluses
_title="${_title//$_tags}" # strips the tags
_tags="Notebooks/$_nb${_tags// +/, }" # replaces ' +' with ', '
_file=`echo "$_title" | sed 's/ /-/g; s/.*/\L&/g'` # convert Title Case to snake-case
}
if [[ "$_input" == *' '* ]]; then # todo.txt style
parseTodoTxt
else # filename style
parseFileName
fi
if [ "$_ts" = "true" ]; then
local _today="$(date --iso-8601 -u)"
_file="$_today-$_file"
_title="$_today $_title"
fi
_path="$_notes/$_nb/$_file.md"
local _header=$(printf "%s\n" "---" \
"tags: [$_tags]" \
"title: $_title" \
"created: '$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")'" \
"---" "" \
"# $_title")
if [ "$_debug" = "true" ]; then
echo "[file=$_path]"
echo "$_header"
return 128
fi
if [[ ! -e "$_path" ]]; then
local _dir=`dirname "$_path"`
if [[ ! -e "$_dir" ]]; then
read -r -k 1 "REPLY?Notebook '$_nb' does not exist. Do you want to create it? [Yn] "
if [[ "$REPLY" =~ "^[a-xzA-XZ]$" ]]; then
echo ""
return 128
else
[[ "$REPLY" =~ "^[yY]$" ]] && echo ""
mkdir -p "$_dir"
fi
fi
printf "%s\n" "$_header" "" >$_path
fi
(cd "$_notes" && vim $_path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment