Skip to content

Latest commit

 

History

History
8369 lines (6978 loc) · 295 KB

org-special-block-extras.org

File metadata and controls

8369 lines (6978 loc) · 295 KB

org-special-block-extras

html-export-style:solarized_light

#

#

HTML & LaTeX Setup

#

Lisp Package Preamble

;;; org-special-block-extras.el --- 30 new custom blocks & 34 link types for Org-mode   -*- lexical-binding: t; -*-

;; Copyright (c) 2021 Musa Al-hassy

;; Author: Musa Al-hassy <alhassy@gmail.com>
;; Version: 4.1.1
;; Package-Requires: ((s "1.13.1") (dash "2.18.1") (emacs "27.1") (org "9.1") (lf "1.0") (dad-joke "1.4") (seq "2.0") (lolcat "0"))
;; Keywords: org, blocks, colors, convenience
;; URL: https://alhassy.github.io/org-special-block-extras


;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; This library provides common desirable features using the Org interface for
;; blocks and links:
;;
;; 0. A unified interface, the ‘defblock’ macro, for making new block and link types.
;;
;; 1. Colours: Regions of text and inline text can be coloured using 19 colours;
;;  easily extendable; below is an example.
;;
;;             #+begin_red org
;;             /This/
;;                   *text*
;;                          _is_
;;                               red!
;;             #+end_red
;;
;; 2. Multiple columns: Regions of text are exported into multiple side-by-side
;; columns
;;
;; 3. Remarks: First-class visible editor comments
;;
;; 4. Details: Regions of text can be folded away in HTML
;;
;; 5. Badges: SVG badges have the pleasant syntax
;; badge:key|value|colour|url|logo; only the first two are necessary.
;;
;; 6. Tooltips: Full access to Lisp documentation as tooltips, or any other
;; documentation-backend, including user-defined entries; e.g., doc:thread-first
;; retrives the documentation for thread-first and attachs it as a tooltip to
;; the text in the HTML export and as a glossary entry in the LaTeX export
;;
;; 7. Various other blocks: Solution, org-demo, spoiler (“fill in the blanks”).
;;
;; This file has been tangled from a literate, org-mode, file; and so contains
;; further examples demonstrating the special blocks it introduces.
;;
;; Full documentation can be found at
;; https://alhassy.github.io/org-special-block-extras

;;; Code:

;; String and list manipulation libraries
;; https://github.com/magnars/dash.el
;; https://github.com/magnars/s.el

(require 's)               ;; “The long lost Emacs string manipulation library”
(require 'dash)            ;; “A modern list library for Emacs”
(require 'subr-x)          ;; Extra Lisp functions; e.g., ‘when-let’.
(require 'cl-lib)          ;; New Common Lisp library; ‘cl-???’ forms.

(require 'cus-edit) ;; To get the custom-* faces

(require 'org)
(require 'ox-latex)
(require 'ox-html)
(require 'seq)

(require 'lf)

(defconst org-special-block-extras-version (package-get-version))
(defun org-special-block-extras-version ()
  "Print the current version of the package in the minibuffer."
  (interactive)
  (message org-special-block-extras-version))

<<forward-decls>>

#

  (defcustom org-special-block-add-html-extra t
    "Whether to let `org-special-block-extras' to add content to the `ox-html' head tag.

The `org-special-block-extras' mode adds a lot of extra HTML/JS code that
1. [Bloat] may not be needed by everyone using this package,
2. [Security Threat] loads stuff from foreign websites.

Since the extra stuff is for beautiful tooltips or styles,
for ease of use, the default behaviour is to use such
“untrusted data from untrusted websites”.

To avoid such behaviour, set this variable to `nil'.")
;;;###autoload
(define-minor-mode org-special-block-extras-mode
    "Provide 30 new custom blocks & 34 link types for Org-mode.

All relevant Lisp functions are prefixed ‘org-’; e.g., `org-docs-insert'.

This minor mode uses “untrusted data from untrusted websites” when exporting
to HTML, this is done for beautiful tooltips or styles.
Disable this behaviour by setting `org-special-block-add-html-extra' to `nil'.
"
  :lighter " OSPE"
  (if org-special-block-extras-mode
      (progn
        <<enable-mode>>
      ) ;; Must be on a new line; I'm using noweb-refs
    <<disable-mode>>
    )) ;; Must be on a new line; I'm using noweb-refs

Block and link types provided by this package

Folded Details —Let the user see stuff only if they’re interested

osbe-example:~/org-special-block-extras/tests/details.yaml

The implementation of details above is hidden away, and this is a concrete example of hiding a boring, but important, code snippet. Below is a concrete example of a ‘conversation-style’ usage of the details block:

We have thus found the above Lisp program to compute the inverse factorial of 𝓃; i.e., $\large \frac{1}{𝓃!}$.

Neato, let’s do more super cool stuff ^_^


summary:hover {background:pink;}

Sometimes you want to remark on details without drawing too much attention, and so a tooltip via tooltip suffices.

Remark —Inline footnotes, viz HTML tooltips and LaTeX notes in the margin

Sometimes you want to remark on details without drawing too much attention, and so a tooltip via remark suffices.

osbe-example:~/org-special-block-extras/tests/tooltip.yaml

It is pronounced “mar key”.

is a scrolling piece of text.


Source:

An HTML “marquee”
♯+begin_tooltip
An example is best:
♯+begin_export html
<marquee>Catch me if you can!</marquee>
♯+end_export
It is pronounced “mar key”.
♯+end_tooltip
is a scrolling piece of text.

The rest is an arduous exercise if you don’t know what’s going on.

exercise to show that ℕ is fixedpoint of Maybe.


Source:

It's a
#+begin_tooltip simple
/Proof Sketch:/ “Squint” your eyes to see ~zero : ℕ~ and ~nothing : Maybe ℕ~ as
essentially the same, and “squint” your eyes to see that ~suc~ is essentially the
same as ~just~.

More formally, here's one direction:
#+begin_src haskell :tangle no
to : Maybe ℕ → ℕ
to nothing  = zero
to (just n) = suc n
#+end_src

The rest is an arduous exercise if you don't know what's going on.
#+end_tooltip
exercise to show that ℕ is fixedpoint of ~Maybe~.

We can show Maybe ℕ ≅ ℕ by writing two functions…

to : Maybe   
to nothing = zero
to (just n) = suc n

from :   Maybe 
from zero = nothing
from (suc n) = just n

…and, finally, checking that the two functions undo each other…

to∘from : ∀ {n} →  to (from n)  ≡  n
to∘from n = {! try it! }

from∘to : ∀ {m} →  from (to m)  ≡  m
from∘to m = {! try it! }

This is “simple”, but involved!

exercise to show that ℕ is fixedpoint of Maybe.


Source:

It's a
#+begin_tooltip simple
We show that there is an /isomorphism/; i.e., a non-lossy protocol between ~Maybe ℕ~
and ~ℕ~ in stages.

First, let's recall the definitions ... in Agda ...
#+begin_src haskell :tangle no :tangle no
data Maybe (A : Set) : Set₁ where
  nothing : Maybe A
  just    : A → Maybe A

data ℕ : Set where
  zero : ℕ
  suc  : ℕ → ℕ
#+end_src

We can show ~Maybe ℕ ≅ ℕ~ by writing two functions...
#+begin_src haskell :tangle no
to : Maybe ℕ → ℕ
to nothing = zero
to (just n) = suc n

from : ℕ → Maybe ℕ
from zero = nothing
from (suc n) = just n
#+end_src

...and, finally, checking that the two functions undo each other...
#+begin_src emacs-lisp
to∘from : ∀ {n} →  to (from n)  ≡  n
to∘from n = {! try it! }

from∘to : ∀ {m} →  from (to m)  ≡  m
from∘to m = {! try it! }
#+end_src

This is “simple”, but involved!
#+end_tooltip
exercise to show that ℕ is fixedpoint of ~Maybe~.
pre.tooltip {color: black; background-color:Snow;}

For the tooltips containing code snippets, I’ve declared the following to make the code look nice.

#+html:      <style> pre.tooltip {color: black; background-color:Snow;} </style>

Boxed Text —Calling out super duper info

osbe-example:~/org-special-block-extras/tests/box.yaml

Three demos of box



Or, with just the header option :shadow t


Or, with the header option :shadow (:left "inset cyan" :right "inset pink" :deep-right orange)

For further header options, see the documentation of box.

Subtle Colours


In the first example above, how did we get that nice light blue? What is its HTML code? That’s not something I care to remember, so let’s make a handy dandy utility … Now when users request a colour to box their text, it will be a ‘subtle colour’ ;-)

To use these colour names, you will need the following incantations in your Org file.

#+latex_header: \usepackage{xcolor}

#+latex_header: \definecolor{teal}    {HTML}{99FFCC}
#+latex_header: \definecolor{brown}   {HTML}{CCCC99}
#+latex_header: \definecolor{gray}    {HTML}{CCCCCC}
#+latex_header: \definecolor{purple}  {HTML}{CCCCFF}
#+latex_header: \definecolor{lime}    {HTML}{CCFF99}
#+latex_header: \definecolor{green}   {HTML}{CCFFCC}
#+latex_header: \definecolor{blue}    {HTML}{CCFFFF}
#+latex_header: \definecolor{orange}  {HTML}{FFCC99}
#+latex_header: \definecolor{peach}   {HTML}{FFCCCC}
#+latex_header: \definecolor{pink}{HTML}{FFCCFF}
#+latex_header: \definecolor{yellow}  {HTML}{FFFF99}
#+latex_header: \definecolor{custard}{HTML}{FFFFCC}

#+latex_header: \definecolor{cyan}{HTML}{00FFFF}

In the future, it’d be nice to account for colours for LaTeX as well. ( E.g., src_latex[:exports code]{\color{blue}} is a nightmare. )

  latex-definitions for hiding LaTeX declarations in HTML

To present mathematical formulae in HTML export, we may use LaTeX-style commands such as {\color{red} x} by enclosing them in $-symbols to obtain ${\color{red}x}$. This is known as the MathJax tool —Emacs’ default HTML export includes it. (Unfortunately, MathJax does not directly support arbitrary HTML elements to occur within the $-delimiters.)

It is common to declare LaTeX definitions for convenience, but such declarations occur within $-delimiters and thereby produce undesirable extra whitespace. See the superflous vertical whitespace in the Result side below.

As such, we declare the latex-definitions block type which avoids displaying such extra whitespace in the resulting HTML.

osbe-example:~/org-special-block-extras/tests/latex-definitions.yaml

Nice Keystroke Renditions: kbd:C-h_h

Anyone who writes about Emacs will likely want to mention keystrokes in an aesthetically pleasing way, such as kbd:C-u 80 - to insert 80 dashes, or kbd:C-c_C-e_h_o to export an Org-mode file to HTML, or the useful <kbd:M-s h .>.

  • kbd:𝒳 will show a tooltip defining 𝒳, as an Emacs Lisp function, if possible. For example, kbd:C-h_h is kbd:C-h_h; and likewise <kbd:M-s h .> is <kbd:M-s h .> (we need to use <...> since punctuation is not picked up as part of link labels). In contrast, kbd:nope renders as kbd:nope without a tooltip (nor a red border).

    You can also supply explicit tooltip description: [[kbd:key sequence][description]] will show as description; i.e., the key sequence in nice key font along with a tooltip explaining it.

#

./images/kbd.png

The following styling rule is used to make the keystrokes displayed nicely.

(defvar org--ospe-kbd-html-setup nil
  "Has the necessary keyboard styling HTML beeen added?")

(unless org--ospe-kbd-html-setup
  (setq org--ospe-kbd-html-setup t))
(when org-special-block-add-html-extra
 (setq org-html-head-extra
  (concat org-html-head-extra
   "
<style>
/* From: https://endlessparentheses.com/public/css/endless.css */
/* See also: https://meta.superuser.com/questions/4788/css-for-the-new-kbd-style */
kbd
{
  -moz-border-radius: 6px;
  -moz-box-shadow: 0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset;
  -webkit-border-radius: 6px;
  -webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset;
  background-color: #f7f7f7;
  border: 1px solid #ccc;
  border-radius: 6px;
  box-shadow: 0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset;
  color: #333;
  display: inline-block;
  font-family: 'Droid Sans Mono', monospace;
  font-size: 80%;
  font-weight: normal;
  line-height: inherit;
  margin: 0 .1em;
  padding: .08em .4em;
  text-shadow: 0 1px 0 #fff;
  word-spacing: -4px;

  box-shadow: 2px 2px 2px #222; /* MA: An extra I've added. */
}
</style>")))

Let’s have some sanity tests…

(deftest "It becomes <kbd> tags, but final symbol non-ascii *may* be ignored"
  [kbd direct-org-links]
  (⇝ (⟰ "kbd:C-u_80_-∀") "<p>\n<kbd style=\"\">C-u 80</kbd>_-∀</p>"))

(deftest "[[It]] becomes <kbd> tags"
  [kbd square-org-links]
  (⇝ (⟰ "[[kbd:C-u_80_-]]") "<p>\n<kbd style=\"\">C-u 80 -</kbd></p>"))

(deftest "<It> becomes <kbd> tags, and surrounding space is trimmed"
  [kbd angle-org-links]
  (⇝ (⟰ "<kbd: C-u 80 - >")  "<p>\n<kbd style=\"\">C-u 80 -</kbd></p>"))

;; FIXME: uh-oh!
(when nil
(deftest "It has a tooltip documenting the underlying Lisp function, when possible"
  [kbd tooltip]
  (⇝ (⟰ "<kbd: M-s h .>")

     "<abbr class=\"tooltip\""
     (* anything)
     "Highlight each instance of the symbol at point.<br>Uses the
     next face from ‘hi-lock-face-defaults’ without
     prompting,<br>unless you use a prefix argument.<br>Uses
     ‘find-tag-default-as-symbol-regexp’ to retrieve the symbol
     at point.<br><br>This uses Font lock mode if it is enabled;
     otherwise it uses overlays,<br>in which case the
     highlighting will not update as you type.&emsp;The
     Font<br>Lock mode is considered ''enabled'' in a buffer if
     its ‘major-mode’<br>causes ‘font-lock-specified-p’ to return
     non-nil, which means<br>the major mode specifies support for
     Font Lock."
     (* anything)
     "<kbd style=\"border-color: red\">M-s h .</kbd></abbr>")))
kbd { -moz-border-radius: 6px; -moz-box-shadow: 0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; -webkit-border-radius: 6px; -webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; background-color: #f7f7f7; border: 1px solid #ccc; border-radius: 6px; box-shadow: 0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; color: #333; display: inline-block; font-family: 'Droid Sans Mono', monospace; font-size: 80%; font-weight: normal; line-height: inherit; margin: 0 .1em; padding: .08em .4em; text-shadow: 0 1px 0 #fff; word-spacing: -4px; box-shadow: 2px 2px 2px #222; /* MA: An extra I've added. */ }

Parallel —/Place ideas side-by-side, possibly with a separator/

osbe-example:~/org-special-block-extras/tests/parallel.yaml

[#A] COMMENT README improvements

Add images for the “osbe-example” results and link to the html, since otherwise things don’t look as nice in a markdown readme file.

images/parallel.png

images/details.png

( Markdown does not support colour; go look at the HTML or PDF! )

[#A] COMMENT Summary

The full article may be read as a PDF or as HTML —or visit the repo.

link-here:summary Let 𝒞 be any of the following: black, blue, brown, cyan, darkgray, gray, green, lightgray, lime, magenta, olive orange, pink, purple, red, teal, violet, white, yellow.

IdeaDocumentationLink only?
Colours𝒞, latex-definitions, color
Parallelparallel
Editorial Commentsremark
Folded Detailsdetails , box
Keystrokeskbd
OctoIcons & Link Hereoctoicon, link-here
Documentation-Glossarydocumentationdoc
Marginal remarksmargin
Badgesbadge
Equational proofscalc

Other fun stuff: solution, org-demo, stutter, rename, spoiler, tree 😁

There are also the social badge links: reddit-subscribe-to, github-followers, github-forks, github-stars, github-watchers, twitter-follow, and tweet.

Installation Instructions

Manually or using quelpa:

;; ⟨0⟩ Download the org-special-block-extras.el file manually or using quelpa
(quelpa '(org-special-block-extras :fetcher github :repo
"alhassy/org-special-block-extras"))

;; ⟨1⟩ Have this always active in Org buffers
(add-hook #'org-mode-hook #'org-special-block-extras-mode)

;; ⟨1′⟩ Or use: “M-x org-special-block-extras-mode” to turn it on/off

Or with use-package:

(use-package org-special-block-extras
  :ensure t
  :hook (org-mode . org-special-block-extras-mode)
  :custom
    ;; The places where I keep my ‘#+documentation’
    (org-docs-libraries
     '("~/org-special-block-extras/documentation.org"))
    ;; Details heading “flash pink” whenever the user hovers over them?
    (org-html-head-extra (concat org-html-head-extra "<style>  summary:hover {background:pink;} </style>"))
    ;; For the “doc:𝒳” link type
    ;;;; Nearly instantaneous display of tooltips.
    (setq tooltip-delay 0)
    ;;;;; Give user 30 seconds before tooltip automatically disappears.
    (setq tooltip-hide-delay 300)
    ;; The message prefixing a ‘tweet:url’ badge
    (org-link-twitter-excitement
     "This looks super neat (•̀ᴗ•́)و:")
    :config
    ;; For use with the “fortune” links, if you want to use them.
    (system-packages-ensure "cowsay")  ;; ≈ brew install cowsay
    (system-packages-ensure "fortune") ;; ≈ brew install fortune
    (system-packages-ensure "aha"))    ;; ≈ brew install aha

Then, provide support for a new type of special block, say re-using the src blocks that, say, folds up all such blocks in HTML export, by declaring the following.

(org-defblock src (lang nil title nil exports nil file nil)
  "Fold-away all ‘src’ blocks as ‘<details>’ HTML export.
If a block has a ‘:title’, use that to title the ‘<details>’."
  (format "<details> <summary> %s </summary> <pre> %s </pre></details>"
          (or title (concat "Details; " lang))
          raw-contents))
14 days ago I have made some research, and I could find nice resources:

Especially the last link were this seems to have been implemented. However it does not use “hooks” but rather define a new export back-end.

I’ll let you know if I can combine different thing I can find to make something that works.

Cheers


Context: https://www.reddit.com/r/emacs/comments/k2whsy/declaring_new_special_blocks_with_arguments/gevyoml/?context=3

Minimal working example

The following example showcases the prominent features of this library.

#+begin_parallel
[[color:orange][Are you excited to learn some Lisp?]] [[blue:Yes!]]

Pop-quiz: How does doc:apply work?
#+end_parallel

#+begin_details Answer
link-here:solution
Syntactically, ~(apply f '(x0 ... xN)) = (f x0 ... xN)~.

[[remark:Musa][Ain't that cool?]]

#+begin_spoiler aqua
That is, [[color:magenta][we can ((apply)) a function to a list of arguments!]]
#+end_spoiler

#+end_details

#+html: <br>
#+begin_box
octoicon:report Note that kbd:C-x_C-e evaluates a Lisp form!
#+end_box

/Allah[[margin:][The God of Abraham; known as Elohim in the Bible]] does
not burden a soul beyond what it can bear./ --- Quran 2:286

#+LATEX_HEADER: \usepackage{multicol}
#+LATEX_HEADER: \usepackage{tcolorbox}
#+latex: In the LaTeX output, we have a glossary.

show:GLOSSARY

badge:Thanks|for_reading
tweet:https://github.com/alhassy/org-special-block-extras
badge:|buy_me_a coffee|gray|https://www.buymeacoffee.com/alhassy|buy-me-a-coffee

Here is what it looks like as HTML (left) and LaTeX (right):

images/minimal-working-example.png

The above section, ‘practice problems’, presents a few puzzles to get you comfortable with defblock ;-)

Other cool stuff…

images/inference-rules.png

images/calculational_proofs.png

images/marginal_remarks.png

Bye!

badge:thanks|for_reading tweet:https://github.com/alhassy/org-special-block-extras badge:|buy_me_a coffee|gray|https://www.buymeacoffee.com/alhassy|buy-me-a-coffee

Lisp Postamble

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(provide 'org-special-block-extras)

;;; org-special-block-extras.el ends here

Glossary

show:GLOSSARY

Footnotes

[fn:1] See /A tutorial on the universality and expressiveness of fold/ and /Unifying Structured Recursion Schemes/