taskwarrior.el/taskwarrior.el
Patrick Winter df20f9d1c1 Fix format of taskwarrior entries
Handle that certain entries don't have a project.
2018-10-23 21:32:01 +02:00

103 lines
3.5 KiB
EmacsLisp

;; Frontend for taskwarrior
;;
;; TODO: Implement modeline indicator for deadline and entries
;; TODO: Update buffer if command modifies the state
;; TODO: Extract "1-1000" id filter into variable
(require 'json)
(defgroup taskwarrior nil "An emacs frontend to taskwarrior.")
(defconst taskwarrior-mutating-commands '("add" "modify"))
(defvar taskwarrior-description 'taskwarrior-description
"Taskwarrior mode face used for tasks with a priority of C.")
(setq taskwarrior-highlight-regexps
`(("^[0-9]*" . font-lock-variable-name-face)
("([0-9.]*?)" . font-lock-builtin-face)
("\\[.*\\]" . font-lock-preprocessor-face)
("[:space:].*:" . font-lock-function-name-face)))
(defvar taskwarrior-mode-map nil "Keymap for `taskwarrior-mode'")
(progn
(setq taskwarrior-mode-map (make-sparse-keymap))
(define-key taskwarrior-mode-map (kbd "p") 'previous-line)
(define-key taskwarrior-mode-map (kbd "k") 'previous-line)
(define-key taskwarrior-mode-map (kbd "n") 'next-line)
(define-key taskwarrior-mode-map (kbd "j") 'next-line)
(define-key taskwarrior-mode-map (kbd "q") 'quit-window)
(define-key taskwarrior-mode-map (kbd "a") 'taskwarrior-add)
(define-key taskwarrior-mode-map (kbd "p") 'taskwarrior-change-project))
(defun taskwarrior-id-at-point ()
(let ((line (thing-at-point 'line t)))
(string-match "^[0-9]*" line)
(match-string 0 line)))
(defun taskwarrior--shell-command (command &optional filter modifications miscellaneous)
(shell-command-to-string
(format "task %s %s %s %s"
(or filter "")
command
(or modifications "")
(or miscellaneous ""))))
(defun taskwarrior-export (filter)
"Export taskwarrior entries as JSON"
(json-read-from-string
(taskwarrior--shell-command "export" filter)))
(defun taskwarrior-change-project (project)
(interactive "sProject: ")
(let ((filter (taskwarrior-id-at-point))
(command "modify")
(modifications (concat "project:" project)))
(taskwarrior--shell-command command filter modifications)))
(defun taskwarrior-add (description)
(interactive "sDescription: ")
(taskwarrior--shell-command "add" "" description))
;; Setup a major mode for taskwarrior
;;;###autoload
(define-derived-mode taskwarrior-mode text-mode "taskwarrior"
"Major mode for interacting with taskwarrior. \\{taskwarrior-mode-map}"
(setq font-lock-defaults '(taskwarrior-highlight-regexps))
(setq goal-column 0)
(auto-revert-mode)
(setq buffer-read-only t))
;;; Externally visible functions
;;;###autoload
(defun taskwarrior ()
"Open the taskwarrior buffer. If one already exists, bring it to
the front and focus it. Otherwise, create one and load the data."
(interactive)
(taskwarrior-update-buffer))
(defun taskwarrior-update-buffer ()
(let* ((buf (get-buffer-create "taskwarrior")))
(progn
(switch-to-buffer buf)
(setq font-lock-defaults '(taskwarrior-highlight-regexps))
(goto-char (point-min))
(toggle-read-only)
(erase-buffer)
(taskwarrior-write-entries)
(taskwarrior-mode)
(hl-line-mode)
(goto-char (point-min))
(while (not (equal (overlays-at (point)) nil))
(forward-char)))))
(defun taskwarrior-write-entries ()
(let ((entries (append (taskwarrior-export "1-1000") nil)))
(dolist (entry entries)
(let ((id (alist-get 'id entry))
(urgency (alist-get 'urgency entry))
(project (alist-get 'project entry))
(description (alist-get 'description entry)))
(insert (if project
(format "%-2d (%05.2f) [%s] %s?\n" id urgency project description)
(format "%-2d (%05.2f) %s?\n" id urgency description)))))))