All Articles

How I Org

Overview

Org-mode is the reason that emacs won out over vim (though I do dabble in evil-mode) for me when it comes to IDEs.

In 2019 during my first batch at the Recurse Center, I peeked over Shapr’s shoulder while he was deep in coding, and was like, “WHAT’S THAT??” I used Sublime Text 2 as my IDE at the time, but the moment I saw org mode, I dropped everything to learn emacs and I haven’t looked back since. Why was it such a gamechanger? For me, it make it unbelievably easy to context switch and keep good notes. I previously kept a running daily log in markdown, but that was fairly unstructured outside a list of daily bullet points. I rely on my org file to keep my brag sheet up to date, track time and effort on tasks.

If your manager at any point questions your sprint velocity, you can use org-mode to build a report of your unticketed “glue” work time. When I say I use it for everything, I mean everything. Every ticket with a task list, writing all those tickets with task lists, every MR review with comments, every meeting with meeting notes (also a good way to keep track of your meeting to focus-time ratio), even literal programming via code snippets, and slideshow presentations. All of these things can be captured and done in org-mode.

Like many emacs users, my personal config is cobbled together from others (I can name at least Sasha Chua, Shapr, and Ryan Prior as major influences).

My startup configuration within each .org file isn’t that fancy:

* org-mode configuration
#+STARTUP: overview
#+STARTUP: hidestars
#+STARTUP: logdone
#+PROPERTY: Effort_ALL 0:10 0:20 0:30 1:00 2:00 4:00 6:00 8:00
#+COLUMNS: %38ITEM(Details) %TAGS(Context) %7TODO(To Do) %5Effort(Time){:} %6CLOCKSUM{Total}
#+TAGS: { WORK(w) HOME(h) } SCHOOL(s) LEARN(l) FUN(f) PROFESSIONAL_DEVELOPMENT(p) GOALS(g) CODESCREEN(c) ARCHITECTURE(a) CONVERSATION(n) BEHAVIORAL(b) NEGOTIATION(n) ONSITE(o) JOBHUNT(j)
#+SEQ_TODO: TODO(t) STARTED(s) WAITING(w) APPT(a) PROBLEM(p) | DONE(d) CANCELLED(c) DEFERRED(f) SOLVED(l)

One feature I particularly like about tags is their nested behavior (a child heading will inherit its parent’s tags). I have a number of custom tags, as I used them to track effort and time spent on my last job hunt and make some nifty data visualizations. I also have some custom SEQ_TODO for a similar reason.

I use Doom emacs now, with the following org packages in my packages.el file.

(package! org-cliplink)
(package! org-download)
(package! org-modern)
(package! org-mime)
(package! org-pomodoro)
(package! org-present)
(package! org-projectile)
(package! org-ql)
(package! org-rich-yank)

Most of these are helper functions to allow things like drag and drop into org files, but a particular favorite is the org-modern package for getting really nice styling.

I also use some other variable customizations in config.el for styling my org files:

(setq org-modern-star '("◉" "○" "◈" "◇" "*"))

(setq
 ;; Edit settings
 org-auto-align-tags nil
 org-tags-column 0
 org-catch-invisible-edits 'show-and-error
 org-special-ctrl-a/e t
 org-insert-heading-respect-content t

 ;; Org styling, hide markup etc.
 org-hide-emphasis-markers t
 org-pretty-entities t
 org-ellipsis "…"

 ;; Agenda styling
 org-agenda-tags-column 0
 org-agenda-block-separator ?─
 org-agenda-time-grid
 '((daily today require-timed)
   (800 1000 1200 1400 1600 1800 2000)
   " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
 org-agenda-current-time-string
 "⭠ now ─────────────────────────────────────────────────")

;; Global
(global-org-modern-mode)

Here are examples of some of my most often used features:

Org Agenda

Org-Agenda Day Example
Org-Agenda Day Example

Source Block - Python

Thanks to org-babel, there is support for literate programming within emacs in many programming languages. So far, I’ve tried out Python, Javascript, Ruby, Rust, and SQL. The SQL snippets are something I use quite often with work, as it’s a good way to keep track of query responses on different days by keeping them in notes with a date tag assigned.

*** Python
#+begin_src python :results output
from collections import defaultdict
class Graph:

    def __init__(self):
        self.nodes = defaultdict(list)

    def add_edge(self, u, v):
        self.nodes[u].append(v)

    def DFSrecursion(self, v, visited):

        visited.add(v)
        print(v, end=" ")
        for neighbor in self.nodes[v]:
            if neighbor not in visited:
                self.DFSrecursion(neighbor, visited)

    def DFS(self, v):
        visited = set()

        self.DFSrecursion(v, visited)

    def print_graph(self):
        print(self.nodes)

def make_graph():
    g = Graph()

    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 2)
    g.add_edge(2, 0)
    g.add_edge(2, 3)
    g.add_edge(3, 3)

    print("DFS starting at Node 1")

    g.DFS(1)
    return
make_graph()

#+end_src

#+RESULTS:
: DFS starting at Node 1
: 1 2 0 3

Source Block - SQL

** Business Logic Applies to Use Cases
#+begin_src sql :engine postgresql :dbhost localhost :dbport 5434
select album.title as album,
       sum(milliseconds) * interval '1 ms' as duration
from album
join artist using(artist_id)
left join track using (album_id)
where artist.name = 'Red Hot Chili Peppers'
group by album
order by album;
#+end_src

#+RESULTS:
| album                 |     duration |
|-----------------------+--------------|
| Blood Sugar Sex Magik | 01:13:57.073 |
| By The Way            | 01:08:49.951 |
| Californication       | 00:56:25.461 |

Clock Tables

Config:

#+BEGIN: clocktable :scope subtree :maxlevel 6 :tags t :match "CONVERSATION|ONSITE|CODESCREEN|BEHAVIORAL|ARCHITECTURE|NEGOTIATION" :timestamp "SCHEDULED"

Output:

| Timestamp                     | Tags                                                    | Headline                                         | Time     |          |       |      |      |
|-------------------------------+---------------------------------------------------------+--------------------------------------------------+----------+----------+-------+------+------|
|                               |                                                         | *Total time*                                     | *1d 21:00*
|-------------------------------+---------------------------------------------------------+--------------------------------------------------+----------+----------+-------+------+------|
|                               | PROFESSIONAL_DEVELOPMENT, JOBHUNT                       | \_  Job Applications 2022                        |          | 1d 21:00 |       |      |      |
| <2022-05-19 Thu 11:00-12:30>  | PROFESSIONAL_DEVELOPMENT, JOBHUNT, ONSITE, ARCHITECTURE | \_        Technical Presentation                 |          |          |       |      | 1:30 |
| <2022-05-19 Thu 12:30-14:00>  | PROFESSIONAL_DEVELOPMENT, JOBHUNT, ONSITE, CODESCREEN   | \_        Work along                             |          |          |       |      | 1:30 |
| <2022-05-20 Fri 17:00-17:30>  | PROFESSIONAL_DEVELOPMENT, JOBHUNT, NEGOTIATION          | \_      Offer phone call                         |          |          |       | 0:30 |      |
| <2022-06-02 Thu 14:30-15:00>  | PROFESSIONAL_DEVELOPMENT, JOBHUNT, NEGOTIATION          | \_      Offer clarification meeting              |          |          |       | 0:30 |      |

I’ve only recently investigated using org-roam for furthering my personal knowledge management system, and I’m eager to incorporate it into my workflow!

ETA

This blog post was a hit among Recursers, so I’m including some of the resources other org-mode enthusiasts pointed me towards:

Published Jan 14, 2024

Striving to stay curious.