Modern Org Style

Next:   [Contents]

Modern Org Style

Table of Contents


1 Introduction

This package implements a modern style for your Org buffers using font locking and text properties. The package styles headlines, keywords, tables and source blocks. The styling is configurable, you can disable or modify the style of each syntax element individually via the ‘org-modern’ customization group.

https://github.com/minad/org-modern/blob/screenshots/example.gif?raw=true

The screenshots shows example.org with ‘org-modern-mode’ turned on and off. The elegant theme featured in the screenshot is modus-operandi.

Since this package adjusts text styling, it depends on your font settings. You should ensure that your ‘variable-pitch’ and ‘fixed-pitch’ fonts combine harmonically and have approximately the same height. As default font, I recommend variants of the Iosevka font, e.g., Iosevka Term Curly. ‘org-modern-mode’ tries to adjust the tag label display based on the value of ‘line-spacing’. This looks best if ‘line-spacing’ has a value between 0.1 and 0.4 in the Org buffer. Larger values of ‘line-spacing’ are not recommended, since Emacs does not center the text vertically (see Emacs bug#76390).


2 Configuration

The package is available on GNU ELPA and MELPA. You can install the package with ‘package-install’. Then ‘org-modern’ can be enabled manually in an Org buffer by invoking ‘M-x org-modern-mode’. In order to enable ‘org-modern’ for all your Org buffers, add ‘org-modern-mode’ to the Org mode hooks.

;; Option 1: Per buffer
(add-hook 'org-mode-hook #'org-modern-mode)
(add-hook 'org-agenda-finalize-hook #'org-modern-agenda)

;; Option 2: Globally
(with-eval-after-load 'org (global-org-modern-mode))

Try the following more extensive setup in ‘emacs -Q’ to reproduce the looks of the screenshot above after the installation of ‘org-modern’.

;; Minimal UI
(package-initialize)
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(modus-themes-load-operandi)

;; Choose some fonts
;; (set-face-attribute 'default nil :family "Iosevka")
;; (set-face-attribute 'variable-pitch nil :family "Iosevka Aile")
;; (set-face-attribute 'org-modern-symbol nil :family "Iosevka")

;; Add frame borders and window dividers
(modify-all-frames-parameters
 '((right-divider-width . 40)
   (internal-border-width . 40)))
(dolist (face '(window-divider
                window-divider-first-pixel
                window-divider-last-pixel))
  (face-spec-reset-face face)
  (set-face-foreground face (face-attribute 'default :background)))
(set-face-background 'fringe (face-attribute 'default :background))

(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-agenda-tags-column 0
 org-ellipsis "…")

(global-org-modern-mode)

An alternative setup, using use-package and modifying some of the display entities:

(use-package org-modern
  :custom
  (org-modern-block-indent t)  ; to enable org-modern-indent when org-indent is active
  (org-modern-hide-stars nil)
  (org-modern-todo-faces
   '(("STARTED" :foreground "yellow")
     ("CANCELED" org-special-keyword :inverse-video t :weight bold)))
  (org-modern-list
   '((?* . "•")
     (?+ . "‣")))
  (org-modern-fold-stars
   '(("▶" . "▼")
     ("▷" . "▽")
     ("▸" . "▾")
     ("▹" . "▿")))
  (org-modern-checkbox
   '((?X . "✔")
     (?- . "┅")
     (?\s . " ")))
  (org-modern-label-border 1)
  :hook
  (org-mode . org-modern-mode)
  (org-agenda-finalize . org-modern-agenda))

3 Block indentation

Since version 2.0, this package also incorporates org-modern-indent, which provides block bracket styling when org-indent-mode is enabled, including support for "bulk-indented" blocks nested within plain lists:

org-modern-indent is disabled by org-modern by default. Configure org-modern-block-indent=t to enable. To activate org-indent-mode in all org files, set org-startup-indented=t.

Note: Currently ‘org-modern-indent’ requires zero line-spacing, as it leads to gaps in the vertical bars drawn to indicate blocks, but hopefully this can be improved in the future.


3.1 Bulk-indented blocks (e.g. within plain lists):

Bulk-indented blocks have "real" (space/tab) indentation applied and managed by org. This extra indentation is applied by org on top of the (fake, prefix-based) indentation used by org-indent. To nest blocks properly within such indented content, e.g. in plain list items, you only have to begin the #+begin at the same level as the list element’s text.

As an important principle, org-modern-indent does not alter the contents of the text in your org documents, not even indentation. It just styles what is there. To help achieve proper block bulk-indented alignment, here are a few ways to alter blocks indentation using org and other commands:

  • Start things right: Hit return after your last line of text (e.g in a list item), then immediately hit ‘C-c C,’ to create the desired block. It will be indented at the right level:
    - This list item contains a:
      - sublist, which holds a block:
        [C-c C-,] here
    
  • Move flush left: Note: ‘M-{’ will get you to the start of a block quickly. ‘M-\’ at block start will move the block’s first header line to column 0. Then ‘M-S-left’ (or ‘right’) will indent the full block.
  • Indent rigidly: ‘M-h’ selects the entire block. Then ‘C-x TAB’ enters "rigid indent" mode, after which left/right moves the entire block.
  • Re-indent a block: If you have a block that is partially aligned, perhaps with a "hanging end", like so:
    
    - List 1
        - List 2
          #+begin_src lang
             foo_lang(x)
          #+end_src
    

    you can simply use ‘M-S-left/right’ at block start (or in fact anywhere on the block header/footer) to org-indent-block. Note that org-src-preserve-indentation=nil is an important setting, to allow org to (re-)indent blocks to respect the local indentation inside list and other elements. Also note that (from org-indent-region):

    The function will not indent contents of example blocks, verse blocks and export blocks as leading white spaces are assumed to be significant there.


3.2 Font spacing and faces

The default fixed-pitch font (from which org-meta-line inherits) has line spacing >1.0 on some systems. This will introduce gaps even if your default font is changed, and line-space is nil. To correct it, add:

(set-face-attribute 'fixed-pitch nil :family "Hack" :height 1.0) ; or whatever font family

3.2.1 The bracket style

If you’d like a different face than org-meta-line for the "bracket", configure the org-modern-indent-bracket-line face.


4 Incompatibilities


5 Alternatives

The tag style of ‘org-modern’ is inspired by Nicholas Rougier’s svg-tag-mode. In contrast to ‘svg-tag-mode’, the package ‘org-modern’ avoids images and uses more efficient Emacs box text properties. By only styling the text via text properties, the styled text, e.g., dates or tags stay editable and are easy to interact with.

The approach used here restricts the flexibility (e.g., no rounded corners) and creates dependence on the size and alignment of the font. Combining ‘org-modern-mode’ with ‘svg-tag-mode’ is possible. You can use SVG tags and use the table and block styling from ‘org-modern’. If you are interested in further tweaks, Emacs comes with the builtin ‘prettify-symbols-mode’ which can be used for individual styling of custom keywords.

Alternatives are the older org-superstar and org-bullets packages, which are more limited and mainly adjust headlines and lists. ‘org-superstar’ relies on character composition, while ‘org-modern’ uses text properties, which are considered more future-proof. Note that ‘org-modern’ is a full replacement for both ‘org-superstar’ and ‘org-bullets’. You can disable styling of certain elements, e.g., ‘org-modern-timestamp’, if you only want to use the subset of ‘org-modern’ equivalent to ‘org-superstar’.


Previous: , Up: Modern Org Style   [Contents]

6 Contributions

Since this package is part of GNU ELPA contributions require a copyright assignment to the FSF.