--- /dev/null
+#!/bin/sh
+set -eu
+
+CODEDIR=~/code/taskwarrior
+
+[ -d $CODEDIR/tasklib ] && export PYTHONPATH=$CODEDIR/tasklib
+
+for dir in $CODEDIR/taskwarrior/src /usr/bin; do
+ [ ! -x $dir/task ] || exec $dir/task "$@"
+done
+
+echo >&2 E: task binary not found.
--- /dev/null
+#!/bin/sh
+set -eu
+
+if [ $# != 2 ]; then
+ echo >&2 E: Need exactly two arguments.
+ return 1
+fi
+
+TSK="$1"
+LINK="$2"
+
+case "$LINK" in
+ (*@*|"<*>")
+ LINK="${LINK%>}"; LINK="%{LINK#<}"
+ echo >&2 I: "Adding MsgID <$LINK> to task $TSK"
+ task "$TSK" mod data:msgid:"$LINK"
+ ;;
+
+ (*://*)
+ echo >&2 I: "Adding URL $LINK to task $TSK"
+ task "$TSK" mod data:url:"$LINK"
+ ;;
+
+ (*)
+ if [ -f "$LINK" ]; then
+
+ LINK="$(readlink -e "$LINK")"
+
+ case "$LINK" in
+ ($HOME/*) LINK="~${LINK#$HOME}";;
+ esac
+ echo >&2 I: "Adding file $LINK to task $TSK"
+ task "$TSK" mod data:file:"$LINK"
+
+ else
+ echo >&2 E: "Don't know how to handle link data $LINK"
+ return 1
+
+ fi
+ ;;
+esac
--- /dev/null
+#!/bin/sh
+set -eu
+
+if [ $# != 1 ]; then
+ echo >&2 E: Need exactly one argument.
+ return 1
+fi
+
+TSK="$1"
+
+DATA="$(task _get "$TSK".data)"
+DATATYPE="${DATA%%:*}"
+DATAPAYL="${DATA#*:}"
+
+case "$DATATYPE" in
+ ('')
+ echo >&2 I: No link data available for this task.
+ task "$TSK"
+ ;;
+
+ (msgid)
+ mutt -f =store -e "push '<search>~i $DATAPAYL'<enter>"
+ ;;
+
+ (url)
+ sensible-browser "$DATAPAYL"
+ ;;
+
+ (file)
+ if eval test -f "$DATAPAYL"; then
+ case "$(file --mime-type "$DATAPAYL")" in
+ (*": text/"*) eval sensible-editor "$DATAPAYL";;
+ (*) eval run-mailcap --action=edit "$DATAPAYL";;
+ esac
+ fi
+ ;;
+
+ (*)
+ eval run-mailcap --action=edit "$DATAPAYL"
+ ;;
+
+esac
--- /dev/null
+- /*.pem
+- /taskd-credentials.rc
--- /dev/null
+../taskpirate/on-add-pirate
\ No newline at end of file
--- /dev/null
+../taskpirate/on-modify-pirate
\ No newline at end of file
--- /dev/null
+include /usr/share/taskwarrior/light-256.theme
+data.location=~/.var/taskwarrior
+
+nag=
+recurrence.indicator=@
+recurrence=off
+hyphenate=off
+
+color.tag.TEMPLATE=gray16 on white
+color.alternate=
+
+include /usr/share/taskwarrior/holidays.de-DE.rc
+include /usr/share/taskwarrior/holidays.en-NZ.rc
+
+include ~/.config/taskwarrior/taskd-credentials.rc
+
+uda.data.type=string
+uda.data.label=Ext.data
+uda.data.indicator=→
+
+report.next.columns=id,data.indicator,start.age,entry.age,depends,priority,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description,urgency
+report.next.labels=ID,X,Active,Age,Deps,P,Project,Tag,Recur,S,Due,Until,Description,Urg
+
+alias.call=execute task_call
+alias.attach=execute task_attach
--- /dev/null
+Copyright 2015-2017 Tomas Babej
+https://github.com/tbabej/taskpirate
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+Taskpirate
+----------
+
+Taskpirate is a pluggable system for TaskWarrior python hooks.
+
+Why?
+----
+
+Simpler hooks:
+
+ def hook_example(task):
+ task['description'] += "changed by a hook"
+
+The above is fully working example, no more boilerplate needed.
+
+Much faster execution time in case of multiple hooks (read the more details section).
+
+Install
+-------
+
+You'll need tasklib as a dependency:
+
+ pip install --user git+git://github.com/tbabej/tasklib@develop
+
+Then you need to drop ```on-add-pirate``` and ```on-modify-pirate``` into ~/.task/hooks/.
+
+After that, you can just clone any taskpirate-enabled hook as a subfolder into ~/.task/hooks/:
+
+ git clone https://github.com/tbabej/task.default-date-time ~/.task/hooks/default-date-time/
+
+How to write a taskpirate hook
+------------------------------
+
+In your hook's repository, any file matching ```pirate_add*.py``` will be searched for hooks in on-add event. In the same sense, any file matching ```pirate_mod*.py``` will be searched for hooks in on-modify event.
+
+Now, the pirate_add_example.py might look as follows:
+
+ def hook_example(task):
+ task['description'] += "changed by a hook"
+
+Any function in pirate_add_example that is called ```hook_*``` will be considered as a hook in on-add event. It will be passed the ```Task``` object corresponding to the current state of the task being added (as modified by the previous hooks).
+
+More details
+------------
+
+TaskWarrior hooks are intended to be simple, but they involve writing some boilerplate code (parsing/formatting json). To allow users to write dead simple code, they can leverage tasklib.
+
+Using tasklib simplifies things a lot, however, it's not a super-lightweight - usage of tasklib can slow down the hook by as much as 30-50ms (usual python hook can probably run in under 40ms), since it imports multiple libraries.
+
+This becomes a problem when user has multiple tasklib-based hooks, since the import time adds up.
+
+Also, note that taskpirate with arbitrary number of hooks will be most likely faster than 2-3 regular python hooks.
+
+Example hooks
+-------------
+
+You can look into my ```task.default-date-time``` or ```task.shift-recurrence``` hooks.
--- /dev/null
+#!/usr/bin/env python
+
+import glob
+import imp
+import os
+
+from tasklib import TaskWarrior, Task
+
+
+def find_hooks(file_prefix):
+ # Find all files in subdirectories whose names start with <file_prefix>
+ file_pattern = os.path.dirname(__file__) + '/*/' + file_prefix + "*.py"
+ module_paths = [f for f in glob.glob(file_pattern) if os.path.isfile(f)]
+ module_paths.sort()
+
+ # Gather all hooks in these files
+ hooks = []
+
+ for module_path in module_paths:
+ # Load the module
+ module_dir = os.path.dirname(module_path)
+ module_filename = os.path.basename(module_path)
+ module_name = 'pirate_{0}_{1}'.format(module_dir, module_filename)
+ module_name = module_name.replace('.', '_')
+ module = imp.load_source(module_name, module_path)
+
+ # Find all hook methods available
+ module_hooks = [
+ getattr(module, hook_name)
+ for hook_name in dir(module)
+ if hook_name.startswith('hook_')
+ ]
+
+ hooks += module_hooks
+
+ return hooks
+
+task = Task.from_input()
+
+for hook in find_hooks('pirate_add'):
+ hook(task)
+
+print(task.export_data())
--- /dev/null
+#!/usr/bin/env python
+
+import glob
+import imp
+import os
+
+from tasklib import TaskWarrior, Task
+
+
+def find_hooks(file_prefix):
+ # Find all files in subdirectories whose names start with <file_prefix>
+ file_pattern = os.path.dirname(__file__) + '/*/' + file_prefix + "*.py"
+ module_paths = [f for f in glob.glob(file_pattern) if os.path.isfile(f)]
+ module_paths.sort()
+
+ # Gather all hooks in these files
+ hooks = []
+
+ for module_path in module_paths:
+ # Load the module
+ module_dir = os.path.dirname(module_path)
+ module_filename = os.path.basename(module_path)
+ module_name = 'pirate_{0}_{1}'.format(module_dir, module_filename)
+ module_name = module_name.replace('.', '_')
+ module = imp.load_source(module_name, module_path)
+
+ # Find all hook methods available
+ module_hooks = [
+ getattr(module, hook_name)
+ for hook_name in dir(module)
+ if hook_name.startswith('hook_')
+ ]
+
+ hooks += module_hooks
+
+ return hooks
+
+task = Task.from_input()
+
+for hook in find_hooks('pirate_mod'):
+ hook(task)
+
+print(task.export_data())
--- /dev/null
+*/30 * * * * ( task sync && task next && task sync ) >/dev/null 2>&1
--- /dev/null
+*
+!/.bin/task
+!/.bin/task_attach
+!/.bin/task_call
+!/.config/taskwarrior/.gitignore
+!/.config/taskwarrior/hooks/on-add-pirate
+!/.config/taskwarrior/hooks/on-modify-pirate
+!/.config/taskwarrior/rc
+!/.config/taskwarrior/taskpirate/LICENCE
+!/.config/taskwarrior/taskpirate/on-add-pirate
+!/.config/taskwarrior/taskpirate/on-modify-pirate
+!/.config/taskwarrior/taskpirate/README.md
+!/.crontab.d/taskwarrior
+!/.gitignore.d/taskwarrior
+!/.taskrc
+!/.var/taskwarrior/.gitignore
+!/.var/taskwarrior/hooks
+!/.zsh/zshrc/parts.d/50-taskwarrior
--- /dev/null
+.config/taskwarrior/rc
\ No newline at end of file
--- /dev/null
+../../.config/taskwarrior/hooks
\ No newline at end of file
--- /dev/null
+#
+# taskwarrior shell integration
+#
+# Copyright © 2018 martin f. krafft <madduck@madduck.net>
+# Released under the terms of the Artistic Licence 2.0
+#
+# Source repository: http://git.madduck.net/v/etc/zsh.git
+#
+
+if whence task >/dev/null; then
+
+ function t() { task "$@"; }
+
+ alias t\?='alias -rm t[-+a-z]'
+ alias ta='t add'
+ alias tc='t call'
+ alias th='t attach'
+ alias tn='t next'
+ alias tl='t all'
+ alias ty='t sync'
+ alias td='t done'
+ alias te='t edit'
+ alias tu='t undo'
+ alias tm='t modify'
+ alias ts='t start'
+ alias t+='t annotate'
+
+ run_at_most_every 5m \
+ t 2>/dev/null || :
+fi
+
+# vim:ft=zsh