AlBasmala Archive Tags RSS About

AlBasmala:
Blogging with Emacs & Org-mode (•̀ᴗ•́)و

  Ξ  

How my blog is setup (•̀ᴗ•́)و

Here are some notable features of my blog.

Super Simple Intro to Org-mode

Org-mode is an outliner, a rich markup language, spreadsheet tool, literate programming systems, and so much more.

Org-mode syntax is very natural; e.g., the following is Org-mode!

+ Numbered and bulleted lists are as expected.
  - Do the things:
    1.  This first
    2.  This second
    44. [@44] This forty-fourth
  - [@𝓃] at the beginning of an iterm forces
    list numbering to start at 𝓃
  - [ ] or [X] at the beginning for checkbox lists
  - Use Alt ↑, ↓ to move items up and down lists;
    renumbering happens automatically.

+ Definitions lists:
   - term :: def
+ Use a comment, such as # separator, between two lists
  to communicate that these are two lists that happen to be
  one after the other. Or use any non-indented text to split
  a list into two.

* My top heading, section
  words
** Child heading, subsection
  more words
*** Grandchild heading, subsubsection
    even more!

You make a heading by writing * heading at the start of a line, then you can TAB to fold/unfold its contents. A table of contents, figures, tables can be requested as follows:

# figures not implemented in the HTML backend
# The 𝓃 is optional and denotes headline depth
#+toc: headlines 𝓃
#+toc: figures
#+toc: tables

Export In Emacs, press C-c C-e h o to obtain an HTML format of the Org-mode markup; use C-c C-e l o to obtain a PDF rendition.

Working with tables

#+ATTR_HTML: :width 100%
#+name: my-tbl
#+caption: Example table
| Who? | What? |
|------+-------|
| me   | Emacs |
| you  | Org   |

Note the horizontal rule makes a header row and is formed by typing | - then pressing TAB . You can TAB between cells.

Working with links

Link syntax is [[source url][description]]; e.g., we can refer to the above table with [[my-tbl][woah]]. Likewise for images: file:path-to-image.

Source code

1: #+begin_src C
2: int tot = 1; (start)
3: for (int i = 0; i != 10; i++) (loop)
4:    tot *= i; (next)
5: printf("The factorial of 10 is %d", tot);
6: #+end_src

The labels (ref:name) refer to the lines in the source code and can be referenced with link syntax: [[(name)]]. Hovering over the link, in the HTML export, will dynamically highlight the corresponding line of code. To strip-out the labels from the displayed block, use -r -n in the header so it becomes #+begin_src C -r -n, now the references become line numbers.

Another reason to use Org: If you use :results raw, you obtain dynamic templates that may use Org-markup:

printf("*bold* +%d+ (strikethrough) /slanted/", 12345);

bold 12345 (strikethrough) slanted bold 12345 (strikethrough) slanted

Also: Notice that a C program can be run without a main ;-)

Mathematics

$\sin^2 x + \cos^2 x = \int_\pi^{\pi + 1} 1 dx = {3 \over 3}$

\[ ⇒ \quad \sin^2 x + \cos^2 x = \int_\pi^{\pi + 1} 1 dx = {3 \over 3} \]

#+name: euler
\begin{equation}
e ^ {i \pi} + 1 = 0
\end{equation}

See equation [[euler]].

\begin{equation} \label{org9598b28} e ^ {i \pi} + 1 = 0 \end{equation}

See equation \eqref{org9598b28}.

1 Using org-static-block

Let's use org-static-block to make our blog. Why?

  • It's a Lisp program smaller than 900 lines, its source is easy to read and understand, and, most importantly, it was super easy to get started using it using the given example.

Let's declare the necessary basic facts of our blog.

 1: (setq org-static-blog-publish-title "Life & Computing Science")
 2: (setq org-static-blog-publish-url "https://alhassy.github.io/")
 3: (setq org-static-blog-publish-directory "~/blog/")
 4: (setq org-static-blog-posts-directory "~/blog/posts/")
 5: (setq org-static-blog-drafts-directory "~/blog/drafts/")
 6: 
 7: ;; Use “#+filetags: τ₁ τ₂ … τₙ”
 8: (setq org-static-blog-enable-tags t)
 9: 
10: ;; I'd like to have tocs and numbered headings
11: (setq org-export-with-toc t)
12: (setq org-export-with-section-numbers t)

2 HTML Header

What do we want to be inserted into the head of every page?

Firstly, we want some styling rules to be loaded.

1: (concat
2: "<meta name=\"author\" content=\"Musa Al-hassy\">
3:  <meta name=\"referrer\" content=\"no-referrer\">"
4: "<link href=\"usual-org-front-matter.css\" rel=\"stylesheet\" type=\"text/css\" />"
5: "<link href=\"org-notes-style.css\" rel=\"stylesheet\" type=\"text/css\" />"
6: "<link href=\"floating-toc.css\" rel=\"stylesheet\" type=\"text/css\" />"
7: "<link href=\"blog-banner.css\" rel=\"stylesheet\" type=\"text/css\" />"
8: "<link rel=\"icon\" href=\"images/favicon.png\">")
usual-org-front-matter.css
Org-static-blog ignores any styling exported by Org, so let's bring that back in. I just exported this file with the usual C-c C-e h o , then saved the CSS it produced.
org-notes-style.css
I like the rose-style of this org-notes-style for HTML export. However, it seems loading the CSS directly from its homepage does not work, so I've copied the CSS file for my blog.
floating-toc.css
I want to have an unobtrusive floating table of contents, see §5.
blog-banner.css
Finally, we want a beautiful welcome mat, see §3.

In addition, we have two more pieces we would like to add to the header: Support for dynamic code-line highlighting, §3, and support for using LaTeX-style notation to write mathematics, §4. We will use a noweb-ref named my-html-header to refer to them, which are then catenated below.

 (setq org-static-blog-page-header
  (concat
   org-html-head-extra  ;; Alterd by ‘org-special-block-extras
   (concat
   "<meta name=\"author\" content=\"Musa Al-hassy\">
    <meta name=\"referrer\" content=\"no-referrer\">"
   "<link href=\"usual-org-front-matter.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link href=\"org-notes-style.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link href=\"floating-toc.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link href=\"blog-banner.css\" rel=\"stylesheet\" type=\"text/css\" />"
   "<link rel=\"icon\" href=\"images/favicon.png\">")
   "<script type=\"text/javascript\">
   /*
   @licstart  The following is the entire license notice for the
   JavaScript code in this tag.
   
   Copyright (C) 2012-2020 Free Software Foundation, Inc.
   
   The JavaScript code in this tag is free software: you can
   redistribute it and/or modify it under the terms of the GNU
   General Public License (GNU GPL) as published by the Free Software
   Foundation, either version 3 of the License, or (at your option)
   any later version.  The code is distributed WITHOUT ANY WARRANTY;
   without even the implied warranty of MERCHANTABILITY or FITNESS
   FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
   
   As additional permission under GNU GPL version 3 section 7, you
   may distribute non-source (e.g., minimized or compacted) forms of
   that code without the copy of the GNU GPL normally required by
   section 4, provided you include this license notice and a URL
   through which recipients can access the Corresponding Source.
   
   
   @licend  The above is the entire license notice
   for the JavaScript code in this tag.
   */
   <!--/*--><![CDATA[/*><!--*/
    function CodeHighlightOn(elem, id)
    {
      var target = document.getElementById(id);
      if(null != target) {
        elem.cacheClassElem = elem.className;
        elem.cacheClassTarget = target.className;
        target.className = \"code-highlighted\";
        elem.className   = \"code-highlighted\";
      }
    }
    function CodeHighlightOff(elem, id)
    {
      var target = document.getElementById(id);
      if(elem.cacheClassElem)
        elem.className = elem.cacheClassElem;
      if(elem.cacheClassTarget)
        target.className = elem.cacheClassTarget;
    }
   /*]]>*///-->
   </script>"
   "<script type=\"text/x-mathjax-config\">
       MathJax.Hub.Config({
           displayAlign: \"center\",
           displayIndent: \"0em\",
   
           \"HTML-CSS\": { scale: 100,
                           linebreaks: { automatic: \"false\" },
                           webFont: \"TeX\"
                          },
           SVG: {scale: 100,
                 linebreaks: { automatic: \"false\" },
                 font: \"TeX\"},
           NativeMML: {scale: 100},
           TeX: { equationNumbers: {autoNumber: \"AMS\"},
                  MultLineWidth: \"85%\",
                  TagSide: \"right\",
                  TagIndent: \".8em\"
                }
   });
   </script>
   <script type=\"text/javascript\"
           src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML\"></script>
   "
   ))

[ Warning: The noweb-ref invocation l <<𝓍𝓈>> r expands into

l 𝓍₀ r
l 𝓍₁ r
  ⋮
l 𝓍ₙ r
Where the 𝓍ᵢ are the lines referenced by 𝓍𝓈. As such, we had our reference call, above, in its own line! ]

3 Blog Banner and Dynamic Code Highlighting

I want to have a nice banner at the top of every page, which should link to useful parts of my blog.

 1: (setq org-static-blog-page-preamble
 2: "<div class=\"header\">
 3:   <a href=\"https://alhassy.github.io/\" class=\"logo\">Life & Computing Science</a>
 4:   <br>
 5:     <a href=\"https://alhassy.github.io/AlBasmala\">AlBasmala</a>
 6:     <a href=\"https://alhassy.github.io/archive\">Archive</a>
 7:     <a href=\"https://alhassy.github.io/tags\">Tags</a>
 8:     <a href=\"https://alhassy.github.io/rss.xml\">RSS</a>
 9:     <a href=\"https://alhassy.github.io/about\">About</a>
10: </div>")

Note that we could have been needlessly more generic by using, say, (org-static-blog-get-absolute-url org-static-blog-rss-file), instead of hardcoding the links.

I want to style it as follows:

  • Line 1: The banner is in a box at the top with some shadowing and centred text using the fantasy font
  • Line 13: The blog's title is large and bold
  • Line 18: All links in the banner are black
  • Line 25: When you hover over a link, it becomes blue
 1: .header {
 2:   /* Try to load ‘fantasy’ if possible, else try to load the others. */
 3:   font-family: fantasy, monospace, Times;
 4:   text-align: center;
 5:   overflow: hidden;
 6:   /* background-color: #f1f1f1 !important; */
 7:   /* background: #4183c4 !important; */
 8:   padding-top: 10px;
 9:   padding-bottom: 10px;
10:   box-shadow: 0 2px 10px 2px rgba(0, 0, 0, 0.2);
11: }
12: 

14:   font-size: 50px;
15:   font-weight: bold;
16: }
17: 
18: .header a {
19:   color: black;
20:   padding: 12px;
21:   text-decoration: none;
22:   font-size: 18px;
23: }
24: 
25: .header a:hover {
26:   background-color: #ddd;
27:   background-color: #fff;
28:   color: #4183c4;
29: }

Notice that as you hover over the references, such as this, the corresponding line of code is highlighted! Within a src block, one uses the switches -n -r to enable references via line numbers, then declares (ref:name) on line and refers to it by [[(name)][description]]. Org-mode by default styles such highlighting.

Details
"<script type=\"text/javascript\">
/*
@licstart  The following is the entire license notice for the
JavaScript code in this tag.

Copyright (C) 2012-2020 Free Software Foundation, Inc.

The JavaScript code in this tag is free software: you can
redistribute it and/or modify it under the terms of the GNU
General Public License (GNU GPL) as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version.  The code is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.

As additional permission under GNU GPL version 3 section 7, you
may distribute non-source (e.g., minimized or compacted) forms of
that code without the copy of the GNU GPL normally required by
section 4, provided you include this license notice and a URL
through which recipients can access the Corresponding Source.


@licend  The above is the entire license notice
for the JavaScript code in this tag.
*/
<!--/*--><![CDATA[/*><!--*/
 function CodeHighlightOn(elem, id)
 {
   var target = document.getElementById(id);
   if(null != target) {
     elem.cacheClassElem = elem.className;
     elem.cacheClassTarget = target.className;
     target.className = \"code-highlighted\";
     elem.className   = \"code-highlighted\";
   }
 }
 function CodeHighlightOff(elem, id)
 {
   var target = document.getElementById(id);
   if(elem.cacheClassElem)
     elem.className = elem.cacheClassElem;
   if(elem.cacheClassTarget)
     target.className = elem.cacheClassTarget;
 }
/*]]>*///-->
</script>"

[ Remark: TODO Before we move on, I'd like to have heavy red font for links.

a {color:#DD514C;text-decoration:none;font-weight:700}
But this causes the table of contents to be red, which I dislike ლ(ಠ益ಠ)ლ ]

4 MathJax Support — \(e^{i \cdot \pi} + 1 = 0\)

Org loads the MathJax display engine for mathematics whenever users write LaTeX-style math delimited by $...$ or by \[...\]. Here is an example.

Details

This is the CSS that Org loads by default.

"<script type=\"text/x-mathjax-config\">
    MathJax.Hub.Config({
        displayAlign: \"center\",
        displayIndent: \"0em\",

        \"HTML-CSS\": { scale: 100,
                        linebreaks: { automatic: \"false\" },
                        webFont: \"TeX\"
                       },
        SVG: {scale: 100,
              linebreaks: { automatic: \"false\" },
              font: \"TeX\"},
        NativeMML: {scale: 100},
        TeX: { equationNumbers: {autoNumber: \"AMS\"},
               MultLineWidth: \"85%\",
               TagSide: \"right\",
               TagIndent: \".8em\"
             }
});
</script>
<script type=\"text/javascript\"
        src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML\"></script>
"

\[ p ⊓ q = p \quad ≡ \quad p ⊔ q = q \label{Golden-Rule}\tag{Golden-Rule}\]

Look at \ref{Golden-Rule}, it says, when specialised to numbers, the minimum of two items is the first precisely when the maximum of the two is the second —d'uh!

[ Warning: We can make an equation ℰ named 𝒩 and refer to it by ℒ by declaring \[ℰ \tag{𝒩} \label{ℒ} \] then refer to it with \ref{ℒ}. However, if 𝒩 contains Unicode, then the reference will not generally be ‘clickable’ —it wont take you to the equation's declaration site. For example, \ref{⊑-Definition} below has Unicode in both its tag and label, and so clicking that link wont go anywhere, whereas \ref{Order-Definition} has Unicode only in its tag, with the label being \label{Order-Definition}, and clicking it takes you to the formula. \[ p ⊑ q \quad ≡ \quad p ⊓ q = p \tag{⊑-Definition}\label{⊑-Definition} \] \[ p ⊑ q \quad ≡ \quad p ⊔ q = q \tag{⊑-Definition}\label{Order-Definition} \] ]

The following rule for anchors a {⋯} resurrects \ref{} calls via MathJax —which org-notes-style kills.

a { white-space: pre !important; }

5 Ξ: Floating Table of Contents

I would like to have a table of contents that floats so that it is accessible to the reader in case they want to jump elsewhere in the document quickly —possibly going to the top of the document.

When we write #+toc: headlines 2 in our Org, HTML export produces the following.

 1: <div id="table-of-contents">
 2:   <h2>Table of Contents</h2>
 3:   <div id="text-table-of-contents">
 4:     <ul>
 5:       <li> section 1 </li>
 6:  7:       <li> section 𝓃 </li>
 8:     </ul>
 9:   </div>
10: </div>

Hence, we can style the table of contents by writing rules that target those id's. We use the following rules, adapted from the Worg community.

 1: /*TOC inspired by https://orgmode.org/worg/ */
 2: #table-of-contents {
 3:     /* Place the toc in the top right corner */
 4:     position: fixed; right: 0em; top: 0em;
 5:     margin-top: 120px; /* offset from the top of the screen */
 6: 
 7:     /* It shrinks and grows as necessary */
 8:     padding: 0em !important;
 9:     width: auto !important;
10:     min-width: auto !important;
11: 
12:     font-size: 10pt;
13:     background: white;
14:     line-height: 12pt;
15:     text-align: right;
16: 
17:     box-shadow: 0 0 1em #777777;
18:     -webkit-box-shadow: 0 0 1em #777777;
19:     -moz-box-shadow: 0 0 1em #777777;
20:     -webkit-border-bottom-left-radius: 5px;
21:     -moz-border-radius-bottomleft: 5px;
22: 
23:     /* Ensure doesn't flow off the screen when expanded */
24:     max-height: 80%;
25:     overflow: auto;}
26: 
27: /* How big is the text “Table of Contents” and space around it */
28: #table-of-contents h2 {
29:     font-size: 13pt;
30:     max-width: 9em;
31:     border: 0;
32:     font-weight: normal;
33:     padding-left: 0.5em;
34:     padding-right: 0.5em;
35:     padding-top: 0.05em;
36:     padding-bottom: 0.05em; }
37: 
38: /* Intially have the TOC folded up; show it if the mouse hovers it */
39: #table-of-contents #text-table-of-contents {
40:     display: none;
41:     text-align: left; }
42: 
43: #table-of-contents:hover #text-table-of-contents {
44:     display: block;
45:     padding: 0.5em;
46:     margin-top: -1.5em; }

[ Strange: If I zoom in over 100% in my browser, the toc disappears until I zoom out. ]

Since the table of contents floats, the phrase Table of Contents is rather ‘in your face’, so let's use the more subtle Greek letter Ξ.

 1: (advice-add 'org-html--translate :before-until 'display-toc-as-Ξ)
 2: 
 3: ;; (advice-remove 'org-html--translate 'display-toc-as-Ξ)
 4: 
 5: (defun display-toc-as-Ξ (phrase info)
 6:   (when (equal phrase "Table of Contents")
 7:     (s-collapse-whitespace
 8:     " <a href=\"javascript:window.scrollTo(0,0)\"
 9:         style=\"color: black !important; border-bottom: none !important;\"
10:         class=\"tooltip\"
11:         title=\"Go to the top of the page\">
12:       Ξ
13:     </a> ")))

How did I get here?

  1. How does Org's HTML export TOCs? ⇒ org-html-toc
  2. Looking at its source, we see org-html--translate being the only place mentioning the string Table of Contents
  3. Let's advise it, with advice-add, to return Ξ only on that particular input string.
  4. Joy ♥‿♥

( The Unicode whitespace ‘ ’ before and after Ξ is to appease the clickable headlines utility, below. )

6 Ensuring Useful HTML Anchors

Upon HTML export, each tree heading is assigned an ID to be used for hyperlinks. Default IDs are something like org1957a9d, which does not endure the test of time: Re-export will produce a different id. Here's a rough snippet to generate IDs from headings, by replacing spaces with hyphens, for headings without IDs.

(defun my/ensure-headline-ids (&rest _)
  "Org trees without a

All non-alphanumeric characters are cleverly replaced with ‘-’.

If multiple trees end-up with the same id property, issue a
message and undo any property insertion thus far.

E.g., ↯ We'll go on a ∀∃⇅ adventure
   ↦  We'll-go-on-a-adventure
"
  (interactive)
  (let ((ids))
    (org-map-entries
     (lambda ()
       (org-with-point-at (point)
         (let ((id (org-entry-get nil "CUSTOM_ID")))
           (unless id
             (thread-last (nth 4 (org-heading-components))
               (s-replace-regexp "[^[:alnum:]']" "-")
               (s-replace-regexp "-+" "-")
               (s-chop-prefix "-")
               (s-chop-suffix "-")
               (setq id))
             (if (not (member id ids))
                 (push id ids)
               (message-box "Oh no, a repeated id!\n\n\t%s" id)
               (undo)
               (setq quit-flag t))
             (org-entry-put nil "CUSTOM_ID" id))))))))

;; Whenever html & md export happens, ensure we have headline ids.
(advice-add 'org-html-export-to-html   :before 'my/ensure-headline-ids)
(advice-add 'org-md-export-to-markdown :before 'my/ensure-headline-ids)

One may then use [[#my-custom-id]] to link to the entry with CUSTOM_ID property my-custom-id.

Interestingly, org-set-property, C-c C-x p, lets us insert a property from a selection of available ones, then we'll be prompted for a value for it from a list of values you've used elsewhere. This is useful for remaining consistent for when trees share similar properties.

This section has been #+include'd from my init.org

7 Clickable Headlines

By default, HTML export generates ID's to headlines so they may be referenced to, but there is no convenient way to get at them to refer to a particular heading. The following spell fixes this issue: Headlines are now clickable, resulting in a link to the headline itself.

;; Src: https://writepermission.com/org-blogging-clickable-headlines.html
(setq org-html-format-headline-function
(lambda (todo todo-type priority text tags info)
  "Format a headline with a link to itself."
  (let* ((headline (get-text-property 0 :parent text))
         (id (or (org-element-property :CUSTOM_ID headline)
                 (org-export-get-reference headline info)
                 (org-element-property :ID headline)))
         (link (if id
                   (format "<a href=\"#%s\">%s</a>" id text)
                 text)))
     (org-html-format-headline-default-function todo todo-type priority link tags info))))

Warning: The header cannot already be a link! Otherwise you get cyrptic and unhelpful error (wrong-type-argument plistp :section-number); which then pollutes the current Emacs session resulting in stange nil errors after C-x C-s, thereby forcing a full Emacs restart. Instead, you need at least one portion of each heading to be not a link.

  1. Need to have a custom id declared.

      :PROPERTIES:
      :CUSTOM_ID: my-header
      :END:
    
  2. Failing headers: * [[link]] nor * ~code~ nor * $math$.
    • Any non-link text before it will work: ok [[link]].
      • Using Unicode non-breaking space ‘ ’ is is ok.
    • Text only after the link is insufficient.
This section has been #+include'd from my init.org

9 Article Headers & Images

Every article declaratively has an associated image ^_^

  • If none declared, we use emacs-birthday-present.png :-)
  • Images are loaded from the ~/blog/images/ directory.
 1: (cl-defun my/org-static-blog-assemble-image (file)
 2: "Assemble the value of ‘#+fileimage: image width height border?’ as an HTML form."
 3: (with-temp-buffer
 4:   (insert-file-contents file)
 5:   (goto-char 0)
 6:   (search-forward-regexp "^\\#\\+fileimage: \\(.*\\)" nil t)
 7:   (-let [(image width height no-border?)
 8:          (s-split " " (substring-no-properties
 9:                        (or (match-string 1)
10:                            "emacs-birthday-present.png")))]
11:     (setq width (or width 350))
12:     (setq height (or height 350))
13:     (setq no-border? (if no-border? "" "style=\"border: 2px solid black;\""))
14:     (format "<center> <img src=\"images/%s\" alt=\"Article image\"
15:             %s width=\"%s\" height=\"%s\" align=\"top\" /> </center>"
16:             image no-border? width height))))

To make use of org-notes-style, I need the title to use the title class but org-static-blog uses the post-title blog, so I'll override the org-static-blog preamble method to simply use an auxiliary div.

  • Along the way, I'll position the article image under the article's title.
  • Line 8: org-notes-style has too much vertical space after the title, let's reduce it so that the article's data can follow it smoothly.
 1: (defun org-static-blog-post-preamble (post-filename)
 2:   "Returns the formatted date and headline of the post.
 3: This function is called for every post and prepended to the post body.
 4: Modify this function if you want to change a posts headline."
 5:   (concat
 6:    ;; The title
 7:    "<h1 class=\"post-title\">"
 8:    "<div class=\"title\" style=\"margin: 0 0 0 0 !important;\">"
 9:    "<a href=\"" (org-static-blog-get-post-url post-filename) "\">"
10:    (org-static-blog-get-title post-filename)
11:    "</a>"
12:    "</h1></div>"
13:    ;; Move to the footer? Near the ‘Tags’ of the article?
14:    ;; The date
15:    "<div style=\"text-align: center;\">"
16:    (format-time-string (org-static-blog-gettext 'date-format)
17:                        (org-static-blog-get-date post-filename))
18:    "</div>"
19:    ;; The article's image
20:    (my/org-static-blog-assemble-image post-filename)
21:    "<br><center><strong>Abstract</strong></center>"))

10 Article Footers

 1: (defun org-static-blog-post-postamble (post-filename)
 2:   "Returns the tag list and comment box at the end of a post.
 3: This function is called for every post and the returned string is
 4: appended to the post body, and includes the tag list generated by
 5: followed by the HTML code for comments."
 6: ;; Generate an htmlized version of the source file
 7: (let ((org-hide-block-startup nil))
 8:   (with-temp-buffer
 9:     (find-file post-filename)
10:     ;; (insert "\n#+HTML_HEAD: <link href=\"../doom-solarized-light.css\" rel=\"stylesheet\">\n")
11:     (org-mode)
12:     (outline-show-all)
13:     (switch-to-buffer (htmlize-buffer))
14:     (write-file (concat "~/blog/" (f-base post-filename) ".org.html"))
15:     (kill-buffer)))
16:   ;; Actual bottom matter
17:   (concat
18:    ;; Tags
19:    "<div class=\"taglist\">"
20:    (org-static-blog-post-taglist post-filename)
21:    "</div>"
22:    ;;
23:    "<center><strong> Generated by Emacs and Org-mode (•̀ᴗ•́)و </strong></center>"
24:    ;; Link to source and history
25:    "<center>"
26:    ;; "<a href=\"https://raw.githubusercontent.com/alhassy/alhassy.github.io/master/posts/"
27:    "<a href=\""
28:    (f-base post-filename) ".org.html\"><img
29:    src=\"https://img.shields.io/badge/-Source-informational?logo=read-the-docs\"></a>"
30:    "&emsp;"
31:    "<a href=\"https://github.com/alhassy/alhassy.github.io/commits/master/"
32:    "posts/" (f-base post-filename) ".org\"><img
33:    src=\"https://img.shields.io/badge/-History-informational?logo=github\"></a>"
34:    "<br>"
35:    "<a href=\"https://www.buymeacoffee.com/alhassy\"><img src="
36:    "\"https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee\">"
37:    "</a>"
38:    "</center>"
39:    ;; Comments
40:    (if (string= org-static-blog-post-comments "")
41:        ""
42:      (concat "\n<div id=\"comments\">"
43:              org-static-blog-post-comments
44:              "</div>"))
45: 
46:    ;; ReadRemaining.js ∷ How much time is left to finish reading this article?
47:    ;;
48:   ;; jQuery already loaded by org-special-block-extras.
49:   ;; "<script
50:   ;; src=\
51:   ;; "https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js\"></script>"
52:  "<link rel=\"stylesheet\" href=\"readremaining.js-readremainingjs/css/rr_light.css\"
53:      type='text/css'/>
54:   <script
55:      src=\"readremaining.js-readremainingjs/src/readremaining.jquery.js\"></script>
56:   <script src='readremaining.js/src/readremaining.jquery.js'
57:      type='text/javascript'></script>
58:   <script type=\"text/javascript\"> $('body').readRemaining({showGaugeDelay : 10,
59:      showGaugeOnStart : true}); </script>"))

ReadRemaining.js gives us a little floating clock on the bottom left of the screen which says, e.g., 4m 9s left when reading an article.

  • It tells us how much time is left before the article is done.
  • The time adjusts dynamically as the user scrolls down —but not up.
  • Apparently it has to be at the end of the HTML <body>, otherwise it wont work for me.
    • It may be best to avoid loading jQuery multiple times; see here for the necessary conditional.

[ ლ(ಠ益ಠ)ლ: I want to consistently use the same theme to htmlize Org source, rather than the current session's theme. ]

11 The Index Page

I'd like to be able to quickly change the blurb on the index page, so we make a variable for that —consisting of Org-markup.

1: (setq index-content-header
2:   (concat
3:    "Here are some of my latest thoughts..."
4:    " badge:Made_with|Lisp such as doc:thread-first and doc:loop (•̀ᴗ•́)و"
5:    " tweet:https://alhassy.github.io/"))

The index page is a multipost page, so I'll override the org-static-blog-assemble-multipost-page method so that articles are summarised by their title, data & image, ‘abstract’, and a read-more badge.

  • Every article is intended to have a section named Abstract, whose contents are used as the preview of the article. See §13 for a template.
 1: (setq show-reading-time nil)
 2: 
 3: (defun org-static-blog-assemble-multipost-page
 4:     (pub-filename post-filenames &optional front-matter)
 5:   "Assemble a page that contains multiple posts one after another.
 6: Posts are sorted in descending time."
 7:   (setq post-filenames
 8:         (sort post-filenames (lambda (x y)
 9:                                (time-less-p (org-static-blog-get-date y)
10:                                             (org-static-blog-get-date x)))))
11:   (with-temp-buffer
12:     (insert
13:      (concat
14:       "#+EXPORT_FILE_NAME: " pub-filename
15:       "\n#+options: toc:nil title:nil html-postamble:nil"
16:       "\n#+title: " (if (equal "index" (f-base pub-filename))
17:                         org-static-blog-publish-title
18:                         (f-base pub-filename))
19:       "\n#+begin_export html\n "
20:         org-static-blog-page-preamble
21:         org-static-blog-page-header
22:         (if front-matter front-matter "")
23:       "\n#+end_export"
24: 
25:       "\n\n"
26:       (if (equal "index" (f-base pub-filename))
27:           (format "#+begin_export html\n%s\n#+end_export\n%s"
28:                   org-static-blog-page-header index-content-header)
29:         "")
30: 
31:       "\n\n" ;; abstracts of posts
32:       (thread-last post-filenames
33:         (--map
34:          (format
35:           (concat
36:            ;; ⟨0⟩ Title and link to article
37:            "#+HTML: <h2 class=\"title\"><a href=\"%s\"> %s</a></h2>"
38:            ;; ⟨1⟩ Tags and reading time
39:            "\n#+begin_center\n%s\n%s\n#+end_center"
40:            ;; ⟨2⟩ Article image
41:            "\n@@html:%s@@"
42:            ;; ⟨3⟩ Preview
43:            "\n#+INCLUDE: \"%s::*Abstract\" :only-contents t"
44:            ;; ⟨4⟩ “Read more” link
45:            "\n@@html:<p style=\"text-align:right\">@@"
46:            " badge:Read|more|green|%s|read-the-docs @@html:</p>@@")
47:           ;; ⟨0⟩ Title and link to article
48:           (concat org-static-blog-publish-url (f-base it))
49:           (org-static-blog-get-title it)
50:           ;; ⟨1⟩ Tags and reading time
51:           (concat octoicon:tag " "
52:                   (s-join " "
53:                           (--map (format "badge:|%s|grey|%stag-%s.html"
54:                                          (s-replace "-" "_" it)
55:                                          org-static-blog-publish-url it)
56:                                  (org-static-blog-get-tags it))))
57:           (if (not show-reading-time)
58:               ""
59:             (format "\n%s %s mins read"
60:                     octoicon:clock
61:                     (with-temp-buffer (insert-file-contents it)
62:                                       (org-ascii-export-as-ascii)
63:                                       (setq __x
64:                                             (count-words (point-min) (point-max)))
65:                                       (kill-buffer "*Org ASCII Export*")
66:                                       (delete-other-windows)
67:                                       (/ __x 200)))) ;; 200 words per minute reading
68:           ;; ⟨2⟩ Article image
69:           (my/org-static-blog-assemble-image it)
70:           ;; ⟨3⟩ Preview
71:           it
72:           ;; ⟨4⟩ “Read more” link
73:           (concat org-static-blog-publish-url (f-base it))))
74:         (s-join "\n\n"))
75: 
76:       ;; bottom matter
77:       "\n#+begin_export html:\n"
78:       "<hr><hr> <div id=\"archive\">"
79:       "<a href=\""
80:       (org-static-blog-get-absolute-url org-static-blog-archive-file)
81:       "\">" (org-static-blog-gettext 'other-posts) "</a>"
82:       "</div>"
83:       "</div>"
84:       "<div id=\"postamble\" class=\"status\">"
85:       org-static-blog-page-postamble
86:       "</div>"
87:       "\n#+end_export"))
88:     (org-mode)
89:     (org-html-export-to-html)))

12 Curvy Source Blocks

The border-radius property defines the radius of an element's corners, we use it to make curvy looking source blocks. Its behaviour changes depending on how many arguments it is given.

  • We also style the code block's label to be curvy.
  • Both .src and pre.src:before are defined by Org.
 1: .src {
 2:   border: 0px !important;
 3:   /* 50px for top-left and bottom-right corners;
 4:      20px for top-right and bottom-left cornerns. */
 5:   border-radius: 50px 20px !important;
 6: }
 7: 
 8: pre.src:before {
 9:     /* border: 0px !important; */
10:     /* background-color: inherit !important; */
11:     padding: 3px !important;
12:     border-radius: 20px 50px !important;
13:     font-weight:700
14: }
15: 
16:  /* wrap lengthy lines for code blocks */
17:  pre{white-space:pre-wrap}
18: 
19:  /* Also curvy inline code with ~ ⋯ ~ and = ⋯ = */
20:  code {
21:      background: Cyan !important;
22:      border-radius: 7px;
23:      /* border: 1px solid lightgrey; background: #FFFFE9; padding: 2px */
24:  }

Code such as (= 2 (+ 1 1)) now sticks out with a cyan background ♥‿♥

 table {
     background: pink;
     border-radius: 10px;
     /* width:90% */

     border-bottom: hidden;
     border-top: hidden;

     display: table !important;

     /* Put table in the center of the page, horizontally. */
     margin-left:auto !important;margin-right:auto !important;

     font-family:"Courier New";
     font-size:90%;
 }

 /* Styling for ‘t’able ‘d’ata and ‘h’eader elements */
 th, td {
     border: 0px solid red;
 }
Table 1: Example table
Prime 2Prime
1 2
2 4
3 8
5 32
7 128
11 2048
;; MA: Relocate this to my init.
;; Table captions should be below the tables
(setq org-html-table-caption-above nil
      org-export-latex-table-caption-above nil)
Let's show folded, details, regions with a nice greenish colour

MA: Relocate the following to org-special-block-extras.

details {
  padding: 1em;
  background-color: #e5f5e5;
  /* background-color: pink; */
  border-radius: 15px;
  color: hsl(157 75% 20%);
  font-size: 0.9em;
  box-shadow: 0.05em 0.1em 5px 0.01em  #00000057;
}

13 Getting Started: my/blog/new-article

Helper function to make a new article.

 1: (defvar my/blog/tags
 2:   '(emacs faith category-theory order-theory
 3:     lisp types packages haskell agda
 4:     c frama-c program-proving)
 5:   "Tags for my blog articles.")
 6: 
 7: ;; Use C-SPC to select multiple items
 8: 
 9: (defun my/blog/new-article ()
10:   "Make a new article for my blog; prompting for the necessary ingredients.
11: 
12: If the filename entered already exists, we simply write to it.
13: The user notices this and picks a new name."
14:   (interactive)
15:   (let (file desc)
16: 
17:     (thread-last org-static-blog-posts-directory
18:       f-entries
19:       (mapcar #'f-filename)
20:       (completing-read "Filename (Above are existing): ")
21:       (concat org-static-blog-posts-directory)
22:       (setq file))
23: 
24:     ;; For some reason, ‘find-file’ in the thread above
25:     ;; wont let the completing-read display the possible completions.
26:     (find-file file)
27: 
28:     (insert "#+title: " (read-string "Title: ")
29:             "\n#+author: " user-full-name
30:             "\n#+email: "  user-mail-address
31:             "\n#+date: " (format-time-string "<%Y-%m-%d %H:%M>")
32:             "\n#+filetags: " (s-join " " (helm-comp-read "Tags: "
33:                                                          my/blog/tags
34:                                                          :marked-candidates t))
35:             "\n#+fileimage: " (completing-read
36:                                "Image: "
37:                                (mapcar #'f-filename (f-entries "~/blog/images/")))
38:             "\n#+include: ../MathJaxPreamble.org"
39:             "\n#+description: "
40:                (setq desc (read-string "Article Purpose: "))
41:             "\n\n* Abstract :ignore: \n" desc
42:             "\n\n* ???")))

The #+description is exported as HTML meta-data which is used to ‘unfurl’ a link to an article: When a link to an article is pasted in a social media website, it unfurls into a little card showing some information about the link, such as its image, description, and author.

  • For long descriptions, one can use multiple #+description lines; I'd like to have a terse one-liner with a longer description in the Abstract heading.

14 Publishing with [C-u C-u] C-c C-b

 1: ;; Override all minor modes that use this binding.
 2: (bind-key* (kbd "C-c C-b")
 3:   (lambda (&optional prefix)
 4: "C-c C-b        ⇒ Publish current buffer
 5: C-u C-c C-b     ⇒ Publish entire blog
 6: C-u C-u C-c C-b ⇒ Publish entire blog; re-rendering all blog posts
 7:                   (This will take time!)
 8: "
 9:      (interactive "P")
10:      (pcase (or (car prefix) 0)
11:        (0  (org-static-blog-publish-file (f-full (buffer-name))))
12:            ;; (browse-url-of-file (format "%s%s.html" org-static-blog-posts-directory
13:            ;;                            (f-base (buffer-name))))
14:        ;; Apparently I have to publish the current buffer before trying
15:        ;; to publish the blog; otherwise I got some errors.
16:        (4  (org-static-blog-publish-file (f-full (buffer-name)))
17:            (org-static-blog-publish))
18:        (16 ;; (org-static-blog-publish t) ⇒ Crashes.
19:            ;; Delete all .html files, except “about”
20:            (thread-last (f-entries "~/blog/")
21:              (--filter (and (equal (f-ext it) "html")
22:                             (not (member (f-base it) '("about")))))
23:              (--map (f-delete it)))
24:            ;; Publish as usual
25:            (org-static-blog-publish-file (f-full (buffer-name)))
26:            (org-static-blog-publish)))))

Line 23: To re-render an article, just remove its corresponding .html file ;-)

15 The name: al-bas-mala

The prefix al is the Arabic definite particle which may correspond to English's the; whereas basmala refers to a beginning.

That is, this is a variation on the traditional "hello world" ;-)

Creative Commons License
Life & Computing Science by Musa Al-hassy is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
comments powered by Disqus
Tags: emacs
Generated by Emacs and Org-mode (•̀ᴗ•́)و