Adam Richardson's Site

Emacs Config

Table of Contents

<2022-05-19 Thu>

Early Init

Disable package.el since I use straight.el

(setq package-enable-at-startup nil)

Environment

Set various environment variables in emacs

(setenv "LD_LIBRARY_PATH"
        (concat
         (getenv "HOME")
         "/.local/lib"))

Dired Mode

A set of customizations to dired mode to make it a little easier to use

(require 'dired)
(setq dired-dwim-target t)
(setq dired-recursive-copies (quote always))
(setq dired-recursive-deletes (quote top))
(add-hook 'dired-mode-hook
          (lambda ()
            (dired-hide-details-mode)))

(let ((map dired-mode-map))
  (define-key map (kbd "C-b") #'bongo-dired-append-enqueue-lines))

Alt Key

This allows the alt key to work as meta

(setq x-alt-keysym 'meta)

Visual line mode in text mode

This ensures that visual line mode is enabled by default for all major modes that derive from text-mode

(add-hook 'text-mode-hook 'turn-on-visual-line-mode)

Packages

Setup straight.el

This code is from the straight.el README.md in the github repo straight.el

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

Upgrading

  • M-x straight-pull-all or M-x straight-pull-package
  • The packages will be rebuilt when you restart emacs or you can run M-x straight-check-all to rebuild them, (its probably better to restart emacs to clean the old version out)

Package List

(straight-use-package 'magit)
(straight-use-package 'counsel)
(straight-use-package 'hydra)
(straight-use-package 'ivy-hydra)
(straight-use-package 'ace-window)
(straight-use-package 'avy)
(straight-use-package 'markdown-mode)
(straight-use-package 'geiser)
(straight-use-package 'geiser-guile)
(straight-use-package 'bongo)
(straight-use-package 'speed-type)
(straight-use-package 'paredit)
(straight-use-package 'elfeed)
(straight-use-package 'password-store)
(straight-use-package 'password-store-otp)
(straight-use-package 'lua-mode)
(straight-use-package 'notmuch)
(straight-use-package 'yasnippet)
(straight-use-package 'yasnippet-snippets)
(straight-use-package 'yafolding)
(straight-use-package 'coterm)
(straight-use-package 'pulseaudio-control)
(straight-use-package 'yaml-mode)
(straight-use-package 'ledger-mode)
(straight-use-package 'slime)
(straight-use-package 'sunshine)
(straight-use-package 'gnuplot)
(straight-use-package 'graphviz-dot-mode)
(straight-use-package 'go-mode)
(straight-use-package 'ob-go)
(straight-use-package 'olivetti)
(straight-use-package 'auctex)
(straight-use-package 'lsp-mode)
(straight-use-package 'flycheck)
(straight-use-package 'company)
(straight-use-package 'lsp-ui)
(straight-use-package 'sudoku)
(straight-use-package 'plantuml-mode)
(straight-use-package 'kotlin-mode)

Personal Elisp Files

shelllike filter

This is a process filter that handles carriage returns and newlines. From this, using process filter for carriage returns, stack overflow.

(defun ajr-shelllike-filter (proc string)
  (let* ((buffer (process-buffer proc))
         (window (get-buffer-window buffer)))
    (with-current-buffer buffer
      (if (not (mark)) (push-mark))
      (exchange-point-and-mark) ;Use the mark to represent the cursor location
      (dolist (char (append string nil))
        (cond ((char-equal char ?\r)
               (move-beginning-of-line 1))
              ((char-equal char ?\n)
               (move-end-of-line 1) (newline))
              (t
               (if (/= (point) (point-max)) ;Overwrite character
                   (delete-char 1))
               (insert char))))
      (exchange-point-and-mark))
    (if window
        (with-selected-window window
          (goto-char (point-max))))))

Start Process in Buffer

(defun ajr-start-process-in-buffer (buffer-name
                                    program-name
                                    program
                                    &optional program-dir
                                    initial-message
                                    &rest program-args)
  "Starts a process in buffer with BUFFER-NAME. If an optional
INITIAL-MESSAGE is supplied it will be added to the beginning of the
buffer. If you pass the optional PROGRAM-DIR this will change to the
argument directory before starting the program. The final arugments
will be pass as PROGRAM-ARGS to the PROGRAM."
  (with-current-buffer (generate-new-buffer buffer-name)
    (special-mode)
    (setq buffer-read-only nil)
    (when initial-message
      (insert initial-message)
      (newline))
    (when program-dir
      (cd program-dir))
    (let ((proc (apply 'start-process
                       (append
                        (list
                         program-name
                         (current-buffer)
                         program)
                        program-args))))
      (set-process-filter proc 'ajr-shelllike-filter)
      (pop-to-buffer (current-buffer)))))

Example Usage

(ajr-start-process-in-buffer
 "*ajr-process-example*"
 "lsblk"
 "lsblk"
 nil
 "This is an example of using the start process
in buffer function.
---------------------------------------------"
 "-t")

elfeed

Syncing

Info on how to sync elfeed here.

(defun ajr-elfeed ()
  "My command to start and update elfeed"
  (interactive)
  (elfeed)
  (elfeed-search-clear-filter)
  (elfeed-search-update--force)
  (beginning-of-buffer))

(defun ajr-elfeed-save-db-and-bury ()
  "Wrapper to save the efleed db to disk before burying buffer"
  (interactive)
  (elfeed-db-save)
  (quit-window))

Make org mode link

(defun ajr-elfeed-copy-org-link ()
  "Generates an org mode link from an elfeed entry"
  (interactive)
  (kill-new "[[")
  (save-excursion
    (let ((kill-elfeed-entry-field
           (lambda (field-name)
             (goto-char (point-min))
             (search-forward field-name)
             (set-mark-command nil)
             (move-end-of-line nil)
             (kill-ring-save (mark) (point))
             (deactivate-mark))))
      (append-next-kill)
      (funcall kill-elfeed-entry-field "Link: ")
      (kill-append "][" nil)
      (append-next-kill)
      (funcall kill-elfeed-entry-field "Title: ")
      (kill-append "]]" nil))))

org capture

(defun ajr-org-basic-capture (key name filename)
  "Generates a basic capture template. It will
  prompt you for the title of the heading and place
  the point in the body of the heading. KEY is the
  character that needs to be pressed in org capture
  to use this template. NAME is the name of the capture
  template. FILENAME is which org file in your org-directory."
  (list key name 'entry
        (list 'file+headline filename name)
        "* %^{Title?}\n%?"))

web search

(defun ajr-search-web (term)
  "Prompts the user for a search TERM. Searches
  duckduckgo with eww for the term. Inspired by
  https://gist.github.com/brenns10/69d39f6c46170093f73d"
  (interactive "MSearch Web: ")
  (eww (format "https://html.duckduckgo.com/html/?q=%s"
               (url-hexify-string term))))

mail

(defcustom ajr-sync-mail-program
  "syncmail"
  "Program that syncs mail and updates notmuch")

(defun ajr-sync-mail ()
  "Starts a process name `syncmail' and sends the output to
  a special mode buffer. This will pop to the buffer as the
  process is running."
  (interactive)
  (ajr-start-process-in-buffer
   "*syncmail*"
   "syncmail"
   ajr-sync-mail-program))

music

(defcustom ajr-music-dir
  (concat (getenv "HOME")
          "/music")
  "Directory where your music is kept.")

(defconst ajr--no-dot-regexp
  "^[^\\.].+$"
  "Only matches files that do not start with a dot")

(defun ajr--dir-subdirs (directory)
  "Returns the list of sub dirs inside the argument DIRECTORY.
  Ignores directories that start with a `.' "
  (mapcar 'car (seq-filter (lambda (f-or-d)
                             (not (eq (nth 1 f-or-d)
                                      nil)))
                           (directory-files-and-attributes directory
                                                           nil
                                                           ajr--no-dot-regexp))))

(defun ajr--all-albums ()
  "Returns a list of pairs of all available albums `(ARTIST . ALBUM)'"
  (let ((artists (ajr--dir-subdirs ajr-music-dir)))
    (mapcan (lambda (artist)
              (let ((artist-path (string-join
                                  (list ajr-music-dir
                                        "/" artist))))
                (mapcar (lambda (album)
                          `(,artist . ,album))

                        (ajr--dir-subdirs artist-path))))
            artists)))

(defun ajr--ask-album ()
  "Prompts the user to choose an album, returns `(ARTIST . ALBUM)"
  (let* ((albums (ajr--all-albums))
         (album-display-names
          (mapcar (lambda (album)
                    (format "%s - %s" (car album) (cdr album)))
                  albums))
         (albums-alist (mapcar (lambda (n)
                                 `(,(nth n album-display-names) .
                                   ,(nth n albums)))
                               (number-sequence 0 (- (length albums) 1)))))

    (cdr (assoc (completing-read "Which album? "
                                 album-display-names)
                albums-alist))))

(defun ajr--album-path (album)
  "Gets the path of an album from `(ARTIST . ALBUM)'"
  (string-join (list ajr-music-dir
                     "/"
                     (car album)
                     "/"
                     (cdr album))))

(defun ajr-bongo-play-album ()
  "Prompts the user for an album and starts playing it"
  (interactive)
  (let ((album (ajr--ask-album)))
    (with-bongo-playlist-buffer
      (bongo-stop)
      (bongo-erase-buffer)
      (bongo-insert-directory-tree (ajr--album-path album))
      (goto-char (point-min))
      (bongo-play))))

podcasts

Variables

(defcustom ajr-podcast-dir
  (concat (getenv "HOME")
          "/podcasts")
  "Directory where your podcasts are kept.
  Used the `ajr-podcast-*' functions.")

Podcast dired

(defun ajr-podcast-dired ()
  "Opens dired buffer to `ajr-podcast-dir' in other window"
  (interactive)
  (find-file-other-window ajr-podcast-dir))

video

Variables

(defcustom ajr-video-dir
  (concat (getenv "HOME")
          "/videos")
  "Directory where your videos are kept.
  Used the `ajr-video-*' functions."
  :type 'directory)

(defcustom ajr-video-program
  "mpv"
  "Program used to play videos.
  This program should accept the path to the video as its argument."
  :type 'string)

(defcustom ajr-video-regexp
  ".+\\.\\(mp4\\|webm\\|mkv\\)$"
  "Only matches files ending in `mp4' or `webm' or `mkv'."
  :type 'regexp)

Prompt user for video

(defun ajr--ask-video (is-by-date video-dir)
  (let ((videos (directory-files
                 video-dir
                 nil
                 ajr-video-regexp))
        (sorted-videos (mapcar 'car (sort
                                     (directory-files-and-attributes
                                      video-dir
                                      nil
                                      ajr-video-regexp)
                                     (lambda (x y)
                                       (time-less-p
                                        (file-attribute-modification-time (cdr y))
                                        (file-attribute-modification-time (cdr x))))))))

    (completing-read "Which video? " (if is-by-date
                                         sorted-videos
                                       videos))))

Video playback

(defun ajr-video-play (arg &optional video-dir)
  "Prompts the user for a video from `ajr-video-dir'. If you pass a
`video-dir' in it will use that instead of `ajr-video-dir'. Uses the
`ajr-video-program' to play the video. Use C-u to sort the videos by
date (newest first)."
  (interactive "P")
  (let* ((vdir (or video-dir ajr-video-dir))
         (video (ajr--ask-video arg vdir))
         (video-buffer (get-buffer-create "*video-player*"))
         (script-proc-buffer
          (make-comint-in-buffer "video-player"
                                 video-buffer
                                 ajr-video-program
                                 nil
                                 (string-join (list vdir
                                                    "/"
                                                    video))))
         (video-proc (get-buffer-process video-buffer)))
    (with-current-buffer video-buffer
      ;; If the buffer was previously in special mode,
      ;; need to set read only to false
      (setq buffer-read-only nil))
    (set-process-sentinel video-proc
                          (lambda (proc change)
                            (with-current-buffer (process-buffer proc)
                              (special-mode))))))

Video dired

(defun ajr-video-dired ()
  "Opens dired buffer to `ajr-video-dir' in other window"
  (interactive)
  (find-file-other-window ajr-video-dir))

Video download

(require 'url-util)
(defun ajr-video-youtube-dl-at-point ()
  (interactive)
  (let ((yt-url (url-get-url-at-point)))
    (ajr-start-process-in-buffer
     "*youtube-dl*"
     (format "youtube-dl %s" yt-url)
     "youtube-dl"
     ajr-video-dir
     yt-url
     "-f"
     "best[height<=1080]"
     yt-url)))

mini scroll

Based on 2021 Emacs lightning talk, "Transient Key Maps" - Zachary Kanfer

(defvar ajr-mini-scroll-amount 5
  "Scroll lines used by ajr-mini-scroll.")

(defvar ajr-mini-scroll-map
  (let ((m (make-sparse-keymap)))
    (define-key m (kbd "<down>") 'ajr-mini-scroll-up)
    (define-key m (kbd "<up>") 'ajr-mini-scroll-down)
    m))

(defun ajr-mini-scroll (lines)
  "Scroll by `lines' lines"
  (interactive)
  (scroll-up lines)
  (set-transient-map ajr-mini-scroll-map))

(defun ajr-mini-scroll-down ()
  "Scroll down"
  (interactive)
  (ajr-mini-scroll (- ajr-mini-scroll-amount)))

(defun ajr-mini-scroll-up ()
  "Scroll up"
  (interactive)
  (ajr-mini-scroll ajr-mini-scroll-amount))

Prompt before closing frame in daemon mode

Based on https://emacs.stackexchange.com/questions/30454/how-to-make-emacs-prompt-me-before-closing-the-last-emacs-gui-frame-when-running

(defun ajr-ask-before-closing ()
  "Close frame only if y was pressed"
  (interactive)
  (if (y-or-n-p (format "Do you want to close this frame? "))
      (save-buffers-kill-terminal)
    (message "Ok")))

Switch to Scratch

  • Function that allows me to bind switching to the scratch buffer to a key
(defun ajr-scratch ()
  "Switch to the scratch buffer"
  (interactive)
  (switch-to-buffer "*scratch*"))

Emulation

Variables

;; Game Boy
(defcustom ajr-emu-gameboy-dir
  (concat (getenv "HOME")
          "/games/gb/")
  "Directory where your Game Boy games are kept. Used the
`ajr-emu-gameboy-*' functions."
  :type 'directory)

(defcustom ajr-emu-gameboy-program
  (list
   "gambatte")
  "Program used to play Game Boy games. The program should be the
first item in the list. Any additional flags for the program should
get there own list item. The path the game will be added as the
final argument to the program but this does not need to be in the
list"
  :type '(repeat string))

(defcustom ajr-emu-gameboy-regexp
  ".+\\.\\(gbc\\|gb\\)$"
  "Only matches files ending in `gbc' or `gb'"
  :type 'regexp)

;; GBA
(defcustom ajr-emu-gba-dir
  (concat (getenv "HOME")
          "/games/gba/")
  "Directory where your Game Boy Advance games are kept. Used the
`ajr-emu-gba-*' functions."
  :type 'directory)

(defcustom ajr-emu-gba-program
  (list
   "mgba")
  "Program used to play Game Boy Advance games. The program should be
the first item in the list. Any additional flags for the program
should get there own list item. The path the game will be added as the
final argument to the program but this does not need to be in the list"
  :type '(repeat string))

(defcustom ajr-emu-gba-regexp
  ".+\\.\\(gba\\)$"
  "Only matches files ending in `gba'"
  :type 'regexp)

;; SNES
(defcustom ajr-emu-snes-dir
  (concat (getenv "HOME")
          "/games/snes/")
  "Directory where your SNES games are kept. Used the
`ajr-emu-snes-*' functions."
  :type 'directory)

(defcustom ajr-emu-snes-program
  (list
   "ares")
  "Program used to play SNES games. The program should be the
first item in the list. Any additional flags for the program should
get there own list item. The path the game will be added as the
final argument to the program but this does not need to be in the
list"
  :type '(repeat string))

(defcustom ajr-emu-snes-regexp
  ".+\\.\\(sfc\\)$"
  "Only matches files ending in `sfc'"
  :type 'regexp)

Prompting for a Game

(defun ajr--ask-emu (dir regexp)
  (let ((games (directory-files
                dir
                nil
                regexp)))
    (concat dir
            (completing-read "Which Game? "
                             games))))

Running the Emulators

(defun ajr--emu-run (buffer-name
                     emu-program
                     game)
  (let ((emu (car emu-program))
        (args (cdr emu-program))
        (cmd-str (string-join
                  (list
                   (string-join emu-program " ")
                   game)
                  " ")))
    (apply #'ajr-start-process-in-buffer
           (append (list
                    buffer-name
                    (format "%s %s" emu game)
                    emu
                    nil
                    cmd-str)
                   args
                   (list game)))))

  • Game Boy
    (defun ajr-emu-gameboy-play ()
      "Prompts for a game in `ajr-emu-gameboy-dir' with
    `ajr-emu-gameboy-program'."
      (interactive)
      (let ((game (ajr--ask-emu
                   ajr-emu-gameboy-dir
                   ajr-emu-gameboy-regexp)))
        (ajr--emu-run "*Game Boy*"
                      ajr-emu-gameboy-program
                      game)))
    
  • GBA
    (defun ajr-emu-gba-play ()
      "Prompts for a game in `ajr-emu-gba-dir' with
    `ajr-emu-gba-program'."
      (interactive)
      (let ((game (ajr--ask-emu
                   ajr-emu-gba-dir
                   ajr-emu-gba-regexp)))
        (ajr--emu-run "*GBA*"
                      ajr-emu-gba-program
                      game)))
    
  • SNES
    (defun ajr-emu-snes-play ()
      "Prompts for a game in `ajr-emu-snes-dir' with
    `ajr-emu-snes-program'."
      (interactive)
      (let ((game (ajr--ask-emu
                   ajr-emu-snes-dir
                   ajr-emu-snes-regexp)))
        (ajr--emu-run "*SNES*"
                      ajr-emu-snes-program
                      game)))
    

Add timestamp above first org heading

  • These elisp functions add a timestamp above the first heading
  • I use them for this repo specifically to know when I have last updated something
(defun ajr-org-goto-first-heading()
  (goto-char (point-min))
  (unless (org-at-heading-p)
    (org-next-visible-heading 1)))

(defun ajr-org-add-edit-timestamp ()
  (save-excursion
    (ajr-org-goto-first-heading)
    (if (eq (line-number-at-pos) 1)
        (progn
          (newline)
          (previous-line))
      (progn
        (previous-line)
        (if (org-at-timestamp-p)
            (kill-whole-line)
          (next-line))
        (newline)
        (previous-line)))
    (org-insert-time-stamp (current-time))))

View Android Screenshot

(defun ajr-android-screenshot ()
  "Uses adb to capture a screencap of the connected device.
The screenshot is opened in the other window."
  (interactive)
  (let ((fname (expand-file-name
                (concat
                 "~/tmp/android-"
                 (format-time-string "%Y%m%d%H%M%S")
                 ".png"))))
    (shell-command
     (concat
      "adb exec-out screencap -p > "
      fname))
    (find-file-other-window fname)))

ajr.el

Load the personal elisp files in init file

(load "~/.emacs.d/ajr")

Completion

I use ivy for my completion framework

(ivy-mode)

Global Hotkeys

ivy

(global-set-key (kbd "C-M-s") 'swiper)
(global-set-key (kbd "C-M-j") 'avy-goto-char)
(global-set-key (kbd "C-c r") 'ivy-resume)
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "C-x C-f") 'counsel-find-file)
(global-set-key (kbd "C-x b") 'counsel-switch-buffer)

function keys

(global-set-key (kbd "<f5>") 'ajr-elfeed)
(global-set-key (kbd "<f6>") 'ajr-scratch)
(global-set-key (kbd "<f7>") 'shell)
(global-set-key (kbd "<f8>") 'compile)
(global-set-key (kbd "<f9>") 'whitespace-mode)
(global-set-key (kbd "<f10>") 'whitespace-cleanup)
(global-set-key (kbd "<f12>") 'comment-dwim)

mail

(global-set-key (kbd "C-c n n") 'notmuch)
(global-set-key (kbd "C-c n u") 'ajr-sync-mail)

password-store

(global-set-key (kbd "C-c p c") 'password-store-copy)
(global-set-key (kbd "C-c p o") 'password-store-otp-token-copy)

music and podcasts

(define-key global-map (kbd "C-c m") (make-sparse-keymap))
(global-set-key (kbd "C-c m b") 'bongo-playlist)
(global-set-key (kbd "C-c m a") 'ajr-bongo-play-album)
(global-set-key (kbd "C-c m p") 'bongo-pause/resume)
(global-set-key (kbd "C-c m <right>") 'bongo-next)
(global-set-key (kbd "C-c m <left>") 'bongo-previous)
(global-set-key (kbd "C-c m c") 'ajr-podcast-dired)

videos

(define-key global-map (kbd "C-c v") (make-sparse-keymap))
(global-set-key (kbd "C-c v p") 'ajr-video-play)
(global-set-key (kbd "C-c v b") 'ajr-video-dired)
(global-set-key (kbd "C-c v d") 'ajr-video-youtube-dl-at-point)

emulation

(define-key global-map (kbd "C-c e") (make-sparse-keymap))
(global-set-key (kbd "C-c e a") 'ajr-emu-gba-play)
(global-set-key (kbd "C-c e g") 'ajr-emu-gameboy-play)
(global-set-key (kbd "C-c e s") 'ajr-emu-snes-play)

org capture

(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)

ace window

(global-set-key (kbd "M-o") 'other-window)
(global-set-key (kbd "C-x o") 'ace-window)

yafolding

(global-set-key (kbd "C-<return>") 'yafolding-toggle-element)

prompt before closing

(when (daemonp)
  (global-set-key (kbd "C-x C-c") 'ajr-ask-before-closing))

misc

(global-set-key (kbd "C-x C-b") 'ibuffer)
(global-set-key (kbd "C-x w") 'webjump)
(global-set-key (kbd "C-c f") 'find-file-at-point)
(global-set-key (kbd "C-x l") 'slime-repl)

Disable C-z

(global-unset-key (kbd "C-z"))
(global-unset-key (kbd "C-x C-z"))

Paredit

This enables paredit mode for various lisps

(autoload 'enable-paredit-mode "paredit"
  "Turn on pseudo-structural editing of Lisp code." t)
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
(add-hook 'lisp-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
(add-hook 'scheme-mode-hook #'enable-paredit-mode)

Org Mode

Customizations and global keys for org mode

(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c c") 'org-capture)
(setq org-capture-templates
      '(("t" "TODO")
        ("ti" "Misc TODO" entry
         (file+headline "todos.org" "Misc")
         "* TODO %?\n"
         :prepend t)))

Before Save Hook

(add-hook 'before-save-hook 'whitespace-cleanup)

Bongo

(require 'bongo)

Artist Mode

(add-hook 'artist-mode-hook
          (lambda ()
            (setq indent-tabs-mode nil)))

js mode (JavaScript)

(add-hook 'js-mode-hook
          (lambda ()
            (setq indent-tabs-mode nil)))

Global Modes

(yas-global-mode)
(yafolding-mode)
(add-hook 'prog-mode-hook 'linum-mode)
(add-hook 'prog-mode-hook 'company-mode)
(add-hook 'prog-mode-hook 'hl-line-mode)
(coterm-mode)
(require 'elfeed)

Emacs Server Mode

  • You can enable the emacs server to start at login with systemctl --user enable emacs
  • You can connect to the server with emacsclient -c
  • The -c flag creates a new frame
  • From the ArchWiki when emacs is started from systemd it doesn't source .bash_profile
  • Another option is the start it in your .Xprofile with emacs --fg-daemon
  • This way would inherit the environment variables

lsp-mode

  • lsp-mode performance docs
  • In addition to native compilation the --with-json flag can result in an almost 15x performance increase
  • This flag requires libjansson to be installed
  • Increasing the amount of garbage collection cons threshold (gc-cons-threshold) to 100Mb (setq gc-cons-threshold 100000000)
  • Increase the read brocess buffer from 4k to 1mb (setq read-process-output-max (* 5 1024 1024)) ;; 5mb

lsp-dart

;; Dart Stuff
(straight-use-package 'dart-mode)
(straight-use-package 'lsp-mode)
(straight-use-package 'lsp-dart)
(straight-use-package 'lsp-treemacs)
(straight-use-package 'flycheck)
(straight-use-package 'company)
(straight-use-package 'lsp-ui)
(straight-use-package 'hover)
(straight-use-package 'lsp-ivy)

(add-hook 'dart-mode-hook 'lsp)

(setq lsp-keymap-prefix "C-c n")

(defun ajr-lsp-format-on-save-hook ()
  (when (bound-and-true-p lsp-mode)
    (lsp-format-buffer)))

(add-hook 'before-save-hook 'ajr-lsp-format-on-save-hook)

Go

  • Install the go language server gopls, go get golang.org/x/tools/gopls@latest
(add-hook 'go-mode-hook 'lsp-deferred)

SLIME

Inferior Lisp Program

(setq inferior-lisp-program "/usr/bin/sbcl")

HyperSpec Path

(setq common-lisp-hyperspec-root
  (concat "file://" (expand-file-name "~/docs/HyperSpec/")))

Hydra

  • Use the example hydra for zooming text
(require 'hydra)

(require 'ivy-hydra)

(defhydra hydra-zoom (global-map "<f2>")
  "zoom"
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))

Games

asm-blox

  • A really cool TIS-100 like game made for Emacs, asm-blox
(straight-use-package '(asm-blox :host github :repo "zkry/asm-blox"))

Graphviz

(setq graphviz-dot-indent-width 4)

EWW

  • Start olivetti mode when using eww
(defun ajr-eww-setup ()
  (olivetti-mode)
  (text-scale-mode)
  (text-scale-increase 3))

(add-hook 'eww-mode-hook #'ajr-eww-setup)

Org Mode

Source Block Indentation

  • This ensures that org-mode does not modify the indentation of a source block
(setq org-src-preserve-indentation t)
(setq org-src-tab-acts-natively t)

Elfeed

Elfeed Key Map

(with-eval-after-load 'elfeed
  (define-key elfeed-show-mode-map (kbd "TAB") #'shr-next-link)
  (define-key elfeed-show-mode-map (kbd "o") #'ajr-elfeed-copy-org-link))

Customizations

  • Customizations should be stored in a separate file ~/.emacs-custom.el
  • This should be last to ensure that the ~/.emacs-custom.el can do any local overrides that might be needed
  • Elfeed feeds are defined in ~/.elfeed-feeds.el
  • This should be loaded last to allow for overrides in the the .emacs-custom.el
(setq custom-file "~/.emacs-custom.el")
(load custom-file)

(load "~/.elfeed-feeds.el")

Common Customizations

  • confirm-kill-emacs - y-or-n-p
  • Set the theme to modus-vivendi or modus-operandi
  • Change the font to Hack 12 point
  • Change the variable-pitch face to Noto Serif
  • Set the bongo-default-directory to ~/music
  • Set the bongo-enabled-backends to vlc
  • Change the browse-url-browser-function to 'eww-browse-url
  • Set the efleed-sort-order to 'ascending
  • Set the initial-buffer-choice to ~/
  • Set menu-bar-mode to nil
  • Set tool-bar-mode to nil
  • Set tab-bar-show to nil
  • Set visible-bell to t
  • Edit the org-babel-load-languages to enable: C, shell, ditaa, lisp
  • Set org-hide-emphasis-markers to t
  • Set org-startup-folded to 'content
  • Set org-agenda-files to ~/org
  • Set save-place-mode to t
  • Set shr-image-animate to nil to disable animated gifs in shr
  • Set recenter-positions to '(top middle bottom)