My Personal Website
Find a file
Pierre-antoine Comby b576d3fbf4
update late august
2025-08-30 12:07:45 +02:00
.github/workflows update 2024-04-10 15:11:54 +02:00
archetypes Initial commit 2022-11-07 21:12:06 +00:00
assets feat: add scholar icons 2024-08-28 11:41:21 +02:00
config/_default hugo chores 2025-08-29 12:16:39 +02:00
content-org update late august 2025-08-30 12:07:45 +02:00
layouts update late august 2025-08-30 12:07:45 +02:00
lisp fix: xkcd update 2025-08-29 12:16:31 +02:00
resume@a2bc1ff71a bump CV 2025-08-29 13:30:02 +02:00
static update late august 2025-08-30 12:07:45 +02:00
themes update late august 2025-08-30 12:07:45 +02:00
.DS_Store added multi-lang example 2024-01-04 23:11:25 +00:00
.gitignore update 2024-09-03 19:53:24 +02:00
.gitmodules update 2024-04-10 15:11:54 +02:00
.hugo_build.lock added multi-lang example 2024-01-04 23:11:25 +00:00
build.el update late august 2025-08-30 12:07:45 +02:00
build.sh update 2024-04-11 22:28:42 +02:00
LICENSE Initial commit 2022-11-07 21:12:06 +00:00
Makefile udpate 2024-11-01 10:00:59 +01:00
README.org update late august 2025-08-30 12:07:45 +02:00
update.sh updated theme 2023-08-15 10:54:50 +01:00

My Website build using Orgmode and Hugo

This repository hosts the sources for /paquiteau/website/src/branch/main/pierre-antoine-comby.fr, my personal website

  • 🛠️ It is built using Hugo, a static site generator, and Org mode, an Emacs mode for notes, planning, and authoring.
  • 🔗 Connecting the two is done using ox-hugo, an Emacs package that provides an export backend for Org mode to Hugo.
  • The theme used is Blowfish, a beautiful and minimal theme for Hugo.

Building the website

TL;DR

  1. Have emacs , git , make , hugo and rclone installed
  2. Clone the repository
  3. Run the bootstrap command:
emacs -Q --batch --eval "(progn (require 'ob-tangle) (org-babel-tangle-file "'"'"README.org"'"'"))"
  1. Run make to build the website and the resume
make
  1. Run make deploy to deploy the website. This requires rclone to be configured (and it remains my secret).
   make deploy

Build dependencies

(setq package-user-dir (expand-file-name "./.packages"))
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
                         ("elpa" . "https://elpa.gnu.org/packages/")))

;; Initialize the package system
(package-initialize)
(unless package-archive-contents
  (package-refresh-contents))

(use-package ox-hugo
  :ensure t
  :pin melpa
  :after ox)

(use-package citeproc
  :ensure t
  :pin melpa)

(use-package emacsql
  :ensure t)

(use-package xkcd
  :ensure t
  :pin melpa)

;; (require 'citeproc)
(require 'ox-publish)

;; custom packages
(load (expand-file-name "lisp/xkcd-extras.el"))
;; (load (expand-file-name "lisp/lorem.el"))

;; a single line fix is required for custom link type to work with info backend.
(load (expand-file-name "lisp/custom-org-hugo-link.el"))

A Custom export backend for blowfish

Expanding the capabilities of ox-hugo and tweaking it for using blowfish template.

(setq pac/blowfish-paired-shortcodes '("alert"
                                       "article"
                                       "badge"
                                       "button"
                                       "carousel"
                                       "codeimporter"
                                       "codeberg"
                                       "figure"
                                       "forgejo"
                                       "gallery"
                                       "keyword"
                                       "keywordList"
                                       "lead"
                                       "mdimporter"
                                       "mermaid"
                                       "timeline")
      pac/blowfish-shortcodes '("lead" "icon" "katex" "github" "gitlab" "gitea" "forgejo" "codeberg" "codeimporter" "youtubeLite"))

(setq org-hugo-paired-shortcodes (string-join pac/blowfish-paired-shortcodes " "))

(setq org-export-global-macros '(
("icon" . "@@hugo:{{< icon \"$1\" >}}@@")
("katex" . "@@hugo:{{< katex >}}@@")
("github" . "@@hugo:{{< mygithub repo=\"$1\" >}}@@")
("gitlab-raw" . "@@hugo:{{< gitlab repo=\$1\", server=\"$2\" >}}@@") ;; FIXME
("gitea" . "@@hugo:{{<gitea repo=\"$1\" server=\"$2\"  >}}@@")
;; 2nd level
("gitea-comby" . "{{{gitea($1, https://git.comby.xyz)}}}")
("gitlab-crans" . "{{{gitlab-raw($1, https://gitlab.crans.org)}}}")
("gitlab" . "{{{gitlab-raw($1, https://gitlab.com)}}}")
("chaithyagr". "[[https://chaithyagr.github.io/][Chaithya GR]]")
                                ) )

Custom link types

XKCD

(org-link-set-parameters "xkcd"
                         :image-data-fun #'+org-xkcd-image-fn
                         :follow #'+org-xkcd-open-fn
                         :export #'+org-xkcd-export
                         :complete #'+org-xkcd-complete)

(defun +org-xkcd-open-fn (link)
  (+org-xkcd-image-fn nil link nil))


(defun +org-xkcd-image-fn (protocol link description)
  "Get image data for xkcd num LINK"
  (let* ((xkcd-info (+xkcd-fetch-info (string-to-number link)))
         (img (plist-get xkcd-info :img))
         (alt (plist-get xkcd-info :alt)))
    (message alt)
    (+org-image-file-data-fn protocol (xkcd-download img (string-to-number link)) description)))

(defun +org-xkcd-export (num desc backend &optional _com)
  "Convert xkcd to html/LaTeX form"
  (let* ((xkcd-info (+xkcd-fetch-info (string-to-number num)))
         (img (plist-get xkcd-info :img))
         (alt (plist-get xkcd-info :alt))
         (title (plist-get xkcd-info :title))
         (file (xkcd-download img (string-to-number num))))
    ;; TODO add cond ox-hugo
    (cond ((org-export-derived-backend-p backend 'md)
           (format "{{< figure src=\"%s\" alt=\"%s\" caption=\"%s\" >}}" img  (subst-char-in-string 34 8220 alt) (or desc title)))
          ;; ((org-export-derived-backend-p backend 'html)
          ;;  (format "<img class='invertible center' src='%s' title=\"%s\" alt='%s'>" img (subst-char-in-string 34 8220 alt) title)) ;; "" -->  “”
          ((org-export-derived-backend-p backend 'latex)
           (format "\\begin{figure}[!htb]
  \\centering
  \\includegraphics[scale=0.4]{%s}%s
\\end{figure}" file (if (equal desc (format "xkcd:%s" num)) ""
                      (format "\n  \\caption*{\\label{xkcd:%s} %s}"
                              num
                              (or desc
                                  (format "\\textbf{%s} %s" title alt))))))
          (t (format "https://xkcd.com/%s" num)))))

Highlighted files

We put the file in a keyword box with a nice box

(org-link-set-parameters "hfile"
                         :complete #'org-link-complete-file
                         :follow #'org-link-open-in-emacs
                         :face 'org-link
                         :help-echo "Open file"
                         :export #'+org-hugo-export-keywords)
(defun +org-hugo-export-keywords (path desc backend info)
  "Export a hfile link."
  (cond ((org-export-derived-backend-p backend 'md)
         ;; call org-hugo-link for doing the heavy lifting for us
  (let* (
         (path (org-hugo--attachment-rewrite-maybe (expand-file-name path) info)))
               ;; use our shortcode
               (format "{{< mykeyword icon=\"download\" link=\"%s\" >}} %s {{< /mykeyword >}}" path (or desc "file"))))
         (t (format "[[file:%s][%s]]" path (or desc path)))))

Referencing standards and development

(org-link-set-parameters "pep"
                         :export (lambda (link desc backend _protocol)
                                   (let ((desc (or desc (format "PEP %s" link))))
                                     (cond ((org-export-derived-backend-p backend 'md)
                                            (format "[%s](https://peps.python.org/pep-%s/)" desc link))
                                           (t (format "https://peps.python.org/pep-%s/" link)))))
                         :follow (lambda (link)
                                   (browse-url (format "https://peps.python.org/pep-%s/" link)))
                         :help-echo "Open PEP"
                         :face 'org-linrightdoubk)

Export

And this is how we do the export:

(setq org-hugo-citations-plist '(:bibliography-section-heading "")
      org-hugo-base-dir (expand-file-name ".")
      org-hugo-section "post"
      org-export-html-date-format-string "%Y-%m-%d"
      )
(defun pac/org-hugo-publish (plist filename pub-dir)
  (org-open-file filename)
    (org-hugo-export-wim-to-md t))

Customizing the bibliography export

Just a little tweak to highlight my name in the bibliography.

(defvar org-hugo--highlight-bibliography-regex (rx (or "comby" "Pierre-Antoine" "P-A" "P.-A." "Comby"))
  "list of strings to highlight in the bibliography")


(defun org-hugo--org-cite-export-bibliography (orig-fun &rest args)
  "Insert a heading before the exported bibliography.

ORIG-FUN is the original function `org-cite-export-bibliography'
that this function is designed to advice using `:around'.  ARGS
are the arguments of the ORIG-FUN."
  (let ((bib (apply orig-fun args)))
    (let ((case-fold-search t))
          (setq bib (replace-regexp-in-string org-hugo--highlight-bibliography-regex "<span class=\"font-bold\">\\&</span>" bib t nil)))
    (when (org-string-nw-p bib)
      ;; Auto-inject Bibliography heading.
      (let ((info (nth 2 args)) ;(org-cite-export-bibliography KEYWORD _ INFO)
            (bib-heading (or (plist-get org-hugo-citations-plist :bibliography-section-heading) "References")))
        (when bib-heading
          (let* ((bib-heading (org-blackfriday--translate nil info bib-heading))
                 (loffset (string-to-number
                           (or (org-entry-get nil "EXPORT_HUGO_LEVEL_OFFSET" :inherit)
                               (plist-get info :hugo-level-offset))))
                 (level-mark (make-string (+ loffset 1) ?#)))
            (format "%s %s\n\n%s" level-mark bib-heading bib)))))))
org-hugo--org-cite-export-bibliography

Plumbing ox-hugo with org-publish

(setq org-export-with-broken-links t)
(setq org-publish-project-alist `(("mainsite"
                                   :base-directory ,(expand-file-name "content-org")
                                   :recursive t
                                   :exclude "intro.org"
                                   :publishing-directory "content"
                                   :publishing-function pac/org-hugo-publish)))

(message "default directory %s" default-directory)
(org-publish-all '(4))
(message "Export done")

Some nice to have

These are not use in the build process, but help with the writing and local exporting.

local variable for emacs

((nil . (
         (org-hugo-section . "post")
         (org-hugo-use-code-for-kbd . t)
         ))

 ("content-org/"
  . ((org-mode . (
                  (org-hugo-base-dir . "..")
                ;;  (eval . (org-hugo-auto-export-mode))
                  )))))

Automate things with a makefile

build: build_resume org_files
		hugo

org_files: $(wildcard content-org/*.org)
		# rm -rf content/
		emacs -Q --script build.el

build_resume:
		cd resume; latexmk -pdf CV2.tex
		cp resume/CV2.pdf assets/CV2.pdf


deploy: cleanall build
		hugo --gc --minify
		rclone sync public/ blog:www/ --delete-before

cleanall:
		rm -rf public/*
		rm -rf content/*

TODO Use CI to handle the deployment

For now I do it manually, but it would be nice to have a CI pipeline to do it automatically.

How to write a blog post

I use Ox-Hugo for the export from org mode to md (to html/css/js with Hugo).

https://ox-hugo.scripter.co/

https://blowfish.page/docs/shortcodes/