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 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
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-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.
(if emacs-build-time
(setq elpaca-core-date (format-time-string "%Y%m%d" emacs-build-time)))
(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))
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.
#+BEGIN_SRC emacs-lisp :tangle "early-init.el"
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-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 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
2024-12-03 13:14:31 +01:00
*** Load the General
Needs to load early so the ~:general~ keyword is available for ~use-package~ .
#+BEGIN_SRC emacs-lisp
(use-package general :ensure t :demand t)
#+END_SRC
#+RESULTS :
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 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)
(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 :
2025-01-13 07:24:33 +01:00
: v1.2025.0
2024-08-11 11:36:44 +02:00
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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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-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 13:14:31 +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 13:14:31 +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 13:14:31 +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
2024-12-19 17:05:14 +01:00
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-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
(use-package undo-tree
2024-12-19 17:05:14 +01:00
:defer t
2024-12-02 14:43:46 +01:00
:ensure t
2024-12-19 17:05:14 +01:00
:custom
(undo-tree-history-directory-alist
`(("." . ,(expand-file-name (file-name-as-directory "undo-tree-hist")
user-emacs-directory))))
2024-12-02 14:43:46 +01:00
:init
2024-12-19 17:05:14 +01:00
(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-12-02 14:43:46 +01:00
#+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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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 13:14:31 +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]
2024-12-03 13:14:31 +01:00
** Evil Vim Keybindings
#+BEGIN_SRC emacs-lisp
;; load evil
(use-package evil
:ensure t ;; install the evil package if not installed
:init ;; tweak evil's configuration before loading it
(setq evil-search-module 'evil-search)
(setq evil-ex-complete-emacs-commands nil)
(setq evil-vsplit-window-right t)
(setq evil-split-window-below t)
(setq evil-shift-round nil)
(setq evil-want-C-u-scroll nil)
:config
(evil-mode)
;; set leader keys
(evil-set-leader nil (kbd "C-SPC"))
(evil-set-leader 'normal (kbd "SPC"))
(evil-set-leader 'normal "," t) ;; set localleader
;; make vc commands available via leader key
(evil-define-key 'normal 'global
(kbd "<leader >v") vc-prefix-map)
(keymap-global-set "C-c v" vc-prefix-map)
;; make project commands available via leader key
(evil-define-key 'normal 'global
(kbd "<leader >p") project-prefix-map)
(keymap-global-set "C-c p" project-prefix-map)
(evil-define-key 'normal 'global
(kbd "<leader >ff") #'find-file
(kbd "<leader >fo") #'recentf
(kbd "<leader >fr") #'revert-buffer
(kbd "<leader >fd") #'diff-buffer-with-file)
(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)
)
#+END_SRC
** Load Evil Collection for comprehensive evil support
#+BEGIN_SRC emacs-lisp
(use-package evil-collection
:ensure t
:after evil
:init
(evil-collection-init))
#+END_SRC
** Harpoon configuration
#+BEGIN_SRC emacs-lisp :tangle no
(use-package harpoon
:ensure t
:init
(setq pti-harpoon-map (make-sparse-keymap))
(keymap-set pti-harpoon-map (kbd "h") 'harpoon-toggle-quick-menu)
(keymap-set pti-harpoon-map (kbd "a") 'harpoon-add-file)
(keymap-set pti-harpoon-map (kbd "f") 'harpoon-toggle-file)
(keymap-set pti-harpoon-map (kbd "j") 'harpoon-go-to-1)
(keymap-set pti-harpoon-map (kbd "k") 'harpoon-go-to-2)
(keymap-set pti-harpoon-map (kbd "l") 'harpoon-go-to-3)
(keymap-set pti-harpoon-map (kbd ";") 'harpoon-go-to-4)
(keymap-set pti-harpoon-map (kbd "h") 'harpoon-toggle-quick-menu)
:bind
(("<leader >h" . 'pti-harpoon-map)
("C-c h" . 'pti-harpoon-map)))
#+END_SRC
#+RESULTS :
: [nil 26284 54919 318035 nil elpaca-process-queues nil nil 339000 nil]
2024-12-02 14:43:46 +01:00
** 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 13:14:31 +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)
2024-12-18 11:42:53 +01:00
(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)
2024-07-30 14:40:34 +02:00
(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-12-30 13:40:04 +01:00
*** Add Snippet Collection
#+BEGIN_SRC emacs-lisp
;; add yasnippet collection
(use-package yasnippet-snippets
:ensure t)
#+END_SRC
#+RESULTS :
: [nil 26481 25510 926111 nil elpaca-process-queues nil nil 690000 nil]
2024-08-02 13:23:26 +02:00
** Enable LLM access with Ellama
2024-12-03 13:14:31 +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 13:14:31 +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
2025-01-13 07:24:33 +01:00
(use-package llm :ensure t)
2024-11-18 11:26:22 +01:00
#+END_SRC
2025-01-08 11:57:26 +01:00
#+RESULTS :
2025-01-13 07:24:33 +01:00
: [nil 26497 15516 337719 nil elpaca-process-queues nil nil 495000 nil]
2024-11-18 11:26:22 +01:00
2025-01-08 11:57:26 +01:00
#+RESULTS :g
2024-11-18 11:26:22 +01:00
2025-01-13 07:24:33 +01:00
#+BEGIN_SRC emacs-lisp
(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 (auth-source-pass-get 'secret "snamellit/openai-api-key")
:chat-model "gpt-4o"))))
))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-11-18 11:26:22 +01:00
#+RESULTS :
2025-01-13 07:24:33 +01:00
: [nil 26497 19957 511863 nil elpaca-process-queues nil nil 742000 nil]
2024-11-18 11:26:22 +01:00
2024-07-30 14:40:34 +02:00
2025-01-13 07:24:33 +01:00
It seems the *gpt-4o* model provides better responses.
2025-01-08 11:57:26 +01:00
2025-01-13 07:24:33 +01:00
I should investigate local models more.
2025-01-08 11:57:26 +01:00
2025-01-13 07:24:33 +01:00
*** Use Gemini with ellama
2025-01-08 11:57:26 +01:00
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
2025-01-13 07:24:33 +01:00
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.
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
2024-12-30 13:50:39 +01:00
#+BEGIN_SRC emacs-lisp
2024-10-23 11:52:07 +02:00
(use-package embark
:ensure t
:bind
2024-12-30 13:50:39 +01:00
(("C-." . embark-act)
2024-10-23 11:52:07 +02:00
("C-;" . embark-dwim)
("C-h B" . embark-bindings))
:config
(setq prefix-help-command #'embark-prefix-help-command))
#+END_SRC
#+RESULTS :
2024-12-30 13:50:39 +01:00
: [nil 26482 38660 809617 nil elpaca-process-queues nil nil 672000 nil]
2024-10-23 11:52:07 +02:00
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 13:14:31 +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-12-10 09:59:35 +01:00
** Enable Avy jumping
Avy mode replace ace-jump mode with a lot of functionality hidden
see [[https://karthinks.com/software/avy-can-do-anything/ ][Avy can Do Anything ]] article by the author on the design philosophy
behind it.
#+BEGIN_SRC emacs-lisp
(use-package avy
:ensure t
2024-12-11 11:50:04 +01:00
: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)
:general
(:states 'normal
"<leader > j j" #'avy-goto-char-timer
"<leader > j w" #'avy-goto-word-0))
2024-12-10 09:59:35 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
2024-12-11 11:56:24 +01:00
: [nil 26457 28589 796769 nil elpaca-process-queues nil nil 977000 nil]
2024-12-11 11:50:04 +01:00
2024-12-10 09:59:35 +01:00
Avy is supported by evil and setup in the *evil-integration* package.
#+RESULTS :
2024-12-11 11:50:04 +01:00
* Programming
2024-08-11 11:36:44 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(report-time-since-load "Programming")
2024-08-11 11:36:44 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
** Programming Support Infrastructure
#+BEGIN_SRC emacs-lisp
(report-time-since-load "Programming - Infrastructure")
#+END_SRC
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
*** Integration with LSP Servers for language support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; configure eglot-mode
(use-package eglot
:config
(evil-define-key 'normal eglot-mode-map
(kbd "<leader >c a") 'eglot-code-actions
(kbd "<leader >c d") 'eglot-find-declaration
(kbd "<leader >c i") 'eglot-find-implementation
(kbd "<leader >c k") 'eglot-find-typeDefinition
(kbd "<leader >c f") 'eglot-format
(kbd "<leader >c F") 'eglot-format-buffer
(kbd "<leader >c r") 'eglot-rename
(kbd "<leader >c Q") 'eglot-shutdown
(kbd "<leader >c q") 'eglot-reconnect
(kbd "<leader >c n") 'flymake-goto-next-error
(kbd "<leader >c p") 'flymake-goto-prev-error
(kbd "]d") #'flymake-goto-next-error
(kbd "[d") #'flymake-goto-prev-error
2024-07-30 14:40:34 +02:00
)
2024-12-11 11:50:04 +01:00
;; Shutdown server when last managed buffer is killed
(setq eglot-autoshutdown t)
2024-08-04 01:37:17 +02:00
2024-12-11 11:50:04 +01:00
;; from https://www.reddit.com/r/emacs/comments/ye18nd/setting_up_eglot_for_python/
(add-to-list 'eglot-server-programs '(python-mode . ("pylsp")))
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
(setq-default eglot-workspace-configuration
'((:pylsp . (:configurationSources ["flake8"]
:plugins (:pycodestyle (:enabled nil)
:mccabe (:enabled nil)
:flake8 (:enabled t))))))
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01: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))
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
*** Flymake Support
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(defun pti-flymake-evil-keybindings ()
"Map flymake error navigation to easier key sequences."
(evil-define-key 'normal flymake-mode-map
(kbd "]d") #'flymake-goto-next-error
(kbd "[d") #'flymake-goto-prev-error))
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
(add-hook 'flymake-mode-hook #'pti-flymake-evil-keybindings)
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
*** Use Treesitter parser support
#+BEGIN_SRC emacs-lisp
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
;; 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-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
:hook
((prog . treesit-inspect-mode)))
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
(use-package treesit-auto
2024-07-30 14:40:34 +02:00
:ensure t
2024-12-11 11:50:04 +01:00
: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 nu
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
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
#+RESULTS :
: [nil 26284 45426 709595 nil elpaca-process-queues nil nil 734000 nil]
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01: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.
2024-08-05 10:32:04 +02:00
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
***** 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
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))
2024-08-05 10:32:04 +02:00
#+END_SRC
#+RESULTS :
2024-12-11 11:50:04 +01:00
| bash | cmake | css | elisp | go | gomod | haskell | html | java | javascript | json | lua | make | markdown | ocaml | python | toml | tsx | typescript | yaml |
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01: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.
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01: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-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
This will download the dynamic library to _user-emacs-directory_ /elpa/tree-sitter-langs/bin
2024-08-05 10:44:37 +02:00
2024-12-11 11:50:04 +01:00
However they'll have the wrong filename and are not in the path where treesitter looks in.
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01: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
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
and they will now be installed.
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
Normally that should work for other OSes too, but there is no real need for it.
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
see also [[https://www.masteringemacs.org/article/how-to-get-started-tree-sitter ][How to get started with tree sitter ]] .
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
*** Create a folder to store downloaded LSP servers
2024-08-05 10:32:04 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; LSP support
(let ((lsp_dir (file-name-concat user-emacs-directory "lsp")))
(if (not (file-exists-p lsp_dir))
(mkdir lsp_dir t)))
2024-08-05 10:32:04 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
*** Electric Return
2024-08-05 10:32:04 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; enable electric return to automatically indent code
(defvar electrify-return-match
"[\]}\)\"]"
"The text after the cursor to do an \"electric\" return.")
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
(defun electrify-return-if-match (arg)
"Insert a newline, and indent it when needed.
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
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.
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
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)))
2024-08-05 10:32:04 +02:00
2024-12-11 11:50:04 +01:00
;; Using local-set-key in a mode-hook is a better idea.
;(global-set-key (kbd "RET") 'electrify-return-if-match)
#+END_SRC
2024-08-05 10:32:04 +02:00
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
**** TODO Evaluate if Electric Return is still useful
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
** Configure Selected Languages
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(report-time-since-load "Programming - Selected Languages")
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
*** Rust Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; 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-07-30 14:40:34 +02:00
)
2024-12-11 11:50:04 +01:00
(use-package rustic
:ensure t
:init
(setq rustic-lsp-client 'eglot))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
*** OCaml Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; 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))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
*** Go Support
#+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
(go-ts . eglot-ensure))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
*** Javascript, Typescript, TSC, etc...
#+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))
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
;; 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))
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
;; 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))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01: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-08-16 00:43:50 +02:00
2024-12-11 11:50:04 +01:00
#+END_SRC
*** Lisp and Scheme Support
**** Aggressive Indent for lisp modes
2024-08-16 00:43:50 +02:00
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(use-package aggressive-indent
:ensure t
:hook ((lisp-mode-hook scheme-mode-hook clojure-mode-hook)))
#+END_SRC
**** Enable ParEdit in lispy modes
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-19 17:05:14 +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
(dolist (mode '(emacs-lisp-mode-hook
lisp-interaction-mode-hook
lisp-mode-hook
scheme-mode-hook))
(add-hook mode #'enable-paredit-mode)))
(use-package enhanced-evil-paredit
:ensure (enhanced-evil-paredit :host github :repo "jamescherti/enhanced-evil-paredit.el" :wait t)
:config
(add-hook 'paredit-mode-hook #'enhanced-evil-paredit-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-12-19 17:05:14 +01:00
***** TODO Fix paredit bug related to obsolete macro
2024-12-11 11:50:04 +01:00
evil-paredit relies on an obsolete (and no longer available method)
`evil-called-interactively-p`. So I define it here till evil-paredit
has implemented the new method.
2024-12-03 13:14:31 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(defmacro evil-called-interactively-p ()
"Wrapper for `called-interactively-p'.
In older versions of Emacs, `called-interactively-p' takes
no arguments. In Emacs 23.2 and newer, it takes one argument."
(called-interactively-p 'any))
(make-obsolete 'evil-called-interactively-p
"please use (called-interactively-p 'any) instead."
"Git commit 222b791")
#+END_SRC
**** Rainbow Parentheses
#+BEGIN_SRC emacs-lisp
(use-package rainbow-delimiters
2024-12-03 13:14:31 +01:00
:ensure t
2024-12-11 11:50:04 +01:00
:commands (rainbow-delimiters-mode)
2024-12-03 13:14:31 +01:00
:hook
2024-12-11 11:50:04 +01:00
(prog-mode . rainbow-delimiters-mode))
2024-12-03 13:14:31 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
: [nil 26418 38138 672360 nil elpaca-process-queues nil nil 82000 nil]
**** Configure Sly for Common Lisp
2024-12-03 13:14:31 +01:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
(use-package sly
:ensure t
:config
(require 'sly-autoloads)
:hook (lisp-mode-hook . #'sly-editing-mode))
2024-12-03 13:14:31 +01:00
2024-12-11 11:50:04 +01:00
(use-package sly-quicklisp
:ensure t
:after sly)
2024-12-03 13:14:31 +01:00
2024-12-11 11:50:04 +01:00
(use-package sly-repl-ansi-color
:ensure t
:after sly)
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
(use-package sly-asdf
:ensure t
:after sly)
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-02 11:39:46 +02:00
#+RESULTS :
2024-12-11 11:50:04 +01:00
: [nil 26432 28005 611924 nil elpaca-process-queues nil nil 196000 nil]
**** Configure CLHS documentation
2024-08-02 11:39:46 +02:00
2024-12-11 11:50:04 +01:00
Common Lisp Hyperspec is distributed as a package for
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01: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].
("clhs")
2024-08-09 10:32:41 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
There is a wizard to help installing it in Emacs:
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC shell :tangle no
AOC/2024/02> (clhs:print-emacs-setup-form)
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
[ Quicklisp directory: "/home/pti/quicklisp/ " (exists)
If the above location is not correct, do:
(setf clhs:*quicklisp-directory* "/path/to/quicklisp/ ") ]
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
Then, run (clhs:print-emacs-setup-form) again for instructions for step 2.
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
; No values
AOC/2024/02> (clhs:install-clhs-use-local)
T
AOC/2024/02> (clhs:print-emacs-setup-form)
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
[ Quicklisp directory: "/home/pti/quicklisp/ " (exists)
If the above location is not correct, do:
(setf clhs:*quicklisp-directory* "/path/to/quicklisp/ ") ]
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
Make Emacs evaluate this form to browse the CLHS locally:
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
(load "/home/pti/quicklisp/clhs-use-local.el" t)
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
Put the form in your ~/.emacs to persist the change for future sessions.
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
; No values
AOC/2024/02>
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
(load (expand-file-name "~/quicklisp/clhs-use-local.el") t)
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-02 14:49:05 +02:00
#+RESULTS :
2024-12-11 11:50:04 +01:00
: t
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
**** Enable Geiser Mode in Scheme Mode
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
Configure Geiser and Scheme
- map .scm file by default to Guile
#+BEGIN_SRC emacs-lisp
(use-package geiser
2024-12-30 13:40:04 +01:00
:ensure t
2024-12-11 11:50:04 +01:00
:commands (geiser-mode)
:config
2024-12-30 13:40:04 +01:00
(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))
2024-12-11 11:50:04 +01:00
(use-package scheme-mode
2024-12-30 13:40:04 +01:00
:ensure nil
2024-12-11 11:50:04 +01:00
:commands (scheme-mode)
:hook (scheme-mode . geiser-mode))
2024-08-09 10:32:41 +02:00
#+END_SRC
#+RESULTS :
2024-12-30 13:40:04 +01:00
| geiser-mode | enable-paredit-mode | geiser-mode--maybe-activate |
2024-08-09 10:32:41 +02:00
2024-12-30 15:49:44 +01:00
**** GUIX support
[[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.
#+BEGIN_SRC emacs-lisp
(use-package guix
:ensure t
:after geiser)
#+END_SRC
I find it a bit a confusing module.
It provides a minor-mode
2024-12-11 11:50:04 +01:00
**** Enable Cider for Clojure mode
2024-08-09 10:32:41 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(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))
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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
2024-08-09 10:32:41 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(use-package clj-refactor
:defer t
:ensure t
:diminish clj-refactor-mode
:config (cljr-add-keybindings-with-prefix "C-c C-m"))
2024-08-09 10:32:41 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
**** Allow saving of an SBCL images
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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.
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01: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:
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
#+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
2024-08-02 14:49:05 +02:00
2024-12-11 11:50:04 +01:00
This function has to be called in the *sly-inferior-lisp*
2024-08-11 11:36:44 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp :tangle no
;; in *sly-inferior-lisp* buffer
(sbcl-save-sly-and-die)
2024-08-11 11:36:44 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
*** Terraform Support
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; configure terraform support
(use-package terraform-mode
:ensure t
2024-07-30 14:40:34 +02:00
:config
2024-12-11 11:50:04 +01:00
(setq
terraform-indent-level 2
terraform-format-on-save t)
(evil-define-key 'normal terraform-mode-map
(kbd "<leader >c k") #'terraform-open-doc
(kbd "<leader >c f") #'terraform-format
(kbd "<leader >c F") #'terraform-format-buffer
2024-12-03 13:14:31 +01:00
(kbd "<leader >c n") 'flymake-goto-next-error
(kbd "<leader >c p") 'flymake-goto-prev-error
(kbd "]d") #'flymake-goto-next-error
2024-12-11 11:50:04 +01:00
(kbd "[d") #'flymake-goto-prev-error))
#+END_SRC
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
Map the keymap consistently to the eglot mappings.
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
*** Zig Support
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp
;; configure zig support
(use-package zig-mode
:ensure t
2024-07-30 14:40:34 +02:00
:hook
2024-12-02 14:43:46 +01:00
(zig-mode . eglot-ensure))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
** Debugger Support
2024-12-03 13:14:31 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(report-time-since-load "Programming - Debugger Support")
2024-12-03 13:14:31 +01:00
#+END_SRC
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; 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)))
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
(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")))
2024-08-11 11:36:44 +02:00
2024-12-11 11:50:04 +01:00
(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")
))
2024-08-04 01:37:17 +02:00
2024-12-11 11:50:04 +01:00
;; configure dape (dap-mode)
(use-package dape
:ensure (dape :host github :repo "svaante/dape" :wait t)
2024-07-30 14:40:34 +02:00
:defer 5
2024-12-11 11:50:04 +01:00
:config (progn
;; Use n for next etc. in REPL
;; (setq dape-repl-use-shorthand t)
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
;; By default dape uses gdb keybinding prefix
;; (setq dape-key-prefix "<space >d")
(evil-define-key 'normal 'global (kbd "<leader >d") dape-global-map)
2024-08-02 13:23:26 +02:00
2024-12-11 11:50:04 +01:00
;; Kill compile buffer on build success
;; (add-hook 'dape-compile-compile-hooks 'kill-buffer)
2024-08-02 13:23:26 +02:00
2024-12-11 11:50:04 +01:00
;; 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-08-02 13:23:26 +02:00
2024-12-11 11:50:04 +01:00
))
2024-08-02 13:23:26 +02:00
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
** Copilot Support
2024-08-09 10:32:41 +02:00
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(report-time-since-load "Programming - Copilot Support")
2024-08-15 13:19:57 +02:00
#+END_SRC
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-18 11:42:53 +01:00
(use-package copilot
2025-01-13 07:24:33 +01:00
:ensure (copilot :host github :repo "zerolfx/copilot.el"
2024-12-18 11:42:53 +01:00
:branch "main"
:files ("dist" "*.el"))
:bind
(:map evil-insert-state-map
("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))
2024-12-30 15:49:44 +01:00
:custom
(copilot-indent-offset-warning-disabled t "Disable indent offset warning" )
2024-12-18 11:42:53 +01:00
:hook
(prog-mode . copilot-mode)
(org-mode . copilot-mode))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
2025-01-13 07:24:33 +01:00
: [nil 26500 6758 925534 nil elpaca-process-queues nil nil 360000 nil]
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
*** TODO move scheme configuration to the scheme section
or leave it here but move it to config, whatever makes most sense at
the moment.
2025-01-13 07:24:33 +01:00
2024-12-11 11:50:04 +01:00
** Gitlab Support
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(report-time-since-load "Programming - Gitlab Support")
2024-12-02 14:43:46 +01:00
#+END_SRC
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01: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 "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
#+RESULTS :
2024-12-11 11:50:04 +01:00
: [nil 26292 38256 549743 nil elpaca-process-queues nil nil 11000 nil]
2024-07-30 20:11:52 +02:00
2024-12-11 11:50:04 +01:00
** BoilerPlate Generator
2024-12-03 13:14:31 +01:00
2024-12-11 11:50:04 +01: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-12-03 13:14:31 +01:00
2024-12-11 11:50:04 +01:00
The *org-generate* package uses an org file to structure boilerplate
templates to be generated. By default it uses
2024-11-18 11:26:22 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(use-package org-generate
2024-11-18 11:26:22 +01:00
:ensure t
2024-12-11 11:50:04 +01:00
)
2024-11-18 11:26:22 +01:00
#+END_SRC
#+RESULTS :
2024-12-11 11:50:04 +01:00
: [nil 26455 5250 886750 nil elpaca-process-queues nil nil 641000 nil]
* Writing and Planning
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(report-time-since-load "Writing and Planning")
#+END_SRC
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
** Org Mode
*** Mixed Pitch Support by Default in Org
#+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)
)
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
(use-package org-bullets
:ensure t
:if (display-graphic-p)
:hook (org-mode . org-bullets-mode))
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
(use-package mixed-pitch
:ensure t
:if (display-graphic-p)
:hook
(org-mode . mixed-pitch-mode))
2024-12-02 14:43:46 +01:00
#+END_SRC
#+RESULTS :
2024-12-11 11:50:04 +01:00
: [nil 26279 36119 854408 nil elpaca-process-queues nil nil 376000 nil]
*** 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-12-03 09:12:46 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
: [nil 26432 31427 677147 nil elpaca-process-queues nil nil 738000 nil]
*** Org Babel Support
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 Mermaid Diagrams in Babel Blocks
#+BEGIN_SRC emacs-lisp
;; enable mermaid for org-babel
(use-package ob-mermaid
:ensure t
2025-01-13 07:24:33 +01:00
:demand t
:config
(message "configuring ob-mermaid")
(org-babel-do-load-languages
'org-babel-load-languages
(add-to-list 'org-babel-load-languages '(mermaid . t))))
2024-12-11 11:50:04 +01:00
#+END_SRC
2025-01-13 07:24:33 +01:00
#+RESULTS:
: [nil 26499 60213 709442 nil elpaca-process-queues nil nil 672000 nil]
2024-12-11 11:50:04 +01:00
Mermaid needs support of the mermaid-cli which is a node package. It
can be installed with
2024-12-03 09:12:46 +01:00
#+BEGIN_SRC shell :tangle no
2024-12-11 11:50:04 +01:00
npm install -g @mermaid-js/mermaid-cli
#+END_SRC
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
#+RESULTS :
| | | | | | |
| changed | 194 | packages | in | 6s | |
| | | | | | |
| 39 | packages | are | looking | for | funding |
| run | `npm | fund` | for | details | |
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
**** Support PlantUML Diagrams in Babel Blocks
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
Requires nothing special, other than *plantuml.jar* archive installed.
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01: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 `pti-download-latest-plantuml` is made
interactive to manually install the latest version if needed.
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp :lexical t
(defun pti-download-latest-plantuml ()
"Download the latest version of PlantUML.
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
This function is interactive to make it easy to upgrade to
the latest, current version with `M-x pti-download-latest-plantuml'."
(interactive)
(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)))
(let ((plantuml-jar (concat user-emacs-directory "plantuml.jar")))
(if (not (file-exists-p plantuml-jar))
(pti-download-latest-plantuml))
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
(setq org-plantuml-jar-path plantuml-jar))
#+END_SRC
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
#+RESULTS :
2025-01-13 07:24:33 +01:00
: ~/.config/emacs/plantuml.jar
2024-12-03 09:12:46 +01:00
2025-01-13 07:24:33 +01:00
**** Configure Babel Languages
#+BEGIN_SRC emacs-lisp :tangle no
;; configure babel languages
(use-package org-babel
:demand t
:custom
(org-babel-load-languages '((emacs-lisp . t)
(shell . t)
(python . t)
(latex . t)
(scheme . t)
(plantuml . t)
(dot . t)))
:config
(message "Configuring org-babel languages")
)
2024-12-11 11:50:04 +01:00
#+END_SRC
2024-12-03 09:12:46 +01:00
2024-12-18 11:42:53 +01:00
#+RESULTS :
2025-01-13 07:24:33 +01:00
: [nil 26499 54180 830807 nil elpaca-process-queues nil nil 413000 nil]
2024-12-18 11:42:53 +01:00
2024-12-11 11:50:04 +01:00
**** Temporary Patches for Org Babel
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
***** Fix Scheme Babel Bug
#+BEGIN_SRC emacs-lisp
;; 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
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
#+RESULTS :
: org-babel-scheme--table-or-string
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
**** TODO Move babel test file to emacs config folder
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
Alternatively I might add a sample after each configured block to keep
it in the same context. Hmmm.... sounds even better.
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01:00
*** Org Export
**** Org Export to Markdown
2024-12-03 09:12:46 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(use-package ox-md
:ensure nil
:after ox
)
2024-12-03 09:12:46 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
**** Org Latex Export
***** Syntax Highlighting requires Multiple Passes
#+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
***** Load Customer Latex Classes
#+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
***** 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}"))))
2024-12-03 09:12:46 +01:00
2024-12-11 11:50:04 +01: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
**** Blogging with Zola
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01: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
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(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"))
2025-01-13 07:24:33 +01:00
:after (ox-hugo)
2024-12-11 11:50:04 +01:00
:config
(require 'ox-hugo)
:general
("<leader > o z" 'ox-zola-export-wim-to-md))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-12-11 11:50:04 +01: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.]]
*** Org Capture Customization
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(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%?"))
;; 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)))
2024-12-02 14:43:46 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
: t
*** Evil Support for Org
Better keybinding for evil mode from [[https://github.com/Somelauw/evil-org-mode ][the evil-org github repo ]].
2024-12-02 14:43:46 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(use-package evil-org
2024-12-02 14:43:46 +01:00
:ensure t
2024-12-11 11:50:04 +01:00
:after org
:hook
(org-mode . evil-org-mode)
2024-12-02 14:43:46 +01:00
:config
2024-12-11 11:50:04 +01:00
(require 'evil-org-agenda)
(evil-org-agenda-set-keys))
2024-12-02 14:43:46 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
Here is a snapshot of the keybindings dd <2024-07-30 Tue >.
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
**** Quick overview
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
|----------------+---------------------------|
| key | explanation |
|----------------+---------------------------|
| gh, gj, gk, gl | navigate between elements |
| vae | select an element |
|----------------+---------------------------|
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
**** Headings and items
2024-12-02 14:43:46 +01:00
2024-12-11 11:50:04 +01:00
|--------------+------------------------|
| key | explanation |
|--------------+------------------------|
| M-ret | insert heading |
| <tab>, g TAB | fold / unfold headings |
| M-h or << | promote a heading |
| M-l or >> | demote a heading |
| M-k | move subtree up |
| M-j | move subtree down |
| M-S-h or <aR | promote a subtree |
| M-S-l or >aR | demote a subtree |
| vaR | select a subtree |
|--------------+------------------------|
2024-11-18 11:26:22 +01:00
2024-12-11 11:50:04 +01:00
**** Tables
2024-11-18 11:26:22 +01:00
2024-12-11 11:50:04 +01:00
|-----------+--------------------------------|
| key | explanation |
|-----------+--------------------------------|
| ( | previous table cell |
| ) | next table cell |
| { | beginning of table |
| } | end of table |
| M-h / M-l | move table column left / right |
| M-k / M-j | move table column up / down |
| vae | select table cell |
| vaE | select table row |
| var | select whole table |
|-----------+--------------------------------|
2024-11-18 11:26:22 +01:00
2024-12-11 11:50:04 +01:00
**** Agenda
2024-11-18 11:26:22 +01:00
2024-12-11 11:50:04 +01:00
|-------------------------+-------------------------+-----------------------------------------------------------------------------------|
| Evil key | Emacs key | explanation |
|-------------------------+-------------------------+-----------------------------------------------------------------------------------|
| gH | | Move cursor to the top of window |
| gM | | Move cursor to the middle of window |
| gL | | Move cursor to the bottom of window |
| <tab>, S-<return> | <tab> | go to the corresponding entry at point |
| g TAB | <tab> | go to the corresponding entry at point |
| <return> | <return> | go to the Org mode file which contains the item at point |
| M-<return> | L | Display Org file and center around the item |
| <space> | <space> | scroll up |
| <delete> or <backspace> | <delete> or <backspace> | scroll down |
| j, k | n, p | next, previous line |
| gj, gk, C-j, C-k | N, P | next, previous item |
| [, ] | b, f | previous, next week |
| J, K | -, +, S-down, S-up | down, up priority |
| H, L | S-left, S-right | modify date to earlier, later |
| t | t | cycle TODO keywords |
| M-j, M-k | M-down, M-up | drag line forward, backward |
| C-S-h, C-S-l | C-S-left, C-S-right | previous, next keyword |
| u | C-_, C-/ | undo |
| dd | C-k | delete item |
| da | a | ask and archive item |
| dA | $ | archive item |
| ct | : | set tags |
| ce | e | set effort |
| cT | ; | set timer |
| i | i | insert entry in diary |
| a | z | add note |
| A | A | append to agenda |
| C | k | capture |
| m | m | mark |
| * | * | toggle all marks |
| % | % | mark regexp |
| M | U | remove all marks |
| x | B | execute action on marks |
| gr | r | refresh agenda |
| gR | g | refresh all agendas |
| ZQ | x | exit agenda |
| ZZ | Q | quit agenda |
| gD | v | tweak display (deadlines, diary, follow/log-mode, entry text, grid, day/week/year |
| ZD | # | dim blocked tasks |
| sc, sr, se, st, s^ | <, =, _, /, ^ | filter by category, regexp, effort, tag, top headline |
| S | \vert | remove all filters |
| ss | ~ | filter/limit interactively |
| I | I | clock in |
| O | O | clock out |
| cg | J | jump to the currently clocked in task within the agenda |
| cc | X | cancel the current running clock |
| cr | R | toggle clocktable mode in an agenda buffer |
| . | . | go to today's date |
| gc | c | pop up calendar |
| gC | C | pop up date converter |
| p | > | pop up date selector |
| gh | H | pop up holiday calendar |
| gm | M | pop up phases of the moon |
| gs | S | pop up sunrise/sunset times |
| gt | T | pop up tag list |
| +, - | [, ] | manipulate the query by adding a search term with positive or negative selection |
|-------------------------+-------------------------+-----------------------------------------------------------------------------------|
2024-11-18 11:26:22 +01:00
2024-12-11 11:50:04 +01:00
*** Org GCal Support
#+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-11-18 11:26:22 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
*** Org Jira Integration
2024-11-18 11:26:22 +01:00
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-30 13:40:04 +01: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
'(
))
(make-directory "~/.org-jira" 'parents)
(setq jiralib-url (auth-source-pass-get "url" "customer/jira"))
(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")
2024-12-30 13:41:44 +01:00
(: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")
)
2024-12-30 13:40:04 +01:00
)
(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)))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
2024-12-30 13:40:04 +01:00
: [nil 26482 31576 432899 nil elpaca-process-queues nil nil 614000 nil]
2024-12-11 11:50:04 +01: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.
**** 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-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
@daviwil has a set of productivity tools which are very useful. I have
2024-10-26 21:10:54 +02:00
2024-12-11 11:50:04 +01:00
**** Find all tasks with a specific tag (or without)
2024-10-26 21:10:54 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("p" "Planning" tags-todo "+@planning")))
2024-08-15 13:19:57 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+RESULTS :
| p | Planning | tags-todo | +@planning |
2024-08-15 13:19:57 +02:00
2024-12-11 11:50:04 +01:00
We can remove tasks with a certain tag by adding `-@work` to the pattern.
2024-08-15 13:19:57 +02:00
2024-12-11 11:50:04 +01:00
**** Find all tasks with a specific tag (or without)
2024-08-15 13:19:57 +02:00
2024-12-11 11:50:04 +01:00
#+BEGIN_SRC emacs-lisp :tangle no
(setq org-agenda-custom-commands
'(("u" "Untagged Tasks" tags-todo "-{.*}")))
#+END_SRC
2024-08-15 13:19:57 +02:00
2024-12-11 11:50:04 +01:00
#+RESULTS :
| u | Untagged Tasks | tags-todo | -{.*} |
2024-08-15 13:19:57 +02:00
2024-12-11 11:50:04 +01:00
**** Combine multiple filters
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
We can add a list of queries
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
#+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
#+RESULTS :
2024-12-11 11:50:04 +01:00
| p | Planning | ((tags-todo +@planning) (tags-todo -{.*})) |
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
**** We can add settings to each filter
2024-08-09 10:32:41 +02:00
2024-12-11 11:50:04 +01:00
#+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")))))))
2024-08-15 13:19:57 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+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
2024-07-30 14:40:34 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(setq org-agenda-custom-commands
'(("i" "Inbox" ((todo ".*"
((org-agenda-files '("~/Nextcloud/org/inbox.org"))
(org-agenda-overriding-header "Unprocessed Inbox Items")))))))
2024-07-30 14:40:34 +02:00
#+END_SRC
#+RESULTS :
2024-12-11 11:50:04 +01:00
| i | Inbox | ((todo .* ((org-agenda-files '(~/Nextcloud/org/inbox.org)) (org-agenda-overriding-header Unprocessed Inbox Items)))) |
2024-07-30 14:40:34 +02:00
2024-12-11 11:50:04 +01:00
**** Daily Agenda
2024-07-30 14:40:34 +02:00
2024-08-15 13:19:57 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(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-08-15 13:19:57 +02:00
#+END_SRC
2024-12-11 11:50:04 +01:00
#+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
2024-08-09 10:32:41 +02:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
(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)))
))))
2024-07-30 14:40:34 +02:00
#+END_SRC
2024-08-09 10:32:41 +02:00
#+RESULTS :
2024-12-11 11:50:04 +01:00
| 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-12-09 18:21:17 +01:00
2025-01-13 07:24:33 +01:00
*** Org Configuration
#+BEGIN_SRC emacs-lisp
(use-package org
:ensure nil
:demand t
: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))
))
(org-babel-load-languages '((emacs-lisp . t)
(shell . t)
(python . t)
(latex . t)
(scheme . t)
(plantuml . t)
(dot . t)))
: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")
(org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
: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
2024-12-09 18:21:17 +01:00
2025-01-13 07:24:33 +01:00
#+RESULTS :
2024-12-11 11:50:04 +01:00
** Denote
2024-12-09 18:21:17 +01:00
#+BEGIN_SRC emacs-lisp
2024-12-11 11:50:04 +01:00
;; configure denote
(use-package denote
2024-12-09 18:21:17 +01:00
:ensure t
2024-12-11 11:50:04 +01:00
: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)))))
2024-12-09 18:21:17 +01:00
#+END_SRC
2024-12-11 11:50:04 +01:00
**** TODO explain what denote-dired-mode-in-directories does.
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)
"@"
(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 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
: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-12-03 13:14:31 +01:00
** TODO Decide about general keybindings.
The *general* package offers enhanced support for *evil* keybindings,
notably it integrates with *use-package* to define keybindings which
will load the package if not loaded yet.
It considerably streamlines managing evil bindings so it should offer
enough value but I just removed it, so it'll have to wait a bit.
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: