hamacs/ha-org-word-processor.org
Howard Abrams 0599164dec Finally fixed my fonts so that variable-pitch works in org
At least, it works in Org with the ability to change the font sizes,
which is important when giving presentations with larger fonts.

The real culprit was the mixed-pitch project that didn't allow for
changing font sizes (which was easy enough to configure).
2022-03-18 14:17:20 -07:00

13 KiB
Raw Blame History

Org As A Word Processor

A literate programming file for making Org file more readable.

Introduction

I like having org-mode files look more like a word processor than having it look like programming code. But that is just me.

General Org Settings

Since I use ellipsis in my writing… to change how org renders a collapsed heading.

  (setq org-pretty-entities t
        org-ellipsis "⤵"     ; …, ➡, ⚡, ▼, ↴, , ∞, ⬎, ⤷, ⤵
        org-agenda-breadcrumbs-separator " ❱ "
        org-src-fontify-natively t ;; Pretty code blocks
        org-hide-emphasis-markers t)

Typographic Quotes

According to Artur Malabarba of Endless Parenthesis blog, I type a straight quote, ", Emacs actually inserts Unicode rounded quotes, like “this”. This idea isnt how a file is displayed, but actually how the file is made. Time will tell if this idea works with my auxiliary functions on my phone, like Orgzly and Orgro.

Stealing his function so that “quotes” just work to insert rounded quotation marks:

(define-key org-mode-map "\"" #'endless/round-quotes)

(defun endless/round-quotes (italicize)
  "Insert “” and leave point in the middle.
With prefix argument ITALICIZE, insert /“”/ instead
\(meant for org-mode).
Inside a code-block, just call `self-insert-command'."
  (interactive "P")
  (if (and (derived-mode-p 'org-mode)
           (org-in-block-p '("src" "latex" "html")))
      (call-interactively #'self-insert-command)
    (if (looking-at "”[/=_\\*]?")
        (goto-char (match-end 0))
      (when italicize
        (if (derived-mode-p 'markdown-mode)
            (insert "__")
          (insert "//"))
        (forward-char -1))
      (insert "“”")
      (forward-char -1))))

Stealing function for automatically adding a single quote (not in pairs):

(define-key org-mode-map "'" #'endless/apostrophe)

(defun endless/apostrophe (opening)
  "Insert  in prose or `self-insert-command' in code.
With prefix argument OPENING, insert  instead and
leave point in the middle.
Inside a code-block, just call `self-insert-command'."
  (interactive "P")
  (if (and (derived-mode-p 'org-mode)
           (org-in-block-p '("src" "latex" "html")))
      (call-interactively #'self-insert-command)
    (if (looking-at "['][=_/\\*]?")
        (goto-char (match-end 0))
      (if (null opening)
          (insert "")
        (insert "")
        (forward-char -1)))))

Quote: “From this time forward, I shouldnt have to worry about quotes.”

Note: I still need to worry about how quotes affect spell checking.

Org Beautify

I really want to use the Org Beautify package, but it overrides my darker themes (and all I really want is headlines to behave).

First step is to make all Org header levels to use the variable font, and be the same color as the default text:

  (when window-system
    (let ((default-color (face-attribute 'default :foreground)))
      (dolist (face '(org-level-1 org-level-2 org-level-3 org-level-4 org-level-5 org-level-6 org-level-7 org-level-8))
        (set-face-attribute face nil
                            :foreground default-color :weight 'bold :font ha-variable-font))))

Next, we just need to change the header sizes:

  (when window-system
    (set-face-attribute 'org-level-1 nil :height 2.2)
    (set-face-attribute 'org-level-2 nil :height 1.8)
    (set-face-attribute 'org-level-3 nil :height 1.4)
    (set-face-attribute 'org-level-4 nil :height 1.1))

While we are at it, lets make sure the code blocks are using my fixed with font:

  (when window-system
    (dolist (face '(org-block org-code org-verbatim org-table org-drawer
                    org-special-keyword org-property-value org-document-info-keyword))
      (set-face-attribute face nil :inherit 'fixed-pitch)))

Not sure why the above code removes the color of org-verbatim, so lets make it stand out slightly:

  (set-face-attribute 'org-verbatim nil :foreground "#aaaacc")

And some slight adjustments to the way blocks are displayed:

  (set-face-attribute 'org-block-begin-line nil :background "#282828")
  (set-face-attribute 'org-block nil :height 0.95)
  (set-face-attribute 'org-block-end-line nil :background "#262626")

And decrease the prominence of the property drawers:

  (set-face-attribute 'org-drawer nil :height 0.8 :line-height 0.8)
  (set-face-attribute 'org-property-value nil :height 0.85)
  (set-face-attribute 'org-special-keyword nil :height 0.85)

This process allows us to use variable-pitch mode for all org documents.

  (use-package org
    :hook (org-mode . variable-pitch-mode))

Superstar

Now that headers are noticeable, I have no reason to see a number of asterisks. Once I used the org-bullets package, but believe we've replaced it with org-superstar-mode, so the following is an improvement, especially with the sub-bullets:

  (use-package org-superstar
    :after org
    :straight (:type git :protocol ssh :host github :repo "integral-dw/org-superstar-mode")
    :hook (org-mode . org-superstar-mode)
    :init
    (setq ; org-superstar-headline-bullets-list '("▶")
          org-superstar-special-todo-items nil
          org-superstar-todo-bullet-alist t
          org-superstar-prettify-item-bullets t
          org-superstar-item-bullet-alist '((42 . "●")   ; *
                                            (43 . "○")   ; +
                                            (45 . "•"))))

If this works, then we get the prettier bulleted list:

  • Top bullets
  • Plus bullets:

    • Apples
    • Oranges
    • Bananas
  • Minus bullets:

    • Dogs
    • Cats
    • Birds

Oh, and as I indent lists, they should change the bulleting in a particular sequence. If I begin with an * asterisk, I walk down the chain, but with the dashed bullets (my default choice), I just stay with dashed bullets. Numeric bullets should cycle:

  (setq org-list-demote-modify-bullet '(("*" . "+") ("+" . "-") ("-" . "-")
                                        ("1." . "a.") ("a." . "1.")))

Since the following code does not work like I would have expected:

(setq org-hide-leading-stars t)

I add a hook to standard Org, and since this is a Lisp-2, I can get away with:

(defun org-hide-leading-stars ()
  (let* ((keyword
          `(("^\\(\\*+ \\)\\s-*\\S-" ; Do not hide empty headings!
             (1 (put-text-property (match-beginning 1) (match-end 1) 'invisible t)
                nil)))))
    (font-lock-add-keywords nil keyword)))

  (add-hook 'org-mode-hook 'org-hide-leading-stars)

Checkboxes

According to an idea by Huy Trần, we can prettify the list checkboxes as well:

(defun ha-org-prettify-checkboxes ()
  "Beautify Org Checkbox Symbol"
  (push '("[ ]" . "☐") prettify-symbols-alist)
  (push '("[X]" . "☒") prettify-symbols-alist)
  (push '("[-]" . "☐-") prettify-symbols-alist)
  (prettify-symbols-mode))

And now we can attach it to a newly loaded org files:

(add-hook 'org-mode-hook 'ha-org-prettify-checkboxes)

To make it more distinguishable, he also changed the colors:

(defface org-checkbox-done-text
  '((t (:foreground "#71696A" :strike-through t)))
  "Face for the text part of a checked org-mode checkbox.")

(font-lock-add-keywords
 'org-mode
 `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)"
    1 'org-checkbox-done-text prepend))
 'append)

SVG-Based Prettiness

While I'm intrigued with Nicolas P. Rougier's notebook project, I really just want to steal their svg-lib project that allows me to create and display various SVG objects, namely tags, progress bars, progress pies and icons. Each object fits nicely in a text buffer ensuring width is an integer multiple of character width.

  (use-package svg-lib
    :straight (:type git :protocol ssh :host github :repo "rougier/svg-lib"))

  (use-package svg-tag-mode
    :straight (:type git :protocol ssh :host github :repo "rougier/svg-tag-mode"))

  (use-package notebook
    :straight (:type git :protocol ssh :host github :repo "rougier/notebook")
    :after org
    :hook (org-mode . notebook-mode))

Padding

The org-padding project looks places extra space before and after headers and blocks (essentially leading), to create a more word-processor-y experience. Great idea, however, I have spent a lot of extra time entering blank lines before and after my headers and blocks:

(use-package org-padding
  :straight (:type git :protocol ssh :host github :repo "TonCherAmi/org-padding")
  :hook
  (org-mode . org-padding-mode)
  :config
  (setq org-padding-block-begin-line-padding '(0.5 . 0.3)
        org-padding-block-end-line-padding '(0.1 . 0.5)
        org-padding-heading-padding-alist
        '((4.0 . 1.5) (3.0 . 0.5) (3.0 . 0.5) (3.0 . 0.5) (2.5 . 0.5) (2.0 . 0.5) (1.5 . 0.5) (0.5 . 0.5))))

However, I'm just going to have to write a function to clean this.

(defun ha-remove-superfluous-org-padding ()
  (interactive)
  (goto-char (point-min))
  (ha-remove-org-header-padding)
  (goto-char (point-min))
  (ha-remove-org-block-padding))

(defun ha-remove-org-header-padding ()
  ;; (goto-char (point-min))
  (while (re-search-forward (rx (optional bol (zero-or-more space) eol "\n")
                                (group bol (one-or-more "*") (one-or-more space) (one-or-more any) "\n")
                                (optional bol (zero-or-more space) eol "\n")) nil t)
    (replace-match (match-string 1) nil :no-error)))

(defun ha-remove-org-block-padding ()
  ;; (goto-char (point-min))
  (while (re-search-forward (rx (optional bol (zero-or-more space) eol "\n")
                                (group bol (zero-or-more space) "#+BEGIN" (one-or-more any) eol "\n"
                                       (zero-or-more (group bol (zero-or-more any) eol "\n"))
                                       bol (zero-or-more space) "#+END" (zero-or-more any) eol "\n")
                                (optional bol (zero-or-more space) eol "\n")) nil t)
    (replace-match (match-string 1) nil :no-error)))

Now that is some complicated regular expressions.

Pasting

I like the idea that I will paste HTML text from the clipboard and have it converted to org-formatted text:

(defun ha-org-paste ()
  (interactive)
  (if (eq system-type 'gnu/linux)
      (shell-command "xclip -t text/html -o | pandoc -r html -w org" t)))

Presentations

The org-tree-slide still seems to be the best presentation tool for Org files, but I really need to issue a pull request to fix a few warnings.

(use-package org-tree-slide
    :init
    (setq org-tree-slide-skip-outline-level 4)
    :config
    (org-tree-slide-simple-profile))