298 lines
13 KiB
Org Mode
298 lines
13 KiB
Org Mode
#+TITLE: Org As A Word Processor
|
||
#+AUTHOR: Howard X. Abrams
|
||
#+DATE: 2020-09-10
|
||
#+FILETAGS: :emacs:
|
||
|
||
A literate programming file for making Org file more readable.
|
||
|
||
#+BEGIN_SRC emacs-lisp :exports none
|
||
;;; ha-org-word-processor --- Making Org file more readable. -*- lexical-binding: t; -*-
|
||
;;
|
||
;; © 2020-2022 Howard X. Abrams
|
||
;; This work is licensed under a Creative Commons Attribution 4.0 International License.
|
||
;; See http://creativecommons.org/licenses/by/4.0/
|
||
;;
|
||
;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
|
||
;; Maintainer: Howard X. Abrams
|
||
;; Created: September 10, 2020
|
||
;;
|
||
;; This file is not part of GNU Emacs.
|
||
;;
|
||
;; *NB:* Do not edit this file. Instead, edit the original literate file at:
|
||
;; ~/other/hamacs/ha-org-word-processor.org
|
||
;; Using `find-file-at-point', and tangle the file to recreate this one .
|
||
;;
|
||
;;; Code:
|
||
#+END_SRC
|
||
* 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.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)
|
||
#+END_SRC
|
||
|
||
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:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-list-demote-modify-bullet '(("*" . "+") ("+" . "-") ("-" . "-")
|
||
("1." . "a.") ("a." . "1.")))
|
||
#+END_SRC
|
||
** Typographic Quotes
|
||
According to [[http://endlessparentheses.com/prettify-your-quotation-marks.html][Artur Malabarba]] of [[http://endlessparentheses.com/prettify-you-apostrophes.html][Endless Parenthesis]] blog, I type a /straight quote/, ", Emacs actually inserts Unicode rounded quotes, like “this”. This idea isn’t 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 [[https://play.google.com/store/apps/details?id=com.orgzly&hl=en_US&gl=US][Orgzly]] and [[https://github.com/amake/orgro][Orgro]].
|
||
|
||
Stealing his function so that “quotes” just work to insert /rounded/ quotation marks:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))))
|
||
#+END_SRC
|
||
|
||
Stealing function for automatically adding a single quote (not in pairs):
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))))
|
||
#+END_SRC
|
||
Quote: “From this time forward, I shouldn’t have to worry about quotes.”
|
||
|
||
*Note:* I still need to worry about how quotes affect [[file:ha-org.org::*Spell Checking][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:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))))
|
||
#+END_SRC
|
||
|
||
Next, we just need to change the header sizes:
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
|
||
While we are at it, let’s make sure the code blocks are using my fixed with font:
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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)))
|
||
#+END_SRC
|
||
Not sure why the above code removes the color of =org-verbatim=, so let’s make it stand out slightly:
|
||
#+BEGIN_SRC emacs-lisp
|
||
(set-face-attribute 'org-verbatim nil :foreground "#aaaacc")
|
||
#+END_SRC
|
||
And some slight adjustments to the way blocks are displayed:
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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")
|
||
#+END_SRC
|
||
And decrease the prominence of the property drawers:
|
||
#+BEGIN_SRC emacs-lisp
|
||
(set-face-attribute 'org-drawer nil :height 0.8)
|
||
(set-face-attribute 'org-property-value nil :height 0.85)
|
||
(set-face-attribute 'org-special-keyword nil :height 0.85)
|
||
#+END_SRC
|
||
This process allows us to use =variable-pitch= mode for all org documents.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package org
|
||
:hook (org-mode . variable-pitch-mode))
|
||
#+END_SRC
|
||
* SVG-Based Prettiness
|
||
While I'm intrigued with [[https://github.com/rougier][Nicolas P. Rougier]]'s [[https://github.com/rougier/notebook-mode][notebook project]], I really just want to steal their [[https://github.com/rougier/svg-lib][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.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
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:
|
||
#+BEGIN_SRC emacs-lisp :tangle no
|
||
(use-package notebook
|
||
:straight (:type git :protocol ssh :host github :repo "rougier/notebook")
|
||
:after org
|
||
:hook (org-mode . notebook-mode))
|
||
#+END_SRC
|
||
|
||
In the interim, let’s use [[https://github.com/minad/org-modern][org-modern]] mode:
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
|
||
I liked the approach to the [[https://github.com/TonCherAmi/org-padding][org-padding]] project in how it allowed granular tweaks to add extra padding. This package doesn’t 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:
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defun ha-org-paste ()
|
||
(interactive)
|
||
(if (eq system-type 'gnu/linux)
|
||
(shell-command "xclip -t text/html -o | pandoc -r html -w org" t)))
|
||
#+END_SRC
|
||
* Presentations
|
||
Used to use [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for showing org files as presentations. Converted to use [[https://github.com/rlister/org-present][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.
|
||
|
||
#+BEGIN_SRC emacs-lisp
|
||
(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))
|
||
#+END_SRC
|
||
* Technical Artifacts :noexport:
|
||
Let's provide a name so that the file can be required:
|
||
#+BEGIN_SRC emacs-lisp :exports none
|
||
(provide 'ha-org-word-processor)
|
||
;;; ha-org-word-processor.el ends here
|
||
#+END_SRC
|
||
Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~
|
||
|
||
#+DESCRIPTION: A literate programming file for making Org file more readable.
|
||
|
||
#+PROPERTY: header-args:sh :tangle no
|
||
#+PROPERTY: header-args:emacs-lisp :tangle yes
|
||
#+PROPERTY: header-args :results none :eval no-export :comments no
|
||
|
||
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
|
||
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|