Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Emacs Configuration

This is my Emacs configuration I have been using since 2018. I am currently switching to a new configuration which is much more lightweight than this one.

Table of contents


  • Linux or Window Subsystem for Linux
  • Nix package manager for installing dependencies


This configuration depends on some external programs as well as Emacs Lisp packages built by Nix.

At present, a suggested installation procedure is to first install my home.nix and then run mr checkout at your home directory. In the future, it may support an alternative for trying out.


GPL v3.

Some libraries were originally written by other people, and they follow their respective licenses.


(when (version< emacs-version "27.1")
  (error "Use GNU Emacs version 27.1 or later"))

(let ((local-custom-file "~/local/emacs/custom.el"))
  (if (file-exists-p local-custom-file)
      (setq custom-file local-custom-file)
    (message "%s does not exist, so custom-file is not set"

(when custom-file
  (load custom-file nil :nomessage))

(unless (fboundp 'whitespace-cleanup-mode)
  (defun whitespace-cleanup-mode (&rest args)
    (when (require 'whitespace-cleanup-mode nil t)
      (apply #'whitespace-cleanup-mode args))))

(add-to-list 'exec-path (expand-file-name "~/.nix-profile/bin"))

(defconst akirak/to-be-run-as-exwm (member "--exwm" command-line-args))

(defun akirak/exwm-session-p ()

Configure straight.el

(load-file (expand-file-name "core/straight.el" user-emacs-directory))

Install use-package using straight.el

(straight-use-package 'use-package)

Use straight.el by default in use-package directives

(setq straight-use-package-by-default t)

Benchmarking the startup process

(use-package benchmark-init
  (after-init . benchmark-init/deactivate))

Use the latest Git version of Org mode

(require 'cl-lib)
(require 'subr-x)

Remove org-mode shipped with Emacs from load-path

(use-package org
  :straight (:type built-in)
  (require 'org-loaddefs))

Recipe overrides


(setq straight-x-pinned-packages
      '(("dracula-theme" . "11391ea531d40fb08c64313bbb86e4d29d7fe1c5")))

Load configuration files

(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
(require 'my/const/system)

TODO: Move to lisp/

(add-to-list 'load-path (expand-file-name "extras" user-emacs-directory))


Prevent a confirmation dialog when the org file is loaded. Don’t forget to revert this variable at the beginning of the Org file.

(setq-default enable-local-variables :all)
(load-file (expand-file-name "core/setup.el" user-emacs-directory))

Things to set up before using use-package

(akirak/require 'setup-gc)

(setq-default enable-local-variables :safe)

These packages are required in other use-package directives declared in this configuration.

(use-package el-patch
  (el-patch-enable-use-package-integration t))

Package-specific configuration files, including snippets, are kept in a separate repository, not in this repository.

(use-package no-littering
  (let* ((var-dir "~/local/emacs/var/"))
    (unless (file-directory-p var-dir)
      (make-directory var-dir t))
    (setq no-littering-var-directory var-dir)))

Use the executable path from the shell

(use-package exec-path-from-shell
  :disabled t
  :if (memq window-system '(mac ns x))

(use-package use-package-company
  ;; Originally written by Foltik, but I use my fork
  :straight (use-package-company :host github :repo "akirak/use-package-company"))

(use-package info
  :straight (:type built-in)
  (add-to-list 'Info-directory-list
               (expand-file-name "share/info"
                                  (string-remove-suffix "/" invocation-directory)))))


(use-package which-key

  (which-key-mode t)

  (defmacro akirak/which-key-add-stripped-prefix (prefix)
    "Add PREFIX as a stripped prefix to `which-key-replacement-alist'."
    `(add-to-list 'which-key-replacement-alist
                  (quote ((nil . ,prefix) .
                          (lambda (kb)
                            (cons (car kb)
                                  (string-remove-prefix ,prefix (cdr kb))))))))

  (akirak/which-key-add-stripped-prefix "akirak/")
  (akirak/which-key-add-stripped-prefix "helm-org-multi-wiki-create/"))

Use general.el to define keybindings. It has made several improvements over bind-key, including a built-in integration with which-key.

This also adds support for :general keyword in use-package directives.

(use-package general

  (general-create-definer akirak/bind-search :prefix "M-s")
  (general-create-definer akirak/bind-jump :prefix "M-g")
  (general-create-definer akirak/bind-register :prefix "C-x r")

  (general-create-definer akirak/bind-help :prefix "<f1>")
  (general-create-definer akirak/bind-file-extra :prefix "<f6>")
  ;; <f7> is currently free
  (general-create-definer akirak/bind-f8 :prefix "<f8>")
  ;; <f9> is reserved for recompile
  (general-create-definer akirak/bind-admin :prefix "<f12>"
    :prefix-map 'akirak/admin-map)

  ;; ~C-c~ is reserved for the user.
  ;; Package developers should not use them for their packages.
  (general-create-definer akirak/bind-user :prefix "C-c")

  ;; bind-mode (C-,) for major-mode-specific commands
  (defconst akirak/mode-prefix-key "C-,"
    "Prefix for mode-specific keys.")
  (general-create-definer akirak/bind-mode :prefix akirak/mode-prefix-key)

  ;; Use ~<C-return>~ for starting a REPL session
  (general-create-definer akirak/bind-mode-repl
    :prefix "<C-return>")

  ;; TODO: I want to change this key to something else
  (general-create-definer akirak/bind-customization :prefix "C-x ESC"))

(use-package defrepeater
  ([remap other-window] (defrepeater #'other-window)
   [remap winner-undo] (defrepeater #'winner-undo)
   [remap winner-redo] (defrepeater #'winner-redo)
   [remap text-scale-increase] (defrepeater #'text-scale-increase)
   [remap text-scale-decrease] (defrepeater #'text-scale-decrease)))

Default settings

(require 'setup-defaults)

(when (akirak/running-on-crostini-p)
  (require 'my/system/platform/crostini))

(require 'setup-gpg)


In case there are functions that depends on these modules, load them first.

(require 'my/project)
(require 'my/buffer/predicate)
(org-babel-load-file (expand-file-name "" user-emacs-directory))


(use-package dash-docs)
(use-package emacs-everywhere
  ;; Use my fork until the path issue is fixed
  :straight (:host github :repo "akirak/emacs-everywhere" :branch "with-editor-1")
  :functions (emacs-everywhere)
  (:keymaps 'emacs-everywhere-mode-map
            ;; Analogous to the post command in most web applications,
            ;; and it's also bound to mode-aware repl commands, which
            ;; is irrelevant in text-mode.
            "<C-return>" #'emacs-everywhere-finish))
(use-package helm-dash
  (dash-docs-browser-func #'akirak/browse-url))
(use-package discover-my-major
  :commands (discover-my-major))
(use-package electric
  :straight (:type built-in)
  (text-mode . electric-pair-local-mode))
(use-package epkg)

(use-package helm-tail
  :commands (helm-tail))
(use-package org-recent-headings
  :disabled t
  :after org
  (general-add-hook 'org-recent-headings-advise-functions
  (org-recent-headings-mode 1)

  (setq org-recent-headings-reject-any-fns
        (list (defun akirak/org-recent-headings-reject-journal-date (entry)
                (when (featurep 'org-multi-wiki)
                  (let ((file (org-recent-headings-entry-file entry))
                        (olp (org-recent-headings-entry-outline-path entry)))
                    (when-let (plist (org-multi-wiki-entry-file-p file))
                      (and (eq 'journal (plist-get plist :namespace))
                           (= 1 (length olp)))))))))

  (defun akirak/org-recent-headings-cleanup ()
    (let ((m (length org-recent-headings-list))
          (start-time (float-time))
          (n (progn
               (dolist (x org-recent-headings-list)
                 (condition-case _
                     (org-recent-headings--entry-marker x)
                   (error (cl-delete x org-recent-headings-list
                                     :test #'org-recent-headings--equal))))
               (length org-recent-headings-list))))
      (unless (= m n)
        (message "Deleted %d non-existent items from org-recent-headings-list in %.1f s"
                 (- m n)
                 (- (float-time) start-time))))
    ;; Prevent automatic GC toon soon after getting back to work
  (run-with-idle-timer 1200 t #'akirak/org-recent-headings-cleanup))
(use-package helm-org-recent-headings
  :disabled t
  :after (helm org-recent-headings)
  ;; Modified from `helm-org-recent-headings-source'.
  (defvar akirak/helm-org-recent-headings-source
    (helm-build-sync-source " Recent Org headings"
      :candidates (lambda ()
      :candidate-number-limit 'org-recent-headings-candidate-number-limit
      :candidate-transformer 'helm-org-recent-headings--truncate-candidates
      :keymap helm-org-recent-headings-map
      :action 'akirak/helm-org-recent-headings-actions)
    "Helm source for `org-recent-headings'.")
  (defvar akirak/helm-org-recent-headings-actions
     "Show entry (default function)" 'org-recent-headings--show-entry-default
     "Show entry in real buffer" 'org-recent-headings--show-entry-direct
     "Show entry in indirect buffer" 'org-recent-headings--show-entry-indirect
     "Insert a link to the heading"
     (defun akirak/org-recent-headings-insert-link (entry)
       (unless (derived-mode-p 'org-mode)
         (user-error "Not in org-mode"))
       (let ((marker (org-recent-headings--entry-marker entry)))
         (with-current-buffer (marker-buffer marker)
            (goto-char marker)
            (org-store-link nil 'interactive))))
       (org-insert-last-stored-link 1))
     "Remove entry" 'helm-org-recent-headings-remove-entries
     "Bookmark heading" 'org-recent-headings--bookmark-entry)))
(use-package license-templates)
(use-package project
  (add-hook 'project-find-functions
            (defun akirak/project-tramp-root (dir)
              (-some->> (file-remote-p dir)
                (cons 'remote))))
  (add-hook 'project-find-functions
            (defun akirak/project-syncthing-root (dir)
              (-some->> (locate-dominating-file dir ".stfolder")
                (cons 'syncthing)))))
(use-package su)
(use-package valign
  :disabled t
  (org-mode . valign-mode))
(use-package whole-line-or-region)


(require 'setup-project)
(require 'setup-git-bookmark)
(require 'setup-info)
(require 'setup-unicode)
(require 'setup-mmm)

Starting the server

This may fail if there is another Emacs session running a server.

  (unless (server-running-p)

Commands and keybindings

Basic keybindings

These keybindings basically emulate UNIX shells (i.e. sh, bash, etc.).

I also like to define “dwim” commands, if applicable, to save the keybinding space and key strokes.


By default, C-a is bound to beginning-of-line.

This command first jump to the indentation and then visits the beginning of line.

(general-def prog-mode-map
  (defun akirak/back-to-indentation-or-beginning-of-line ()
    (if (or (looking-at "^")
            (string-match-p (rx (not (any space)))

In org-mode, I prefer org-beginning-of-line.

(general-def :keymaps 'org-mode-map :package 'org
  "C-a" #'org-beginning-of-line)


(general-def :keymaps 'org-mode-map :package 'org
  "C-e" #'org-end-of-line)


  "C-h" 'backward-delete-char)


  (defun akirak/kill-region-or-backward-kill-word (&optional arg)
    "If a region is active, run `kill-region'. Otherwise, run `backward-kill-word'."
    (interactive "p")
    (if (region-active-p)
        (kill-region (region-beginning) (region-end))
      (backward-kill-word arg))))

(general-def minibuffer-local-map
  "C-w" #'backward-kill-word)

(general-def ivy-minibuffer-map :package 'ivy
  "C-w" #'ivy-backward-kill-word)


(general-def minibuffer-local-map
  "C-u" #'backward-kill-sentence)

(general-def ivy-minibuffer-map :package 'ivy
  (defun ivy-backward-kill-sentence ()
    (if ivy--directory
        (progn (ivy--cd "/")
      (if (bolp)
          (kill-region (point-min) (point))


In minibuffers, C-r should call history.

(general-def ivy-minibuffer-map :package 'ivy
  "C-r" 'counsel-minibuffer-history)

Key translation and simulation

Since I have bound C-h to backward-delete-char but still use the help system frequently, I bind M-` to <f1> in key-translation-map.

(general-def key-translation-map
  ;; * Obsolete
  ;; As <menu> (application on Windows keyboards) is hard to reach on some
  ;; keyboards, I will use <C-tab> instead. This key combination is occupied on
  ;; web browsers but vacant on most Emacs major modes, so it is safe to use it
  ;; on non-EXWM buffers.
  ;; "<C-tab>" (kbd "<menu>")

  ;; Chromebook don't have physical function keys. They substitute
  ;; Search + num for function keys, but Search + 1 is hard to press,
  ;; especially when Search and Ctrl are swapped.
  ;; This is quite annoying, so I will use M-` as <f1>.
  "M-`" (kbd "<f1>"))

(general-def "M-r" (general-simulate-key "C-x r"))

Emulate virtual function keys of Chrome OS

Emulate function keys of Chrome OS, i.e. use s-NUM as function keys.

(define-globalized-minor-mode akirak/emulate-chromeos-fnkey-mode
  (lambda ()
      (dolist (n (number-sequence 1 9))
        (define-key key-translation-map
          (kbd (format "s-%d" n)) (kbd (format "<f%d>" n))))
      (define-key key-translation-map
        (kbd "s-0") (kbd "<f10>"))
      (define-key key-translation-map
        (kbd "s--") (kbd "<f11>"))
      (define-key key-translation-map
        (kbd "s-=") (kbd "<f12>")))
      (dolist (n (number-sequence 0 9))
        (define-key key-translation-map
          (kbd (format "s-%d" n)) nil))
      (define-key key-translation-map
        (kbd "s--") nil)
      (define-key key-translation-map
        (kbd "s-=") nil)))))

(unless (akirak/running-on-crostini-p)
  (akirak/emulate-chromeos-fnkey-mode 1))

Insert strings/characters

(defmacro akirak/def-insert-date-time-command (name format)
  `(defun ,(intern (format "akirak/insert-%s" name)) ()
     (insert (format-time-string ,format))))

This prefix map will be overridden in org-mode

(general-def :prefix "C-c !"
  "8" (akirak/def-insert-date-time-command "yyyymmdd-date" "%Y%m%d")
  "f" (akirak/def-insert-date-time-command "iso8601-date" "%F")
  "t" (akirak/def-insert-date-time-command "iso8601-datetime" "%FT%X"))

Switching buffers

Switching buffers is the most essential operation in Emacs. Most of these commands are bound on C-x.

Helm commands

  "C-x b"
  (defun akirak/switch-to-project-file-buffer (project)
    (interactive (list (if current-prefix-arg
                         (-some-> (project-current)
     ((eq project 'all)
      (let ((default-directory (or project default-directory)))
        (helm :prompt (format "Project %s: " project)
              `(,@(akirak/helm-project-buffer-sources project #'akirak/switch-to-project-file-buffer)
  "C-x p"
  (defun akirak/find-file-recursively (root)
    (interactive (list (or (akirak/project-root default-directory)
                           (user-error "Cannot find the project root"))))
    (require 'my/helm/source/file)
    (when current-prefix-arg
      (akirak/clear-project-file-cache root :sort 'modified))
    (let ((default-directory root))
      (helm :prompt (format "Browse %s: " root)
            (list akirak/helm-source-project-files
  "C-x d"
  (defun akirak/switch-to-dired-buffer ()
    "Switch to a directory buffer interactively.

Without a prefix, it displays a list of dired buffers, a list of
directories of live file buffers, and a list of directory

With a single universal prefix, it displays a list of known Git

With two universal prefixes, it displays a list of remote
connection identities of recent files."
    (pcase current-prefix-arg
       (require 'my/helm/source/remote)
       (helm :prompt "Remote: "
       (require 'my/helm/source/dir)
       (helm :prompt "Directory/repository: "
             (list (akirak/helm-dired-buffer-source)
      (_ (user-error "Not matching %s" current-prefix-arg))))
  "C-x g"
  (defun akirak/browse-git-repository ()
    (require 'my/helm/source/dir)
    (helm :prompt "Directory/repository: "
          (list akirak/helm-directory-bookmark-as-git-source
  "C-x j"
  (defun akirak/switch-to-org-buffer ()
    (require 'helm-org-ql)
    ;; (require 'org-recent-headings)
    ;; (require 'helm-org-recent-headings)
    (helm :prompt "Switch to Org: "
           (list (akirak/helm-indirect-org-buffer-source)
                 (unless (org-clocking-p)
  "C-x x"
  (defun akirak/switch-to-x-buffer (&optional arg)
    (interactive "P")
      (helm :prompt "Switch to EXWM buffer: "
            :sources (akirak/helm-exwm-buffer-source)))
      (user-error "Not supported on WSL"))
     ((eq system-type 'gnu/linux)
      ;; TODO: Implement it
      (cl-assert (executable-find "wmctrl"))
      (helm :prompt "X window: "
            (helm-build-sync-source "X windows"
              :candidates (-map (lambda (s)
                                    (when (string-match (rx bol (group (+ (not (any space))))
                                                            (+ space)
                                                            (group (+ (+ digit)))
                                                            (+ space)
                                                            (+ (not (any space)))
                                                            (+ space)
                                                            (group (+ anything)))
                                      (cons (format "%s: %s" (match-string 2 s)
                                                    (match-string 3 s))
                                            (match-string 1 s)))))
                                (process-lines "wmctrl" "-l"))
              :action (lambda (wid)
                        (call-process "wmctrl" nil nil nil "-i" "-a" wid)))))))
  "C-x '"
  (defun akirak/switch-to-reference-buffer-or-browser ()
    (require 'my/helm/source/web)
    (helm :prompt "Switch to a reference buffer: "
          :default (list (thing-at-point 'symbol)
                         (buffer-name helm-current-buffer))
          :sources (append (list (akirak/helm-reference-buffer-source))
                           (list helm-source-bookmark-info
                           (list (helm-def-source--info-files))

  "<f6> <f6>"
  (defun akirak/switch-to-recent-file-buffer ()
    (if-let (buf (->> (buffer-list)
                      (-filter (lambda (buf)
                                 (and (buffer-file-name buf)
                                      (not (get-buffer-window buf)))))
                      (-map (lambda (buf)
                              (cons buf
                                    (buffer-local-value 'buffer-display-time buf))))
                      (-filter #'cdr)
                      (-sort (-on (-compose #'not #'time-less-p) #'cdr))
        (if current-prefix-arg
            (pop-to-buffer buf)
          (switch-to-buffer buf))
      (user-error "No recent buffer"))))

In the list of project buffers, you can switch to a file list with M-/.

  :keymaps 'akirak/helm-project-buffer-map
  :package 'my/helm/source/complex
  "M-/" (lambda ()
           (lambda ()
             (akirak/find-file-recursively default-directory)))))

I haven’t bound any key to this command yet.

(defun akirak/switch-to-scratch-buffer ()
  (helm :prompt "Switch to a scratch/REPL buffer: "

Browsing contents in specific buffers without leaving the context

  ;; This command lets you browse lines in error buffers.
  "C-x t" #'helm-tail)

Navigation in buffer


avy-goto-word-1 was recommended in, but avy-goto-char-2 looks better on cognitive load.

  "C-'" #'avy-goto-char-2)

(defun akirak/avy-pre-action-function (operand operation res)
  (let ((start (caar res))
        (window (cdr res)))
    (with-current-buffer (window-buffer window)
        (goto-char start)
        (cl-ecase operand
          (symbol (let ((begin (if (looking-at (rx symbol-start))
                                 (re-search-backward (rx symbol-start) nil t)))
                        (end (save-excursion
                                (rx (group (+? anything)) symbol-end)
                                nil t))))
                    (funcall operation begin end))))))))

(cl-defmacro akirak/def-avy-edit-command (name
                                          operand operation
                                          &rest post-action)
  (declare (indent 1))
  `(defun ,(intern (concat "akirak/avy-" name)) ()
     (let ((avy-all-windows t)
           (avy-pre-action (-partial #'akirak/avy-pre-action-function
           (call-interactively #'avy-goto-char-timer)))

Jump straight to the destination and do a thing

(general-def :prefix "C-;"
  "s" `(,(akirak/def-avy-edit-command "mirror-symbol"
           'symbol #'copy-region-as-kill)
        :wk "mirror symbol"))

Page navigation

I will use C-x [ and C-x ] for “page” navigation. These keys are bound to backward-page and forward-page by default, but they should be rebound depending on the major mode, since the notion of page/chunk varies.

  ;; Default
  "C-x [" #'backward-page
  "C-x ]" #'forward-page)

(general-def :keymaps 'org-mode-map :package 'org
  ;; [remap backward-page]
  [remap forward-page]
  (defun akirak/org-narrow-to-next-sibling-subtree ()
    (if (buffer-narrowed-p)
        (let ((old-level (save-excursion
                           (goto-char (point-min))
              (end (point-max)))
          (goto-char (point-max))
          (if (re-search-forward org-heading-regexp nil t)
              (let ((new-level (org-outline-level)))
                 ((= new-level old-level)
                  (message "Narrowing to the next sibling"))
                 ((> new-level old-level)
                  (message "Narrowing to a child"))
                 ((< new-level old-level)
                  (message "Narrowing to an upper level"))))
            (message "No more heading")))
      (message "Buffer is not narrowed"))))

(general-def :keymaps 'org-journal-mode-map :package 'org-journal
  [remap forward-page] #'org-journal-next-entry
  [remap backward-page] #'org-journal-previous-entry)

(general-def :keymaps 'Info-mode-map :package 'info
  "h" #'Info-up
  [remap forward-page] #'Info-next-preorder
  [remap backward-page] #'Info-prev)

Help and documentation

Use <f1> as the prefix for help commands

  [help ?.] #'helpful-at-point)

(general-def :package 'lsp-mode :keymaps 'lsp-mode-map
  [help ?.] #'lsp-describe-thing-at-point)

  "M" #'discover-my-major
  "xc" #'describe-char
  "xf" #'counsel-faces)

e.g. M-` M-m -> <f1> ESC m

  "ESC m" #'woman
  "ESC i" #'helm-info
  "ESC d" #'helm-dash)

Dash Docs

  "d" '(nil :wk "doc")
  "da" #'dash-docs-activate-docset
  "dh" #'helm-dash
  "di" #'dash-docs-async-install-docset)


Undo and redo

You still can use the built-in undo command with C-x u

(use-package undo-fu
  ("C-/" #'undo-fu-only-undo
   "C-?" #'undo-fu-only-redo))

Editing source code comments in org-mode using outorg

Bind ~C-c ‘~ to outorg, which is the same keybinding as org-edit-special.

(use-package outorg
  :commands (outorg-edit-as-org)
  (el-patch-defun outorg-convert-oldschool-elisp-buffer-to-outshine ()
    "Transform oldschool elisp buffer to outshine.
In `emacs-lisp-mode', transform an oldschool buffer (only
semicolons as outline-regexp) into an outshine buffer (with
outcommented org-mode headers)."
      (goto-char (point-min))
      (when (outline-on-heading-p)
      (while (not (eobp))
    (el-patch-remove (funcall 'outshine-hook-function))))
(general-def :keymaps 'emacs-lisp-mode-map
  "C-c '" #'outorg-edit-as-org)
(general-def :keymaps 'outorg-edit-minor-mode-map :package 'outorg
  "C-c '" #'outorg-copy-edits-and-exit)

Source navigation

Bind M-s M-s

  "M-s" #'xref-find-apropos)

Running external commands

  "C-x c"
  (defun akirak/project-compile ()
    (pcase current-prefix-arg
       (message "Set compilation-auto-jump-to-first-error to %s"
                (setq-default compilation-auto-jump-to-first-error
                              (not compilation-auto-jump-to-first-error))))
      ;; If two prefixes are given, select the compilation buffer window.
       (if-let (buffer (or (get-buffer "*compilation*")
                           (-find (lambda (buf)
                                    (buffer-local-value 'compilation-minor-mode buf))
           (if-let (window (get-buffer-window buffer))
               (select-window window)
             (pop-to-buffer buffer))
         (user-error "No compilation buffer")))
  "C-x C"
  (defun akirak/helm-shell-command (&optional root)
    (require 'my/helm/source/org)
    (require 'my/helm/action/org-marker)
    (let ((root (or root
                    (akirak/project-root default-directory)
      (setq akirak/programming-recipe-mode-name "sh"
            akirak/helm-org-ql-buffers-files (org-multi-wiki-entry-files 'refs :as-buffers t))
      (helm :prompt (format "Execute command (project root: %s): " root)
            (list (helm-make-source "Command" 'akirak/helm-source-org-ql-src-block
                    :action akirak/helm-org-marker-sh-block-action-list)
                  (helm-build-dummy-source "Command"
                       . (lambda (command)
                           (akirak/compile command :directory ,root)))
                       . (lambda (command)
                           (let ((default-directory ,root))
                             (eshell-command command)))))))))))

Maintenance and development of the config

These commands are used to maintain this Emacs configuration.

  "" '(nil :wk "customize")
  "f" #'customize-face-other-window
  "o" #'customize-group-other-window
  "l" #'counsel-find-library
  "p" '((lambda () (interactive)
          (if (featurep 'straight)
              (call-interactively 'straight-use-package)
        :wk "packages")
  "s" #'customize-set-value
  "v" #'customize-variable-other-window)

  "C-x M-m"
  (defun akirak/helm-my-library ()
    "Browse the library for this configuration."
    (require 'my/helm/source/file)
    (let ((default-directory (f-join user-emacs-directory "lisp")))
      (helm :prompt (format "Files in %s: " default-directory)
            :sources (list (helm-make-source "Files in project"
                           (helm-build-dummy-source "New file in lisp directory"
                             :action #'find-file))))))


(cl-defmacro akirak/run-at-project-root (command &key other-window)
  `(defun ,(intern (concat "akirak/project-" (symbol-name command))) ()
     (let ((root (akirak/project-root default-directory)))
       (when ,other-window
         (or (other-window 1)
       (let ((default-directory root))
         (call-interactively (quote ,command))))))

(cl-defmacro akirak/run-at-vc-root (command &key other-window)
  `(defun ,(intern (concat "akirak/vc-root-" (symbol-name command))) ()
     (when ,other-window
       (or (other-window 1)
     (let ((default-directory (vc-root-dir)))
       (call-interactively (quote ,command)))))

(cl-defmacro akirak/run-shell-command-silently-at-vc-root (name command)
  `(defun ,name ()
     (let ((default-directory (or (vc-root-dir)
       (shell-command ,command))))

(cl-defmacro akirak/make-vc-root-file-command (filename &key regexp name)
  `(defun ,(intern (format "akirak/open-%s-at-root" (or name (s-replace "." "-" filename)))) ()
     (let* ((default-directory (vc-root-dir))
            (file (pcase (if ,regexp
                             (directory-files default-directory nil ,filename t)
                           (when (file-exists-p ,filename)
                             (list ,filename)))
                    (`(,file) file)
                    ('() (if (and (not regexp)
                                  (yes-or-no-p (format "%s does not exist. Create it?" ,filename)))
                           (user-error "Aborted")))
                    (files (completing-read "File: " files)))))
       (find-file file))))

  ;; Project.el commands
  ;; Based on `project-prefix-map' in project.el 0.5.3
  "!" #'project-shell-command
  "&" #'project-async-shell-command
  "f" #'project-find-file
  ;; "F" #'project-or-external-find-file
  "b" #'project-switch-to-buffer
  "s" #'project-shell
  "d" #'project-dired
  ;; "v" #'project-vc-dir
  "c" (defun akirak/project-or-vc-compile (&optional arg)
        (interactive "P")
        (if arg
            (counsel-compile (vc-root-dir))
  ;; "e" #'project-eshell
  ;; "k" #'project-kill-buffers
  ;; "p" #'project-switch-project
  ;; "g" #'project-find-regexp
  ;; "G" #'project-or-external-find-regexp
  ;; "r" #'project-query-replace-regexp

  ;; Custom project commands
  "g" #'deadgrep
  "t" (akirak/run-at-project-root vterm :other-window t)

  ;; Commands run at a vc root
  "A" (defun akirak/treemacs-add-vc-root-to-workspace ()
        (treemacs-add-project-to-workspace (vc-root-dir)))
  "D" (akirak/run-at-vc-root add-dir-local-variable)
  "n" '(:wk "nix")
  "nd" (akirak/make-vc-root-file-command "default.nix")
  "ne" (akirak/run-shell-command-silently-at-vc-root
        akirak/project-nix-shell-exit "nix-shell --run exit")
  "nf" (akirak/make-vc-root-file-command "flake.nix")
  "nr" (akirak/run-at-vc-root nix-repl :other-window t)
  "ns" (akirak/make-vc-root-file-command "shell.nix")
  "r" (akirak/make-vc-root-file-command "^README\\..+\\'" :regexp t :name "readme")

  ;; Unused commands
  ;; "c" (akirak/run-at-project-root compile)
  ;; "d" #'project-dired
  ;; "e" (akirak/run-at-project-root ielm :other-window t)

f12: Administration and external tool integration


  ;; WIP: Use transient to organize these entry points
  "c" '(nil :wk "capture")
  ;; Based on
  (defun screenshot-svg ()
    "Save a screenshot of the current frame as an SVG image.
Saves to a temp file and puts the filename in the kill ring."
    (let* ((filename (make-temp-file "Emacs" nil ".svg"))
           (data (x-export-frames nil 'svg)))
      (with-temp-file filename
        (insert data))
      (kill-new filename)
      (message filename)))
  "cE" #'akirak/gif-screencast
  "cx" #'org-download-screenshot)


  "d" '(nil :wk "dir")
  "de" #'direnv-allow
  "du" #'disk-usage
  "dh" #'helm-linux-disks)




  "g" '(nil :wk "git")
  "gb" #'akirak/git-bookmark-repository
  "gc" #'akirak/git-clone-remote-repo
  "gl" #'magit-list-repositories
  "go" #'akirak/github-owned-repos
  "gr" #'commonplace-repos-counsel-rg
  "gs" #'akirak/github-starred-repos
  "gt" #'akirak/git-module-add-tags
  "gu" #'akirak/github-users)


  "k" '(nil :wk "docker")
  "ki" #'docker-images
  "kk" #'docker-containers
  "kn" #'docker-networks
  "kv" #'docker-volumes)


  "n" '(nil :wk "nix")
  "nf" #'akirak/nix-prefetch-url)

Misc query commands

  "q" '(nil :wk "query")
  "qc" #'calc)

Remote connections (TRAMP)

  "r" '(nil :wk "remote")
  "rk" #'helm-delete-tramp-connection)


No releases published


No packages published