#+title: AlBasmala: @@html: <br>@@ Blogging with Emacs & Org-mode (•̀ᴗ•́)و
#+description: How my blog is setup (•̀ᴗ•́)و
#+date: <2020-05-03 Sun>
#+filetags: emacs org html css javascript git lisp
#+fileimage: org_logo.png 150 150 no-border
#+property: header-args :tangle "~/blog/AlBasmala.el" :results silent :exports code :noeval
#+html_head: <style> ul {list-style-type: " ✓"} </style>
* COMMENT Speculative TODO-s
:my-html-header__variable:
See the-html-header above
In addition, we have two more pieces we would like to add to the header: Support
for dynamic code-line highlighting, §blog-banner, and support for using
LaTeX-style notation to write mathematics, §MathJax-Support. We will use a
noweb-ref named my-html-header to refer to them, which are then catenated below.
#+begin_remark "ლ(ಠ益ಠ)ლ"
I want to consistently use the same theme to htmlize Org source, rather than the current session's theme.
#+end_remark
;; TODO: Consider a tag “draft”, such that articles with this tag are not considered
;; for publication? Or better, they are published and have a badge “Warning: Incomplete Draft”, after all I think most articles are drafts since I want to be able to continously update them, that's why I have the “history” badge.
;;
;; Use “#+filetags: τ₁ τ₂ … τₙ”
;; See (@tags ⋯) method.
;; TODO. (defun @tags (json) (s-split " " (map-elt json "tags"))) ;; TODO Have this be a list, in the actual json for future AngularJS search by tags
TODO: The sections that have been tangled from my init: Just move that code
here. That code was written with my blog in mind, and so it deserves to be here,
and not in my init.
TODO: Look at stuff in my init and see what there is specifically serving my
blog; and move that here. Can always link to AlBasmala.html.
** font for links
#+html: <br>
#+begin_remark
Before we move on, I'd like to have heavy red font for links.
# +begin_src css :tangle ~/blog/blog-banner.css :noeval -n :tangle no
HERE PLS
# +end_src
But this causes the table of contents to be red, which I dislike ლ(ಠ益ಠ)ლ
#+end_remark
** wrt floating toc:
#+begin_remark Strange
If I zoom in over 100% in my browser, the toc disappears until I zoom out.
#+end_remark
(org-export-string-as
"blog/new-article"
'html
:body-only)
** COMMENT TODO: Make the floating toc “Ξ” be aware of links...
... so that “doc:blog/new-article” renders nicely in the floating doc!
** TODO COMMENT Add dates, and sort by them.
** TODO COMMENT avoid being asked for unicode encodings
(cl-defun select-safe-coding-system-interactively (&rest args) (setq last-coding-system-specified 'utf-8))
Related:
- https://github.com/abingham/emacs-ycmd/issues/496
- https://stackoverflow.com/questions/63644928/emacs-failed-quit-with-error-of-utf-8-cannot-encode
** TODO Misc :noexport:
:PROPERTIES:
:CUSTOM_ID: Misc
:END:
TODO: Add #+date when publishing, otherwise order's are all wonky.
TODO:
Find-replace all px with percentages, then ensure things look good!
*** Magit and large HTML files
:PROPERTIES:
:CUSTOM_ID: Magit-and-large-HTML-files
:END:
Since I'm producing massive HTML files for each post, trying to review changes with the default Magit buffer which shows
all changes in the repository can be painfully slow. As such, when I'm blogging, let's change my C-x g binding from
doc:magit-status to doc:magit-file-dispatch, which just narrow's Magit's view to the file I'm currently working with:
C-x g D u to see the “u”nstaged “d”ifferences for the file, then stage what I like with s, then C-x g c to “c”ommit whatever differences I have staged.
#+begin_src emacs-lisp
(bind-key "C-x g" #'magit-file-dispatch)
#+end_src
*** Column Width
:PROPERTIES:
:CUSTOM_ID: Column-Width
:END:
When blogging, I see live HTML previews whenever I save thanks to
doc:blog/preview. As such, I cannot have my lines being too wide. I'll settle
for a modest 80 columns. Then kbd:M-q will format my paragraphs to wrap nicely
into this 80-column width.
#+begin_src emacs-lisp
(setq-default fill-column 80)
#+end_src
(When I'm coding with a single open window, I usually use a comfortable 120 columns.)
*** Required loads
:PROPERTIES:
:CUSTOM_ID: Clean-this-section-up
:END:
#+begin_src emacs-lisp :exports none
(setq byte-compile-warnings '(cl-functions))
(require 'cl-lib)
(require 'shortdoc)
(ignore-errors
(use-package org-preview-html)
(setq org-preview-html-viewer 'xwidget)
(advice-add #'xwidget-webkit-browse-url :before (lambda (&rest _) (doom-modeline-mode 0)))
(advice-add #'xwidget-webkit-browse-url :after (lambda (&rest _) (--map (with-current-buffer it (setq mode-line-format "%b %p L%l C%c")) (buffer-list)) ))
(advice-add #'doom-modeline-mode :before (lambda (&rest _) (-let [kill-buffer-query-functions nil]
(mapcar #'kill-buffer (--filter (s-starts-with? "*xwidget" (buffer-name it)) (buffer-list)))
)))
(use-package org-special-block-extras)
)
(defun quelpa-read-cache ()) (setq quelpa-cache nil)
#+end_src
#+begin_src emacs-lisp :exports none
(cl-defun org-clocking-buffer (&rest _))
#+end_src
*** COMMENT Arabic Setup :Possibly_already_in_AlBasmala_so_just_load_that:
:PROPERTIES:
:CUSTOM_ID: COMMENT-Arabic-Setup
:END:
#+begin_src emacs-lisp
(bind-key "M-x" #'execute-extended-command)
(set-fontset-font "fontset-default" '(#x600 . #x6ff) "Amiri Quran Colored")
(bind-key* "M-SPC" (lambda () (interactive)
(message (if (not current-input-method)
(progn (set-input-method "farsi-transliterate-banan" t) "Perso-Arabic! Hint: M-x describe-input-method")
(progn (set-input-method nil) "English!")))))
(bind-key* "C-q" (lambda () (interactive) (insert (format "“%s”" (thing-at-point 'word))) (kill-word 1)))
#+end_src
**** COMMENT [HERE TODAY] Rndm
:PROPERTIES:
:CUSTOM_ID: COMMENT-HERE-TODAY-Rndm
:END:
;; After startup, if Emacs is idle for 10 seconds, then open my work file;
;; which is a GPG file and so requires passphrase before other things can load.
;; (run-with-idle-timer 10 nil (lambda () (find-file "~/Desktop/work.org.gpg")))
;; NOTE: Will not work when doom-modeline is enabled!
;; (xwidget-webkit-browse-url "https://www.reddit.com/r/emacs/")
;; Press C-q on a word to quote it with nice unicode quotes.
(bind-key* "C-q" (lambda () (interactive) (insert (format "“%s”" (thing-at-point 'word))) (kill-word 1)))
(load-file "~/blog/AlBasmala.el")
#+begin_src emacs-lisp :exports code
(org-deflink card
"Show one of 6 hardcoded phrases as a small inline image."
(-let [url
(pcase o-label
("Let's take a break" "https://i0.wp.com/oerabic.llc.ed.ac.uk/wp-content/uploads/2020/09/Visual-Communication-Signs-IRAQI-19.png")
("Yes" "https://i1.wp.com/oerabic.llc.ed.ac.uk/wp-content/uploads/2020/09/Visual-Communication-Signs-IRAQI-20.png")
("No" "https://i0.wp.com/oerabic.llc.ed.ac.uk/wp-content/uploads/2020/09/Visual-Communication-Signs-IRAQI-21.png")
("Agree" "https://i0.wp.com/oerabic.llc.ed.ac.uk/wp-content/uploads/2020/09/Visual-Communication-Signs-IRAQI-22.png")
("Disagree" "https://i1.wp.com/oerabic.llc.ed.ac.uk/wp-content/uploads/2020/09/Visual-Communication-Signs-IRAQI-23.png")
("I have a question" "https://i1.wp.com/oerabic.llc.ed.ac.uk/wp-content/uploads/2020/09/Visual-Communication-Signs-IRAQI-35.png"))]
(format "<a href=\"%s\" class=\"tooltip\" title=\"%s\"><img src=\"%s\" height=50></a>" url o-label url)))
#+end_src
** COMMENT Ideas
:PROPERTIES:
:CUSTOM_ID: COMMENT-todo
:END:
+ in the index, under each article's name:
- twitter link
- per article via advice
#+begin_export html
<footer class="container">
<div class="site-footer">
<div class="copyright pull-left">
Powered by
<a href="https://github.com/alhassy/emacs.d">Emacs</a>
</div>
<a href="https://github.com/alhassy" target="_blank" aria-label="view source code">
octicon-github
</a>
<div class="pull-right">
<a href="javascript:window.scrollTo(0,0)" >TOP</a>
</div>
</div>
</footer>
#+end_export
+ Footer should include
- See Org Source; see HTML source
- buy-me-a-coffee
#+html: <hr>
*** COMMENT To consider
:PROPERTIES:
:CUSTOM_ID: COMMENT-To-consider
:END:
#+BEGIN_SRC emacs-lisp :tangle no
(maybe-clone "https://github.com/adithyaov/helm-org-static-blog")
(load-file "~/helm-org-static-blog/helm-org-static-blog.el")
(setq blog/title "Life & Computing Science")
(setq blog/url "https://alhassy.github.io/")
(setq blog/publish-directory "~/alhassy.github/posts/")
(setq blog/posts-directory "~/alhassy.github/posts/")
(setq org-static-blog-drafts-directory "~/alhassy.github/drafts/")
#+END_SRC
Show me the “non-trivial” files in my blog repo.
#+begin_src emacs-lisp :results raw
(thread-last (f-entries "~/alhassy.github")
(--filter (or (not (equal (f-ext it) "html"))
(s-starts-with? "tag-" (f-base it))))
(--map (format "[[file:%s]]" it))
(s-join "\n" ))
#+end_src
*** COMMENT Mention alternative to using “Abstract”
:PROPERTIES:
:CUSTOM_ID: COMMENT-Mention-alternative-to-using-Abstract
:END:
src: https://ogbe.net/blog/blogging_with_org.html
When I write a blog post, I enclose the "preview" part of the post in #+BEGIN_PREVIEW...#+END_PREVIEW tags, which my (very simple) parser then inserts into the sitemap page.
(defun my-blog-get-preview (file)
"The comments in FILE have to be on their own lines, prefereably before and after paragraphs."
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(let ((beg (+ 1 (re-search-forward "^#\\+BEGIN_PREVIEW$")))
(end (progn (re-search-forward "^#\\+END_PREVIEW$")
(match-beginning 0))))
(buffer-substring beg end))))
*** COMMENT Old Jekyll Setup :posterity:terrible:
:PROPERTIES:
:CUSTOM_ID: COMMENT-Old-Jekyll-Setup
:header-args: :noeval
:END:
Write in Org-mode and generate coloured markdown for Jekyll usage
**** Server Setup
:PROPERTIES:
:CUSTOM_ID: Server-Setup
:END:
When drafting, it's ideal to be able to inspect the resulting web article.
To do so, we may initialise the Jekyll server as follows.
#+begin_src emacs-lisp :tangle no
(shell-command "cd ~/alhassy.github.io/ ; bundle exec jekyll serve &")
#+end_src
#+RESULTS:
: #<window 328 on *Org-Babel Error Output*>
In order to be an Org only interface, let's remove this shell invocation from
the user's view --as an Org user, they need not be forced to learn such Jekyll intricacies.
#+begin_src emacs-lisp
(defvar jekyll-served nil "Documents whether the blog server has begun.")
(defun ensure-blog-is-serving ()
"Ensure that the server has begun."
(unless jekyll-served
(shell-command "cd ~/alhassy.github.io/ ; bundle exec jekyll serve &")
(setq jekyll-served t)))
#+end_src
#+RESULTS:
: ensure-blog-is-serving
Super simple, but hides an annoying step & layer from the user.
**** file Symbols
:PROPERTIES:
:CUSTOM_ID: file-Symbols
:END:
We will look at various generated files revolving around the given file,
so let us generate the necessary variables that refer to such names.
First off, some useful libraries.
#+BEGIN_SRC emacs-lisp
(require 'dash) (require 's) #+END_SRC
#+RESULTS:
: s
Now, let's make a function that produces our variables.
This way we avoid tedious repetition of a particular pattern.
#+BEGIN_SRC emacs-lisp
(cl-defun make-file-extension-variables (&key prefix name extensions)
" Produce symbols ‘prefix.ext’ whose value is the string ‘name.ext’, where
‘ext’ range over the list ‘extensions’.
Both ‘prefix’ and ‘name’ should be strings.
I insist that the arguments be keywords, “:prefix, :name, :extensions”,
since I currently feel that this is more informative.
All three pieces need to be there, otherwise no variables are formed.
Success is signalled by the message string ”new filename variables created”.
Moreover, these symbols are local to the current buffer;
in-particular, their values cannot be altered from other buffers.
"
(and prefix name
(dolist (ext extensions (message "new filename variables created"))
(let* ((name.ext (concat name "." ext))
(symbol (intern (concat prefix "." ext))))
(set symbol name.ext)
))))
#+END_SRC
#+RESULTS:
: make-file-extension-variables
:Example_of_locals_in_elisp:
#+BEGIN_SRC emacs-lisp :tangle no
(setq bar "noah") (make-local-variable 'bar) (setq bar "rab")
(make-local-variable 'foo) (setq foo "woah")
#+END_SRC
#+RESULTS:
: woah
:End:
With that in hand, let's actually make the file.* variables.
#+BEGIN_SRC emacs-lisp
(setq AbsNAME (file-name-sans-extension buffer-file-name))
(setq NAME (file-name-sans-extension (buffer-name)))
(make-file-extension-variables
:prefix "file"
:name NAME
:extensions '("org" "el" "src" "tex" "pdf" "html"))
#+END_SRC
#+RESULTS:
: new filename variables created
Finally, it would be nice to know where the blog repository lives.
#+BEGIN_SRC emacs-lisp
(defvar blogrepo "~/alhassy.github.io/"
"The path to the blog repository on a local machine.")
(defvar blogrepo-posts "~/alhassy.github.io/_posts/"
"The path to the blog repository's posts directory.")
(defvar blogrepo-file.pdf (concat "../assets/pdfs/" file.pdf) "The path to the blog repository where the generated PDF should live.")
#+END_SRC
#+RESULTS:
: blogrepo-file\.pdf
Before we close we need Jekyll relevant names.
#+begin_src emacs-lisp
(defvar jekyll.name nil
"The formal name of the resulting Jekyll blog article.")
(defvar jekyll.name.md nil
"The formal markdown of the resulting Jekyll blog article.")
#+end_src
#+RESULTS:
: jekyll\.name\.md
**** Get Org Keywords
:PROPERTIES:
:CUSTOM_ID: Get-Org-Keywords
:END:
We want to be able to access #+key: value pairs from the article org source
as a variable org.key. We also allow as input default values, since the user
may not have provided values for them.
#+begin_src emacs-lisp
(defvar albasmala/keywords
`(("title" . nil)
("date" . ,(format-time-string "%Y-%m-%d"))
("author" . nil)
("image" . nil)
("imageheight" . 142)
("imagewidth" . 142)
("categories" . nil)
("sourcefile" .
,(concat "https://raw.githubusercontent.com/alhassy/alhassy.github.io/master/content/"
(buffer-name)))
("nopdf" . nil)
("nomodificationdate" . nil)
("draft" . nil))
"This list contains tuples denoting a ‘property’ and it's ‘default’ value.
These are the keywords that the user of this AlBasmala setup should utilise.
For example, if the user does not provide a ‘date’, then one is provided,
for them; the default date.
Note that ‘sourcefile’ refers to the URL to the raw master location of the blog
repository by default, but it's useful for the user to set it when the file is
associated with a different repoistory. The URL should begin ‘https://⋯’.
By default we produce a PDF and link to it from the article.
If ‘nopdf’ is set to a non-nil value, then no PDF is generated
--which may be usefull since making a pdf takes time, which may not be desirable
while drafting. Likewise, we always produce the most recent modification date,
unless instructed otherwise. --c.f., ‘draft’.
The ‘draft’ variable is useful since it puts the word DRAFT alongside
a generated number when drafting so as to ensure you're actually
re-generating the article --rather than loading a previously generated one.
When drafting, no PDF is generated.
Warning: The values cannot have links; e.g., embedding a link in the
value of ‘author’ renders this script useless.
")
#+end_src
#+RESULTS:
: albasmala/keywords
For each keyword, let's uniformly produce these symbols, attempt to obtain their values,
and use the defaults otherwise.
#+begin_src emacs-lisp
(defun make-org-variables (keywords)
"For each “(key . default)” in the ‘keywords’ list, we produce a symbol named
‘org.key’ whose value is set to be the value from “#+key: value”
from the current buffer.
The keys may be in lower case; we upcase them before obtaining
their values. If there is no value, we use the defaults in ‘keywords’.
"
(dolist (keydef keywords (message "new org keyword variables created"))
(let* ((key (car keydef))
(value (org-keyword (upcase key)))
(org.key (concat "org." key))
(symbol (intern org.key)))
(set symbol value)
(unless value (set symbol (cdr keydef)))
(put symbol 'variable-documentation
"Variable generated by ‘make-org-variables’")
)))
#+end_src
#+RESULTS:
: make-org-variables
:Setting_docstrings_after_the_fact:
(put FUNCTIONSYMBOL 'function-documentation VALUE)
(get 'org.sourcefile 'variable-documentation)
(put 'org.sourcefile 'variable-documentation "nice")
(get symbol 'variable-documentation)
(put 'symbol 'variable-documentation 'doc-string)
:End:
We know turn to actually obtaining the values of keywords as a function call.
Why not just set them once? These values can be altered any time by the user, e.g., me,
and as such they need to be reloaded before the post is created as a precautionary measure.
E.g., the title in the org file and the title in the article may be distinct, so we allow
the user this added flexibility.
We invoke make-org-variables to produce variables of the form org.var.
#+BEGIN_SRC emacs-lisp
(defun GetOrgKeyWords () "Get the #+KEYWORD values from the org-file."
(make-org-variables albasmala/keywords)
(setq jekyll.name (concat org.date "-" NAME))
(setq jekyll.name.md (concat org.date "-" NAME ".markdown"))
)
#+END_SRC
#+RESULTS:
: GetOrgKeyWords
Note that these values can be manually overridden by including in your locals, for example:
#+BEGIN_SRC emacs-lisp :tangle no
# eval: (setq org.title "Experimenting..." )
#+END_SRC
**** MakeHeader
:PROPERTIES:
:CUSTOM_ID: MakeHeader
:END:
The Jekyll backend has a particular header for articles, which we produce:
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(defun MakeHeader () "Header for Jekyll backend."
(setq HEADER (concat
"---\nlayout: post\nname: " jekyll.name
"\ntitle: " org.title
"\ndate: " org.date
"\nauthor: " org.author
"\nimage:\n href: " org.image
"\ncategories: " org.categories
"\n---\n"
)))
#+END_SRC
**** Article Image
:PROPERTIES:
:CUSTOM_ID: Article-Image
:END:
An image is included via the #+IMAGE:location --see the usages sections below.
Alternative methods include.
+ An image can be embedded as a url, in Org-mode:
#+BEGIN_SRC org :tangle no
,#+begin_export html
<center> <img src="http://book.realworldhaskell.org/support/rwh-200.jpg"
alt="RWH Cover" width="142" height="142" align="top"> </center>
,#+end_export
#+END_SRC
:One_long_line:
#+BEGIN_SRC org :tangle no
,#+HTML: <center> <img src="http://book.realworldhaskell.org/support/rwh-200.jpg" alt="RWH Cover" width="142" height="142" align="top"> </center>
#+END_SRC
:End:
+ Or as an Org link:
#+BEGIN_SRC org :tangle no
[[file:../assets/img/rwh-200.jpg]]
#+END_SRC
+ Or as local image via explicit html link:
#+BEGIN_SRC org :tangle no
,#+begin_export html
<center> <img src="../assets/img/rwh-200.jpg" alt="RWH Cover"
width="142" height="142" align="top"> </center>
,#+end_export
#+END_SRC
:One_long_line:
#+BEGIN_SRC org :tangle no
,#+HTML: <center> <img src="../assets/img/rwh-200.jpg" alt="RWH Cover" width="142" height="142" align="top"> </center>
#+END_SRC
:End:
For now, I use the approach of inserting an HTML URL:
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(defun insert-image-and-other-formats ()
"Insert image location obtained from #+IMAGE org keyword, as well as top-matter."
(let ((html.image.info
(concat "<center> <img src=\"" org.image
"\" alt=\"Musa's article image\""
" width=\"" (format "%s" org.imagewidth) "\" "
"height=\"" (format "%s" org.imageheight) "\" "
"align=\"top\"> </center>")))
(re-replace-in-file (concat AbsNAME ".html")
"<h1.*h1>"
(lambda (x) (concat x "\n" html.image.info "\n" (make-top-matter))))))
#+END_SRC
One possible extension would be to make parameters for image width and height.
Perhaps I will get to doing so in time.
Disclaimer: I wrote the following before I learned any lisp; everything below is
probably terrible.
#+BEGIN_SRC emacs-lisp
(defun re-replace-in-file (file regex whatDo)
"Find and replace a regular expression in-place in a file.
Terrible function … before I took the time to learn any Elisp!
"
(find-file file)
(goto-char 0)
(let ((altered (replace-regexp-in-string regex whatDo (buffer-string))))
(erase-buffer)
(insert altered)
(save-buffer)
(kill-buffer)))
#+END_SRC
Example usage:
#+BEGIN_EXAMPLE emacs-lisp
(re-replace-in-file "mysite.html"
"<h1.*h1>"
(lambda (x) (concat x "\n NICE")))
#+END_EXAMPLE
**** PDF Generation
:PROPERTIES:
:CUSTOM_ID: PDF-Generation
:END:
:Old_tangle_latex_approach:
The org block header for the following has
#+begin_src org :tangle no
:var webArticle = (file-name-sans-extension (buffer-name))
#+end_src
This allows us to use the buffer's name within the tangled LaTeX! Neato.
#+NAME: headers
BEGIN_SRC org :tangle headers.ltx :exports code :var webArticle = (file-name-sans-extension (buffer-name))
END_SRC
That is, the string webArticle is a parameter of this source block.
Later,
;; Replace webArticle with the name of the article in our headers.ltx file.
(re-replace-in-file "~/alhassy.github.io/content/headers.ltx" "webArticle" (lambda (x) NAME))
:End:
Finally, we weave everything together:
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(defun prepend-for-simple-latex (&rest extras)
"Prepend an Org file with a simple LaTeX preamble; perform extras before returing to source file.
"
(save-buffer)
(copy-file file.org file.src 'overwrite) (beginning-of-buffer)
(insert (s-join "\n" `(
"#+OPTIONS: toc:nil"
"#+LATEX_HEADER: \\usepackage[margin=0.5in]{geometry}"
"#+LATEX_HEADER: \\usepackage{fancyhdr}"
"#+LATEX_HEADER: \\setlength{\\headheight}{30pt}"
"#+LATEX_HEADER: \\lhead{} \\rhead{} \\cfoot{\\vspace{-3em} \\thepage} \\lfoot{} \\rfoot{}"
"#+LATEX_HEADER: \\chead{\\emph{This PDF was generated \\emph{ungracefully} from a web article on"
,(concat "#+LATEX_HEADER: \\url{https://alhassy.github.io/" NAME "/}}}")
"#+LATEX_HEADER: \\let\\doit=\\maketitle"
"#+LATEX_HEADER: \\def\\maketitle{\\doit\\thispagestyle{fancy}}"
"#+LATEX: \\pagestyle{fancy} \\tableofcontents \\newpage"
"#+LATEX_HEADER: \\usepackage{color}"
"#+LATEX_HEADER: \\definecolor{darkgreen}{rgb}{0.0, 0.3, 0.1}"
"#+LATEX_HEADER: \\definecolor{darkblue}{rgb}{0.0, 0.1, 0.3}"
"#+LATEX_HEADER: \\hypersetup{colorlinks,linkcolor=darkblue,citecolor=darkblue,urlcolor=darkgreen}"
"\n"
)))
(eval extras)
(copy-file file.src file.org 'overwrite)
(delete-file file.src)
(toggle enable-local-variables :all
(revert-buffer 'ignore-auto 'no-confirmation))
(copy-file file.pdf
(concat "~/alhassy.github.io" (s-chop-prefix ".." blogrepo-file.pdf))
'overwrite
)
)
(defun my-org-latex-export-to-pdf ()
"Produce a simple PDF that has wide margins and has a warning"
(prepend-for-simple-latex (lambda () (org-latex-export-to-pdf)))
)
#+END_SRC
**** Other Formats
:PROPERTIES:
:CUSTOM_ID: Other-Formats
:END:
Readers of the article may want to see the source
--which may contain code or parts not rendered in the article, such as exercise solutions.
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(defun get-raw-and-commits (url)
"
Given a github ‘url’, return the associated commits history and raw textual urls,
as a dotted pair.
For example,
url → https://github.com/⟪user⟫/⟪project⟫/blob/master/content/⟪filepath⟫
raw → https://raw.githubusercontent.com/⟪user⟫/⟪project⟫/master/content/⟪filepath⟫
commits → https://github.com/⟪user⟫/⟪project⟫/commits/master/content/⟪filepath⟫
"
(let* ((github "https://github.com/")
(comm (s-split "/" (s-chop-prefix github url)))
)
(setf (nth 2 comm) "commits")
`(
, (s-prepend "https://raw.githubusercontent.com/"
(s-replace "/blob/" "/" (s-chop-prefix github url)))
.
,(s-prepend github (s-join "/" comm))
)
)
)
#+END_SRC
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(defun make-html-link (url identifier)
"Yield HTML string code for a link to ‘url’ presented as ‘identifier’;
if ‘url’ is non-nil; otherwise, yield only the text ‘identifier’.
"
(if url
(concat "<a href=\"" url "\" target=\"_self\">" identifier "</a>")
identifier
)
)
#+END_SRC
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(defun make-top-matter ()
"This is the top-most text that appears right after the article's
title. It includes viewing the source, a PDF rendition, and
the most recent date of modification --unless the variables are nil.
"
(let* ((date (format-time-string "%Y-%m-%d"))
(content "")
(rawsrc (car (get-raw-and-commits org.sourcefile)))
(commits (cdr (get-raw-and-commits org.sourcefile)))
)
(dolist (var `( (,org.nopdf ,blogrepo-file.pdf "Read as PDF" )
(,org.nopdf nil " or " )
(nil ,rawsrc "See the source")
(,org.nomodificationdate nil
,(concat " ; " (unless org.nopdf "<br>")))
(,org.nomodificationdate ,commits "Last modified")
(,org.nomodificationdate nil ,(concat " on " date))
)
content)
(unless (car var) (setq content (concat content (make-html-link (cadr var) (caddr var)))))
)
(concat
(when org.draft (format "<center> Draft: %s </center>" (gensym)))
"<small> <center> ⟨ " content " ⟩ </center> </small>")
)
)
#+END_SRC
***** COMMENT org-html-postamble-format at the end of the webpage :old_approach:
:PROPERTIES:
:CUSTOM_ID: COMMENT-org-html-postamble-format-at-the-end-of-the-webpage
:END:
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(setq org-html-postamble-format
(let* ((nomorg (buffer-name))
(nom (file-name-sans-extension nomorg))
(src (make-html-link (concat "../content/" nomorg) "Org Source"))
(nompdf (concat blogrepo "/assets/pdfs/" nom ".pdf"))
(pdf (make-html-link nompdf "View me as a PDF"))
)
`(("en" ,(concat "<hr> <center> Last modified on %C ; " pdf " or see the " src " ; Contact me at %e </center>"))))
)
#+END_SRC
To avoid having a postamble altogether we could include
#+BEGIN_SRC org
,#+OPTIONS: html-postamble:nil
#+END_SRC
**** preview-article -- the heart of AlBasmala.el
:PROPERTIES:
:CUSTOM_ID: preview-article-the-heart-of-AlBasmala-el
:END:
We make the article in stages:
0. Go to the Org source and use the native Org utitlies to produce a coloured html file.
1. Insert the article image into that html file.
- We do so before producing the Jekyll markdown variant so that we can preview it correctly.
2. Remove some clutter from the html, yielding a markdown file.
3. Prepend the Jekyll header created using the keywords.
4. Move the markdown file to the _posts directory and show the html file in a browser.
:Nope:
We use toggle, a personal function from my init,
that toggles a variables value till the end of its form.
We use it below to disable all Emacs buffer local variables, do some work,
then re-enable them afterwards. Such variables generally require a query
since they could be dangerous, like erasing the disk, so we disable them temporarily.
:End:
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(local-set-key (kbd "<f7>") 'preview-article)
(cl-defun preview-article (&key (browser nil) (draft nil))
"Create and preview a the html form of the content.
A non-nil value for “org.nopdf” short-circuits the generation of a PDF,
thereby yielding a possibly faster execution.
A non-nil value for “:browser” opens the article using the default browser.
This may be undesirable, since it may open many tabs in your brower.
The ‘draft’ keyword option is here in case we want to override
whatever the local ‘#+DRAFT’ value may be.
"
(interactive)
(save-buffer)
(ensure-blog-is-serving)
(shell-command (concat "rm ~/alhassy.github.io/_posts/" jekyll.name.md))
(setq enable-local-variables nil)
(setq enable-local-eval nil)
(find-file file.org)
(GetOrgKeyWords)
(when draft (setq org.draft draft))
(org-html-export-to-html)
(insert-image-and-other-formats)
(shell-command (concat "tail -n +4 <" file.html " >" jekyll.name.md))
(find-file jekyll.name.md)
(beginning-of-buffer)
(MakeHeader)
(insert HEADER)
(save-buffer)
(kill-buffer jekyll.name.md)
(shell-command (concat "mv " jekyll.name.md " " blogrepo-posts))
(unless (or org.draft org.nopdf) (my-org-latex-export-to-pdf))
(when browser
(let* ((buf (concat "*AlBasmala*" NAME "*")))
(toggle kill-buffer-query-functions nil (ignore-errors (kill-buffer buf)))
(async-shell-command (concat "open http://localhost:4000/" NAME "/") buf)
)
)
(message "Article has been opened in your browser.")
(setq enable-local-variables t)
(setq enable-local-eval t)
)
#+END_SRC
**** COMMENT Version control :Deprecated:Before_magit_time:
:PROPERTIES:
:CUSTOM_ID: COMMENT-Version-control
:END:
A simple version control mechanism; will likely switch to magit in the future.
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(global-set-key (kbd "<f8>") 'commit)
(defun commit () "Commit changes to git in the form: “ChangedFile: CommitMessage”."
(interactive)
(preview-article)
(shell-command "rm *.html")
(let ((msg (read-string (format "Commit message for %s: " NAME))))
(shell-command (s-join " " (cons "git add" commitables)))
(shell-command (s-join " " (append (cons "git commit" commitables) (list (format "-m \"%s: %s\"" NAME msg)))))
)
)
#+END_SRC
**** Publish
:PROPERTIES:
:CUSTOM_ID: Publish
:END:
#+BEGIN_SRC emacs-lisp :tangle AlBasmala.el
(defun publish () "Send material to github pages."
(interactive)
(message (format "Publishing article: %s " NAME))
(shell-command "rm *.html")
(eshell)
(with-current-buffer "*eshell*"
(eshell-return-to-prompt)
(insert (concat "cd ~/alhassy.github.io/_posts/"
" ; "
(format "git add %s %s" jekyll.name.md blogrepo-file.pdf))
" ; "
(format "git commit %s %s -m \"%s: %s\"" jekyll.name.md blogrepo-file.pdf NAME "Article updated.")
" ; "
"git push")
(switch-to-buffer "*eshell*")
(eshell-send-input)
)
)
#+END_SRC
**** Usage
:PROPERTIES:
:CUSTOM_ID: Usage
:END:
#+BEGIN_EXPORT html
<table style="width:100%">
<tr>
#+END_EXPORT
#+HTML: <td>
The example source,
#+HTML: <small>
#+HTML: </small> </td>
#+HTML: <td> Results in, <br> <br> <br>
#+BEGIN_EXPORT html
<iframe src="../assets/demoing_template.html" style="width:100%" height="487">
alternative content for browsers which do not support iframe.
</iframe>
#+END_EXPORT
#+HTML: </td>
#+BEGIN_EXPORT html
</tr>
</table>
#+END_EXPORT
#+latex: In the LaTeX format, this content is not supported.
**** footer
:PROPERTIES:
:CUSTOM_ID: footer
:END:
NOTE: It takes about 20secs ~ 1min for the changes to be live on github pages.
** Using org-static-block
:PROPERTIES:
:CUSTOM_ID: https-github-com-bastibe-org-static-blog-org-static-block
:END:
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.
* COMMENT Abstract :ignore:
:PROPERTIES:
:CUSTOM_ID: Abstract
:END:
How my blog is setup (•̀ᴗ•́)و
Here are some notable features of my blog.
+ Org-mode, a rich markup, to write articles ‿
+ Tags and RSS feed for blog articles --- §initial-setup
+ A nice blog banner --- §blog-banner
+ Dynamically highlighting code from references in prose --- §blog-banner
+ Tooltips, folded regions, and badges --- badge:org-special-block-extras|2.0|informational|https://alhassy.github.io/org-special-block-extras/|Gnu-Emacs
+ Overall nice looking HTML style --- org-notes-style
+ Beautiful math using LaTeX notation, $\forall \phi ⇒ \exists \phi$ ---
§MathJax-Support
+ A floating, yet unobtrusive, table of contents --- §floating-toc
+ Headings are clickable links with the resulting anchors being
Github-like --- §ensuring-useful-html-anchors and §clickable-headlines
+ Comments for blog readers --- §Comments
+ Articles have dedicated images, §Images, which are displayed
on the blog's welcome page along with the article's abstract, §Index
- Auto-generated index/sitemap that shows an image and short abstract of each article
+ Augment article footers to link to the Org source and to the Github history
--- §footers
- Org source is colourised!
+ Article titles may contain arbitrary html: ... yet still render nicely in both the frame tab and page title,
thanks to doc:org-link/blog.
+ Dynamically adjust amount of time left until user finishes reading the
article --- §footers
+ Style inline code and tables --- §curvy-blocks
+ Unfurling links --- §unfurling
* Image Org Link :details_imagelink:
A quick way to embed clickable images, along with tooltip credits and other configs.
#+begin_src emacs-lisp :exports code
(org-deflink image
"Provide a quick way to insert images along with credits via tooltips.
Example usage:
image:https://upload.wikimedia.org/wikipedia/commons/3/33/Heisokudachi.svg|100|100
image:URL|WIDTH|HEIGHT|CENTER?|CREDIT?
"
(-let [(image width height center? credit?) (s-split "|" o-label)]
(-let [unsplash (cl-second (s-match ".*unsplash.com/photos/\\(.*\\)" image))]
(let* ((href (if unsplash (concat "https://unsplash.com/photos/" unsplash) image))
(title (format "Image credit “%s”" (or credit? (if unsplash (concat "https://unsplash.com/photos/" unsplash) image))))
(src (if unsplash (format "https://source.unsplash.com/%s/%sx%s" unsplash width height) image))
(it (format "<a href=\"%s\" class=\"tooltip\" title=\"%s\"><img src=\"%s\" alt=\"Article image\"
width=\"%s\" height=\"%s\" align=\"top\"/></a>"
href title src width height)))
(if center?
(format "<center> %s </center>" it)
it)))))
#+end_src
This will eventually be part of org-special-block-extras.
* TODO COMMENT Automatically Generate PDFs upon Save :details_pdfs:
Here is my ~/.latexmkrc file: It previews PDFs using Emacs, uses LuaLaTeX for making PDFs, and to update the PDF viewer
please change focus to the PDF file.
#+begin_src shell :tangle "~/.latexmkrc"
$pdf_previewer="emacsclient %S";
$pdflatex = 'lualatex -interaction=nonstopmode -synctex=1 %O %S';
$pdf_update_method = 4;
$pdf_update_command = "emacsclient %S &";
#+end_src
Then files that want to have this feature should end with:
#+begin_src org :tangle no
,* Local Variables :ignore:
# Ensure EmacsClient can connect to running emacs, enable automatic reverts for whenever PDFs change.
# Local Variables:
# eval: (server-start)
# eval: (global-auto-revert-mode)
# eval: (add-hook 'after-save-hook 'org-latex-export-to-latex nil t)
# eval: (compile "latexmk -pdf -pvc -pdflatex='lualatex -shell-escape -interaction nonstopmode'")
# End:
#+end_src
* Redefining Org Section for purposes of blocks :details_deftag:
image:https://i.redd.it/rre5ggpx9jya1.png|100%|100%|center|Musa
(Reddit Post)
This will eventually be part of org-special-block-extras.
#+BEGIN_SRC emacs-lisp :export none
(defmacro org-deftag (name args docstring &rest body)
"Re-render an Org section in any way you like, by tagging the section with NAME.
That is to say, we essentially treat tags as functions that act on Org headings:
We redefine Org sections for the same purposes as Org special blocks.
Anyhow:
ARGS are the sequence of items seperated by underscores after the NAME of the new tag.
BODY is a form that may anaphorically mention:
- O-BACKEND: The backend we are exporting to, such as `latex' or `html'.
- O-HEADING: The string denoting the title of the tagged section heading.
DOCSTRING is mandatory; everything should be documented for future maintainability.
The result of this anaphoric macro is a symbolic function name `org-deftag/NAME',
which is added to `org-export-before-parsing-hook'.
----------------------------------------------------------------------
Below is the motivating reason for inventing this macro. It is used:
,** Interesting, but low-priority, content :details_red:
Blah blah blah blah blah blah blah blah blah blah blah.
Blah blah blah blah blah blah blah blah blah blah blah.
Here is the actual implementation:
(org-deftag details (color)
\"HTML export a heading as if it were a <details> block; COLOR is an optional
argument indicating the background colour of the resulting block.\"
(insert \"\n#+html:\"
(format \"<details style=\\\"background-color: %s\\\">\" color)
\"<summary>\" (s-replace-regexp \"^\** \" \"\" heading) \"</summary>\")
(org-next-visible-heading 1)
(insert \"#+html: </details>\"))
"
(let ((func-name (intern (format "org-deftag/%s" name))))
`(progn
(cl-defun ,func-name (o-backend)
,docstring
(outline-show-all)
(org-map-entries
(lambda ()
(kill-line)
(let ((o-heading (car kill-ring)))
(if (not (s-contains? (format ":%s" (quote ,name)) o-heading 'ignoring-case))
(insert o-heading)
(-let [,args (cdr (s-split "_" (car (s-match (format "%s[^:]*" (quote ,name)) o-heading))))]
(setq o-heading (s-replace-regexp (format ":%s[^:]*:" (quote ,name)) "" o-heading))
,@body)
(insert "\n"))))))
(add-hook 'org-export-before-parsing-hook (quote ,func-name))
(quote ,func-name))))
#+END_SRC
#+BEGIN_SRC emacs-lisp :export none
(org-deftag details (anchor color)
"HTML export a heading as if it were a <details> block; ANCHOR & COLOR are optional
arguments indicating the anchor for this block as well as the background colour of the resulting block.
For example, in my blog, I would use :details_rememberthis_#F47174: to mark a section as
friendly-soft-red to denote it as an “advanced” content that could be ignored
on a first reading of my article.
Incidentally, `orange' and `#f2b195' are also nice ‘warning’ colours."
(insert "\n#+html:"
(format "<div>%s <details class=\"float-child\" style=\"background-color: %s\">"
(if anchor (format "<a style=\"width: 1%%;float: left; padding: 0px\" id=\"%s\" href=\"#%s\">🔗</a>" anchor anchor) "")
color)
"<summary> <strong> <font face=\"Courier\" size=\"3\" color=\"green\">"
(s-replace-regexp "^\** " "" o-heading)
"</font> </strong> </summary>")
(org-next-visible-heading 1)
(insert "#+html: </details> </div>"))
#+END_SRC
** COMMENT Demo
See: https://www.reddit.com/r/emacs/comments/13bdlck/tags_are_functions_of_org_sections_%E1%B4%97%D9%88/
html: <div style="padding-bottom: 30cm;"></div>
*** Tags are functions of Org sections :quote_blue:
Just as a source block is a function on a region of text, so too a tag is
construable as a function operating on an Org section. Thanks to doc:org-deftag (•̀ᴗ•́)و
For instance, this tree is tagged :quote: with the single parameter blue.
Look to the buffer to the right for the resulting HTML rendition.
*** Here is the actual implementation :details_quoteSource:
The implementation is interesting, but it is of low-priority and so it is tagged
with :details: which folds it away via a <details> element, with an anchor.
#+begin_src emacs-lisp
(org-deftag quote (color)
"HTML export a section as if it were a <blockquote> block; COLOR is an optional
argument indicating the text colour of the resulting block."
(insert "\n#+html:" (format "<blockquote style=\"color: %s\">" color))
(org-next-visible-heading 1)
(insert "#+html: </blockquote>"))
#+end_src
See http://alhassy.com/AlBasmala#deftag for the definition of org-deftag.
*** Bye! :ignore:
Have a great evening!
html: <div style="padding-bottom: 30cm;"></div>
** Known bug and proposed fix. :noexport:
Warning!
#+begin_src org :tangle no
,* Useful notes :noexport:
Be a good person.
,* Advice to readers :details:
Since this section is rewritten as a <details> block,
it will, by structure, reside as an element in the previous
tree which is not exported! This this tree wont be visible!
#+end_src
TODO: Fix the above bug by ensuring all altered headings are preserved as
follows.
#+begin_src org :tangle no
,* original heading :FOO:
becomes
,* original heading :ignore:
⦃transformed heading⦄
#+end_src
This way we ensure that the new tree is completely independent of the previous
tree.
*** COMMENT Posterity :Delete_when_things_settle:
:PROPERTIES:
:CUSTOM_ID: COMMENT-Posterity
:END:
#+BEGIN_SRC emacs-lisp :export none
(defun my-headline-alteration (backend)
"BACKEND is the export back-end being used, as a symbol."
(setq first-heading t)
(outline-show-all)
(org-map-entries
(lambda ()
(kill-line)
(let ((heading (car kill-ring)))
(if (not (s-contains? ":NOPE:" heading 'ignoring-case))
(insert heading)
(insert heading) (insert "NIIIIICE")
(org-next-visible-heading 1)
(insert "WOW :: " (s-chop-prefix "\** " heading))
(insert "\n") )
)
)))
(add-hook 'org-export-before-parsing-hook 'my-headline-alteration)
(remove-hook 'org-export-before-parsing-hook 'my-headline-alteration)
#+END_SRC
(org-next-visible-heading 1)
* TODO COMMENT Glossary Library of Arabic Linguistic Jargon
:PROPERTIES:
:CUSTOM_ID: COMMENT-Glossary-Library-of-Arabic-Linguistic-Jargon
:END:
#+begin_src emacs-lisp
(push "~/blog/posts/arabic-glossary.org" org-docs-libraries)
#+end_src
* COMMENT Presentation Order
:PROPERTIES:
:CUSTOM_ID: COMMENT-Presentation-Order
:END:
We start off with
1. the styling I'd like to have,
2. then move on to grouping those styles togther,
3. then making that result practical to use anywhere via a new Org-mode link, namely doc:blog,
4. then doing this blog-link injection seemlessly/automatically.
5. Wrapping all of this up into a nice "article preview" background function.
6. Finally, hooking this stuff up into the org-static-blog setup.
- Which I use since it provides me with a nice index.html to showcase my posts,
a tagging mechanism, an RSS mechanism, etc.
* COMMENT Preview :move_to_init:Mention_in_AlBasmala:
:PROPERTIES:
:CUSTOM_ID: COMMENT-Preview
:END:
#+begin_src emacs-lisp
(setq org-preview-html-viewer 'xwidget)
(org-preview-html-mode) TODO. Something in my init.el breaks this package!?!
(xwidget-webkit-browse-url "https://github.com/adithyaov/helm-org-static-blog")
(advice-add #'xwidget-webkit-browse-url :before (lambda (&rest _) (doom-modeline-mode 0)))
(advice-add #'xwidget-webkit-browse-url :after (lambda (&rest _) (--map (with-current-buffer it (setq mode-line-format "%b %p L%l C%c")) (buffer-list)) ))
(advice-add #'doom-modeline-mode :before (lambda (&rest _) (-let [kill-buffer-query-functions nil]
(mapcar #'kill-buffer (--filter (s-starts-with? "*xwidget" (buffer-name it)) (buffer-list)))
)))
#+end_src
* Typical workflow: How do I publish an article?
:PROPERTIES:
:CUSTOM_ID: COMMENT-Typical-workflow-How-do-I-publish-an-article
:END:
1. Open an Org-mode buffer ---or invoke doc:blog/new-article.
2. ℰ𝓁𝒾𝓈𝓅﴾(org-babel-load-file "~/blog/AlBasmala.org")﴿
3. Invoke doc:blog/preview to get live WYSIWYG in an adjacent buffer after every
save kbd:C-x_C-s.
4. Until content:
1. Write, write, and write!
2. kbd:C-x_C-s
3. Preview
Consider using kbd:C-x_n_s, or kbd:C-x_n_n, to focus your attention on a
particular section, thereby dramatically increasing the speed at which the
preview renders.
5. Execute doc:blog/publish-current-article when you're done.
- This gets the new article showing up in index, RSS, archive, and updates
the tags.
- NOTE: It takes about 20secs ~ 1min for the changes to be live on github pages.
* Why not use an existing blogging platform?
:PROPERTIES:
:CUSTOM_ID: Why-not-use-an-existing-blogging-platform
:END:
I dislike coding in any website's primitive textarea, likewise for general
writing.
For a brief period, I used Hashnode: I'd write in Emacs, then
kbd:C-c_C-e_C-b_h_h to export current body as HTML, then paste that into
Hashnode. However, Hashnode does not respect my CSS nor my inline JS. This was
problematic, since I wanted to write a tiny root-meaning program to learn Arabic
and to have a tiny web-app for Arabic shows for my kids.
* “Goal-driven development” ---or, Getting Started: doc:blog/new-article
:PROPERTIES:
:CUSTOM_ID: blog-new-article
:END:
<<new-article>>
<<initial-setup>>
Here's what an example article source looks like:
#+begin_example org
#+title: Example Article
#+author: Musa Al-hassy
#+email: alhassy@gmail.com
#+filetags: demo math
#+fileimage: emacs-birthday-present.png
#+description: This is an example article.
,* Abstract :ignore:
Here is the extended abstract, which is rather concrete,
regarding the goals of this article.
,* Body
I like maths.
,* Conclusion
I like programming.
#+end_example
Almost all #+keyword:⋯ lines become part of the JSON file
https://alhassy.com/posts.json, that I'll use to generate the index landing
page.
#+html: <div style="overflow-y: scroll; height:250px;">
#+begin_src emacs-lisp :tangle no :results replace value :wrap example js :exports results
(f-read-text "~/blog/posts.json")
#+end_src
#+RESULTS:
#+begin_example js
[
{
"file": "java-cheat-sheet",
"title": "Java CheatSheet",
"date": "2023-12-25 Mon",
"image": "modern-java.png 88% 88%",
"description": "Quick reference for an old-school-cool high-level language ^_^",
"tags": "java cheat-sheet",
"url": "https://alhassy.com/java-cheat-sheet",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/java-cheat-sheet.org",
"abstract": "\n#+begin_center\n#+html: This is a quick reference of concepts in modern Java.\n\nbadge:PDF|colorful_cheat_sheet|success|https://alhassy.com/java-cheat-sheet.pdf|read-the-docs\n\n# badge:license|GNU_3|informational|https://www.gnu.org/licenses/gpl-3.0.en.html|read-the-docs\ntweet:https://alhassy.com/java-cheat-sheet\nbadge:|buy_me_a_coffee|gray|https://www.buymeacoffee.com/alhassy|buy-me-a-coffee\nbadge:contributions|welcome|green|https://github.com/alhassy/alhassy.github.io/issues\n# badge:author|musa_al-hassy|purple|https://alhassy.github.io/|nintendo-3ds\n# badge:Warning|Incomplete_DRAFT|red||codeigniter\n#+end_center\n\n# @@html: <br> @@\n\nModern Java is a strongly-typed, eagery evaluated, case sensative, yet\nwhitespace insensative language. It uses hierarchies of classes/types\nto structure data, but also has first-class support for\nfunctional-style algebraic datatypes.\n\nJava programs are made up of ‘classes’, classes contain methods, and methods contain commands. To just try out a\nsnippet of code, we can\n+ Open a terminal and enter ~jshell~; then enter:\n #+begin_src java\n1 + 2 // The jshell lets you try things out!\n\n// Say hello in a fancy way\nimport javax.swing.*;\nJOptionPane.showMessageDialog(new JFrame(), \"Hello, World!\");\n\n#+end_src\n\n+ Alternatively, in IntelliJ, click /Tools/ then /Groovy Console/ to try things out!\n+ Finally, [[http://alhassy.com/making-vscode-itself-a-java-repl.html][VSCode]] allows arbitrary Java code to be sent to a ~jshell~\n in the background(!) and it echoes the result in a friendly way.\n\n# A program cannot consist of only commands. Java commands must be inside functions, and functions must be inside classes.\n#\n# Imagine a sofa. A sofa cannot exist on its own. It exist in a room somewhere. And a room also cannot exist on its own. A room is located in some house. Or, you could say that the house is divided into rooms, and those rooms contain things.\n#\n# Java programs are made up of classes, classes contain methods, and methods contain commands.\n\n# A minimal program must consist of at least one class, which must have at least\n# one method (function) that marks the program's starting point. This method must\n# be named main.\n\n:MWE:\nIn order to run a java program, it must have a main method as an entry point.\n\n#+begin_src java\n public class LearnJava {\n // In order to run a java program, it must have a main method as an entry\n // point.\n public static void main(String[] args) {\n System.out.println(\"Hello World!\");\n\n // Use System.out.printf() for easy formatted printing.\n System.out.printf(\"pi = %.5f\", Math.PI); // => pi = 3.14159\n }\n }\n#+end_src\n:End:\n\n** Web reference :ignore:\n\n#+macro: begin-ignore-html #+html: <!--\n#+macro: end-ignore-html #+html: -->\n\n#+latex: \\vspace{-1em}\n{{{begin-ignore-html()}}}\nTo be terse, lots of content is not shown in this [[http://alhassy.com/java-cheat-sheet.pdf][PDF]], but is shown in the *[[https://alhassy.com/java-cheat-sheet][HTML]]*\nversion.\n{{{end-ignore-html()}}}\n"
},
{
"file": "repl-driven-development",
"title": "💐 Repl Driven Development: /Editor Integrated REPLs for all languages/ 🔁",
"date": "2023-09-08 Fri",
"image": "rdd-benefits.png",
"description": "Press “C-x C-e” to send any piece of code (in any language) to a REPL in the background, within Emacs!",
"tags": "repl-driven-development vscode emacs javascript java python lisp clojure haskell arend purescript idris racket",
"url": "https://alhassy.com/repl-driven-development",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/repl-driven-development.org",
"abstract": "\n#+begin_center\nbadge:Warning|Incomplete_DRAFT|red||codeigniter\n#+end_center\n\nThe melpa:repl-driven-development package makes the philosophy of REPL Driven\nDevelopment (RDD) accessible to any language that has a primitive CLI repl: /The\nresult is an Emacs interface for the language, where code of your choosing is/\n/evaluated, and results are echoed at your cursor in overlays./\n\nThat is, with Repl *green:aided* development, you make software by starting with\nan already working program (i.e., the repl) then *green:incrementlly* “teach it”\nto be the program you want, by defining & redefining things. Until satisfied,\nloop: Type/modify code *[[green:in your editor]]*, press some keys to evaluate what you\nwrote/modified /in the currently running system/, and explore/test the resulting\nruntime.\n# Eventually, save your code as a clean text file.\n\n/RDD is programming emphasising fast & rich feedback from a running system./ RDD\nis fantastic for quickly /teaching/exploring/ an idea; as such, the running\nexample of this article will be on servers ---no prior experience with servers\nis assumed.\nThe main examples will be in JavaScript, Python, and Java. (Since /JavaScript is\njust Lisp in C clothing/, we will not discuss Lisp.) Since Java is verbose, the\npower of REPLs really pays off when exploring a new idea. We see how many\nimports and setup-code simply disappear in the RDD approach, letting you focus\non the core idea you're exploring/teaching. For comparison, a traditional\nself-contained Java server program is ~30 lines long whereas the focused RDD\napproach is ~4 lines long.\n#\n# + We begin with JavaScript: Write some code, and see it interact with your browser.\n# + Then Python: Write some code, and see it interact with the terminal.\n\n# badge:repl-driven-development|1.4|informational|https://github.com/alhassy/repl-driven-development|Gnu-Emacs\n\n#+begin_center\nbadge:license|GNU_3|informational|https://www.gnu.org/licenses/gpl-3.0.en.html|read-the-docs\ntweet:https://alhassy.com/repl-driven-development\nbadge:|buy_me_a_coffee|gray|https://www.buymeacoffee.com/alhassy|buy-me-a-coffee\n@@TODO: FIX contributions URL@@\nbadge:contributions|welcome|green|https://github.com/alhassy/alhassy.github.io/issues\n#+end_center\n\n# @@html: <br> @@\n\n/tdlr:/ This library provides the Emacs built-in kbd:C-x_C-e behaviour for\narbitrary languages, provided they have a primitive cli REPL.\n"
},
{
"file": "arabic-cheat-sheet",
"title": "Arabic CheatSheet",
"date": "2023-06-14 Wed",
"image": "arabic-irab.png 100% 100%",
"description": "Quick reference for the Arabic language; Modern Standard Arabic",
"tags": "arabic cheat-sheet",
"url": "https://alhassy.com/arabic-cheat-sheet",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/arabic-cheat-sheet.org",
"abstract": "\n#+latex: \\iffalse\n\n#+begin_center\n#+html: This is a quick reference of concepts in the Arabic language.\n\nbadge:PDF|colorful_cheat_sheet|success|https://alhassy.com/arabic-cheat-sheet.pdf|read-the-docs\n\n# badge:license|GNU_3|informational|https://www.gnu.org/licenses/gpl-3.0.en.html|read-the-docs\ntweet:https://alhassy.com/arabic-cheat-sheet\nbadge:|buy_me_a_coffee|gray|https://www.buymeacoffee.com/alhassy|buy-me-a-coffee\n#+end_center\n\n# @@html: <br> @@\n\n#+latex: \\fi\n"
},
{
"file": "family-tree",
"title": "My Family Tree",
"date": "2023-02-02 Thu",
"image": "../images/family-tree.png 88% 88%",
"description": "من هو في شجرة العائلة القديمة",
"tags": "family",
"url": "https://alhassy.com/family-tree",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/family-tree.org",
"abstract": "\n#+begin_center\nbadge:Warning|Incomplete_DRAFT|red||codeigniter\n#+end_center\n\nWho's who in the old family tree\n"
},
{
"file": "karate",
"title": "A Brisk Introduction to Karate",
"date": "2023-02-02 Thu",
"image": "https://www.usadojo.com/wp-content/uploads/2013/08/Goju-Ryu-Karate-600x300.png 88% 88%",
"description": "Discovering what be ka-ra-te",
"tags": "karate",
"url": "https://alhassy.com/karate",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/karate.org",
"abstract": "\n#+begin_center\nbadge:Warning|Incomplete_DRAFT|red||codeigniter\n#+end_center\n\nWhat are the basic forms of Karate? What is Karate?\n\n/“The ultimate aim of karate lies not in victory or defeat but in the perfection\nof the character of its participants … to subdue the enemy without fighting is/\n/the highest skill, know your enemy and know yourself, in a hundred battles you\nwill not be defeated”/ says Gichin Funakoshi ---known as The Father of Modern Karate.\n\n/Karate/ means “empty hand” and was developed on the island of Okinawa ---part of\nmodern-day Japan. The major styles (“Ryu”) are Shotokan, Wado-ryu,\nShito-ryu, and Goju-ryu ---many other styles of Karate are derived from these\nfour. I'm focusing on Goju-Ryu in this article: Goju-Ryu was founded by Chojun\nMiyagi; whose colleague, Gichin Funakosi, founded Shotokan-Ryu.\n\n#+begin_center\nimage:http://www.traditionalshotokankarate.co.uk/kara-te-do.gif\n#+end_center\n\nOccasionally one sees /Karate-Do/, which means “the way of the empty hand”.\nThis usage is a reminder that Karate is not just about fighting, but is also\na spiritual discipline.\n\nThe basic form of Goju-Ryu karate is Sanchin, “3 battles”: The battles of the\nmind, the body, and the spirit. However, this was considered a bit difficult\nfor beginners, and so new forms were needed as a way of introducing fundamental\nkarate forms to a wider audience. There are the “peaceful and safe” forms known\nas Pinan/Heian, the “first course” or Taikyoku forms, the “popularising forms”\nknown as Fukyugata ---the second of which was rebranded as “attack & smash”,\nGekaisai--- and, finally, there is the so-called Dachi-waza form. This last one\nis relatively new, and aims to be a smooth introduction to the world of\nforms/Kata.\n\nIn this article, I'd like to discuss the basic forms and their relationships.\n#+begin_center\nimage:https://www.sullivanskarateschool.com/wp-content/uploads/2019/07/saifa.gif\n#+end_center\n"
},
{
"file": "arabic-word-order",
"title": "A Brisk Introduction to the Fundamentals of Arabic Grammar, نحو",
"date": "2022-11-03 Thu",
"image": "arabic-irab.png 100% 100%",
"description": "Discovering how to say “a/an/the” in Arabic leads onto a zany adventure into case markings, gender, annexation, non-verbal sentences, plurals, and concludes with whether “Muslims” is مسلمون or مسلمین ---it's both!",
"tags": "arabic",
"url": "https://alhassy.com/arabic-word-order",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/arabic-word-order.org",
"abstract": "\n# I'd like to discuss the importance of Arabic's short vowels and their use to give Arabic flexible word order.\n\nIn short: In English sometimes we mess-up between “I/me/my”, likewise in Arabic we might mess up with “ابو / ابا / ابي”:\nThese are just اب followed by one of ا/ي/و (which are the pronounced case endings!)\n\n#+begin_center\n~ ~ ~ ~ ~ ~ ~\n#+end_center\n\n How do Arabs say the English “a/an/the”, as in “an apple” or “the chair”? Easy! By default, all words are /indefinite/\n (“a/an”); and made /definite/ (“the”) by adding الـ to the front of the word.\n\n But... there's some subtleties, which first require us to discuss vowel markings... which also change if the /feminine\n marker/ ة is used, so we also need to briefly discuss gender.\n\nEnglish relies on /word order/ for meaning; for example, /Jim hit Bob/ is a sentence where the person doing the action is\n/Jim/ and we know it has to be /Jim/, and not /Bob/, since /Jim/ is the word /before/ the action /hit/. However, in Arabic words can\nbe ordered in almost any way you like! Then how do we identifiy who does an action? We use *[[green:case markings]]*: We add small\nsymbols to the end of words to indiciate the role they play in a sentence.\n\nWith vowel markings, we can finally flesh-out the nature of\n“a/an/the” in Arabic... but then something wild happens if we stick\nan (in)definite /followed by/ a definite! We get the concepts of ownership and complete sentences that don't need a verb!\n\nFinally, we conclude with an explanation of why in the world English Qurans use the single word /muslim/ where's Arabic\nQurans use both مسلمون and مسلمين.\n"
},
{
"file": "arabic-roots",
"title": "Arabic Roots: The Power of Patterns",
"date": "2022-11-02 Wed",
"image": "https://unsplash.com/photos/Ejdemp9O7Po",
"description": "Let's learn about how the Arabic language makes use of “roots” to obtain various words",
"tags": "arabic javascript emacs",
"url": "https://alhassy.com/arabic-roots",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/arabic-roots.org",
"abstract": "\nI want to quickly introduce the Arabic language, through its “root system” ---i.e., most words have 3-letters at their\ncore--- and how these roots can be placed in “patterns” to obtain new words.\n\nI'd like to take a glance at Arabic's Verb Forms: These give you 10 words for each root!\n\nSome *green:interesting* concepts will also be mentioned, for those curious, but should be ignored on a first\nreading. These will be hidden away in /clickable/foldable/ regions.\n\nThese are notes of things that I'm learning; there's likely errors.\n"
},
{
"file": "arabic-glossary",
"title": "Glossary of Arabic Linguistic Terms",
"date": "2022-11-01 Tue",
"image": "arabic-irab.png 100% 100%",
"description": "Definitions, and discussions, of jargon relating to learning the Arabic language.",
"tags": "arabic",
"url": "https://alhassy.com/arabic-glossary",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/arabic-glossary.org",
"abstract": "Definitions, and discussions, of jargon relating to learning the Arabic language."
},
{
"file": "cartoon",
"title": "Arabic Cartoons",
"date": "2022-10-21 Fri 11:20",
"image": "https://upload.wikimedia.org/wikipedia/en/6/64/Dora_and_Boots.jpg 350 300",
"description": "A simple interface to watch the engaging Arabic cartoons",
"tags": "family arabic javascript",
"url": "https://alhassy.com/cartoon",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/cartoon.org",
"abstract": "\nA simple interface to watch the engaging Arabic cartoons.\n"
},
{
"file": "making-vscode-itself-a-java-repl",
"title": "💐 Making VSCode itself a Java REPL 🔁",
"date": "2022-09-05 Mon",
"image": "https://github.com/alhassy/easy-extensibility/blob/main/graphics/repl-java.gif?raw=true 90% 90%",
"description": "VSCode evaluates Java code wherever it sees it, by sending it to a JShell in the background, and echos the results in a friendly way!",
"tags": "repl-driven-development vscode emacs javascript java python ruby clojure typescript haskell lisp",
"url": "https://alhassy.com/making-vscode-itself-a-java-repl",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/making-vscode-itself-a-java-repl.org",
"abstract": "\nVSCode evaluates Java code wherever it sees it, by sending it to a JShell in the background, and echos the results in a\nfriendly way!\n\nThis is achieved with a [[https://github.com/alhassy/easy-extensibility][meta-extension for VSCode]] that makes VSCode into a living, breathing, JS interpreter: It can\nexecute arbitrary JS that alters VSCode on-the-fly. /(Inspired by using Emacs and Lisp!)/\n\nThe relevant docs show how to make a similar REPL for [[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1417-L1420][Python]], [[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1459-L1462][Ruby]], [[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1475-L1479][Clojure]], [[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1490-L1494][Common Lisp]], [[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1509-L1515][JavaScript]], [[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1527-L1536][Typescript]],\n[[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1553-L1557][Haskell]], and of-course [[https://github.com/alhassy/easy-extensibility/blob/65572a283e4864d9bef157b438c33f4e47276e3a/vscodejs/index.js#L1575-L1585][Java]].\n"
},
{
"file": "vscode-is-itself-a-javascript-repl",
"title": "💐 VSCode is itself a JavaScript REPL 🔁",
"date": "2022-08-17 Wed",
"image": "https://raw.githubusercontent.com/alhassy/easy-extensibility/main/graphics/repl.gif 90% 90%",
"description": "A meta-extension for VSCode that makes VSCode into a living, breathing, JS interpreter: It can execute arbitrary JS that alters VSCode on-the-fly. A gateway into the world of Editor Crafting!",
"tags": "repl-driven-development vscode emacs javascript",
"url": "https://alhassy.com/vscode-is-itself-a-javascript-repl",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/vscode-is-itself-a-javascript-repl.org",
"abstract": "\nA meta-extension for VSCode that makes VSCode into a living, breathing, JS interpreter: It can execute arbitrary JS that\nalters VSCode on-the-fly. A gateway into the world of Editor Crafting!\n\n| /(Inspired by using Emacs and Lisp!)/ |\n"
},
{
"file": "TypedLisp",
"title": "Typed Lisp, A Primer",
"date": "2019-08-21 19:29",
"image": "emacs-birthday-present.png",
"description": "Exploring Lisp's fine-grained type hierarchy.",
"tags": "types lisp program-proving emacs",
"url": "https://alhassy.com/TypedLisp",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/TypedLisp.org",
"abstract": "\n#+TOC: headlines 2\n\nLet's explore Lisp's fine-grained type hierarchy!\n\nWe begin with a shallow comparison to Haskell, a rapid tour of type theory,\ntry in vain to defend dynamic approaches, give a somewhat humorous account of history,\nnote that you've been bamboozled ---type's have always been there---,\nthen go into technical details of some Lisp types, and finally conclude by showing\nhow /macros permit typing/.\n\n# Lisp types are fine-grained; e.g., rather than ~int~ we may use a spefied range of numbers,\n# or a set of specfiied elements, intersections, unions, and complements of types, and\n# even arbitrary predicates!\n\nGoals for this article:\n\n1. Multiple examples of type constructions in Lisp.\n2. Comparing Lisp type systems with modern languages, such as Haskell.\n3. Show how algebraic polymorphic types like ~Pair~ and ~Maybe~ can be defined in Lisp.\n Including heterogeneously typed lists!\n4. Convey a passion for an elegant language.\n5. Augment Lisp with functional Haskell-like type declarations ;-)\n\nUnless suggested otherwise, the phrase “Lisp” refers to\n[[https://www.gnu.org/software/emacs/manual/html_mono/cl.html#index-cl_002ddeftype-14][Common Lisp as supported by Emacs Lisp]]. As such, the resulting discussion\nis applicable to a number of Lisp dialects\n---I'm ignoring editing types such as buffers and keymaps, for now.\n"
},
{
"file": "three-minute-thesis",
"title": "Have you ever packaged anything?",
"date": "2019-03-12 19:29",
"image": "packages.png 250 250",
"description": "I learned something neat, and wanted to share!",
"tags": "packages dependent-types",
"url": "https://alhassy.com/three-minute-thesis",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/three-minute-thesis.org",
"abstract": "\n#+TOC: headlines 2\n\n# copied from the repo\n\nHerein I try to make my current doctoral research accessible to the average person:\nExtending dependently-typed languages to implement module system features in the core\nlanguage. It's something I can direct my family to, if they're inclined to know what it is\nI've been doing lately.\n\nThe technical matter can be seen at the associated website\n─[[https://alhassy.github.io/next-700-module-systems-proposal/][The Next 700 Module Systems]]─ which includes a poster, slides, and a demo.\n\nExcluding the abstract, this is my thesis proposal in /three minutes/ (•̀ᴗ•́)و\n"
},
{
"file": "InteractiveWayToC",
"title": "An Interactive Way To C",
"date": "2019-01-12 19:29",
"image": "interactive_way_to_c.png 450 450",
"description": "Learning C program proving using Emacs --reminiscent of Coq proving with Proof General.",
"tags": "program-proving c emacs frama-c",
"url": "https://alhassy.com/InteractiveWayToC",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/InteractiveWayToC.org",
"abstract": "\n#+TOC: headlines 2\n\n# copied from the repo\n\nDo you know what the above program accomplishes?\nIf you do, did you also spot a special edge case?\n\nWe aim to present an approach to program proving in C using a minimal Emacs setup\nso that one may produce literate C programs and be able to prove them correct\n--or execute them-- using a single button press; moreover the output is again in Emacs.\n\nThe goal is to learn program proving using the Frama-C tool\n--without necessarily invoking its gui-- by loading the source of this file into\nEmacs then editing, executing, & proving as you read along.\nOne provides for the formal specification of properties of C programs --e.g., using ACSL--\n which can then be verified for the implementations using tools that interpret such annotation\n--e.g., Frama-C invoked from within our Emacs setup.\n\nRead on, and perhaps you'll figure out how to solve the missing ~FixMe~ pieces 😉\n\nThe intent is for rapid editing and checking.\nIndeed, the Frama-c gui does not permit editing in the gui, so one must switch between\ntheir text editor and the gui.\n[[https://orgmode.org/worg/org-tutorials/org4beginners.html][Org mode beginning at the basics]] is a brief tutorial that covers a lot of Org and,\nfrom the get-go, covers “the absolute minimum you need to know about Emacs!”\n\nIf anything, this effort can be construed as a gateway into interactive theorem proving\nsuch as with Isabelle, Coq, or Agda.\n\nThe article /aims/ to be self-contained ---not even assuming familiarity with any C!\n\n\n#+BEGIN_QUOTE\n The presentation and examples are largely inspired by\n\n + Gilles Dowek's exquisite text [[https://www.springer.com/gp/book/9781848820319][Principles of Programming Languages]].\n - It is tremendously accessible!\n\n + Allan Blanchard's excellent tutorial\n [[https://allan-blanchard.fr/publis/frama-c-wp-tutorial-en.pdf][Introduction to C Program Proof using Frama-C and its WP Plugin]].\n\n Another excellent and succinct tutorial is Virgile Prevosto's [[https://frama-c.com/download/acsl-tutorial.pdf][ACSL Mini-Tutorial]].\n In contrast, the tutorial [[https://www.cs.umd.edu/class/spring2016/cmsc838G/frama-c/ACSL-by-Example-12.1.0.pdf][ACSL By Example]] aims to provide a variety of algorithms\n rendered in ACSL.\n#+END_QUOTE\n\nThere are no solutions since it's too easy to give up and look at the solutions that're\nnearby. Moreover, I intend to use some of the exercises for a class I'm teaching ;-)\n"
},
{
"file": "PathCat",
"title": "Graphs are to categories as lists are to monoids",
"date": "2018-12-24 19:29",
"image": "PathCat.png 300 300",
"description": "A fast-paced introduction to Category Theory based on the notion of graphs.",
"tags": "category-theory agda types",
"url": "https://alhassy.com/PathCat",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/PathCat.org",
"abstract": "\n#+TOC: headlines 2\n\nNumbers are the lengths of lists which are the flattenings of trees which are\nthe spannings of graphs.\nUnlike the first three, graphs have /two/ underlying types of interest\n--the vertices and the edges-- and it is getting to grips with this complexity\nthat we attempt to tackle by considering their ‘algebraic’ counterpart: Categories.\n\n# trees are just those graphs for which arbitrary points are connected by a unique undirected path.\n\nIn our exploration of what graphs could possibly be and their relationships to lists are,\nwe shall /mechanise,/ or /implement,/ our claims since there will be many details and it is easy\nto make mistakes --moreover as a self-learning project, I'd feel more confident to make"
},
{
"file": "HeytingAlgebra",
"title": "Discovering Heyting Algebra",
"date": "2018-11-14 19:29",
"image": "HeytingAlgebra.png 350 350",
"description": "How do friends communicate secretly using non-invertible operations such as minimum? An introduction to Heyting Algebra --an instance of Cartesian Closed Categories!",
"tags": "order-theory category-theory",
"url": "https://alhassy.com/HeytingAlgebra",
"history": "https://github.com/alhassy/alhassy.github.io/commits/master/posts/HeytingAlgebra.org",
"abstract": "\n#+toc: headlines 2\n\nWe attempt to motivate the structure of a Heyting Algebra\nby considering ‘inverse problems’.\n\nFor example,\n+ You have a secret number $x$ and your friend has a secret number $y$, which you've\n communicated to each other in person.\n+ You communicate a ‘message’ to each other\n by adding onto your secret number.\n+ Hence, if I receive a number $z$, then I can /undo/ the addition operation to find the ‘message’ $m = z - y$.\n\nWhat if we decided, for security, to change our protocol from using addition to using\nminimum. That is, we encode our message $m$ as $z = x ↓ m$. Since minimum is not\ninvertible, we decide to send our encoded messages with a ‘context’ $c$ as a pair $(z, c)$.\nFrom this pair, a unique number $m′$ can be extracted, which is not necessarily the original $m$.\nRead on, and perhaps you'll figure out which messages can be communicated 😉\n\n# For example, we wrote our message on a piece of paper and placed it on a cafe bulletin board --a context!\n\nThis exploration demonstrates that relative pseudo-complements\n+ Are admitted by the usual naturals precisely when infinity is considered a number;\n+ Are /exactly/ implication for the Booleans;\n+ /Internalises/ implication for sets;\n+ Yield /the largest complementary subgraph/ when considering subgraphs.\n# + Generalise the /deduction theorem/.\n\nIn some sense, the pseudo-complement is the “best approximate inverse” to forming meets, minima, intersections.\n\nAlong the way we develop a number of the theorems describing the relationships\nbetween different structural components of Heyting Algebras;\nmost notably the internalisation of much of its own structure.\n\nThe article aims to be self-contained, however it may be helpful to\nlook at [[https://alhassy.github.io/CatsCheatSheet/LatticesCheatSheet.pdf][this lattice cheat sheet]] (•̀ᴗ•́)و\n"
}
]
#+end_example
#+html: </div>
<<unfurling>>
The #+description is exported, by standard Org-mode, 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.
Below are the methods to make a new article, to get the meta-data about each
article, to create the JSON file, and to load it.
** Use-package declarations :details:
#+begin_src emacs-lisp -n :exports code
(use-package org-static-blog)
(use-package lf) #+end_src
** Basic facts (global variables) of my blog :details:
#+begin_src emacs-lisp :exports code
(defvar blog/title "Life & Computing Science"
"Title of the blog.")
(defvar blog/url "https://alhassy.com"
"URL of the blog.")
(defvar blog/publish-directory "~/blog/"
"Directory containing published HTML files.")
(defvar blog/posts-directory "~/blog/posts"
"Directory containing source Org files.
When publishing, posts are rendered as HTML and included in the index and RSS feed.
See `blog/make-index-page' and `blog/publish-directory'.")
#+end_src
** blog/new-article: Helper function to make a new article :details:
#+BEGIN_SRC emacs-lisp -n
(defun blog/new-article ()
"Make a new article for my blog; prompting for the necessary ingredients.
If the filename entered already exists, we simply write to it.
The user notices this and picks a new name.
This sets up a new article based on existing tags and posts.
+ Use C-SPC to select multiple tag items
Moreover it also enables `org-preview-html-mode' so that on every alteration,
followed by a save, C-x C-s, will result in a live preview of the blog article,
nearly instantaneously."
(interactive)
(let (file desc)
(thread-last blog/posts-directory
f-entries
(mapcar #'f-filename)
(completing-read "Filename (Above are existing): ")
(concat blog/posts-directory)
(setq file))
(find-file file)
(insert "#+title: " (read-string "Title: ")
"\n#+author: " user-full-name
"\n#+email: " user-mail-address
"\n#+filetags: " (s-join " " (helm-comp-read "Tags: "
blog/tags
:marked-candidates t))
"\n#+fileimage: emacs-birthday-present.png"
"\n#+description: "
(setq desc (read-string "Article Purpose: "))
"\n\n* Abstract :ignore: \n" desc
"\n\n* ???")
(save-buffer)
(blog/preview)))
#+END_SRC
** blog/create-posts-json-file :details:
#+begin_src emacs-lisp -n
(defun blog/create-posts-json-file ()
"Create cache info about posts."
(interactive)
(require 'json)
(cl-loop for file in (f-files "~/blog/posts")
when (s-ends-with? ".org" file)
collect (blog/info file) into posts
finally
(setq posts (sort posts (lambda (newer older) (time-less-p (date-to-time (@date older)) (date-to-time (@date newer))))))
(f-write-text (json-encode posts) 'utf-8 (f-expand "~/blog/posts.json"))
(find-file "~/blog/posts.json")
(json-pretty-print-buffer)
(write-file "~/blog/posts.json")))
(defvar blog/posts (with-temp-buffer (insert-file-contents "~/blog/posts.json") (json-parse-buffer))
"Load cached info about posts")
(defvar blog/tags (sort (seq-uniq (-flatten (seq-map (lambda (it) (s-split " " (map-elt it "tags"))) blog/posts))) #'string<)
"Tags for my blog articles.")
#+end_src
** Convenient accessor methods: Given a JSON hashmap, get the specified key values :details:
Since “accessor” begins with ‘a’, and ‘@’ looks like an ‘a’, all these methods
start with ‘@’.
+ The final 3 below not only access, but also produce HTMLized renditions of
what they access. This is useful for when we want to organise an index landing
page of all of my posts.
#+begin_src emacs-lisp
(defun @title (json) (map-elt json "title"))
TODO(defun @date (json)
"Extract the “#+date:” from JSON."
(map-elt json "date"))
(defun @file (json) (map-elt json "file"))
(defun @description (json) (map-elt json "description"))
(defun @abstract (json) (map-elt json "abstract"))
(defun @url (json) (map-elt json "url"))
#+end_src
** @history: Get an HTML badge that points to the Github history of a given file name, in my blog :details:
#+begin_src emacs-lisp
(defun @history (json)
"Get an HTML badge that points to the Github history of a given file name, in my blog."
(concat
"<a class=\"tooltip\" title=\"See the various edits to this article over time\" href=\""
(map-elt json "history")
"\"><img src=\"https://img.shields.io/badge/-History-informational?logo=github\"></a>"))
#+end_src
** @tags: Get an HTML listing of tags, as shields.io bages, associated with the given file :details:
#+begin_src emacs-lisp
(defun @tags (json)
"Get an HTML listing of tags, as shields.io bages, associated with the given file.
Example use: (@tags (seq-elt blog/posts 0))
"
(concat
(concat
(format "<a href=\"https://alhassy.github.io/tags.html\"> %s </a>"
(org-link/octoicon "tag" nil 'html))
(s-join " "
(--map (org-link/badge
(format "|%s|grey|%stag-%s.html"
(s-replace "-" "_" it)
"https://alhassy.com/" it)
nil 'html)
(s-split " " (map-elt json "tags")))))))
#+end_src
** @image :details:
<<Images>>
Every article declaratively has an associated image ^_^
- Images are loaded from the ~/blog/images/ directory, but may be explicit paths or URLs.
- If none declared, we use emacs-birthday-present.png
#+html: <center> <img src="http://alhassy.com/images/emacs-birthday-present.png" width=100 height=100> </center>
#+begin_src emacs-lisp
(cl-defun @image (json &optional explicit-image-path-prefix)
"Assemble the value of ‘#+fileimage: image width height border?’ as an HTML form.
By default, the image should be located in the top-level `images/' directory.
If the image is located elsewhere, or is a URL, is dictated by the presence of a `/'
in the image path.
Example use: (@image (seq-elt blog/posts 0))
Here are 4 example uses:
,#+fileimage: emacs-birthday-present.png
,#+fileimage: ../images/emacs-birthday-present.png
,#+fileimage: https://upload.wikimedia.org/wikipedia/en/6/64/Dora_and_Boots.jpg 350 300
,#+fileimage: https://unsplash.com/photos/Vc2dD4l57og
+ Notice that the second indicates explicit width and height.
+ (To make the first approach work with local previews,
we need the variable EXPLICIT-IMAGE-PATH-PREFIX which is used for local previews in `my/blog/style-setup'. This requires a slash at the end.)
+ The unsplash approach is specific: It shows the *main* image in the provided URL, and links to the provided URL.
"
(-let [(image width height no-border?) (s-split " " (map-elt json "image"))]
(setq width (or width 350))
(setq height (or height 350))
(setq no-border? (if no-border? "" "style=\"border: 2px solid black;\""))
(cond
((s-contains? "/" image) t) (explicit-image-path-prefix (setq image (format "%s%s" explicit-image-path-prefix image)))
((not (s-contains? "/" image)) (setq image (format "images/%s" image))))
(-let [unsplash (cl-second (s-match ".*unsplash.com/photos/\\(.*\\)" image))]
(setq href (if unsplash (concat "https://unsplash.com/photos/" unsplash) image))
(setq title (format "Image credit “%s”" (if unsplash (concat "https://unsplash.com/photos/" unsplash) image)))
(setq src (if unsplash (format "https://source.unsplash.com/%s/%sx%s" unsplash width height) image))
(s-collapse-whitespace
(format "<center class=\"post-image\"><a href=\"%s\" class=\"tooltip\" title=\"%s\"><img src=\"%s\" alt=\"Article image\"
%s width=\"%s\" height=\"%s\" align=\"top\"/></a></center>"
href title src no-border? width height)))))
#+end_src
** blog/info: Core helper to get the plist/JSON metadata about each post :details:
#+begin_src emacs-lisp
(defun blog/info (post-filename)
"Extract the `#+BLOG_KEYWORD: VALUE` pairs from POST-FILENAME.
Example use: (blog/info \"~/blog/posts/HeytingAlgebra.org\")
"
(let ((case-fold-search t))
(with-temp-buffer
(insert-file-contents post-filename)
(-snoc
(cons
(cons "file" (f-base post-filename))
(cl-loop for (prop.name prop.regex prop.default) on
`("title" "^\\#\\+title:[ ]*\\(.+\\)$" ,post-filename
"date" "^\\#\\+date:[ ]*<\\([^]>]+\\)>$" ,(time-since 0)
"image" "^\\#\\+fileimage: \\(.*\\)" "emacs-birthday-present.png 350 350"
"description" "^\\#\\+description:[ ]*\\(.+\\)$" "I learned something neat, and wanted to share!"
"tags" "^\\#\\+filetags:[ ]*\\(.+\\)$" "" )
by 'cdddr
do (goto-char (point-min))
collect (cons prop.name
(if (search-forward-regexp prop.regex nil t)
(match-string 1)
prop.default))))
(cons "url" (concat "https://alhassy.com/" (f-base post-filename)))
(cons "history" (format "https://github.com/alhassy/alhassy.github.io/commits/master/posts/%s.org"
(f-base post-filename)))
(cons "abstract" (progn
(goto-char (point-min))
(when (re-search-forward "^\* Abstract" nil t)
(beginning-of-line)
(-let [start (point)]
(org-narrow-to-subtree)
(org-fold-show-entry)
(re-search-forward "^ *:END:" nil t) (forward-line)
(buffer-substring-no-properties (point) (point-max))))))))))
#+end_src
** The <code>#+begin_abstract</code> is an Org-mode Special Block :details_orange:
Every article is intended to have a section named Abstract, whose contents are
used as the preview of the article, in the index landing page.
See §new-article for a template.
Below is an alteration from the examples of the docstring of doc:org-defblock.
#+begin_src emacs-lisp
(org-defblock abstract (main) nil
"Render a block in a slightly narrowed blueish box, titled \"Abstract\".
Supported backends: HTML. "
(format (concat
"<div class=\"abstract\" style=\"border: 1px solid black;"
"padding: 1%%; margin-top: 1%%; margin-bottom: 1%%;"
"margin-right: 10%%; margin-left: 10%%; background-color: lightblue;\">"
"<center> <strong class=\"tooltip\""
"title=\"What's the goal of this article?\"> Abstract </strong> </center>"
"%s </div>")
contents))
#+end_src
#+html: <br><center> ★ ★ ★ </center>
For example, the source:
#+begin_example org
,#+begin_abstract
In this article, we learn to have fun!
,#+end_abstract
#+end_example
Results in:
#+begin_abstract
In this article, we learn to have fun!
#+end_abstract
** Generating the Index Page :details:
<<Index>>
The actual look and feel of index.html is due to the method
doc:blog/make-index-page. It summarises all of my articles by their title, data
& image, ‘abstract’, and a read-more badge.
#+begin_src emacs-lisp -n
(cl-defun blog/make-index-page ()
"Assemble the blog index page.
The index page contains blurbs of all of my articles.
Precondition: `blog/posts' refers to all posts, in reverse chronological order.
You can view the generated ~/blog/index.html by invoking:
(blog/make-index-page)
"
(interactive)
(blog/make-tags-page :export-file-name "~/blog/index.html"))
#+end_src
** blog/make-tags-page & blog/make-all-tag-pages: Generating “tag-𝑻.html” pages :details:
#+begin_src emacs-lisp
(defun blog/make-all-tag-pages ()
"Make tag pages for all of my tags"
(interactive)
(loop for total = (length blog/tags)
for tag in blog/tags
for n from 0
for progress = (* (/ (* n 1.0) total) 100)
do
(let ((inhibit-message t)) (blog/make-tags-page :tag tag))
(message "Progress ... %d%%" progress)
TODO finally (shell-command "cd ~/blog; git add \"tag-*.html\"; git commit -m \"Generated tags file\"")))
#+end_src
where
#+begin_src emacs-lisp
(cl-defun blog/make-tags-page
(&key
(tag nil)
(title (if tag (format "Posts tagged “%s”" tag) ""))
(greeting (format "Here are some of my latest thoughts %s... badge:Made_with|Lisp|success|https://alhassy.github.io/ElispCheatSheet/CheatSheet.pdf|Gnu-Emacs such as doc:thread-first and doc:loop (•̀ᴗ•́)و tweet:https://alhassy.com @@html:<br><br>@@"
(if tag (concat "on " tag) "")))
(export-file-name
(concat-to-dir blog/publish-directory
(if tag (concat "tag-" (downcase tag) ".html")
"index.html"))))
"Assemble a page of only articles tagged TAG blog index page.
The page contains blurbs of all of my articles tagged TAG.
Precondition: `blog/posts' refers to all posts, in reverse chronological order.
Example uses:
1. (blog/make-tags-page :export-file-name \"~/blog/index.html\" :title \"Hello world\" :tag \"arabic\")
2. (blog/make-tags-page :tag \"arabic\")
"
(interactive)
(view-echo-area-messages)
(blog/preview/disable)
(with-temp-buffer
(insert
(s-join
"\n"
(list
TODO (setq org-html-head-extra "")
(concat "#+EXPORT_FILE_NAME: " export-file-name)
"#+options: toc:nil title:nil html-postamble:nil"
"#+begin_export html"
org-static-blog-page-preamble
org-static-blog-page-header
"#+end_export"
(concat "#+html: <br><center style=\"font-size: 3em; font-weight: bolder;\">" title "</center>")
TODO
"#+html: <br>" greeting "#+html: <br>"
TODO (s-join "\n" (--map
(if (and tag (not (seq-contains-p (s-split " " (map-elt it "tags")) tag)))
""
(concat
(progn (message "Processing %s..." it) "")
TODO
(format "#+HTML: <h2 class=\"title\"><a href=\"%s\"> %s</a></h2>" (@url it) (@title it))
TODO
(format "\n#+begin_export html\n<center>%s\n</center>\n#+end_export" (@tags it)) ;; TODO
(format "\n@@html:%s@@\n" (@image it)) ;; TODO
(@abstract it)
TODO (format (concat "\n@@html:<p style=\"text-align:right\">@@" " badge:Read|more|green|%s|read-the-docs @@html:</p>@@") (@url it))))
(seq--into-list blog/posts)))
"#+begin_export html"
"<hr> <center> <em> Thanks for reading everything! 😁 Bye! 👋 </em> </center> <br/>"
(blog/license) TODO "\n#+end_export"
)))
(org-mode)
(org-html-export-to-html)))
#+end_src
* Seamlessly Previewing Articles within Emacs
:PROPERTIES:
:CUSTOM_ID: Seamlessly-Previewing-Articles-within-Emacs
:END:
Whenever I save, kbd:C-x_C-s, I'd like to see the final product, the resulting
web-page in a JavaScript-supported browser within Emacs.
+ By “final product” I mean all styles and other features of my blog, as
discussed in this article; for example, this includes the article image,
abstract, and blog header and footer.
- I'd like to have all of my styles automatically loaded in the right places.
+ This gives me a nonintrusive way to preview what I write; ≈WYSIWYG≈.
We accomplish these goals via the following methods.
** org-link/blog: Using My Blog Styles Anywhere :details:
In any Org-mode file ---including random ones that are not even for my blog--- I'll use the Org links blog:header and
blog:footer to obtain the nice styling of my blog.
This is a minor alteration from the examples within the docstring of doc:org-deflink.
#+begin_src emacs-lisp :exports code
(org-deflink blog
"Provide the styles for “www.alhassy.com”'s “header” and “footer”.
The use of “blog:footer” aims to provide a clickable list of tags, produce an HTMLized version of the Org source,
and provides a Disqus comments sections. For details, consult the `blog/footer' function.
Finally, I want to avoid any `@@backend:...@@' from appearing in the browser frame's title.
We accomplish this with the help of some handy-dandy JavaScript: Just use “blog:sanitise-title”.
"
(pcase o-label
("header" (concat
org-static-blog-page-preamble
org-static-blog-page-header
"<link href=\"https://alhassy.github.io/org-notes-style.css\" rel=\"stylesheet\" type=\"text/css\" />"
"<link href=\"https://alhassy.github.io/floating-toc.css\" rel=\"stylesheet\" type=\"text/css\" />"
"<link href=\"https://alhassy.github.io/blog-banner.css\" rel=\"stylesheet\" type=\"text/css\" />"
(thread-last (org-static-blog-get-title (buffer-file-name))
(s-replace-regexp "@@html:" "")
(s-replace-regexp "@@" "")
(format "<br><center><h1 class=\"post-title\">%s</h1></center>"))))
("footer" (blog/footer (buffer-file-name)))
("sanitise-title" "<script> window.parent.document.title = window.parent.document.title.replace(/@@.*@@/, \"\") </script>")
(_ "")))
#+end_src
See also: How do I make a new Org link type?
** COMMENT blog/posts FUNCTION
#+begin_src emacs-lisp
(defun blog/posts (file-name)
"Retrieve the JSON cache from `blog/posts' regarding FILE-NAME.
Example usage: (blog/posts \"java-cheat-sheet\")
"
(seq-filter (lambda (it) (equal (map-elt it "file") file-name)) blog/posts))
#+end_src
** blog/style-setup: A function to insert org-link/blog into a buffer :details:
#+begin_src emacs-lisp
(defun blog/style-setup (_backend)
"Insert blog header (fancy title), tags, blog image (before “* Abstract”), and footer (links to tags).
There are default options: TOC is at 2 levels, no classic Org HTML postamble nor drawers are shown.
Notice that if you explicitly provide options to change the toc, date, or show drawers, etc;
then your options will be honoured. (Since they will technically come /after/ the default options,
which I place below at the top of the page.)
"
(goto-char (point-min))
(let ((post (blog/info (buffer-file-name))))
(insert "#+options: toc:2 html-postamble:nil d:nil"
"\n#+date: " (format-time-string "%Y-%m-%d" (current-time))
(if (buffer-narrowed-p) "\n#+options: broken-links:t" "")
"\n blog:header blog:sanitise-title \n"
"\n* Tags, then Image :ignore:"
"\n#+html: "
"<center>"
(@tags post)
"</center>"
"\n#+html: "
(@image post
TODO (if (equal (f-base (@file post)) "AlBasmala") "./images/" "../images/"))
"\n")
TODO@abstract (blog/info (buffer-file-name))), or (when (re-search-forward "^\* Abstract" nil t)
(beginning-of-line)
(-let [start (point)]
(org-narrow-to-subtree)
(org-show-entry)
(re-search-forward "^ * :END:" nil t) (forward-line)
(insert "\n#+begin_abstract\n")
(call-interactively #'org-forward-heading-same-level)
(when (equal start (point)) (goto-char (point-max)))
(insert "\n#+end_abstract\n")
(widen)))
(goto-char (point-max))
(insert (format "\n* footer :ignore: \n blog:footer \n #+options: title:nil \n"))))
#+end_src
** Inserting org-link/blog <em>seamlessly</em> via the export process; <em>then</em> preview with every save :details:
#+begin_src emacs-lisp
(cl-defun blog/preview ()
"Enable preview-on-save, and add blog/style-setup from Org's export hook."
(interactive)
(-let [kill-buffer-query-functions nil]
(mapcar #'kill-buffer (--filter (equal 'xwidget-webkit-mode (buffer-local-value 'major-mode it)) (buffer-list))))
(add-hook 'org-export-before-processing-hook #'blog/style-setup)
(setq org-preview-html-viewer 'xwidget)
(org-preview-html-mode))
(cl-defun blog/preview/disable ()
"Disable preview-on-save, and remove blog/style-setup from Org's export hook."
(interactive)
(remove-hook 'org-export-before-processing-hook #'blog/style-setup)
(org-preview-html-mode -1))
#+end_src
Upon a save, kbd:C-x_C-s, a new HTML file is created ---bearing the same name as the Org file. It seems an incremental
export is performed and so this is rather fast ---at least much faster than manually invoking kbd:C-c_C-e_h_o.
** Article Footer: HTMLized Source and Git History :details:
:PROPERTIES:
:CUSTOM_ID: Article-Footers
:END:
<<footers>>
#+begin_src emacs-lisp -n
(defun blog/footer (post-file-name)
"Returns the HTML rendering the htmlised source, version history, and comment box at the end of a post.
This function is called for every post and the returned string is appended to the post body, as a postamble."
(let ((post (blog/info (buffer-file-name))))
(concat
"<hr>"
"<center>"
(blog/htmlize-file post-file-name)
" "
(@history post)
(blog/css/arabic-font-setup)
"<br>"
"<a href=\"https://www.buymeacoffee.com/alhassy\"><img src="
"\"https://img.shields.io/badge/-buy_me_a%C2%A0coffee-gray?logo=buy-me-a-coffee\">"
"</a>"
"<br><strong> Generated by Emacs and Org-mode (•̀ᴗ•́)و </strong>"
(blog/license)
"</center>"
"<div hidden> <div id=\"postamble\" class=\"status\"> </div> </div>"
(blog/read-remaining-js))))
#+end_src
** blog/htmlize-file: Generate an htmlized version of a given source file; return an HTML badge linking to the colourised file :details:
#+begin_src emacs-lisp
(defun blog/htmlize-file (file-name)
"Generate an htmlized version of a given source file; return an HTML badge linking to the colourised file.
We do not take the extra time to produce a colourised file when we are previewing an article."
(unless org-preview-html-mode
(let ((org-hide-block-startup nil))
(with-temp-buffer
(find-file file-name)
(org-mode)
(outline-show-all)
(switch-to-buffer (htmlize-buffer))
(write-file (concat "~/blog/" (f-base file-name) ".org.html"))
(kill-buffer))))
(concat
"<a class=\"tooltip\" title=\"See the colourised Org source of this article; i.e., what I typed to get this nice webpage\" href=\""
(f-base file-name) ".org.html\"><img
src=\"https://img.shields.io/badge/-Source-informational?logo=read-the-docs\"></a>"))
#+end_src
** blog/license: HTML for Creative Commons Attribution-ShareAlike 3.0 Unported License :details:
<<Comments>>
#+begin_src emacs-lisp
(defun blog/license ()
"Get HTML for Creative Commons Attribution-ShareAlike 3.0 Unported License."
(s-collapse-whitespace (s-replace "\n" ""
"
<center style=\"font-size: 12px\">
<a rel=\"license\" href=\"https://creativecommons.org/licenses/by-sa/3.0/\">
<img alt=\"Creative Commons License\" style=\"border-width:0\"
src=\"https://i.creativecommons.org/l/by-sa/3.0/88x31.png\"/>
</a>
<br/>
<span xmlns:dct=\"https://purl.org/dc/terms/\"
href=\"https://purl.org/dc/dcmitype/Text\"
property=\"dct:title\" rel=\"dct:type\">
<em>Life & Computing Science</em>
</span>
by
<a xmlns:cc=\"https://creativecommons.org/ns#\"
href=\"https://alhassy.github.io/\"
property=\"cc:attributionName\" rel=\"cc:attributionURL\">
Musa Al-hassy
</a>
is licensed under a
<a rel=\"license\" href=\"https://creativecommons.org/licenses/by-sa/3.0/\">
Creative Commons Attribution-ShareAlike 3.0 Unported License
</a>
</center>")))
#+end_src
** blog/comments: Embed Disqus Comments for my blog :details:
#+begin_src emacs-lisp -n
(defun blog/comments ()
"Embed Disqus Comments for my blog"
(s-collapse-whitespace (s-replace "\n" ""
"
<div id=\"disqus_thread\"></div>
<script type=\"text/javascript\">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'life-and-computing-science';
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the
<a href=\"http://disqus.com/?ref_noscript\">comments powered by Disqus.</a></noscript>
<a href=\"http://disqus.com\" class=\"dsq-brlink\">comments powered by <span class=\"logo-disqus\">Disqus</span></a>")))
#+end_src
** blog/read-remaining-js: HTML to use ReadRemaining.js :details:
#+begin_src emacs-lisp
(defun blog/read-remaining-js ()
"Get the HTML required to make use of ReadRemaining.js"
(if (equal org-preview-html-viewer 'xwidget)
""
"<link rel=\"stylesheet\" href=\"readremaining.js-readremainingjs/css/rr_light.css\"
type='text/css'/>
<script
src=\"readremaining.js-readremainingjs/src/readremaining.jquery.js\"></script>
<script src='readremaining.js/src/readremaining.jquery.js'
type='text/javascript'></script>
<script type=\"text/javascript\"> $('body').readRemaining({showGaugeDelay : 10,
showGaugeOnStart : true}); </script>"))
#+end_src
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.
* Style! What do we want to be inserted into the head of every page?
:PROPERTIES:
:CUSTOM_ID: HTML-Header
:END:
<<the-html-header>>
For each article, I'll have a set of styles loaded as well as a set of <script> code fragments. Here is an overview of
these fragments, and throughout the rest of this article, I'll tangle code to where appropriate.
** Style Header Elements
:PROPERTIES:
:CUSTOM_ID: Style-Header-Elements
:END:
Firstly, we want some styling rules to be loaded.
#+begin_src emacs-lisp -r -n :noweb-ref my-html-header :tangle no
(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\" />" (ref:usualCSS)
"<link href=\"org-notes-style.css\" rel=\"stylesheet\" type=\"text/css\" />" (ref:orgNotesCSS)
"<link href=\"floating-toc.css\" rel=\"stylesheet\" type=\"text/css\" />" (ref:tocCSS)
"<link href=\"blog-banner.css\" rel=\"stylesheet\" type=\"text/css\" />" (ref:bannerCSS)
"<link rel=\"icon\" href=\"images/favicon.png\">")
#+end_src
+ usual-org-front-matter.css badge:||success|usual-org-front-matter.css|css3 ::
Org-static-blog ignores any styling exported by Org, so let's bring that back
in. I just exported this file with the usual kbd:C-c_C-e_h_o, then saved the CSS
it produced.
+ org-notes-style.css badge:||success|org-notes-style.css|css3 ::
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 badge:||success|floating-toc.css|css3 ::
I want to have an unobtrusive floating table of contents, see
§floating-toc.
+ blog-banner.css badge:||success|blog-banner.css|css3 ::
Finally, we want a beautiful welcome mat, see §blog-banner.
** Script Header Elements
:PROPERTIES:
:CUSTOM_ID: Script-Header-Elements
:END:
In addition, we have two more pieces we would like to add to the header: Support
for dynamic code-line highlighting, §blog-banner, and support for using
LaTeX-style notation to write mathematics, §MathJax-Support. We will use a
noweb-ref named my-html-header to refer to them, which are then catenated below.
#+begin_details "Full, tangled, value of org-static-blog-page-header"
#+begin_src emacs-lisp -r :noweb yes :results raw -n
(setq org-static-blog-page-header
(concat
;; NOPE: org-html-head-extra ;; Altered by ‘org-special-block-extras’
<<my-html-header>>
))
#+end_src
# Using “html-header” as the noweb-ref caused the entirrity of the source
# block, along with the #+begin…#+end to be included.
:MetaRemark_about_above_lisp:
The noweb-ref invocation l <<𝓍𝓈>> r expands into
#+begin_src emacs-lisp :tangle no :noeval
l 𝓍₀ r
l 𝓍₁ r
⋮
l 𝓍ₙ r
#+end_src
Where the 𝓍ᵢ are the lines referenced by 𝓍𝓈.
As such, we had our reference call, above, in its own line!
:End:
#+end_details
** Lisp Header Elements
:PROPERTIES:
:CUSTOM_ID: Lisp-Header-Elements
:END:
Some Lisp code is required to string everything together.
+ Lisp fragments are tangled to AlBasmala.el.
** Blog Banner and Dynamic Code Highlighting
:PROPERTIES:
:CUSTOM_ID: Blog-Banner
:END:
<<blog-banner>>
I want to have a nice banner at the top of every page, which should link
to useful parts of my blog.
#+begin_src emacs-lisp -n
(setq org-static-blog-page-preamble
"<div class=\"header\">
<a href=\"https://alhassy.github.io/\" class=\"logo\">Life & Computing Science</a>
<br/>
<a href=\"https://alhassy.github.io/AlBasmala\">AlBasmala</a>
<a href=\"https://alhassy.github.io/rss.xml\">RSS</a>
<a href=\"https://alhassy.github.io/about\">About</a>
</div>")
#+end_src
:Lisp_Remark:
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.
:End:
:Also:
blog/url
blog/title
:End:
I want to style it as follows:
+ Line (headerHeader): The banner is in a box at the top with some shadowing and
centerd text using the fantasy font
+ Line (headerLogo): The blog's title is large and bold
+ Line (headerAnchor): All links in the banner are black
+ Line (headerHover): When you hover over a link, it becomes blue
#+begin_details CSS Details
#+begin_src css -r -n :tangle ~/blog/blog-banner.css :noeval -n
.header { (ref:headerHeader)
* Try to load ‘fantasy’ if possible, else try to load the others. *
font-family: fantasy, monospace, Times;
text-align: center;
overflow: hidden;
* background-color: #f1f1f1 !important;
background: #4183c4 !important; *
padding-top: 10px;
padding-bottom: 10px;
box-shadow: 0 2px 10px 2px rgba(0, 0, 0, 0.2);
}
.header a.logo { (ref:headerLogo)
font-size: 50px;
font-weight: bold;
}
.header a { (ref:headerAnchor)
color: black;
padding: 12px;
text-decoration: none;
font-size: 18px;
}
.header a:hover { (ref:headerHover)
background-color: #ddd;
background-color: #fff;
color: #4183c4;
}
#+end_src
#+end_details
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.
#+begin_details Dynamic Code Highlighting
#+begin_src emacs-lisp -n :noweb-ref my-html-header :tangle no
"<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>"
#+end_src
#+end_details
** Miscellaneous Styles
** Curvy Source Blocks & Pink Inline :details:
<<curvy-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 used by Org.
#+begin_src css -r -n :tangle ~/blog/blog-banner.css :noeval -n
.src {
border: 0px !important;
border-radius: 50px 20px !important;
}
pre.src:before {
padding: 3px !important;
border-radius: 20px 50px !important;
font-weight:700
}
pre{white-space:pre-wrap}
code {
background: pink !important;
border-radius: 7px;
}
#+end_src
Code such as (= 2 (+ 1 1)) now sticks out with a pink background ♥‿♥
** Pink Tables :details:
#+begin_src css :tangle ~/blog/blog-banner.css :noeval -n
table {
background: pink;
border-radius: 10px;
border-bottom: hidden;
border-top: hidden;
display: table !important;
margin-left:auto !important;margin-right:auto !important;
font-family:"Courier New";
font-size:90%;
}
th, td {
border: 0px solid red;
}
#+end_src
#+caption: Example table
| Prime | 2^{Prime} |
|-------+-----------|
| <c> | <c> |
| 1 | 2 |
| 2 | 4 |
| 3 | 8 |
| 5 | 32 |
| 7 | 128 |
| 11 | 2048 |
#+TBLFM: $2='(expt 2 $1);N
#+begin_src emacs-lisp
(setq org-html-table-caption-above nil
org-export-latex-table-caption-above nil)
#+end_src
** Let's show folded, details, regions with a nice greenish colour :details:
This is part of org-special-block-extras, and it's something like this:
#+begin_src css :tangle ~/blog/blog-banner.css :noeval -n
details {
padding: 1em;
background-color: #e5f5e5;
border-radius: 15px;
color: hsl(157 75% 20%);
font-size: 0.9em;
box-shadow: 0.05em 0.1em 5px 0.01em #00000057;
}
#+end_src
* Ξ: Floating Table of Contents
:PROPERTIES:
:CUSTOM_ID: Floating-TOC
:END:
<<floating-toc>>
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.
#+html: <br><center> ★ ★ ★ </center><br>
When we write #+toc: headlines 2 in our Org, HTML export produces the following.
#+begin_src html -n :exports code :tangle no :noeval
<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li> section 1 </li>
⋮
<li> section 𝓃 </li>
</ul>
</div>
</div>
#+end_src
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.
#+begin_details "CSS for a floating TOC"
#+begin_src css -n :tangle ~/blog/floating-toc.css :noeval
*TOC inspired by https://orgmode.org/worg */
#table-of-contents {
* Place the toc in the top right corner *
position: fixed; right: 0em; top: 0em;
margin-top: 120px; * offset from the top of the screen *
* It shrinks and grows as necessary *
padding: 0em !important;
width: auto !important;
min-width: auto !important;
font-size: 10pt;
background: white;
line-height: 12pt;
text-align: right;
box-shadow: 0 0 1em #777777;
-webkit-box-shadow: 0 0 1em #777777;
-moz-box-shadow: 0 0 1em #777777;
-webkit-border-bottom-left-radius: 5px;
-moz-border-radius-bottomleft: 5px;
* Ensure doesn't flow off the screen when expanded *
max-height: 80%;
overflow: auto;}
* How big is the text “Table of Contents” and space around it *
#table-of-contents h2 {
font-size: 13pt;
max-width: 9em;
border: 0;
font-weight: normal;
padding-left: 0.5em;
padding-right: 0.5em;
padding-top: 0.05em;
padding-bottom: 0.05em; }
* Intially have the TOC folded up; show it if the mouse hovers it *
#table-of-contents #text-table-of-contents {
display: none;
text-align: left; }
#table-of-contents:hover #text-table-of-contents {
display: block;
padding: 0.5em;
margin-top: -1.5em; }
#+end_src
#+end_details
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 Ξ.
#+begin_src emacs-lisp -n
(advice-add 'org-html--translate :before-until 'blog/display-toc-as-Ξ)
(defun blog/display-toc-as-Ξ (phrase info)
(when (equal phrase "Table of Contents")
(s-collapse-whitespace
" <a href=\"javascript:window.scrollTo(0,0)\"
style=\"color: black !important; border-bottom: none !important;\"
class=\"tooltip\"
title=\"Go to the top of the page\">
Ξ
</a> ")))
#+end_src
How did I get here?
1. How does Org's HTML export TOCs? ⇒ doc:org-html-toc
2. Looking at its source, we see doc:org-html--translate being
the only place mentioning the string Table of Contents
3. Let's advise it, with doc:advice-add, to return “Ξ”
only on that particular input string.
4. Joy ♥‿♥
Finally,
#+begin_src emacs-lisp :exports code
(setq org-export-with-toc t)
(setq org-export-with-section-numbers t)
#+end_src
* Clickable Sections with Sensible Anchors
** Ensuring Useful HTML Anchors
:PROPERTIES:
:CUSTOM_ID: Ensuring-Useful-HTML-Anchors
:END:
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.
#+begin_details "blog/ensure-useful-section-anchors: Advised to Org Export"
#+BEGIN_SRC emacs-lisp
(defun blog/ensure-useful-section-anchors (&rest _)
"Org sections without an ID are given one based on its title.
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 'blog/ensure-useful-section-anchors)
(advice-add 'org-md-export-to-markdown :before 'blog/ensure-useful-section-anchors)
#+END_SRC
#+end_details
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.
** Clickable Headlines
:PROPERTIES:
:CUSTOM_ID: Clickable-Headlines
:END:
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.
#+begin_details org-html-format-headline-function
#+begin_src emacs-lisp
;; 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)
(ignore-errors (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))))
#+end_src
#+end_details
#+begin_box "Known Issues" :background-color cyan
1. Need to have a custom id declared.
#+BEGIN_SRC org :tangle no
:PROPERTIES:
:CUSTOM_ID: my-header
:END:
#+END_SRC
2. Failing headers: * [[link]] nor * ~code~ nor * $math$.
- Any non-link text before it will work: ok [[link]].
* Using Unicode non-breaking space ‘ ’ is ok.
- Text only after the link is insufficient.
#+begin_details Details on failing headers
Warning: The header cannot already be a link! Otherwise you get the cryptic and
unhelpful error (wrong-type-argument plistp :section-number); which then
pollutes the current Emacs session resulting in strange 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.
#+end_details
#+end_box
* MathJax Support --- $e^{i \cdot \pi} + 1 = 0$
:PROPERTIES:
:CUSTOM_ID: MathJax-Support
:END:
<<MathJax-Support>>
Org loads the MathJax display engine for mathematics whenever users write LaTeX-style math delimited by $...$ or by
\[...\]. Here is an example.
#+begin_org-demo
\[ 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!
#+end_org-demo
#+html: <br>
#+begin_details "The script that Org loads by default"
#+begin_src emacs-lisp -n :noweb-ref my-html-header :tangle no
"<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>
"
#+end_src
#+end_details
** Unicode Warning!
:PROPERTIES:
:CUSTOM_ID: Unicode-Warning
:END:
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} (⊑-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.
#+begin_org-demo
\[ p ⊑ q \quad ≡ \quad p ⊓ q = p \tag{⊑-Definition}\label{⊑-Definition} \]
\[ p ⊑ q \quad ≡ \quad p ⊔ q = q \tag{⊑-Definition}\label{Order-Definition} \]
#+end_org-demo
** Rule Resurrection
:PROPERTIES:
:CUSTOM_ID: Rule-Resurrection
:END:
The following rule for anchors a {⋯} resurrects \ref{} calls via MathJax
---which org-notes-style kills.
#+begin_src css :tangle ~/blog/blog-banner.css :noeval
a { white-space: pre !important; }
#+end_src
** Making Math Stick-out with Spacing!
:PROPERTIES:
:CUSTOM_ID: COMMENT-nice-math-spacing
:END:
Notice how the math expressions stick out in these following sentences:
1. We use $x$ as the name of the unknown.
2. The phrase $∀ x • ∃ y • x 〔R〕 y$ indicates that relation $R$ is “total”.
Nice, the following adds extra whitespace around MathJax,
so that math elements have extra whitespace about them
so as to make them stand-out.
#+HTML_MATHJAX: padding: 25px 25px
#+begin_details "The script that Org loads by default"
#+begin_src emacs-lisp -n :noweb-ref my-html-header :tangle no
"
<script type=\"text/x-mathjax-config\">
MathJax.Hub.Config({
\"HTML-CSS\": {
styles: {
\".MathJax nobr\": {
padding: \"0.5em 0.5em\"
},
}
}
});
</script>
"
#+end_src
#+end_details
** COMMENT Example calculation from that MathJax Setup?
:PROPERTIES:
:CUSTOM_ID: COMMENT-Example-calculation-from-that-MathJax-Setup
:END:
Maybe move the MathJax setup into AlBasmala directly, then include it?
Or, maybe incorporate the MathJax setup via Emacs directly ♥‿♥
Such as org-html-head-extra
\begin{calc}
x \;⊓\; ¬ x \quad=\quad ⊥
\step{ \ref{⊑-antisymmetric} }
(x \;⊓\; ¬ x) \sqleqs ⊥
\landS ⊥ \sqleqs (x \;⊓\; ¬ x)
\step{ \ref{Bottom Element} }
x \;⊓\; ¬ x \sqleqS ⊥
\step{ \ref{Modus Ponens} }
\mathsf{true}
\end{calc}
Then,
\[\eqn{Constructive De Morgan}{¬(x \;⊔\; y) \quad=\quad ¬ x \;⊓\; ¬ y}\]
* Arabic Font Setup
:PROPERTIES:
:CUSTOM_ID: Arabic-Font-Setup
:END:
I'd like inline Arabic to be displayed using الخط الأمیری since that's how it looks within Emacs for me. But, Arabic
within tables should be displayed in a more formal font, Scheherazade, that makes it really clear where letters start
and end, and where the vowels above/below letters are positioned.
#+begin_details
#+begin_src emacs-lisp
(defun blog/css/arabic-font-setup ()
"Setup the CSS/HTML required to make my Arabic writing look nice.
For a one-off use in an article, just place an “#+html:” in front of the result
of this function."
"
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Amiri'>
<style>
body {font-family: 'Amiri', sans-serif;}
table {font-family: 'Scheherazade'; font-size: 105%; }
</style>")
#+end_src
To understand why these styling rules work, see this website:
Right-to-left Styling.
#+end_details
#+html: <br>
#+begin_org-demo :source-color white :result-color white
For example,
+ Inline: اهلاً وسهلاً
+ Within a table:
| اهلاً وسهلاً |
#+end_org-demo
As the above left source demonstrates, unless some explicit action is taken, Arabic fonts are by default rendered
hideously small.
* Actually publishing an article
:PROPERTIES:
:CUSTOM_ID: Actually-publishing-an-article
:END:
#+begin_src emacs-lisp
(cl-defun blog/git (cmd &rest args)
"Execute git command CMD, which may have %s placeholders whose values are positional in ARGS."
(shell-command (apply #'format (concat "cd ~/blog; git " cmd) args)))
(cl-defun blog/publish-current-article ()
"Place HTML files in the right place, update index, rss, tags; git push!"
(interactive)
(blog/git "add %s" (buffer-file-name))
(blog/preview)
(save-buffer)
(-let [article (concat (f-base (buffer-file-name)) ".html")]
(shell-command (concat "mv " article " ~/blog/"))
(blog/git "add %s %s" (buffer-file-name) article)
(when (equal (f-base (buffer-file-name)) "AlBasmala")
(blog/git "add AlBasmala.el")))
(blog/preview/disable) (view-echo-area-messages)
(message "⇒ HTMLizing article...") (blog/htmlize-file (buffer-file-name))
(message "⇒ Assembling tags...") (blog/make-all-tag-pages) TODO TODO (message "⇒ Assembling landing page...") (blog/make-index-page)
(blog/git "add %s.org.html tag* rss.xml index.html" (f-base (buffer-file-name)))
TODO (blog/git "commit -m \"%s\"; git push"
(if current-prefix-arg
(read-string "Commit message: ")
(format "Publish: Article %s.org" (f-base (buffer-file-name)))))
(message "⇒ It may take up 20secs to 1minute for changes to be live at alhassy.com; congratulations!"))
#+end_src
* COMMENT Publishing with [C-u C-u] C-c C-b
:PROPERTIES:
:CUSTOM_ID: Publishing-with-C-u-C-u-C-c-C-b
:END:
:Hide_fornow:
#+begin_src emacs-lisp -n :tangle no
(setq create-lockfiles nil)
#+end_src
:End:
#+begin_src emacs-lisp -r -n
(bind-key* (kbd "C-c C-b")
(lambda (&optional prefix)
"C-c C-b ⇒ Publish current buffer
C-u C-c C-b ⇒ Publish entire blog
C-u C-u C-c C-b ⇒ Publish entire blog; re-rendering all blog posts
(This will take time!)
"
(interactive "P")
(pcase (or (car prefix) 0)
(0 (org-static-blog-publish-file (f-full (buffer-file-name)))
(browse-url-of-file (format "file://%s%s.html" (file-truename blog/publish-directory)
(f-base (buffer-file-name)))))
(4 (org-static-blog-publish-file (f-full (buffer-name)))
(org-static-blog-publish))
(16 (thread-last (f-entries "~/blog/")
(--filter (and (equal (f-ext it) "html")
(not (member (f-base it) '("about")))))
(--map (f-delete it))) (ref:delAll)
(org-static-blog-publish-file (f-full (buffer-name)))
(org-static-blog-publish)))))
#+end_src
Line (delAll): To re-render an article, just remove its corresponding .html file
* COMMENT [Part of publishing a file] org-static-blog-post-preamble: Making this work with org-notes-style and org-static-blog
:PROPERTIES:
:CUSTOM_ID: Making-this-work-with-org-notes-style-and-org-static-blog
:END:
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 (fixTitle): 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.
#+begin_src emacs-lisp -r -n -n
(defun org-static-blog-post-preamble (post-filename)
"Returns the formatted date and headline of the post.
This function is called for every post and prepended to the post body.
Modify this function if you want to change a posts headline."
(let ((post (blog/info (buffer-file-name))))
(concat
"<h1 class=\"post-title\">"
"<div class=\"title\" style=\"margin: 0 0 0 0 !important;\">" (ref:fixTitle)
"<a href=\"" (@url post) "\">"
(@title post)
"</a>"
"</h1></div>"
"<div style=\"text-align: center;\">"
(@date post)
"</div>"
(@image post)
"<br><center><strong>Abstract</strong></center>")))
#+end_src
* The name: al-bas-mala
:PROPERTIES:
:CUSTOM_ID: the-name
:END:
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"
* Appendix: Using a Custom Domain: alhassy.com
:PROPERTIES:
:CUSTOM_ID: COMMENT-Using-a-Custom-Domain-alhassy-com
:UNNUMBERED: t
:END:
#+begin_details
1. Go to your repo: https://github.com/alhassy/alhassy.github.io/settings/pages
2. Add a Custom Domain such as an “apex domain” like alhassy.com (or a www domain like www.alhassy.com)
- Apex domains require A records to be setup on your DNS provider.
- www domains require CNAME records.
- On my DNS provider, I setup both: That way, with or without www., people will arrive at my blog.
3. Go to your DNS provider, and add two records
| Type | Name | Priority | Content | TTL |
|-------+------+----------+-------------------+-------|
| CNAME | www | 0 | alhassy.github.io | 14400 |
| CNAME | @ | 0 | alhassy.github.io | 14400 |
4. In a terminal, run: dig www.alhassy.com +nostats +nocomments +nocmd
- The www. is intentional.
5. You should see something like:
#+begin_example bash
www.alhassy.com. 14400 IN CNAME alhassy.github.io.
alhassy.github.io. 3600 IN A 185.199.111.153
alhassy.github.io. 3600 IN A 185.199.108.153
alhassy.github.io. 3600 IN A 185.199.109.153
alhassy.github.io. 3600 IN A 185.199.110.153
#+end_example
This says that it may take 3600 seconds, or 1hour, for the redirect of alhassy.com to
alhassy.github.io to be completed. It may take longer; keep reading.
6. In your DNS provider, add 4 records, one for each IP Address you got from the dig command.
(These addresses are also on the official Github docs).
| Type | Name | Priority | Content | TTL |
|------+------+----------+-----------------+-------|
| A | @ | 0 | 185.199.108.153 | 14400 |
| A | @ | 0 | 185.199.109.153 | 14400 |
| A | @ | 0 | 185.199.110.153 | 14400 |
| A | @ | 0 | 185.199.111.153 | 14400 |
7. Run dig alhassy.com +noall +answer -t A and ensure it points to these IP addresses.
- Notice the lack of a www.
8. Open an incognito browser, private browsing session, and navigate to alhassy.com.
a. If this redirects to your alhassy.github.io blog, then joy!
- If the redirect does not happen in your non-incognito browser, just clear your browsing history and try again.
b. Otherwise, it may take some time (something like 1/2hour to 3 days) for the DNS propagation
to be completed.
- You can check the progress by using a service like this.
- It took me about 1/2hour for the URL to redirect to my github.io blog.
Further resources:
- Managing a custom domain for your GitHub Pages site - GitHub Docs
- Linking A Custom Domain To Github Pages
#+end_details
* COMMENT Archives
** Org Marco: “This section has been #+include'd from my init.org” :ignore:
:PROPERTIES:
:CUSTOM_ID: Org-Marco-This-section-has-been-include'd-from-my-init-org
:END:
#+html: <style> center.tiny a img { height: 15px } </style>
#+macro: init badge:A_Life_Configuring|Emacs|green|https://alhassy.github.io/emacs.d|gnu-emacs
#+macro: from-my-init-text /This section has been =#+include='d from my init.org/, {{{init}}}
#+macro: from-my-init @@html: <center class="tiny" style="font-size: 15px">@@ {{{from-my-init-text}}} @@html: </center>@@
*** COMMENT Example usage
from-my-init
<<ensuring-useful-html-anchors>>
#+include: "~/.emacs.d/init.org::*Ensuring Useful HTML Anchors" :only-contents t
** COMMENT unsplash link setup :Leave_as_cute_remark:
:PROPERTIES:
:CUSTOM_ID: COMMENT-unsplash-link-setup
:END:
#+begin_src emacs-lisp :exports code
#+end_src
(-let [unsplash (cl-second (s-match ".*unsplash.com/photos/\\(.*\\)" "https://unsplash.com/photos/Vc2dD4l57og"))]
(if unsplash
(format "<center><a href=\"https://unsplash.com/photos/%s\" class=\"tooltip\" title=\"Photo from Unsplash\"><img
src=\"https://source.unsplash.com/%s/300x300\"></a></center>"
unsplash unsplash)))
unsplash:XXX0GQfgMy8