Sacha Chua


Starting from the next slide, you can press “play” once in the audio controls (or type “a”) to start the presentation, which advances automatically afterwards.

1. Overview

How we use Org Mode and TRAMP to organize and run a multi-track conference

1.1. Reasons for making this presentation

  • Revisit scrambled-together code and document things along the way

  • Show the process of thinking about a complex project and building it up

  • Point to more information

1.2. Map

2. Organizing information

  • E-mail: Notmuch + Emacs

  • Private conf.org

  • Public organizers' notebook

  • Public webpages

  • Mailing lists

  • Backstage area

  • Public media files

  • Configuration, etc.

Storing talk information as properties

2.1. Basic talk properties

* WAITING_FOR_PREREC EmacsConf.org: How we use Org Mode and TRAMP to organize and run a multi-track conference
SCHEDULED: <2023-12-03 Sun 14:55-15:15>
:CUSTOM_ID:  emacsconf
:SLUG:       emacsconf
:NAME:       Sacha Chua

2.2. Capturing a talk proposal from an e-mail


2.3. Parsing a submission from e-mail

(defun emacsconf-mail-parse-submission (body)
  "Extract data from EmacsConf submissions in BODY."
  (when (listp body) (setq body (plist-get (car body) :content)))
  (let* ((data (list :body body))
         (fields '((:title "^[* ]*Talk title")
                   (:description "^[* ]*Talk description")
                   (:format "^[* ]*Format")
                   (:intro "^[* ]*Introduction for you and your talk")
                   (:name "^[* ]*Speaker name")
                   (:availability "^[* ]*Speaker availability")
                   (:q-and-a "^[* ]*Preferred Q&A approach")
                   (:public "^[* ]*Public contact information")
                   (:private "^[* ]*Private emergency contact information")
                   (:release "^[* ]*Please include this speaker release")))
         (field-regexp (mapconcat
                        (lambda (o)
                          (concat "\\(?:" (cadr o) "\\)"))
                        fields "\\|")))
      (insert body)
      (goto-char (point-min))
      ;; Try to parse it
      (catch 'done
        (while (not (eobp))
          ;; skip the field title
          (unless (looking-at field-regexp)
            (unless (re-search-forward field-regexp nil t)
              (throw 'done nil)))
          (goto-char (match-beginning 0))
          (setq field (seq-find (lambda (o)
                                  (looking-at (cadr o)))
          (when field
            ;; get the text between this and the next field
            (re-search-forward "\\(:[ \t\n]+\\|\n\n\\)" nil t)
            (setq data
                   (car field)
                    (or (and
                         (re-search-forward field-regexp nil t)
                         (goto-char (match-beginning 0))
      (if (string-match "[0-9]+" (or (plist-get data :format) ""))
          (plist-put data :time (match-string 0 (or (plist-get data :format) ""))))

2.4. Setting the property to a region

(defun my-org-set-property (property value)
  "In the current entry, set PROPERTY to VALUE.
Use the region if active."
    (when (region-active-p)
       "[ \n\t]+" " "
       (buffer-substring (point) (mark))))))
  (org-set-property property value))

2.5. Setting properties

3. Calculating and then editing properties

3.1. Calculating and then editing properties

:FILE_PREFIX: emacsconf-year-slug--title--speakers

3.2. Setting properties that are unset

(defun emacsconf-set-file-prefixes ()
  "Set the FILE_PREFIX property for each talk entry that needs it."
   (lambda ()
      (point) "FILE_PREFIX"
      (emacsconf-file-prefix (emacsconf-get-talk-info-for-subtree))))

4. Renaming files