UP | HOME

My Personal Weblog

SBCL Setup with MSYS2 on Windows

1. Download and Install MSYS2

  • Visit the official MSYS2 website at https://www.msys2.org/ and download the latest installer.
  • Run the downloaded installer and follow the on-screen instructions to install MSYS2. The default installation path (C:\msys64) is recommended.
  • After installation, open MSYS2 using the shortcut created in the Start Menu.
  • Update the package database and base packages by running the following commands in the terminal: pacman -Syu
  • Close the terminal if prompted, then reopen it and complete the update process with: pacman -Su

2. Install Build Essentials for UCRT64

  • In the MSYS2 terminal, install the build essentials for the UCRT64 environment by executing: pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain
  • This command installs the necessary compilers and tools to build software using the UCRT64 environment.

3. Download and Install SBCL

  • Go to the SBCL website at http://www.sbcl.org/ and download the latest Windows binary available.
  • Run the installer and follow the prompts to install SBCL. Note the installation directory (e.g., C:\Program Files\Steel Bank Common Lisp).

4. Clone the SBCL Git Repository

  • Open the MSYS2 terminal and clone the SBCL repository to the ~/sbcl directory with: git clone git://git.code.sf.net/p/sbcl/sbcl ~/sbcl

5. Checkout the Latest SBCL Version

  • Open the UCRT64 MSYS2 terminal as administrator. You can do this by right-clicking the UCRT64 shortcut and selecting “Run as administrator.”
  • Change the directory to the cloned SBCL source with: cd ~/sbcl
  • Checkout the latest tagged version (e.g., 2.4.1) with: git checkout sbcl-2.4.1

6. Build SBCL

  • Add the Windows SBCL binary to your PATH by executing:export PATH=$PATH:’c/Program Files/Steel Bank Common Lisp
  • In the UCRT64 terminal (still as administrator), navigate to the ~/sbcl directory and start the build process with: sh make.sh --fancy
  • This process may take some time, depending on your capabilities.

7. Install the Built SBCL Version

  • After the build completes successfully, install SBCL by running: sh install.sh
  • Follow any on-screen prompts to complete the installation.

8. Install libzstd.dll Dependency

  • SBCL depends on libzstd.dll to run. Download the DLL from the latest release at https://github.com/facebook/zstd/releases.
  • After downloading, place libzstd.dll in a directory that is part of your PATH environment variable, or add the directory where you placed libzstd.dll to your PATH. This can be done by:
    • Searching for “Environment Variables” in Windows search, opening the dialog.
    • In the “System Properties” window, click on “Environment Variables”.
    • In the “System Variables” section, find the Path variable and select “Edit”.
    • Add the path to the directory containing libzstd.dll.
    • Click “OK” to close each dialog and apply the changes.

Extract headlines and their content from current buffer by tag

I wanted to share a function that I’ve found incredibly useful while conducting qualitative data analysis of interviews. During this type of research, structuring my interview data and maintaining a clear overview is crucial. To assist with this, I’ve developed a function in Emacs Lisp that uses tags to extract specific headlines into a new buffer.

This function, extract-headlines-by-tag, prompts the user to enter a tag. The function then scans the entire buffer, and for each headline that contains the specified tag, it extracts not only the headline but also its content. These extracted parts are then transferred into a new buffer. I’ve made the new buffer pop up for immediate review after the extraction process.

Here’s the piece of code:

(defun extract-headlines-by-tag (tag)
  "Extract headlines and their content from current buffer by TAG."
  (interactive "sEnter tag: ")
  (save-excursion
    (let ((result-buffer (generate-new-buffer (concat "/Extracted Headlines " tag "*"))))
      (with-current-buffer result-buffer
        (org-mode)
        (insert "* Extracted Headlines by Tag: " tag " *\n\n"))
      (org-element-map (org-element-parse-buffer) 'headline
        (lambda (headline)
          (when (member tag (org-element-property :tags headline))
            (with-current-buffer result-buffer
              (insert (org-element-interpret-data headline) "\n")))))
      (pop-to-buffer result-buffer))))

#emacs #elisp #lisp

Use org tables with custom elisp functions

Just wanted to show you how to use org tables with custom elisp functions, in case you dont know its possible:

The following table shows results from a questionnaire:

#+name: sus-questionnaire-results
#+caption: SUS Questionnaire Results
#+attr_latex: :align l|r|r|r|r|r|r|r|r|r|r|l  :font \fontspec{Noto Sans Condensed Light}
| USER | Q1 | Q2 | Q3 | Q4 | Q5 | Q6 | Q7 | Q8 | Q9 | Q10 |  SUS |
|------+----+----+----+----+----+----+----+----+----+-----+------|
| U1   |  5 |  2 |  2 |  1 |  3 |  4 |  3 |  2 |  1 |   1 | 60.0 |
| U2   |  5 |  2 |  4 |  2 |  5 |  1 |  4 |  1 |  4 |   1 | 87.5 |
| U3   |  5 |  2 |  4 |  1 |  4 |  2 |  4 |  1 |  4 |   3 | 80.0 |
#+tblfm: $12='(ux:sus-calc-score-per-row '($2..$11));N

The SUS column is calculated for each row using the values from column 2 to 11. When the ā€˜Nā€™ flag is used, all referenced elements are parsed as numbers and interpolated as Lisp numbers

Here is the elisp function:

(defun ux:sus-calc-score (lst)
  (let ((counter 0))
    (mapcar (lambda (x)
              (setq counter (1+ counter))
              (if (= 0 (% counter 2))
                  (- 5 x)
                (1- x)))
            lst)))

(defun ux:sus-calc-score-per-row (lst)
  (* (apply '+ (ux:sus-calc-score lst)) 2.5))

Thats all!

Execute lisp files as scripts (sbcl)

Standard Unix tools that are interpreters follow a common command line protocol that is necessary to work with “shebang scripts”. SBCL doesn’t do this by default, but adding the following snippet to an initialization file does the trick:

;; content of ~/.sbclrc

;;; If the first user-processable command-line argument is a filename,
;;; disable the debugger, load the file handling shebang-line and quit.
(let ((script (and (second *posix-argv*)
                   (probe-file (second *posix-argv*)))))
  (when script
    ;; Handle shebang-line
    (set-dispatch-macro-character #\# #\!
                                  (lambda (stream char arg)
                                    (declare (ignore char arg))
                                    (read-line stream)))
    ;; Disable debugger
    (setf *invoke-debugger-hook*
          (lambda (condition hook)
            (declare (ignore hook))
            ;; Uncomment to get backtraces on errors
            ;; (sb-debug:backtrace 20)
            (format *error-output* "Error: ~A~%" condition)
            (quit)))
    (load script)
    (quit)))
#!/usr/local/bin/sbcl --noinform
(write-line "Hello, World!")

Sharing Emacs Org-Mode Capture Template Optimization

Hey #Emacs enthusiasts! I’ve been working on optimizing my #OrgMode capture templates, and I thought I’d share what I’ve come up with.

The goal is to make note-taking and task management more interconnected and context-aware. I wanted to automatically link notes to tasks I’m currently working on, or manually link them if no task is clocked in.

This function checks if a task is clocked in. If yes, it grabs the ID and heading of that task and formats it into an Org link. If no task is clocked in, it prompts for a manual ID.

(defun mk/link-to-current-task ()
  "Return an Org link to the current clocked-in task, if any, or prompt for manual entry."
  (if (org-clock-is-active)
      (with-current-buffer (marker-buffer org-clock-marker)
        (save-excursion
          (goto-char org-clock-marker)
          (format ":TASK_ID: [[id:%s][%s]]"
                  (org-id-get)
                  (org-get-heading t t))))
    (let ((manual-id (read-string "Enter Task ID (leave empty if not applicable): ")))
      (unless (string-empty-p manual-id)
        (format ":TASK_ID: [[id:%s][Manual Task]]" manual-id)))))

This template captures a note and uses the above function to populate a :TASK_ID: property, linking the note to a task.

(add-to-list 'org-capture-templates
             `("n" "Note" entry (file+headline "agenda/notes.org" "Notes")
               ,(concat "* %? :NOTE:\n"
                        ":PROPERTIES:\n"
                        "%(mk/link-to-current-task)\n"
                        ":END:\n"
                        "%i\n%a\n"
                        "Entered on: %U\n")))

This template automatically generates an :ID: property when capturing a new task.

(add-to-list 'org-capture-templates
             `("t" "Task" entry (file "agenda/tasks.org")
                   ,(format "* TODO %%? :TASK:\n:PROPERTIES:\n:ID: %s\n:END:\nEntered on %%U\n%%a"
                            (org-id-new))))

Hope you find this useful! Feedback and improvements are always welcome. #EmacsLife #Productivity

How do I perform spell checking in Emacs?

[2023-02-25 Sat] Use hunspell instead of aspell as background service for spell checking. Why? because hunspell allows you to use more than one dictionary at the same time.

Windows

On Windows, you need to setup msys2 to install hunspell.

Emacs

(use-package ispell
  :ensure nil
  :custom
  ;; On windows: Copy files from ~/.emacs.d/dicts/ to c:/msys64/mingw64/share/dict/ooo/
  (ispell-dictionary "german,english")
  (ispell-local-dictionary-alist
   '(("german" "[[:alpha:]]" "[^[:alpha:]]" "[']" t ("-d" "de_DE_frami,de_AT_frami,de_CH_frami") nil utf-8)
     ("english" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US,en_GB") nil utf-8)
     ("german,english" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "de_DE_frami,en_US") nil utf-8)))
  (ispell-hunspell-dictionary-alist ispell-local-dictionary-alist)
  :config
  (if (eq system-type 'windows-nt)
      (setq ispell-program-name "c:/msys64/mingw64/bin/hunspell.exe")
    (setq ispell-program-name "hunspell")))

Update ox-rss.el to use :CUSTOM_ID property for custom urls

[2023-01-30 Mon] If you are using ox-rss to export an RSS file from org, and want to use custom urls and not the reference number generate by org. You need to set a :CUSTOM_ID property for every headline. Change the code in ox-rss.el on line 247:

(anchor (org-export-get-reference headline info))

to the following code:

(anchor
 (or (org-element-property :CUSTOM_ID headline)
     (org-export-get-reference headline info)))

Private cloud for file sharing

[2023-01-29 Sun] If you are like me, and have more than one PC or smartphone, you need to share important files between these devices. I was looking for an private cloud which respects the EU GDPR. I found a excelent service provided by Hetzner, the Storage Share.

Author: Marcus Kammer

Email: marcus.kammer@mailbox.org

Date: Sun, 10 Mar 2024 11:18 +0100

Emacs 29.1.90 (Org mode 9.6.11)

License: CC BY-SA 3.0

Subscribe: RSS Feed