Skip to content

Instantly share code, notes, and snippets.

@cedricpim
Last active August 16, 2018 06:44
Show Gist options
  • Save cedricpim/266ee4807ed81117f74812e60756dae6 to your computer and use it in GitHub Desktop.
Save cedricpim/266ee4807ed81117f74812e60756dae6 to your computer and use it in GitHub Desktop.
#!/bin/bash
# From https://github.com/ginatrapani/todo.txt-cli/tree/addons/.todo.actions.d/adda
action=$1
shift
[ "$action" = "usage" ] && {
echo " Add and prioritize A:"
curcmd=`basename $0`
echo " $curcmd \"THING I NEED TO DO +project @context\""
echo " Add an item and prioritize it A in one step"
echo ""
exit
}
if "$TODO_SH" command add "$@"; then
# figure out the line of what we just added, and prioritize it A
line=`sed -n '$ =' "$TODO_FILE"`
echo "$line"
"$TODO_SH" command pri "$line" A
fi
#!/bin/bash
# Frome https://github.com/xzys/todotxt-study-suite/blob/master/.todo.actions.d/addr
action=$1
shift
[ "$action" = "usage" ] && {
echo " Add with the tags of most recent addition:"
curcmd=`basename $0`
echo " $curcmd \"THING I NEED TO DO +project @context\""
echo " Append the tags of the most recently added item"
echo " to this item."
echo ""
exit
}
# get the last line added and extract context
lastadded=`sed -n '$ =' "$TODO_FILE"`
"$TODO_FULL_SH" command add "$1"
newest=`sed -n '$ =' "$TODO_FILE"`
REGEX='[@|+][A-Za-z0-9]*'
echo "Appending:" $(sed $lastadded"q;d" "$TODO_FILE" | grep -o "$REGEX")
# add contexts and projects
sed $lastadded"q;d" "$TODO_FILE" | grep -o "$REGEX" | while read -r app
do
"$TODO_FULL_SH" command append "$newest" "$app"
done
# set priority
# PRIREGEX='\(([A-Z])\)'
# matchpri=`sed $lastadded"q;d" "$TODO_FILE" | grep -o "$PRIREGEX"`
# # if there is a proiority on the last one
# count=`echo $matchpri | wc -l`
# if [ $count -ne 0 ]; then
# # remove parentheses
# matchpri=`echo $matchpri | sed 's/[)(]//g'`
# echo "Prioritizing:" $matchpri
# "$TODO_FULL_SH" command pri "$newest" "$matchpri"
# fi
#!/bin/bash
# From https://github.com/mgarrido/todo.txt-cli/blob/note/todo.actions.d/archive
[ "$1" = "usage" ] && exit 0
grep "^x" "$TODO_FILE" | while read -r line; do "$TODO_SH" note __archive $line; done
"$TODO_SH" command "$@"
#!/bin/bash
# From https://github.com/mgarrido/todo.txt-cli/blob/note/todo.actions.d/del
[ "$1" = "usage" ] && exit 0
item="$2"
# Take into account "del #ITEM TERM"
if [ -z "$3" ]; then
getTodo "$item"
fi
"$TODO_SH" command "$@"
[ $? -eq 0 ] && [ -z "$3" ] && "$TODO_SH" note __rmfromtext "DDDD$todo"
#!/bin/bash
# From https://github.com/Thann/todo-cli-plugins/blob/master/edit
case $1 in
"usage")
echo "$(basename $0) [BASENAME]"
echo " Open \$TODO_DIR/BASENAME.txt in \$EDITOR."
echo " If BASENAME is not given, defaults to 'todo'."
;;
*)
FILE=${2:-todo}.txt
if [ -n "$EDITOR" ]; then
$EDITOR $TODO_DIR/$FILE
else
echo "Error: The EDITOR environment variable is not set"
fi
;;
esac
#!/bin/bash
# From https://github.com/cedricpim/todo.txt-graph/blob/master/graph
# v0.1.0
action=$1
flag=$2
shift
[ "$action" = "usage" ] && {
echo ""
echo " Visualize done tasks:"
echo " graph"
echo " Draws bar graphs visualizing the number of completed task per day."
echo " Optional argument (integer): number of days to visualize (default: 7)"
echo ""
exit
}
[ "$action" = "graph" ] && {
# check if python2 is defined
if hash python2 2>/dev/null; then
python2 "$TODO_ACTIONS_DIR"/graph.py "$TODO_DIR" $flag
else
# use default python
python "$TODO_ACTIONS_DIR"/graph.py "$TODO_DIR" $flag
fi
}
#!/bin/sh
# encoding: utf-8
from __future__ import print_function
''''which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" # '''
''''which python >/dev/null 2>&1 && exec python "$0" "$@" # '''
''''exec echo "Error: I can't find python anywhere" # '''
# Author: Tim Pulver
# Date: 2015
# https://github.com/timpulver/todo.txt-graph
#
# Visualizes the completed tasks in todo.txt with horizontal bar graphs
# Items are coloured green when there are more than 5 completed tasks per day,
# grey otherwise to motivate completing stuff.
# Have a look at Jerry Seinfeld's "Don't break the chain" methodoligy:
# https://dontbreakthechain.com/what
# You can change the threshold by adding this line to your todo.cfg file:
# export TODOTXT_GRAPH_THRESHOLD=123
#
# Params:
# - TODO_TXT_PATH: Where the todo.txt / done.txt file is located
# - NUMBER_OF_DAYS: How many days should be visualized (optional, default: 7)
import datetime
import sys
import os
import re
import collections
TICK_CHAR = '■'
DEFAULT_THRESHOLD = 5 # grey bar < DEFAULT_THRESHOLD >= green bar
WIDTH = 60 # Graph width
DONE = "done.txt"
# try to use xrange, which is faster
try:
range = xrange
except NameError:
pass
# Bash color codes and color helper class from:
# https://github.com/emilerl/emilerl/blob/master/pybash/bash/__init__.py
RESET = '\033[0m'
CCODES = {
'black' :'\033[0;30m',
'blue' :'\033[0;34m',
'green' :'\033[0;32m',
'cyan' :'\033[0;36m',
'red' :'\033[0;31m',
'purple' :'\033[0;35m',
'brown' :'\033[0;33m',
'light_gray' :'\033[0;37m',
'dark_gray' :'\033[0;30m',
'light_blue' :'\033[0;34m',
'light_green' :'\033[0;32m',
'light_cyan' :'\033[0;36m',
'light_red' :'\033[0;31m',
'light_purple' :'\033[0;35m',
'yellow' :'\033[0;33m',
'white' :'\033[0;37m',
}
# A helper class to colorize strings
class Colors(object):
def __init__(self, state = False):
self.disabled = state
def disable(self):
self.disabled = True
def enable(self):
self.disabled = False
def __getattr__(self,key):
if key not in CCODES.keys():
raise AttributeError, "Colors object has no attribute '%s'" % key
else:
if self.disabled:
return lambda x: x
else:
return lambda x: RESET + CCODES[key] + x + RESET
def __dir__(self):
return self.__class__.__dict__.keys() + CCODES.keys()
# Graph based on:
# https://github.com/mkaz/termgraph/blob/master/termgraph.py
def print_blocks(label, count, step):
blocks = int(count / step)
print("{}: ".format(label), end="")
threshold = int(os.getenv('TODOTXT_GRAPH_THRESHOLD', DEFAULT_THRESHOLD))
c = Colors()
for i in range(blocks):
if count >= threshold:
sys.stdout.write(c.green(TICK_CHAR))
else:
sys.stdout.write(c.light_gray(TICK_CHAR))
# format the text (number of tasks done)
if count < 10:
print("{:>2.0f}".format(count))
elif count < 100:
print("{:>3.0f}".format(count))
else:
print("{:>4.0f}".format(count))
# Based on Lately Addon:
# https://github.com/emilerl/emilerl/tree/master/todo.actions.d
def main(directory, cutoffDays = 7):
f = open(os.path.join(directory, DONE), 'r')
lines = f.readlines()
today = datetime.datetime.today()
cutoff = today - datetime.timedelta(days=cutoffDays)
dic = {}
for line in lines:
m = re.match("x ([\d]{4}-[\d]{2}-[\d]{2}).*", line)
if m is not None:
done = m.group(1)
year, month, day = m.group(1).split("-")
completed = datetime.datetime(int(year),int(month),int(day))
if completed >= cutoff:
#print c.green(m.group(1)) + " " + c.blue(line.replace("x %s" % m.group(1), "").strip())
if m.group(1) in dic:
oldVal = dic.get(m.group(1), 1)
dic.update({m.group(1): oldVal+1})
else:
dic[m.group(1)] = 1
# find out max value
max = 0
for key, value in dic.iteritems():
if value > max:
max = value
maxf = float(max)
step = maxf / WIDTH
orderedDic = collections.OrderedDict(sorted(dic.items()))
# display graph
print()
for key, value in orderedDic.iteritems():
print_blocks(key, value, step)
print()
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: graph.py [TODO_DIR] <days back>")
sys.exit(1)
if os.path.isdir(sys.argv[1]):
if len(sys.argv) is 3:
main(sys.argv[1], int(sys.argv[2]))
else:
main(sys.argv[1])
else:
print("Error: %s is not a directory" % sys.argv[1])
sys.exit(1)
#!/bin/bash
#
# MIT
#
# Bash script to add funcitonality to todo.txt cli by Gina Trapani. Most
# Important Tasks (MIT) are intended to be specific todo items associated
# with a specific day. They differ from events in that they do not necessarily
# have a specified time. As a best practice only 3 MITs should be scheduled
# per day. This script is intended to parse the todo.txt file and generate a
# schedule of MITs by day of the week if no arguments are given, or add new
# MITs to the list.
#
# MITs are stored in the following format:
# {YYYY.MM.DD} mit task information
#
# Author(s): Cody Buell
#
# Licensing: GPL, http://www.gnu.org/copyleft/gpl.html
#
# Revisions: 2012.06.27 Framework roughed out.
# 2012.06.28 Initial version completed.
# 2012.06.29 Moved away from using DOY to prevent problems in
# spanning years.
# 2012.07.01 Added ability to move MITs.
# 2012.07.02 Made greps a bit more robust.
# 2012.07.13 Added ability to invert context listings.
# 2012.09.22 Modified greps and seds to handle MITs with priorities.
# 2012.10.29 Merged corrections from 00Davo regarding #2.
# 2012.10.31 Added BSD vs GNU date detection.
# 2013.01.16 Merged enhancements from rcraggs, adding ability to move
# non-mit tasks into a mit and vise versa. Incremented
# version number from 1.1 to 1.2. Setup core functions,
# added short options section and re-arranged accordingly.
# 2013.03.10 Added support for dated tasks per Justin Le's request.
# Incremented version number from 1.2 to 1.3.
# 2015.06.29 Support for GNU Sed 4.2.2.
#
# Requisite: todo.sh by Gina Trapanni
#
# Resources: https://github.com/ginatrapani/todo.txt-cli/wiki
#
# Task List: - Add extra check on mit mv to see that it is an MIT being moved.
# - Add ability to add a time {YYYY.MM.DD HH:MMam/pm}
# t mit today@10pm go to work @nasa
# - Fix mv function so that when a task is converted to a mit, the
# whole task name is displayed in the results. Currently it
# snips out the first word.
# - Create brew formula.
# - Rewrite in a speedier language.
# - Date tab hinting, dates with weekday names, on mit creation.
# - Add 't mit [today,tomorrow,dow]' report output.
# - Ability to sort, prioritize and schedule.
# - Add 'events' to mit, non completable items that auto remove after date.
# - Overview to show exact dates for 0 - 14 days out, then by 'this month' then 'next month +'
###################
# Usage Functions #
###################
usage() {
cat <<-ENDOFUSAGE
Most Important Tasks (MIT):
Displays from or adds Most Important Tasks (MIT) to todo.txt file.
$(basename $0) [-h|--help] [-v|--version] [date|day task] [rm ID]
[not @context|@context] [mv ID DATE|DAY]
-h, --help Displays help message.
-v, --version Displays version information.
mit DATE|DAY task
DATE must be in the format of YYYY.MM.DD.
DAY can be full or short day names, today or tomorrow.
mit rm ID
Convert the MIT identified by ID to a standard task.
mit not @context|@context
Displays all MIT's not in or in specified context.
mit mv ID DATE|DAY
Move the MIT identified by ID to a new day.
DATE must be in the format of YYYY.MM.DD.
DAY can be full or short day names, today or tomorrow.
mit wed upload code to github
Creates a new MIT for next Wednesday unless the current day
is Wednesday in which case it will be created for today.
ENDOFUSAGE
exit
}
error() {
echo "error: $1"
echo "usage: $(basename $0) [-hv] [date|day task] [not @context|@context] [mv ID DATE|DAY]"
}
version() {
echo "mit version $VERSION"
}
####################
# Helper Funcitons #
####################
makeDOW() {
# format YYYY.MM.DD to day of week (Monday)
if [ $DVER = "BSD" ]; then
eval $1=`date -j -f "%Y.%m.%d" $2 +%A`
else
local DAY=`echo $2 | sed 's/\./\//g'`
eval $1=`date -d $DAY +%A`
fi
}
makeDATE() {
# format YYYY.MM.DD to Day, Month DD
if [ $DVER = "BSD" ]; then
eval $1=`date -j -f "%Y.%m.%d" $2 "+%A', '%B' '%d"`
else
local DAY=`echo $2 | sed 's/\./\//g'`
eval $1=`date -d $DAY "+%A', '%B' '%d"`
fi
}
parseDAY() {
# create YYYY.MM.DD from upcoming day of week
if [ $DVER = "BSD" ]; then
MITDATE=`date -v +$1 +%Y.%m.%d`
else
local dayid=$1
if [ $dayid = "1d" ]; then
dayid="1day"
fi
MITDATE=`date -d +$dayid +%Y.%m.%d`
fi
}
getMITS() {
# print out mits matching specific date criteria
for (( i=0; i < ${#MITS[@]}; i++ )); do
MITDATE=`echo ${MITS[$i]} | awk '{print $1}' | sed 's/\.//g'`
MITTASK=`echo ${MITS[$i]} | awk '{$1 = ""; print}'`
if [ "$MITDATE" $1 "$2" ]; then
echo " $MITTASK"
fi
done
}
##################
# Core Functions #
##################
moveMIT() {
# check that second argument is an id and a valid one
if [[ $1 =~ ^[0-9]+$ ]]; then
MITTASK=`awk -v ID=$1 'NR==ID {sub(/\{[0-9.]{10}\}/, ""); sub(/^ /, ""); print "\x27"$0"\x27"}' "$TODO_FILE"`
TASK=`awk -v ID=$1 'NR==ID {print "\x27"$0"\x27"}' "$TODO_FILE"`
# Add a date to this item if there is none so that we can move it.
if [[ ! $TASK =~ \{[0-9]{4}\.[0-9]{2}\.[0-9]{2}\} ]]; then
TODAY="`date +%Y.%m.%d`"
FIRST_PART=`awk '{print $1"\x27"}' <<< $TASK`
SECOND_PART=`awk '{print "\x27"$2"\x27"}' <<< $TASK`
if [[ $FIRST_PART =~ ([A-Z] ) ]]; then
if [[ $SECOND_PART =~ [0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then
$SEDI "$1 s/\(^([A-Z]\{1\} ) [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} \)\(.*$\)/\1{$TODAY} \2/" "$TODO_FILE"
else
$SEDI "$1 s/\(^([A-Z]\{1\} ) \)\(.*$\)/\1{$TODAY} \2/" "$TODO_FILE"
fi
elif [[ $FIRST_PART =~ [0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then
$SEDI "$1 s/\(^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} \)\(.*$\)/\1{$TODAY} \2/" "$TODO_FILE"
else
$SEDI "$1 s/^/{$TODAY} /" "$TODO_FILE"
fi
fi
case $2 in
today )
MITDATE="`date +%Y.%m.%d`"
$SEDI "$1 s/{[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}}/{$MITDATE}/" "$TODO_FILE"
echo "TODO: MIT $MITTASK moved to today."
exit
;;
tomorrow )
parseDAY 1d
$SEDI "$1 s/{[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}}/{$MITDATE}/" "$TODO_FILE"
echo "TODO: MIT $MITTASK moved to tomorrow."
exit
;;
monday|mon|tuesday|tue|wednesday|wed|thursday|thu|friday|fri|saturday|sat|sunday|sun )
parseDAY $2
makeDOW DOW $MITDATE
$SEDI "$1 s/{[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}}/{$MITDATE}/" "$TODO_FILE"
echo "TODO: MIT $MITTASK moved to $DOW."
exit
;;
[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9][0-9] )
makeDATE DATE $2
$SEDI "$1 s/{[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}}/{$2}/" "$TODO_FILE"
echo "TODO: MIT $MITTASK moved to $DATE."
exit
;;
* )
error "invalid date"
exit
;;
esac
else
error "invalid task id"
exit
fi
}
removeMIT() {
$SEDI "$1 s/{[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}}[ ]*//" "$TODO_FILE"
echo "Removed MIT from task $1"
}
#######################
# Establish Variables #
#######################
if date -v 1d > /dev/null 2>&1; then # detect date version in use
DVER="BSD" # set as bsd date
else # if it isn't bsd then...
DVER="GNU" # set as gnu date
fi
if sed --version > /dev/null 2>&1; then # detect sed version in use
SEDI="sed -i " # set as gnu sed syntax
else # if it isn't gnu then...
SEDI="sed -i '' " # set as bsd sed syntax
fi
VERSION="1.4" # mit version number
ACTION=$1 # set first argument to action
shift # shift arguments
################
# Long Options #
################
# display usage
[ "$ACTION" = "usage" ] || [ x"$1" = x"--help" ] && {
usage
exit
}
# display version
[ x"$1" = x"--version" ] && {
version
exit
}
# move mit
[ x"$1" = x"mv" ] && {
moveMIT $2 $3
}
# remove mit
[ x"$1" = x"rm" ] && {
removeMIT $2
exit
}
#################
# Short Options #
#################
while getopts ":hv" Option; do
case $Option in
h )
usage
exit
;;
v )
version
exit
;;
: )
echo "Option -$OPTARG requires an argument." >&2
exit
;;
esac
done
##########
# Run It #
##########
# DISPLAY MITS
[ -z $1 ] || [[ $1 =~ @.* ]] || [ "$1" = "not" ] && {
# define array element separator as newlines
OLDIFS=$IFS
IFS=$'\n'
# invert search if not is specified before context
if [ "$1" = "not" ]; then
shift
FLAG="-v"
else
FLAG=""
fi
# pull out MITs from the todo file, clean and sort
# grepping for "X {YYYY.MM.DD}", "{YYYY.MM.DD}", "X YYYY-MM-DD {YYYY.MM.DD}" or "YYYY-MM-DD {YYYY.MM.DD}"
NUM='[0-9].* '
PRI='([A-Z]\{1\}) '
ADD='[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} '
MDD='{[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}}'
# creat an array with values like YYYY.MM.DD [priority] [task info] [task number]
MITS=(`grep -n "^$PRI$MDD\|^$MDD\|^$PRI$ADD$MDD\|^$ADD$MDD" "$TODO_FILE" | grep $FLAG "$1" | sed "s/:/ /;s/\(^$NUM\)\($PRI\)\($ADD\)\(.*$\)/\1\2\4/;s/\(^$NUM\)\($ADD\)\(.*$\)/\1\3/;s/\(^$NUM\)\($PRI\)\($MDD \)\(.*\)/\1\3\2\4/;s/{//;s/}//" | awk '{s=$1;e=$NF;$1="";$NF=e" ("s")"}1' | sort`)
# return array element separator to spaces
IFS=$OLDIFS
# make an array of ordered unique MIT dates
DATES=(`grep "^$PRI$MDD\|^$MDD\|^$PRI$ADD$MDD\|^$ADD$MDD" "$TODO_FILE" | grep $FLAG "$1" | sed 's/^.*{\([0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}\).*$/\1/' | sort | uniq`)
#DATES=(`grep "^$PRI$MDD\|^$MDD\|^$PRI$ADD$MDD\|^$ADD$MDD" "$TODO_FILE" | grep $FLAG "$1" | sed -e 's/{//' -e 's/}//' -e 's/([A-Z]\{1\})//' | awk '{print $1}' | sort | uniq`)
TODAY=`date +%Y%m%d`
# processing if there are no mits
if [ "${#DATES[@]}" -eq "0" ]; then
echo "No MITs found."
exit
fi
# processing of past due mits
PASTDUE="false"
for day in ${DATES[@]}; do
DAY=`echo $day | sed 's/\.//g'`
if [ "$DAY" -lt "$TODAY" ]; then
PASTDUE="true"
fi
done
if [ "$PASTDUE" = "true" ]; then
echo "Past Due:"
getMITS -lt $TODAY
echo ""
fi
# processing of all other mits
for day in ${DATES[@]}; do
DAY=`echo $day | sed 's/\.//g'`
DAYSTO=$(( $DAY - $TODAY ))
if [ "$DAY" -eq "$TODAY" ]; then
echo "Today:"
getMITS -eq $DAY
echo ""
elif [ "$DAYSTO" -gt "0" ] && [ "$DAYSTO" -lt "7" ]; then
makeDOW DOW $day
echo "$DOW:"
getMITS -eq $DAY
echo ""
elif [ "$DAYSTO" -ge "7" ]; then
makeDATE DATE $day
echo "$DATE:"
getMITS -eq $DAY
echo ""
fi
done
exit
}
# ADD NEW MITS
[ -n "$1" ] && {
MITDATE=`echo $1 | tr [A-Z] [a-z]`
shift
MITTASK=$@
TODAY=`date +%u`
case $MITDATE in
today )
NEWMIT="{`date +%Y.%m.%d`} $MITTASK"
;;
tomorrow )
parseDAY 1d
NEWMIT="{$MITDATE} $MITTASK"
;;
monday|mon|tuesday|tue|wednesday|wed|thursday|thu|friday|fri|saturday|sat|sunday|sun )
parseDAY $MITDATE
NEWMIT="{$MITDATE} $MITTASK"
;;
[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9][0-9] )
NEWMIT="{$MITDATE} $MITTASK"
;;
* )
error "invalid date"
exit
;;
esac
"$TODO_FULL_SH" add $NEWMIT
exit
}
#!/usr/bin/env bash
# From https://github.com/mgarrido/todo.txt-cli/blob/note/todo.actions.d/note
TODO_NOTES_DIR=$TODO_DIR/notes
TODO_NOTE_TAG="note"
TODO_NOTE_TEMPLATE="XXX"
TODO_NOTE_EXT=${TODO_NOTE_EXT:-.txt}
TODO_NOTE_ARCHIVE="$TODO_NOTES_DIR/archive$TODO_NOTE_EXT"
usage() {
echo " $(basename $0) add|a ITEM#"
echo " Adds a note to the task on line ITEM#."
echo " $(basename $0) edit|e ITEM#|archive|a"
echo " Opens in EDITOR the note related with the task on line ITEM# or the notes archive."
echo " $(basename $0) show|s ITEM#|archive|a"
echo " Shows the note related with the task on line ITEM# or the notes archive."
}
getnotenamefromnumber() {
# Parameters:
# $1: task number
# Preconditions:
# $errmsg contains usage message.
# Postcondition:
# $notename contains note name, if task has note.
# $item contains the task name
item="$1"
getTodo "$item"
getnotenamefromtext "$todo"
}
getnotenamefromtext() {
# Parameters: $1: task text
# Preconditions: none
# Postcondition:
# $notename contains note name, if task has note.
notename=$(echo "$1" | grep -o " $TODO_NOTE_TAG:[^ .]*${TODO_NOTE_EXT}" | grep -o "[^:]*${TODO_NOTE_EXT}")
}
editnote() {
# Parameter:: $1: Path of the file to edit
# Preconditions: none
# Postcondition: none
if [[ "$EDITOR" =~ "vim" ]]
then
$EDITOR -n "$1"
elif [ "$EDITOR" ]
then
$EDITOR "$1"
else
echo The EDITOR environment variable is not set.
fi
}
getnotefilepath () {
# Parameter:: $1: Task number or reference to file
# Preconditions:
# Postcondition: $notefilepath contains the path of the file to edit or show
item="$1"
if [[ "$item" ]] && [[ archive =~ ^${item}.*$ ]]
then
notefilepath=$TODO_NOTE_ARCHIVE
else
getnotenamefromnumber $1
if [ $notename ]
then
notefilepath="$TODO_NOTES_DIR/${notename}"
else
die "TODO: Task $item has no note."
fi
fi
}
mdless () {
pandoc -s -f markdown -t man $1 | groff -T utf8 -man | less
}
if [ "$1" = "usage" ]
then
usage
exit 0
fi
shift
TODO_NOTE_ACTION=$1
shift
case "$TODO_NOTE_ACTION" in
"add" | "a")
errmsg="usage: $TODO_SH $(basename $0) $TODO_NOTE_ACTION ITEM#"
getnotenamefromnumber $1
[ $notename ] && die "TODO: Task $item already has a note."
# Create notes directory if doesn't exist
[ -d "$TODO_NOTES_DIR" ] || mkdir -p "$TODO_NOTES_DIR" 2> /dev/null || die "Error: $TODO_NOTES_DIR is not a directory"
# Create file
filename=$(mktemp "$TODO_NOTES_DIR/${TODO_NOTE_TEMPLATE}")
notename=$(basename "$filename${TODO_NOTE_EXT}")
title=$(echo "$todo" | sed -e "s/^\(x ....-..-.. \)\?//" -e "s/^(.) \?//")
echo \# $title > "$TODO_NOTES_DIR/${notename}"
rm $filename # remove temporary file
# Append note tag to task
sed -i.bak $item" s/$/ ${TODO_NOTE_TAG}:$notename/" "$TODO_FILE"
getTodo "$item"
echo $item $todo
echo TODO: Note added to task $item.
echo "Edit note? (y/n)"
read ANSWER
if [ "$ANSWER" = "y" ]
then
editnote "$TODO_NOTES_DIR/${notename}"
fi
;;
"edit" | "e")
errmsg="usage: $TODO_SH $(basename $0) edit|e ITEM#|archive|a"
getnotefilepath $*
editnote "$notefilepath"
;;
"show" | "s")
errmsg="usage: $TODO_SH $(basename $0) show|s ITEM#|archive|a"
getnotefilepath $*
mdless "$notefilepath"
;;
"__archive")
getnotenamefromtext "$*"
if [ $notename ]
then
cat "$TODO_NOTES_DIR/${notename}" >> "$TODO_NOTE_ARCHIVE"
echo >> "$TODO_NOTE_ARCHIVE" ## Add blank line
rm -f "$TODO_NOTES_DIR/${notename}"
fi
;;
"__rmfromtext")
getnotenamefromtext "$*"
if [ -n "$notename" ]; then rm -f "$TODO_NOTES_DIR/$notename"; fi
;;
*)
usage
;;
esac
#!/bin/bash
# From https://github.com/mgarrido/todo.txt-cli/blob/note/todo.actions.d/rm
[ "$1" = "usage" ] && exit 0
shift
"$TODO_SH" -n del "$@"
#!/bin/bash
# From https://github.com/Thann/todo-cli-plugins/blob/master/top
# Lists as many items as can fit in the terminal, no wrapping or scrolling.
if [ -n "$1" ]; then
if [ "$1" == "usage" ]; then
echo " $(basename $0) [TERM...]"
echo " Lists as many items as can fit in the terminal, no wrapping or scrolling."
echo ""
exit
fi
shift
fi
TERMINAL_FIT_SUB="sed -e '$(expr $(tput lines) - 3),\$d' -e 's/\(^\x1B\[[0-9;]*[mK]\)\?\([^\x1B]\{$(expr $(tput cols) - 1)\}\).*$/\1\2…/g'"
export TODOTXT_FINAL_FILTER=$TODOTXT_FINAL_FILTER" | "$TERMINAL_FIT_SUB
_list "$TODO_FILE" "$@"
#!/bin/bash
# Author : Mark Wu, http://blog.markplace.net
# License: GPL3, http://www.gnu.org/copyleft/gpl.html
# Credit : Inspired by and based on Paul Mansfield's projectview, http://github.com/the1ts/todo.txt-plugins/blob/master/README.projects
# Stop Verbose lines, thanks to Mark Harrison
TODOTXT_VERBOSE=0
# Get action
action=$1
shift
# Get option
option=$1;
shift
# Get rest of them
term="$@"
function usage() {
echo " $(basename $0) [OPTION] [TERM]"
echo " Show todo items containing TERM, grouped by OPTION, and displayed in"
echo " priority order. If no TERM provided, displays entire todo.txt."
echo " OPTION:"
echo " project : Show todo items group by project"
echo " context : Show todo items group by context"
echo " date : Show todo items group by date"
echo " nodate : Show todo items group by date without date"
echo " past : Show todo items group by date from today to past"
echo " future : Show todo items group by date from today to future"
echo " today : Show todo items group by date only today"
echo " yesterday : Show todo items group by date from today to yesterday"
echo " tomorrow : Show todo items group by date from today to tomorrow"
echo " ?length : Show todo items group by date from today to ?length"
echo " ? could be signed(+-) or unsigned numbers."
echo " Length could be (days|weeks|months|years)"
echo " Example:"
echo " \$ todo.sh $(basename $0) project # Show todo items grouped by project"
echo " \$ todo.sh $(basename $0) project @context # Show todo items grouped by project and filtered by @context"
echo " \$ todo.sh $(basename $0) context # Show todo items grouped by context"
echo " \$ todo.sh $(basename $0) date +project # Show todo items grouped by date and filtered by +project"
echo " \$ todo.sh $(basename $0) -3days # Show todo items grouped by date from today to 3days before today"
echo " \$ todo.sh $(basename $0) 4weeks # Show todo items grouped by date from today to 4weeks after today"
echo ""
exit
}
function project_view() {
# Show projects in alphabetical order and todo items in priority order
echo "===== Projects ====="
echo ""
# Find all projects and sort
PROJECTS=$(grep -o '[^ ]*+[^ ]\+' "$TODO_FILE" | grep '^+' | sort -u | sed 's/^+//g')
# For each project show header and the list of todo items
for project in $PROJECTS; do
# Use core _list function, does numbering and colouring for us
PROJECT_LIST=$(_list "$TODO_FILE" "+$project\b" "$term" | sed 's/\(^+\|\ *+\)[a-zA-Z0-9\{._\-\}]*\ */ /g')
if [[ -n "${PROJECT_LIST}" ]]; then
echo "--- $project ---"
echo "${PROJECT_LIST}"
echo ""
fi
done
# Show todo items not associated to a project
PROJECT_LIST=$(_list "$TODO_FILE" "$term" | grep -v "+\w")
if [[ -n "${PROJECT_LIST}" ]]; then
echo "--- Items without project ---"
echo "${PROJECT_LIST}"
fi
}
function context_view() {
# Show contexts in alphabetical order and todo items in priority order
echo "===== Contexts ====="
echo ""
# Find all contexts and sort
CONTEXTS=$(grep -o '[^ ]*@[^ ]\+' "$TODO_FILE" | grep '^@' | sort -u | sed 's/@//g')
# For each context show header and the list of todo items
for context in $CONTEXTS ; do
# Use core _list function, does numbering and colouring for us
CONTEXT_LIST=$(_list "$TODO_FILE" "@$context\b" "$term" | sed 's/(^@|\ *@)[^[:cntrl:] ]\ */ /g')
if [[ -n "${CONTEXT_LIST}" ]]; then
echo "--- $context ---"
echo "${CONTEXT_LIST}"
echo ""
fi
done
# Show todo items not associated to a context
CONTEXT_LIST=$(_list "$TODO_FILE" "$term" | grep -v "@[^ ]*\ *")
if [[ -n "${CONTEXT_LIST}" ]]; then
echo "--- Items without context ---"
echo "${CONTEXT_LIST}"
fi
}
function date_view() {
# Show dates in alphabetical order and todo items in priority order
echo "===== Dates ====="
echo ""
# Find all dates and sort
DATES=$(grep -o '[^ ]*t:[^ ]\+' "$TODO_FILE" | grep '^t:' | sort -u | sed 's/^t://g')
# Get option
option=$1
# Get today
today=$(date -d $(date +%Y-%m-%d) +%s)
# For each date show header and the list of todo items
for date in $DATES ; do
# Check it is a valid date or not
date_check $option $today $date
show="$?"
if [[ $show -eq 0 ]]; then
# If it is not a valid date, just do nothing
continue
fi
# Use core _list function, does numbering and colouring for us
DATE_LIST=$(_list "$TODO_FILE" "t:$date" "$term" | sed 's/\(^t:\|\ *t:\)[0-9-]*\ */ /g')
if [ -n "${DATE_LIST}" ]; then
echo "--- $date ---"
echo "${DATE_LIST}"
echo ""
fi
done
# Show todo items not associated to a date
re="^(date|nodate)$"
if [[ "$option" =~ $re ]]; then
DATE_LIST=$(_list "$TODO_FILE" "$term" | grep -v "t:[0-9-]*")
if [ -n "${DATE_LIST}" ]; then
echo "--- Items without date ---"
echo "${DATE_LIST}"
fi
fi
}
function date_check() {
# Assign variables
threshold=$1
today=$2
_date=$(date -d "$3" +%s)
# Check if the date is valid or not
# return:
# 1: If the date is valid
# 0: If the date is invalid
case $threshold in
'future')
if [[ "$_date" -ge "$today" ]]; then
return 1
fi
;;
'past')
if [[ "$_date" -le "$today" ]]; then
return 1
fi
;;
'nodate')
return 0
;;
'date')
return 1
;;
*)
if [[ "$threshold" -eq "$today" ]]; then
if [[ "$_date" -eq "$today" ]]; then
return 1
fi
elif [[ "$threshold" -gt "$today" ]]; then
if [[ ( "$_date" -ge "$today" ) && ( "$_date" -le "$threshold" ) ]]; then
return 1
fi
elif [[ "$threshold" -lt "$today" ]]; then
if [[ ( "$_date" -le "$today" ) && ( "$_date" -ge "$threshold" ) ]]; then
return 1
fi
fi
;;
esac
return 0
}
# Validate the input options
re="^(help|project|context|date|nodate|future|past|today|tomorrow|yesterday|([+-][0-9]+|[0-9]+)(days|weeks|months|years))$"
if [[ "$option" =~ $re ]]; then
case $option in
'help')
usage
;;
'project')
project_view
;;
'context')
context_view
;;
*)
re="^(date|nodate|future|past)$"
if [[ ! ( "$option" =~ $re ) ]]; then
option=$(date -d $(date -d $option +%Y-%m-%d) +%s)
fi
date_view $option
;;
esac
else
echo "Error: Unrecognized option \"$option\"."
echo "Try \"todo.sh view help\" to get more information."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment