2025-07-29 09:28:16 +02:00
#+TITLE : My Emacs Configuration
2024-08-07 09:51:49 +02:00
#+PROPERTY : header-args :tangle yes
2024-08-11 11:36:44 +02:00
#+PROPERTY : header-args:emacs-lisp :lexical yes :tangle yes :comments nil :padline yes
2024-08-07 09:51:49 +02:00
2024-07-30 14:40:34 +02:00
* Literate Configuration for Emacs
2024-08-04 01:37:17 +02:00
** Goals
2024-07-30 14:40:34 +02:00
- Manage *init.el* as an org-file
- Leverage inclusion of ~use-package~ in Emacs29 for configuration and
loading
- Reduce dependencies : read evaluate the value a package brings
before including it
- Refactor existing configuration
2024-07-30 20:09:06 +02:00
** Notes on Elpaca and dev versions of emacs.
Elpaca needs the build date of emacs to compare to package versions or
2024-12-03 13:14:31 +01:00
something. However it does not support all dev versions.
2024-07-30 20:09:06 +02:00
For guix emacs-next packages you can find the date with: ( <C-c C-c >
in the source block below:
#+BEGIN_SRC shell
stat /gnu/store/ *emacs-next-[23]* .drv | rg Birth | cut -d' ' -f3 | tr -d '-'
#+END_SRC
#+RESULTS :
| 20240727 |
| 20240727 |
2024-08-02 14:49:05 +02:00
It is possible there are more so probably the most recent one is the
one to use.
2024-07-30 20:09:06 +02:00
2024-07-30 16:45:22 +02:00
** Inspiration Sources
2024-07-30 14:40:34 +02:00
2024-07-30 16:45:22 +02:00
- [[https://pages.sachachua.com/.emacs.d/Sacha.html ][Sacha Chua's Emacs config ]]
- [[https://github.com/jwiegley/use-package ][GitHub repo for use-package ]]
- [[https://github.com/jwiegley/dot-emacs/blob/master/init.org ][John Wiegley's .emacs file ]]
- [[https://github.com/TheBB/dotemacs/blob/master/init.el ][Eivind Fonn's init.el ]]
2024-08-04 01:37:17 +02:00
2025-06-02 16:13:05 +02:00
** Make tangled file read-only
Add a preamble to the file to ensure some global settings, most
importantly make the file read-only to avoid editing the tangled file by
accident instead of the source in the org-mode file.
#+BEGIN_SRC emacs-lisp
;; init.el --- Literate configuration for Emacs -*- lexical-binding: t; read-only-mode: t; -* -
;;
;;; Commentary:
;;
;; DO NOT EDIT!!!
;;
;; This file is automatically generated from the source in *init.org* .
;;
#+END_SRC
Also immediately set lexical binding mode.
2024-12-10 09:59:35 +01:00
* First Things First
** Bootstrapping Emacs Configuration
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp :tangle "early-init.el"
2025-06-02 16:13:05 +02:00
;; early-init.el --- Bootstrap Emacs -*- lexical-binding: t; read-only-mode: t; -* -
2024-12-02 14:43:46 +01:00
2025-01-08 11:57:26 +01:00
;;; Bootstrap elpaca
(setq package-enable-at-startup nil)
;; for guix emacs-next packages you can find the date with
;; ➜ stat /gnu/store/ *emacs-next-[23]* .drv | rg Birth | cut -d' ' -f3 | tr -d '-'
;; 20240727
;;
;; it is possible there are more so probably the most recent one is the one to use.
2025-01-19 19:09:13 +01:00
(when emacs-build-time
2025-06-02 16:16:48 +02:00
(setq elpaca-core-date (format-time-string "%Y%m%d" emacs-build-time)))
(defvar elpaca-installer-version 0.11)
2025-01-08 11:57:26 +01:00
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
2025-06-02 16:16:48 +02:00
:ref nil :depth 1 :inherit ignore
2025-01-08 11:57:26 +01:00
:files (:defaults "elpaca-test.el" (:exclude "extensions"))
:build (:not elpaca--activate-package)))
(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory))
(build (expand-file-name "elpaca/" elpaca-builds-directory))
(order (cdr elpaca-order))
(default-directory repo))
(add-to-list 'load-path (if (file-exists-p build) build repo))
(unless (file-exists-p repo)
(make-directory repo t)
2025-06-02 16:16:48 +02:00
(when (<= emacs-major-version 28) (require 'subr-x))
2025-01-08 11:57:26 +01:00
(condition-case-unless-debug err
(if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap* "))
2025-06-02 16:16:48 +02:00
((zerop (apply #'call-process `("git" nil ,buffer t "clone"
,@(when-let* ((depth (plist-get order :depth)))
(list (format "--depth=%d" depth) "--no-single-branch"))
,(plist-get order :repo) ,repo))))
((zerop (call-process "git" nil buffer t "checkout"
(or (plist-get order :ref) "--"))))
(emacs (concat invocation-directory invocation-name))
((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
"--eval" "(byte-recompile-directory \".\" 0 'force)")))
((require 'elpaca))
((elpaca-generate-autoloads "elpaca" repo)))
2025-01-08 11:57:26 +01:00
(progn (message "%s" (buffer-string)) (kill-buffer buffer))
(error "%s" (with-current-buffer buffer (buffer-string))))
((error) (warn "%s" err) (delete-directory repo 'recursive))))
(unless (require 'elpaca-autoloads nil t)
(require 'elpaca)
(elpaca-generate-autoloads "elpaca" repo)
2025-06-02 16:16:48 +02:00
(let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
2025-01-08 11:57:26 +01:00
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
;; Enable :elpaca use-package keyword.
(elpaca elpaca-use-package
2025-06-02 16:16:48 +02:00
(elpaca-use-package-mode))
2024-12-02 14:43:46 +01:00
#+END_SRC
2024-12-03 13:14:31 +01:00
Tangle the init file if it has been updated. I maintain the same
2024-12-02 14:43:46 +01:00
configuration on multiple machines and fetch changes with a ~git pull~
2024-12-03 13:14:31 +01:00
outside emacs so there is on opportunity to tangle the new file. If
2024-12-02 14:43:46 +01:00
I see it is outdated I tangle it.
2025-06-02 16:13:05 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
2024-12-03 13:14:31 +01:00
;; tangling to generate scripts for the local bin directory. This
2024-12-02 14:43:46 +01:00
;; causes the name of the scripts to be returned in the car of the
2024-12-03 13:14:31 +01:00
;; tangle command which is used to load the file. The net result is
2024-12-02 14:43:46 +01:00
;; that not the initialization is loaded, but the first exported
;; script.
(use-package ob-tangle)
(let ((src (concat user-emacs-directory "init.org"))
(tgt (concat user-emacs-directory "init.el"))
(enable-local-variables nil)) ;; disable local variables to prevent asking confirmation before frame is available
(when (file-newer-than-file-p src tgt)
(message "tangling init.org")
(delete-file tgt)
(org-babel-tangle-file src tgt "emacs-lisp")))
#+END_SRC
2024-07-30 14:40:34 +02:00
** Set the garbage collector threshold, to avoid collections
2024-11-11 17:10:55 +01:00
The emacs history goes back to times where memory was counted in
2024-12-03 13:14:31 +01:00
bytes, not gigabytes. We can afford to be a bit more generous with the
2024-11-11 17:10:55 +01:00
garbage collector settings.
2024-07-30 14:40:34 +02:00
#+begin_src emacs-lisp
(setq gc-cons-percentage 0.5
gc-cons-threshold (* 128 1024 1024))
#+end_src
** Report time spent loading the configuration
#+begin_src emacs-lisp
2024-08-04 01:37:17 +02:00
(defconst emacs-start-time (current-time))
(defun report-time-since-load (&optional suffix)
"Report the time since the file was init script was started.
2024-07-30 14:40:34 +02:00
2024-08-04 01:37:17 +02:00
If SUFFIX is provided, it is appended to the message."
2024-08-11 11:36:44 +02:00
(message "%.3fs: %s"
2024-08-04 01:37:17 +02:00
(float-time (time-subtract (current-time) emacs-start-time))
suffix))
2024-07-30 14:40:34 +02:00
2024-08-04 01:37:17 +02:00
(add-hook 'after-init-hook
#'(lambda () (report-time-since-load " [after-init]"))
t)
2024-08-07 09:51:49 +02:00
(report-time-since-load "start init file")
2024-07-30 14:40:34 +02:00
#+end_src
When looking for where the time goes, the `report-time-since-load`
with a string indicating the location in the init process can report
on the time since start.
*** Save customizations in a separate file
By default customization settings are saved at the end of the *init.el*
2024-12-03 13:14:31 +01:00
file. This wreaks havoc with managing the files in git and will not
2024-07-30 14:40:34 +02:00
work with the tangled version anyway as it will be removed/overwritten
each time the file is regenerated.
Here we set the location of the file to save the customizations and
then load it.
#+BEGIN_SRC emacs-lisp
;;; Code:
(setq custom-file (concat user-emacs-directory "custom.el"))
(when (and custom-file
(file-exists-p custom-file))
(load custom-file nil :nomessage))
#+END_SRC
2025-07-22 18:08:22 +02:00
*** Load transient as used by a lot of packages
2025-07-29 08:56:01 +02:00
#+BEGIN_SRC emacs-lisp
2025-07-22 18:08:22 +02:00
(use-package transient
2025-07-29 08:56:01 +02:00
:ensure t)
2025-07-22 18:08:22 +02:00
#+END_SRC
2025-07-29 08:56:01 +02:00
#+RESULTS :
2025-08-04 12:21:46 +02:00
: [nil 26768 31512 287826 nil elpaca-process-queues nil nil 20000 nil]
2025-07-29 08:56:01 +02:00
2025-07-22 18:08:22 +02:00
2024-12-02 14:43:46 +01:00
*** Wait for initial installations
#+BEGIN_SRC emacs-lisp
(elpaca-wait)
#+END_SRC
2025-08-04 10:48:03 +02:00
** Start Emacs Servers
To get a fast snappy editing experience in terminals emacs allows
running in client-server where the actual editing runs in an already
running process. This enables interaction with the other buffers in
the context/project and more importantly the client does not need to
load all the customizations in the init file. However the server must
be started for this to work.
If a server is already running it will be restarted. If clients are
connected to that server, confirmation will be asked. see [[help:server-start][server-start
documentation]] .
#+BEGIN_SRC emacs-lisp
(server-start)
#+END_SRC
#+RESULTS :
2024-08-05 10:32:04 +02:00
** Utility Functions
2024-08-09 10:32:41 +02:00
*** Reload dir local variables
#+BEGIN_SRC emacs-lisp
2025-01-19 13:59:42 +01:00
(defun snm-reload-dir-locals-for-current-buffer ()
2024-08-11 11:36:44 +02:00
"Reload dir locals for the current buffer."
2024-08-09 10:32:41 +02:00
(interactive)
(let ((enable-local-variables :all))
(hack-dir-local-variables-non-file-buffer)))
#+END_SRC
#+RESULTS :
2025-01-19 13:59:42 +01:00
: snm-reload-dir-locals-for-current-buffer
2024-08-09 10:32:41 +02:00
2024-08-05 10:32:04 +02:00
** Get latest version of a github released project
2024-12-03 13:14:31 +01:00
Many projects nowadays use github to release their software. However
2024-08-05 10:32:04 +02:00
there is no easy way to get the latest version of a project
2024-12-03 13:14:31 +01:00
provided. This functions uses the releases API to get the latest
2024-08-05 10:32:04 +02:00
metadata and get the version number from the JSON.
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(require 'url)
2025-01-19 13:59:42 +01:00
(defun snm-latest-github-release (repo)
2024-08-05 10:32:04 +02:00
"Return the latest version of the releases for REPO.
2024-08-11 11:36:44 +02:00
The repo should be in the form of `owner/repo'."
(with-temp-buffer
(url-insert-file-contents
(format "https://api.github.com/repos/ %s/releases/latest" repo))
(let ((result (json-read)))
(cdr (assoc 'name result)))))
2024-08-05 10:32:04 +02:00
#+END_SRC
2024-08-11 11:36:44 +02:00
#+RESULTS :
2025-01-19 13:59:42 +01:00
: snm-latest-github-release
2024-08-11 11:36:44 +02:00
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp :tangle no :results value
2025-01-19 13:59:42 +01:00
(snm-latest-github-release "plantuml/plantuml")
2024-08-11 11:36:44 +02:00
#+END_SRC
#+RESULTS :
2025-02-17 00:59:26 +01:00
: v1.2025.1
2024-08-11 11:36:44 +02:00
2025-08-05 20:56:14 +02:00
* Writing and Planning
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(report-time-since-load "Writing and Planning")
2024-08-11 11:36:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
** Org Mode
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
*** Org Configuration
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package org
:mode (("\\.org\\'" . org-mode))
:ensure nil
:demand t ; force loading to initialize constants
:custom
(org-return-follows-link t)
(org-mouse-1-follows-link t)
(org-link-descriptive t)
(org-agenda-skip-scheduled-if-done t)
(org-agenda-skip-deadline-if-done t)
(org-hide-emphasis-markers t)
(line-spacing 0.1)
(left-margin-width 2)
(right-margin-width 2)
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
(org-todo-keywords '((sequence "TODO(t)" "NEXT(n)" "WAITING(w)" "SOMEDAY(s)" "PROJ(p)"
"|" "DONE(d)" "CANCELED(c)")))
(org-todo-keywords-for-agenda '((sequence "NEXT(n)" "TODO(t)" "WAITING(w)" "SOMEDAY(s)" "PROJ(p)" "|" "DONE(d)" "CANCELED(c)")))
(org-agenda-files (list
"~/Nextcloud/org/ "
"~/org/snamellit/ "
"~/org/customer/ "
"~/org/personal/ "
"~/.org-jira/ "
))
(org-refile-targets '(
(org-agenda-files . (:level . 1))
("~/org/customer/gtd.org" . (:level . 1))
("~/org/personal/bijen.org" . (:level . 1))
("~/org/personal/fitness.org" . (:level . 1))
))
:config
(message "Configuring org mode")
;; set files for agenda views
(setq +org-capture-todo-file "~/Nextcloud/org/inbox.org"
+org-capture-notes-file "~/Nextcloud/org/inbox.org"
+org-capture-journal-file "~/Nextcloud/org/journal.org"
+org-capture-projects-file "~/Nextcloud/org/projects.org")
(setq org-log-done 'time)
(setq org-confirm-babel-evaluate nil)
(setq org-export-babel-evaluate nil)
(setq org-html-validation-link nil)
:hook (
(org-mode . org-indent-mode)
)
:bind (
("C-c a" . org-agenda)
("C-c l" . org-store-link)
))
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
: org-store-link
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
*** Add org-contrib
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
Some modules are providedd by org-contrib, like exporting to
confluence
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package org-contrib
:ensure t)
#+END_SRC
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26768 38477 62891 nil elpaca-process-queues nil nil 29000 nil]
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
*** Mixed Pitch and Fancy Bullet Support by Default in Org
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
Enable mixed pitch and fancy bullets when using a graphical display
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(defun snm-org-mode-config ()
"Set options for better writing in org buffers."
(mixed-pitch-mode)
(visual-line-mode)
(turn-on-auto-fill)
)
(add-hook 'org-mode-hook #'snm-org-mode-config)
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
(use-package org-bullets
:ensure t
:if (display-graphic-p)
:hook (org-mode . org-bullets-mode))
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
(use-package mixed-pitch
2024-07-30 14:40:34 +02:00
:ensure t
2025-08-05 20:56:14 +02:00
:if (display-graphic-p)
:hook
(org-mode . mixed-pitch-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-07-22 11:40:01 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26279 36119 854408 nil elpaca-process-queues nil nil 376000 nil]
*** Org Appear
2025-07-22 11:40:01 +02:00
2025-08-05 20:56:14 +02:00
Hide the org markers when point is not on the element being decorated.
2025-05-10 19:41:56 +02:00
#+BEGIN_SRC emacs-lisp
2025-06-29 17:25:56 +02:00
2025-08-05 20:56:14 +02:00
(use-package org-appear
:ensure t
:hook (org-mode . org-appear-mode))
2025-06-29 17:25:56 +02:00
2025-08-05 20:56:14 +02:00
#+END_SRC
2025-06-29 17:25:56 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26432 31427 677147 nil elpaca-process-queues nil nil 738000 nil]
2025-06-29 17:25:56 +02:00
2025-08-05 20:56:14 +02:00
*** Org Babel Support
2025-06-29 17:25:56 +02:00
2025-08-05 20:56:14 +02:00
I have a test file which has samples of babel features for easy
testing in my [[file:~/org/snamellit/testfile.org::*User Journey Graph ][org babel test file. ]]
2025-06-29 17:25:56 +02:00
2025-08-05 20:56:14 +02:00
**** Configure Babel Languages
2025-06-29 17:25:56 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package ob-mermaid
:ensure t
:demand t)
2025-06-29 17:25:56 +02:00
#+END_SRC
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package ob-latex
:ensure nil
:demand t
:custom
(org-preview-latex-default-process "lualatex"))
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26768 38911 12050 nil elpaca-process-queues nil nil 97000 nil]
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp :tangle yes
;; configure babel languages
(use-package ob
:ensure nil
:after org
:custom
(org-babel-load-languages '((emacs-lisp . t)
(shell . t)
(python . t)
(scheme . t)
(plantuml . t)
(mermaid . t)
(sql . t)
(sqlite . t)
(dot . t)))
)
#+END_SRC
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
***** Example Emacs Lisp
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
2025-08-05 20:56:14 +02:00
(+ 2 3)
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: 5
2024-07-30 14:40:34 +02:00
2025-06-30 09:41:09 +02:00
2025-08-05 20:56:14 +02:00
***** Example shell
2025-06-30 09:41:09 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC shell
echo "Foo bar"
2025-06-30 09:41:09 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: Foo bar
2025-06-30 09:41:09 +02:00
2025-08-05 20:56:14 +02:00
***** Example python
2024-08-04 01:37:17 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC python
bar="bar"
return f"Foo {bar}"
2024-08-04 01:37:17 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
***** TODO Example Latex
2025-02-25 12:32:48 +01:00
2025-08-05 20:56:14 +02:00
#+name : hello-latex
#+BEGIN_SRC latex :results file raw :exports results :file latex.png
\LaTeX
Dit is ne pot en tis ne grote!
2025-02-25 12:32:48 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS : hello-latex
[[file:latex.png ]]
2025-02-25 12:32:48 +01:00
2025-08-05 20:56:14 +02:00
***** Example Scheme
2025-02-26 00:11:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC scheme
(+ 3 4)
2025-02-26 00:11:31 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: 7
2025-02-26 00:11:31 +01:00
2025-08-05 20:56:14 +02:00
***** Example PlantUML
2024-08-11 11:36:44 +02:00
2025-08-05 20:56:14 +02:00
****** Archimate example : Capability Metamodel
2024-08-11 11:36:44 +02:00
2025-08-05 20:56:14 +02:00
#+begin_src plantuml :file cap-meta-model.png
!include <archimate/Archimate >
title Capability Metamodel
2024-09-23 13:42:45 +02:00
2025-08-05 20:56:14 +02:00
Strategy_ValueStream(vs, "ValueStream")
Business_Service(svc, "Service")
Strategy_Capability(cap, "Capability")
Strategy_Resource(fun, "Function")
Strategy_Resource(ppl, "People")
Strategy_Resource(process, "Processes")
Strategy_Resource(tools, "Tools")
2024-09-23 13:42:45 +02:00
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
Rel_Serving_Right(svc, vs, "supports")
Rel_Serving_Right(cap, svc, "provides")
Rel_Assignment_Up(fun,cap,"implements")
Rel_Composition_Up(ppl,fun,"")
Rel_Composition_Up(tools,fun,"")
Rel_Composition_Up(process,fun,"")
#+end_src
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
[[file:cap-meta-model.png ]]
2024-12-02 14:43:46 +01:00
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
***** Example Mermaid
:PROPERTIES:
:header-args: :tangle no
:END:
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
****** Directed Graph
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+begin_src mermaid :file test2.png
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[Car]
#+end_src
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
****** Gantt Chart
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+begin_src mermaid :file gantt.png
gantt
section Section
Completed :done, des1, 2014-01-06,2014-01-08
Active :active, des2, 2014-01-07, 3d
Parallel 1 : des3, after des1, 1d
Parallel 2 : des4, after des1, 1d
Parallel 3 : des5, after des3, 1d
Parallel 4 : des6, after des4, 1d
#+end_src
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
[[file:gantt.png ]]
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
****** Class Diagram
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+begin_src mermaid :file class.png
classDiagram
Class01 <|-- AveryLongClass : Cool
<<Interface >> Class01
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
class Class10 {
<<service >>
int id
size()
}
2024-08-02 13:44:21 +02:00
2025-08-05 20:56:14 +02:00
#+end_src
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
[[file:class.png ]]
****** State Diagram
#+begin_src mermaid :file state.png
stateDiagram-v2
[*] --> Still
Still --> [*]
Still --> Moving
Moving --> Still
Moving --> Crash
Crash --> [*]
#+end_src
2024-07-30 14:40:34 +02:00
2024-08-02 13:44:21 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
[[file:state.png ]]
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
****** Pie Chart
2024-11-11 13:30:16 +01:00
2025-08-05 20:56:14 +02:00
#+begin_src mermaid :file pie.png
pie
"Dogs" : 386
"Cats" : 85
"Rats" : 15
#+end_src
2024-08-02 13:44:21 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
[[file:pie.png ]]
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
***** Example sql
:PROPERTIES:
:header-args: :engine postgresql :dbuser emacs :dbpassword (auth-source-pass-get 'secret "snamellit/emacs/test-psql") :database emacs
:END:
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
In the assumption that postgres is running and the current user has
admin privileges on the local dev database
#+BEGIN_SRC shell :result output
pass snamellit/emacs/test-psql | sed '/ ./{p}' | createuser emacs -P 2>&1
createdb -Oemacs -EUNICODE emacs 2>&1
#+END_SRC
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
| Enter | password | for | new | role: |
| Enter | it | again: | | |
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC sql :var rel="tname" n=300 :colnames yes
drop table if exists $rel;
create table $rel(id int, val int);
insert into $rel(id, val) values (1,210), (3,800);
select * from $rel where val > $n;
#+END_SRC
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
| DROP TABLE | |
|--------------+-----|
| CREATE TABLE | |
| INSERT 0 2 | |
| id | val |
| 3 | 800 |
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC sql
SELECT * FROM DUAL;
2024-12-02 14:43:46 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
|---|
2025-07-17 12:14:00 +02:00
2025-08-05 20:56:14 +02:00
***** Example sqlite
2024-12-03 13:14:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC sqlite :db /tmp/rip.db :var rel="tname" n=300 :colnames yes
drop table if exists $rel;
create table $rel(n int, id int);
insert into $rel(n,id) values (1,210), (3,800);
select * from $rel where id > $n;
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
| n | id |
|---+-----|
| 3 | 800 |
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
***** Example dot aka Graphviz
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC dot :file metrics.png
digraph MetricsHierarchy {
node [shape=box, style=rounded];
// Fundamental Metrics
subgraph cluster_fundamental_metrics {
label="Fundamental Metrics";
Performance_Rating [label="Performance Rating"];
Latency_Rating [label="Latency Rating"];
Quality_Rating [label="Quality Rating"];
Security_Rating [label="Security Rating"];
}
// Derived Metrics
subgraph cluster_derived_metrics {
label="Derived Metrics";
Application_Health_Score [label="Application Health Score"];
User_Experience_Index [label="User Experience Index"];
// Add more derived metrics as needed
}
// Top-Level Metrics
subgraph cluster_toplevel_metrics {
label="Top-Level Metrics";
Overall_Application_Performance [label="Overall Application Performance"];
// Add more top-level metrics as needed
}
// Connections
Performance_Rating -> Application_Health_Score;
Latency_Rating -> Application_Health_Score;
Quality_Rating -> User_Experience_Index;
Security_Rating -> User_Experience_Index;
Application_Health_Score -> Overall_Application_Performance;
}
#+END_SRC
2024-08-04 01:37:17 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
[[file:metrics.png ]]
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
****** Git Graph
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+begin_src mermaid :file git.png
gitGraph:
options
{
"nodeSpacing": 150,
"nodeRadius": 10
}
end
commit
branch newbranch
checkout newbranch
commit
commit
checkout master
commit
commit
merge newbranch
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+end_src
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
[[file:git.png ]]
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
****** User Journey Graph
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+begin_src mermaid :file user_journey.png
journey
title My working day
section Go to work
Make tea: 5: Me
Go upstairs: 3: Me
Do work: 1: Me, Cat
section Go home
Go downstairs: 5: Me
Sit down: 3: Me
#+end_src
2024-08-04 01:37:17 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
[[file:user_journey.png ]]
2024-08-04 01:37:17 +02:00
2025-01-19 13:59:42 +01:00
2025-08-05 20:56:14 +02:00
****** ER Diagram
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+begin_src mermaid :file er.png
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
#+end_src
2024-07-30 14:40:34 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
[[file:er.png ]]
2025-02-17 00:59:26 +01:00
2025-08-05 20:56:14 +02:00
***** TODO Example Rust
2025-02-17 00:59:26 +01:00
2025-08-05 20:56:14 +02:00
#+begin_src rust
fn main() {
print!("hello world");
}
#+end_src
2025-02-17 00:59:26 +01:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: hello world
2024-07-30 14:40:34 +02:00
2024-08-02 13:23:26 +02:00
2025-08-05 20:56:14 +02:00
**** Temporary Patches for Org Babel
2025-01-19 19:21:45 +01:00
2025-08-05 20:56:14 +02:00
***** Fix Scheme Babel Bug
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; fix a bug in ob-scheme which causes an error to be thrown when evaluating
;; a cons cell or improper list
;; see https://list.orgmode.org/87bkk3x1bu.fsf@gajsin.name/T/
(defun org-babel-scheme--table-or-string (results)
"Convert RESULTS into an appropriate elisp value.
If the results look like a list or tuple, then convert them into an
Emacs-lisp table, otherwise return the results as a string."
(let ((res (org-babel-script-escape results)))
(cond ((proper-list-p res)
(mapcar (lambda (el)
(if (or (null el) (eq el 'null))
org-babel-scheme-null-to
el))
res))
(t res))))
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-08-04 10:48:03 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: org-babel-scheme--table-or-string
2024-12-30 13:40:04 +01:00
2025-08-05 20:56:14 +02:00
**** TODO Move babel test file to emacs config folder
2024-12-30 13:40:04 +01:00
2025-08-05 20:56:14 +02:00
Alternatively I might add a sample after each configured block to keep
it in the same context. Hmmm.... sounds even better.
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
*** Org Export
**** Org Export to Markdown
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package ox-md
:ensure nil
:after ox
)
2024-11-18 11:26:22 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
**** Org Latex Export
***** Syntax Highlighting requires Multiple Passes
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; support for minted in LaTeX for code highlighting
(use-package ox-latex
:ensure nil
:after ox
:config
(setq org-latex-compiler "lualatex")
(setq org-latex-pdf-process
'("%latex -shell-escape -interaction nonstopmode -output-directory %o %f"
"%latex -interaction nonstopmode -output-directory %o %f"
"%latex -interaction nonstopmode -output-directory %o %f"))
)
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
***** Load Customer Latex Classes
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; Customer LaTeX classes
(setq mlx-latex-classes
'(
("mlx-beamer" "\\documentclass{mlx-beamer}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
("mlx-book" "\\documentclass{mlx-book}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\part{%s}" . "\\part*{%s}")
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
("mlx-report" "\\documentclass{mlx-report}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\part{%s}" . "\\part*{%s}")
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
("mlx-article" "\\documentclass{mlx-article}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
("mlx-project-charter" "\\documentclass{mlx-project-charter}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\section{%s}
\\begin{mdframed}" "\\end{mdframed}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))))
#+END_SRC
***** Load My Latex Classes
#+BEGIN_SRC emacs-lisp
(setq snm-latex-classes
'(
("snm-beamer" "\\documentclass{snm-beamer}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
("snm-book" "\\documentclass{snm-book}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\part{%s}" . "\\part*{%s}")
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
("snm-report" "\\documentclass{snm-report}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\part{%s}" . "\\part*{%s}")
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
("snm-invoice" "\\documentclass{snm-invoice}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
("snm-article" "\\documentclass{snm-article}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}"))))
2025-01-08 11:57:26 +01:00
2025-08-05 20:56:14 +02:00
(with-eval-after-load 'ox-latex
(dolist
(class (append mlx-latex-classes snm-latex-classes))
(add-to-list 'org-latex-classes class)))
#+END_SRC
**** Export to Confluence
2025-01-08 11:57:26 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package ox-confluence
:after org-contrib
:ensure nil)
#+END_SRC
2025-01-08 11:57:26 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
2025-01-08 11:57:26 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package ox-confluence-en
:after ox-confluence
:ensure (ox-confluence-en :host github :repo "correl/ox-confluence-en"))
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-01-08 11:57:26 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26576 2809 520906 nil elpaca-process-queues nil nil 290000 nil]
2025-07-17 12:04:43 +02:00
2025-08-05 20:56:14 +02:00
**** Blogging with Zola
2025-07-17 12:04:43 +02:00
2025-08-05 20:56:14 +02:00
gicrisf has [[https://github.com/gicrisf/ox-zola ][created a package ]] to export org files to Zola.
2025-07-17 12:04:43 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package ox-hugo
:ensure t
:after ox)
(use-package ox-zola
:ensure (ox-zola :host github :repo "gicrisf/ox-zola" :files (:defaults "*.el" "backend" "stylesheets"))
:after (ox-hugo)
:config
(require 'ox-hugo)
)
#+END_SRC
2025-07-17 12:04:43 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
2025-07-17 12:04:43 +02:00
2025-08-05 20:56:14 +02:00
It is a wrapper around ~ox-hugo~ to export org files to Zola. It
supports most features of it and directs the user to the [[https://ox-hugo.scripter.co/ ][the hugo
exporter manual.]]
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
*** Org Capture Customization
#+BEGIN_SRC emacs-lisp
(use-package org-capture
:ensure nil
:config (progn
(setq org-capture-templates '())
(add-to-list 'org-capture-templates
'("t" "Todo" entry (file+headline +org-capture-todo-file "Tasks")
"* TODO %?\n %i\n %a"))
(add-to-list 'org-capture-templates
'("n" "Note" entry (file+headline +org-capture-todo-file "Notes")
"* %?\n %i\n %a"))
(add-to-list 'org-capture-templates
'("j" "Journal" entry (file+datetree +org-capture-journal-file)
"* %?\nEntered on %U\n %i\n %a"))
(add-to-list 'org-capture-templates
'("b" "Blog Post" entry
(file+headline "~/org/snamellit/blog.org" "Blog Posts")
"** %^{Blog Title:}\n:PROPERTIES:\n:EXPORT_FILE_NAME %^{Export Filename:}\n:EXPORT_DATE: %t\n:END:\n%i%?"))
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
;; configure support for recipes
(add-to-list 'org-capture-templates
'("c" "Cookbook" entry (file "~/org/cookbook.org")
"%(org-chef-get-recipe-from-url)"
:empty-lines 1))
(add-to-list 'org-capture-templates
'("m" "Manual Cookbook" entry (file "~/org/cookbook.org")
"* %^{Recipe title: }\n :PROPERTIES:\n :source-url:\n :servings:\n :prep-time:\n :cook-time:\n :ready-in:\n :END:\n** Ingredients\n %?\n** Directions\n\n")))
:bind (("C-c C" . org-capture)))
2025-07-17 12:04:43 +02:00
2025-08-05 20:56:14 +02:00
#+END_SRC
2024-07-30 14:40:34 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: t
*** Org GCal Support
2024-08-04 01:37:17 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; configure support for google calendar
(use-package org-gcal
;; :ensure t
:custom
(org-gcal-client-id (auth-source-pass-get 'secret "snamellit/org-gcal-client"))
(org-gcal-client-secret (auth-source-pass-get "id" "snamellit/org-gcal-client"))
(org-gcal-fetch-file-alist '(("pti@snamellit.com" . "~/org/schedule.org")))
:commands (org-gcal-sync org-gcal-fetch) )
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
*** Org Jira Integration
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; configure org-jira
(use-package org-jira
:ensure t ; (:host github :repo "ptillemans/org-jira" :branch "pti_fix_getUsers")
:commands (org-jira-get-issues org-jira-get-projects)
:config
(setq org-jira-users '(("Peter Tillemans". "557058:bdf83521-663b-4ae6-9b71-487bb98e2add")))
(setq jiralib-agile-page-size 1000)
(setq org-jira-custom-jqls
'(
))
(make-directory "~/.org-jira" 'parents)
(setq jiralib-url (auth-source-pass-get "url" "customer/melexis.atlassian.net"))
(setq org-jira-custom-jqls
'((:jql " assignee = currentUser() and (created > '2024-01-01' or updated > '2024-01-01') order by created DESC"
:limit 100 :filename "this-year")
(:jql " assignee = currentUser() and project = UNILRN order by priority DESC "
:limit 100 :filename "~/Projects/unifylearn/jira")
(:jql " assignee = currentUser() and project = TTRK order by priority DESC "
:limit 100 :filename "~/Projects/timetrak/jira")
)
)
(jiralib-login
(auth-source-pass-get "user" "customer/jira")
(auth-source-pass-get 'secret "customer/jira"))
:bind (("C-c j i g" . 'org-jira-get-issues)
("C-c j p g" . 'org-jira-get-projects)
("C-c j i j" . 'org-jira-get-issues-from-custom-jql)))
#+END_SRC
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26760 26288 212481 nil elpaca-process-queues nil nil 913000 nil]
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
It is very useful to create for each active project a custom JQL to
make a snapshot of issues just for that project in the folder of the
project to keep everything in context.
2024-10-23 11:52:07 +02:00
2025-01-19 19:09:13 +01:00
2025-08-05 20:56:14 +02:00
**** Keybindings
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
| Key | Command |
|---------+------------------------------------------|
| C-c pg | org-jira-get-projects |
| C-c bg | org-jira-get-boards |
| C-c iv | org-jira-get-issues-by-board |
| C-c ib | org-jira-browse-issue |
| C-c ig | org-jira-get-issues |
| C-c ij | org-jira-get-issues-from-custom-jql |
| C-c ih | org-jira-get-issues-headonly |
| C-c if | org-jira-get-issues-from-filter-headonly |
| C-c iF | org-jira-get-issues-from-filter |
| C-c iu | org-jira-update-issue |
| C-c iw | org-jira-progress-issue |
| C-c in | org-jira-progress-issue-next |
| C-c ia | org-jira-assign-issue |
| C-c isr | org-jira-set-issue-reporter |
| C-c ir | org-jira-refresh-issue |
| C-c iR | org-jira-refresh-issues-in-buffer |
| C-c ic | org-jira-create-issue |
| C-c ik | org-jira-copy-current-issue-key |
| C-c sc | org-jira-create-subtask |
| C-c sg | org-jira-get-subtasks |
| C-c cc | org-jira-add-comment |
| C-c cu | org-jira-update-comment |
| C-c wu | org-jira-update-worklogs-from-org-clocks |
| C-c tj | org-jira-todo-to-jira |
| C-c if | org-jira-get-issues-by-fixversion |
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
**** TODO add focused project support
There should be some things we can do to better integrate this with
projects:
- update issues in background when opening the project.
- run custom JQL defined in the project iso globally.
*** Daviwil's Productivity Tools
2024-12-10 09:59:35 +01:00
2025-08-05 20:56:14 +02:00
@daviwil has a set of productivity tools which are very useful. I have
2024-12-10 09:59:35 +01:00
2025-06-02 16:13:05 +02:00
2025-08-05 20:56:14 +02:00
**** Find all tasks with a specific tag (or without)
2025-07-17 12:47:57 +02:00
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp :tangle no
2025-08-05 20:56:14 +02:00
(setq org-agenda-custom-commands
'(("p" "Planning" tags-todo "+@planning")))
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-07-17 12:47:57 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
| p | Planning | tags-todo | +@planning |
2024-12-10 09:59:35 +01:00
2025-08-05 20:56:14 +02:00
We can remove tasks with a certain tag by adding `-@work` to the pattern.
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
**** Find all tasks with a specific tag (or without)
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("u" "Untagged Tasks" tags-todo "-{.*}")))
2025-02-17 01:53:31 +01:00
#+END_SRC
2024-12-10 09:59:35 +01:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
| u | Untagged Tasks | tags-todo | -{.*} |
2024-12-10 09:59:35 +01:00
2025-08-05 20:56:14 +02:00
**** Combine multiple filters
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
We can add a list of queries
2025-02-03 10:18:58 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("p" "Planning" ((tags-todo "+@planning")
(tags-todo "-{.*}")))))
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
| p | Planning | ((tags-todo +@planning) (tags-todo -{.*})) |
**** We can add settings to each filter
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("p" "Planning" ((tags-todo "+@planning"
((org-agenda-overriding-header "Planning Tasks")))
(tags-todo "-{.*}"
((org-agenda-overriding-header "Untagged Tasks")))))))
2025-02-03 10:18:58 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
| p | Planning | ((tags-todo +@planning ((org-agenda-overriding-header Planning Tasks))) (tags-todo -{.*} ((org-agenda-overriding-header Untagged Tasks)))) |
2025-01-19 19:09:13 +01:00
2025-08-05 20:56:14 +02:00
**** Add support for an input file
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("i" "Inbox" ((todo ".*"
((org-agenda-files '("~/Nextcloud/org/ "))
(org-agenda-overriding-header "Unprocessed Inbox Items")))))))
2025-01-19 19:09:13 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
| i | Inbox | ((todo .* ((org-agenda-files '(~/Nextcloud/org/)) (org-agenda-overriding-header Unprocessed Inbox Items)))) |
2024-07-30 14:40:34 +02:00
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
**** Daily Agenda
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("d" "Daily Agenda"
((agenda "" ((org-agenda-span 'day)
(org-deadline-warning-days 1)
(org-agenda-overriding-header "Today's Agenda")))
(tags-todo "+PRIORITY=\"A\""
((org-agenda-overriding-header "High-Priority Unfinished Tasks")
))))))
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-12-02 14:43:46 +01:00
2025-02-17 01:53:31 +01:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
| d | Daily Agenda | ((agenda ((org-agenda-span 'day) (org-deadline-warning-days 1) (org-agenda-overriding-header Today's Agenda))) (tags-todo +PRIORITY="A" ((org-agenda-overriding-header High-priority unfinished tasks)))) |
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
**** Weekly Review
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(setq org-log-done 'time) ; log the time when a task is completed
(setq org-agenda-start-with-log-mode t) ; show the log mode when starting the agenda
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
(setq org-agenda-custom-commands
'(("w" "Weekly Review"
((agenda "" ((org-agenda-overriding-header "Completed Tasks")
(org-agenda-skip-function (org-agenda-skip-entry-if 'nottodo 'done))
(org-agenda-span 'week)))
(agenda "" ((org-agenda-overriding-header "Unfinished Scheduled Tasks")
(org-agenda-skip-function (org-agenda-skip-entry-if 'todo 'done))
(org-agenda-span 'week)))
))))
#+END_SRC
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
| w | Weekly Review | ((agenda ((org-agenda-overriding-header Completed Tasks) (org-agenda-skip-function (org-agenda-skip-entry-if 'nottodo 'done)) (org-agenda-span 'week))) (agenda ((org-agenda-overriding-header Unfinished Scheduled Tasks) (org-agenda-skip-function (org-agenda-skip-entry-if 'todo 'done)) (org-agenda-span 'week)))) |
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
**** Customer GTD
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
Create an agenda view specifically focused on customer tasks both in
the org tree and in the customer JIRA.
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(add-to-list 'org-agenda-custom-commands
'("G" "Customer GTD"
((alltodo ".*"
((org-agenda-files '("~/org/customer/" "~ /.org-jira/ "))
(org-agenda-overriding-header "Customer GTD"))))))
#+END_SRC
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
| G | Customer GTD | ((alltodo .* ((org-agenda-files '(~/org/customer/ ~/.org-jira/)) (org-agenda-overriding-header Customer GTD)))) |
| G | Customer GTD | ((alltodo .* ((org-agenda-files '(~/org/customer/)) (org-agenda-overriding-header Customer GTD)))) |
| w | Weekly Review | ((agenda ((org-agenda-overriding-header Completed Tasks) (org-agenda-skip-function (org-agenda-skip-entry-if 'nottodo 'done)) (org-agenda-span 'week))) (agenda ((org-agenda-overriding-header Unfinished Scheduled Tasks) (org-agenda-skip-function (org-agenda-skip-entry-if 'todo 'done)) (org-agenda-span 'week)))) |
2024-07-30 14:40:34 +02:00
2024-08-05 10:32:04 +02:00
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
**** Context aware GTD
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
Create agenda views for specific contexts
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(add-to-list 'org-agenda-custom-commands '("fb" "Busy Bees" ((tags-todo "+bees"))))
(add-to-list 'org-agenda-custom-commands '("fm" "Melexis" ((tags-todo "+mlx"))))
(add-to-list 'org-agenda-custom-commands '("fg" "Geel" ((tags-todo "+geel"))))
(add-to-list 'org-agenda-custom-commands '("fh" "Home" ((tags-todo "+home"))))
(add-to-list 'org-agenda-custom-commands '("fr" "Rillaar" ((tags-todo "+rillaar"))))
(add-to-list 'org-agenda-custom-commands '("fe" "Emacs" ((alltodo ".*" ((org-agenda-files '("~/org/snamellit/emacs.org")))))))
#+END_SRC
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
| fr | Rillaar | ((tags-todo +rillaar)) |
| fh | Home | ((tags-todo +home)) |
| fg | Geel | ((tags-todo +geel)) |
| fr | Melexis | ((tags-todo +rillaar)) |
| fh | Melexis | ((tags-todo +home)) |
| fg | Melexis | ((tags-todo +geel)) |
| fm | Melexis | ((tags-todo +mlx)) |
| fb | Busy Bees | ((tags-todo +bees)) |
| m | Melexis | ((tags-todo +mlx)) |
| b | Busy Bees | ((tags-todo +bees)) |
| G | Customer GTD | ((alltodo .* ((org-agenda-files '(~/org/customer/ ~/.org-jira/)) (org-agenda-overriding-header Customer GTD)))) |
| w | Weekly Review | ((agenda ((org-agenda-overriding-header Completed Tasks) (org-agenda-skip-function (org-agenda-skip-entry-if 'nottodo 'done)) (org-agenda-span 'week))) (agenda ((org-agenda-overriding-header Unfinished Scheduled Tasks) (org-agenda-skip-function (org-agenda-skip-entry-if 'todo 'done)) (org-agenda-span 'week)))) |
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
** Denote
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; configure denote
(use-package denote
:ensure t
:init
(setq denote-directory (file-name-concat (expand-file-name "~") "Nextcloud/denote"))
(setq denote-dired-directories
(list denote-directory
(expand-file-name "~/Documents/denote")))
:hook (dired-mode . denote-dired-mode-in-directories)
:bind (
("<leader > n d" . (lambda () (interactive) (dired denote-directory)))
("<leader > n n" . #'denote)
("<leader > n N" . #'denote-type)
("<leader > n c" . #'denote-link-or-create)
("<leader > n t" . #'denote-template)
("<leader > n z" . #'denote-signature)
("<leader > n l" . #'denote-link)
("<leader > n L" . #'denote-find-link)
("<leader > n k" . #'denote-keywords-add)
("<leader > n b" . #'denote-link-backlink)
("<leader > n B" . #'denote-find-backlink)
("<leader > n r" . #'denote-rename-file)
("<leader > n R" . #'denote-rename-file-using-front-matter)
("<leader > n f" . (lambda () (interactive) (consult-find denote-directory)))))
#+END_SRC
2024-08-05 10:44:37 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26544 34903 498589 nil elpaca-process-queues nil nil 963000 nil]
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
**** TODO explain what denote-dired-mode-in-directories does.
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
** BoilerPlate Generator
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
The way I do advent of code requires me to create a main file and a
test file every day with some boilerplate content.
2024-08-05 10:32:04 +02:00
2025-08-05 20:56:14 +02:00
The *org-generate* package uses an org file to structure boilerplate
templates to be generated. By default it uses
2024-08-05 10:32:04 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package org-generate
:ensure t
)
2024-08-05 10:32:04 +02:00
#+END_SRC
2025-02-17 01:53:31 +01:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26455 5250 886750 nil elpaca-process-queues nil nil 641000 nil]
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
* Integration with Environment
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(report-time-since-load "Integration with Environment")
#+END_SRC
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
** Set default Coding System to Use UTF-8 Everywhere
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
Ensures UTF-8 is the default coding system everywhere.
#+BEGIN_SRC emacs-lisp
(set-default-coding-systems 'utf-8)
(set-language-environment 'utf-8)
(setq locale-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
;; Treat clipboard input as UTF-8 string first; compound text next, etc.
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-02-17 00:59:26 +01:00
2025-08-05 20:56:14 +02:00
Here’ s a breakdown of what each line does:
2025-02-17 00:59:26 +01:00
2025-08-05 20:56:14 +02:00
1. *(set-default-coding-systems 'utf-8)*
2024-08-16 00:43:50 +02:00
2025-08-05 20:56:14 +02:00
This line sets the default coding system for new buffers. When you
create a new buffer or open a file, Emacs will use UTF-8 encoding
by default. It will also set the default terminal and keyboard
coding systems. This applies to all internal operations where a
specific coding system has not been specified.
2024-08-16 00:43:50 +02:00
2025-08-05 20:56:14 +02:00
2. *(set-language-environment 'utf-8)*
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
This sets the language environment to UTF-8. Emacs uses the
language environment to guess the preferred coding systems for
reading and writing files and for other operations. Setting this to
UTF-8 ensures that UTF-8 is preferred in all language-related
contexts.
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
3. *(setq locale-coding-system 'utf-8)*
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
This sets the coding system for locale data, such as environment
variables and system messages. It ensures that Emacs correctly
interprets UTF-8 encoded data coming from the operating system.
2024-12-03 13:14:31 +01:00
2025-08-05 20:56:14 +02:00
4. *(prefer-coding-system 'utf-8)*
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
This makes UTF-8 the preferred coding system for any situation
where Emacs needs to choose an encoding. It ensures that Emacs
prefers UTF-8 over other encodings.
5. *(setq x-select-request-type ...)*
Treat clipboard input as UTF8_STRING first, compound text next,
etc... .
** Set Path from shell configuration
In order to get the paths in Emacs to be consistent with the ones in
the terminals we get them from a started shell instead of the current
environment which can be considerably different in X, Wayland or on
Mac because the shell initialization scripts have not run yet.
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; set path from shell when started in UI-RELATED
(use-package exec-path-from-shell
:ensure t
:defer 1
:if (or (daemonp) (memq window-system '(mac ns x)))
:config (exec-path-from-shell-initialize))
#+END_SRC
** Setup backup directories and other file saving settings
Configures where backup files are stored:
#+BEGIN_SRC emacs-lisp
;; setup backup directories
;; see https://www.emacswiki.org/emacs/BackupDirectory
(setq backup-directory-alist
`(("." . ,(file-name-concat user-emacs-directory "backups"))))
2024-12-03 13:14:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
: ((. . /home/pti/ .config/emacs/backups))
To avoid losing files when deleting in dired, move them to the trash:
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(setq delete-by-moving-to-trash t)
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
** Enable integration with the Unix Password Store aka *pass*
The *pass* command gives a super practical way to store secrets
encrypted using *gpg* and use them in *.envrc* files, batch scripts on the
command line and, of course, in *Emacs* .
2024-12-03 13:14:31 +01:00
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
For setups with GnuPG >= 2.1, pinentry package is not needed anymore.
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
Quote from the Emacs News.26 file:
2024-08-02 11:39:46 +02:00
2025-08-05 20:56:14 +02:00
*** The pinentry.el library has been removed.
That package (and the corresponding change in GnuPG and pinentry)
was intended to provide a way to input passphrase through Emacs with
GnuPG 2.0. However, the change to support that was only implemented
in GnuPG >= 2.1 and didn't get backported to GnuPG 2.0. And with
GnuPG 2.1 and later, pinentry.el is not needed at all. So the
library was useless, and we removed it. GnuPG 2.0 is no longer
supported by the upstream project.
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
To adapt to the change, you may need to set 'epa-pinentry-mode' to the
symbol 'loopback'. Alternatively, leave 'epa-pinentry-mode' at its
default value of nil, and remove the 'allow-emacs-pinentry' setting
from your 'gpg-agent.conf' configuration file, usually found in the
'~/.gnupg' directory.
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
Note that previously, it was said that passphrase input through
minibuffer would be much less secure than other graphical pinentry
programs. However, these days the difference is insignificant: the
'read-password' function sufficiently protects input from leakage to
message logs. Emacs still doesn't use secure memory to protect
passphrases, but it was also removed from other pinentry programs as
the attack is unrealistic on modern computer systems which don't
utilize swap memory usually.
See also a discussion on why pinentry was removed from Emacs core.
So a setup may now consist of:
In Emacs' user-init-file:
#+BEGIN_SRC elisp
(require 'epg)
(setq epg-pinentry-mode 'loopback)
2024-08-09 10:32:41 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
In ~/.gnupg/gpg-agent.conf:
2024-08-11 11:36:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC text :tangle no
allow-emacs-pinentry
# on Mac OS
pinentry-program /usr/local/bin/pinentry-mac
2024-08-11 11:36:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
*** Enable pass secrets
2024-08-11 11:36:44 +02:00
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(auth-source-pass-enable)
#+END_SRC
2025-07-17 12:26:28 +02:00
2025-08-05 20:56:14 +02:00
This enables *pass* secrets to be used for all subsystems supporting
*auth-source* (which are probably all of them nowadays). It does require
some finagling to map the parts on the name in the pass system.
- [[https://www.passwordstore.org/ ][Pass Website ]]
- [[info:auth#The Unix password store ][auth#The Unix password store in the info pages ]]
*** Use of Pass Secrets in ELisp
It is very convenient to get secrets from this store (once gpg is set
up, which a totally different can of worms). A function
`auth-source-pass-get` is provided :
#+BEGIN_SRC emacs-lisp :tangle no
(auth-source-pass-get 'secret "dummy/password")
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: shht!secret
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
*** Major mode to edit pass keychain
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package pass
:ensure t)
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26721 10916 917127 nil elpaca-process-queues nil nil 78000 nil]
2025-01-23 14:22:39 +01:00
2025-08-05 20:56:14 +02:00
** Add a fully featured terminal emulator
2025-01-23 14:22:39 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package eat
:commands eat
:ensure (eat
:host codeberg
:repo "akib/emacs-eat"
:files ("*.el" ("term" "term/* .el") "*.texi"
"*.ti" ("terminfo/e" "terminfo/e/* ")
("terminfo/65" "terminfo/65/ *")
("integration" "integration/*")
(:exclude ".dir-locals.el" "*-tests.el"))))
2025-01-23 14:22:39 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26538 15682 653403 nil elpaca-process-queues nil nil 807000 nil]
** Enable vterm
2025-07-22 18:08:22 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package vterm
:ensure t
:commands vterm)
#+END_SRC
2025-07-22 18:08:22 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26557 35507 493630 nil elpaca-process-queues nil nil 948000 nil]
** Docker Integration
Detect which container tool is installed and configures accordingly
2025-07-22 18:08:22 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(setq snm-docker-executable (if (executable-find "docker") 'docker 'podman))
(use-package docker
:defer t
:ensure t
:bind ("C-c d" . docker)
:config
(pcase snm-docker-executable
('docker
(setf docker-command "docker"
docker-compose-command "docker-compose"
docker-container-tramp-method "docker"))
('podman
(setf docker-command "podman"
docker-compose-command "podman-compose"
docker-container-tramp-method "podman"))))
2025-07-22 18:08:22 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26557 44955 396008 nil elpaca-process-queues nil nil 436000 nil]
2025-07-22 18:08:22 +02:00
2025-08-05 20:56:14 +02:00
Add support to edit Dockerfile files :
2025-02-26 00:11:31 +01:00
#+BEGIN_SRC emacs-lisp
(use-package dockerfile-mode
:defer t
:ensure t
:config
2025-08-05 20:56:14 +02:00
(setq dockerfile-mode-command docker-command))
2025-02-26 00:11:31 +01:00
#+END_SRC
#+RESULTS :
: [nil 26557 44943 649 nil elpaca-process-queues nil nil 729000 nil]
2025-08-05 20:56:14 +02:00
** Confluence Integration
This module is advertised as being alpha quality but should allow
importing and exporting confluence pages.
2025-07-22 11:40:01 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package tributary
:ensure (tributary :type git :host github :repo "mrkrd/tributary")
:config
(setq tributary-api-url "https://melexis.atlassian.net/wiki/rest/api/content/ "))
2025-07-22 11:40:01 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26770 1000 217140 nil elpaca-process-queues nil nil 894000 nil]
2025-08-04 18:01:44 +02:00
2025-08-06 00:00:07 +02:00
** Mu4e Configuration
#+BEGIN_SRC emacs-lisp
(setq snm/mu4e-load-path (concat
(file-name-parent-directory
(file-name-directory
(executable-find "mu")))
"share/emacs/site-lisp/mu4e"))
(use-package mu4e
:load-path snm/mu4e-load-path
;"/usr/share/emacs/site-lisp/mu4e"
:config
;; use mu4e for e-mail in emacs
(setq mail-user-agent 'mu4e-user-agent)
(setq mu4e-drafts-folder "/[Gmail].Drafts")
(setq mu4e-sent-folder "/[Gmail].Sent Mail")
(setq mu4e-trash-folder "/[Gmail].Trash")
;; don't save message to Sent Messages, Gmail/IMAP takes care of this
(setq mu4e-sent-messages-behavior 'delete)
;; (See the documentation for `mu4e-sent-messages-behavior' if you have
;; additional non-Gmail addresses and want assign them different
;; behavior.)
;; setup some handy shortcuts
;; you can quickly switch to your Inbox -- press ``ji''
;; then, when you want archive some messages, move them to
;; the 'All Mail' folder by pressing ``ma''.
(setq mu4e-maildir-shortcuts
'( (:maildir "/INBOX" :key ?i)
(:maildir "/[Gmail].Sent Mail" :key ?s)
(:maildir "/[Gmail].Trash" :key ?t)
(:maildir "/[Gmail].All Mail" :key ?a)))
(add-to-list 'mu4e-bookmarks
;; ':favorite t' i.e, use this one for the modeline
'(:query "maildir:/inbox" :name "Inbox" :key ?i :favorite t))
;; allow for updating mail using 'U' in the main view:
(setq mu4e-get-mail-command "offlineimap")
;; something about ourselves
(setq
user-mail-address "pti@snamellit.com"
user-full-name "Peter Tillemans"
message-signature
(concat
"Peter Tillemans\n"
"Snamellit BV\n"
"http://www.smamellit.com\n"))
;; sending mail -- replace USERNAME with your gmail username
;; also, make sure the gnutls command line utils are installed
;; package 'gnutls-bin' in Debian/Ubuntu
(require 'smtpmail)
(setq
message-send-mail-function 'smtpmail-send-it
starttls-use-gnutls t
smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil))
smtpmail-auth-credentials
'(("smtp.gmail.com" 587 "pti@snamellit.com" (auth-source-pass-get 'secret "snamellit/imap.gmail.com")))
smtpmail-default-smtp-server "smtp.gmail.com"
smtpmail-smtp-server "smtp.gmail.com"
smtpmail-smtp-service 587)
;; alternatively, for emacs-24 you can use:
;;(setq message-send-mail-function 'smtpmail-send-it
;; smtpmail-stream-type 'starttls
;; smtpmail-default-smtp-server "smtp.gmail.com"
;; smtpmail-smtp-server "smtp.gmail.com"
;; smtpmail-smtp-service 587)
;; don't keep message buffers around
(setq message-kill-buffer-on-exit t)
)
#+END_SRC
#+RESULTS :
: t
2025-08-05 20:56:14 +02:00
* Editor Features
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Editor Features")
2025-08-04 18:01:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
** Emacs configuration
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; A few more useful configurations...
(use-package emacs
:custom
;; Support opening new minibuffers from inside existing minibuffers.
(enable-recursive-minibuffers t)
;; Hide commands in M-x which do not work in the current mode. Vertico
;; commands are hidden in normal buffers. This setting is useful beyond
;; Vertico.
(read-extended-command-predicate #'command-completion-default-include-p)
:init
;; Add prompt indicator to `completing-read-multiple'.
;; We display [CRM<separator >], e.g., [CRM,] if the separator is a comma.
(defun crm-indicator (args)
(cons (format "[CRM%s] %s"
(replace-regexp-in-string
"\\`\\[.*?]\\* \\|\\[.*?]\\* \\'" ""
crm-separator)
(car args))
(cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
** Save history over sessions
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
Persist history over Emacs restarts. Vertico sorts by history
position.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package savehist
:init
(savehist-mode))
2025-08-04 18:01:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
** Completion Configuration
*** Use Vertico for better selection lists
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
Vertico is a big package by minad. Well documented in the [[https://github.com/minad/vertico][vertico
github repo]].
2025-08-04 18:01:44 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; Enable vertico
(use-package vertico
:ensure t
:custom
(vertico-scroll-margin 0) ;; Different scroll margin
(vertico-count 12) ;; Show more candidates
(vertico-resize t) ;; Grow and shrink the Vertico minibuffer
(vertico-cycle t) ;; Enable cycling for `vertico-next/previous'
:init
(vertico-mode))
2025-08-04 18:01:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
*** Orderless for better narrowing
2025-07-22 11:40:01 +02:00
2024-12-03 13:14:31 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package orderless
:ensure t
:custom
;; Configure a custom style dispatcher (see the Consult wiki)
;; (orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch))
;; (orderless-component-separator #'orderless-escapable-split-on-space)
(completion-styles '(orderless basic))
;;(completion-category-defaults nil)
(completion-category-overrides '((file (styles partial-completion)))))
2024-12-03 13:14:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
*** Marginalia for better context awareness
2024-08-02 13:23:26 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; Enable rich annotations using the Marginalia package
(use-package marginalia
:ensure t
;; Bind `marginalia-cycle' locally in the minibuffer. To make the binding
;; available in the *Completions* buffer, add it to the
;; `completion-list-mode-map'.
:bind (:map minibuffer-local-map ("M-A" . marginalia-cycle))
2024-08-02 13:23:26 +02:00
2025-08-05 20:56:14 +02:00
:init
(marginalia-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: marginalia-cycle
2024-08-09 10:32:41 +02:00
2025-08-05 20:56:14 +02:00
*** Add consult
2024-08-09 10:32:41 +02:00
2025-08-05 20:56:14 +02:00
See the excellent documentation on [[https://github.com/minad/consult ][Minad's consult repo ]].
2025-06-02 16:13:05 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; Example configuration for Consult
(use-package consult
:ensure t
;; Replace bindings. Lazily loaded by `use-package'.
:bind (;; C-c bindings in `mode-specific-map'
("C-c M-x" . consult-mode-command)
("C-c h" . consult-history)
("C-c k" . consult-kmacro)
("C-c m" . consult-man)
("C-c i" . consult-info)
([remap Info-search] . consult-info)
;; C-x bindings in `ctl-x-map'
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
;; M-g bindings in `goto-map'
("M-g e" . consult-compile-error)
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
("M-g g" . consult-goto-line) ;; orig. goto-line
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
;; M-s bindings in `search-map'
("M-s d" . consult-find) ;; Alternative: consult-fd
("M-s c" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch-history)
:map isearch-mode-map
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
;; Minibuffer history
:map minibuffer-local-map
("M-s" . consult-history) ;; orig. next-matching-history-element
("M-r" . consult-history)) ;; orig. previous-matching-history-element
2025-08-04 12:21:46 +02:00
2025-08-05 20:56:14 +02:00
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI.
:hook (completion-list-mode . consult-preview-at-point-mode)
2025-08-04 12:21:46 +02:00
2025-08-05 20:56:14 +02:00
;; The :init configuration is always executed (Not lazy)
:init
2025-08-04 12:21:46 +02:00
2025-08-05 20:56:14 +02:00
;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
2025-08-04 12:21:46 +02:00
2025-08-05 20:56:14 +02:00
;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
(advice-add #'register-preview :override #'consult-register-window)
2025-06-02 16:13:05 +02:00
2025-08-05 20:56:14 +02:00
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; Configure other variables and modes in the :config section,
;; after lazily loading the package.
:config
2025-08-04 12:21:46 +02:00
2025-08-05 20:56:14 +02:00
;; Optionally configure preview. The default value
;; is 'any, such that any key triggers the preview.
;; (setq consult-preview-key 'any)
;; (setq consult-preview-key "M-.")
;; (setq consult-preview-key '("S-<down >" "S-<up >"))
;; For some commands and buffer sources it is useful to configure the
;; :preview-key on a per-command basis using the `consult-customize' macro.
(consult-customize
consult-theme :preview-key '(:debounce 0.2 any)
consult-ripgrep consult-git-grep consult-grep
consult-bookmark consult-recent-file consult-xref
consult--source-bookmark consult--source-file-register
consult--source-recent-file consult--source-project-recent-file
;; :preview-key "M-."
:preview-key '(:debounce 0.4 any))
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
;; Optionally configure the narrowing key.
;; Both < and C-+ work reasonably well.
(setq consult-narrow-key "<") ;; "C-+"
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
;; Optionally make narrowing help available in the minibuffer.
;; You may want to use `embark-prefix-help-command' or which-key instead.
;; (keymap-set consult-narrow-map (concat consult-narrow-key " ?") #'consult-narrow-help)
)
2024-12-02 14:43:46 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26434 3705 536018 nil elpaca-process-queues nil nil 266000 nil]
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
** Frequently used File/Project Operations
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(keymap-global-set "C-c v" vc-prefix-map)
(keymap-global-set "C-c p" project-prefix-map)
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
(recentf-mode 1) ;; enable recent file tracking
(keymap-global-set "C-c f f" #'find-file)
(keymap-global-set "C-c f o" #'recentf)
(keymap-global-set "C-c f r" #'revert-buffer)
(keymap-global-set "C-c f d" #'diff-buffer-with-file)
2024-12-03 09:12:46 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
** User Interface
*** Display startup time
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; Profile emacs startup
(add-hook 'emacs-startup-hook
(lambda ()
(message "Emacs started in %s."
(emacs-init-time))))
2024-12-11 11:50:04 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
*** Configure Fonts with Fontaine
2024-12-03 09:12:46 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;;
;; Font configuration
;;
2024-12-03 09:12:46 +01:00
2025-08-05 20:56:14 +02:00
(defun snm-find-installed-font (fonts)
"Find the first font in FONTS which is installed on this system."
(seq-find
(lambda (f) (find-font (font-spec :family f)))
fonts))
2024-12-18 11:42:53 +01:00
2025-08-05 20:56:14 +02:00
(defun snm-configure-fonts (&optional frame)
"Set configuration of fonts based on display size.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
The FRAME argument makes it possible to set the fonts for new frames by
adding this function to `after-make-frame-functions' which must have
this argument."
(defvar snm-font-size
(if (> (display-pixel-height) 1600) 22 14))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; set startup and default fontsets to make org-bullet work
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(set-fontset-font "fontset-startup" nil "DejaVu Sans Mono" nil)
(set-fontset-font "fontset-default" nil "DejaVu Sans Mono" nil)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(setq fontaine-presets
`((t
:default-family ,(snm-find-installed-font
'("FiraCode NF" "FiraCode Nerd Font"))
:default-weight regular
:default-height ,snm-font-size
:variable-pitch-family ,(snm-find-installed-font
'("Lato" "Literation Sans" "FiraCode NF Propo" "FiraCode Nerd Font Propo" "DejaVu Sans"))
:variable-pitch-height 1.33
:bold-weight heavy
:line-spacing 1
)
(regular
:default-height 100)
(small
:default-height 75)
(medium
:default-height 125)
(large
:default-height 150)))
(fontaine-set-preset 'regular))
(use-package fontaine
:ensure t
:if (display-graphic-p)
:demand t
:config (progn
(snm-configure-fonts)
(add-hook 'after-make-frame-functions #'snm-configure-fonts)))
2025-08-04 18:01:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
*** Update configuration of each created frame
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
When running as daemon there is no graphical context. This means that
all graphical related settings cannot be set properly at initial
startup if we need to interrogate the capabilities of the current
screen.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;;
;; remove chrome from the frames
;; also support client frames
;;
(defun snm-display-tweaks (&optional frame)
"Configure a newly created FRAME."
(interactive)
(menu-bar-mode 1)
(tool-bar-mode -1)
(if (display-graphic-p)
(scroll-bar-mode -1)))
(add-hook 'after-make-frame-functions #'snm-display-tweaks)
;; run it in the current frame, because the hooks have already fired
(snm-display-tweaks)
2025-08-04 18:01:44 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
*** Set Theme
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
;; Set theme
(use-package catppuccin-theme
:ensure t
:demand t
:config
(setq catppuccin-flavor 'mocha)
(load-theme 'catppuccin t)
(defun catppuccin-toggle ()
(interactive)
(setq catppuccin-flavor (if (eq catppuccin-flavor 'mocha) 'latte 'mocha))
(catppuccin-reload)
(message (format "Cattpuccin Flavor set to %s" catppuccin-flavor)))
:bind
(("<f5 >" . #'catppuccin-toggle)))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
(use-package modus-themes
:ensure t
:demand t
:custom
(modus-themes-italic-constructs t)
(modus-themes-bold-constructs t)
(modus-themes-mixed-fonts t "enable mixed fonts in org and markdown et al.")
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(modus-themes-to-toggle '(modus-operandi-tinted modus-vivendi-tinted))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(modus-themes-completions '((matches . (extrabold background intense))
(selection . (semibold accented intense))))
(modus-themes-org-blocks 'tinted-background)
(modus-themes-mixed-fonts t)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(modus-themes-headings '((1 . (monochrome extrabold background overline variable-pitch 1.6))
(2 . (monochrome bold overline 1.4))
(3 . (monochrome semibold overline 1.3))
(4 . (monochrome 1.2))
(5 . (monochrome 1.1))
(agenda-date . (semilight 1.5))
(agenda-structure . (variable-pitch light 1.9))
(t . (monochrome light))))
:config
(load-theme 'modus-operandi-tinted :no-confirm)
:bind
(("<f5 >" . #'modus-themes-toggle)))
2025-08-04 18:01:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
There is a keybinding on *<F5>* to toggle between light and dark mode.
2025-08-04 18:01:44 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: modus-themes-toggle
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** EF Themes
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp :tangle yes
(use-package ef-themes
:ensure t
:init
;; If you like two specific themes and want to switch between them, you
;; can specify them in `ef-themes-to-toggle' and then invoke the command
;; `ef-themes-toggle'. All the themes are included in the variable
;; `ef-themes-collection'.
(setq ef-themes-to-toggle '(ef-day ef-night))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(setq ef-themes-headings ; read the manual's entry or the doc string
'((0 variable-pitch light 1.9)
(1 variable-pitch light 1.8)
(2 variable-pitch regular 1.7)
(3 variable-pitch regular 1.6)
(4 variable-pitch regular 1.5)
(5 variable-pitch 1.4) ; absence of weight means `bold'
(6 variable-pitch 1.3)
(7 variable-pitch 1.2)
(t variable-pitch 1.1)))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; They are nil by default...
(setq ef-themes-mixed-fonts t
ef-themes-variable-pitch-ui t)
:config
;; Disable all other themes to avoid awkward blending:
(mapc #'disable-theme custom-enabled-themes)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; load the theme which also calls `ef-themes-post-load-hook':
(ef-themes-select 'ef-night)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
:bind
("<f5 >" . #'ef-themes-toggle)
)
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26538 31881 746655 nil elpaca-process-queues nil nil 312000 nil]
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Spacious Padding
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package spacious-padding
:ensure t
:bind (("<f8 >" . #'spacious-padding-mode)))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26538 30896 455747 nil elpaca-process-queues nil nil 302000 nil]
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Limit Height of Selected Popup Windows
#+BEGIN_SRC emacs-lisp
(push '("\\*Occur\\* "
;; display-buffer functions, first one that succeeds is used
(display-buffer-reuse-mode-window
display-buffer-below-selected)
;; Parameters
(window-height . 10))
display-buffer-alist)
(push '("\\*Warnings\\* "
;; display-buffer functions, first one that succeeds is used
(display-buffer-reuse-mode-window
display-buffer-below-selected)
;; Parameters
(window-height . 10))
display-buffer-alist)
(push '("\\*Geiser Debug\\* "
;; display-buffer functions, first one that succeeds is used
(display-buffer-reuse-mode-window
display-buffer-below-selected)
;; Parameters
(window-height . 10))
display-buffer-alist)
(push '("magit:.*"
;; display-buffer functions, first one that succeeds is used
(display-buffer-reuse-mode-window
display-buffer-below-selected)
;; Parameters
(window-height . 10))
display-buffer-alist)
(push '("\\*sly-mrepl for .* \\*"
;; display-buffer functions, first one that succeeds is used
(display-buffer-reuse-mode-window
display-buffer-below-selected)
;; Parameters
(window-height . 10))
display-buffer-alist)
(add-to-list 'Info-default-directory-list "~/.local/share/info/ ")
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
| ~/.local/share/info/ |
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
a quick way to test this it to generate a warning with
#+BEGIN_SRC emacs-lisp :tangle no
(warn "This is a warning")
#+END_SRC
2025-08-04 18:01:44 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: t
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
** Yasnippet configuration
*** Enable Yasnippet
Enables and configures Yasnippet, a template system for Emacs:
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; configure yasnippet
(use-package yasnippet
:ensure nil
:defer 5
:config
(yas-global-mode 1)
(add-to-list 'yas-snippet-dirs "~/src/guix/etc/snippets/yas"))
#+END_SRC
2025-08-04 18:01:44 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: t
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Add Snippet Collection
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; add yasnippet collection
(use-package yasnippet-snippets
:ensure t)
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26481 25510 926111 nil elpaca-process-queues nil nil 690000 nil]
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
* Programming
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming")
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
** Programming Support Infrastructure
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Infrastructure")
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Integration with LSP Servers for language support
#+BEGIN_SRC emacs-lisp
;; configure eglot-mode
(use-package eglot
:config
(keymap-set eglot-mode-map "C-c c a" #'eglot-code-actions)
(keymap-set eglot-mode-map "C-c c d" #'eglot-find-declaration)
(keymap-set eglot-mode-map "C-c c i" #'eglot-find-implementation)
(keymap-set eglot-mode-map "C-c c k" #'eglot-find-typeDefinition)
(keymap-set eglot-mode-map "C-c c f" #'eglot-format)
(keymap-set eglot-mode-map "C-c c F" #'eglot-format-buffer)
(keymap-set eglot-mode-map "C-c c r" #'eglot-rename)
(keymap-set eglot-mode-map "C-c c Q" #'eglot-shutdown)
(keymap-set eglot-mode-map "C-c c q" #'eglot-reconnect)
(keymap-set eglot-mode-map "C-c c n" #'flymake-goto-next-error)
(keymap-set eglot-mode-map "C-c c p" #'flymake-goto-prev-error)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; Shutdown server when last managed buffer is killed
(setq eglot-autoshutdown t)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; from https://www.reddit.com/r/emacs/comments/ye18nd/setting_up_eglot_for_python/
(add-to-list 'eglot-server-programs '(python-mode . ("pylsp")))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(setq-default eglot-workspace-configuration
'((:pylsp . (:configurationSources ["flake8"]
:plugins (:pycodestyle (:enabled nil)
:mccabe (:enabled nil)
:flake8 (:enabled t))))))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
:hook
(go-ts-mode . eglot-ensure)
(rust-ts-mode . eglot-ensure)
(java-ts-mode . eglot-ensure)
(python-ts-mode . eglot-ensure)
(zig-mode . eglot-ensure))
2025-08-04 18:01:44 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
*** Use Treesitter parser support
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
Recently with verion 0.25 the treesitter library changed ABI version
to 15. Newer parsers will complain about a version mismatch if the
installed library used by emacs is lower than this version. This ABI
version was introduced in the 0.25 branch of treesitter.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
The best course of action till lib treesitter is updated is to pin
the version of the parser to the last version supporting ABI 14.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
With the new ABI 15 version, parsers are required to provide a
~treesitter.json~ file with additional metadata which can be used as
proxy to find a version which still supports ABI-14, i.e. the commit
before that.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
A lot of the parsers are provided by the treesitter project as sub
repos, and they follow the same version convention as the library,
selecting the last tag before the 0.25 tag is a good way to find a
compatible version.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
This branch can be added after the repo url in the
~treesit-language-source-alist~ variable. Note that if you use
~treesit-auto-install-all~ to get it over with, you have to probably
restart your emacs as treesit-auto apparently caches the value
during iniitialisation and changes are not picked up.
#+BEGIN_SRC emacs-lisp
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; set locations for treesitter grammars
(use-package treesit
:config
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash" "v0.23.3")
(c "https://github.com/tree-sitter/tree-sitter-c" "v0.23.6")
(cmake "https://github.com/uyha/tree-sitter-cmake")
(css "https://github.com/tree-sitter/tree-sitter-css")
(elisp "https://github.com/Wilfred/tree-sitter-elisp")
(go "https://github.com/tree-sitter/tree-sitter-go")
(gomod "https://github.com/camdencheek/tree-sitter-go-mod.git")
(haskell "https://github.com/tree-sitter/tree-sitter-haskell" "master" "src" nil nil)
(html "https://github.com/tree-sitter/tree-sitter-html")
(java "https://github.com/tree-sitter/tree-sitter-java.git")
(javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src")
(json "https://github.com/tree-sitter/tree-sitter-json")
(lua "https://github.com/tjdevries/tree-sitter-lua")
(make "https://github.com/alemuller/tree-sitter-make")
(markdown "https://github.com/ikatyang/tree-sitter-markdown")
(ocaml "https://github.com/tree-sitter/tree-sitter-ocaml" nil "ocaml/src")
(rust "https://github.com/tree-sitter/tree-sitter-rust" "v0.23.3")
(python "https://github.com/tree-sitter/tree-sitter-python")
(toml "https://github.com/tree-sitter/tree-sitter-toml")
(tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
(yaml "https://github.com/ikatyang/tree-sitter-yaml")))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
:hook
((prog . treesit-inspect-mode)))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
Treesit-auto automatically configures things behind the scenes to use
the treesitter modes and download them if needed. \
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package treesit-auto
:ensure t
:defer 5
:custom
(treesit-auto-install 'prompt)
(treesit-auto-langs '(awk bash c c-sharp clojure cmake commonlisp cpp css
dart dockerfile elixir go gomod html java
javascript json julia kotlin lua make markdown nix
org perl proto python r ruby rust scala sql toml tsx
typescript vue yaml)) ; reduced langs list somewhat
:config
(treesit-auto-add-to-auto-mode-alist 'all)
(global-treesit-auto-mode))
#+END_SRC
2025-08-04 18:01:44 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26284 45426 709595 nil elpaca-process-queues nil nil 734000 nil]
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
I always get errors compiling support for *janet* so I pruned the
`treesit-auto-langs` to exclude it and other things I don't use.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
***** TODO figure out why Latex does not want to install
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
**** Recompiling all Treesitter Grammars
To recompile all treesitter grammars, execute following block with
*C-c C-c* .
#+BEGIN_SRC emacs-lisp :tangle no
(mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
#+END_SRC
2025-08-04 18:01:44 +02:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
| bash | cmake | css | elisp | go | gomod | haskell | html | java | javascript | json | lua | make | markdown | ocaml | python | toml | tsx | typescript | yaml |
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
**** Treesitter Grammars for Windows
Windows does not come with a handy-dandy C-compiler available as *cc* or *gcc* or even *c99* and treesitter does not have a handy dandy feature to remap that to *zig cc* and similar.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
However we can download it from the release page of the tree-sitter-langs repo or even better install the *tree-sitter-langs* package.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
This will download the dynamic library to _user-emacs-directory_ /elpa/tree-sitter-langs/bin
However they'll have the wrong filename and are not in the path where treesitter looks in.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
- Open the folder with *dired*
- switch to writable with `C-xC-q` to enable *wdired*
- :%s/[a-z-]\*.dll/libtree-sitter-\\0/
- `C-cC-c` to confirm the changes if it looks ok
- `%m` to mark all files starting with libtree
- `R` them to the *~/.config/emacs/tree-sitter* folder
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
and they will now be installed.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
Normally that should work for other OSes too, but there is no real need for it.
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
see also [[https://www.masteringemacs.org/article/how-to-get-started-tree-sitter ][How to get started with tree sitter ]] .
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Create a folder to store downloaded LSP servers
#+BEGIN_SRC emacs-lisp
;; LSP support
(let ((lsp_dir (file-name-concat user-emacs-directory "lsp")))
(if (not (file-exists-p lsp_dir))
(mkdir lsp_dir t)))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
** Configure Selected Languages
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Selected Languages")
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Rust Support
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; configure rust support
(let* ((release-date "2023-10-30")
(os (pcase system-type
('darwin "x86_64-apple-darwin")
('gnu/linux "x86_64-unknown-linux-gnu")
('windows-nt "x86_64-pc-windows-msvc")
(_ "unknown")))
(releases-url "https://github.com/rust-lang/rust-analyzer/releases/download/ ")
(download-url (concat releases-url release-date "/rust-analyzer-" os ".gz"))
(rust-analyzer (file-name-concat
user-emacs-directory
(concat "lsp/rust-analyzer"
(if (eq system-type 'windows-nt)
".exe"
"")))))
(if (not (file-exists-p rust-analyzer))
(let ((rust-analyzer-archive (concat rust-analyzer ".gz" )))
(message "install rust-analyzer from %s at %s" download-url rust-analyzer)
(url-copy-file download-url rust-analyzer-archive t)
(call-process "gzip" nil "*snam-install* " t "-d" (concat rust-analyzer ".gz"))
(call-process "chmod" nil "*snam-install* " t "+x" rust-analyzer)
(message "rust-analyzer installed at %s" rust-analyzer)))
)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(use-package rustic
:ensure t
:after (flymake flycheck eglot)
:init (setq rustic-lsp-client 'eglot))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** OCaml Support
#+BEGIN_SRC emacs-lisp
;; configure Ocaml support
(setq opam-emacs-dir (file-name-concat (expand-file-name "~") "/.opam/default/share/emacs/site-lisp"))
(use-package ocp-indent
:ensure t
:load-path opam-emacs-dir
:if (file-exists-p opam-emacs-dir))
(use-package tuareg
:ensure t
:hook
(tuareg-mode . eglot-ensure))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Go Support
#+BEGIN_SRC emacs-lisp :tangle no
;; configure go support
(use-package go-ts-mode
:hook
(go-ts . eglot-ensure))
#+END_SRC
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
*** Javascript, Typescript, TSC, etc...
#+BEGIN_SRC emacs-lisp
;; configure typescript support
(use-package typescript-ts-mode
:hook
(typescript-ts-mode . eglot-ensure))
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
;; configure javascript support
(use-package javascript-ts-mode
:hook
(javascript-ts-mode . eglot-ensure))
2024-12-03 09:12:46 +01:00
2025-08-05 20:56:14 +02:00
;; configure react support
(use-package tsx-ts-mode
:hook
(tsx-ts-mode . eglot-ensure))
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
| eglot-ensure |
2024-12-03 09:12:46 +01:00
2025-08-05 20:56:14 +02:00
*** Java and other JVM languages
#+BEGIN_SRC emacs-lisp
;; configure java support
(use-package java-ts-mode
:hook
(javascript-ts-mode . eglot-ensure)
:config
(let* ((download-url"https://www.eclipse.org/downloads/download.php?file=/jdtls/snapshots/jdt-language-server-latest.tar.gz")
(jdtls-dir (file-name-concat user-emacs-directory "lsp/jdtls"))
(jdtls-prog (concat jdtls-dir "/bin/jdtls" (if (eq system-type 'windows-nt) ".bat" "")))
(archive (file-name-concat jdtls-dir "jdtls.tgz")))
(if (not (file-exists-p jdtls-dir))
(mkdir jdtls-dir t))
(if (not (file-exists-p jdtls-prog))
(progn
(message "install jdtls at %s" jdtls-dir)
(if (not (file-exists-p archive))
(url-copy-file download-url archive))
(call-process "tar" nil "*snam-install* " t "-C" jdtls-dir "-xzvf" archive )
(report-time-since-load "jdtls installed at %s" jdtls-prog)))
(with-eval-after-load 'eglot
(progn
(setenv "JAVA_HOME" (getenv "GUIX_PROFILE"))
(add-to-list 'eglot-server-programs `((java-mode java-ts-mode) ,jdtls-prog))))))
2024-12-03 09:12:46 +01:00
2025-08-05 20:56:14 +02:00
#+END_SRC
*** Lisp and Scheme Support
**** Aggressive Indent for lisp modes
2024-12-03 09:12:46 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package aggressive-indent
:ensure t
:hook ((lisp-mode-hook scheme-mode-hook clojure-mode-hook)))
2024-12-03 09:12:46 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
**** Enable ParEdit in lispy modes
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; Lisp support
(use-package package-lint-flymake
:ensure t) ;; needed before activating lisp-interaction-mode-hook
(use-package paredit
2024-12-11 11:50:04 +01:00
:ensure nil
2025-08-05 20:56:14 +02:00
:after package-lint-flymake
:commands (enable-paredit-mode)
:init
(dolist (mode '(emacs-lisp-mode-hook
lisp-interaction-mode-hook
lisp-mode-hook
scheme-mode-hook))
(add-hook mode #'enable-paredit-mode)))
2024-12-11 11:50:04 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
**** Rainbow Parentheses
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package rainbow-delimiters
:ensure t
:commands (rainbow-delimiters-mode)
:hook
(prog-mode . rainbow-delimiters-mode))
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-12-03 09:12:46 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: [nil 26418 38138 672360 nil elpaca-process-queues nil nil 82000 nil]
**** Configure Sly for Common Lisp
2025-05-04 00:02:31 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package sly
:ensure t
:config
(require 'sly-autoloads)
:hook (lisp-mode-hook . #'sly-editing-mode))
2025-05-04 00:02:31 +02:00
2025-08-05 20:56:14 +02:00
(use-package sly-quicklisp
:ensure t
:after sly)
(use-package sly-repl-ansi-color
:ensure t
:after sly)
(use-package sly-asdf
:ensure t
:after sly)
2025-05-04 00:02:31 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26432 28005 611924 nil elpaca-process-queues nil nil 196000 nil]
**** Configure CLHS documentation
2025-05-04 00:02:31 +02:00
2025-08-05 20:56:14 +02:00
Common Lisp Hyperspec is distributed as a package for
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC shell :tangle no
AOC/2024/02> (ql:quickload "clhs")
To load "clhs":
Install 1 Quicklisp release:
clhs
; Fetching #<URL "http://beta.quicklisp.org/archive/clhs/2015-04-07/clhs-0.6.3.tgz" >
; 2186.27KB
==================================================
2,238,743 bytes in 0.04 seconds (50845.91KB/sec)
; Loading "clhs"
[package clhs].
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
("clhs")
2024-07-30 14:40:34 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
There is a wizard to help installing it in Emacs:
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC shell :tangle no
AOC/2024/02> (clhs:print-emacs-setup-form)
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
[ Quicklisp directory: "/home/pti/quicklisp/ " (exists)
If the above location is not correct, do:
(setf clhs:*quicklisp-directory* "/path/to/quicklisp/ ") ]
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
clhs-use-local.el was not found in your quicklisp directory.
This means you're at step 1 of 2 for configuring Emacs/Slime
to perform lookups/browsing with your local copy of the CLHS.
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
Please run (clhs:install-clhs-use-local) in the (Common Lisp) REPL.
This will install clhs-use-local.el in your quicklisp directory.
2024-12-02 14:43:46 +01:00
2025-08-05 20:56:14 +02:00
Then, run (clhs:print-emacs-setup-form) again for instructions for step 2.
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
; No values
AOC/2024/02> (clhs:install-clhs-use-local)
T
AOC/2024/02> (clhs:print-emacs-setup-form)
2024-11-18 11:26:22 +01:00
2025-08-05 20:56:14 +02:00
[ Quicklisp directory: "/home/pti/quicklisp/ " (exists)
If the above location is not correct, do:
(setf clhs:*quicklisp-directory* "/path/to/quicklisp/ ") ]
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
(clhs-use-local.el was found in your quicklisp directory.
Moreover, its version matches the one bundled with this CLHS ASDF wrapper.
You may proceed with step 2 of 2 below.)
2024-11-18 11:26:22 +01:00
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
Make Emacs evaluate this form to browse the CLHS locally:
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
(load "/home/pti/quicklisp/clhs-use-local.el" t)
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
Use C-c C-d h make-instance RET to test if the change was successful.
If it was, then this will open your browser and the URL will begin with "file:///".
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
Put the form in your ~/.emacs to persist the change for future sessions.
2024-12-11 11:50:04 +01:00
2025-08-05 20:56:14 +02:00
The README file has some further information,
including a list of 3 useful Slime CLHS lookup commands
and how to get Emacs to open CLHS pages in a different browser.
(Location: /home/pti/quicklisp/dists/quicklisp/software/clhs-0.6.3/README)
2024-07-30 14:40:34 +02:00
2025-08-05 20:56:14 +02:00
; No values
AOC/2024/02>
2024-10-26 21:10:54 +02:00
2025-08-05 20:56:14 +02:00
#+END_SRC
2024-10-26 21:10:54 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(load (expand-file-name "~/quicklisp/clhs-use-local.el") t)
2024-08-15 13:19:57 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
2025-08-05 20:56:14 +02:00
: t
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
**** Enable Geiser Mode in Scheme Mode
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
Configure Geiser and Scheme
- map .scm file by default to Guile
#+BEGIN_SRC emacs-lisp
(use-package geiser-guile
:ensure t
:commands (geiser-guile))
(use-package geiser-chicken
:ensure t
:commands (geiser-chicken))
(use-package geiser-racket
:ensure t
:commands (geiser-racket))
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
(use-package geiser
:ensure t
:commands (geiser geiser-mode)
:config
(add-to-list 'geiser-implementations-alist `((dir ,(expand-file-name "~/src/guile")) guile))
(add-to-list 'geiser-implementations-alist `((dir ,(expand-file-name "~/src/chicken")) chicken))
(add-to-list 'geiser-implementations-alist `((dir ,(expand-file-name "~/src/racket")) racket))
(setq geiser-default-implementation 'guile))
(use-package scheme-mode
:ensure nil
:commands (scheme-mode)
:hook (scheme-mode . geiser-mode))
2025-02-17 01:53:31 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26508 11537 881112 nil elpaca-process-queues nil nil 113000 nil]
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
**** GUIX support
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
[[https://gitlab.com/emacs-guix/emacs-guix ][Emacs-guix ]] is a module to interact with the guix system and help
manage packages and profiles. It also offers support for creating
additional profiles and packages for Guix.
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package guix
:ensure t
:after geiser)
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
I find it a bit a confusing module.
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
It provides a minor-mode
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
**** Enable Cider for Clojure mode
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package clojure-mode
:ensure t
:mode (("\\.clj\\'" . clojure-mode)
("\\.edn\\'" . clojure-mode))
:init
(add-hook 'clojure-mode-hook #'yas-minor-mode)
(add-hook 'clojure-mode-hook #'linum-mode)
(add-hook 'clojure-mode-hook #'subword-mode)
(add-hook 'clojure-mode-hook #'smartparens-mode)
(add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
(add-hook 'clojure-mode-hook #'eldoc-mode)
(add-hook 'clojure-mode-hook #'idle-highlight-mode))
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package cider
:ensure t
:defer t
:init (add-hook 'cider-mode-hook #'clj-refactor-mode)
:diminish subword-mode
:config
(setq nrepl-log-messages t
cider-repl-display-in-current-window t
cider-repl-use-clojure-font-lock t
cider-prompt-save-file-on-load 'always-save
cider-font-lock-dynamically '(macro core function var)
nrepl-hide-special-buffers t
cider-overlays-use-font-lock t)
(cider-repl-toggle-pretty-printing))
#+END_SRC
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
(use-package clj-refactor
:defer t
:ensure t
:diminish clj-refactor-mode
:config (cljr-add-keybindings-with-prefix "C-c C-m"))
#+END_SRC
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
**** Allow saving of an SBCL images
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
When trying to call `(save-lisp-and-die #p"somefile")` , sbcl will
throw an error that it cannot comply when multiple threads are active.
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
For each project using this you need to define some helper function to
stop the repl threads before saving the image like the following:
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC common-lisp :tangle no
(defun sbcl-save-sly-and-die ()
"Save a sbcl image, even when running from inside Sly.
This function should only be used in the *inferior-buffer* buffer,
inside emacs."
(mapcar #'(lambda (x)
(slynk::close-connection
x nil nil))
slynk::*connections* )
(dolist (thread (remove
(slynk-backend::current-thread)
(slynk-backend::all-threads)))
(slynk-backend::kill-thread thread))
(sleep 1)
(sb-ext:save-lisp-and-die #P"~/your-main-program.exe"
:toplevel #'your-main-function-here
:executable t
:compression t))
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
This function has to be called in the *sly-inferior-lisp*
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC common-lisp :tangle no
;; in *sly-inferior-lisp* buffer
(sbcl-save-sly-and-die)
#+END_SRC
2025-07-29 08:56:01 +02:00
2025-08-05 20:56:14 +02:00
*** Terraform Support
2025-07-29 08:56:01 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; configure terraform support
(use-package terraform-mode
:ensure t
:config
(setq
terraform-indent-level 2
terraform-format-on-save t)
(keymap-set terraform-mode-map "C-c c k" #'terraform-open-doc)
(keymap-set terraform-mode-map "C-c c f" #'terraform-format)
(keymap-set terraform-mode-map "C-c c F" #'terraform-format-buffer))
2025-07-29 08:56:01 +02:00
#+END_SRC
2025-08-05 20:56:14 +02:00
Map the keymap consistently to the eglot mappings.
2025-07-29 08:56:01 +02:00
2025-08-05 20:56:14 +02:00
*** Zig Support
2025-07-29 08:56:01 +02:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; configure zig support
(use-package zig-mode
:ensure t
:hook
(zig-mode . eglot-ensure))
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+END_SRC
2025-08-04 12:21:46 +02:00
2025-08-05 20:56:14 +02:00
*** Python Support
**** Enable Pyvenv
2025-08-04 12:21:46 +02:00
2025-08-05 20:56:14 +02:00
(pyvenv-mode 1))
2025-08-04 12:21:46 +02:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package pyvenv
:ensure t
:hook
(python-mode . pyvenv-mode)
(python-ts-mode . pyvenv-mode))
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
**** Enable UV
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(require 'treesit)
2025-08-04 18:01:44 +02:00
2025-08-05 20:56:14 +02:00
(use-package uv
:ensure (uv :type git :host github :repo "johannes-mueller/uv.el" :wait t)
:init
(add-to-list 'treesit-language-source-alist '(toml "https://github.com/tree-sitter-grammars/tree-sitter-toml"))
(unless (treesit-language-available-p 'toml)
(treesit-install-language-grammar 'toml)))
2025-08-04 18:01:44 +02:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26751 43082 733388 nil elpaca-process-queues nil nil 945000 nil]
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
*** Gitlab CI Yaml Support
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
(use-package gitlab-ci-mode
:ensure (:host gitlab :repo "ptillemans/gitlab-ci-mode" :branch "fixes_2024")
:mode "\\.gitlab-ci\\.yml\\'"
:custom
(gitlab-ci-url (auth-source-pass-get "url" "customer/gitlab/token"))
(gitlab-ci-api-token (auth-source-pass-get 'secret "customer/gitlab/token")))
2025-02-17 01:53:31 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
: [nil 26760 26150 568817 nil elpaca-process-queues nil nil 219000 nil]
*** Support Mermaid Diagrams
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
;; enable mermaid for org-babel
(use-package mermaid-mode
:ensure t
:demand t
:mode "\\.mmd\\'")
#+END_SRC
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS:
: [nil 26499 60213 709442 nil elpaca-process-queues nil nil 672000 nil]
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
Mermaid needs support of the mermaid-cli which is a node package. It
can be installed with
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC shell :tangle no
npm install -g @mermaid-js/mermaid-cli
2025-02-17 01:53:31 +01:00
#+END_SRC
#+RESULTS :
2025-08-05 20:56:14 +02:00
| | | | | | | | | | | | |
| added | 281 | packages, | removed | 60 | packages, | and | changed | 134 | packages | in | 18s |
| | | | | | | | | | | | |
| 52 | packages | are | looking | for | funding | | | | | | |
| run | `npm | fund` | for | details | | | | | | | |
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
*** Support PlantUML Diagrams
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
Requires nothing special, other than *plantuml.jar* archive installed.
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
The following code block depends on [[*Get latest version of a github released project][Get latest version of a github
released project]] utility function. This block will check if there is a
plantuml.jar in the emacs config directory and if not download the
latest version from github. The `snm-download-latest-plantuml` is made
interactive to manually install the latest version if needed.
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp :lexical t
(setq plantuml-jar-path (concat user-emacs-directory "plantuml.jar"))
(setq plantuml-default-exec-mode 'jar)
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
(defun snm-download-latest-plantuml ()
"Download the latest version of PlantUML.
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
This function is interactive to make it easy to upgrade to
the latest, current version with `M-x snm-download-latest-plantuml'."
(interactive)
(let* ((version (snm-latest-github-release "plantuml/plantuml"))
(url (format
"https://github.com/plantuml/plantuml/releases/download/ %s/plantuml-%s.jar"
version (substring version 1))))
(message "Downloading PlantUML version %s from %s" version url)
(url-copy-file
url
(concat user-emacs-directory "plantuml.jar")
t)))
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
(if (not (file-exists-p plantuml-jar-path))
(snm-download-latest-plantuml))
(setq org-plantuml-jar-path plantuml-jar-path)
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
(use-package plantuml
:ensure nil
:mode "\\.puml\\'")
#+END_SRC
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+RESULTS :
: ((\.ya?ml\' . yaml-ts-mode) (\.ts\' . typescript-ts-mode) (\.tsx\' . tsx-ts-mode) (\.toml\' . toml-ts-mode) (\.rs\' . rust-ts-mode) (\(?:\.\(?:rbw?\|ru\|rake\|thor\|jbuilder\|rabl\|gemspec\|podspec\)\|/\(?:Gem\|Rake\|Cap\|Thor\|Puppet\|Berks\|Brew\|Vagrant\|Guard\|Pod\)file\)\' . ruby-ts-mode) (\.py[iw]?\' . python-ts-mode) (\.md\' . markdown-ts-mode) (\.lua\' . lua-ts-mode) (\.json\' . json-ts-mode) (\.js\' . js-ts-mode) (\.java\' . java-ts-mode) (\.html\' . html-ts-mode) (go\.mod\' . go-mod-ts-mode) (\.go\' . go-ts-mode) (\.ex\' . elixir-ts-mode) ([/ \]\(?:Containerfile\|Dockerfile\)\(?:\.[^/\]*\)?\' . dockerfile-ts-mode) (\.css\' . css-ts-mode) (\.cpp\' . c++-ts-mode) (\.cmake\' . cmake-ts-mode) (\.cs\' . csharp-ts-mode) (\.c\' . c-ts-mode) (\.sh\' . bash-ts-mode) (\.envrc\' . direnv-envrc-mode) (/git-rebase-todo\' . git-rebase-mode) (\.gitlab-ci\.yml\' . gitlab-ci-mode) (\.mmd\' . mermaid-mode) (\.gitlab-ci.yml\' . gitlab-ci-mode) (\.\(e?ya?\|ra\)ml\' . yaml-mode) (\.dockerfile\' . dockerfile-mode) ([/\]\(?:Containerfile\|Dockerfile\)\(?:\.[^/\]* \)?\' . dockerfile-mode) (\.puml\' . plantuml) (\.edn\' . clojure-mode) (\.clj\' . clojure-mode) (/home/pti/ .password-store/.*\.gpg\' . pass-view-mode) (\.\(zig\|zon\)\' . zig-mode) (\.t\(f\(vars\)?\|ofu\)\' . terraform-mode) (\.nomad\' . hcl-mode) (\.hcl\' . hcl-mode) (\(?:build\|profile\)\.boot\' . clojure-mode) (\.joke\' . joker-mode) (\.jank\' . jank-mode) (\.cljd\' . clojuredart-mode) (\.cljs\' . clojurescript-mode) (\.cljc\' . clojurec-mode) (\.\(clj\|cljd\|dtm\|edn\|lpy\)\' . clojure-mode) (/guix/drvs/[[:alnum:]]\{2\}/[[:alnum:]]\{30\}-\(?:[+._[:alnum:]-]+\)\.drv\' . guix-build-log-mode) (/gnu/store/\(?:[+._[:alnum:]-]+\)\.drv\' . guix-derivation-mode) (/etc/profile\' . guix-env-var-mode) (/tmp/guix-build-\(?:[+._[:alnum:]-]+\)\.drv-[[:digit:]]+/environment-variables\' . guix-env-var-mode) (/guix/profiles/system\(?:[+._[:alnum:]-]+\)* /\(?:boot\|parameters\)\' . guix-scheme-mode) (/gnu/store/ \(?:[0-9a-df-np-sv-z]\{32\}\)-\(?:activate\|activate-service\|boot\|parameters\|shepherd\.conf\|shepherd\(?:[+._[:alnum:]-]+ \)\.scm\|\(?:[+._[:alnum:]-]+ \)-builder\)\' . guix-scheme-mode) ([./]opam_?\' . tuareg-opam-mode) (\.mly\' . tuareg-menhir-mode) (\.eliomi?\' . tuareg-mode) (\.ml[ip]?\' . tuareg-mode) (\.rs\' . rustic-mode) (\.rs\' . rust-mode) (\.\(?:md\|markdown\|mkd\|mdown\|mkdn\|mdwn\)\' . markdown-mode) (\.gpg\(~\|\.~[0-9]+~\)?\' nil epa-file) (\.elc\' . elisp-byte-code-mode) (\.\(?:3fr\|a\(?:rw\|vs\)\|bmp[23]?\|c\(?:als?\|myka?\|r[2w]\|u[rt]\)\|d\(?:c[mrx]\|ds\|jvu\|ng\|px\)\|exr\|f\(?:ax\|its\)\|gif\(?:87\)?\|hrz\|ic\(?:on\|[bo]\)\|j\(?:2c\|ng\|p\(?:eg\|[2cg]\)\)\|k\(?:25\|dc\)\|m\(?:iff\|ng\|rw\|s\(?:l\|vg\)\|tv\)\|nef\|o\(?:rf\|tb\)\|p\(?:bm\|c\(?:ds\|[dltx]\)\|db\|ef\|gm\|i\(?:ct\|x\)\|jpeg\|n\(?:g\(?:24\|32\|8\)\|[gm]\)\|pm\|sd\|tif\|wp\)\|r\(?:a[fs]\|gb[ao]?\|l[ae]\)\|s\(?:c[rt]\|fw\|gi\|ix\|r[2f]\|un\|vgz?\)\|t\(?:ga\|i\(?:ff\(?:64\)?\|le\|m\)\|tf\)\|uyvy\|v\(?:da\|i\(?:car\|d\|ff\)\|st\)\|w\(?:bmp\|pg\)\|x\(?:3f\|bm\|cf\|pm\|wd\|[cv]\)\|yuv\)\' . image-mode) (\.zst\' nil jka-compr) (\.dz\' nil jka-compr) (\.xz\' nil jka-compr) (\.lzma\' nil jka-compr) (\.lz\' nil jka-compr) (\.g?z\' nil jka-compr) (\.bz2\' nil jka-compr) (\.Z\' nil jka-compr) (\.vr[hi]?\' . vera-mode) (\(?:\.\(?:rbw?\|ru\|rake\|thor\|axlsx\|jbuilder\|rabl\|gemspec\|podspec\)\|/ \(?:Gem\|Rake\|Cap\|Thor\|Puppet\|Berks\|Brew\|Fast\|Vagrant\|Guard\|Pod\)file\)\' . ruby-mode) (\.re?st\' . rst-mode) (/\(?:Pipfile\|\.?flake8\)\' . conf-mode) (\(?:\.\(?:p\(?:th\|y[iw]?\)\)\|/ \(?:SCons\(?:\(?:crip\|truc\)t\)\)\)\' . python-mode) (\.m\' . octave-maybe-mode) (\.less\' . less-css-mode) (/go\.work\' . go-work-ts-mode) (\.editorconfig\' . editorconfig-conf-mode) (\.scss\' . scss-mode) (\.cs\' . csharp-mode) (\.awk\' . awk-mode) (\.\(u?lpc\|pike\|pmod\(\.in\)?\)\' . pike-mode) (\.idl\' . idl-mode) (\.java\' . java-mode) (\.m\' . objc-mode) (\.ii\' . c++-mode) (\.i\' . c-mode) (\.lex\' . c-mode) (\.y\(acc\)?\' . c-mode) (\.h\' . c-or-c+ +-mode) (\.c\' . c-mode) (\.\(CC?\|HH?\)\' . c+ +-mode) (\.[ch]\(pp\|xx\|\+ \
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
#+BEGIN_SRC emacs-lisp
2025-02-17 01:53:31 +01:00
2025-08-05 20:56:14 +02:00
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-08-05 20:56:14 +02:00
#+RESULTS :
: ~/.config/emacs/plantuml.jar
2025-02-17 01:53:31 +01:00
2025-02-25 12:32:48 +01:00
2025-08-05 20:56:14 +02:00
** Debugger Support
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Debugger Support")
#+END_SRC
2025-02-25 12:32:48 +01:00
#+BEGIN_SRC emacs-lisp
2025-08-05 20:56:14 +02:00
;; install DAP servers
(setq snm-vscode-js-debug-dir (file-name-concat user-emacs-directory "dape/vscode-js-debug"))
(defun snm-install-vscode-js-debug ()
"Run installation procedure to install JS debugging support."
(interactive)
(mkdir snm-vscode-js-debug-dir t)
(let ((default-directory (expand-file-name snm-vscode-js-debug-dir)))
2025-02-25 12:32:48 +01:00
2025-08-05 20:56:14 +02:00
(vc-git-clone "https://github.com/microsoft/vscode-js-debug.git" "." nil)
(report-time-since-load "git repository created")
(call-process "npm" nil "*snm-install* " t "install")
(report-time-since-load "npm dependencies installed")
(call-process "npx" nil "*snm-install* " t "gulp" "dapDebugServer")
(report-time-since-load "vscode-js-debug installed")))
2025-02-25 12:32:48 +01:00
2025-08-05 20:56:14 +02:00
(setq snm-codelldb-dir (file-name-concat user-emacs-directory "dape/codelldb"))
(defun snm-install-codelldb ()
"Install Vadimcn.Vscode-Lldb DAP server for C/C++/RUST."
(interactive)
(let* ((default-directory snm-codelldb-dir)
(arch (car (split-string system-configuration "-" nil nil)))
(os (pcase system-type
('windows-nt "windows")
('gnu/linux "linux")
('darwin "darwin")
(_ "unknown")))
(version "1.10.0")
(release-url (concat "https://github.com/vadimcn/codelldb/releases/download/v" version "/codelldb-" arch "-" os ".vsix")))
(mkdir default-directory t)
(url-copy-file release-url "codelldb.zip" t)
(report-time-since-load "codelldb archive downloaded")
(call-process "unzip" nil "*snm-install* " t "codelldb.zip")
(report-time-since-load "codelldb installed")
))
;; configure dape (dap-mode)
(use-package dape
:ensure (dape :host github :repo "svaante/dape" :wait t)
:defer 5
:config (progn
;; Use n for next etc. in REPL
;; (setq dape-repl-use-shorthand t)
;; Projectile users
(add-to-list 'dape-configs
`(vscode-js-node
modes (js-mode js-ts-mode typescript-mode typescript-ts-mode)
host "localhost"
port 8123
command "node"
command-cwd ,(file-name-concat snm-vscode-js-debug-dir "dist")
command-args ("src/dapDebugServer.js" "8123")
:type "pwa-node"
:request "launch"
:cwd dape-cwd
:program dape-buffer-default
:outputCapture "console"
:sourceMapRenames t
:pauseForSourceMap nil
:enableContentValidation t
:autoAttachChildProcesses t
:console "internalConsole"
:killBehavior "forceful"))
(add-to-list 'dape-configs
`(delve
modes (go-mode go-ts-mode)
command "dlv"
command-args ("dap" "--listen" "127.0.0.1:55878")
command-cwd dape-command-cwd
host "127.0.0.1"
port 55878
:type "debug" ;; needed to set the adapterID correctly as a string type
:request "launch"
:cwd dape-cwd
:program dape-buffer-default))
(add-to-list 'dape-configs
`(codelldb
modes (c-mode c-ts-mode
c++-mode c+ +-ts-mode
rust-ts-mode rust-mode)
;; Replace vadimcn.vscode-lldb with the vsix directory you just extracted
command ,(expand-file-name
(file-name-concat
snm-codelldb-dir
(concat "extension/adapter/codelldb"
(if (eq system-type 'windows-nt)
".exe"
""))))
host "localhost"
port 5818
command-args ("--port" "5818")
:type "lldb"
:request "launch"
:cwd dape-cwd
:program dape-buffer-default))
(add-to-list 'dape-configs
`(debugpy
modes (python-ts-mode python-mode)
command "python"
command-args ("-m" "debugpy.adapter")
:type "executable"
:request "launch"
:cwd dape-cwd
:program dape-buffer-default))
))
#+END_SRC
#+RESULTS :
*** TODO move scheme configuration to the scheme section
or leave it here but move it to config, whatever makes most sense at
the moment.
* AI Support
** AI Provider API keys
As many tools require API keys, I better define them once and reuse
them in the configuration of the individual tools.
#+BEGIN_SRC emacs-lisp
(setq openai-api-key (auth-source-pass-get 'secret "snamellit/openai-api-key"))
(setq anthropic-api-key (auth-source-pass-get 'secret "snamellit/anthropic-api-key"))
(setq gemini-api-key (auth-source-pass-get 'secret "snamellit/gemini-api-key"))
#+END_SRC
#+RESULTS :
: AIzaSyBAkk0xHNkIBxCzkfvbOgYVb-B6BguWVUI
** Enable LLM access with Ellama
Configures access to language models using Ellama. I don't know
whether to put it under writing, comms or programming as it is equally
/useful(?)/ for either activity. So I promoted it to an Editor feature.
#+BEGIN_SRC emacs-lisp
(use-package llm :ensure t)
#+END_SRC
#+RESULTS :
: [nil 26497 15516 337719 nil elpaca-process-queues nil nil 495000 nil]
#+RESULTS :g
#+BEGIN_SRC emacs-lisp :tangle no
(use-package ellama
:ensure t
:defer t
:requires (llm)
:config
(message "Ellama loaded")
(keymap-global-set "C-c e" 'ellama-transient-main-menu)
:custom
(ellama-language "English")
(ellama-sessions-directory (expand-file-name "~/Nextcloud/ellama-sessions"))
(ellama-providers
'(("openai" . (progn
(require 'llm-openai)
(make-llm-openai
:key openai-api-key
:chat-model "gpt-4o"))))
))
#+END_SRC
#+RESULTS :
: [nil 26497 19957 511863 nil elpaca-process-queues nil nil 742000 nil]
It seems the *gpt-4o* model provides better responses.
I should investigate local models more.
*** Use Gemini with ellama
This is mostly for those who want to use Google Cloud specifically, most users should use Gemini instead, which is easier to set up.
You can set up with make-llm-vertex, with the following parameters:
| paramter | description |
|------------------+-------------------------------------------------------------------------------------------------------------------------|
| | |
| :project | Your project number from Google Cloud that has Vertex API enabled. |
| :chat-model | A model name from the list of Vertex's model names. This is optional, and will default to a reasonable model. |
| :embedding-model | A model name from the list of Vertex's embedding model names. This is optional, and will default to a reasonable model. |
In addition to the provider, which you may want multiple of (for example, to charge against different projects), there are customizable variables:
- llm-vertex-gcloud-binary: The binary to use for generating the API key.
- llm-vertex-gcloud-region: The gcloud region to use. It's good to set this to a region near where you are for best latency. Defaults to "us-central1".
If you haven't already, you must run the following command before using this:
#+BEGIN_SRC shell :tangle no
gcloud beta services identity create --service=aiplatform.googleapis.com --project=PROJECT_ID
#+END_SRC
However this is not for the Gemini Code Assistant. It is unclear how
to use that backend. Gemini Code Assistant is part of the Google Cloud
Tools.
** GPTel LLM support
Most of the mind share seems to be around [[https://github.com/karthink/gptel ][gptel ]] as basis for LLM
integration in Emacs.
#+BEGIN_SRC emacs-lisp
(use-package gptel
:ensure t
:commands (gptel)
:config
;;(setq gptel-default-mode 'org-mode)
(setq gptel-api-key openai-api-key)
(gptel-make-gemini "Gemini" :key gemini-api-key :stream t)
(gptel-make-anthropic "Claude" :stream t :key anthropic-api-key)
(gptel-make-ollama "Qwen Coder"
:models '(qwen2.5-coder:14b
:description "QWen 2.5 Coder 14b"))
;; define some tools for gptel
(gptel-make-tool
:function (lambda (url)
(with-current-buffer (url-retrieve-synchronously url)
(goto-char (point-min)) (forward-paragraph)
(let ((dom (libxml-parse-html-region (point) (point-max))))
(run-at-time 0 nil #'kill-buffer (current-buffer))
(with-temp-buffer
(shr-insert-document dom)
(buffer-substring-no-properties (point-min) (point-max))))))
:name "read_url"
:description "Fetch and read the contents of a URL"
:args (list '(:name "url"
:type "string"
:description "The URL to read"))
:category "web")
(gptel-make-tool
:function (lambda (buffer text)
(with-current-buffer (get-buffer-create buffer)
(save-excursion
(goto-char (point-max))
(insert text)))
(format "Appended text to buffer %s" buffer))
:name "append_to_buffer"
:description "Append text to the an Emacs buffer. If the buffer does not exist, it will be created."
:args (list '(:name "buffer"
:type "string"
:description "The name of the buffer to append text to.")
'(:name "text"
:type "string"
:description "The text to append to the buffer."))
:category "emacs")
;; Message buffer logging tool
(gptel-make-tool
:function (lambda (text)
(message "%s" text)
(format "Message sent: %s" text))
:name "echo_message"
2025-02-25 12:32:48 +01:00
:description "Send a message to the *Messages* buffer"
:args (list '(:name "text"
:type "string"
:description "The text to send to the messages buffer"))
:category "emacs")
;; buffer retrieval tool
(gptel-make-tool
:function (lambda (buffer)
(unless (buffer-live-p (get-buffer buffer))
(error "Error: buffer %s is not live." buffer))
(with-current-buffer buffer
(buffer-substring-no-properties (point-min) (point-max))))
:name "read_buffer"
:description "Return the contents of an Emacs buffer"
:args (list '(:name "buffer"
:type "string"
:description "The name of the buffer whose contents are to be retrieved"))
:category "emacs")
(gptel-make-tool
:function (lambda (directory)
(mapconcat #'identity
(directory-files directory)
"\n"))
:name "list_directory"
:description "List the contents of a given directory"
:args (list '(:name "directory"
:type "string"
:description "The path to the directory to list"))
:category "filesystem")
(gptel-make-tool
:function (lambda (parent name)
(condition-case nil
(progn
(make-directory (expand-file-name name parent) t)
(format "Directory %s created/verified in %s" name parent))
(error (format "Error creating directory %s in %s" name parent))))
:name "make_directory"
:description "Create a new directory with the given name in the specified parent directory"
:args (list '(:name "parent"
:type "string"
:description "The parent directory where the new directory should be created, e.g. /tmp")
'(:name "name"
:type "string"
:description "The name of the new directory to create, e.g. testdir"))
:category "filesystem")
(gptel-make-tool
:function (lambda (path filename content)
(let ((full-path (expand-file-name filename path)))
(with-temp-buffer
(insert content)
(write-file full-path))
(format "Created file %s in %s" filename path)))
:name "create_file"
:description "Create a new file with the specified content"
:args (list '(:name "path"
:type "string"
:description "The directory where to create the file")
'(:name "filename"
:type "string"
:description "The name of the file to create")
'(:name "content"
:type "string"
:description "The content to write to the file"))
:category "filesystem")
(gptel-make-tool
:function (lambda (filepath)
(with-temp-buffer
(insert-file-contents (expand-file-name filepath))
(buffer-string)))
:name "read_file"
:description "Read and display the contents of a file"
:args (list '(:name "filepath"
:type "string"
:description "Path to the file to read. Supports relative paths and ~."))
:category "filesystem")
2025-02-26 00:11:31 +01:00
;; follow output
(add-hook 'gptel-post-stream-hook 'gptel-auto-scroll)
;; move to next prompt after response
(add-hook 'gptel-post-response-functions 'gptel-end-of-response)
2025-02-25 12:32:48 +01:00
)
#+END_SRC
#+RESULTS :
2025-05-04 00:02:31 +02:00
: [nil 26626 15252 706789 nil elpaca-process-queues nil nil 969000 nil]
2025-02-25 12:32:48 +01:00
2025-02-17 01:53:31 +01:00
** Copilot Support
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Copilot Support")
#+END_SRC
2025-06-02 16:13:05 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
2025-02-17 01:53:31 +01:00
(use-package copilot
:ensure (copilot :host github :repo "zerolfx/copilot.el"
:branch "main"
:files ("dist" "*.el"))
:bind ("C-S-y" . copilot-accept-completion)
:config
(add-to-list 'copilot-indentation-alist '(scheme-mode . 2))
(add-to-list 'copilot-indentation-alist '(emacs-lisp-mode . 2))
(add-to-list 'copilot-indentation-alist '(lisp-mode . 2))
:custom
(copilot-indent-offset-warning-disabled t "Disable indent offset warning" )
:hook
(prog-mode . copilot-mode)
(org-mode . copilot-mode))
#+END_SRC
#+RESULTS :
: [nil 26506 39443 528692 nil elpaca-process-queues nil nil 667000 nil]
** SuperMaven Support
There is a lot of positive hubbub around [[https://github.com/crazywolf132/supermaven.el ][SuperMaven ]].
#+BEGIN_SRC emacs-lisp :tangle no
(use-package supermaven
:ensure (supermaven :host github :repo "crazywolf132/supermaven.el"
:branch "main")
:init
(setq supermaven-ignore-filetypes '("org" "txt"))
(setq supermaven-disable-inline-completion nil)
(setq supermaven-keymaps
'((accept-suggestion . "TAB")
(clear-suggestion . "C-]")
(accept-word . "C-j")))
(setq supermaven-log-level 'debug)
:hook (prog-mode . supermaven-mode))
#+END_SRC
#+RESULTS :
: [nil 26528 36711 407251 nil elpaca-process-queues nil nil 656000 nil]
<2025-01-28 Tue > Tried it out but did not work. I got following
errors :
#+BEGIN_SRC fundamental
[2025-01-28 14:47:15] [INFO] Supermaven process started successfully
[2025-01-28 14:47:17] [INFO] Stopping Supermaven process...
[2025-01-28 14:47:17] [INFO] Supermaven process killed
[2025-01-28 14:47:17] [INFO] Supermaven process started successfully
[2025-01-28 14:47:19] [INFO] Stopping Supermaven process...
[2025-01-28 14:47:19] [INFO] Supermaven process killed
[2025-01-28 14:47:19] [INFO] Supermaven process started successfully
[2025-01-28 14:47:21] [INFO] Stopping Supermaven process...
[2025-01-28 14:47:21] [INFO] Supermaven process killed
[2025-01-28 14:47:21] [INFO] Supermaven process started successfully
[2025-01-28 14:47:21] [INFO] Stopping Supermaven process...
[2025-01-28 14:47:21] [INFO] Supermaven process killed
[2025-01-28 14:47:21] [INFO] Supermaven process started successfully
[2025-01-28 14:47:21] [INFO] Supermaven process started successfully
[2025-01-28 14:47:22] [INFO] Supermaven process hangup
#+END_SRC
In a separate terminal I see the pid change every 2 seconds. It seems
to work fine in vscode. +Not tested in neovim yet+ . It works just fine
in Neovim.
Supermaven requires company support at the moment. There is a [[https://github.com/crazywolf132/supermaven.el/issues/12][Feature
Request open]] to add corfu support.
** Gemini Code Completion
#+BEGIN_SRC emacs-lisp
(use-package google-gemini
:ensure (google-gemini
:host github
:repo "emacs-openai/google-gemini")
:config
(setq google-gemini-key gemini-api-key)
)
#+END_SRC
#+RESULTS :
: [nil 26546 33151 856622 nil elpaca-process-queues nil nil 426000 nil]
#+BEGIN_SRC emacs-lisp
(use-package gemini-code-completion
:ensure (gemini-code-completion
:host github
:repo "shishimaru/gemini-code-completion.el"
:files ("*.el"))
:bind
("C-c g" . gemini-code-completion)
:config
;;https://github.com/shishimaru/gemini-code-completion.el/issues/13
(setq gemini-code-completion-min-number-of-candidates 1)
(setq gemini-code-completion-disable-completion-keybinding t)
)
#+END_SRC
#+RESULTS :
: [nil 26525 26586 616591 nil elpaca-process-queues nil nil 615000 nil]
** Aider Support
Aider is a package which works as a pair programming partner to
generate code.
#+BEGIN_SRC emacs-lisp
2025-02-25 12:32:48 +01:00
(use-package aidermacs
:ensure (:host github :repo "MatthewZMD/aidermacs" :files ("*.el"))
2025-02-17 01:53:31 +01:00
:config
;; Use claude-3-5-sonnet cause it is best in aider benchmark
;;(setq aider-args '("--model" "anthropic/claude-3-5-sonnet-20241022"))
;;(setenv "ANTHROPIC_API_KEY" anthropic-api-key)
;; Or use chatgpt model since it is most well known
;; (setq aider-args '("--model" "gpt-4o-mini"))
;; (setenv "OPENAI_API_KEY" <your-openai-api-key >)
;; Or use gemini v2 model since it is very good and free
2025-02-25 12:32:48 +01:00
(setq aidermacs-default-model "gemini-2.0-flash-thinking-exp-01-21")
2025-02-17 01:53:31 +01:00
(setenv "GEMINI_API_KEY" google-gemini-key)
2025-02-25 12:32:48 +01:00
(setq aidermacs-auto-commits t)
(setq aidermacs-use-architect-mode t)
(setq aidermacs-backend 'vterm)
2025-02-17 01:53:31 +01:00
;;
;; Optional: Set a key binding for the transient menu
2025-07-22 18:08:22 +02:00
)
2025-02-17 01:53:31 +01:00
#+END_SRC
#+RESULTS :
2025-02-25 12:32:48 +01:00
: [nil 26557 35519 420170 nil elpaca-process-queues nil nil 238000 nil]
2025-02-17 01:53:31 +01:00
** Dired Configuration
Enables an alternative file navigation behavior in Dired, Emacs' directory editor:
#+BEGIN_SRC emacs-lisp
(put 'dired-find-alternate-file 'disabled nil)
#+END_SRC
** Use Magit for version control
#+BEGIN_SRC emacs-lisp
2025-06-20 10:54:27 +02:00
;; default to magit for version control
(use-package magit
2025-07-22 18:08:22 +02:00
:ensure (:wait t)
2025-06-20 10:54:27 +02:00
:commands (magit-status)
:bind
(("C-x p v" . magit-status)
("<leader > p v" . magit-status)))
2025-02-17 01:53:31 +01:00
#+END_SRC
2025-06-20 10:54:27 +02:00
#+RESULTS :
: [nil 26709 8564 25469 nil elpaca-process-queues nil nil 123000 nil]
2025-02-17 01:53:31 +01:00
** Better EDiff support
#+BEGIN_SRC emacs-lisp
;; better ediff setting suggested by cwebber
(use-package ediff
:commands (ediff ediff-files ediff3 ediff-files3)
:config
(setq
ediff-window-setup-function 'ediff-setup-windows-plain
ediff-split-window-function 'split-window-horizontally))
#+END_SRC
#+RESULTS :
: t
** Replace normal Buffer Support with IBuffer
Configure ibuffer support with project contexts, courtesy of crafted
emacs
#+BEGIN_SRC emacs-lisp
;;; enhance ibuffer with ibuffer-project if it is available.
(defun snm-ide-enhance-ibuffer-with-ibuffer-project ()
"Set up integration for `ibuffer' with `ibuffer-project'."
(setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups))
(unless (eq ibuffer-sorting-mode 'project-file-relative)
(ibuffer-do-sort-by-project-file-relative)))
(use-package ibuffer-project
:ensure t
:hook
(ibuffer-mode . snm-ide-enhance-ibuffer-with-ibuffer-project)
2025-06-20 14:30:15 +02:00
:bind (("C-x C-b" . #'ibuffer-other-window)))
2025-02-17 01:53:31 +01:00
#+END_SRC
** Enable EditorConfig Standard Support
#+BEGIN_SRC emacs-lisp
;;; load editorconfig support
(use-package editorconfig
:hook
(prog-mode . (lambda() (editorconfig-mode 1))))
#+END_SRC
#+RESULTS :
| editorconfig-mode |
2024-08-15 13:19:57 +02:00
2025-02-17 01:53:31 +01:00
** Enable Direnv Integration
2024-08-15 13:19:57 +02:00
2025-02-17 01:53:31 +01:00
Direnv is the key to have isolated project folders which maintain their own bubble to support whatever is done in that folder.
- set environment variables
- run prep scripts or start services
- load nix or guix profiles to provide support applications
2024-08-15 13:19:57 +02:00
2025-02-17 01:53:31 +01:00
Emacs' direnv module gives first class support to Emacs projects so they use the right tools for the project.
2024-08-15 13:19:57 +02:00
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
;; enable direnv mode
(use-package direnv
:ensure t
:config
(direnv-mode))
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-08-15 13:19:57 +02:00
2025-02-17 01:53:31 +01:00
This enables direnv globally.
2024-08-15 13:19:57 +02:00
2025-02-17 01:53:31 +01:00
** Configure Embark
2024-07-30 14:40:34 +02:00
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
(use-package embark
:ensure t
:bind
(("C-." . embark-act)
("C-;" . embark-dwim)
("C-h B" . embark-bindings))
:config
(setq prefix-help-command #'embark-prefix-help-command))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:ensure t ; only need to install it, embark loads it after consult if found
:hook
(embark-collect-mode . consult-preview-at-point-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2025-02-17 01:53:31 +01:00
: [nil 26502 58499 164859 nil elpaca-process-queues nil nil 179000 nil]
2024-07-30 14:40:34 +02:00
2025-02-17 01:53:31 +01:00
** Configure Helpful
2024-08-09 10:32:41 +02:00
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
(use-package helpful
:ensure t
:bind (
( "<remap > <describe-command >" . #'helpful-command)
( "<remap > <describe-function >" . #'helpful-callable)
( "<remap > <describe-key >" . #'helpful-key)
( "<remap > <describe-symbol >" . #'helpful-symbol)
( "<remap > <describe-variable >" . #'helpful-variable)
( "C-h F" . #'helpful-function)))
2024-08-15 13:19:57 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
2025-02-17 01:53:31 +01:00
: [nil 26432 30485 62583 nil elpaca-process-queues nil nil 114000 nil]
2024-12-11 11:50:04 +01:00
2025-07-22 11:40:01 +02:00
** Add emacslisp-demos
A package which enhances helpful by adding API demos to the the help
#+BEGIN_SRC emacs-lisp
(use-package elisp-demos
:ensure t
:init
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
#+END_SRC
#+RESULTS :
: [nil 26745 27316 824254 nil elpaca-process-queues nil nil 497000 nil]
2025-02-17 01:53:31 +01:00
** Enable breadcrumbs
Show breadcrumbs in the header line to keep context of the file being
worked on. See the [[https://github.com/joaotavora/breadcrumb ][breadcrumb repo ]] for more details.
2024-12-11 11:50:04 +01:00
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2025-02-17 01:53:31 +01:00
(use-package breadcrumb
:ensure t
:init
(breadcrumb-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2025-02-17 01:53:31 +01:00
: [nil 26432 31533 350342 nil elpaca-process-queues nil nil 899000 nil]
** Enable Avy jumping
2024-07-30 14:40:34 +02:00
2025-02-17 01:53:31 +01:00
Avy mode replace ace-jump mode with a lot of functionality hidden
2024-07-30 14:40:34 +02:00
2025-02-17 01:53:31 +01:00
see [[https://karthinks.com/software/avy-can-do-anything/ ][Avy can Do Anything ]] article by the author on the design philosophy
behind it.
2024-07-30 14:40:34 +02:00
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp
2025-02-17 01:53:31 +01:00
(use-package avy
:ensure t
:commands (avy-goto-char
avy-goto-char-2
avy-goto-char-2-above
avy-goto-char-2-below
avy-goto-char-in-line
avy-goto-char-timer
avy-goto-line
avy-goto-line-above
avy-goto-line-below
avy-goto-subword-0
avy-goto-subword-1
avy-goto-symbol-1
avy-goto-symbol-1-above
avy-goto-symbol-1-below
avy-goto-word-0
avy-goto-word-1
avy-goto-word-1-above
avy-goto-word-1-below
avy-goto-word-or-subword-1)
:bind
(("C-:" . avy-goto-char-timer)
("M-g w" . avy-goto-word-0)
("M-g f" . avy-goto-line))
:config
(avy-setup-default) ;; setup C-' to jump with isearch
)
2024-08-15 13:19:57 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
2025-02-17 01:53:31 +01:00
: [nil 26507 37720 141708 nil elpaca-process-queues nil nil 278000 nil]
2024-12-11 11:50:04 +01:00
2025-02-17 01:53:31 +01:00
#+RESULTS :
2024-12-11 11:50:04 +01:00
2025-02-17 01:53:31 +01:00
** Ace Window Configuration
2024-12-11 11:50:04 +01:00
2025-02-17 01:53:31 +01:00
#+BEGIN_SRC emacs-lisp
(use-package ace-window
:ensure t
:bind
("C-x o" . ace-window)
:config
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
2025-08-05 20:55:09 +02:00
(setq aw-dispatch-always nil))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-09 10:32:41 +02:00
#+RESULTS :
2025-02-17 01:53:31 +01:00
: [nil 26523 35809 462186 nil elpaca-process-queues nil nil 958000 nil]
2025-01-13 07:24:33 +01:00
2025-02-17 01:53:31 +01:00
** Command Log Mode
2024-12-09 18:21:17 +01:00
2025-02-17 01:53:31 +01:00
surprising sequence of events happened. Command Log Mode is a package
that records all the commands that are executed in the buffer and
provides a way to replay them.
2024-12-09 18:21:17 +01:00
#+BEGIN_SRC emacs-lisp
2025-02-17 01:53:31 +01:00
(use-package command-log-mode
2024-12-09 18:21:17 +01:00
:ensure t
2025-02-17 01:53:31 +01:00
:commands (command-log-mode))
2024-12-09 18:21:17 +01:00
#+END_SRC
2025-02-17 00:59:26 +01:00
#+RESULTS :
2025-02-17 01:53:31 +01:00
: [nil 26503 37477 396927 nil elpaca-process-queues nil nil 128000 nil]
2025-02-17 00:59:26 +01:00
2025-02-17 01:53:31 +01:00
** Abbrev Files
#+BEGIN_SRC emacs-lisp
(use-package abbrev
:ensure nil
:config
(setq abbrev-file-name (expand-file-name "abbrev_defs" user-emacs-directory))
(setq save-abbrevs 'silently)
(if (file-exists-p abbrev-file-name)
(quietly-read-abbrev-file)))
#+END_SRC
2024-12-09 18:21:17 +01:00
2024-08-02 13:23:26 +02:00
* Communication and Interwebs
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Communication and Interwebs")
#+END_SRC
2024-12-02 14:43:46 +01:00
** ERC configuration :disabled:
2024-07-30 14:40:34 +02:00
Set up ERC, an IRC client for Emacs, to automatically join specific channels and log in:
2024-11-18 11:26:22 +01:00
#+BEGIN_SRC emacs-lisp :tangle no
2024-07-30 14:40:34 +02:00
(use-package erc
:ensure t
:defer 5
:config
(erc-services-mode 1)
(erc-autojoin-mode 1)
(erc-update-modules)
(setq erc-autojoin-channels-alist
'(('znc
"#emacs" "#erc" "#spritely" "#guix"
2024-10-23 11:52:07 +02:00
"#systemcrafters" "#systemcrafters-guix" "#systemcrafters-emacs")))
(custom-set-variables
'(erc-fool-highlight-type 'all)
'(erc-fools '("Marvin2"))
'(erc-keyword-highlight-type 'all)
'(erc-pal-highlight-type 'all)
'(erc-pals '("Fade" "daviwil" "alternateved" "trev" "talos" "dthompson"))
'(erc-prompt-for-password nil)))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-10-23 11:52:07 +02:00
: [nil 26384 63712 203392 nil elpaca-process-queues nil nil 785000 nil]
2024-07-30 14:40:34 +02:00
Setup all channels which are joined by default.
2024-08-02 13:23:26 +02:00
*** ERC connect function
2024-07-30 14:40:34 +02:00
2024-12-03 13:14:31 +01:00
Define a function to login to ERC when needed. In principle ERC
2024-07-30 14:40:34 +02:00
reconnects after suspend, and sometimes it even works, but mostly I
run this function again to reconnect, which will update the buffers
with the rooms I joined.
2024-11-18 11:26:22 +01:00
#+BEGIN_SRC emacs-lisp :tangle no
2024-07-30 14:40:34 +02:00
(defun snam-erc ()
"Login to znc bouncer and join rooms."
(interactive)
(erc-tls :id 'znc
:server (auth-source-pass-get "server" "snamellit/znc")
:port (auth-source-pass-get "port" "snamellit/znc")
:user (auth-source-pass-get "user" "snamellit/znc")
:nick (auth-source-pass-get "nick" "snamellit/znc")
:password (auth-source-pass-get 'secret "snamellit/znc")))
#+END_SRC
#+RESULTS :
: snam-erc
In practice this has proven to be a very useful function to reconnect
in all kind of weird situation.
2024-08-02 13:23:26 +02:00
**** TODO Figure out how to make ERC reconnect more reliably
2024-07-30 14:40:34 +02:00
Although running `snam-erc` is not a big deal, it should not be needed
2024-12-03 13:14:31 +01:00
so much. I should figure out in what cases reconnects fail or dropping
2024-07-30 14:40:34 +02:00
connections fail to be recognized.
I often see that ERC is _reconnecting_ however this seems to silently
2024-12-03 13:14:31 +01:00
fail. I dunno, there is something fishy here...
2024-07-30 14:40:34 +02:00
2024-08-02 13:23:26 +02:00
*** Integrate ERC with i3 Desktops
2024-07-30 14:40:34 +02:00
I like to have my IRC channels on workspace 5 in *i3*.
2024-12-02 14:43:46 +01:00
o longer useful : I seldom use i3, but it is useful for
2024-11-18 11:26:22 +01:00
inspiration
#+BEGIN_SRC emacs-lisp :tangle no
2024-07-30 14:40:34 +02:00
(defun my-erc ()
"Create new frame and move to ws5 and launch erc."
(interactive)
(let ((frame (make-frame))
(channel "#systemcrafters"))
(call-process "i3" nil nil nil "move window to workspace 5")
(snam-erc)
(call-process "i3" nil nil nil "workspace 5")
2024-08-11 11:36:44 +02:00
(report-time-since-load "Waiting to connect to IRC...")
2024-07-30 14:40:34 +02:00
(dotimes (i 12)
(unless (member channel (mapcar 'buffer-name (erc-channel-list nil)))
(sleep-for 0.25)))
(set-window-buffer
(frame-selected-window frame) channel)))
#+END_SRC
#+RESULTS :
: my-erc
2024-11-18 11:26:22 +01:00
** rcirc configuration
#+BEGIN_SRC emacs-lisp
(use-package rcirc
:config
2024-12-02 14:43:46 +01:00
(setopt
rcirc-server-alist
2024-11-18 11:26:22 +01:00
(let ((data (auth-source-pass-parse-entry "snamellit/znc")))
`((,(auth-source-pass--get-attr "server" data)
:port ,(auth-source-pass--get-attr "port" data)
:encryption tls
:server-alias "znc"
:nick ,(auth-source-pass--get-attr "nick" data)
2024-12-02 14:43:46 +01:00
:user-name ,(concat
(auth-source-pass--get-attr "user" data)
"@"
2025-06-02 16:13:05 +02:00
(car (string-split (system-name) "\\.")))
2024-11-18 11:26:22 +01:00
:password ,(auth-source-pass--get-attr 'secret data)
2024-12-02 14:43:46 +01:00
:channels '("#emacs"
"#erc"
"#spritely"
"#guix"
"#systemcrafters"
"#systemcrafters-guix"
"#systemcrafters-emacs"
)))))
2024-11-18 11:26:22 +01:00
(setopt rcirc-reconnect-delay 15)
(setopt rcirc-dim-nicks '("Marvin2"))
2024-12-02 14:43:46 +01:00
(setopt rcirc-bright-nicks '("daviwil"
"benoitj"
"Fade"
"trev"
"shom"
"alternateved"
"dthompson"))
2024-11-18 11:26:22 +01:00
(rcirc-track-minor-mode))
#+END_SRC
#+RESULTS :
: t
2024-08-02 13:23:26 +02:00
** Elfeed configuration
2024-07-30 14:40:34 +02:00
Configures Elfeed, an RSS feed reader for Emacs:
#+BEGIN_SRC emacs-lisp
;; configure elfeed
(use-package elfeed
:ensure t
:defer 5
:config
(setq elfeed-feeds
'("https://www.spritelyproject.org/feed.xml"
2024-08-05 22:59:21 +02:00
;; "https://www.emacswiki.org/emacs?action=rss"
2024-07-30 14:40:34 +02:00
;; "https://www.reddit.com/r/emacs.rss"
;; "https://www.reddit.com/r/guix.rss"
;; "https://www.reddit.com/r/linux.rss"
"https://sachachua.com/blog/feed/ "
"https://blog.benoitj.ca/posts/index.xml"
"https://tylerdback.com/index.xml"
"https://www.snamellit.com/rss.xml"
"https://richarddavis.xyz/en/blog/rss.xml"
"https://protesilaos.com/master.xml"
)))
#+END_SRC
#+RESULTS :
: [nil 26279 35504 577569 nil elpaca-process-queues nil nil 161000 nil]
2024-08-07 09:53:38 +02:00
*** TODO OPML To Elfeed
#+BEGIN_SRC emacs-lisp
2025-07-22 11:40:01 +02:00
(use-package opml-to-elfeed-feeds
:ensure (:host "codeberg.org" :repo "kakafarm/emacs-opml-to-elfeed-feeds"
:main "opml-to-elfeed-feeds.el")
:custom
(o2e-opml-list . (("https://craftering.systemcrafters.net/Craftering.opml" blog craftering opml-to-elfeed-feeds)))
:commands
(opml-to-elfeed-feeds-update-o2e-elfeed-feeds)
)
2024-08-07 09:53:38 +02:00
#+END_SRC
#+RESULTS :
2025-07-22 11:40:01 +02:00
: [nil 26750 42629 851189 nil elpaca-process-queues nil nil 224000 nil]
2024-08-07 09:53:38 +02:00
2024-12-03 13:14:31 +01:00
This does all kind of weird things. Apparently elpaca or use-package
2024-08-07 09:53:38 +02:00
magically namespaces all the functions and for some reason it fails
2024-12-03 13:14:31 +01:00
to require 'elfeed'. ... The weird thing is that the emacs lips
2024-08-07 09:53:38 +02:00
feature is used to expand o2e to opml-to-elfeed-feeds, by setting the
`read-symbol-shorthands` variable to `(("o2e"
. "opml-to-elfeed-feeds"))`.
Agreed with cow_2000 to create an issue on the repo with my
recommendation for public API.
2024-08-02 13:23:26 +02:00
** Enable 0x0 to share snippets and files easily
2024-07-30 14:40:34 +02:00
Configures the ~0x0~ package for easily sharing code snippets and files:
#+BEGIN_SRC emacs-lisp
;; configure 0x0
(use-package 0x0
2025-02-17 01:06:23 +01:00
:disabled
2024-07-30 14:40:34 +02:00
:ensure t
:config (setq 0x0-use-curl t))
2025-02-17 01:06:23 +01:00
(defun 0x0-upload-text ()
(interactive)
(let* ((contents
(if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(buffer-string)))
(temp-file (make-temp-file "0x0" nil ".txt" contents)))
(message "Sending %s to 0x0.st..." temp-file)
(let ((url (string-trim-right
(shell-command-to-string
(format "curl -s -F'file=@%s' -Fsecret= -Fexpires=24 https://0x0.st"
temp-file)))))
(message "Yanked â%sâ into kill ring." url)
(kill-new url)
(delete-file temp-file))))
(defun 0x0-upload-file (file-path)
(interactive "fSelect a file to upload: ")
(message "Sending %s to 0x0.st..." file-path)
(let ((url (string-trim-right
(shell-command-to-string
(format "curl -s -F'file=@%s' -Fsecret= -Fexpires=24 https://0x0.st"
(expand-file-name file-path))))))
(message "Yanked â%sâ into kill ring." url)
(kill-new url)))
#+END_SRC
#+RESULTS :
: +0x0-upload-file
2024-07-30 14:40:34 +02:00
The commands this package offers:
- ~0x0-dwim~ chooses the right one of the following, based on location or previous commands.
- ~0x0-upload-text~ will upload the active region or if not existent the entire buffer
- ~0x0-upload-file~ will upload a selected file
- ~0x0-upload-kill-ring~ uploads the content of the kill ring
- ~0x0-popup~ creates and displays a buffer, lets you upload its contents later
- ~0x0-shorten-uri~ prompts for a uri, shortens it
IMSMR the shorten-uri functionality is disabled in the 0x0 service
as apparently is was abused too much.
2025-05-10 19:41:56 +02:00
** Systemcrafters live stream
#+BEGIN_SRC elisp
(defun systemcrafters ()
"Watch SystemCrafters on Twitch"
(interactive)
(message "Watching SystemCrafters on Twitch...")
2025-06-30 09:41:09 +02:00
(start-process "livestream" "*livestream* "
"mpv"
"--quiet"
"https://twitch.tv/SystemCrafters"))
2025-05-10 19:41:56 +02:00
#+END_SRC
2025-06-30 09:41:09 +02:00
#+RESULTS :
: systemcrafters
2025-05-10 19:41:56 +02:00
2024-07-30 14:40:34 +02:00
* Finishing Touches
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Finishing Touches")
#+END_SRC
2024-07-30 14:40:34 +02:00
** Tell the module system that *init.el* is available
Indicates the ~init.el~ file is provided by and ends here:
#+BEGIN_SRC emacs-lisp
(provide 'init)
;;; init.el ends here
#+END_SRC
2024-07-30 20:48:27 +02:00
* Future
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Future")
#+END_SRC
2025-01-23 14:22:39 +01:00
** DONE Add support for zola blogposts writing in org-mode
CLOSED: [2025-01-20 Mon 10:28]
2024-08-16 00:43:50 +02:00
:LOGBOOK:
2024-09-22 01:19:43 +02:00
CLOCK: [2024-08-15 Thu 13:47]--[2024-08-16 Fri 00:57] => 11:10
2024-08-16 00:43:50 +02:00
:END:
2024-08-02 22:31:15 +02:00
2025-01-19 13:59:42 +01:00
see [[https://github.com/gicrisf/ox-zola ][ox-zola ]] for exporting org-mode to zola markdown.
2024-08-04 01:37:17 +02:00
* Final Words
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Final Words")
#+END_SRC
2024-08-04 01:37:17 +02:00
This is the end of the configuration file.
2024-08-02 22:31:15 +02:00
2024-08-04 01:37:17 +02:00
Add a variable so the file is tangling itself each time it is saved.
2024-07-30 14:40:34 +02:00
2024-08-04 01:37:17 +02:00
# Local Variables:
# eval: (add-hook 'after-save-hook #'org-babel-tangle t t)
# End: