Skip to content

Instantly share code, notes, and snippets.

@volhovm
Last active January 20, 2021 22:29
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save volhovm/36aaee84ff709160980de91f36351329 to your computer and use it in GitHub Desktop.
Save volhovm/36aaee84ff709160980de91f36351329 to your computer and use it in GitHub Desktop.

So the basic thing you need to start working with org-mode is to install org-mode. Emacs > 24.??? already have it bundled and if you're not going to use some cool features like org-drill and stuff, that should be enough.

Basically, org-mode operates with org files. Create one (work.org for example). Org files' markup is simple -- there are headers with info. Header format is '*'{1..} TODO-kw Description. To create entry just write it. Also C-c RET does something similar (I never use it tho). So, stars are indentation -- more indented headers are 'contained' inside less indented. Philosophically, you can think that leaves are tasks, while nodes are categories. File is rose tree. Dunno. You can expand or shrink the header with TAB.

Todo-keywords are 'status'es of task. I'm using simple setup that i find rather convenient. Add to your ~/.emacs:

(setq org-todo-keywords '((type "TODO" "STARTED" "WAITING" "|" "DONE" "CANCELED")))

That adds default todo-keywords. You can also specify per-file keywords with file headers (should be placed on the top of file). Here are my work.org headers:

#+TODO: TODO STARTED WAITING | DONE CANCELED
#+TODO: BUG PROGRESS UNTESTED | FIXED DROPPED
#+TITLE: Work stuff

Work file is the only place i add another todo-list with bug-related stuff, but I don't use the second one frequently. Also in study-related files tasks are 'topic's, they have some text inside and task's status defines my knowledge of that topic, so i also have #+TODO: X 0 1 2 | OK header in those. You can see analogy now.

Add some custom hightlighting for those task statuses:

(setq org-todo-keyword-faces
 '(("TODO" . "red")
   ("STARTED" . "yellow")
   ("WAITING" . "purple")
   ("CANCELED" . (:foreground "blue" :weight bold))
   ("DONE" . "green")
   ("BUG" . "red")
   ("PROGRESS" . "yellow")
   ("UNTESTED" . "purple")
   ("DROPPED" . (:foreground "blue" :weight bold))
   ("FIXED" . "green")))

So you now should have some primitive understanding of how to write org file. Create some tasks now. I believe that the best structure of file you can invent is your optimal, but i'll share my though.

Top headers: Clocking, Serokell, OtherCompanyName. Serokell is divided into: Meta task (for speaking in chat, reading logs, issue making), global category (everything that doesn't relate to projects, like the task to create this manual), rscoin, bitgram, ghost. That's all.

Changing task status is S-<arrow left>, S-<arrow right>, but also Num C-c C-t is available (DONE keyword is 4th, so 4 C-c C-t would set DONE status).

You can also use M-S-<arrow up> and M-S-<arrow down> to move task up or down in it's level (I usually arrange tasks in the way that done/canceled are on the bottom while todo/started are on the top).

Ok, what's the point? We now have tasks, but what can you do with them? First of all, let's have a look at agenda. First, press C-c [ in work file to add it to agenda files. M-x org-agenda opens agenda window and then you can press a to view all your tasks. But there's no tasks, because it's agenda, so it's supposed to show scheduled tasks. Easy -- C-c C-s while your cursor is on tasks opens calendar to choose schedule date, C-c C-d is the same for deadline.

The task with schedules and deadlines will look like this:

*** TODO Youtrack tutorial
DEADLINE: <2016-04-17 Sun> SCHEDULED: <2016-04-16 Sat>
https://www.jetbrains.com/youtrack/documentation/

Dates can be altered with S-<arrow up, down, left, right>. You'll get how it works.

OFC you shouldn't call agenda every time with M-x. Here are bindings (I use only the first one, but the second is popular).

(global-set-key (kbd "<f12>") 'org-agenda)
(global-set-key "\C-ca" 'org-agenda)

Now scheduled tasks will show up in agenda, so <f-12> a would show what you should do today, what are deadlines, etc. If you're using evil, you might find helpful:

(add-hook 'org-agenda-mode-hook 'my-org-agenda-mode-hook)
(defun my-org-agenda-mode-hook ()
  "Enables hjkl-bindings for agenda-mode."
  (define-key org-agenda-mode-map "j" 'org-agenda-next-line)
  (define-key org-agenda-mode-map "k" 'org-agenda-previous-line)
  (define-key org-agenda-mode-map "l" 'evil-forward-char)
  (define-key org-agenda-mode-map "h" 'evil-backward-char))

Agenda is much more than that! There are repeated tasks, habits, estimates, tags, ....

Ok, so now we have tasks which we're aware of because of agenda. Clocking! Tasks can be clocked in and out. Clock in creates a record in tas's subtree, clock out closes a record. Simple. Here's a bunch of settings (don't be afraid...):

; sets some hooks for clock persistence over emacs restart
(org-clock-persistence-insinuate)
; dunno what's that
(setq org-clock-in-resume t)
; moves TODO to STARTED when clocked in
(setq org-clock-in-switch-to-state 'bh/clock-in-to-next)
; Sets drawers
(setq org-drawers (quote ("PROPERTIES" "LOGBOOK")))
; Clock entries are stored in drawer (lots of clock lines fit into
; drawer, it's expanded by tab)
(setq org-clock-into-drawer t)
; Do not show up scheduled or deadline tasks if they're done.
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-deadline-if-done t)
; If you clock out task and it's 0 time, the record is not stored.
(setq org-clock-out-remove-zero-time-clocks t)
; Adds DONE record to the task when it's done.
(setq org-log-done t)
; Clocks task out when done
(setq org-clock-out-when-done t)
; Some persistance settings
(setq org-clock-persist-query-resume nil)
(setq org-clock-auto-clock-resolution (quote when-no-clock-is-running))
; Clocking tasks are in clock report
(setq org-clock-report-include-clocking-task t)

; functions for clock-in-to-next
(defun bh/is-project-p ()
  "Any task with a todo keyword subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t)))
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (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))))
      (and is-a-task has-subtask))))

(defun bh/is-task-p ()
  "Any task with a todo keyword and no subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t))) (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) (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))))
      (and is-a-task (not has-subtask)))))

(defun bh/clock-in-to-next (kw)
  "Switch a task from TODO to STARTED when clocking in.
Skips capture tasks, projects, and subprojects.
Switch projects and subprojects from STARTED back to TODO"
  (when (not (and (boundp 'org-capture-mode) org-capture-mode))
    (cond
     ((and (member (org-get-todo-state) (list "TODO"))
           (bh/is-task-p))
      "STARTED")
     ((and (member (org-get-todo-state) (list "STARTED"))
           (bh/is-project-p))
      "TODO"))))

Eeeemm, so here it is. It's not necessary to adopt all settings of course. Press C-c C-x C-i to clock in, C-c C-x C-o to clock out. You can just clock in another task, previous one will clock out automatically. If you forgot to clock task out and already doing some other thing, M-x org-resolve-clocks might be helpful. Pressing K and then choosing the number of minutes to save is the thing.

I have org-resolve-clocks added to startup hook:

(add-hook 'org-mode-hook 'my-org-mode-hook)
(defun my-org-mode-hook ()
  "Hook for org mode."
  (local-set-key (kbd "C-c C-x C-k") 'org-resolve-clocks))

Now clock-reports! That's the thing i have my first top-level header in work.org for. It contains just this thing:

#+BEGIN: clocktable :maxlevel 5 :scope file :block week tcolumns 3
#+END:

Pressing C-c C-c on it would create a clock report. Also C-c C-o C-r generates this stuff. More on clock reports here: http://orgmode.org/manual/The-clock-table.html

There's also one thing to say about clock report styles. By default report is indented with \emsp which is not really nice. But this link points out the solution: StackExchange

Personally i solve it in this way:

(defun my-org-clocktable-indent-string (level)
 (if (= level 1)
     ""
   (let ((str "*"))
     (while (> level 2)
       (setq level (1- level)
             str (concat str "  ")))
     (concat str " "))))

(advice-add 'org-clocktable-indent-string :override #'my-org-clocktable-indent-string)

That's all I guess. Org has lots of features, I can't just cover them all quickly. Read org manual, google more, ask me.

Peace.

@gromakovsky
Copy link

Good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment