Skip to content

Latest commit

 

History

History
648 lines (506 loc) · 22.3 KB

emacs-org.org

File metadata and controls

648 lines (506 loc) · 22.3 KB

Emacs Org-Mode Settings

The Org Mode feature was a big reason in my recent re-kindling of my Emacs love affair. Make sure the latest packages are installed:

(packages-install '( org
                     org-plus-contrib
                     org-bullets
                     ox-reveal
                     org-journal
                     plantuml-mode
                   ))

Initial Settings

I really think that org-mode should be my default for most things, including regular text files:

(add-to-list 'auto-mode-alist '("\\.txt\\'" . org-mode))

Initialization of Org Mode by hooking it into YASnippets, which should allow me to easily add templates to my files.

(add-hook 'org-mode-hook 'turn-on-auto-fill)
(add-hook 'org-mode-hook
          '(lambda ()
             (yas-minor-mode-on)))

Journaling

Didn’t realize that org-journal essentially does what I have been doing by hand. With a little customization, I don’t have to change anything else:

(setq org-journal-dir "~/journal/")

(require 'org-journal nil t)

All my journal entries will be formatted using org-mode:

(add-to-list 'auto-mode-alist '(".*/[0-9]*$" . org-mode))

The date format is essentially, the top of the file.

(setq org-journal-date-format "#+TITLE: Journal Entry- %Y-%b-%d (%A)")

The time format is the heading for each section. I will set it to a blank since I really don’t care about the time I add a section.

(setq org-journal-time-format "")

A function to easily load today (and yesterday’s) journal entry.

(defun get-journal-file-today ()
  "Return filename for today's journal entry."
  (let ((daily-name (format-time-string "%Y%m%d")))
    (expand-file-name (concat org-journal-dir daily-name))))

(defun journal-file-today ()
  "Create and load a journal file based on today's date."
  (interactive)
  (find-file (get-journal-file-today)))

(global-set-key (kbd "C-c f j") 'journal-file-today)

Since I sometimes (not often) forget to create a journal entry, and need to re-write history.

(defun get-journal-file-yesterday ()
  "Return filename for yesterday's journal entry."
  (let ((daily-name (format-time-string "%Y%m%d" (time-subtract (current-time) (days-to-time 1)))))
    (expand-file-name (concat org-journal-dir daily-name))))

(defun journal-file-yesterday ()
  "Creates and load a file based on yesterday's date."
  (interactive)
  (find-file (get-journal-file-yesterday)))

(global-set-key (kbd "C-c f y") 'journal-file-yesterday)

Seems like I need to have the inserted template match the file’s name, not necessarily today’s date:

(defun journal-file-insert ()
  "Insert's the journal heading based on the file's name."
  (interactive)
  (when (string-match "\\(20[0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)" (buffer-name))
    (let ((year  (string-to-number (match-string 1 (buffer-name))))
          (month (string-to-number (match-string 2 (buffer-name))))
          (day   (string-to-number (match-string 3 (buffer-name))))
          (datim nil))
      (setq datim (encode-time 0 0 0 day month year))
      (insert (format-time-string org-journal-date-format datim))
      (insert "\n\n"))))  ; Start with a blank separating line

Nice to automatically insert this header if the journal entry file is empty…yeah, we’re talking auto-insert:

(add-to-list 'auto-insert-alist '(".*/[0-9]*$" . journal-file-insert))

I really would really like to read what I did last year “at this time”, and by that, I mean, 365 days ago, plus or minus a few to get to the same day of the week.

(defun journal-last-year-file ()
  "Returns the string corresponding to the journal entry that
happened 'last year' at this same time (meaning on the same day
of the week)."
(let* ((last-year-seconds (- (float-time) (* 365 24 60 60)))
       (last-year (seconds-to-time last-year-seconds))
       (last-year-dow (nth 6 (decode-time last-year)))
       (this-year-dow (nth 6 (decode-time)))
       (difference (if (> this-year-dow last-year-dow)
                       (- this-year-dow last-year-dow)
                     (- last-year-dow this-year-dow)))
       (target-date-seconds (+ last-year-seconds (* difference 24 60 60)))
       (target-date (seconds-to-time target-date-seconds)))
  (format-time-string "%Y%m%d" target-date)))

(defun journal-last-year ()
  "Loads last year's journal entry, which is not necessary the
same day of the month, but will be the same day of the week."
  (interactive)
  (let ((journal-file (concat org-journal-dir (journal-last-year-file))))
    (find-file journal-file)))

  (global-set-key (kbd "C-c f L") 'journal-last-year)

Taking Meeting Notes

I’ve notice that while I really like taking notes in a meeting, I don’t always like the multiple windows I have opened, so I created this function that I can easily call to eliminate distractions during a meeting.

(defun meeting-notes ()
  "Call this after creating an org-mode heading for where the notes for the meeting
should be. After calling this function, call 'meeting-done' to reset the environment."
  (interactive)
  (outline-mark-subtree)                              ;; Select org-mode section
  (narrow-to-region (region-beginning) (region-end))  ;; Only show that region
  (deactivate-mark)
  (delete-other-windows)                              ;; Get rid of other windows
  (text-scale-set 2)                                  ;; Text is now readable by others
  (fringe-mode 0)
  (when (require 'olivetti nil t)
     (olivetti-mode 1)
     (olivetti-set-width 110)
     (olivetti-toggle-hide-modeline))
  (message "When finished taking your notes, run meeting-done."))

Of course, I need an ‘undo’ feature when the meeting is over…

(defun meeting-done ()
  "Attempt to 'undo' the effects of taking meeting notes."
  (interactive)
  (widen)                                       ;; Opposite of narrow-to-region
  (text-scale-set 0)                            ;; Reset the font size increase
  (fringe-mode 1)
  (when (require 'olivetti nil t)
      (olivetti-toggle-hide-modeline)
      (olivetti-mode 0))
  (winner-undo))                                ;; Put the windows back in place

Org-Mode Colors

Before we load org-mode proper, we need to set the following syntax high-lighting parameters. These are used to help bring out the source code during literate programming mode.

This information came from these instructions, however, they tend to conflict with the color-theme, so we’ll turn them off for now.

(defface org-block-begin-line
  '((t (:underline "#A7A6AA" :foreground "#008ED1" :background "#EAEAFF")))
  "Face used for the line delimiting the begin of source blocks.")

(defface org-block-background
  '((t (:background "#FFFFEA")))
  "Face used for the source block background.")

(defface org-block-end-line
  '((t (:overline "#A7A6AA" :foreground "#008ED1" :background "#EAEAFF")))
  "Face used for the line delimiting the end of source blocks.")

Library Loading

The standard package manager (and most recent versions of Emacs) include org-mode, however, I want the latest version that has specific features for literate programming.

Org-mode is installed in the global directory.

(require 'org)
(require 'ob-tangle)

Global Key Bindings

The org-mode has some useful keybindings that are helpful no matter what mode you are using currently.

(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c b") 'org-iswitchb)

(global-set-key (kbd "C-M-|") 'indent-rigidly)

Local Key Bindings

The following keybind ideas came from Emacs24 Starter Kit.

(add-hook 'org-mode-hook
          (lambda ()
            (local-set-key "\M-\C-n" 'outline-next-visible-heading)
            (local-set-key "\M-\C-p" 'outline-previous-visible-heading)
            (local-set-key "\M-\C-u" 'outline-up-heading)
            ;; table
            (local-set-key "\M-\C-w" 'org-table-copy-region)
            (local-set-key "\M-\C-y" 'org-table-paste-rectangle)
            (local-set-key "\M-\C-l" 'org-table-sort-lines)
            ;; display images
            (local-set-key "\M-I" 'org-toggle-iimage-in-org)))

A couple of short-cut keys to make it easier to edit text.

(defun org-text-bold () "Wraps the region with asterisks."
  (interactive)
  (surround-text "*"))
(defun org-text-italics () "Wraps the region with slashes."
  (interactive)
  (surround-text "/"))
(defun org-text-code () "Wraps the region with equal signs."
  (interactive)
  (surround-text "="))

Now we can associate some keystrokes to the org-mode:

(add-hook 'org-mode-hook
      (lambda ()
        (local-set-key (kbd "A-b") 'org-text-bold)
        (local-set-key (kbd "s-b") 'org-text-bold)    ;; For Linux
        (local-set-key (kbd "A-i") 'org-text-italics)
        (local-set-key (kbd "s-i") 'org-text-italics)
        (local-set-key (kbd "A-=") 'org-text-code)
        (local-set-key (kbd "s-=") 'org-text-code)))

Speed Keys

If point is at the beginning of a headline or code block in org-mode, single keys do fun things. See org-speed-command-help for details (or hit the ? key at a headline).

(setq org-use-speed-commands t)

Specify the Org Directories

I keep all my org-mode files in a few directories, and I would like them automatically searched when I generate agendas.

(setq org-agenda-files '("~/Dropbox/org/personal"
                         "~/Dropbox/org/technical"
                         "~/Dropbox/org/project"))

Auto Note Capturing

Let’s say you were in the middle of something, but would like to take a quick note, but without affecting the file you are working on. This is called a “capture”, and is bound to the following key:

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

This will bring up a list of note capturing templates. I actually override this in my system-specific “local” configuration file.

(defun ha/first-header ()
    (goto-char (point-min))
    (search-forward-regexp "^\* ")
    (beginning-of-line 1)
    (point))

;; General notes go into this file:
(setq org-default-notes-file "~/personal/@SUMMARY.org")
(setq org-default-tasks-file "~/personal/tasks.org")

(setq org-capture-templates
      '(("n" "Thought or Note"  entry
         (file org-default-notes-file)
         "* %?\n\n  %i\n\n  See: %a" :empty-lines 1)
        ("j" "Journal Note"     entry
         (file (get-journal-file-today))
         "* %?\n\n  %i\n\n  From: %a" :empty-lines 1)
        ("t" "Task Entry"        entry
         (file+function org-default-tasks-file ha/first-header)
         "* %?\n\n  %i\n\n  From: %a" :empty-lines 1)
        ("w" "Website Announcement" entry
         (file+function "~/website/index.org" ha/first-header)
         "* %?
  :PROPERTIES:
  :PUBDATE: %t
  :END:
  #+HTML: <div class=\"date\">%<%e %b %Y></div>

  %i

  [[%F][Read more...]" :empty-lines 1)))

After you have selected the template, you type in your note and hit C-c C-c to store it in the file listed above.

Just remember, at some point to hit C-c C-w to refile that note in the appropriate place.

Org and Trello

Using org-trello to sync particular org-mode files with trello.com

(defun ha/org-trello-sync ()
  (interactive)
  (when (require 'org-trello nil t)
    (org-trello-mode 1)
    (org-trello/sync-buffer t)))

(global-set-key (kbd "S-<f1>") 'ha/org-trello-sync)

Export Settings

Seems some change now requires a direct load of HTML:

(require 'ox-html)

To make the org-mode export defaults closer to my liking (without having to put specific #+PROPERTY commands), I get rid of the postamble, and then configure the default fonts.

(setq org-html-postamble nil)
(setq org-export-with-section-numbers nil)
(setq org-export-with-toc nil)

(setq org-html-head-extra "
   <link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
   <link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:400,700' rel='stylesheet' type='text/css'>
   <style type='text/css'>
      body {
         font-family: 'Source Sans Pro', sans-serif;
      }
      pre, code {
         font-family: 'Source Code Pro', monospace;
      }
   </style>")

Narrowing and Widening

After reading this article, I decided to expand how I narrow/widen buffer sections in org-mode. This is specific to org-mode, as I often like to see the surrounding code using fancy-narrow as explained in my Expand Region section.

(defun org-narrow-or-widen-dwim (p)
  "If the buffer is narrowed, it widens. Otherwise, it narrows intelligently.
Intelligently means: region, org-src-block, org-subtree, or defun,
whichever applies first.
Narrowing to org-src-block actually calls `org-edit-src-code'.

With prefix P, don't widen, just narrow even if buffer is already
narrowed."
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
        ((region-active-p)
         (narrow-to-region (region-beginning) (region-end)))
        ((derived-mode-p 'org-mode)
         (cond ((ignore-errors (org-edit-src-code))
                (delete-other-windows))
               ((org-at-block-p)
                (org-narrow-to-block))
               (t (org-narrow-to-subtree))))
        (t (narrow-to-defun))))

(global-set-key (kbd "C-x n o") 'org-narrow-or-widen-dwim)

According to the narrow-widen article, we can have C-x C-s get out of editing org-mode source code blocks:

(eval-after-load 'org-src
  '(define-key org-src-mode-map
     "\C-x\C-s" #'org-edit-src-exit))

Presentations

I alternated between the browser-based presentation tool, reveal.js and staying in Emacs with org-tree-slide.

Reveal

Generate presentations from my org-mode files using org-reveal. Just download and make the results available to the HTML output:

(when (require 'ox-reveal nil t)
  (setq org-reveal-root (concat "file://" (getenv "HOME") "/Public/js/reveal.js"))
  (setq org-reveal-postamble "Howard Abrams"))

Tree Slide

A quick way to display an org-mode file is using org-tree-slide. The only downside is the default key-binding for moving to the next section is C-> … hardly easy to find during a presentation.

  • org-tree-slide-move-next-tree (C->)
  • org-tree-slide-move-previous-tree (C-<)
  • org-tree-slide-content (C-x s c)

Perhaps we can create a function that sets everything at once:

(deftheme ha/org-tree-slide-theme "Sub-theme to hide org code blocks")

(defun ha/present-it ()
  (interactive)
  (when (require 'demo-it nil t)
    (demo-it-presentation (buffer-file-name))
    (org-tree-slide-simple-profile)
    (define-key org-mode-map (kbd "<f1>") 'org-tree-slide-move-next-tree)
    (define-key org-mode-map (kbd "S-<f1>") 'org-tree-slide-move-previous-tree))

   (when (require 'olivetti nil t)
      (olivetti-mode 1)
      (olivetti-set-width 110))

   (setq ha/present-it-restoration '(
      (face-foreground 'org-block-begin-line nil 'default)
   ))

  (let ((fgc (face-background 'org-block-begin-line nil 'default)))
    (setq-default line-spacing 12)
    (custom-theme-set-faces 'ha/org-tree-slide-theme
                            `(org-block-begin-line ((t (:foreground ,fgc :height 0.5 :line-height 1 :invisible t))))
                            `(org-block-end-line   ((t (:foreground ,fgc :height 0.2 :line-height 1 :invisible t))))))
  (fringe-mode '(0 . 0)))

And we need an “undo” for this weird presentation:

(defun ha/present-stop ()
  (interactive)
  (demo-it-end)
  (setq-default line-spacing 2)
   (when (require 'olivetti nil t)
      (olivetti-mode nil))
  (let ((fgc (car ha/present-it-restoration)))
    (custom-theme-set-faces 'ha/org-tree-slide-theme
                            `(org-block-begin-line ((t (:foreground ,fgc :height 1.0 :line-height 1.0 :invisible nil))))
                            `(org-block-end-line   ((t (:foreground ,fgc :height 1.0 :line-height 1.0 :invisible nil))))))
  (olivetti-mode 0))

Displaying the headers using various bullets are nice for my presentations.

(when (require 'org-bullets nil t)
      (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

Here is my approach for quickly making the initial asterisks for listing items and whatnot, appear as Unicode bullets (without actually affecting the text file or the behavior).

(font-lock-add-keywords 'org-mode
   '(("^ +\\([-*]\\) "
          (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) ""))))))

MobileOrg

I use Dropbox with MobileOrg in order to read my notes on my iPad.

The “global” location of my Org files on my local system:

(setq org-directory "~/Dropbox/org/personal")

Set the name of the file where new notes will be stored

(setq org-mobile-inbox-for-pull "~/Dropbox/org/flagged.org")

Set to <your Dropbox root directory>/MobileOrg.

(setq org-mobile-directory "~/Dropbox/Apps/MobileOrg")

To get this going, we just need to: M-x org-mobile-push

The Tower of Babel

The trick to literate programming is in the Babel project, which allows org-mode to not only interpret source code blocks, but evaluate them and tangle them out to a file.

(org-babel-do-load-languages
 'org-babel-load-languages
 '((sh         . t)
   (js         . t)
   (emacs-lisp . t)
   (perl       . t)
   (scala      . t)
   (clojure    . t)
   (python     . t)
   (ruby       . t)
   (dot        . t)
   (css        . t)
   (plantuml   . t)))

Make the code pretty:

(setq org-src-fontify-natively t)

I want CoffeeScript to be supported in org-mode, but I need to do it myself at the moment.

(when (locate-library "ob-coffee")
    (require 'ob-coffee))

It seems to automatically recognize the language used in a source block, but if not, call org-babel-lob-ingest to add all the languages from the code block into the list that Babel supports. Keystroke: C-c C-v i.

Just Evaluate It

I’m normally fine with having my code automatically evaluated.

(setq org-confirm-babel-evaluate nil)

Font Coloring in Code Blocks

; (setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)

(define-key personal-global-map (kbd "S-f") 'org-src-fontify-buffer)
(define-key personal-global-map (kbd "f") 'org-src-fontify-block)

Normally, fontifying the individual code blocks makes it impossible to work with, so instead of turning it on at the global level for all blocks, I created a couple of keystrokes to selectively colorize one block at a time.

Technical Artifacts

Need to provide the init-org-mode so that I can require this package.

(provide 'init-org-mode)

Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: C-c C-c