# -*- eval: (org-babel-load-file "AlBasmala.org") -*- #+title: AlBasmala: @@html:
@@ 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 # Use checkmarks instead of boring bullet points #+html_head: * 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 [[https://github.com/alhassy/emacs.d#what-does-literate-programming-look-like][noweb-ref]] named =my-html-header= to refer to them, which are then catenated below. :end: #+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. # ;; (length blog/posts) ⇒ 16 # TODO: When I'm done, look around and ensure there are no 'TODO's; or if there are any, move them to my todo.org::Blog::Ideas section! # ;; Need this conditional since AlBasmala lives in ~/blog whereas usually articles live in ~/blog/posts. # ;; TODO: Consider just making AlBasmala live in ~/blog/posts, I don't think there's any real reason for breaking consistency. # # In-particular, besides some extra code in blog/style-setup, by breaking consistency, AlBasmala does not produce tag # pages /not/ contribute to them! This is probably a good enough reason to have it live alongside the other posts! # TODO: Following method crashes unexpectedly when there is no #image; this # should not be the case. # (blog/preview) # wrt org-link/blog: # TODO: For the footer, we want ~blog:footer|src|history~ where ~src~ is Boolean to # indicate generating the *.org.html file and ~history~ is the relevant repo. # # Low priority. ** font for links #+html:
#+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 ;; cl-lib was published as a better (namespaced!) alternative to cl, which has a deprecation warning in Emacs27. ;; Yet some old pacakges require cl, and so the below setq silences the deprecation warning. (setq byte-compile-warnings '(cl-functions)) (require 'cl-lib) ;; to get loop instead of cl-loop, etc. (require 'shortdoc) ;; Essentially "tldr" but for Emacs Lisp! ;; (cl-defun define-short-documentation-group (&rest _)) ;; (cl-defun org-duration-to-minutes (&rest _) ) ;; (cl-defun org-id-find-id-file (&rest _)) (ignore-errors (use-package org-preview-html) (setq org-preview-html-viewer 'xwidget) ;; (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))) ))) (use-package org-special-block-extras) ;;(load-file "~/blog/AlBasmala.el") ) ;; M-x blog/preview ;; Required for Github Actions; i.e., testing. ;; TODO Clean me! (defun quelpa-read-cache ()) ;; Used somewhere, but not defined. ;; See: quelpa-persistent-cache-file (setq quelpa-cache nil) ;; Eager macro-expansion failure: (void-function all-the-icons-faicon) ;; Symbol’s function definition is void: all-the-icons-faicon #+end_src #+begin_src emacs-lisp :exports none ;; Error in kill-emacs-hook (org-clock-save): (void-function org-clocking-buffer) (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") ;; Makes all dots, hamza, diadiract marks colored! ;; Note: "arabic" input method just changes my English query keyboard into an Arabic keyboard ---useful if one's mastered touch typing in Arabic! ;; In contrast, the Perso-Arabic input method uses a system of transliteration: Ascii keys are phonetically mapped to Arabic letters. (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!"))))) ;; 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))) #+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 "" url o-label url))) #+end_src ** COMMENT Ideas :PROPERTIES: :CUSTOM_ID: COMMENT-todo :END: # TODO: Automate the insertation of HTML Premable/postable for statics like about/AlBasmala # (maybe-clone "https://github.com/alhassy/alhassy.github.io.git" "~/blog") # teal:TODO: Make C-u C-c C-b switch to a particular theme so all exported html stuffs # look the same ^_^ # Idea: Make the tags at the bottom be badges, alter/advice the corresponding # function # Idea: Add “last updated” date to footer? + in the index, under each article's name: - twitter link ;-) - per article via advice #+begin_export html #+end_export + Footer should include - See Org Source; see HTML source - buy-me-a-coffee #+html:
# # + search # + Org-mode unicorn as faveicon! # This, like the upcoming articles, is intended to be a living document. # The date serves to be date of the first release and the repo contains # the history of any alterations. *** COMMENT To consider :PROPERTIES: :CUSTOM_ID: COMMENT-To-consider :END: #+BEGIN_SRC emacs-lisp :tangle no ;; Okie, dokes. maybe useful (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 # Usage ∷ Begin blog server then load AlBasmala, then edit & preview. # # (shell-command "cd ~/alhassy.github.io/ ; bundle exec jekyll serve &") # (find-file "~/alhassy.github.io/content/AlBasmala.el") # (preview-article :browser t) # (preview-article) **** 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: : # 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) ;; A modern list library for Emacs (require 's) ;; String processing library. #+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) ;; (make-local-variable symbol) ;; Undesirable since I want to use these names in other buffers. )))) #+END_SRC #+RESULTS: : make-file-extension-variables :Example_of_locals_in_elisp: #+BEGIN_SRC emacs-lisp :tangle no (setq bar "noah") ;; All buffers can access this variable, with only this value as default value. (make-local-variable 'bar) ;; All future setq's only affect this buffer. (setq bar "rab") ;; As such, the following approach makes a variable local to begin with. (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) ;; (concat "~/alhassy.github.io/assets/pdfs/" file.pdf) "The path to the blog repository where the generated PDF should live.") ;; Make these variables local to the current buffer. ;; Undesirable since I'd like to utlise these in other buffers. ;; (make-local-variable 'blogrepo) ;; (make-local-variable 'blogrepo-posts) ;; (make-local-variable 'blogrepo-file.pdf) #+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’") ;; (make-local-variable symbol) ;; Undesirable since I use the ‘org.key’ symbols ;; in the assocaited html buffers. ))) #+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) ;; We have these here in-case the “org.date” is altered. (setq jekyll.name (concat org.date "-" NAME)) (setq jekyll.name.md (concat org.date "-" NAME ".markdown")) ) ;; Globally set the variables ;; (GetOrgKeyWords) #+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
RWH Cover
,#+end_export #+END_SRC :One_long_line: #+BEGIN_SRC org :tangle no ,#+HTML:
RWH Cover
#+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
RWH Cover
,#+end_export #+END_SRC :One_long_line: #+BEGIN_SRC org :tangle no ,#+HTML:
RWH Cover
#+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 "
\"Musa's
"))) (re-replace-in-file ;; see below (concat AbsNAME ".html") "" (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 ;; Within mysite.html we rewrite: \n NICE ;; I.e., we add a line break after the first heading and a new word, “NICE”. (re-replace-in-file "mysite.html" "" (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 ;; Include LaTeX Org-calls, produce the PDF, then revert the file. ;; (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) ;; Produce a checkpoint. (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" ))) ;; Using (lambda () (extras...)) makes the extras happen before the reversion below. (eval extras) ;; revert to working file (copy-file file.src file.org 'overwrite) (delete-file file.src) (toggle enable-local-variables :all (revert-buffer 'ignore-auto 'no-confirmation)) ;; A copy, rather a move, since article repo may differ from blog repo. (copy-file file.pdf ;; ‘blogrepo-file.pdf’ is the path relative to the blog repository; ;; this format allows us to view the PDF when the local blog server is running. ;; However, we may currently be residing in a different repository. ;; As such, we shift the cp command to move to the absolute path to the blog repo. (concat "~/alhassy.github.io" (s-chop-prefix ".." blogrepo-file.pdf)) ;; (file-truename blogrepo-file.pdf) ;; fix me '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. # -- # or they may prefer a PDF version for printing or simply for an alternate aesthetic. #+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") ;; raw, then 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’. " ;; (message-box url) (if url (concat "" identifier "") 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))) ) ;; Perform the loop over tuples (constraint url description). (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 "
"))) (,org.nomodificationdate ,commits "Last modified") (,org.nomodificationdate nil ,(concat " on " date)) ) content) ;; Unless there are constraints, concatenate the resulting html. (unless (car var) (setq content (concat content (make-html-link (cadr var) (caddr var))))) ) ;; for debugging / drafting, (concat (when org.draft (format "
Draft: %s
" (gensym))) "
⟨ " content " ⟩
") ) ) ;; Rather than , maybe utilise . #+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: # Look at the super short doc to know how to manipulate this variable: (describe-symbol 'org-html-postamble-format) #+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 "
Last modified on %C ; " pdf " or see the " src " ; Contact me at %e
")))) ) #+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 [[https://www.gnu.org/software/emacs/manual/html_node/elisp/File-Local-Variables.html][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 "") '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) ;; Remove any existing html, in case we fail to generate it ;; we do not want to render an out of date version. (shell-command (concat "rm ~/alhassy.github.io/_posts/" jekyll.name.md)) (setq enable-local-variables nil) (setq enable-local-eval nil) ;; compile coloured html (find-file file.org) (GetOrgKeyWords) (when draft (setq org.draft draft)) (org-html-export-to-html) ;; Insert image, duh. (insert-image-and-other-formats) ;; Discard first 3 lines, (note the 1-indexing), since they don't look very nice ;; in the resulting markdown file when rendered on the Jekyll site. (shell-command (concat "tail -n +4 <" file.html " >" jekyll.name.md)) ;; Preprend file with a header. (find-file jekyll.name.md) (beginning-of-buffer) (MakeHeader) (insert HEADER) (save-buffer) (kill-buffer jekyll.name.md) ;; Move it to posts directory. (shell-command (concat "mv " jekyll.name.md " " blogrepo-posts)) ;; ;; Uncomment for debugging. ;; ;; (find-file (concat "~/alhassy.github.io/_posts/" jekyll.name.md)) ;; no pdf generation in draft mode (unless (or org.draft org.nopdf) (my-org-latex-export-to-pdf)) ;; Preview locally in browser. (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 "") 'commit) (defun commit () "Commit changes to git in the form: “ChangedFile: CommitMessage”." (interactive) ;; In-case the article was updated but we forgot to produce new generated files. (preview-article) (shell-command "rm *.html") ;; remove noise (let ((msg (read-string (format "Commit message for %s: " NAME)))) ; (shell-command (format "git add ../_posts/%s ../content/%s %s %s" jekyll.name.md file.org blogrepo-file.pdf file.el)) ; (shell-command (format "git commit ../_posts/%s ../content/%s %s %s -m \"%s: %s\"" jekyll.name.md file.org blogrepo-file.pdf file.el NAME msg)) ;; “git add commitables” (shell-command (s-join " " (cons "git add" commitables))) ;; “git commit commitables -m NAME: message” ;; Note that the commit message needs to be in quotes. (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") ;; remove noise (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 # Remember it takes 10 seconds for the live github page to actually change! **** Usage :PROPERTIES: :CUSTOM_ID: Usage :END: # Within src blocks containing org, you need to escape org heading, the `*`, delimiters with a comma. # E.g.: ,* My heading #+BEGIN_EXPORT html #+END_EXPORT #+HTML: #+HTML: #+BEGIN_EXPORT html
The [[file:template.org][example]] source, #+HTML: # TODO. ? +INCLUDE: "template.org" src org #+HTML: Results in,


#+BEGIN_EXPORT html #+END_EXPORT #+HTML:
#+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 [[https://github.com/bastibe/org-static-blog][org-static-block]] :PROPERTIES: :CUSTOM_ID: https-github-com-bastibe-org-static-blog-org-static-block :END: Let's use [[https://github.com/bastibe/org-static-blog][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 [[https://github.com/bastibe/org-static-blog#examples][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 --- [[http://taopeng.me/org-notes-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? " ;; (upcase (or o-description o-label)) (-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 "\"Article" href title src width height))) (if center? (format "
%s
" it) it))))) #+end_src This will eventually be part of [[http://alhassy.com/org-special-block-extras/][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 # $pdf_update_command = "emacsclient -e '(progn (switch-to-buffer-other-window (find-buffer-visiting %S)) (pdf-view-revert-buffer nil t))'"; 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 # alias emacsclient="/usr/local/Cellar/emacs-plus@29/29.0.90/bin/emacsclient" # export PATH="/usr/local/Cellar/emacs-plus@29/29.0.90/bin/:$PATH" # emacs & emacsclient * Redefining Org Section for purposes of blocks :details_deftag: image:https://i.redd.it/rre5ggpx9jya1.png|100%|100%|center|Musa ([[https://www.reddit.com/r/emacs/comments/13bdlck/tags_are_functions_of_org_sections_%E1%B4%97%D9%88/][Reddit Post]]) This will eventually be part of [[http://alhassy.com/org-special-block-extras/][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
block; COLOR is an optional argument indicating the background colour of the resulting block.\" (insert \"\n#+html:\" (format \"
\" color) \"\" (s-replace-regexp \"^\** \" \"\" heading) \"\") (org-next-visible-heading 1) (insert \"#+html:
\")) " (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) ;; Otherwise we impede on the auto-inserted “* footer :ignore:” (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
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 "
%s
" (if anchor (format "🔗" anchor anchor) "") color) " " (s-replace-regexp "^\** " "" o-heading) " ") (org-next-visible-heading 1) (insert "#+html:
")) #+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:
@@ *** 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 ~
~ element, with an anchor. #+begin_src emacs-lisp (org-deftag quote (color) "HTML export a section as if it were a
block; COLOR is an optional argument indicating the text colour of the resulting block." (insert "\n#+html:" (format "
" color)) (org-next-visible-heading 1) (insert "#+html:
")) #+end_src See http://alhassy.com/AlBasmala#deftag for the definition of =org-deftag=. *** Bye! :ignore: /Have a great evening!/ @@html:
@@ ** 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
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) ;; (thing-at-point 'line) (let ((heading (car kill-ring))) (if (not (s-contains? ":NOPE:" heading 'ignoring-case)) (insert heading) (insert heading) (insert "NIIIIICE") ;; (if first-heading (setq first-heading nil) ;; (insert "+latex:\\end\{alertblock\}")) ;; (insert "\n\n+latex: \\begin\{alertblock\}\{") (org-next-visible-heading 1) (insert "WOW :: " (s-chop-prefix "\** " heading)) (insert "\n") ;; Otherwise we impede on the auto-inserted “* footer :ignore:” ;; (insert "\}") ) ) ))) (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 ;; See: http://alhassy.com/org-special-block-extras/#Tooltips-for-Glossaries-Dictionaries-and-Documentation ;; My personal documentation library can be seen [[https://alhassy.github.io/org-special-block-extras/documentation.html][here]] (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 ;; Nearly instanteous preview: Just Save and it'll rebuild, and pop-up the preview to the side! (setq org-preview-html-viewer 'xwidget) (org-preview-html-mode) ;; TODO. Need to advise this to turn off doom-modeline first! ;; Why? Since xwidget does not work well with doom-modeline. ;; TODO. Something in my init.el breaks this package!?! ;; ;; Mention this in my AlBasmala.org as a way to preview my articles ^_^ ;; Turn off doom-modeline when previewing. ;; (advice-add #'org-preview-html-mode :before (lambda (&rest _) (doom-modeline-mode 0))) ;; ;; The following suffices. ;; (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))) ;; Make the modeline minimal, otherwise it's super ugly. (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)) )) ;; ;; Make an Issue on both doom-modeline github and on org-preview-html Github. Link these issues to each other. ;; Maybe instead make a README PRs that have the above advice-add clause; I think that might be best ---along with MWE init.el in the PR description to justify these additions. ;; ;; Along with a MWE init.el to substanitate my claim. ;; Conversely, when we start doom-modeline let's ensure we have no xwidget buffer lying around, otherwise Emacs will hang. (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: # TODO. ? +include: ~/.emacs.d/init.org::#Mini-tutorial-on-Org-mode 1. Open an Org-mode buffer ---or invoke doc:blog/new-article. 2. src_emacs-lisp[:exports code]{(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 [[https://alhassy.com/arabic-roots.html][root-meaning program to learn Arabic]] and to have a [[https://alhassy.com/cartoon][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: <> <> 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:
#+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:
@@\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\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:
@@\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:
@@\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:
<> 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) ;; So we can use `lf-string' for multi-line strings supporting interpolation: ;; (lf-string "100/2 is ${ (/ 100 2) }; neato!") ;; ⇒ "100/2 is 50; neato!" #+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)) ;; For some reason, ‘find-file’ in the thread above ;; wont let the completing-read display the possible completions. (find-file file) (insert "#+title: " (read-string "Title: ") "\n#+author: " user-full-name "\n#+email: " user-mail-address ;; "\n#+date: " (format-time-string "<%Y-%m-%d %H:%M>") "\n#+filetags: " (s-join " " (helm-comp-read "Tags: " blog/tags :marked-candidates t)) "\n#+fileimage: emacs-birthday-present.png" ;; "\n#+fileimage: " (completing-read ;; "Image: " ;; (mapcar #'f-filename (f-entries "~/blog/images/"))) ;; "\n#+include: ../MathJaxPreamble.org" ;; TODO. Is this someting I actually want here? If so, then consider tangling it from AlBasmala! (and add the whitespace-MathJax setup from above!) "\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 ;; Sorted in descending time; i.e., the latest article should be first (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 ;; Convenient accessor methods: Given a JSON hashmap, get the specified key values. ;; Later, we redefine these, for example `@image' will actually produces the HTML for the image. ;; Example usage: (@title (seq-elt posts 0)) ⇒ "Java CheatSheet" ;; Extract the ‘#+title:‘ from POST-FILENAME. (defun @title (json) (map-elt json "title")) ;; TODO: Consider using: (format-time-string "%d %b %Y" ⋯) to have the same format across all articles. (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")) ;; Returns absolute URL to the published POST-FILENAME. ;; ;; This function concatenates publish URL and generated custom filepath to the ;; published HTML version of the post. ;; (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 "")) #+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 ;; Straightforward implementation. ;; "
" ;; (org-static-blog-post-taglist file-name) ;; "
" ;; Badges implementation (concat (format " %s " (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: <> 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:
#+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) ;; It's a URL, or explicit path, do nothing to it. (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 "
\"Article
" 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:[ ]*\\(.+\\)$" "" ;; String; Space separated sequence of tags ) by 'cdddr ;; See: https://stackoverflow.com/questions/19774603/convert-alist-to-from-regular-list-in-elisp 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) ;; Ignore :PROPERTIES: drawer, if any. (forward-line) (buffer-substring-no-properties (point) (point-max)))))))))) #+end_src ** The #+begin_abstract 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 "
" "
Abstract
" "%s
") contents)) #+end_src #+html:
★     ★     ★
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: <> 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) ;; Slightly faster to generate all pages, /then/ to git add them all. ;; TODO: I'm doing a “git commit” here, where else? Maybe merge them all together? Likewise with “git add”s. finally (shell-command "cd ~/blog; git add \"tag-*.html\"; git commit -m \"Generated tags file\""))) ;; NOTE: Slightly faster if I get rid of the “Progress…” notifications. #+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:

@@" (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: Actually look at this concat result and notice that osbe is adding ;; way too much content to the header! ;; (progn (org-special-block-extras-mode -1) "") (setq org-html-head-extra "") ;; Org-mode header (concat "#+EXPORT_FILE_NAME: " export-file-name) "#+options: toc:nil title:nil html-postamble:nil" "#+begin_export html" ;; MA: Not ideal, the sizes I've set in the actual article are best. ;; "" org-static-blog-page-preamble org-static-blog-page-header "#+end_export" (concat "#+html:
" title "
") ;; TODO: Delete the following comment when things work and are done. ;; Extra styling of abstracts. ;; Works; but not needed. ;; "\n#+HTML_HEAD_EXTRA: " ;; The greeting message that informs viewers what this page is about. "#+html:
" greeting "#+html:
" ;; TODO: Add this loop body to the info of each post, for future use via AngularJS view-by-tags. ;; Blurbs of posts (s-join "\n" (--map (if (and tag (not (seq-contains-p (s-split " " (map-elt it "tags")) tag))) "" (concat (progn (message "Processing %s..." it) "") ;; Progress indicator ;; TODO: Make this concat of ⟨0⟩-⟨4⟩ into a method `@preview' ;; ⟨0⟩ Title and link to article (format "#+HTML:

%s

" (@url it) (@title it)) ;; TODO: Look at all uses of @title and maybe move this @@html@@ into it. ;; NOTE: This is still a Phase Split since the JSON has the raw data, and the @ABC methods produce @@html⋯@@ code ^_^ ;; ⟨1⟩ Tags and reading time (format "\n#+begin_export html\n
%s\n
\n#+end_export" (@tags it)) ;; TODO: Look at all uses of @tags and maybe move this @@html@@ into it. ;; ⟨2⟩ Article image (format "\n@@html:%s@@\n" (@image it)) ;; TODO: Look at all uses of @image and maybe move this @@html@@ into it. ;; ⟨3⟩ Preview (@abstract it) ;; ⟨4⟩ “Read more” link ;; TODO: Make a @read-more method. (format (concat "\n@@html:

@@" " badge:Read|more|green|%s|read-the-docs @@html:

@@") (@url it)))) (seq--into-list blog/posts))) ;; “Show older posts” ;; This is the bottom-most matter in the index.html page "#+begin_export html" "
Thanks for reading everything! 😁 Bye! 👋

" (blog/license) ;; TODO: Add a “proudly created with Emacs’ Org-mode” tagline? "\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 "" "" "" ;; The use of the “post-title” class is so that the org-static-blog-assemble-rss method can work as intended. (thread-last (org-static-blog-get-title (buffer-file-name)) (s-replace-regexp "@@html:" "") (s-replace-regexp "@@" "") (format "

%s

")))) ("footer" (blog/footer (buffer-file-name))) ("sanitise-title" "") (_ ""))) #+end_src See also: [[http://alhassy.com/org-special-block-extras/#Links][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: " "
" (@tags post) "
" "\n#+html: " (@image post ;; Need this conditional since AlBasmala lives in ~/blog whereas usually articles live in ~/blog/posts. ;; TODO: Consider just making AlBasmala live in ~/blog/posts, I don't think there's any real reason for breaking consistency. (if (equal (f-base (@file post)) "AlBasmala") "./images/" "../images/")) "\n") ;; Wrap contents of “* Abstract” section in the “abstract” Org-special-block ;; (In case we are narrowed, we only act when we can find the Abstract.) ;; TODO: Replace this with (@abstract (blog/info (buffer-file-name))), or: (@abstract post) (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) ;; Ignore :PROPERTIES: drawer, if any. (forward-line) (insert "\n#+begin_abstract\n") (call-interactively #'org-forward-heading-same-level) ;; In case there is no next section, just go to end of file. (when (equal start (point)) (goto-char (point-max))) (insert "\n#+end_abstract\n") (widen))) (goto-char (point-max)) ;; The Org file's title is already shown via blog:header, above, so we disable it in the preview. (insert (format "\n* footer :ignore: \n blog:footer \n #+options: title:nil \n")))) #+end_src ** Inserting org-link/blog seamlessly via the export process; then 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's ensure we have no xwidget buffer lying around, otherwise Emacs might hang. (-let [kill-buffer-query-functions nil] (mapcar #'kill-buffer (--filter (equal 'xwidget-webkit-mode (buffer-local-value 'major-mode it)) (buffer-list)))) ;; Inserting org-link/blog /seamlessly/ via the export process (add-hook 'org-export-before-processing-hook #'blog/style-setup) ;; Preview with every save (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: <> #+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 "
" "
" (blog/htmlize-file post-file-name) " " (@history post) ;; ;; Consider only add this to posts tagged “arabic”? (blog/css/arabic-font-setup) ;; "
" "" "" ;; "
Generated by Emacs and Org-mode (•̀ᴗ•́)و " (blog/license) ;; (blog/comments) ;; TODO. Not working as intended; low priority. "
" ;; The next line is required to make the org-static-blog-assemble-rss method work. "" (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) ;; (insert "\n#+HTML_HEAD: \n") (org-mode) (outline-show-all) (switch-to-buffer (htmlize-buffer)) (write-file (concat "~/blog/" (f-base file-name) ".org.html")) (kill-buffer)))) (concat "")) #+end_src ** blog/license: HTML for Creative Commons Attribution-ShareAlike 3.0 Unported License :details: <> #+begin_src emacs-lisp (defun blog/license () "Get HTML for Creative Commons Attribution-ShareAlike 3.0 Unported License." (s-collapse-whitespace (s-replace "\n" "" "
\"Creative
Life & Computing Science by Musa Al-hassy is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License
"))) #+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" "" "
comments powered by Disqus"))) #+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" ;; [Maybe Not True] ReadReamining.js does not work well with xWidget browser within Emacs (if (equal org-preview-html-viewer 'xwidget) "" ;; ReadRemaining.js ∷ How much time is left to finish reading this article? ;; ;; jQuery already loaded by org-special-block-extras. ;; "" " ")) #+end_src [[https://aerolab.github.io/readremaining.js/][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 ==, otherwise it wont work for me. - It may be best to avoid loading jQuery multiple times; see [[https://alhassy.github.io/org-special-block-extras/#tooltipster][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: <> For each article, I'll have a set of styles loaded /as well as/ a set of ~" #+end_src #+end_details ** Miscellaneous Styles ** Curvy Source Blocks & Pink Inline :details: <> The =border-radius= property defines the radius of an element's corners, we use it to make curvy looking source blocks. Its behaviour [[https://www.w3schools.com/cssref/css3_pr_border-radius.asp][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; /* 50px for top-left and bottom-right corners; 20px for top-right and bottom-left cornerns. */ border-radius: 50px 20px !important; } pre.src:before { /* border: 0px !important; */ /* background-color: inherit !important; */ padding: 3px !important; border-radius: 20px 50px !important; font-weight:700 } /* wrap lengthy lines for code blocks */ pre{white-space:pre-wrap} /* Also curvy inline code with ~ ⋯ ~ and = ⋯ = */ code { /* background: Cyan !important; */ background: pink !important; border-radius: 7px; /* border: 1px solid lightgrey; background: #FFFFE9; padding: 2px */ } #+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; /* width:90% */ border-bottom: hidden; border-top: hidden; display: table !important; /* Put table in the center of the page, horizontally. */ margin-left:auto !important;margin-right:auto !important; font-family:"Courier New"; font-size:90%; } /* Styling for ‘t’able ‘d’ata and ‘h’eader elements */ th, td { border: 0px solid red; } #+end_src #+caption: Example table | Prime | 2^{Prime} | |-------+-----------| | | | | 1 | 2 | | 2 | 4 | | 3 | 8 | | 5 | 32 | | 7 | 128 | | 11 | 2048 | #+TBLFM: $2='(expt 2 $1);N # For the line wrapping, it may be useful to have # =#+PROPERTY: header-args -n= at the top of the file # to have all blocks displayed with line numbers. #+begin_src emacs-lisp ;; Table captions should be below the tables (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; /* background-color: pink; */ border-radius: 15px; color: hsl(157 75% 20%); font-size: 0.9em; box-shadow: 0.05em 0.1em 5px 0.01em #00000057; } #+end_src * Ξ: Floating /Table of Contents/ :PROPERTIES: :CUSTOM_ID: Floating-TOC :END: <> 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:
★     ★     ★

When we write =#+toc: headlines 2= in our Org, HTML export produces the following. #+begin_src html -n :exports code :tangle no :noeval

Table of Contents

  • section 1
  • section 𝓃
#+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 [[https://orgmode.org/worg/][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 # /* TOC entries, unnumbered lists, should not be indented too much */ # #text-table-of-contents ul { padding-left: 20px } Since the table of contents floats, the phrase /Table of Contents/ is rather ‘in your face’, so let's use the more subtle Greek [[https://en.wikipedia.org/wiki/Xi_(letter)][letter]] =Ξ=. #+begin_src emacs-lisp -n (advice-add 'org-html--translate :before-until 'blog/display-toc-as-Ξ) ;; (advice-remove 'org-html--translate 'display-toc-as-Ξ) (defun blog/display-toc-as-Ξ (phrase info) (when (equal phrase "Table of Contents") (s-collapse-whitespace "  Ξ  "))) #+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 ♥‿♥ # ( The Unicode whitespace ‘ ’ before and after =Ξ= is to appease the [[clickable-headlines][clickable headlines utility]], below. ) Finally, #+begin_src emacs-lisp :exports code ;; I'd like to have tocs and numbered headings (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 "%s" 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: <> Org loads the [[https://math.meta.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference][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:
#+begin_details "The script that Org loads by default" #+begin_src emacs-lisp -n :noweb-ref my-html-header :tangle no " " #+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 " " #+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 [[https://www.amirifont.org/][الخط الأمیری]] since that's [[http://alhassy.com/arabic-roots#Arabic-Input-Setup][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." " ") #+end_src To understand /why/ these styling rules work, see this website: [[https://rtlstyling.com/posts/rtl-styling#handling-fonts][Right-to-left Styling]]. #+end_details #+html:
#+begin_org-demo :source-color white :result-color white For example, + Inline: اهلاً وسهلاً + Within a table: | اهلاً وسهلاً | #+end_org-demo # Yuck! + Inline code: =اهلاً وسهلاً= 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: # My preview setup does a great job at "publishing" my articles, as such, it seems I don't really need use org-static-blog-publish-file. # (I would need org-static-blog-publish-file if I were to republish the entire blog, say via org-static-blog-publish) #+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)) ;; Placed article html into the published blog directory (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) ;; Make AlBasmala live with the other posts to avoid this conditional. (when (equal (f-base (buffer-file-name)) "AlBasmala") (blog/git "add AlBasmala.el"))) ;; Need to disable my export-preprocessing hooks. (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: I only need to update the tags pages relevant to the current article! ;; TODO: (message "⇒ Assembling RSS feed...") (org-static-blog-assemble-rss) (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: If we're updating an existing article, prompt for a message. (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 ;; No lock files, for now ;; The “.#file” files ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Interlocking.html#Interlocking (setq create-lockfiles nil) #+end_src :End: #+begin_src emacs-lisp -r -n ;; Override all minor modes that use this binding. (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))))) ;; Apparently I have to publish the current buffer before trying ;; to publish the blog; otherwise I got some errors. (4 (org-static-blog-publish-file (f-full (buffer-name))) (org-static-blog-publish)) (16 ;; (org-static-blog-publish t) ⇒ Crashes. ;; Delete all .html files, except “about” (thread-last (f-entries "~/blog/") (--filter (and (equal (f-ext it) "html") (not (member (f-base it) '("about"))))) (--map (f-delete it))) (ref:delAll) ;; Publish as usual (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. # - Line [[(BR)]]: =org-static-blog= does not support Org-markup in the title, since it # just dumps the title in-place; here I provide a support for just =
=. #+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 ;; The title "

" "
" (ref:fixTitle) "" (@title post) "" "

" ;; The date "
" (@date post) "
" ;; The article's image (@image post) "
Abstract
"))) #+end_src # Before we move on, Org-notes adds extra whitespace after the title, let's avoid # that. # #+begin_src css :tangle ~/blog/blog-banner.css :noeval # .title { margin: 0 0 0 0 !important; } # #+end_src * The name: [[https://en.wikipedia.org/wiki/Basmala][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 [[https://en.wikipedia.org/wiki/%22Hello,_World!%22_program]["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 [[https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site][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 [[https://www.whatsmydns.net/#A/alhassy.com][service like this]]. - It took me about 1/2hour for the URL to redirect to my github.io blog. Further resources: - [[https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site][Managing a custom domain for your GitHub Pages site - GitHub Docs]] - [[https://richpauloo.github.io/2019-11-17-Linking-a-Custom-Domain-to-Github-Pages/][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: # Some sections in this article come from my init.org. # # As such, the {{{from-my-init}}} macro is used to provide a nice, small, linkable, message. # Implementation below. ############################################################ # This CSS rule targets all images within anchors within a
that has a class named “tiny”. In particular, it's used # to target badges so that they are about the same size as text. #+html: #+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:
@@ {{{from-my-init-text}}} @@html:
@@ *** COMMENT Example usage {{{from-my-init}}} <> #+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 ;; If you download images, from unspash, you'll have to host them somewhere! ;; An alternative is just to provide direct links to the unsplash images themselves! ;; ;; Example usage: ;; unsplash:gySMaocSdqs ;; ;; This shows an image along with a useful tooltip; image size is 200x200 by default. ;; The image is also a link, redirecting to the source, including whomever took the original photo. #+end_src (-let [unsplash (cl-second (s-match ".*unsplash.com/photos/\\(.*\\)" "https://unsplash.com/photos/Vc2dD4l57og"))] (if unsplash (format "
" unsplash unsplash))) unsplash:XXX0GQfgMy8