Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 2125 lines (1817 sloc) 78.329 kb

My Emacs Configuration

Paths

When emacs runs external utilities, it runs a bare shell without loading init files like .bashrc, so you have to set the paths up manually.

I mostly use binaries installed in a perl build managed by perlbrew and the binaries installed by macports, the following settings have worked for me so far:

(setenv "PATH"
        (mapconcat 'identity
                   (mapcar 'expand-file-name
                           '("~/perl5/perlbrew/bin"
                             "~/perl5/perlbrew/perls/current/bin"
                             "~/perl5/bin"
                             "~/bin"
                             "/opt/local/bin"
                             "/usr/local/bin"
                             "/usr/bin"
                             "/bin")
                           )
                   ":"))
(add-to-list 'exec-path "/usr/local/bin")
(add-to-list 'exec-path (expand-file-name "~/perl5/perlbrew/bin"))
(add-to-list 'exec-path (expand-file-name "~/perl5/perlbrew/perls/current/bin"))
(add-to-list 'exec-path "/opt/local/bin")
(add-to-list 'exec-path (expand-file-name "~/bin"))

User Interface

Color Theme

Colors syntax highlighting can sometimes be a controversial subject between developers, some absolutely despise it, others absolutely need it, like myself. When I read code, I tend to chase the branches and subroutine invocations back and forth across the code in order to follow the flow for a given execution scenario. Of course, I could run a debugger instead, but I like to give my intuition a shot at figuring out the architecture of the code and issues that lead to bugs, most of the times it’s a lot faster. I put a very bright and colorful theme together based on the monokai textmate color theme. The colors work like parser hints that make it easier for my eye to land on a specific bit of code, instead of having to read/scan sequentially.

(require 'color-theme)
(load (expand-file-name "~/etc/emacs/color-theme-almost-monokai.el"))
(color-theme-almost-monokai)

Note that for reading literature text, I turn the colors off because it draws my attention away from the linear plot. Color-theme is a standard library in most emacs distributions, if you want to try out the theme, it can be found in github.

publish monokai color theme to githubEND

Disable Menu and Scroll Bar

I’m of the opinion that there’s no point having a menu in emacs, given the general philosophy is that you can work a lot faster if you now a fairly small subset of the keyboard shortcuts. Also, the menu and toolbar take up a lot of the display real estate, so I disable those.

(menu-bar-mode 0) (require 'tool-bar) (tool-bar-mode 0) (require
'scroll-bar) (scroll-bar-mode -1)

Add Opacify function

(defun djcb-opacity-modify (&optional dec)
  "modify the transparency of the emacs frame; if DEC is t,
    decrease the transparency, otherwise increase it in 10%-steps"
  (let* ((alpha-or-nil (frame-parameter nil 'alpha)) ; nil before setting
          (oldalpha (if alpha-or-nil alpha-or-nil 100))
          (newalpha (if dec (- oldalpha 10) (+ oldalpha 10))))
    (when (and (>= newalpha frame-alpha-lower-limit) (<= newalpha 100))
      (modify-frame-parameters nil (list (cons 'alpha newalpha))))))

 ;; C-8 will increase opacity (== decrease transparency)
 ;; C-9 will decrease opacity (== increase transparency
 ;; C-0 will returns the state to normal
(global-set-key (kbd "C-8") '(lambda()(interactive)(djcb-opacity-modify)))
(global-set-key (kbd "C-9") '(lambda()(interactive)(djcb-opacity-modify t)))
(global-set-key (kbd "C-0") '(lambda()(interactive)
                               (modify-frame-parameters nil `((alpha . 100)))))

(modify-frame-parameters nil `((alpha . 80)))
(setq frame-inherited-parameters '(alpha))

set input method to portuguese

(setq default-input-method "portuguese-prefix")

use the monaco font and set fontsize size to 10

(add-hook 'windows-setup-hook 'ec/init-font)
(defun ec/init-font ()
  (setq window-system-default-frame-alist
        '((x (font . "Monaco")))))
;(set-face-attribute 'default nil :height 100)

prevent cursor from blinking

(blink-cursor-mode 0)

don’t display the startup splash screen

(setq inhibit-startup-message t)

no echo area help on startup

(defun display-startup-echo-area-message ()
  (message ""))

show matching parens (mixed style)

(show-paren-mode t)
(setq show-paren-delay 0.0)
(setq show-paren-style 'parenthesis)

display position in modeline

(setq line-number-mode t)
(setq column-number-mode t)

syntax highlighting everywhere

(global-font-lock-mode t)

highlight selection

(transient-mark-mode t)

make “yes or no” prompts show “y or n” instead

;; make "yes or no" prompts show "y or n" instead
(fset 'yes-or-no-p 'y-or-n-p)

switching

(iswitchb-mode 1)
(icomplete-mode 1)

no backup files

;; no backup files
(setq make-backup-files nil)
(setq auto-save-default nil)

case insensitive completion

(setq completion-ignore-case t)

mouse stuff

(setq
 mouse-1-click-in-non-selected-windows nil
 mouse-yank-at-point t)
(mouse-avoidance-mode 'exile)

indicate empty lines

(setq-default indicate-empty-lines t)

do not show trailing ws by default

but whenever some buffer changes its major mode, enable it if the buffer is visiting a file

(setq-default show-trailing-whitespace nil)
(add-hook 'after-change-major-mode-hook
          (lambda ()
            (when (buffer-file-name)
              (setq show-trailing-whitespace t))))

set default width to 80

(set-default 'fill-column 76)

user info

(setq user-full-name "Eden Cardim")
(setq user-mail-address "edencardim@gmail.com")
(setq user-homepage "http://edencardim.com")

encoding

everything is utf8

(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(setq file-name-coding-system 'utf-8)
(prefer-coding-system 'utf-8)

indent

spaces, not tabs

(setq indent-tabs-mode nil)
(setq-default indent-tabs-mode nil)

4 spaces

(setq default-tab-width 4)
(setq tab-width 4)
(setq backward-delete-char-untabify 4)

cperl mode

initialize

(defalias 'perl-mode 'cperl-mode)
(setq cperl-hairy t)
(setq cperl-highlight-variables-indiscriminately t)

perltidy

(require 'perltidy)

(global-set-key "\C-cpb" 'perltidy-buffer)
(global-set-key "\C-cps" 'perltidy-subroutine)
(global-set-key "\C-cpr" 'perltidy-region)

cperl-mode in test files

(setq auto-mode-alist (cons '("\\.t$" . cperl-mode) auto-mode-alist))

elisp

display function docs automatically

(dolist (hook '(emacs-lisp-mode-hook ielm-mode-hook eshell-mode-hook))
  (add-hook hook (lambda () (eldoc-mode))))

eproject

;; (require 'eproject)
;; (require 'eproject-extras)

;; (dolist (func '(eproject-compile
;;                 eproject-eshell-cd-here
;;                 eproject-multi-isearch-buffers
;;                 eproject-todo
;;                 eproject-grep
;;                 eproject-revisit-project
;;                 eproject-project-root
;;                 eproject-open-all-project-files
;;                 eproject-kill-project-buffers
;;                 eproject-ibuffer
;;                 eproject-find-file
;;                 eproject-ifind-file))
;;   (autoload func "eproject-extras"))

;; (add-hook 'after-change-major-mode-hook
;;           (lambda ()
;;             (when (and (buffer-file-name)
;;                        (not eproject-root))
;;               (eproject-maybe-turn-on))))

;; (define-project-type perl (generic)
;;   (or (look-for "dist.ini") (look-for "Makefile.PL") (look-for "Build.PL"))
;;   :relevant-files ("\\.pm$" "\\.pod$" "\\.t$""\\.pl$" "\\.PL$" "\\.ini$" "\\.conf$"
;;                    "\\.tt$""Changes" "ChangeLog")
;;   :irrelevant-files ("inc/" "blib/" ".build/" "cover_cb/" "\\.tar\\.gz$"  "\\.fix$")
;;   :file-name-map (lambda (root)
;;                    (lambda (root file)
;;                      (cond ((string-match "^lib/\\(.+\\)[.]\\(pm|pod\\)$" file)
;;                             (let ((m (string-match 1 file)))
;;                               (while (string-match "/" m)
;;                                 (setf m (replace-match "::" nil nil m)))
;;                               m))
;;                            (t file))))
;;   :main-file "dist.ini")

;; (defmacro .emacs-curry (function &rest args)
;;   `(lambda () (interactive)
;;      (,function ,@args)))

;; (defmacro .emacs-eproject-key (key command ep-only)
;;   (cons 'progn
;;         (loop for (k . p) in (list (cons key 4) (cons (upcase key) 1))
;;               collect
;;               `(,@(if ep-only '(define-key eproject-mode-map) '(global-set-key))
;;                 (kbd ,(format "C-x p %s" k))
;;                 (.emacs-curry ,command ,p)))))

;; (.emacs-eproject-key "k" eproject-kill-project-buffers t)
;; (.emacs-eproject-key "v" eproject-revisit-project nil)
;; (.emacs-eproject-key "b" eproject-ibuffer t)
;; (.emacs-eproject-key "o" eproject-open-all-project-files t)

gnus

 (require 'gnus)
 (require 'bbdb)
 (require 'bbdb-gnus)
  
 (setq gnus-group-highlight
       '(((and
           (= unread 0)
           (eq level 1))
          . gnus-group-news-1-empty)
         ((and
           (eq level 1))
          . gnus-group-news-1)
         ((and
           (= unread 0)
           (eq level 2))
          . gnus-group-news-2-empty)
         ((and
           (eq level 2))
          . gnus-group-news-2)
         ((and
           (= unread 0)
           (eq level 3))
          . gnus-group-news-3-empty)
         ((and
           (eq level 3))
          . gnus-group-news-3)
         ((and
           (= unread 0)
           (eq level 4))
          . gnus-group-news-4-empty)
         ((and
           (eq level 4))
          . gnus-group-news-4)
         ((and
           (= unread 0)
           (eq level 5))
          . gnus-group-news-5-empty)
         ((and
           (eq level 5))
          . gnus-group-news-5)
         ((and
           (= unread 0)
           (eq level 6))
          . gnus-group-news-5-empty)
         ((and
           (eq level 6))
          . gnus-group-news-5)
         ((and
           (= unread 0))
          . gnus-group-news-low-empty)
         (t . gnus-group-news-low)))
 
 (setq gnus-select-method '(nntp "news.gmane.org"))
 (setq gnus-secondary-select-methods '())
 
 ;; gmail IMAP/SMTP
 ;; needs credentials in ~/.authinfo
 ;; machine imap.gmail.com login username@gmail.com password secret port 993
 
 ; subscribe to gmail
  
 (add-to-list 'gnus-secondary-select-methods
              `(nnimap "gmail"
                       (nnimap-address "imap.gmail.com")
                       (nnimap-server-port 993)
                       (nnimap-stream ssl)
                       (nnimap-inbox "INBOX")))

 (add-to-list 'gnus-secondary-select-methods
              '(nntp "nntp.aioe.org"))
   
 (load "~/.gnus-smtp-password.el")
 
 (setq message-send-mail-function 'smtpmail-send-it)
 (setq smtpmail-default-smtp-server "smtp.gmail.com")
 (setq smtpmail-smtp-server "smtp.gmail.com")
 (setq smtpmail-smtp-service 587)
 
 (setq gnus-check-new-newsgroups t)
 
 (setq starttls-use-gnutls t)
 
 (setq gnus-activate-level 3)
 (setq gnus-asynchronous t)
 (setq gnus-use-header-prefetch t)
 (setq gc-cons-threshold 3500000)
 (setq gnus-use-correct-string-widths nil)
 (setq gnus-use-adaptive-scoring '(word list))
 (setq gnus-adaptive-word-no-group-words t)
 (setq large-newsgroup-initial 50)
 (setq nnrss-use-local t)
 (setq nnimap-nov-is-evil nil)
 (setq gnus-use-trees nil)
 (setq gnus-read-active-file nil)
 (setq gnus-auto-select-first nil)
 (add-hook 'gnus-summary-exit-hook 'gnus-summary-bubble-group)
  
 (setq gnus-ignored-adaptive-words
   '("comic"
     "january"
     "february"
     "march"
     "april"
     "may"
     "june"
     "july"
     "august"
     "september"
     "october"
     "november"
     "december"
     "jan"
     "feb"
     "mar"
     "apr"
     "may"
     "jun"
     "jul"
     "aug"
     "sep"
     "oct"
     "nov"
     "dev"
     "fwd"
     "res"
     "re"
     "de"
     "e"))
 
(defun ec/bbdb-find-subscribed-addresses ()
  (list (mapconcat (lambda (record)
               (regexp-quote (car (bbdb-record-mail record))))
             (bbdb-search (bbdb-records) nil nil nil
                          '(gnus-public . ".+")) "\\|")))
(ec/bbdb-find-subscribed-addresses)
  
 (setq message-subscribed-address-functions
       '(ec/bbdb-find-subscribed-addresses gnus-find-subscribed-addresses))
 (setq
  starttls-use-gnutls t
 
  ;;; display threads in the summary buffer in a way humans can understand. for
  ;;; example like this:
  ;;
  ;; O   14.07.2010 21:40  Nicholas Clark   Re: Directions of perl 5 development
  ;; O   15.07.2010 16:46  Steffen Schwigo  ├►
  ;; O   15.07.2010 17:09  Nicholas Clark   │├►
  ;; O   17.07.2010 15:15  Steffen Schwigo  ││├►
  ;; O   17.07.2010 18:30  Ævar Arnfjörð B  ││└►
  ;; O   17.07.2010 22:14  chromatic        ││ ├►
  ;; O   18.07.2010 07:34  Joshua ben Jore  ││ └►
  ;; O   15.07.2010 20:36  Jesse Vincent    │└►
  ;; O   15.07.2010 17:37  Dave Rolsky      └►
 
  gnus-summary-line-format "%U%R%z %5i %5V %(%&user-date;  %-15,15f %* %B%s%)\n"
  gnus-user-date-format-alist '((t . "%d.%m.%Y %H:%M"))
  gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references
 
  ;; "INBOX" instead of "nnimap+perldition:INBOX"
  gnus-group-line-format "%M%S%p%P%5y:%B%(%G%)%O\n"
 
  gnus-message-archive-group "nnimap+gmail:Sent"
  gnus-gcc-mark-as-read t)

(setq gnus-summary-display-arrow t)
(setq gnus-summary-same-subject "")
(setq gnus-sum-thread-tree-indent " ")
(setq gnus-sum-thread-tree-single-indent "# ")
(setq gnus-sum-thread-tree-root "* ")
(setq gnus-sum-thread-tree-false-root "@ ")
(setq gnus-sum-thread-tree-vertical "|")
(setq gnus-sum-thread-tree-leaf-with-other "|-> ")
(setq gnus-sum-thread-tree-single-leaf "`-> ")

 
 (add-hook 'message-sent-hook 'gnus-score-followup-article)
 
 (add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
 ;;(add-hook 'gnus-message-setup-hook 'mml-secure-message-sign-pgpmime)
 
 ;; FIXME: no worky
 ;;(eval-after-load "mm-decode"
 ;;  '(add-to-list 'mm-automatic-display "application/pgp$"))
 ;;(eval-after-load "mm-decode"
 ;;  (quote (setq mm-automatic-display (remove "application/pgp-signature"
 ;;                                            mm-automatic-display))))
 
 (require 'supercite)
 
 ;; from http://www.delorie.com/gnu/docs/emacs/sc_13.html
 (add-hook 'mail-citation-hook 'sc-cite-original)
 (setq sc-auto-fill-region-p nil)
 (setq sc-nested-citation-p nil)
 
 (setq news-reply-header-hook nil)
 
 (require 'mm-url)
 (defadvice mm-url-insert (after DE-convert-atom-to-rss () )
   "Converts atom to RSS by calling xsltproc."
   (when (re-search-forward "xmlns=\"http://www.w3.org/.*/Atom\""
                nil t)
     (goto-char (point-min))
     (message "Converting Atom to RSS... ")
     (call-process-region (point-min) (point-max)
                          "xsltproc"
                          t t nil
                          (expand-file-name "~/src/atom2rss.xsl") "-")
     (goto-char (point-min))
     (message "Converting Atom to RSS... done")))
 
 (ad-activate 'mm-url-insert)
 
 (setq mm-url-use-external t)
 
 (gnus-add-configuration
  '(article
   (horizontal 1.0
              (vertical 50 (group 1.0))
              (vertical 1.0
                        (summary 0.25 point)
                        (article 1.0)))))
 
 (gnus-add-configuration
  '(summary
   (horizontal 1.0
              (vertical 50 (group 1.0))
              (vertical 1.0 (summary 1.0 point)))))
 
 (setq message-signature-directory (expand-file-name "~/var/lib/org/sigs"))
 (setq gnus-posting-styles
       '((".*"
          (signature-file "edencardim"))
         ("saopaulo"
          (to "saopaulo-pm@mail.pm.org")
          (organization "São Paulo Perl Mongers"))
         ("postgresql\\|perl\\|catalyst\\|dbi\\|london"
          (signature-file "shadowcat")
          (organization "ShadowCat Systems"))))
 
 (require 'starttls)
 
  (defun set-smtp (mech server port user password)
    "Set related SMTP variables for supplied parameters."
    (setq smtpmail-smtp-server server
          smtpmail-smtp-service port
          smtpmail-auth-credentials (list (list server port user password))
          smtpmail-auth-supported (list mech)
          smtpmail-starttls-credentials nil)
    (message "Setting SMTP server to `%s:%s' for user `%s'."
             server port user))
  (defun set-smtp-ssl (server port user password  &optional key cert)
    "Set related SMTP and SSL variables for supplied parameters."
    (setq starttls-use-gnutls t
          starttls-gnutls-program "gnutls-cli"
          starttls-extra-arguments nil
          smtpmail-smtp-server server
          smtpmail-smtp-service port
          smtpmail-auth-credentials (list (list server port user password))
          smtpmail-starttls-credentials (list (list server port key cert)))
    (message
     "Setting SMTP server to `%s:%s' for user `%s'. (SSL enabled.)"
     server port user))
  (defun change-smtp ()
    "Change the SMTP server according to the current from line."
    (save-excursion
      (loop with from = (save-restriction
                          (message-narrow-to-headers)
                          (message-fetch-field "from"))
            for (auth-mech address . auth-spec) in smtp-accounts
            when (string-match address from)
            do (cond
                ((memq auth-mech '(cram-md5 plain login))
                 (return (apply 'set-smtp (cons auth-mech auth-spec))))
                ((eql auth-mech 'ssl)
                 (return (apply 'set-smtp-ssl auth-spec)))
                (t (error "Unrecognized SMTP auth. mechanism: `%s'." auth-mech)))
            finally (error "Cannot infer SMTP information."))))
 (add-hook 'message-send-hook 'change-smtp)
 
 (require 'nnir)
 
 (setq nnir-search-engine 'imap)
 (setq gnus-treat-from-gravatar 'head)
 
 (require 'bbdb-autoloads)
 (require 'bbdb)
 (load "bbdb-com" t)
 (bbdb-initialize 'gnus 'message 'w3)
 (bbdb-insinuate-message)
; (bbdb-insinuate-sc)
; (bbdb-insinuate-w3)
 
 (setq gnus-adaptive-word-score-alist
       `((,gnus-read-mark . 1)
         (,gnus-catchup-mark . -1)
         (,gnus-killed-mark . -5)
         (,gnus-del-mark . -5)))
  
 (setq gnus-decay-scores "\\.ADAPT\\.")
 (require 'boxquote)
 
 (setq gnus-thread-sort-functions
       '((not gnus-thread-sort-by-most-recent-date)
         gnus-thread-sort-by-total-score))
   
 (setq gnus-score-find-score-files-function
       '(gnus-score-find-bnews bbdb/gnus-score))
 (setq bbdb/gnus-score-default 1000)
 
 (setq gnus-level-subscribed 7)
 (setq gnus-level-default-unsubscribed 8)
 (setq gnus-group-default-list-level 1)
 (setq gnus-save-killed-list t)

  

 ;(add-hook 'message-mode-hook (lambda () (flyspell-mode 1)))

ibuffer

(setq ibuffer-saved-filter-groups
      (quote (("default"
               ("dired" (mode . dired-mode))
               ("docs" (mode . pod-mode))
               ("perl" (mode . cperl-mode))
               ("erc" (mode . erc-mode))
               ("config" (name . "\\.conf$"))
               ("planner" (or
                           (name . "^\\*Calendar\\*$")
                           (name . "^diary$")
                           (mode . muse-mode)))
               ("emacs" (or
                         (name . "^\\*scratch\\*$")
                         (name . "^\\*Messages\\*$")))
               ("gnus" (or
                        (mode . message-mode)
                        (mode . bbdb-mode)
                        (mode . mail-mode)
                        (mode . gnus-group-mode)
                        (mode . gnus-summary-mode)
                        (mode . gnus-article-mode)
                        (name . "^\\.bbdb$")
                        (name . "^\\.newsrc-dribble")))))))

(add-hook 'ibuffer-mode-hook
          (lambda ()
            (ibuffer-switch-to-saved-filter-groups "default")))

ido

(require 'ido)
(ido-mode)

magit

;(require 'magit)
;(global-set-key (kbd "\C-c \C-g") 'magit-status)

yasnippet

install

(add-to-list 'load-path (expand-file-name "~/src/yasnippet"))
(require 'yasnippet) ;; not yasnippet-bundle
(yas/initialize)
(yas/load-directory (expand-file-name "~/src/yasnippet/snippets"))
(yas/load-directory (expand-file-name "~/etc/yasnippet"))

fix org-mode key bindings

(defun yas/org-very-safe-expand ()
  (let ((yas/fallback-behavior 'return-nil)) (yas/expand)))

(add-hook 'org-mode-hook
          (lambda ()
            ;; yasnippet (using the new org-cycle hooks)
            (make-variable-buffer-local 'yas/trigger-key)
            (setq yas/trigger-key [tab])
            (add-to-list 'org-tab-first-hook 'yas/org-very-safe-expand)
            (define-key yas/keymap [tab] 'yas/next-field)))

GTD with Org Mode

Org Mode is, as it’s name suggests, a text-editing mode for emacs that helps you deal with organizational tasks for virtually anything. The main philosophy is to use plain-text to keep the data portable, this allows you to edit your org files anywhere.

Introduction And Overview

This post describes my personal org mode configuration and the reasoning behind each choice. I won’t be explaining any of the basic org-mode syntax, the org manual already has an excelent tutorial on that. If you aren’t familiar with the basic syntax of org-mode I suggest you at least read the ”Document Structure” section of the org mode manual before proceeding.

How to read this article

Emacs configuration files are prone to be enormous, and subject to a lot of change over time, so I decided to keep this as a permanent page on the blog so anyone can check the current state of my entire configuration and I’ll post a new entry every time something changes. If you’re looking for a step-to-step guide of how everything evolved into this page, look at the posts under the orgmode tag of the blog, ordered chronologically.

Installing

Org Mode has a very active contributor community, so development happens very fast and new features are being added every day, so I keep a close eye on the repository and mailing list. Generally, I hold off on implementing fancy things on my own until I get feedback from the ML, because odds are someone somewhere is trying to do something similar. My install is based on the bleeding edge version from git, which is very easy to set up:

git clone git://orgmode.org/org-mode.git

Org Babel

Babel is a feature that has to be mentioned before we start the actual tour of org mode, because it’s the feature that actually bootstraps the setup. Through this feature, you can evaluate code from several languages by using the following syntax:

(message "%s" "hello world")

#+results:
: hello world

Results can be produced in several different ways, depending on what language you’re evaluating.

I use org babel to keep my emacs file organized in several code blocks with structured comments to go along with them. This makes it easier to keep track of the rationale. In fact, this post is actually just a formatted export of my emacs startup org file, created by org-mode itself. You can download the raw org-mode file that originated this post from https://github.com/edenc/dotemacs/blob/master/emacs.org.

To use an org file as your emacs startup file, you need the following elisp snippet in your ~/.emacs file, to bootstrap the load process:

(setq dotfiles-dir
      (file-name-directory
       (or (buffer-file-name) load-file-name)))

(let* ((org-dir (expand-file-name
                 "lisp" (expand-file-name
                         "org" (expand-file-name
                                "src" dotfiles-dir))))
       (org-contrib-dir (expand-file-name
                         "lisp" (expand-file-name
                                 "contrib" (expand-file-name
                                            ".." org-dir))))
       (load-path (append (list org-dir org-contrib-dir)
                          (or load-path nil))))
  (require 'org-install)
  (require 'ob-tangle))

(mapc #'org-babel-load-file
      (directory-files
       (expand-file-name "~/etc/emacs")
       t "\\.org$"))

The above snippet loads the babel source blocks of all the .org files in the ~/etc/emacs directory, you should edit that to your preference. After setting up the bootstrap code in .emacs, you can mimic my setup with:

git clone git@github.com:edenc/dotemacs.git ~/etc/emacs

Activating

Org mode’s architecture is modular, so you get to pick what features to use by loading the equivalent modules.

These are the modules I use:

(setq org-modules
      '(org-bbdb
        org-gnus
        org-info
        org-jsinfo
        org-irc
        org-w3m
        org-id
        org-habit))
(require 'org-install)

To enable org mode automatically for .org and .org_archive files:

(add-to-list 'auto-mode-alist
             '("\\.\\(org\\|org_archive\\)$" . org-mode))

The Five Stages of Mastering Workflow

As the post title suggests, My daily work process is based on David Allen’s GTD methodology. As recommended in his book, I have adapted a few things that I think will enhance my productivity, based on my personal characteristics and thought process. It is recommendable that you read the book and take some time to adapt the process to your own lifestyle.

These are a few simple recommendations extracted from the GTD book, which I have implemented in org mode. The basis of the system is to try and relieve your mind from having to remember things, so that you can focus on doing things instead. The process consists of five core activities:

  1. Collect
  2. Process
  3. Organize
  4. Review
  5. Do

The only thing I have to remember to do is to collect things to do and notes throughout the day and follow the schedule I have established within a file called gtd.org.

Collecting

The recommendation is that everything you are considering to do at some point should be captured somewhere then fed to the GTD process. The rationale is that if you need to stop and consider if something needs doing or not, at the point where the issue arises, you will end up not making the ideal judgement on that task. So you should just get in the habit of taking notes of everything, then you can process those notes subsequently. Knowing that everything you capture will be processed and dealt with at some point leaves you more focused on the task at hand. You can just quickly take a note and go back to what you were doing before, knowing that at some point, you will deal with the note you just took.

Taking notes in org is a process called “capturing” within the org jargon. You can specify templates for several different types of notes. Over time, your brain will associate “capturing” with “doing”, and you’ll always take notes of everything you want to do.

Org directory

This is where org looks for files when you use relative paths to specify files. I keep a linux root-like structure in my home dir, and I treat my org files as if they were a like a simple database or log system, so files go into ~/var/lib/org by default.

(setq org-directory (expand-file-name "~/var/lib/org"))

Headline Types

I use 5 types of headlines to control task state and help me keep track of progress in general.

TODO
tasks that have been captured and haven’t been dealt with yet
NEXT
tasks that have been flagged for attention once everything else is cleared
STARTED
tasks in course
DONE
tasks that have been concluded
CANCELLED
tasks that were scheduled previously but can’t be concluded for one or another reason
INBOX
A special marker indicating that this headline is actually an container for incoming tasks, this is just here so that the inbox headings don’t show up as a task in the agenda.
(setq org-todo-keywords
      (quote ((sequence
               "TODO(t)"
               "NEXT(n)"
               "STARTED(s)"
               "|" "DONE(d!/!)" "CANCELLED(c@/!)")
              (sequence "INBOX"))))

The letters between parentheses are the keybindings you need to use after changing the headline state. The vertical bar is special, meaning that states listed from here on in the current sequence are final states.

Inboxes

Whenever you capture something, org-mode will place the entry(ies) you create in this file. The trick is to make the capture process as quick and painless as possible and capture absolutely everything throughout your day. It’s very important that nothing gets in the way of capturing, otherwise you’ll start avoiding it, which means you’ll also avoid doing things. Just capture everything without caring much about what it is and then process it later. Whenever I capture, the headline gets stored in my default notes file and I can process it later and possibly move it somewhere else.

(setq org-default-notes-file (concat org-directory "/todo.org"))

Org mode has a sprintf-like notation for specifying how the headline is supposed to be formatted and what information is supposed to go in it when you capture. I use a single template for everything, from notes to tasks and reminders. The workflow keywords have different meanings for these based on what the headline actually is. If it’s a note, the headline task means “file this note under the proper headline and tags”. If it’s an email it can mean “reply to this email”. TODO Headlines basically mean “deal with this bit of information”. Your mileage may vary.

I use C-c r as the key binding for capturing notes, this is legacy from the days of remember.el, I got used to it and decided to keep it. You can change this to whatever you see fit. Capture creates a headline from the template and places it under whatever file and headline you configure.

(setq org-capture-templates
      (quote
       (("t" "todo" entry (file+headline "todo.org" "inbox")
         "* TODO %?%a\n %U\n"
         :clock-in t
         :clock-resume t))))

The characters in the template mean the following:

%? after filling in the template, place the cursor here
%a invoke org-store-link and insert the link here
%U insert an inactive timestamp here

That specific template is configured to interrupt the current task clock, clock the time we’ve spent capturing and resume the clock on the interrupted task once we’re done capturing.

Org mode automatically adjusts the amount of * to the target heading you’re capturing to. If my inbox heading were a level 3 heading, it would add 3 extra stars to the captured headline, to make it a sibling of inbox.

(global-set-key (kbd "C-c r") 'org-capture)

Org mode can create links pointing to several different locations. I won’t go into all the details of the linking syntax, and you won’t need to know it all because invoking org-capture, preferably through a key binding, will create an org headline with a link created by org-store-link for you automatically, and place it in your inbox.

You can also invoke org-store-link manually then use org-insert-link to insert the link into an org file. Mostly, links are just a file name and some text between brackets. Org uses the text line under the cursor for searching inside the file, much like you would do with grep, except that when you follow the link, you get a buffer with the file opened in it and the cursor placed over the line where the first search matched.

(global-set-key "\C-cl" 'org-store-link)

I maintain a global inbox for everything, during the processing phase, I either move the headlines into their definitive locations in my org files or I send it to a specific project’s inbox if I know it belongs to another project and I’m still skeptic about what to with it. This also lets me account the time I spend processing that specific project’s tasks under the right heading.

You can also teach org how to open your links, my setup uses all the defaults, except for the gnus setting, which I set to gnus-no-server, so that following links uses the local message cache and doesn’t connect to the imap server, which takes forever.

(setq org-link-frame-setup
      '((vm . vm-visit-folder-other-window)
       (gnus . gnus-no-server)
       (file . find-file-other-window)
       (wl . wl)))

Email

Links to mail messages have special syntax and logic that allows org to invoke Gnus and open the equivalent emails correctly. As usual, capturing inside a mail buffer will do the right thing.

IRC

(setq org-irc-link-to-logs t)

By default, if you capture in an erc buffer, it’ll create a link to the channel you captured in. This setting changes this behaviour to saving a log file and link to that instead.Tthe text under the cursor when you captured will be used for searching, when you access the link later on. This is very useful because I use IRC for everything, I even do IM in it via bitlbee, so most of the meetings and conversations happen in an erc buffer throughout the day. With org-capture, I can quickly annotate the meeting while it happens, and/or review it later. This is a lot better than taking several separate notes because you get the full transcript of the chat to give you context. It’s also very useful for when you say “I’ll do X tomorrow” to someone in a quick chat. These types of promises made inside IM windows tend to be forgotten more often than not, I got into the habit of only confirming if I’m going to do something after I’ve captured a reminder to do it. This sole feature has justified moving to ERC, which ships with emacs.

Live/Phone Meetings

For capturing annotations during meetings outside of IRC, I use org-timer. Start it with C-c C-x 0, move your cursor into the heading where you want to annotate and use C-c C-x - to start a list, pressing M-RET (alt + return) will insert additional items into the list and record the times on each new item. And you get a list like this one:

- 0:00:01 :: started meeting
- 0:01:02 :: John reveals his new product proposal: the frobnicator
- 0:01:35 :: frobnicators are supposed to be good organizational devices
- 0:01:52 :: it's a variation on a taser
- 0:02:08 :: electrocutes you whenever you slip a deadline

org-mode

Processing

Processing, in my case, means looking at any incoming email messages and other things I have captured throughout the day. I process my inboxes twice a day, after breakfast and after lunch. Before establishing the routine of checking at a given point of the day, I found I was looking at my mailboxes all the time, and that diverts focus and wastes time.

The Agenda

The best way to process items is by using the agenda. Tasks can be displayed in several dimensions, and while I used the default agenda settings for quite a long time, I found that using a single agenda view which displays all the dimensions I need at once is a lot more practical. I use what org mode calls a “block agenda”, which are just several agendas bundled into one.

(setq org-agenda-custom-commands
      '(("w" "Work Agenda"
         ;; inbox
         ((tags-todo "-TODO=\"INBOX\"+#inbox"
                     ((org-agenda-overriding-header "Inbox")))

          ;; waiting
          (tags-todo "+#waiting"
                     ((org-agenda-overriding-header "Waiting")
                      (org-agenda-tags-todo-honor-ignore-options t)
                      (org-agenda-todo-ignore-scheduled t)
                      (org-agenda-todo-ignore-deadlines t)))

          ;; today's schedule
          (agenda "")

          ;; started tasks
          (tags-todo "+TODO=\"STARTED\"-#hold"
                     ((org-agenda-overriding-header "STARTED Actions")
                      (org-agenda-tags-todo-honor-ignore-options t)
                      (org-agenda-todo-ignore-scheduled nil)
                            (org-agenda-todo-ignore-deadlines nil)))

          ;; next tasks
          (tags-todo "+TODO=\"NEXT\"-#hold"
                     ((org-agenda-overriding-header "NEXT Actions")
                      (org-agenda-tags-todo-honor-ignore-options t)
                      (org-agenda-todo-ignore-scheduled t)
                      (org-agenda-todo-ignore-deadlines t)))

          ;; projects
          (tags-todo "-#waiting-TODO=\"INBOX\""
                     ((org-agenda-skip-function 'bh/skip-non-projects)
                      (org-agenda-overriding-header
                        "Projects (< to restrict by project)")))

          ;; backlog
          (tags-todo "+TODO=\"TODO\"-#hold-#inbox"
                     ((org-agenda-overriding-header "Action Backlog")
                      (org-agenda-tags-todo-honor-ignore-options t)
                      (org-agenda-todo-ignore-scheduled t)
                      (org-agenda-todo-ignore-deadlines t))))
         ((org-agenda-filter-preset '("-#hold"))))

      ;; stuck projects revision agenda view
      ("#" "Stuck Projects"

        ;; stuck projects
       ((tags-todo "-#hold"
                   ((org-agenda-skip-function 'bh/skip-non-stuck-projects)
                    (org-agenda-overriding-header "Stuck Projects")))

        ;; action backlog
        (tags-todo "-#hold"
                   ((org-agenda-overriding-header "Action Backlog")))))

      ;; candidate tasks for archiving
      ("A" "Tasks to be Archived" tags "-#hold"
       ((org-(and )genda-overriding-header "Tasks to Archive")
        (org-agenda-skip-function 'bh/skip-non-archivable-tasks)))

      ;; held items for revision
      ("r" "Review Items" tags-todo "+#hold"
       ((org-agenda-todo-ignore-with-date nil)
        (org-agenda-todo-ignore-scheduled nil)
        (org-agenda-todo-ignore-deadlines nil)))))
(setq org-agenda-ndays 1)
(global-set-key "\C-ca" 'org-agenda)

Habits

To remind me to process my inboxes, I have the following tasks defined in my gtd.org file:

** TODO Read mail - 1st pass
   SCHEDULED: <2011-05-21 Sat 06:20 ++1d>
   :PROPERTIES:
   :STYLE:    habit
   :Effort:   0:10
   :CLOCK_MODELINE_TOTAL: today
   :END:
** TODO Process inbox - 1st pass
   SCHEDULED: <2011-05-21 Sat 06:30 ++1d>
   :PROPERTIES:
   :STYLE:    habit
   :Effort:   0:10
   :CLOCK_MODELINE_TOTAL: today
   :END:
** TODO Read mail - 2nd pass
   SCHEDULED: <2011-05-21 Sat 14:00 ++1d>
   :PROPERTIES:
   :STYLE:    habit
   :Effort:   0:10
   :CLOCK_MODELINE_TOTAL: today
   :END:
** TODO Process inbox - 2nd pass
   SCHEDULED: <2011-05-21 Sat 14:10 ++1d>
   :PROPERTIES:
   :STYLE:    habit
   :Effort:   0:10
   :CLOCK_MODELINE_TOTAL: today
   :END:

I have defined all four tasks as habits, this is enabled by the org-habit module which we loaded earlier. To define a task as a habit, it needs to have a repeating SCHEDULED or DEADLINE property and have the STYLE property set to “habit”, as demonstrated above. A habit appears in the agenda like this:

./habits.png

Setting up the agenda and displaying will be covered later on in this article.

3 Organize

4 Review

5 Do

org mode

(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(require 'org-checklist)
(require 'org-inlinetask)
(require 'org-depend)

(setq org-inlinetask-export nil)
(setq org-inlinetask-default-state "TODO")
(setq org-habit-graph-column 65)


; enable org-mode in emails
;(add-hook 'message-mode-hook 'orgstruct++-mode)
;(add-hook 'message-mode-hook 'orgtbl-mode)

(global-set-key "\C-cb" 'org-iswitchb)
(global-set-key "\C-ci" 'bh/clock-in)
(global-set-key "\C-co" 'bh/clock-out)
(global-set-key "\C-cj" 'org-clock-goto)
(global-set-key "\C-ct" 'edenc/link-to-test)
;(global-set-key "\C-cpp" 'org-jekyll-export-blog)

(require 'org-timer)
(setq org-clock-idle-time 15)

(defun bh/is-project-p-with-open-subtasks ()
  "Any task with a todo keyword subtask"
  (let ((has-subtask)
        (subtree-end (save-excursion (org-end-of-subtree t))))
    (save-excursion
      (forward-line 1)
      (while (and (not has-subtask)
                  (< (point) subtree-end)
                  (re-search-forward "^\*+ " subtree-end t))
        (when (and
               (member (org-get-todo-state) org-todo-keywords-1)
               (not (member (org-get-todo-state) org-done-keywords)))
          (setq has-subtask t))))
    has-subtask))

(defun bh/clock-in-to-started (kw)
  "Switch task from TODO or NEXT to STARTED when clocking in.
Skips capture tasks and tasks with subtasks"
  (if (and (member (org-get-todo-state) (list "TODO" "NEXT"))
           (not (and (boundp 'org-capture-mode) org-capture-mode))
           (not (bh/is-project-p-with-open-subtasks)))
      "STARTED"))

(defun bh/clock-in-to-next (kw)
  "Switch task from TODO to NEXT when clocking in.
Skips capture tasks and tasks with subtasks"
  (if (and (string-equal kw "TODO")
           (not (and (boundp 'org-capture-mode) org-capture-mode)))
      (let ((subtree-end (save-excursion (org-end-of-subtree t)))
            (has-subtask nil))
        (save-excursion
          (forward-line 1)
          (while (and (not has-subtask)
                      (< (point) subtree-end)
                      (re-search-forward "^\*+ " subtree-end t))
            (when (member (org-get-todo-state) org-not-done-keywords)
              (setq has-subtask t))))
        (when (not has-subtask)
          "NEXT"))))

;; Resume clocking tasks when emacs is restarted
(org-clock-persistence-insinuate)
;;
;; Yes it's long... but more is better ;)
(setq org-clock-history-length 28)
;; Resume clocking task on clock-in if the clock is open
(setq org-clock-in-resume t)
;; Change task state to NEXT when clocking in
(setq org-clock-in-switch-to-state (quote bh/clock-in-to-started))
;; Separate drawers for clocking and logs
(setq org-drawers (quote ("PROPERTIES" "LOGBOOK" "CLOCK")))
;; Save clock data in the CLOCK drawer and state changes and notes in the LOGBOOK drawer
(setq org-clock-into-drawer t)
;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)
;; Clock out when moving task to a done state
(setq org-clock-out-when-done t)
;; Save the running clock and all clock history when exiting Emacs, load it on startup
(setq org-clock-persist (quote history))
;; Enable auto clock resolution for finding open clocks
(setq org-clock-auto-clock-resolution (quote when-no-clock-is-running))
;; Include current clocking task in clock reports
(setq org-clock-report-include-clocking-task t)

(setq bh/keep-clock-running nil)

(defun bh/clock-in ()
  (interactive)
  (setq bh/keep-clock-running t)
  (if (marker-buffer org-clock-default-task)
      (unless (org-clock-is-active)
        (bh/clock-in-default-task))
    (unless (marker-buffer org-clock-default-task)
      (org-agenda nil "c"))))

(defun bh/clock-out ()
  (interactive)
  (setq bh/keep-clock-running nil)
  (when (org-clock-is-active)
    (org-clock-out)))

(defun bh/clock-in-default-task ()
  (save-excursion
    (org-with-point-at org-clock-default-task
      (org-clock-in))))

(defun bh/clock-out-maybe ()
  (when (and bh/keep-clock-running (not org-clock-clocking-in) (marker-buffer org-clock-default-task))
    (bh/clock-in-default-task)))

(add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append)

;; Set default column view headings: Task Effort Clock_Summary
(setq org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM")

;; Remove empty CLOCK drawers on clock out
(defun bh/remove-empty-drawer-on-clock-out ()
  (interactive)
  (save-excursion
    (beginning-of-line 0)
    (org-remove-empty-drawer-at "CLOCK" (point))))

(add-hook 'org-clock-out-hook 'bh/remove-empty-drawer-on-clock-out 'append)

;; === AGENDA ===

(if (not (boundp 'ec/org-agenda-export)) (setq org-agenda-files '("~/var/lib/org")))

(setq org-refile-targets (quote ((org-agenda-files :maxlevel . 5) (nil :maxlevel . 5))))
; Targets start with the file name - allows creating level 1 tasks
(setq org-refile-use-outline-path (quote file))

; Targets complete in steps so we start with filename, TAB shows the next level of targets etc
(setq org-outline-path-complete-in-steps t)

(setq org-timeline-show-empty-dates nil)

(setq org-enforce-todo-dependencies t)
(setq org-agenda-dim-blocked-tasks t)

(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-deadline-if-done t)

(setq org-agenda-log-mode-items (quote (clock)))

(setq org-agenda-include-diary t)

;; Show all future entries for repeating tasks
(setq org-agenda-repeating-timestamp-show-all t)

;; Show all agenda dates - even if they are empty
(setq org-agenda-show-all-dates t)

;; Sorting order for tasks on the agenda
(setq org-agenda-sorting-strategy
      (quote ((agenda time-up habit-up user-defined-up priority-down effort-up category-up)
              (todo priority-down category-up)
              (tags priority-down category-up))))

;; Start the weekly agenda today
(setq org-agenda-start-on-weekday nil)

;; enable display of the time grid
(setq org-agenda-use-time-grid t)

;; Display tags farther right
(setq org-agenda-tags-column -102)

;; Agenda sorting functions
(setq org-agenda-cmp-user-defined 'bh/agenda-sort)

(defun bh/agenda-sort (a b)
  "Sorting strategy for agenda items.
Late deadlines first, then scheduled, then non-late deadlines"
  (let (result num-a num-b)
    (cond
     ; time specific items are already sorted first by org-agenda-sorting-strategy

     ; late deadlines
     ((bh/agenda-sort-test-num 'bh/is-late-deadline '< a b))

     ; deadlines for today
     ((bh/agenda-sort-test 'bh/is-due-deadline a b))

     ; pending deadlines
     ((bh/agenda-sort-test-num 'bh/is-pending-deadline '< a b))

     ; late scheduled items
     ((bh/agenda-sort-test-num 'bh/is-scheduled-late '> a b))

     ; scheduled items for today
     ((bh/agenda-sort-test 'bh/is-scheduled-today a b))

     ; non-deadline and non-scheduled items
     ((bh/agenda-sort-test 'bh/is-not-scheduled-or-deadline a b))

     ; finally default to unsorted
     (t (setq result nil))
     )
    result))

(defmacro bh/agenda-sort-test (fn a b)
  "Test for agenda sort"
  `(cond
    ; if both match leave them unsorted
    ((and (apply ,fn (list ,a))
          (apply ,fn (list ,b)))
     (setq result nil))
    ; if a matches put a first
    ((apply ,fn (list ,a))
     ; if b also matches leave unsorted
     (if (apply ,fn (list ,b))
         (setq result nil)
       (setq result -1)))
    ; otherwise if b matches put b first
    ((apply ,fn (list ,b))
     (setq result 1))
    ; if none match leave them unsorted
    (t nil)))

(defmacro bh/agenda-sort-test-num (fn compfn a b)
  `(cond
    ((apply ,fn (list ,a))
     (setq num-a (string-to-number (match-string 1 ,a)))
     (if (apply ,fn (list ,b))
         (progn
           (setq num-b (string-to-number (match-string 1 ,b)))
           (setq result (if (apply ,compfn (list num-a num-b))
                            -1
                          1)))
       (setq result -1)))
    ((apply ,fn (list ,b))
     (setq result 1))
    (t nil)))

(defun bh/is-not-scheduled-or-deadline (date-str)
  (and (not (bh/is-deadline date-str))
       (not (bh/is-scheduled date-str))))

(defun bh/is-due-deadline (date-str)
  (string-match "Deadline:" date-str))

(defun bh/is-late-deadline (date-str)
  (string-match "In *\\(-.*\\)d\.:" date-str))

(defun bh/is-pending-deadline (date-str)
  (string-match "In \\([^-]*\\)d\.:" date-str))

(defun bh/is-deadline (date-str)
  (or (bh/is-due-deadline date-str)
      (bh/is-late-deadline date-str)
      (bh/is-pending-deadline date-str)))

(defun bh/is-scheduled (date-str)
  (or (bh/is-scheduled-today date-str)
      (bh/is-scheduled-late date-str)))

(defun bh/is-scheduled-today (date-str)
  (string-match "Scheduled:" date-str))

(defun bh/is-scheduled-late (date-str)
  (string-match "Sched\.\\(.*\\)x:" date-str))

;; === DIARY ===

(setq diary-file (expand-file-name "~/var/lib/org/diary"))

;; === LINKS ===

;; this function needs a #+LINK test definition in every org file
;; so we can point it to the correct project path
(defun edenc/link-to-test (&optional arg)
  "create link to test using headline text" (interactive "i")
  (insert
   (org-make-link-string
    (concat
     "test:"
     (mapconcat 'identity
                (split-string
                 (downcase (nth 4 (org-heading-components))) "[ ]")
                "-")
     ".t")
    "test")))
(setq org-open-non-existing-files t)

(setq gnus-level-default-subscribed 2)

;; === VISUALS ===
(setq org-hide-leading-stars t)
(setq org-deadline-warning-days 7)
(setq org-insert-mode-line-in-empty-file t)

;; === CAPTURING ===

(global-set-key (kbd "C-c gi") 'ec/generate-invoice-template)
(defun ec/generate-invoice-template ()
  (interactive)
  (let ((heading (org-entry-get nil "EXPORT_TITLE" t))
        (code (concat (org-entry-get nil "CLIENT_CODE" t)
                         (format-time-string "%Y%m%d" (current-time))))
        (rate (org-entry-get nil "RATE" t))
        (rate-string (org-entry-get nil "RATE_STRING" t))
        (curr-sym (org-entry-get nil "CURRENCY_SYMBOL" t))
        (task-str (org-entry-get nil "TASK_STRING" t))
        (time-str (org-entry-get nil "TIME_STRING" t))
        (cblock (format-time-string "%Y-%m" (current-time))))
    (progn
      (org-insert-heading-respect-content)
      (org-demote-subtree)
      (insert (format "%s %s\n\n%s: %s %s/hr\n\n#+begin: clocktable :maxlevel 4 :scope file :header \"\" :narrow nil :block %s :indent t :tags \"-ARCHIVE\"\n#+TBLFM: @1$1=%s::@1$2=%s::@2$1=Total::$1='(replace-regexp-in-string \"\\\\(\\\\(DONE\\\\|NEXT\\\\|PROJECT\\\\|ONGOING\\\\|TODO\\\\) ?\\\\)?\\\\(\\\\[#.\\\\] \\\\)?\" \"\" $1)::$6='(format \"%s %%.2f\" (* (/ $PROP_RATE 60) (apply 'org-hh:mm-string-to-minutes '($2..$6))))
#+end: clocktable"
                      heading code rate-string curr-sym rate cblock task-str time-str curr-sym))
      (previous-line 2)
      (org-beginning-of-line)
      (org-update-dblock))))

(setq org-export-latex-tables-centered t)
(defun org-feed-parse-rdf-feed (buffer)
  "Parse BUFFER for RDF feed entries.
Returns a list of entries, with each entry a property list,
containing the properties `:guid' and `:item-full-text'."
  (let (entries beg end item guid entry)
    (with-current-buffer buffer
      (widen)
      (goto-char (point-min))
      (while (re-search-forward "<item[> ]" nil t)
    (setq beg (point)
          end (and (re-search-forward "</item>" nil t)
               (match-beginning 0)))
    (setq item (buffer-substring beg end)
          guid (if (string-match "<link\\>.*?>\\(.*?\\)</link>" item)
               (org-match-string-no-properties 1 item)))
    (setq entry (list :guid guid :item-full-text item))
    (push entry entries)
    (widen)
    (goto-char end))
      (nreverse entries))))

(setq org-feed-alist
 '(("Socialflow"
    "https://www.shadowcat.co.uk/tickets/Search/Results.rdf?Order=ASC|ASC|ASC|ASC&OrderBy=id|||&Query=(%20Owner%20%3D%20'edenc'%20OR%20Creator%20%3D%20'edenc'%20OR%20Cc.EmailAddress%20LIKE%20'edencardim%40gmail.com'%20)%20AND%20Queue%20%3D%20'SocialFlow%3A%3APlannedFeatures'"
    "~/var/lib/org/shadowcat.org" "Inbox Socialflow" :template "* TODO %h\n %U\n %a\n")))

;; load feed specs from org directory
(dolist (file (directory-files org-directory t "\\.el$"))
  (load file))

(setq
 org-mobile-inbox-for-pull "~/var/lib/org/mobile.org"
 org-mobile-directory "~/Dropbox/MobileOrg"
 org-refile-allow-creating-parent-nodes (quote confirm)
 org-global-properties
              '(("Effort_ALL". "0 0:10 0:30 1:00 2:00 3:00 4:00")))

(defun ae/weekday-p ()
  (let ((wday (nth 6 (decode-time))))
    (and (< wday 6) (> wday 0))))

(defun ae/working-p ()
  (let ((hour (nth 2 (decode-time))))
    (and (ae/weekday-p)
         (or (and (>= hour 7) (< hour 13))
             (and (>= hour 14) (< hour 18))))))

(defun ae/business-p ()
  (let ((hour (nth 2 (decode-time))))
    (and (ae/weekday-p)
         (or (and (>= hour 8) (<= hour 18))))))

(defun ae/bank-p ()
  (let ((hour (nth 2 (decode-time))))
    (and (ae/weekday-p)
         (or (and (>= hour 11) (<= hour 15))))))

(defun ae/network-p ()
  (= 0 (call-process "ping" nil nil nil
                     "-c1" "-q" "google.com")))

(defun ae/home-p ()
  (= 0 (call-process "ishome" nil nil nil)))

(defun ae/org-agenda-auto-exclude-function (tag)
  (and (cond
        ((string= tag "#hold")
         t)
        ((string= tag "@internet")
         (not (ae/network-p)))
        ((string= tag "@bank")
         (not (ae/bank-p)))
        ((or (string= tag "@errand")
             (string= tag "@phone")
             (string= tag "@business"))
         (not (ae/business-p)))
        ((string= tag "@home")
         (not (ae/home-p)))
       )
       (concat "-" tag)))

(setq org-agenda-auto-exclude-function 'ae/org-agenda-auto-exclude-function)

(setq org-todo-keywords (quote ((sequence "TODO(t)" "NEXT(n)" "STARTED(s)" "|" "DONE(d!/!)" "CANCELLED(c@/!)")
                                (sequence "INBOX")
                                (sequence "GOAL"))))

(setq org-todo-keyword-faces
      `(("TODO"      :foreground ,monokai-magenta :weight bold)
        ("NEXT"      :foreground ,monokai-yellow  :weight bold)
        ("INBOX"     :foreground "#f0dfaf"        :weight bold)
        ("STARTED"   :foreground ,monokai-blue    :weight bold)
        ("DONE"      :foreground ,monokai-green   :weight bold)
        ("GOAL"      :foreground "indianred1"     :weight bold)))

(setq org-quote-string "")
(setq org-icalendar-store-UID t)
(setq org-icalendar-use-scheduled '(event-if-todo))

(defun jump-to-org-agenda ()
  (interactive)
  (let ((buf (get-buffer "*Org Agenda*"))
        wind)
    (if buf
        (if (setq wind (get-buffer-window buf))
            (select-window wind)
          (if (called-interactively-p)
              (progn
                (select-window (display-buffer buf t t))
                (org-fit-window-to-buffer)
                ;; (org-agenda-redo)
                )
            (with-selected-window (display-buffer buf)
              (org-fit-window-to-buffer)
              ;; (org-agenda-redo)
              )))
      (call-interactively 'org-agenda-list)))
  ;;(let ((buf (get-buffer "*Calendar*")))
  ;;  (unless (get-buffer-window buf)
  ;;    (org-agenda-goto-calendar)))
  )

; Erase all reminders and rebuilt reminders for today from the agenda
(defun bh/org-agenda-to-appt ()
  (interactive)
  (setq appt-time-msg-list nil)
  (org-agenda-to-appt))

; Rebuild the reminders everytime the agenda is displayed
(add-hook 'org-finalize-agenda-hook 'bh/org-agenda-to-appt)

; This is at the end of my .emacs - so appointments are set up when Emacs starts
(bh/org-agenda-to-appt)

; Activate appointments so we get notifications
(appt-activate t)

(setq appt-message-warning-time 30)
(setq appt-display-interval 15)

; If we leave Emacs running overnight - reset the appointments one minute after midnight
(run-at-time "24:01" nil 'bh/org-agenda-to-appt)

(run-with-idle-timer 300 t 'jump-to-org-agenda)

; pull from org mobile
(org-mobile-pull)
(run-at-time nil 1800 'org-save-all-org-buffers)

(setq org-ditaa-jar-path (expand-file-name "~/workspace/org-mode/contrib/scripts/ditaa.jar"))

(add-hook 'org-babel-after-execute-hook 'org-display-inline-images)

(org-babel-do-load-languages
 'org-babel-load-languages
  '((emacs-lisp . t)
    (ditaa . t)
    (perl . t)
    (css .t)
    (sh . t)
    (org . t)
    (ledger .t)
    (latex .t)
    (dot .t)))

(setq org-hierarchical-todo-statistics nil)
;; start emacs with main todo file open
(if (not (boundp 'ec/org-agenda-export)) (find-file org-default-notes-file))

(setq org-export-latex-minted nil)
(add-to-list 'org-export-latex-packages-alist '("" "listings"))
;(add-to-list 'org-export-latex-packages-alist '("" "minted"))
(add-to-list 'org-export-latex-packages-alist '("" "color"))
(setq org-latex-to-pdf-process
  '("pdflatex -interaction nonstopmode -shell-escape -output-directory %o %f"
    "pdflatex -interaction nonstopmode -shell-escape -output-directory %o %f"
    "pdflatex -interaction nonstopmode -shell-escape -output-directory %o %f"))
(setq org-beamer-fragile-re "^[ \t]*\\\\begin{\\(verbatim\\|lstlisting\\)}")
(setq org-export-latex-minted-with-line-numbers nil)
(setq org-export-with-LaTeX-fragments t)
(setq org-default-priority ?C)
(setq org-lowest-priority ?D)

(defun ec/restrict-agenda (&optional arg)
  (interactive "P")
  (org-agenda-goto)
  (if (and arg
           (not (org-up-heading-safe)))
      (org-agenda-remove-restriction-lock)
    (org-agenda-set-restriction-lock))
  (jump-to-org-agenda))
(org-defkey org-agenda-mode-map "<" 'ec/restrict-agenda)

(setq org-log-into-drawer t)

(setq org-email-link-description-format "%c: %.80s")

(setq org-habit-following-days 14)
(setq org-habit-preceding-days 14)

(defun bh/is-project-p ()
  "Any task with a todo keyword subtask"
  (let ((has-subtask)
        (subtree-end (save-excursion (org-end-of-subtree t))))
    (save-excursion
      (forward-line 1)
      (while (and (not has-subtask)
                  (< (point) subtree-end)
                  (re-search-forward "^\*+ " subtree-end t))
        (when (member (org-get-todo-state) org-todo-keywords-1)
          (setq has-subtask t))))
    has-subtask))

(setq org-archive-mark-done nil)

(defun bh/skip-non-archivable-tasks ()
  "Skip trees that are not available for archiving"
  (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
         (a-month-ago (* 60 60 24 31))
         (last-month (format-time-string "%Y-%m-" (time-subtract (current-time) (seconds-to-time a-month-ago))))
         (this-month (format-time-string "%Y-%m-" (current-time)))
         (subtree-is-current (save-excursion
                               (forward-line 1)
                               (and (< (point) subtree-end)
                                    (re-search-forward (concat last-month "\\|" this-month) subtree-end t)))))
    (if subtree-is-current
        subtree-end ; Has a date in this month or last month, skip it
      nil)))

(defun bh/skip-non-stuck-projects ()
  "Skip trees that are not stuck projects"
  (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
         (has-next (save-excursion
                     (forward-line 1)
                     (and (< (point) subtree-end)
                          (re-search-forward "^\\*+ \\(NEXT\\|STARTED\\) " subtree-end t)))))
    (if (and (bh/is-project-p) (not has-next))
        nil ; a stuck project, has subtasks but no next task
      subtree-end)))

(defun bh/skip-non-projects ()
  "Skip trees that are not projects"
  (let* ((subtree-end (save-excursion (org-end-of-subtree t))))
    (if (bh/is-project-p)
        nil
      subtree-end)))

(defun bh/skip-projects ()
  "Skip trees that are projects"
  (let* ((subtree-end (save-excursion (org-end-of-subtree t))))
    (if (bh/is-project-p)
        subtree-end
      nil)))

(setq org-archive-mark-done nil)

(defun bh/skip-non-archivable-tasks ()
  "Skip trees that are not available for archiving"
  (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
         (a-month-ago (* 60 60 24 31))
         (last-month (format-time-string "%Y-%m-" (time-subtract (current-time) (seconds-to-time a-month-ago))))
         (this-month (format-time-string "%Y-%m-" (current-time)))
         (subtree-is-current (save-excursion
                               (forward-line 1)
                               (and (< (point) subtree-end)
                                    (re-search-forward (concat last-month "\\|" this-month) subtree-end t)))))
    (if subtree-is-current
        subtree-end ; Has a date in this month or last month, skip it
      nil)))

(setq org-export-latex-classes '(("article"
     "\\documentclass[11pt]{article}"
     ("\\section{%s}" . "\\section*{%s}")
     ("\\subsection{%s}" . "\\subsection*{%s}")
     ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
     ("\\paragraph{%s}" . "\\paragraph*{%s}")
     ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
    ("report"
     "\\documentclass[11pt]{report}"
     ("\\part{%s}" . "\\part*{%s}")
     ("\\chapter{%s}" . "\\chapter*{%s}")
     ("\\section{%s}" . "\\section*{%s}")
     ("\\subsection{%s}" . "\\subsection*{%s}")
     ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
    ("book"
     "\\documentclass[11pt]{book}"
     ("\\part{%s}" . "\\part*{%s}")
     ("\\chapter{%s}" . "\\chapter*{%s}")
     ("\\section{%s}" . "\\section*{%s}")
     ("\\subsection{%s}" . "\\subsection*{%s}")
     ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
    ("beamer"
     "\\documentclass{beamer}"
     org-beamer-sectioning )
    ("letter"
     "\\documentclass{letter}"
     ("\\begin{letter}{%s}" "\\end{letter}")
     ("\\opening{%s}" "\\closing{Cordially,}"))))

(setq org-todo-repeat-to-state "TODO")

(org-babel-lob-ingest
  (expand-file-name "~/src/org-mode/contrib/babel/library-of-babel.org"))

(setq org-export-latex-tables-centered t)

(global-set-key (kbd "\C-cgi") 'ec/generate-invoice-template)

Mail Invoice

(defun ec/mail-invoice ()
  (interactive)
  (let ((invoice-file (concat
                  (file-name-sans-extension
                   (buffer-file-name))
                  ".pdf"))
        (invoice (org-get-heading)))
    (org-up-heading-safe)
    (setq title (org-get-heading))
    (setq subject (format "%s %s" title invoice))
  (let ((name (org-entry-get nil "RECIPIENT" t)))
    (bbdb-search (bbdb-records) name)
  (set-buffer bbdb-buffer-name)
  (bbdb-mail (bbdb-current-record) subject)
  (mml-attach-file invoice-file))))

(global-set-key (kbd "\C-cgm") 'ec/mail-invoice)

org2blog

(require 'org2blog-autoloads)
(load (expand-file-name "~/.my-blog-password.el"))
(setq org2blog/wp-use-wp-latex nil)
(setq org2blog/wp-blog-alist
      `(("blog"
         :url "http://blog.edencardim.com/xmlrpc.php"
         :username "edenc"
         :password ,org2blog-password)))

irc

servers

(defun ec/erc-connect ()
  (interactive)
  (load (expand-file-name "~/.my-erc-servers.el")))
(global-set-key "\C-cc" 'ec/erc-connect)

bitlbee auto-identify

(load "~/.my-bitlbee-password.el")
(add-hook 'erc-join-hook 'bitlbee-identify)
(defun bitlbee-identify ()
 "If we're on the bitlbee server, send the identify command to the
&bitlbee channel."
(when (and (string= "localhost" erc-session-server)
           (string= "&bitlbee" (buffer-name)))
  (erc-message "PRIVMSG" (format "%s identify %s"
                                 (erc-default-target)
                                 bitlbee-password))))

make queries as important as someone mentioning your name in a channel

(defadvice erc-track-find-face (around erc-track-find-face-promote-query activate)
  (if (erc-query-buffer-p)
      (setq ad-return-value 'erc-current-nick-face)
    ad-do-it))

general config

(require 'erc)
(require 'erc-spelling)
(setq erc-modules '(netsplit button match track completion readonly networks ring autojoin noncommands irccontrols move-to-prompt stamp menu list log stamp truncate spelling))
(setq
 erc-track-use-faces t
 erc-auto-query 'bury
 erc-autoaway-idle-method 'user
 erc-autoaway-message "I'm gone"
 erc-auto-discard-away t
 ;; I'd actually like for bbdb to store stuff on join and nick changes
 ;; too, but it sometimes wants to be interactive when creating new
 ;; records, so this is turned off by default.
 erc-bbdb-auto-create-on-join-p nil
 erc-bbdb-auto-create-on-nick-p nil
 erc-bbdb-auto-create-on-whois-p nil
 erc-fill-column 78
 erc-hide-list '("JOIN" "PART" "QUIT")
 erc-join-buffer 'bury
 erc-keywords '("\\beden\\b" "\\bedenc\\b" "\\breaction\\b")
 erc-kill-buffer-on-part t
 erc-kill-server-buffer-on-quit t
 erc-max-buffer-size 80000
 erc-query-display 'bury
 erc-timestamp-only-if-changed-flag t
 erc-track-exclude-server-buffer t
 erc-track-exclude-types
 '("JOIN" "NICK" "PART" "QUIT" "MODE" "324" "329" "332" "333" "353" "477")
 erc-track-faces-priority-list '(erc-current-nick-face erc-keyword-face)
 erc-track-minor-mode t
 erc-track-position-in-mode-line t)
(setq
 erc-track-priority-faces-only
 '("#mongodb" "#dbix-class" "#catalyst" "#debian-perl" "#idlerpg" "#idleRPG"
   "#london.pm" "#rt" "#musicbrainz-devel" "#poe" "#perlrdf" "#mogilefs" "#startups"
   "#yapcbrasil-org" "#mysql" "#perlde"))
(setq
 erc-track-exclude '("&bitlbee" "#git" "#python" "#emacs" "#memcached" "#irssi"
                     "#xmonad" "#mojo" "#postgresql" "#perl" "#parrot")
 erc-track-shorten-start 2
 erc-track-switch-direction 'importance
 erc-truncate-mode t
 erc-whowas-on-nosuchnick t
 erc-server-send-ping-interval 10
 erc-server-send-ping-timeout 40)
 (setq erc-spelling-dictionaries
 '(("#sao-paulo.pm" "brasileiro")
   ("#rio-pm" "brasileiro")
   ("#chicobot" "brasileiro")
   ("#opendata-br" "brasileiro")
   ("#ubuntu-br" "brasileiro")
   ("##ubuntu-off-topic" "brasileiro")
   ("#swurl-dev" "brasileiro")))
 (setq ispell-dictionary "english")

nick colors

(defun ec/erc-track-exclude-current-buffer-toggle ()
  (interactive)
  (let ((channel (buffer-name (current-buffer))))
    (if (not (member channel erc-track-priority-faces-only))
        (progn (message "%s: tracking priority faces only" channel)
               (add-to-list 'erc-track-priority-faces-only channel))
      (progn (message "%s: tracking all faces" channel)
             (setq erc-track-priority-faces-only
                   (delete channel erc-track-priority-faces-only))))))

(global-set-key "\C-ce" 'ec/erc-track-exclude-current-buffer-toggle)

;; Pool of colors to use when coloring IRC nicks.
;; (setq erc-colors-list
;;       '(
;;         "#75715D"
;;         "#65B042"
;;         "#F1266F"
;;         "#66D9EF"
;;         "#89BDFF"
;;         "#FD5FF1"
;;         "#D62E00"))

;; special colors for special people
(setq erc-nick-color-alist
      `(("Getty" . ,monokai-magenta)
        ("ribasushi" . ,monokai-magenta)))

(defun erc-get-color-for-nick (nick)
  "Gets a color for NICK. If NICK is in erc-nick-color-alist, use that color, else hash the nick and use a random color from the pool"
  (or (cdr (assoc nick erc-nick-color-alist))
      (nth
       (mod (string-to-number
	     (substring (md5 (downcase nick)) 0 6) 16)
	    (length erc-colors-list))
       erc-colors-list)))

(defun erc-put-color-on-nick ()
  "Modifies the color of nicks according to erc-get-color-for-nick"
  (save-excursion
    (goto-char (point-min))
    (if (looking-at "<\\([^>]*\\)>")
	(let ((nick (match-string 1)))
	  (put-text-property (match-beginning 1) (match-end 1) 'face
			     (cons 'foreground-color
				   (erc-get-color-for-nick nick)))))))

(add-hook 'erc-insert-modify-hook 'erc-put-color-on-nick)
erc-put-color-on-nick erc-controls-highlight erc-button-add-buttons erc-match-message erc-add-timestamp

logs

(setq erc-log-channels-directory (expand-file-name "~/var/lib/org/log"))

spelling

(global-set-key "\C-css" 'erc-spelling-mode)

pod mode

(autoload 'pod-mode "pod-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.pod$" . pod-mode))

nopaste

(add-to-list 'load-path (expand-file-name "~/src/nopaste"))
(dolist (var '(nopaste nopaste-region))
  (autoload var "nopaste" nil t))

(setq
 nopaste-nickname "edenc"
 nopaste-language "perl"
 nopaste-service "Gist"
 nopaste-args "-q")
(global-set-key (kbd "\C-cnp") 'nopaste)
(global-set-key (kbd "\C-cny") 'nopaste-yank-url)

ledger

;;(require 'ledger)
;;(add-to-list 'auto-mode-alist '("\\.ledger$" . ledger-mode))

time

(setq display-time-world-list
      '(("America/New_York" "New York")
        ("Europe/London" "London")
        ("Australia/Sydney" "Sydney")
        ("America/San_Francisco" "San Francisco")
        ("America/Sao_Paulo" "São Paulo")))
(global-set-key "\C-cw" 'display-time-world)
  

tramp

(require 'tramp)
(setq tramp-default-method "ssh")

(add-to-list 'tramp-default-proxies-alist
             '("\\(pgb1\\|pgt1\\|olap1\\)" nil "/ssh:dev.socialflow.com:"))

tt-mode

(autoload 'tt-mode "tt-mode")
(setq auto-mode-alist
  (append '(("\\.tt$" . tt-mode))  auto-mode-alist ))

uniquify

(require 'uniquify)

(setq uniquify-buffer-name-style 'forward)

vc

;; this basically disables vc.el completely.
;; it's not too useful, and, when started automatically, often gets in
;; the way of things by taking ages to initialize
(setq vc-handled-backends nil)

w3m

(require 'w3m)

(setq mm-text-html-renderer 'w3m)
(setq w3m-default-display-inline-images t)
(setq w3m-toggle-inline-images-permanently t)

diminish

(when (require 'diminish nil 'noerror)
  (eval-after-load "company"
      '(diminish 'company-mode "Cmp"))
  (eval-after-load "abbrev"
    '(diminish 'abbrev-mode "Ab"))
  (eval-after-load "yasnippet"
    '(diminish 'yas/minor-mode "Y")))

(add-hook 'emacs-lisp-mode-hook
  (lambda()
    (setq mode-name "el")))

haskell

(require 'haskell-mode)
(add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)
(add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)

taskjuggler

(require 'taskjuggler-mode)

winner mode

(require 'winner)
(setq winner-dont-bind-my-keys t) ;; default bindings conflict with org-mode

(global-set-key (kbd "<C-s-268632078>") 'winner-undo)
(global-set-key (kbd "<C-s-p>") 'winner-redo)
(winner-mode t) ;; turn on the global minor mode
(windmove-default-keybindings 'meta)
Something went wrong with that request. Please try again.