You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file is read by Emacs before anything else. It shouldn’t depend on any package or frame configurations. Used mostly for basic initializations.
;; Set some sane defaults
(setopt ring-bell-function 'ignore; visual bell
visible-bell t
frame-title-format '("%b")
use-dialog-box t
use-file-dialog nil
use-short-answers t; no more yes-or-no
x-stretch-cursor t
require-final-newline t
inhibit-splash-screen t
inhibit-startup-screen t
inhibit-x-resources t
inhibit-startup-echo-area-message user-login-name
inhibit-startup-buffer-menu t)
;; Indentation
(setopt standard-indent 2
tab-always-indent 'complete)
(setq-default tab-width 4)
(setq-default indent-tabs-mode nil)
;; I don't want some UI elements enabled, so let's disable them.
(when (display-graphic-p)
(tool-bar-mode-1)
(scroll-bar-mode-1)
(global-hl-line-mode-1))
(delete-selection-modet)
(global-auto-revert-mode1) ; reload files when changed
We don’t want Emacs performing too many GC runs on startup, to make it boot as fast as possible.
(setopt gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.5)
(defvarinkel/emacs--file-name-handler-alist file-name-handler-alist)
(defvarinkel/emacs--vc-handled-backends vc-handled-backends)
(setopt file-name-handler-alist nil
vc-handled-backends inkel/emacs--vc-handled-backends)
(defuninkel/emacs--startup-hook ()
"Restore defaults and report initialization time and GC collections."
(setopt gc-cons-threshold (*100010008)
gc-cons-percentage 0.1
file-name-handler-alist inkel/emacs--file-name-handler-alist
vc-handled-backends inkel/emacs--vc-handled-backends)
(message"Emacs ready in %.2fs with %d garbage collections."
(float-time (time-subtract after-init-time before-init-time))
gcs-done))
(add-hook'emacs-startup-hook#'inkel/emacs--startup-hook)
;; force GC run
(add-hook'after-init-hook#'garbage-collectt)
I don’t want my installed packages to be initialized automatically, as sometimes I install packages just to test them.
(setopt package-enable-at-startup nil)
The Go team released nice fonts which are the ones I’ve been using for a long time:
(use-package consult
:hook (completion-list-mode. consult-preview-at-point-mode)
:bind (("M-y". consult-yank-pop) ;; Better yank?;; M-g bindings in `goto-map'
("M-g g". consult-goto-line)
;; ("M-g M-g" . consult-goto-line)
("M-s M-b". consult-buffer)
("M-s M-f". consult-find)
("M-g o". consult-outline)
("M-g i". consult-imenu)
("M-g I". consult-imenu-multi)))
;; This is useful for navigating through xref history;; https://takeonrules.com/2024/06/08/adding-a-consult-function-for-visualizing-xref/
(defvarconsult--xref-historynil"History for the `consult-recent-xref' results.")
(defunconsult-recent-xref (&optionalmarkers)
"Jump to a marker in MARKERS list (defaults to `xref--history'.The command supports preview of the currently selected marker position.The symbol at point is added to the future history."
(interactive)
(consult--read
(consult--global-mark-candidates
(or markers (flatten-list xref--history)))
:prompt"Go to Xref: ":annotate (consult--line-prefix)
:category'consult-location:sortnil:require-matcht:lookup#'consult--lookup-location:history '(:input consult--xref-history)
:add-history (thing-at-point'symbol)
:state (consult--jump-state)))
Completion
Corfu is a great package enhancing in-buffer completion in an interactive way.
;; Glorious package to let you know what binding are available
(use-package which-key
:ensuret:defernil:diminish which-key-mode
:hook (after-init . which-key-mode))
;; Use crux for some useful things, like C-a moving to the first;; character of the line instead of the beggining of the line!.;; https://github.com/bbatsov/crux;; http://pragmaticemacs.com/emacs/open-files-with-the-system-default-application/;; http://pragmaticemacs.com/emacs/move-to-the-beginning-of-a-line-the-smart-way/
(use-package crux
:ensuret:bind (("C-c M-o". crux-open-with)
("C-k". crux-kill-and-join-forward)
("C-x 4 t". crux-transpose-windows)
("C-x D". crux-delete-file-and-buffer)
("C-x M-r". crux-rename-file-and-buffer)
("s-k". crux-kill-whole-line)
("C-a". crux-move-beginning-of-line)))
(global-set-key (kbd"s-n") #'flymake-goto-next-error)
(global-set-key (kbd"s-p") #'flymake-goto-prev-error)
(global-set-key (kbd"M-g f") #'flymake-show-buffer-diagnostics)
(use-package sideline-flymake
:hook (flymake-mode. sideline-mode)
:init
(setopt sideline-flymake-display-mode 'point) ; 'point to show errors only on point; 'line to show errors on the current line
(setopt sideline-backends-right '(sideline-flymake)))
One thing I do all the time in Go is browsing the documentation of a package in pkg.go.dev, so I made a helper to allow me to quickly browse to the package documentation of any of the imports in the current buffer:
(defuninkel/go-file-imports (filename)
"Return a list of the current imports in Go FILENAME. The returnes list is sorted by stdlib first and third-party then."
(cl-flet ((stdlib-p (pkg) (not (string-match-p"\\." pkg))))
(let ((imports (process-lines"go""list""-f""{{range .Imports}}{{println .}}{{end}}" filename)))
(seq-concatenate'list
(sort (seq-filter#'stdlib-p imports) #'string-lessp)
(sort (seq-remove#'stdlib-p imports) #'string-lessp)))))
(defuninkel/go-package-docs (&optionalpackage)
"Open up Go package PACKAGE documentation in pkg.go.dev."
(interactive (list (let ((packages (inkel/go-file-imports buffer-file-name))
(vertico-sort-function nil))
(completing-read"Browse pkg.go.dev documentation for: " packages))))
(browse-url (concat"https://pkg.go.dev/"package)))
In order to have project.el properly understand Go projects we need to define how to identify a Go project. This is done by traversing the current directory and its parents until it finds a go.mod file.
(defunproject-find-go-module (dir)
"Find DIR first parent directory defining a go.mod file."
(when-let* ((root (locate-dominating-file dir "go.mod")))
(cons'go-module root)))
(cl-defmethod project-root ((project (head go-module)))
"Return root directory of the current Go PROJECT."
(cdr project))
(add-hook'project-find-functions#'project-find-go-module)
Running tests is integral to development, and these helpers should make it a bit easier.
Because we are using Tree-sitter we have to use the go-ts-mode package. We also add some hooks to organize the imports and format the buffer every time we save.
(defuninkel/eglot--go-organize-imports-on-save ()
"Hook for organizing Go imports when saving buffer."
(call-interactively'eglot-code-action-organize-imports))
(defuninkel/eglot--go-format-buffer-on-save ()
"Hook for Go projects when saving buffer."
(add-hook'before-save-hook#'inkel/eglot--go-organize-imports-on-save)
(add-hook'before-save-hook#'eglot-format-buffer-10t))
(use-package go-ts-mode
:ensuret:custom (go-ts-mode-indent-offset tab-width)
:mode"\\.go":bind (:map go-ts-mode-map
;("C-c C-t" . inkel/go-test)
("C-c M-p". inkel/go-package-docs))
:hook ((go-ts-mode . eglot-ensure)
(go-ts-mode . inkel/eglot--go-format-buffer-on-save))
:config
(add-to-list'tree-sitter-major-mode-language-alist '(go-ts-mode . go))
(setq-default eglot-workspace-configuration
'((:gopls. ((staticcheck .t)
(matcher ."CaseSensitive")))))
(add-to-list'major-mode-remap-alist '(go-mode. go-ts-mode)))
(defuninkel/org--edit-options ()
"Enable truncate lines and word wrapping on Org files."
(toggle-truncate-linesnil)
(toggle-word-wrapt))
(use-packageorg:pinorg:ensuret:bind (("C-c a". org-agenda)
("C-c c". org-capture)
("C-c b". org-switchb)
("C-c l". org-store-link))
:custom
(org-directory (expand-file-name"~/org"))
(org-imenu-depth 7)
;; Do not indent lines according to node level.
(org-adapt-indentation nil)
;; Do not ask for confirmation when evaluating source blocks.
(org-babel-config-evaluate nil)
(org-confirm-babel-evaluate nil)
;; do not create a popup when editing a source block
(org-src-window-setup 'current-window)
(org-capture-templates '(("t""TODO" entry (file+headline org-default-nodes-file "Tasks")
"* TODO %?\n %i\n %a")
("j""Journal" entry (file+datetree "journal.org")
"* %?\nEntered on %U\n %^g%i")
("o""On-Call" item (file+datetree "on-call.org")
"")
))
;; Make org the default mode when starting Emacs
(initial-major-mode'org-mode)
(initial-scratch-message"#\n# Temporary buffer for notes\n#\n")
:config;; do not create a popup when editing a source block;;(setq org-src-window-setup 'current-window);; enable inserting structured templates easily
(add-to-list'org-modules'org-tempo)
(add-hook'org-mode-hook#'inkel/org--edit-options))
As part of my job I usually write commands that feed onto other commands but I’d like to see the intermediate results or having better options for parsing their output. Following Literate DevOps practices makes my life much easier and nicer. And for this, I need some some languages availabel in Babel.
I haven’t done any of this yet, but if I ever do (and I would like to), this is a neat package that will show which keys & commands got executed on the mode line:
In order to use project.el I need it to instruct how to identify the project, which should be simply a directory, but because I use Git worktrees extensively, it’s a good idea to tell project.el how to find them automatically:
(defunproject-find-dt (dir)
"Find DIR first parent directory with setup-context."
(when-let* ((root (locate-dominating-file dir "setup-context")))
(cons'gdt-root root)))
(cl-defmethod project-root ((project (head gdt-root)))
"Return root directory of the current deployment_tools PROJECT."
(cdr project))
(add-hook'project-find-functions#'project-find-dt)
AI
Yes, it’s time to accept that AI is not important. At work I’ve been trying Claude Code, so let’s start with it:
;; Claude Code IDE integration with Emacs
(add-to-list'vc-handled-backends'Git)
(use-package vterm)
(use-package claude-code-ide
:ensuret:vc (:url"https://github.com/manzaltu/claude-code-ide.el":rev:newest)
:bind ("C-c C-'". claude-code-ide-menu)
:config; Enable Emacs MCP tools - https://github.com/manzaltu/claude-code-ide.el#emacs-mcp-tools
(claude-code-ide-emacs-tools-setup))
(defuninkel/claude-find-skill ()
"Open a Claude skill directory from ~/.claude/skills/ using completion."
(interactive)
(let* ((skills-dir (expand-file-name"~/.claude/skills/"))
(skills (when (file-directory-p skills-dir)
(seq-filter
(lambda (f)
(file-directory-p (expand-file-name f skills-dir)))
(directory-files skills-dir nil"^[^.]"))))
(skill (completing-read"Claude skill: " skills nilt))
(skill-path (expand-file-name (concat skill "/SKILL.md") skills-dir)))
(find-file skill-path)))
(keymap-set global-map "C-c K"#'inkel/claude-find-skill)
I might also try the Pi coding agent, so let’s see how it integrates: