hamacs/ha-org-word-processor.org
Howard Abrams 0396c09af4 Convert to org-present from the org-tree-slide
Simpler and I now have hooks to make it look like what I want.
2022-03-21 16:58:00 -07:00

14 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-catch-invisible-edits 'show-and-error
        org-special-ctrl-a/e t     ; Note: Need to get this working with Evil!
        org-src-fontify-natively t ; Pretty code blocks
        org-hide-emphasis-markers t)

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.")))

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))

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")
    :config
    (setq svg-tag-tags
          '(("TODO:" . ((lambda (tag) (svg-tag-make "TODO" :face 'org-tag
                                                    :radius 2 :inverse t
                                                    :margin 0 :padding 0 :height 0.8))))
            ("NOTE:" . ((lambda (tag) (svg-tag-make "NOTE" :face 'font-lock-comment-face
                                                    :inverse nil :margin 0 :radius 2 :height 0.8))))
            ; The org-modern overrides this:
            ; ("#\\+RESULTS:" . ((lambda (tag) (svg-tag-make tag :beg 0 :end -1 :height 0.6))))
            ("\\(:[A-Z-]+\\):[a-zA-Z#0-9]+:" . ((lambda (tag)
                                                 (svg-tag-make tag :beg 1 :inverse t
                                                               :margin 0 :crop-right t))))
            (":[A-Z-]+\\(:[a-zA-Z#0-9]+:\\)" . ((lambda (tag)
                                                 (svg-tag-make tag :beg 1 :end -1
                                                               :margin 0 :crop-left t))))
            ("\\(:[A-Z-]+:\\)[ \n]" . ((lambda (tag) (svg-tag-make tag :beg 1 :end -1 :margin 0))))))
    (global-svg-tag-mode 1))

What does do? Here are some examples: TODO: Marks comments for tasks (this can be in source files too). NOTE: Highlights comments and other notes. :PROP:tag: are highlighted as two parts of the same tag And :TAG: with colons are highlighted, which include :PROPERTY: drawers.

When the project is more complete, I need to dive into this:

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

In the interim, lets use org-modern mode:

  (use-package org-modern
    :straight (:type git :protocol ssh :host github :repo "minad/org-modern")
    :custom (org-modern-label-border 0.1
             org-modern-variable-pitch t
             org-modern-tag  nil  ; Letting svg-tag do this
             org-modern-list . '((?+ . "◦")
                                 (?- . "•")
                                 (?* . "●")))
    :config
    (setq org-auto-align-tags nil
          org-tags-column 0)
    :hook
    (org-mode . org-modern-mode)
    (org-agenda-finalize . org-modern-agenda))

I liked the approach to the org-padding project in how it allowed granular tweaks to add extra padding. This package doesnt work with org-modern, but I may look more into it later.

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

Used to use org-tree-slide for showing org files as presentations. Converted to use org-present. I love the hooks as that makes it easier to pull out much of my demo-it configuration. My concern with org-present is that it only jumps from one top-level to another top-level header.

  (use-package org-present
    :init
    (defvar ha-org-present-mode-line mode-line-format "Cache previous mode-line format state")

    :config
    (defun org-blocks-hide-headers ()
      "Make the headers and other block metadata invisible. See `org-blocks-show-headers'."
      (add-to-invisibility-spec 'ha-org-block-headers)

      (defun hide-this (regexp)
        (goto-char (point-min))
        (while (re-search-forward regexp nil t)
          (let ((start (match-beginning 0)) (end (1+ (match-end 0))))
            (overlay-put (make-overlay start end) 'invisible 'ha-org-block-headers))))

      (defun hide-these (patterns)
        (when patterns
            (hide-this (car patterns))
            (hide-these (cdr patterns))))

      (save-excursion
        (hide-these (list (rx bol (zero-or-more space)
                              "#+" (or "begin" "end") "_"
                              (one-or-more any) eol)
                          (rx bol (zero-or-more space)
                              "#+" (or "name" "header" "results" "property" "options"
                                       "filetags") ":"
                              (zero-or-more any) eol)
                          (rx bol (zero-or-more space)
                              ":" (or "properties" "header-args" "end") ":"
                              (zero-or-more any) eol)))))

    (defun org-blocks-show-headers ()
      "Un-invisibilize the headers and other block metadata invisible.
    In other words, this undoes what `org-blocks-hide-headers' did."
      (remove-from-invisibility-spec 'ha-org-block-headers))

    (defun org-present-start ()
      (goto-char (point-min)) (re-search-forward (rx bol "*"))
      (org-blocks-hide-headers)
      (org-present-big)
      (setq mode-line-format nil)
      (org-display-inline-images)
      (blink-cursor-mode -1)
      (setq cursor-type nil))

    (defun org-present-end ()
      (org-present-small)
      (org-blocks-show-headers)
      (setq mode-line-format ha-org-present-mode-line-format)
      (setq cursor-type t)
      (blink-cursor-mode 1)
      (org-present-read-write))

    :hook
    (org-present-mode . org-present-start)
    (org-present-mode-quit . org-present-end))