;;; org-effectiveness.el --- Measuring the personal effectiveness ;; Copyright (C) 2013 Free Software Foundation, Inc. ;; Author: David Arroyo Menéndez ;; Keywords: effectiveness, plot ;; Homepage: http://orgmode.org ;; ;; This file is not part of GNU Emacs, yet. ;; ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; This file implements functions to measure the effectiveness in org. ;; Org-mode doesn't load this module by default - if this is not what ;; you want, configure the variable `org-modules'. Thanks to #emacs-es ;; irc channel for your support. ;;; Code: (require 'org) (defcustom org-effectiveness-max-todo 50 "This variable is useful to advice to the user about many TODO pending" :type 'integer :group 'org-effectiveness) (defun org-effectiveness-advice() "Advicing about a possible excess of TODOS" (interactive) (goto-char (point-min)) (if (< org-effectiveness-max-todo (count-matches "* TODO")) (message "An excess of TODOS!"))) ;; Check advice starting an org file (add-hook 'org-mode-hook 'org-effectiveness-advice) (defun org-effectiveness-count-keyword(keyword) "Print a message with the number of keyword outline in the current buffer" (interactive "sKeyword: ") (save-excursion (goto-char (point-min)) (message "Number of %s: %d" keyword (count-matches (concat "* " keyword))))) (defun org-effectiveness-count-todo() "Print a message with the number of todo tasks in the current buffer" (interactive) (save-excursion (goto-char (point-min)) (message "Number of TODO: %d" (count-matches "* TODO")))) (defun org-effectiveness-count-done() "Print a message with the number of done tasks in the current buffer" (interactive) (save-excursion (goto-char (point-min)) (message "Number of DONE: %d" (count-matches "* DONE")))) (defun org-effectiveness-count-canceled() "Print a message with the number of canceled tasks in the current buffer" (interactive) (save-excursion (goto-char (point-min)) (message "Number of Canceled: %d" (count-matches "* CANCEL+ED")))) (defun org-effectiveness() "Returns the effectiveness in the current org buffer" (interactive) (save-excursion (goto-char (point-min)) (let ((done (float (count-matches "* DONE.*\n.*"))) (canc (float (count-matches "* CANCEL+ED.*\n.*")))) (if (and (= done canc) (zerop done)) (setq effectiveness 0) (setq effectiveness (* 100 (/ done (+ done canc))))) (message "Effectiveness: %f" effectiveness)))) (defun org-effectiveness-keywords-in-date(keyword date) (interactive "sKeyword: \nsDate: " keyword date) (setq count (count-matches (concat keyword ".*\n.*" date))) (message (concat "%sS: %d" keyword count))) (defun org-effectiveness-dones-in-date(date) (interactive "sGive me a date: " date) (setq count (count-matches (concat "DONE.*\n.*" date))) (message "DONES: %d" count)) (defun org-effectivenes-todos-in-date(date) (interactive "sGive me a date: " date) (setq count (count-matches (concat "TODO.*\n.*" date))) (message "TODOS: %d" count)) (defun org-effectiveness-canceled-in-date(date) (interactive "sGive me a date: " date) (setq count (count-matches (concat "CANCEL+ED.*\n.*" date))) (message "CANCELEDS: %d" count)) (defun org-effectiveness-in-date(date &optional notmessage) (interactive "sGive me a date: " date) (save-excursion (goto-char (point-min)) (let ((done (float (count-matches (concat "* DONE.*\n.*" date)))) (canc (float (count-matches (concat "* CANCEL+ED.*\n.*" date))))) (if (and (= done canc) (zerop done)) (setq effectiveness 0) (setq effectiveness (* 100 (/ done (+ done canc))))) (if (eq notmessage 1) (message "%d" effectiveness) (message "Effectiveness: %d " effectiveness))))) (defun org-effectiveness-month-to-string (m) (if (< m 10) (concat "0" (number-to-string m)) (number-to-string m))) (defun org-effectiveness-plot(startdate enddate) (interactive "sGive me the start date: \nsGive me the end date: " startdate enddate) (setq dates (org-effectiveness-check-dates startdate enddate)) (setq syear (cadr (assoc 'startyear dates))) (setq smonth (cadr (assoc 'startmonth dates))) (setq eyear (cadr (assoc 'endyear dates))) (setq emonth (assoc 'endmonth dates)) ;; Checking the format of the dates (if (not (string-match "[0-9][0-9][0-9][0-9]-[0-9][0-9]" startdate)) (message "The start date must have the next format YYYY-MM")) (if (not (string-match "[0-9][0-9][0-9][0-9]-[0-9][0-9]" enddate)) (message "The end date must have the next format YYYY-MM")) ;; Checking if startdate < enddate (if (string-match "^[0-9][0-9][0-9][0-9]" startdate) (setq startyear (string-to-number (match-string 0 startdate)))) (if (string-match "[0-9][0-9]$" startdate) (setq startmonth (string-to-number (match-string 0 startdate)))) (if (string-match "^[0-9][0-9][0-9][0-9]" enddate) (setq endyear (string-to-number (match-string 0 enddate)))) (if (string-match "[0-9][0-9]$" enddate) (setq endmonth (string-to-number (match-string 0 enddate)))) (if (> startyear endyear) (message "The start date must be before that end date")) (if (and (= startyear endyear) (> startmonth endmonth)) (message "The start date must be before that end date")) ;; Create a file (let ((month startmonth) (year startyear) (str "")) (while (and (>= endyear year) (>= endmonth month)) (setq str (concat str (number-to-string year) "-" (org-effectiveness-month-to-string month) " " (org-effectiveness-in-date (concat (number-to-string year) "-" (org-effectiveness-month-to-string month)) 1) "\n")) (if (= month 12) (progn (setq year (+ 1 year)) (setq month 1)) (setq month (+ 1 month)))) (write-region str nil "/tmp/org-effectiveness")) ;; Create the bar graph (if (file-exists-p "/usr/bin/gnuplot") (call-process "/bin/bash" nil t nil "-c" "/usr/bin/gnuplot -e 'plot \"/tmp/org-effectiveness\" using 2:xticlabels(1) with histograms' -p") (message "gnuplot is not installed"))) (defun org-effectiveness-ascii-bar(n &optional label) "Print a bar with the percentage from 0 to 100 printed in ascii" (interactive "nPercentage: \nsLabel: ") (if (or (< n 0) (> n 100)) (message "The percentage must be between 0 to 100") (let ((x 0) (y 0) (z 0)) (insert (format "\n### %s ###" label)) (insert "\n-") (while (< x n) (insert "-") (setq x (+ x 1))) (insert "+\n") (insert (format "%d" n)) (if (> n 10) (setq y (+ y 1))) (while (< y n) (insert " ") (setq y (+ y 1))) (insert "|\n") (insert "-") (while (< z n) (insert "-") (setq z (+ z 1))) (insert "+")))) (defun org-effectiveness-check-dates (startdate enddate) "Generate a list with ((startyear startmonth) (endyear endmonth))" (setq str nil) (if (not (string-match "[0-9][0-9][0-9][0-9]-[0-9][0-9]" startdate)) (setq str "The start date must have the next format YYYY-MM")) (if (not (string-match "[0-9][0-9][0-9][0-9]-[0-9][0-9]" enddate)) (setq str "The end date must have the next format YYYY-MM")) ;; Checking if startdate < enddate (if (string-match "^[0-9][0-9][0-9][0-9]" startdate) (setq startyear (string-to-number (match-string 0 startdate)))) (if (string-match "[0-9][0-9]$" startdate) (setq startmonth (string-to-number (match-string 0 startdate)))) (if (string-match "^[0-9][0-9][0-9][0-9]" enddate) (setq endyear (string-to-number (match-string 0 enddate)))) (if (string-match "[0-9][0-9]$" enddate) (setq endmonth (string-to-number (match-string 0 enddate)))) (if (> startyear endyear) (setq str "The start date must be before that end date")) (if (and (= startyear endyear) (> startmonth endmonth)) (setq str "The start date must be before that end date")) (if str (message str) ;; (list (list startyear startmonth) (list endyear endmonth)))) (list (list 'startyear startyear) (list 'startmonth startmonth) (list 'endyear endyear) (list 'endmonth endmonth)))) (defun org-effectiveness-plot-ascii (startdate enddate) (interactive "sGive me the start date: \nsGive me the end date: " startdate enddate) (setq dates (org-effectiveness-check-dates startdate enddate)) (setq syear (cadr (assoc 'startyear dates))) (setq smonth (cadr (assoc 'startmonth dates))) (setq eyear (cadr (assoc 'endyear dates))) (setq emonth (cadr (assoc 'endmonth dates))) ;; (switch-to-buffer "*org-effectiveness*") (let ((month smonth) (year syear) (str "")) (while (and (>= eyear year) (>= emonth month)) (org-effectiveness-ascii-bar (string-to-number (org-effectiveness-in-date (concat (number-to-string year) "-" (org-effectiveness-month-to-string month)) 1)) (format "%s-%s" year month)) (if (= month 12) (progn (setq year (+ 1 year)) (setq month 1)) (setq month (+ 1 month)))))) (provide 'org-effectiveness)