2025-09-30 Hyperbole and Asciidoc

I've started using Hyperbole. I switch off my computers in the evenings. So every morning, Emacs starts fresh. The first thing I want to see is the directory names of various projects I'm working on. This reminds me of the things I'm doing and `M-RET` on these directory names takes me there to do them.

Hyperbole

My short config is below. With it, `~/.emacs.d/hyperb/HYPB` is the first buffer I see (instead of `*scratch*`). I've used Enriched Mode to add some bold headers to group the various starting points.

(use-package hyperbole
  :ensure t
  :config
  (setq hbmap:dir-user "~/.emacs.d/hyperb"
        initial-buffer-choice (expand-file-name
                               hbmap:filename
                               hbmap:dir-user))
  (hyperbole-mode 1))

At work the documentation is written in Asciidoc.

This here helps me jump to stuff.

(defib adoc-xref ()
  "Follow adoc references and open the associated file."
  (let* ((data (or (adoc-example-at-point)
                   (adoc-image-at-point)
                   (adoc-page-at-point)
                   (adoc-include-at-point)
                   (adoc-attribute-use-at-point)))
         (modules-dir (asc:modules-directory))
         module dir file target regexp)
    (when (and data (not (string= modules-dir "/")))
      (cond ((= 4 (length data)) (setq module (nth 1 data) dir (nth 0 data) file (nth 2 data) regexp (nth 3 data)))
            ((= 3 (length data)) (setq module (nth 1 data) dir (nth 0 data) file (nth 2 data)))
            ((= 2 (length data)) (setq module (asc:module-name) dir (nth 0 data) file (nth 1 data))))
      (setq target (file-name-concat modules-dir module dir file))
      (ibut:label-set target)
      (if regexp
          (hact 'link-to-regexp-match (concat ":" regexp ":") 1 target)
        (hact 'link-to-file target)))))

The helper functions include some very peculiar stuff like the fixed path in `adoc-attribute-use-at-point` from an `include::ROOT:partial$attributes.adoc[]` at the beginning of every file.

(autoload 'adoc-xref-id-at-point "adoc-mode")

(defun adoc-example-at-point ()
  "Return the example at point."
  (save-excursion
    (goto-char (line-beginning-position))
    (when (looking-at "include::example\\$\\([^[]+\\)")
      (append '("examples") (split-string (match-string 1) ":")))))

(defun adoc-image-at-point ()
  "Return the image at point."
  (save-excursion
    (goto-char (line-beginning-position))
    (when (looking-at "image::\\([^[]+\\)")
      (append '("images") (split-string (match-string 1) ":")))))

(defun adoc-page-at-point ()
  "Return the page at point."
  (save-excursion
    (let ((id (adoc-xref-id-at-point)))
      (when id
        (setq id (car (split-string id "#")))
        (append '("pages") (split-string id ":"))))))

(defun adoc-include-at-point ()
  "Return the file at point."
  (save-excursion
    (goto-char (line-beginning-position))
    (when (looking-at "include::\\([^[]+\\)")
      (let ((elems (split-string (match-string 1) ":")))
        (when (string-match "^partial\\$" (car (last elems)))
          (setcar (last elems) (substring (car (last elems)) 8)))
        (append '("partials") elems)))))

(defun adoc-attribute-use-at-point ()
  "Return the attribute used at point."
  (save-excursion
    (let ((from (when (or (eq (char-before) ?\{)
                          (and (forward-word -1)
                               (eq (char-before) ?\{)))
                  (point)))
          (to (and (forward-word 1)
                   (eq (char-after) ?\})
                   (point))))
      (when (and from to)
        (let ((attribute (buffer-substring from to)))
          (list "partials" "ROOT" "attributes.adoc" attribute))))))

(defun asc:modules-directory ()
  "Return the modules directory we're in."
  (let ((dir default-directory))
    (while (and
            (not (string= dir "/"))
            (not (string= "modules"
                          (file-name-nondirectory
                           (directory-file-name dir)))))
      (setq dir (expand-file-name
                 (file-name-concat dir ".."))))
    dir))

(defun asc:module-name ()
  "Return the name of the module we're in."
  (let ((dir default-directory)
        last)
    (while (not (string= "modules"
                         (file-name-nondirectory
                          (directory-file-name dir))))
      (setq last (file-name-nondirectory
                  (directory-file-name dir))
            dir (expand-file-name
                 (file-name-concat dir ".."))))
    last))

#Emacs ​#Hyperbole

(defun asc:send-to-clip (text)
  "Send TEXT to clip.exe.
This makes the text available on Windows."
  (call-process-region text nil "clip.exe"))

(setq interprogram-cut-function 'asc:send-to-clip)