]> git.madduck.net Git - etc/taskwarrior.git/commitdiff

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Add 'code/taskwarrior/tasklib/' from commit '9a7dac4599f198c52f268ae8bcc0267743ef934f'
authormartin f. krafft <madduck@madduck.net>
Mon, 18 Nov 2019 03:57:53 +0000 (16:57 +1300)
committermartin f. krafft <madduck@madduck.net>
Mon, 18 Nov 2019 03:57:53 +0000 (16:57 +1300)
git-subtree-dir: code/taskwarrior/tasklib
git-subtree-mainline: 31d9529fe14bb21ff87c6e0030890fb32df15834
git-subtree-split: 9a7dac4599f198c52f268ae8bcc0267743ef934f

39 files changed:
.bin/task [new file with mode: 0755]
.bin/task_attach [new file with mode: 0755]
.bin/task_call [new file with mode: 0755]
.config/taskwarrior/.gitignore [new file with mode: 0644]
.config/taskwarrior/hooks/on-add-pirate [new symlink]
.config/taskwarrior/hooks/on-modify-pirate [new symlink]
.config/taskwarrior/hooks/task.shift-recurrence/.gitignore [new file with mode: 0644]
.config/taskwarrior/hooks/task.shift-recurrence/LICENCE [new file with mode: 0644]
.config/taskwarrior/hooks/task.shift-recurrence/README.md [new file with mode: 0644]
.config/taskwarrior/hooks/task.shift-recurrence/pirate_add_shift_recurrence.py [new file with mode: 0644]
.config/taskwarrior/rc [new file with mode: 0644]
.config/taskwarrior/taskpirate/LICENCE [new file with mode: 0644]
.config/taskwarrior/taskpirate/README.md [new file with mode: 0644]
.config/taskwarrior/taskpirate/on-add-pirate [new file with mode: 0755]
.config/taskwarrior/taskpirate/on-modify-pirate [new file with mode: 0755]
.crontab.d/taskwarrior [new file with mode: 0644]
.gitignore.d/taskwarrior [new file with mode: 0644]
.taskrc [new symlink]
.var/taskwarrior/.gitignore [new file with mode: 0644]
.var/taskwarrior/hooks [new symlink]
.zsh/zshrc/parts.d/50-taskwarrior [new file with mode: 0644]
code/taskwarrior/tasklib/.coveragerc [moved from .coveragerc with 100% similarity]
code/taskwarrior/tasklib/.gitignore [moved from .gitignore with 100% similarity]
code/taskwarrior/tasklib/.travis.yml [moved from .travis.yml with 100% similarity]
code/taskwarrior/tasklib/AUTHORS [moved from AUTHORS with 100% similarity]
code/taskwarrior/tasklib/LICENSE [moved from LICENSE with 100% similarity]
code/taskwarrior/tasklib/MANIFEST.in [moved from MANIFEST.in with 100% similarity]
code/taskwarrior/tasklib/README.rst [moved from README.rst with 100% similarity]
code/taskwarrior/tasklib/docs/Makefile [moved from docs/Makefile with 100% similarity]
code/taskwarrior/tasklib/docs/conf.py [moved from docs/conf.py with 100% similarity]
code/taskwarrior/tasklib/docs/index.rst [moved from docs/index.rst with 100% similarity]
code/taskwarrior/tasklib/setup.py [moved from setup.py with 100% similarity]
code/taskwarrior/tasklib/tasklib/__init__.py [moved from tasklib/__init__.py with 100% similarity]
code/taskwarrior/tasklib/tasklib/backends.py [moved from tasklib/backends.py with 100% similarity]
code/taskwarrior/tasklib/tasklib/filters.py [moved from tasklib/filters.py with 100% similarity]
code/taskwarrior/tasklib/tasklib/lazy.py [moved from tasklib/lazy.py with 100% similarity]
code/taskwarrior/tasklib/tasklib/serializing.py [moved from tasklib/serializing.py with 100% similarity]
code/taskwarrior/tasklib/tasklib/task.py [moved from tasklib/task.py with 100% similarity]
code/taskwarrior/tasklib/tasklib/tests.py [moved from tasklib/tests.py with 100% similarity]

diff --git a/.bin/task b/.bin/task
new file mode 100755 (executable)
index 0000000..8ce793d
--- /dev/null
+++ b/.bin/task
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -eu
+
+CODEDIR=~/code/taskwarrior
+
+[ -d $CODEDIR/tasklib ] && export PYTHONPATH=$CODEDIR/tasklib
+
+for dir in $CODEDIR/taskwarrior/src /usr/bin; do
+  if [ -x $dir/task ]; then
+    export PATH="$dir:$PATH"
+    exec task "$@"
+  fi
+
+done
+
+echo >&2 E: task binary not found.
diff --git a/.bin/task_attach b/.bin/task_attach
new file mode 100755 (executable)
index 0000000..7df89a6
--- /dev/null
@@ -0,0 +1,41 @@
+#!/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
diff --git a/.bin/task_call b/.bin/task_call
new file mode 100755 (executable)
index 0000000..71c4f76
--- /dev/null
@@ -0,0 +1,48 @@
+#!/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.
+    exec task "$TSK"
+    ;;
+
+  (msgid)
+    if command -v neomutt >/dev/null && command -v notmuch >/dev/null; then
+      exec neomutt -f "notmuch://$HOME/mail/?query=thread:{mid:$DATAPAYL}"
+
+    else
+      exec mutt -f =store -e "push '<limit>~(=i\"$DATAPAYL\")<enter><search>=i\"$DATAPAYL\"<enter>'"
+
+    fi
+    ;;
+
+  (url)
+    exec sensible-browser "$DATAPAYL"
+    ;;
+
+  (file)
+    if eval test -f "$DATAPAYL"; then
+      case "$(file --mime-type "$DATAPAYL")" in
+        (*": text/"*) eval exec sensible-editor "$DATAPAYL";;
+        (*) eval exec run-mailcap --action=view "$DATAPAYL";;
+      esac
+    fi
+    ;;
+
+  (*)
+    eval exec run-mailcap --action=view "$DATAPAYL"
+    ;;
+
+esac
diff --git a/.config/taskwarrior/.gitignore b/.config/taskwarrior/.gitignore
new file mode 100644 (file)
index 0000000..645470a
--- /dev/null
@@ -0,0 +1,2 @@
+- /*.pem
+- /taskd-credentials.rc
diff --git a/.config/taskwarrior/hooks/on-add-pirate b/.config/taskwarrior/hooks/on-add-pirate
new file mode 120000 (symlink)
index 0000000..88ed7b8
--- /dev/null
@@ -0,0 +1 @@
+../taskpirate/on-add-pirate
\ No newline at end of file
diff --git a/.config/taskwarrior/hooks/on-modify-pirate b/.config/taskwarrior/hooks/on-modify-pirate
new file mode 120000 (symlink)
index 0000000..006bb1e
--- /dev/null
@@ -0,0 +1 @@
+../taskpirate/on-modify-pirate
\ No newline at end of file
diff --git a/.config/taskwarrior/hooks/task.shift-recurrence/.gitignore b/.config/taskwarrior/hooks/task.shift-recurrence/.gitignore
new file mode 100644 (file)
index 0000000..0d20b64
--- /dev/null
@@ -0,0 +1 @@
+*.pyc
diff --git a/.config/taskwarrior/hooks/task.shift-recurrence/LICENCE b/.config/taskwarrior/hooks/task.shift-recurrence/LICENCE
new file mode 100644 (file)
index 0000000..f90622c
--- /dev/null
@@ -0,0 +1,21 @@
+Copyright 2015 Tomas Babej
+http://github.com/tbabej/taskwarrior-shift-all-recurrence-hook
+
+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.
diff --git a/.config/taskwarrior/hooks/task.shift-recurrence/README.md b/.config/taskwarrior/hooks/task.shift-recurrence/README.md
new file mode 100644 (file)
index 0000000..58792c0
--- /dev/null
@@ -0,0 +1,50 @@
+Taskwarrior Shift All Recurrence Attributes Hook
+------------------------------------------------
+
+This is a hook for TaskWarrior (http://www.taskwarrior.org),
+which allow your recurrent tasks to inherit ``wait``, ``scheduled``
+and ``until`` attributes from the parent.
+
+Install
+-------
+
+Note: This hook has been rewritten to leverage taskpirate, for greater hook efficiency.
+Please see https://github.com/tbabej/taskpirate for instructions. Don't worry, it's straightforward.
+
+```
+git clone https://github.com/tbabej/taskwarrior-shift-all-recurrence-hook.git
+cp taskwarrior-shift-all-recurrence-hook/on-* ~/.task/hooks/
+```
+
+This hook leverages tasklib, so you need to install that too:
+
+```
+pip install tasklib
+```
+
+Use case
+--------
+
+Consider you have a periodic task, which is valid only for the certain day,
+e.g. on every Sunday you go running.
+
+```
+$ task add due:sunday recur:weekly
+```
+
+However, TaskWarrior will display the task right away, and you want to
+showing up only during the weekend, so that it does not distract your task
+list during the work week.
+
+If you try to add the recurrence again, this time with ``wait`` attribute,
+to hide the task until it is not relevant for you:
+
+```
+$ task add due:sunday recur:weekly wait:saturday
+```
+
+You will find out that TaskWarrior does not let tasks generated by this
+recurrence inherit the ``wait`` attribute, in the same manner as it does
+with the ``due`` attribute.
+
+This hook solves that.
diff --git a/.config/taskwarrior/hooks/task.shift-recurrence/pirate_add_shift_recurrence.py b/.config/taskwarrior/hooks/task.shift-recurrence/pirate_add_shift_recurrence.py
new file mode 100644 (file)
index 0000000..0266fc5
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+
+import sys
+import os
+from tasklib import TaskWarrior
+
+time_attributes = ('wait', 'scheduled')
+
+def is_new_local_recurrence_child_task(task):
+    # Do not affect tasks not spun by recurrence
+    if not task['parent']:
+        return False
+
+    # Newly created recurrence tasks actually have
+    # modified field copied from the parent, thus
+    # older than entry field (until their ID is generated)
+    if (task['modified'] - task['entry']).total_seconds() < 0:
+        return True
+
+tw = TaskWarrior(data_location=os.path.dirname(os.path.dirname(sys.argv[0])))
+tw.overrides.update(dict(recurrence="no", hooks="no"))
+
+def hook_shift_recurrence(task):
+    if is_new_local_recurrence_child_task(task):
+        parent = tw.tasks.get(uuid=task['parent']['uuid'])
+        parent_due_shift = task['due'] - parent['due']
+        for attr in time_attributes:
+            if parent[attr]:
+                task[attr] = parent[attr] + parent_due_shift
diff --git a/.config/taskwarrior/rc b/.config/taskwarrior/rc
new file mode 100644 (file)
index 0000000..f207d9a
--- /dev/null
@@ -0,0 +1,37 @@
+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=
+color.tag.next=red
+
+include /usr/share/taskwarrior/holidays.de-DE.rc
+include /usr/share/taskwarrior/holidays.en-NZ.rc
+
+taskd.server=tasks.madduck.net:53589
+taskd.ca=/etc/ssl/certs/ca-certificates.crt
+taskd.certificate=~/.config/taskwarrior/client-cert.pem
+taskd.key=~/.config/taskwarrior/client-key.pem
+include ~/.config/taskwarrior/taskd-credentials.rc
+
+urgency.project.coefficient=0
+urgency.tags.coefficient=0
+urgency.annotations.coefficient=0
+
+due=1
+
+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
+report.next.sort=priority+,urgency-
+
+alias.call=execute task_call
+alias.attach=execute task_attach
diff --git a/.config/taskwarrior/taskpirate/LICENCE b/.config/taskwarrior/taskpirate/LICENCE
new file mode 100644 (file)
index 0000000..e3e582e
--- /dev/null
@@ -0,0 +1,21 @@
+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.
diff --git a/.config/taskwarrior/taskpirate/README.md b/.config/taskwarrior/taskpirate/README.md
new file mode 100644 (file)
index 0000000..4d49a00
--- /dev/null
@@ -0,0 +1,57 @@
+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.
diff --git a/.config/taskwarrior/taskpirate/on-add-pirate b/.config/taskwarrior/taskpirate/on-add-pirate
new file mode 100755 (executable)
index 0000000..9fae1c4
--- /dev/null
@@ -0,0 +1,43 @@
+#!/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())
diff --git a/.config/taskwarrior/taskpirate/on-modify-pirate b/.config/taskwarrior/taskpirate/on-modify-pirate
new file mode 100755 (executable)
index 0000000..b7b4986
--- /dev/null
@@ -0,0 +1,43 @@
+#!/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())
diff --git a/.crontab.d/taskwarrior b/.crontab.d/taskwarrior
new file mode 100644 (file)
index 0000000..d26dae7
--- /dev/null
@@ -0,0 +1 @@
+*/30 * * * * ( task sync && task next && task sync ) >/dev/null 2>&1
diff --git a/.gitignore.d/taskwarrior b/.gitignore.d/taskwarrior
new file mode 100644 (file)
index 0000000..ff65ee9
--- /dev/null
@@ -0,0 +1,22 @@
+*
+!/.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/hooks/task.shift-recurrence/.gitignore
+!/.config/taskwarrior/hooks/task.shift-recurrence/LICENCE
+!/.config/taskwarrior/hooks/task.shift-recurrence/pirate_add_shift_recurrence.py
+!/.config/taskwarrior/hooks/task.shift-recurrence/README.md
+!/.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
diff --git a/.taskrc b/.taskrc
new file mode 120000 (symlink)
index 0000000..3113449
--- /dev/null
+++ b/.taskrc
@@ -0,0 +1 @@
+.config/taskwarrior/rc
\ No newline at end of file
diff --git a/.var/taskwarrior/.gitignore b/.var/taskwarrior/.gitignore
new file mode 100644 (file)
index 0000000..216f0fe
--- /dev/null
@@ -0,0 +1 @@
+- /*.data
diff --git a/.var/taskwarrior/hooks b/.var/taskwarrior/hooks
new file mode 120000 (symlink)
index 0000000..729b1ca
--- /dev/null
@@ -0,0 +1 @@
+../../.config/taskwarrior/hooks
\ No newline at end of file
diff --git a/.zsh/zshrc/parts.d/50-taskwarrior b/.zsh/zshrc/parts.d/50-taskwarrior
new file mode 100644 (file)
index 0000000..2ca20b9
--- /dev/null
@@ -0,0 +1,60 @@
+#
+# 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 task_() {
+    local filter cmd args nofilter=0
+    cmd="$1"; shift
+
+    case "$cmd" in
+      (add|attach|call) nofilter=1;;
+    esac
+
+    for i in "$@"; do
+      case "$nofilter@$i" in
+        (0@<->) :;&
+        (0@/*/) filter="${filter:+$filter }$i";;
+        (*) args="${args:+$args }$i";;
+      esac
+    done
+    eval task $filter $cmd $args
+  }
+
+  function task_postpone() {
+    local args
+    for i in scheduled due until wait; do
+      if [[ -n "$(eval task _get "$1"."$i")" ]]; then
+        args="${args:+$args }${i}:${i}+$2"
+      fi
+    done
+    eval task "$1" modify $args
+  }
+
+  alias t\?='alias -rm t t[-+a-z] | sed -r "s,_ ?, ,"'
+  alias ta='task_ add'
+  alias tc='task_ call'
+  alias th='task_ attach'
+  alias tl='task_ all'
+  alias ty='task_ next rc.recurrence=on >/dev/null && task_ sync'
+  alias td='task_ done'
+  alias te='task_ edit'
+  alias tu='task_ undo'
+  alias tm='task_ modify'
+  alias ts='task_ start'
+  alias tw='task_ waiting'
+  alias tp='task_postpone'
+  alias t+='task_ annotate'
+  alias t='task_ ""'
+
+  run_at_most_every 5m \
+    t 2>/dev/null || :
+fi
+
+# vim:ft=zsh
similarity index 100%
rename from AUTHORS
rename to code/taskwarrior/tasklib/AUTHORS
similarity index 100%
rename from LICENSE
rename to code/taskwarrior/tasklib/LICENSE
similarity index 100%
rename from setup.py
rename to code/taskwarrior/tasklib/setup.py