2024-07-30 14:40:34 +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 09:10:59 +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
2024-12-02 14:43:46 +01:00
* Bootstrapping Emacs Configuration
#+BEGIN_SRC emacs-lisp :tangle "early-init.el"
;;; 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.
(setq elpaca-core-date "20241111")
(defvar elpaca-installer-version 0.8)
(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"
:ref nil :depth 1
: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)
(when (< emacs-major-version 28) (require 'subr-x))
(condition-case-unless-debug err
(if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap* "))
((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)))
(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)
(load "./elpaca-autoloads")))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))
;; Enable :elpaca use-package keyword.
(elpaca elpaca-use-package
(elpaca-use-package-mode))
#+END_SRC
2024-12-03 09:10:59 +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 09:10:59 +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.
#+BEGIN_SRC emacs-lisp :tangle "early-init.el"
2024-12-03 09:10:59 +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 09:10:59 +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
* First Things First
2024-08-11 11:36:44 +02:00
2024-08-02 14:49:05 +02:00
** Make tangled file read-only
2024-07-30 14:40:34 +02:00
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
2024-08-04 01:37:17 +02:00
;; init.el --- Literate configuration for Emacs -*- lexical-binding: t; read-only-mode: t; -* -
;;
;;; Commentary:
2024-07-30 14:40:34 +02:00
;;
;; DO NOT EDIT!!!
;;
;; This file is automatically generated from the source in *init.org* .
;;
#+END_SRC
Also immediately set lexical binding mode.
** 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 09:10:59 +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 09:10:59 +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
2024-11-11 17:10:55 +01:00
*** Enable Undo Tree
2024-12-03 09:10:59 +01:00
undo-tree is my preferred way of undoing and redoing stuff. The main reason is it doesn’ t create a linear undo/redo history, but rather a complete tree you can navigate to see your complete editing history. One of the two obvious things to do are to tell Emacs to save all its undo history fies in a dedicated directory, otherwise we’ d risk littering all of our directories. The second thing is to simply globally enable its mode.
2024-11-11 17:10:55 +01:00
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-03 09:10:59 +01:00
(use-package undo-tree
:defer t
:ensure t
:custom
(undo-tree-history-directory-alist
`(("." . ,(expand-file-name (file-name-as-directory "undo-tree-hist")
user-emacs-directory))))
:init
(global-undo-tree-mode)
:config
(setq undo-tree-visualizer-diff t
undo-tree-auto-save-history t
undo-tree-enable-undo-in-region t
undo-limit (* 800 1024)
undo-strong-limit (* 12 1024 1024)
undo-outer-limit (* 128 1024 1024)))
2024-11-11 17:10:55 +01:00
2024-12-02 14:43:46 +01:00
#+END_SRC
#+RESULTS :
: [nil 26444 18481 193426 nil elpaca-process-queues nil nil 879000 nil]
2024-11-11 17:10:55 +01:00
2024-12-02 14:43:46 +01:00
*** Wait for initial installations
#+BEGIN_SRC emacs-lisp
(elpaca-wait)
#+END_SRC
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
(defun pti-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 :
: pti-reload-dir-locals-for-current-buffer
2024-08-05 10:32:04 +02:00
** Get latest version of a github released project
2024-12-03 09:10:59 +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 09:10:59 +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)
(defun pti-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 :
: pti-latest-github-release
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp :tangle no :results value
2024-08-11 11:36:44 +02:00
(pti-latest-github-release "plantuml/plantuml")
#+END_SRC
#+RESULTS :
: v1.2024.6
2024-08-02 13:23:26 +02:00
* Integration with Environment
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Integration with Environment")
#+END_SRC
2024-08-02 13:23:26 +02:00
** Set default Coding System to Use UTF-8 Everywhere
2024-07-30 14:40:34 +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)
;; Treat clipboard input as UTF-8 string first; compound text next, etc.
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
#+END_SRC
Here’ s a breakdown of what each line does:
1. *(set-default-coding-systems 'utf-8)*
2024-12-03 09:10:59 +01:00
This line sets the default coding system for new buffers. When you
2024-07-30 14:40:34 +02:00
create a new buffer or open a file, Emacs will use UTF-8 encoding
2024-12-03 09:10:59 +01:00
by default. It will also set the default terminal and keyboard
coding systems. This applies to all internal operations where a
2024-07-30 14:40:34 +02:00
specific coding system has not been specified.
2. *(set-language-environment 'utf-8)*
2024-12-03 09:10:59 +01:00
This sets the language environment to UTF-8. Emacs uses the
2024-07-30 14:40:34 +02:00
language environment to guess the preferred coding systems for
2024-12-03 09:10:59 +01:00
reading and writing files and for other operations. Setting this to
2024-07-30 14:40:34 +02:00
UTF-8 ensures that UTF-8 is preferred in all language-related
contexts.
3. *(setq locale-coding-system 'utf-8)*
This sets the coding system for locale data, such as environment
2024-12-03 09:10:59 +01:00
variables and system messages. It ensures that Emacs correctly
2024-07-30 14:40:34 +02:00
interprets UTF-8 encoded data coming from the operating system.
4. *(prefer-coding-system 'utf-8)*
This makes UTF-8 the preferred coding system for any situation
2024-12-03 09:10:59 +01:00
where Emacs needs to choose an encoding. It ensures that Emacs
2024-07-30 14:40:34 +02:00
prefers UTF-8 over other encodings.
5. *(setq x-select-request-type ...)*
Treat clipboard input as UTF8_STRING first, compound text next,
etc... .
2024-08-02 13:23:26 +02:00
** Set Path from shell configuration
2024-07-30 14:40:34 +02:00
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.
#+BEGIN_SRC emacs-lisp
;; 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
2024-08-02 13:23:26 +02:00
** Setup backup directories
2024-07-30 14:40:34 +02:00
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"))))
#+END_SRC
2024-08-02 13:23:26 +02:00
** Enable integration with the Unix Password Store aka *pass*
2024-07-30 14:40:34 +02:00
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* .
#+BEGIN_SRC emacs-lisp
;; enable unix password-store
;;(use-package epg)
;;(setq epg-pinentry-mode 'loopback)
(auth-source-pass-enable)
#+END_SRC
This enables *pass* secrets to be used for all subsystems supporting
2024-12-03 09:10:59 +01:00
*auth-source* (which are probably all of them nowadays). It does require
2024-07-30 14:40:34 +02:00
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 ]]
2024-08-02 13:23:26 +02:00
*** Use of Pass Secrets in ELisp
2024-07-30 14:40:34 +02:00
It is very convenient to get secrets from this store (once gpg is set
2024-12-03 09:10:59 +01:00
up, which a totally different can of worms). A function
2024-07-30 14:40:34 +02:00
`auth-source-pass-get` is provided :
#+BEGIN_SRC emacs-lisp :tangle no
(auth-source-pass-get 'secret "dummy/password")
#+END_SRC
#+RESULTS :
: shht!secret
2024-08-02 13:23:26 +02:00
** GUIX support
2024-07-30 14:40:34 +02:00
[[https://gitlab.com/emacs-guix/emacs-guix ][Emacs-guix ]] is a module to interact with the guix system and help
2024-12-03 09:10:59 +01:00
manage packages and profiles. It also offers support for creating
2024-07-30 14:40:34 +02:00
additional profiles and packages for Guix.
#+BEGIN_SRC emacs-lisp
(use-package guix
:ensure t
:defer 5)
#+END_SRC
I find it a bit a confusing module.
It provides a minor-mode
2024-08-04 01:37:17 +02:00
** Add a fully featured terminal emulator
#+BEGIN_SRC emacs-lisp
(use-package eat
:ensure t
:defer 5)
#+END_SRC
#+RESULTS :
: [nil 26285 20099 685413 nil elpaca-process-queues nil nil 626000 nil]
2024-10-26 21:10:54 +02:00
** Enable editing textareas in browsers with Emacs
#+BEGIN_SRC emacs-lisp
(use-package edit-server
:ensure t
:commands edit-server-start
:init (if after-init-time
(edit-server-start)
(add-hook 'after-init-hook
#'(lambda() (edit-server-start))))
:config (setq edit-server-new-frame-alist
'((name . "Edit with Emacs FRAME")
(top . 200)
(left . 200)
(width . 80)
(height . 25)
(minibuffer . t)
(menu-bar-lines . t)
(window-system . x))))
#+END_SRC
#+RESULTS :
: [nil 26383 36877 803383 nil elpaca-process-queues nil nil 768000 nil]
2024-08-02 13:23:26 +02:00
* Editor Features
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Editor Features")
#+END_SRC
2024-09-23 13:42:45 +02:00
2024-12-02 14:43:46 +01:00
** Emacs configuration
2024-09-23 13:42:45 +02:00
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
;; 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
2024-12-03 09:10:59 +01:00
;; commands are hidden in normal buffers. This setting is useful beyond
2024-12-02 14:43:46 +01:00
;; 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)
;; 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
** Enable undo-tree
2024-12-03 09:10:59 +01:00
see [[https://elpa.gnu.org/packages/undo-tree.html ][undo-tree web page ]]. There is a lot of background info there to
2024-12-02 14:43:46 +01:00
explain the problems and solutions.
Emacs actually maintains undo/redo information is an way that any
2024-12-03 09:10:59 +01:00
state can be restored. Both undo and redo is remembered in contrast to
many apps which essentially reset after doing a redo operation. It is
2024-12-02 14:43:46 +01:00
very hard to keep track of the state using the
normal undo/redo machinery to restore a specific state by tracking the
branching naturranching nature.
The *undo-tree* package solves this by redefining the undo/redo bindings
and offering a visualization of the undo/redo state and allow
navigation with real-time updates of the state in the original buffer.
When undo-tree-mode is active the following bindings are available:
- C-_ : undo
- M-_: redo
- C-/ : undo
- C-? : redo
- C-x u : undo-tree-vizualizer
- C-x r u : store undo-tree state in the given register
- C-x r U : restore undo-tree state from the given register
#+BEGIN_SRC emacs-lisp
(use-package undo-tree
:ensure t
:init
(global-undo-tree-mode))
#+END_SRC
#+RESULTS :
: [nil 26433 42993 909143 nil elpaca-process-queues nil nil 187000 nil]
In the visualizer you can navigate the undo/redo state with:
- p : navigate to the previous node in the graph
- n : navigate to the next node in the graph
- q : quit window
- C-q : abort undo tree visualizer
- C-b : switch branch left
- C-f : switch branch right
- M-{ or C-<up > : undo to X where X is a stored register or a branch point
- M-} or C-<down > : redo to X where X is a stored register or a branch point
2024-07-30 14:40:34 +02:00
2024-12-02 14:43:46 +01:00
** Save history over sessions
2024-12-03 09:10:59 +01:00
Persist history over Emacs restarts. Vertico sorts by history
2024-12-02 14:43:46 +01:00
position.
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-02 14:43:46 +01:00
(use-package savehist
:init
(savehist-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-02 14:43:46 +01:00
** Completion Configuration
*** Use Vertico for better selection lists
2024-12-03 09:10:59 +01:00
Vertico is a big package by minad. Well documented in the [[https://github.com/minad/vertico][vertico
2024-12-02 14:43:46 +01:00
github repo]].
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-02 14:43:46 +01: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))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-02 14:43:46 +01:00
*** Orderless for better narrowing
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-02 14:43:46 +01: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-07-30 14:40:34 +02:00
#+END_SRC
2024-12-02 14:43:46 +01:00
*** Marginalia for better context awareness
2024-08-02 13:44:21 +02:00
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-02 14:43:46 +01:00
;; 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))
:init
(marginalia-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-02 13:44:21 +02:00
#+RESULTS :
2024-12-02 14:43:46 +01:00
: marginalia-cycle
*** Add consult
2024-11-11 13:30:16 +01:00
2024-12-02 14:43:46 +01:00
See the excellent documentation on [[https://github.com/minad/consult ][Minad's consult repo ]].
2024-08-02 13:44:21 +02:00
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-02 14:43:46 +01:00
;; Example configuration for Consult
(use-package consult
:ensure t
2024-12-03 09:10:59 +01:00
;; Replace bindings. Lazily loaded by `use-package'.
2024-12-02 14:43:46 +01:00
: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
2024-12-03 09:10:59 +01:00
;; Enable automatic preview at point in the *Completions* buffer. This is
2024-12-02 14:43:46 +01:00
;; relevant when you use the default completion UI.
:hook (completion-list-mode . consult-preview-at-point-mode)
;; The :init configuration is always executed (Not lazy)
:init
2024-12-03 09:10:59 +01:00
;; Optionally configure the register formatting. This improves the register
2024-12-02 14:43:46 +01:00
;; 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)
;; 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)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
;; Configure other variables and modes in the :config section,
;; after lazily loading the package.
:config
2024-12-03 09:10:59 +01:00
;; Optionally configure preview. The default value
2024-12-02 14:43:46 +01:00
;; 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))
;; Optionally configure the narrowing key.
;; Both < and C-+ work reasonably well.
(setq consult-narrow-key "<") ;; "C-+"
;; 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)
)
#+END_SRC
#+RESULTS :
: [nil 26434 3705 536018 nil elpaca-process-queues nil nil 266000 nil]
** User Interface
*** Display startup time
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; Profile emacs startup
(add-hook 'emacs-startup-hook
(lambda ()
(message "Emacs started in %s."
(emacs-init-time))))
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Configure Fonts with Fontaine
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;;
;; Font configuration
;;
(defun pti-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-07-30 16:45:22 +02:00
(defun pti-configure-fonts (&optional frame)
2024-08-04 01:37:17 +02:00
"Set configuration of fonts based on display size.
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."
2024-07-30 14:40:34 +02:00
(defvar pti-font-size
(if (> (display-pixel-height) 1600) 22 14))
;; set startup and default fontsets to make org-bullet work
(set-fontset-font "fontset-startup" nil "DejaVu Sans Mono" nil)
(set-fontset-font "fontset-default" nil "DejaVu Sans Mono" nil)
(setq fontaine-presets
`((t
:default-family ,(pti-find-installed-font
'("FiraCode NF" "FiraCode Nerd Font"))
:default-weight regular
:default-height ,pti-font-size
:variable-pitch-family ,(pti-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)
2024-08-04 01:37:17 +02:00
:demand t
2024-07-30 14:40:34 +02:00
:config (progn
(pti-configure-fonts)
(add-hook 'after-make-frame-functions #'pti-configure-fonts)))
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Update configuration of each created frame
2024-07-30 14:40:34 +02:00
2024-12-03 09:10:59 +01:00
When running as daemon there is no graphical context. This means that
2024-07-30 14:40:34 +02:00
all graphical related settings cannot be set properly at initial
startup if we need to interrogate the capabilities of the current
screen.
#+BEGIN_SRC emacs-lisp
;;
;; remove chrome from the frames
;; also support client frames
;;
(defun pti-display-tweaks (&optional frame)
2024-08-04 01:37:17 +02:00
"Configure a newly created FRAME."
(interactive)
2024-11-11 17:08:02 +01:00
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1))
2024-07-30 14:40:34 +02:00
(add-hook 'after-make-frame-functions #'pti-display-tweaks)
;; run it in the current frame, because the hooks have already fired
(pti-display-tweaks)
#+END_SRC
2024-08-04 01:37:17 +02:00
#+RESULTS :
2024-08-02 13:23:26 +02:00
*** Set Theme
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-10-26 21:10:54 +02:00
;; Set theme
(use-package catppuccin-theme
:ensure t
:demand t)
(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.")
(modus-themes-to-toggle '(modus-operandi-tinted modus-vivendi-tinted))
(modus-themes-completions '((matches . (extrabold background intense))
(selection . (semibold accented intense))))
(modus-themes-org-blocks 'tinted-background)
(modus-themes-mixed-fonts t)
(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)))
2024-07-30 14:40:34 +02:00
#+END_SRC
There is a keybinding on *<F5>* to toggle between light and dark mode.
#+RESULTS :
: modus-themes-toggle
2024-08-02 13:23:26 +02:00
*** Limit Height of Selected Popup Windows
2024-07-30 14:40:34 +02:00
#+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
2024-08-04 01:37:17 +02:00
(window-height . 10))
2024-07-30 14:40:34 +02:00
display-buffer-alist)
(push '("\\*Warnings\\* "
;; display-buffer functions, first one that succeeds is used
(display-buffer-reuse-mode-window
display-buffer-below-selected)
;; Parameters
2024-08-04 01:37:17 +02:00
(window-height . 10))
2024-07-30 14:40:34 +02:00
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
2024-08-04 01:37:17 +02:00
(window-height . 10))
2024-07-30 14:40:34 +02:00
display-buffer-alist)
;; set custom info folder
(add-to-list 'Info-default-directory-list "~/.local/share/info/ ")
#+END_SRC
2024-08-02 13:23:26 +02:00
#+RESULTS :
| ~/.local/share/info/ |
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
#+RESULTS :
: t
** Yasnippet configuration
2024-07-30 14:40:34 +02:00
Enables and configures Yasnippet, a template system for Emacs:
#+BEGIN_SRC emacs-lisp
;; configure yasnippet
(use-package yasnippet
:ensure nil
:defer 5
:config
(yas-global-mode 1))
#+END_SRC
2024-08-02 13:23:26 +02:00
** Enable LLM access with Ellama
2024-12-03 09:10:59 +01:00
Configures access to language models using Ellama. I don't know
2024-07-30 14:40:34 +02:00
whether to put it under writing, comms or programming as it is equally
2024-12-03 09:10:59 +01:00
/useful(?)/ for either activity. So I promoted it to an Editor feature.
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-08-02 14:49:05 +02:00
(use-package llm
:ensure t
2024-11-18 11:26:22 +01:00
:commands (llm-chat llm-ask-about llm-ask-line llm-ask-selection))
#+END_SRC
#+BEGIN_SRC emacs-lisp
2024-08-02 14:49:05 +02:00
(use-package llm-openai
:ensure nil
2024-11-18 11:26:22 +01:00
:requires llm
:commands (make-llm-openai))
#+END_SRC
#+BEGIN_SRC emacs-lisp
2024-08-02 14:49:05 +02:00
(use-package ellama
:ensure t
2024-11-18 11:26:22 +01:00
:requires (llm llm-openai)
2024-08-02 14:49:05 +02:00
:commands (ellama-chat ellama-ask-about ellama-ask-line ellama-ask-selection)
:custom
(ellama-language "English")
(ellama-provider
2024-11-18 11:26:22 +01:00
(make-llm-openai
:key (auth-source-pass-get 'secret "snamellit/openai-api-key")
:chat-model "gpt-4o"
))
2024-10-26 21:10:54 +02:00
(ellama-sessions-directory (expand-file-name "~/Nextcloud/ellama-sessions"))
2024-11-18 11:26:22 +01:00
:bind-keymap
("C-c e" . ellama-command-map))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-11-18 11:26:22 +01:00
#+RESULTS :
: [nil 26420 49222 463525 nil elpaca-process-queues nil nil 237000 nil]
2024-12-03 09:10:59 +01:00
It seems the *gpt-4o* model provides better responses. I should
2024-07-30 14:40:34 +02:00
investigate local models more.
2024-08-02 13:23:26 +02:00
** Dired Configuration
2024-07-30 14:40:34 +02:00
Enables an alternative file navigation behavior in Dired, Emacs' directory editor:
#+BEGIN_SRC emacs-lisp
(put 'dired-find-alternate-file 'disabled nil)
#+END_SRC
2024-08-02 13:23:26 +02:00
** Use Magit for version control
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; default to magit for version control
(use-package magit
:ensure t
:commands (magit-status)
:bind
(("C-x p v" . magit-status)
("<leader > p v" . magit-status)))
#+END_SRC
2024-08-02 13:23:26 +02:00
** Better EDiff support
2024-07-30 14:40:34 +02:00
#+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
2024-08-02 13:23:26 +02:00
** Replace normal Buffer Support with IBuffer
2024-12-02 14:43:46 +01:00
Configure ibuffer support with project contexts, courtesy of crafted
emacs
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;;; enhance ibuffer with ibuffer-project if it is available.
2024-12-02 14:43:46 +01:00
(defun snm-ide-enhance-ibuffer-with-ibuffer-project ()
2024-07-30 14:40:34 +02:00
"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)))
2024-08-04 01:37:17 +02:00
2024-07-30 14:40:34 +02:00
(use-package ibuffer-project
2024-08-04 01:37:17 +02:00
:ensure t
2024-07-30 14:40:34 +02:00
:hook
2024-12-02 14:43:46 +01:00
(ibuffer-mode . snm-ide-enhance-ibuffer-with-ibuffer-project)
2024-07-30 14:40:34 +02:00
:bind (("C-x C-b" . #'ibuffer)))
#+END_SRC
2024-08-02 13:23:26 +02:00
** Enable EditorConfig Standard Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;;; load editorconfig support
(use-package editorconfig
:hook
(prog-mode . (lambda() (editorconfig-mode 1))))
#+END_SRC
#+RESULTS :
| editorconfig-mode |
2024-08-02 13:23:26 +02:00
** Enable Direnv Integration
2024-07-30 14:40:34 +02: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
Emacs' direnv module gives first class support to Emacs projects so they use the right tools for the project.
#+BEGIN_SRC emacs-lisp
;; enable direnv mode
(use-package direnv
:ensure t
:config
(direnv-mode))
#+END_SRC
This enables direnv globally.
2024-10-23 11:52:07 +02:00
** Configure Embark
#+BEGIN_SRC emacs-lisp :tangle no
(use-package embark
:ensure t
:bind
(("C-m" . embark-act)
("C-;" . embark-dwim)
("C-h B" . embark-bindings))
:config
(setq prefix-help-command #'embark-prefix-help-command))
#+END_SRC
#+RESULTS :
: [nil 26384 64829 513923 nil elpaca-process-queues nil nil 691000 nil]
2024-12-02 14:43:46 +01:00
** Configure Helpful
#+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)))
#+END_SRC
#+RESULTS :
: [nil 26432 30485 62583 nil elpaca-process-queues nil nil 114000 nil]
** Enable breadcrumbs
Show breadcrumbs in the header line to keep context of the file being
2024-12-03 09:10:59 +01:00
worked on. See the [[https://github.com/joaotavora/breadcrumb ][breadcrumb repo ]] for more details.
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
(use-package breadcrumb
:ensure t
:init
(breadcrumb-mode))
#+END_SRC
#+RESULTS :
: [nil 26432 31533 350342 nil elpaca-process-queues nil nil 899000 nil]
2024-08-09 10:32:41 +02:00
* Writing and Planning
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Writing and Planning")
#+END_SRC
2024-08-02 13:23:26 +02:00
** Org Mode
2024-07-30 14:40:34 +02:00
2024-08-02 13:23:26 +02:00
*** Mixed Pitch Support by Default in Org
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
(defun pti-org-mode-config ()
"Set options for better writing in org buffers."
(mixed-pitch-mode)
(visual-line-mode)
(turn-on-auto-fill)
)
(use-package org-bullets
:ensure t
:if (display-graphic-p)
:hook (org-mode . org-bullets-mode))
2024-08-04 01:37:17 +02:00
2024-07-30 14:40:34 +02:00
(use-package mixed-pitch
:ensure t
:if (display-graphic-p)
:hook
(org-mode . mixed-pitch-mode))
#+END_SRC
#+RESULTS :
: [nil 26279 36119 854408 nil elpaca-process-queues nil nil 376000 nil]
2024-08-02 13:23:26 +02:00
*** Org Configuration
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-02 14:43:46 +01:00
(use-package org
:ensure nil
: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)
(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-refile-targets '(
(org-agenda-files . (:level . 1))
("~/org/personal/bijen.org" . (:level . 1))
("~/org/personal/fitness.org" . (:level . 1))
))
:config
;; 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")
:hook (
(org-mode . pti-org-mode-config)
(org-mode . org-indent-mode)
)
:bind (
("<leader > o a" . org-agenda)
("<leader > o s" . org-store-link)
))
#+END_SRC
#+RESULTS :
*** Org Appear
Hide the org markers when point is not on the element being decorated.
#+BEGIN_SRC emacs-lisp
(use-package org-appear
:ensure t
:hook (org-mode . org-appear-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-12-02 14:43:46 +01:00
: [nil 26432 31427 677147 nil elpaca-process-queues nil nil 738000 nil]
2024-07-30 14:40:34 +02:00
2024-08-02 13:23:26 +02:00
*** Org Babel Support
2024-08-05 10:32:04 +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. ]]
**** Support REST calls in Babel Blocks
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; enable verb package to do REST calls
(use-package verb
:ensure t
:defer 3
:bind
(:map org-mode-map
("C-c C-r" . verb-command-map)))
(use-package ob-verb
:after verb
:defer 3)
2024-08-05 10:32:04 +02:00
#+END_SRC
**** Support Mermaid Diagrams in Babel Blocks
2024-07-30 14:40:34 +02:00
2024-08-05 10:32:04 +02:00
#+BEGIN_SRC emacs-lisp
;; enable mermaid for org-babel
(use-package ob-mermaid
:ensure t
:defer 3)
#+END_SRC
2024-12-03 09:10:59 +01:00
Mermaid needs support of the mermaid-cli which is a node package. It
2024-08-05 10:32:04 +02:00
can be installed with
2024-07-30 14:40:34 +02:00
2024-08-05 10:32:04 +02:00
#+BEGIN_SRC shell :tangle no
npm install -g @mermaid-js/mermaid-cli
#+END_SRC
#+RESULTS :
| | | | | | |
| changed | 194 | packages | in | 6s | |
| | | | | | |
| 39 | packages | are | looking | for | funding |
| run | `npm | fund` | for | details | |
**** Support PlantUML Diagrams in Babel Blocks
Requires nothing special, other than *plantuml.jar* archive installed.
2024-08-05 10:44:37 +02:00
The following code block depends on [[*Get latest version of a github released project][Get latest version of a github
2024-12-03 09:10:59 +01:00
released project]] utility function. This block will check if there is a
2024-08-05 10:44:37 +02:00
plantuml.jar in the emacs config directory and if not download the
2024-12-03 09:10:59 +01:00
latest version from github. The `pti-download-latest-plantuml` is made
2024-08-05 10:44:37 +02:00
interactive to manually install the latest version if needed.
2024-08-05 10:32:04 +02:00
#+BEGIN_SRC emacs-lisp :lexical t
(defun pti-download-latest-plantuml ()
"Download the latest version of PlantUML.
This function is interactive to make it easy to upgrade to
the latest, current version with `M-x pti-download-latest-plantuml'."
(interactive)
2024-08-11 11:36:44 +02:00
(let* ((version (pti-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)))
2024-08-05 10:32:04 +02:00
(let ((plantuml-jar (concat user-emacs-directory "plantuml.jar")))
(if (not (file-exists-p plantuml-jar))
(pti-download-latest-plantuml))
(setq org-plantuml-jar-path plantuml-jar))
#+END_SRC
#+RESULTS :
: /home/pti/ .config/emacs/plantuml.jar
**** Configure Babel Languages
#+BEGIN_SRC emacs-lisp
;; configure babel languages
(use-package org-babel
:no-require
:after '(ob-verb ob-mermaid)
:config
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(shell . t)
(python . t)
(latex . t)
(verb . t)
(scheme . t)
(plantuml . t)
(mermaid . t)
(dot . t))))
#+END_SRC
**** Temporary Patches for Org Babel
***** Fix Scheme Babel Bug
#+BEGIN_SRC emacs-lisp
2024-07-30 14:40:34 +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))))
#+END_SRC
#+RESULTS :
: org-babel-scheme--table-or-string
2024-08-05 10:32:04 +02:00
**** TODO Move babel test file to emacs config folder
Alternatively I might add a sample after each configured block to keep
2024-12-03 09:10:59 +01:00
it in the same context. Hmmm.... sounds even better.
2024-08-05 10:32:04 +02:00
2024-08-02 13:23:26 +02:00
*** Org Export
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
(use-package ox
:ensure nil)
#+END_SRC
2024-08-02 13:23:26 +02:00
**** Org Export to Markdown
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
(use-package ox-md
:ensure nil
:after ox
)
#+END_SRC
2024-08-02 13:23:26 +02:00
**** Org Latex Export
***** Syntax Highlighting requires Multiple Passes
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; 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"))
)
#+END_SRC
2024-08-02 13:23:26 +02:00
***** Load Customer Latex Classes
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; 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
2024-08-02 13:23:26 +02:00
***** Load My Latex Classes
2024-07-30 14:40:34 +02:00
#+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}"))))
(with-eval-after-load 'ox-latex
(dolist
(class (append mlx-latex-classes snm-latex-classes))
(add-to-list 'org-latex-classes class)))
#+END_SRC
2024-08-16 00:43:50 +02:00
**** Blogging with Zola
2024-07-30 14:40:34 +02:00
2024-08-16 00:43:50 +02:00
gicrisf has [[https://github.com/gicrisf/ox-zola ][created a package ]] to export org files to Zola.
2024-07-30 14:40:34 +02:00
2024-08-16 00:43:50 +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)
:general
("<leader > o z" 'ox-zola-export-wim-to-md))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-16 00:43:50 +02:00
#+RESULTS :
2024-12-03 09:10:59 +01:00
It is a wrapper around ~ox-hugo~ to export org files to Zola. It
2024-08-16 00:43:50 +02:00
supports most features of it and directs the user to the [[https://ox-hugo.scripter.co/ ][the hugo
exporter manual.]]
2024-08-02 13:23:26 +02:00
*** Org Capture Customization
2024-07-30 14:40:34 +02:00
#+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
2024-08-16 00:43:50 +02:00
'("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%?"))
2024-07-30 14:40:34 +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 (("<leader >X" . org-capture)))
#+END_SRC
#+RESULTS :
: t
2024-08-02 13:23:26 +02:00
*** Org GCal Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; configure support for google calendar
(use-package org-gcal
2024-11-18 11:26:22 +01:00
;; :ensure t
2024-08-02 11:39:46 +02:00
: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
2024-08-02 11:39:46 +02:00
#+RESULTS :
2024-08-02 13:23:26 +02:00
*** Org Jira Integration
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-08-09 10:32:41 +02:00
;; configure org-jira
(use-package org-jira
:ensure (: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
'(
(:jql " assignee = currentUser() and (created > '2024-01-01' of updated > '2024-01-01) order by created DESC"
:limit 100 :filename "this-year")
(:jql "project = TTRK and (resolution = Unresolved OR updated>=-15d) ORDER BY priority DESC"
:limit 100 :filename "~/Projects/timetrak/jira")
))
(make-directory "~/.org-jira" 'parents)
(setq jiralib-url (auth-source-pass-get "url" "customer/jira"))
(setq org-jira-custom-jqls
'((:jql " assignee = currentUser() and project = TTRK order by priority DESC " :limit 100 :filename "~/Projects/timetrak/jira")
(:jql " assignee = currentUser() and createdDate >= '2024-01-01' order by created DESC " :limit 100 :filename "this-years-work")))
(jiralib-login
(auth-source-pass-get "user" "customer/jira")
(auth-source-pass-get 'secret "customer/jira"))
:bind (("C-c ig" . 'org-jira-get-issues)
("C-c ip" . 'org-jira-get-projects)
2024-08-15 13:19:57 +02:00
("C-c ij" . 'org-jira-get-issues-from-custom-jql)))
2024-08-09 10:32:41 +02:00
#+END_SRC
#+RESULTS :
: [nil 26292 53013 676464 nil elpaca-process-queues nil nil 459000 nil]
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.
**** Keybindings
| 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 |
**** 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-03 09:10:59 +01:00
@daviwil has a set of productivity tools which are very useful. I have
2024-08-09 10:32:41 +02:00
**** Find all tasks with a specific tag (or without)
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("p" "Planning" tags-todo "+@planning")))
#+END_SRC
#+RESULTS :
| p | Planning | tags-todo | +@planning |
We can remove tasks with a certain tag by adding `-@work` to the pattern.
**** 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 "-{.*}")))
#+END_SRC
#+RESULTS :
| u | Untagged Tasks | tags-todo | -{.*} |
**** Combine multiple filters
We can add a list of queries
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("p" "Planning" ((tags-todo "+@planning")
(tags-todo "-{.*}")))))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-02 14:49:05 +02:00
#+RESULTS :
2024-08-09 10:32:41 +02:00
| 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")))))))
#+END_SRC
#+RESULTS :
| p | Planning | ((tags-todo +@planning ((org-agenda-overriding-header Planning Tasks))) (tags-todo -{.*} ((org-agenda-overriding-header Untagged Tasks)))) |
**** Add support for an input file
#+BEGIN_SRC emacs-lisp
(setq org-agenda-custom-commands
'(("i" "Inbox" ((todo ".*"
2024-10-26 21:10:54 +02:00
((org-agenda-files '("~/Nextcloud/org/inbox.org"))
2024-08-09 10:32:41 +02:00
(org-agenda-overriding-header "Unprocessed Inbox Items")))))))
#+END_SRC
#+RESULTS :
2024-10-26 21:10:54 +02:00
| i | Inbox | ((todo .* ((org-agenda-files '(~/Nextcloud/org/inbox.org)) (org-agenda-overriding-header Unprocessed Inbox Items)))) |
2024-08-09 10:32:41 +02:00
**** Daily Agenda
#+BEGIN_SRC emacs-lisp
(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")
))))))
#+END_SRC
#+RESULTS :
| 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)))) |
**** Weekly Review
#+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
(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
#+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-02 14:49:05 +02:00
2024-08-02 13:23:26 +02:00
** Denote
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; configure denote
(use-package denote
:ensure t
2024-09-22 01:19:43 +02:00
:init
2024-10-26 21:10:54 +02:00
(setq denote-directory (file-name-concat (expand-file-name "~") "Nextcloud/denote"))
2024-09-22 01:19:43 +02:00
(setq denote-dired-directories
(list denote-directory
(expand-file-name "~/Documents/denote")))
2024-07-30 14:40:34 +02:00
: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-02 13:23:26 +02:00
**** TODO explain what denote-dired-mode-in-directories does.
2024-07-30 14:40:34 +02:00
2024-08-02 13:23:26 +02:00
* Programming
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming")
#+END_SRC
2024-08-02 13:23:26 +02:00
** Programming Support Infrastructure
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Infrastructure")
#+END_SRC
2024-08-11 11:36:44 +02:00
2024-08-02 13:23:26 +02:00
*** Integration with LSP Servers for language support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; configure eglot-mode
(use-package eglot
:config
;; Shutdown server when last managed buffer is killed
(setq eglot-autoshutdown t)
;; from https://www.reddit.com/r/emacs/comments/ye18nd/setting_up_eglot_for_python/
(add-to-list 'eglot-server-programs '(python-mode . ("pylsp")))
(setq-default eglot-workspace-configuration
'((:pylsp . (:configurationSources ["flake8"]
:plugins (:pycodestyle (:enabled nil)
:mccabe (:enabled nil)
:flake8 (:enabled t))))))
:hook
(go-ts-mode . eglot-ensure)
(rust-ts-mode . eglot-ensure)
(java-ts-mode . eglot-ensure)
(python-ts-mode . eglot-ensure)
2024-12-02 14:43:46 +01:00
(zig-mode . eglot-ensure))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Use Treesitter parser support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; set locations for treesitter grammars
(use-package treesit
:config
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(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")
(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")))
2024-08-11 11:36:44 +02:00
2024-07-30 14:40:34 +02:00
:hook
((prog . treesit-inspect-mode)))
2024-08-04 01:37:17 +02:00
2024-07-30 14:40:34 +02:00
(use-package treesit-auto
:ensure t
:defer 5
:custom
(treesit-auto-install 'prompt)
2024-08-02 13:23:26 +02:00
(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 nu
org perl proto python r ruby rust scala sql toml tsx
typescript vue yaml)) ; reduced langs list somewhat
2024-07-30 14:40:34 +02:00
:config
(treesit-auto-add-to-auto-mode-alist 'all)
(global-treesit-auto-mode))
#+END_SRC
2024-08-02 13:23:26 +02:00
#+RESULTS :
: [nil 26284 45426 709595 nil elpaca-process-queues nil nil 734000 nil]
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.
***** TODO figure out why Latex does not want to install
***** TODO decide whether to keep using treesitter-auto at all or just plain treesit with some support functions.
**** Recompiling all Treesitter Grammars
2024-07-30 14:40:34 +02:00
To recompile all treesitter grammars, execute following block with
*C-c C-c* .
2024-08-04 01:37:17 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
2024-07-30 14:40:34 +02:00
(mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
#+END_SRC
#+RESULTS :
| bash | cmake | css | elisp | go | gomod | haskell | html | java | javascript | json | lua | make | markdown | ocaml | python | toml | tsx | typescript | yaml |
2024-08-02 13:23:26 +02:00
**** Treesitter Grammars for Windows
2024-08-04 01:37:17 +02:00
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.
2024-07-30 14:40:34 +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.
2024-08-04 01:37:17 +02:00
This will download the dynamic library to _user-emacs-directory_ /elpa/tree-sitter-langs/bin
2024-07-30 14:40:34 +02:00
2024-08-04 01:37:17 +02:00
However they'll have the wrong filename and are not in the path where treesitter looks in.
2024-07-30 14:40:34 +02:00
2024-08-04 01:37:17 +02:00
- Open the folder with *dired*
2024-07-30 14:40:34 +02:00
- 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
and they will now be installed.
2024-08-04 01:37:17 +02:00
Normally that should work for other OSes too, but there is no real need for it.
2024-07-30 14:40:34 +02:00
see also [[https://www.masteringemacs.org/article/how-to-get-started-tree-sitter ][How to get started with tree sitter ]] .
2024-08-02 13:23:26 +02:00
*** Create a folder to store downloaded LSP servers
2024-07-30 14:40:34 +02:00
#+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
2024-08-09 10:32:41 +02:00
*** Electric Return
#+BEGIN_SRC emacs-lisp
;; enable electric return to automatically indent code
(defvar electrify-return-match
"[\]}\)\"]"
"The text after the cursor to do an \"electric\" return.")
(defun electrify-return-if-match (arg)
"Insert a newline, and indent it when needed.
If the text after the cursor matches `electrify-return-match' then
open and indent an empty line between the cursor and the text. Move the
cursor to the new line.
With a prefix argument ARG, insert that many newlines"
(interactive "P")
(let ((case-fold-search nil))
(if (looking-at electrify-return-match)
(save-excursion (newline-and-indent)))
(newline arg)
(indent-according-to-mode)))
;; Using local-set-key in a mode-hook is a better idea.
;(global-set-key (kbd "RET") 'electrify-return-if-match)
#+END_SRC
**** TODO Evaluate if Electric Return is still useful
2024-08-02 13:23:26 +02:00
** Configure Selected Languages
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Selected Languages")
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Rust Support
2024-07-30 14:40:34 +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)))
2024-09-22 01:19:43 +02:00
)
2024-07-30 14:40:34 +02:00
(use-package rustic
:ensure t
:init
(setq rustic-lsp-client 'eglot))
#+END_SRC
2024-08-02 13:23:26 +02:00
*** OCaml Support
2024-07-30 14:40:34 +02:00
#+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
2024-08-02 13:23:26 +02:00
*** Go Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
;; configure go support
(use-package go-ts-mode
:init
(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
:hook
2024-08-02 14:49:05 +02:00
(go-ts . eglot-ensure))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Javascript, Typescript, TSC, etc...
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp :tangle no
;; configure typescript support
(use-package typescript-ts-mode
:init
(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
:hook
(typescript-ts-mode . eglot-ensure))
;; configure javascript support
(use-package javascript-ts-mode
:init
(add-to-list 'auto-mode-alist '("\\.js\\'" . js-ts-mode))
:hook
(javascript-ts-mode . eglot-ensure))
;; configure react support
(use-package tsx-ts-mode
:init
(add-to-list 'auto-mode-alist '("\\.[jt]sx\\'" . tsx-ts-mode))
:hook
(tsx-ts-mode . eglot-ensure))
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Java and other JVM languages
2024-07-30 14:40:34 +02:00
#+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 )
2024-08-11 11:36:44 +02:00
(report-time-since-load "jdtls installed at %s" jdtls-prog)))
2024-07-30 14:40:34 +02:00
(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))))))
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Lisp and Scheme Support
2024-12-02 14:43:46 +01:00
**** Aggressive Indent for lisp modes
#+BEGIN_SRC emacs-lisp
(use-package aggressive-indent
:ensure t
:hook ((lisp-mode-hook scheme-mode-hook clojure-mode-hook)))
#+END_SRC
2024-08-02 13:23:26 +02:00
**** Enable ParEdit in lispy modes
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-02 14:43:46 +01:00
;; Lisp support
(use-package package-lint-flymake
:ensure t) ;; needed before activating lisp-interaction-mode-hook
(use-package paredit
:ensure nil
:after package-lint-flymake
:commands (enable-paredit-mode)
:init
2024-07-30 14:40:34 +02:00
(dolist (mode '(emacs-lisp-mode-hook
2024-12-02 14:43:46 +01:00
lisp-interaction-mode-hook
lisp-mode-hook
scheme-mode-hook))
(add-hook mode #'enable-paredit-mode)))
2024-12-03 09:10:59 +01:00
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-07-30 20:11:52 +02:00
2024-11-18 11:26:22 +01:00
**** Rainbow Parentheses
#+BEGIN_SRC emacs-lisp
(use-package rainbow-delimiters
:ensure t
:commands (rainbow-delimiters-mode)
:hook
(prog-mode . rainbow-delimiters-mode))
#+END_SRC
#+RESULTS :
: [nil 26418 38138 672360 nil elpaca-process-queues nil nil 82000 nil]
2024-12-02 14:43:46 +01:00
**** Configure Sly for Common Lisp
#+BEGIN_SRC emacs-lisp
(use-package sly
:ensure t
:config
(require 'sly-autoloads)
:hook (lisp-mode-hook . #'sly-editing-mode))
(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)
#+END_SRC
#+RESULTS :
: [nil 26432 28005 611924 nil elpaca-process-queues nil nil 196000 nil]
2024-12-03 09:12:46 +01:00
**** Configure CLHS documentation
Common Lisp Hyperspec is distributed as a package for
#+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].
("clhs")
#+END_SRC
There is a wizard to help installing it in Emacs:
#+BEGIN_SRC shell :tangle no
AOC/2024/02> (clhs:print-emacs-setup-form)
[ Quicklisp directory: "/home/pti/quicklisp/ " (exists)
If the above location is not correct, do:
(setf clhs:*quicklisp-directory* "/path/to/quicklisp/ ") ]
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.
Please run (clhs:install-clhs-use-local) in the (Common Lisp) REPL.
This will install clhs-use-local.el in your quicklisp directory.
Then, run (clhs:print-emacs-setup-form) again for instructions for step 2.
; No values
AOC/2024/02> (clhs:install-clhs-use-local)
T
AOC/2024/02> (clhs:print-emacs-setup-form)
[ Quicklisp directory: "/home/pti/quicklisp/ " (exists)
If the above location is not correct, do:
(setf clhs:*quicklisp-directory* "/path/to/quicklisp/ ") ]
(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.)
Make Emacs evaluate this form to browse the CLHS locally:
(load "/home/pti/quicklisp/clhs-use-local.el" t)
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:///".
Put the form in your ~/.emacs to persist the change for future sessions.
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)
; No values
AOC/2024/02>
#+END_SRC
#+BEGIN_SRC emacs-lisp
(load (expand-file-name "~/quicklisp/clhs-use-local.el") t)
#+END_SRC
#+RESULTS :
: t
2024-07-30 14:40:34 +02:00
2024-08-02 13:23:26 +02:00
**** Enable Geiser Mode in Scheme Mode
2024-07-30 14:40:34 +02:00
Configure Geiser and Scheme
- map .scm file by default to Guile
#+BEGIN_SRC emacs-lisp
(use-package geiser
:ensure nil
:defer t
:commands (geiser-mode)
:config
(setq geiser-implementation-alist
,(add-to-list 'geiser-implementation-alist '((regexp "\\.scm\\'") guile))))
(use-package scheme-mode
:ensure nil
:defer t
:commands (scheme-mode)
:hook (scheme-mode . geiser-mode))
#+END_SRC
#+RESULTS :
2024-12-03 09:10:59 +01:00
| | geiser-mode | enable-paredit-mode | aggressive-indent-mode | geiser-mode--maybe-activate |
2024-07-30 14:40:34 +02:00
2024-12-02 14:43:46 +01:00
**** Enable Cider for Clojure mode
#+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))
#+END_SRC
#+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
#+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
2024-11-18 11:26:22 +01:00
**** Allow saving of an SBCL images
When trying to call `(save-lisp-and-die #p"somefile")` , sbcl will
throw an error that it cannot comply when multiple threads are active.
For each project using this you need to define some helper function to
stop the repl threads before saving the image like the following:
#+BEGIN_SRC emacs-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))
#+END_SRC
This function has to be called in the *sly-inferior-lisp*
#+BEGIN_SRC emacs-lisp :tangle no
;; in *sly-inferior-lisp* buffer
(sbcl-save-sly-and-die)
#+END_SRC
2024-08-02 13:23:26 +02:00
*** Terraform Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
;; configure terraform support
(use-package terraform-mode
:ensure t
:config
(setq
terraform-indent-level 2
2024-12-03 09:10:59 +01:00
terraform-format-on-save t))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-09 10:32:41 +02:00
Map the keymap consistently to the eglot mappings.
2024-07-30 14:40:34 +02:00
2024-10-26 21:10:54 +02:00
*** Zig Support
#+BEGIN_SRC emacs-lisp
;; configure zig support
(use-package zig-mode
:ensure t
:hook
(zig-mode . eglot-ensure))
#+END_SRC
2024-08-02 13:23:26 +02:00
** Debugger Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-08-15 13:19:57 +02:00
(report-time-since-load "Programming - Debugger Support")
#+END_SRC
#+BEGIN_SRC emacs-lisp
;; install DAP servers
(setq pti-vscode-js-debug-dir (file-name-concat user-emacs-directory "dape/vscode-js-debug"))
(defun pti-install-vscode-js-debug ()
"Run installation procedure to install JS debugging support."
(interactive)
(mkdir pti-vscode-js-debug-dir t)
(let ((default-directory (expand-file-name pti-vscode-js-debug-dir)))
(vc-git-clone "https://github.com/microsoft/vscode-js-debug.git" "." nil)
(report-time-since-load "git repository created")
(call-process "npm" nil "*pti-install* " t "install")
(report-time-since-load "npm dependencies installed")
(call-process "npx" nil "*pti-install* " t "gulp" "dapDebugServer")
(report-time-since-load "vscode-js-debug installed")))
(setq pti-codelldb-dir (file-name-concat user-emacs-directory "dape/codelldb"))
(defun pti-install-codelldb ()
"Install Vadimcn.Vscode-Lldb DAP server for C/C++/RUST."
(interactive)
(let* ((default-directory pti-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 "*pti-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)
;; By default dape uses gdb keybinding prefix
2024-12-03 09:10:59 +01:00
(setq dape-key-prefix "<space >d")
2024-08-15 13:19:57 +02:00
;; Kill compile buffer on build success
;; (add-hook 'dape-compile-compile-hooks 'kill-buffer)
;; Projectile users
;; (setq dape-cwd-fn 'projectile-project-root))
(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 pti-vscode-js-debug-dir "dist")
command-args ("src/dapDebugServer.js" "8123")
:type "pwa-node"
:request "launch"
:cwd dape-cwd-fn
:program dape-find-file-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-cwd-fn
host "127.0.0.1"
port 55878
:type "debug" ;; needed to set the adapterID correctly as a string type
:request "launch"
:cwd dape-cwd-fn
:program dape-cwd-fn))
(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
pti-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-fn
:program dape-find-file))
(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-fn
:program dape-find-file-buffer-default))
))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-08-02 13:23:26 +02:00
** Copilot Support
2024-08-09 10:32:41 +02:00
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Copilot Support")
#+END_SRC
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-07-30 16:45:22 +02:00
(use-package copilot
:ensure (:host github :repo "zerolfx/copilot.el"
:branch "main"
:files ("dist" "*.el"))
:bind
2024-12-03 09:10:59 +01:00
("C-y" . copilot-accept-completion)
2024-07-30 16:45:22 +02:00
: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))
:hook
(prog-mode . copilot-mode)
(org-mode . copilot-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-07-30 16:45:22 +02:00
: [nil 26280 62042 380168 nil elpaca-process-queues nil nil 930000 nil]
2024-07-30 14:40:34 +02:00
2024-08-02 13:23:26 +02:00
*** TODO move scheme configuration to the scheme section
2024-07-30 14:40:34 +02:00
or leave it here but move it to config, whatever makes most sense at
the moment.
2024-08-09 10:32:41 +02:00
** Gitlab Support
2024-07-30 14:40:34 +02:00
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Gitlab Support")
#+END_SRC
2024-08-09 10:32:41 +02:00
#+BEGIN_SRC emacs-lisp
(use-package gitlab-ci-mode
2024-08-11 11:36:44 +02:00
:ensure (:host gitlab :repo "ptillemans/gitlab-ci-mode" :branch "fixes_2024")
2024-08-09 10:32:41 +02:00
:mode "\\.gitlab-ci\\.yml\\'"
:custom
(gitlab-ci-url "https://gitlab.melexis.com")
(gitlab-ci-api-token (auth-source-pass-get 'secret "snamellit/gitlab/token")))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-09 10:32:41 +02:00
#+RESULTS :
: [nil 26292 38256 549743 nil elpaca-process-queues nil nil 11000 nil]
2024-07-30 14:40:34 +02: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 09:10:59 +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 09:10:59 +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 09:10:59 +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)
"@"
(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
(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 (o2e-opml-to-elfeed--update-o2e-efleed-feeds)
)
#+END_SRC
#+RESULTS :
: [nil 26289 17361 350243 nil elpaca-process-queues nil nil 817000 nil]
2024-12-03 09:10:59 +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 09:10:59 +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
:ensure t
:config (setq 0x0-use-curl t))
#+END_SRC
#+RESULTS :
: [nil 26279 35497 183387 nil elpaca-process-queues nil nil 963000 nil]
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.
* 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
2024-08-16 00:43:50 +02:00
** NEXT Add support for zola blogposts writing in org-mode
: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
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: