Skip to content

elamdf/emacs.d

Repository files navigation

Elam’s emacs Configuration

Startup & UI Basics

  (setq inhibit-startup-message t)
  (shell-command "git submodule update --init")
;; we launch in daemon mode, but want these enabled for when we attach
;;  (when (display-graphic-p)
    (setq visible-bell t)                 ; no audible bell
    (setq split-width-threshold 1)        ; prefer vertical splits
    (scroll-bar-mode -1)                  ; hide scroll bar
    (tool-bar-mode   -1)                  ; hide toolbar
    (tooltip-mode   -1)                   ; hide tooltips
    (set-fringe-mode 10)                  ; extra margin
    (menu-bar-mode   -1)                  ; hide menu bar
    (defvar elamdf/fixed-width-font  "Fira Code Retina"
      "The font to use for monospaced (fixed width) text.")
    (defvar elamdf/variable-width-font "Iosevka Aile"
      "The font to use for variable-pitch (document) text.")
    (set-face-attribute 'default nil :font elamdf/fixed-width-font :height 140)
;;)

Personal Modules & Paths

;; Load personal machine‑specific tweaks
(load (concat user-emacs-directory "elam-personal-mac.el"))
;; Private libraries
(add-to-list 'load-path (concat user-emacs-directory "/lisp"))

(add-to-list 'load-path (concat user-emacs-directory "/bismuth"))
(add-to-list 'load-path (concat user-emacs-directory "/flyover"))


(require 'user)                         ; personal helpers
(require 'typewriter-mode)

;; make sure things are available on PATH
(use-package exec-path-from-shell)
(exec-path-from-shell-initialize)

Package Management

(defvar bootstrap-version)
(let\* ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el"
                                          (or (bound-and-true-p straight-base-dir)
                                              user-emacs-directory)))
        (bootstrap-version 7))
       (unless (file-exists-p bootstrap-file)
         (with-current-buffer
             (url-retrieve-synchronously
              "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
              'silent 'inhibit-cookies)
           (goto-char (point-max))
           (eval-print-last-sexp)))
       (load bootstrap-file nil 'nomessage))
(require 'package)
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
                         ("org"   . "https://orgmode.org/elpa/")
                         ("elpa"  . "https://elpa.gnu.org/packages/")))
(package-initialize)
(unless package-archive-contents (package-refresh-contents))
(load-library "server")
(unless (server-running-p) (server-start))
(unless (package-installed-p 'use-package) (package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t
      package-install-upgrade-built-in t)

Core Editor Defaults

(column-number-mode)
(which-key-mode)
(global-display-line-numbers-mode t)
(setq display-line-numbers 'relative)
(setq switch-to-buffer-obey-display-actions t)
(add-hook 'before-save-hook #'delete-trailing-whitespace)
(use-package command-log-mode)
;; Disable line numbers where they get in the way
(dolist (hook '(org-mode-hook term-mode-hook shell-mode-hook eshell-mode-hook))
  (add-hook hook (lambda () (display-line-numbers-mode 0))))

UI, Completion & Navigation

(use-package company)
(use-package doom-themes :init (load-theme 'doom-palenight t))
(use-package doom-modeline :init (doom-modeline-mode 1) :custom ((doom-modeline-height 25)))
(setq mac-command-modifier 'meta)
(use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode))
(setq-default indent-tabs-mode nil)
(use-package markdown-mode
  :mode ("README\\.md\\'" . gfm-mode)
  :init (setq markdown-command "multimarkdown")
  :bind (:map markdown-mode-map ("C-c C-e" . markdown-do)))
(defun elamdf/markdown-no-comment-start ()
  (setq-local comment-start nil))
(add-hook 'markdown-mode-hook #'elamdf/markdown-no-comment-start)

;; casual
(use-package general)
(use-package casual ;; A collection of  user interfaces for various built-in Emacs modes.
  :config
  (require 'casual-calc)
  (require 'casual-dired)
  (require 'casual-agenda)
  (require 'casual-image)
  (require 'casual-ibuffer)
  (require 'casual-info)
  (require 'casual-make)
  :general
  (:keymaps 'org-agenda-mode-map "C-o" 'casual-agenda-tmenu)
  (:keymaps 'bookmark-bmenu-mode-map "C-o" 'casual-bookmarks-tmenu)
  (:keymaps 'calc-mode-map "C-o" 'casual-calc-tmenu)
  (:keymaps 'dired-mode-map "C-o" 'casual-dired-tmenu)
  (:keymaps 'make-mode-map "C-o" 'casual-make-tmenu)
  (:keymaps 'Info-mode-map "C-o" 'casual-info-tmenu))

Completion

;; --- UI: keep completion in the minibuffer ---
(use-package vertico
  :init (vertico-mode 1))

;; --- Matching: nice flexible patterns (optional but popular) ---
(use-package orderless
  :init
  (setq completion-styles '(orderless basic)
        completion-category-defaults nil
        ;; Keep file completion sensible (don’t split paths on /)
        completion-category-overrides '((file (styles basic partial-completion)))))

;; --- Sources/commands + preview control ---
(use-package consult
  :bind (("C-M-s"   . consult-line)     ; search in buffer
         ("M-i"   . consult-imenu))   ; symbols in buffer
  )

;; use better ripgrep
(with-eval-after-load 'projectile
  (advice-add 'projectile-ripgrep :override #'consult-ripgrep))

        ;;; --- ripgrep completion in minibuffer & tame previews ---
(vertico-mode 1)                            ; or (fido-vertical-mode 1)
(setq completion-auto-help nil)             ; don't pop *Completions*
(setq consult-preview-key nil)              ; no auto preview panes
(global-set-key (kbd "C-g") #'keyboard-escape-quit)

        ;;; --- Consult takes over buffer switching ---
(global-set-key (kbd "C-x b")   #'consult-buffer)
(global-set-key (kbd "C-x 4 b") #'consult-buffer-other-window)
(global-set-key (kbd "C-x 5 b") #'consult-buffer-other-frame)

;; Bonus: project-aware buffer list on a separate key
(global-set-key (kbd "C-x B")   #'consult-project-buffer)
(global-set-key (kbd "C-x C-f") #'consult-find)

;; Handy extras
(global-set-key (kbd "C-x C-r") #'consult-recent-file)   ; open recent files
(global-set-key (kbd "M-g g")   #'consult-goto-line)     ; nicer goto-line

        ;;; --- Case-insensitive completion for files/buffers (nice QoL) ---
(setq read-buffer-completion-ignore-case t
      read-file-name-completion-ignore-case t
      completion-ignore-case t)

(with-eval-after-load 'vertico
  (require 'vertico-directory)
  ;; Make Backspace delete the whole folder component, not one char
  (define-key vertico-map (kbd "DEL") #'vertico-directory-delete-word)
  ;; Optional: extra directory niceties
  (define-key vertico-map (kbd "C-l")  #'vertico-directory-up)        ; go up directory
  (define-key vertico-map (kbd "RET")  #'vertico-directory-enter))    ; enter directory

(use-package emacs
  :ensure nil
  :init
  (setq tab-always-indent 'complete)) ;; enable tab completionh

Project & Version Control

(use-package projectile
  :diminish projectile-mode
  :config (projectile-mode)
  :custom (projectile-completion-system 'default)
  :bind-keymap ("C-c p" . projectile-command-map)
  :init
  (setq projectile-project-search-path '("~/bwrc" "~/Documents"))
  (setq projectile-switch-project-action #'projectile-dired))
(use-package consult-projectile
  :straight (consult-projectile :type git :host gitlab :repo "OlMon/consult-projectile" :branch "master"))
(use-package magit :commands magit-status)
(use-package forge :after magit)
(use-package pr-review :after magit)
(setq auth-sources '("\~/.authinfo"))
;; use consult instead of projectile ripgrep
  ;; (global-set-key (kbd "C-c p s r") 'consult-ripgrep)

Language & LSP Support

  (use-package eglot
    :ensure t
    :hook ((( scala-mode python-mode rust-mode)
            . eglot-ensure)
           ((cider-mode eglot-managed-mode) . eglot-disable-in-cider))
    :preface
    (defun eglot-disable-in-cider ()
      (when (eglot-managed-p)
        (if (bound-and-true-p cider-mode)
            (progn
              (remove-hook 'completion-at-point-functions 'eglot-completion-at-point t)
              (remove-hook 'xref-backend-functions 'eglot-xref-backend t))
          (add-hook 'completion-at-point-functions 'eglot-completion-at-point nil t)
          (add-hook 'xref-backend-functions 'eglot-xref-backend nil t))))
    :custom
    (eglot-autoshutdown t)
    (eglot-events-buffer-size 0)
    (eglot-extend-to-xref nil))

  ;; checks
  (use-package flycheck)
  (global-flycheck-mode)
  ;; flyover for prettier inline syntax checks
  (require 'flyover)
  (add-hook 'flycheck-mode-hook #'flyover-mode)
  (setq flyover-checkers '(flycheck flymake))


  ;; Use theme colors for error/warning/info faces
  (setq flyover-use-theme-colors t)

  ;; Adjust background lightness (lower values = darker)
  (setq flyover-background-lightness 45)

  ;; Make icon background darker than foreground
  (setq flyover-percent-darker 40)

  (setq flyover-text-tint 'lighter) ;; or 'darker or nil

  ;; "Percentage to lighten or darken the text when tinting is enabled."
  (setq flyover-text-tint-percent 50)
  (setq flyover-levels '(error))    ; Show only errors and warnings

(use-package calyx-mode
  :straight (calyx-mode :host github :repo "sgpthomas/calyx-mode"))
(use-package platformio-mode)

python lsp stuff

  (use-package python
    :config
    ;; Remove guess indent python message
    (setq python-indent-guess-indent-offset-verbose nil))

  ;; Hide the modeline for inferior python processes.  This is not a necessary
  ;; package but it's helpful to make better use of the screen real-estate at our
  ;; disposal. See: https://github.com/hlissner/emacs-hide-mode-line.

  (use-package hide-mode-line
    :ensure t
    :defer t
    :hook (inferior-python-mode . hide-mode-line-mode))

(use-package blacken
  :ensure t
  :defer t
  :custom
  (blacken-allow-py36 t)
  (blacken-skip-string-normalization t)
  :hook (python-mode-hook . blacken-mode))

Systemverilog lsp stuff

(use-package verilog-ext
  :hook ((verilog-mode . verilog-ext-mode))
  :init
  ;; Can also be set through `M-x RET customize-group RET verilog-ext':
  ;; Comment out/remove the ones you do not need
  (setq verilog-ext-feature-list
        '(font-lock
          xref
          capf
          hierarchy
          eglot
          flycheck
          beautify
          navigation
          template
          formatter
          compilation
          imenu
          which-func
          hideshow
          typedefs
          time-stamp
          block-end-comments
          ports))
  :config
  (verilog-ext-mode-setup))

Org Mode Configuration

(setq org-ellipsis ""
      org-startup-folded 'content
      org-cycle-separator-lines 2
      org-fontify-quote-and-verse-blocks t)
(add-hook 'org-mode-hook #'org-indent-mode)
(org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (shell . t)))
(setq org-directory elamdf/projects-dir)
(setq org-default-notes-file (concat org-directory "/notes.org"))
(use-package org-tempo :ensure nil :demand t)
(dolist (tpl '(("sh" . "src sh")
               ("el" . "src emacs-lisp")
               ("li" . "src lisp")
               ("sc" . "src scheme")
               ("ts" . "src typescript")
               ("py" . "src python")
               ("yaml" . "src yaml")
               ("json" . "src json")))
  (add-to-list 'org-structure-template-alist tpl))
(setq org-deadline-warning-days 1
      org-use-fast-tag-selection t)
(setq org-tag-alist '(("arch" . ?a) ("courses" . ?c) ("ic" . ?i) ("misc" . ?m) ("references" . ?r)))
;; Capture & Refile templates


(use-package fold-and-focus
  :demand t
  :straight (fold-and-focus :type git :host nil :repo
                            "https://git.sr.ht/~flandrew/fold-and-focus")
  :config
  (global-fold-and-focus-org-mode)
  (global-fold-and-focus-md-mode)
  (global-fold-and-focus-el-mode))

;;
(global-set-key (kbd "M-+") 'elamdf/org-word-count)
(global-set-key (kbd "C-M-s") 'consult-line)
(global-set-key (kbd "C-s") 'isearch-forward-regexp)
(global-set-key (kbd "C-r") 'isearch-backward-regexp)

;; make indentation work properly
(setq org-src-tab-acts-natively t)

Org Capture templates and bindings

(setq org-capture-templates
      '(("r" "Read" entry
         (file+headline (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "Reading List")
         "* READ %^{Title} by %^{Author} %^g: \n - Entered on %U\n  %?")


        ("w" "Watch" entry
         (file+headline  (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "Watch List")
         ;; (file+headline (expand-file-name "capture.org" elamdf/projects-dir) "Watch List")

         "* WATCH %^{Title} %^g:\n Link: %^{URL}\n  - Entered on %U\n  %?")

        ("t" "TODO" entry (file+olp  (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "TODO todos")
         "* TODO %U %i %?" :empty-lines-after 1)

        ("l" "Log" entry (file+olp  (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "Log")
         "* %U %i %?" :empty-lines-after 1)
        ("i" "Idea" entry (file+olp  (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "Ideas")
         "* IDEA %U %?" :empty-lines-after 1)
        ("s" "Quote" entry (file+olp  (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "Quotes")
         "* %U \"%i%?\"" :empty-lines-after 1)
        ("R" "Read from Zotero" entry (file+olp  (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "Reading List")
         "* READ %(elamdf/zotero-latest-capture-string)
            - Entered on %U
            %?" :empty-lines-after 1)
        ("e" "Elfeed article" entry
         (file+olp  (lambda () (expand-file-name "notes.org" elamdf/projects-dir)) "Reading List")
         "* [[%:link][%:description]]
:PROPERTIES:
:LINK: %:link
:AUTHOR: %:authors
:END: \n%?" :empty-lines-after 1)))
(defun elamdf/org-capture-elfeed ()
  (interactive)
  (org-capture nil "e"))
(setq org-agenda-sorting-strategy
      '((agenda user-defined-up) (todo user-defined-up)
        (tags urgency-down category-keep) (search category-keep))
      )
(setq org-agenda-cmp-user-defined 'elamdf/compare-todo-status)

(defun elamdf/capture-open-message ()
  (progn (message "\"if one holds onto every glimmer of genius for years, then even the dullest person may look a bit like a genius himself\"") ()))
(add-hook 'org-capture-mode-hook #'elamdf/capture-open-message)

(setq org-agenda-files (directory-files-recursively elamdf/projects-dir "^[a-z0-9]*.org$"))

(setq org-refile-targets '((nil :maxlevel . 9)
                           (org-agenda-files :maxlevel . 9)))
(setq org-outline-path-complete-in-steps nil)         ; Refile in a single go
(setq org-refile-use-outline-path t)                  ; Show full paths for refiling

(use-package zotxt :after org)
(setq org-todo-keywords '((sequence "TODO(t)" "WAIT(w@/!)" "WATCH(v)" "READ(r)" "|" "DONE(d!)" "CANCELED(c@)")))
(setq org-todo-keyword-faces '(("READ" . "dark green") ("IDEA" . "white") ("WATCH" . "dark blue")))
(setq org-src-fontify-natively t)
(use-package htmlize)
(setq org-export-publishing-directory "./assets")
(org-babel-do-load-languages
 'org-babel-load-languages
 '((python . t)))

(use-package ox-reveal) ; reveal js presentations!n
(setq org-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js")
(setq org-hide-emphasis-markers t)

(use-package org-present)

(add-hook 'org-present-mode-hook #'(lambda ()
                                     (progn
                                       (olivetti-mode t)
                                       (visual-line-mode t))
                                     ))

Keybindings & Shortcuts

(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
(global-set-key (kbd "C-c ;")   #'replace-regexp)
(define-key org-mode-map (kbd "C-c ;")   #'replace-regexp)
;; GPTel
(global-set-key (kbd "C-c s") #'gptel-menu)
(global-set-key (kbd "C-c g") #'gptel)
;; Org
(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)

(global-set-key (kbd "C-c m") #'elamdf/create-meeting-notes-file)
;; Bismuth
(global-set-key (kbd "C-c t") #'inline-cr-list-all-actionables)

;; elfeed
(global-set-key (kbd "C-x w w") #'elfeed)

;; Disable arrow keys
(dolist (k '("<left>" "<right>" "<up>" "<down>"))
  (global-unset-key (kbd k)))
(use-package backward-forward
  :ensure t
  :demand t
  :config
  (backward-forward-mode t)
  :bind
  (:map backward-forward-mode-map
        ("<left>" . backward-forward-previous-location)
        ("<right>" . backward-forward-next-location)))

Conda & Environment

(use-package conda)
(conda-env-initialize-interactive-shells)
(conda-env-initialize-eshell)

Tramp & Remote Editing

(use-package tramp
  :defer t
  :custom
  (tramp-default-method "ssh")
  (tramp-default-remote-shell "/bin/bash")
  (tramp-remote-path (append tramp-remote-path '(tramp-own-remote-path)))
  :config
  (add-to-list 'tramp-default-proxies-alist '(nil "\\\`root\\'" "/ssh:%h:")))

Dired & File Management

(defun dw/dired-mode-hook ()
  (dired-hide-details-mode 1)
  (hl-line-mode 1))
(use-package dired :ensure nil
  :bind (:map dired-mode-map ("b" . dired-up-directory))
  :config
  (setq dired-listing-switches "-alv"
        dired-omit-files "^\\..\*\~?\$"
        dired-dwim-target 'dired-dwim-target-next
        delete-by-moving-to-trash t))
(add-hook 'dired-mode-hook #'dw/dired-mode-hook)
(add-hook 'dired-mode-hook #'dired-omit-mode)
;; Ripgrep everywhere
(setq xref-search-program 'ripgrep
      grep-command "rg -nS --noheading")

Snippets & Templates

(use-package yasnippet
  :hook ((text-mode prog-mode conf-mode snippet-mode) . yas-minor-mode)
  :init (setq yas-snippet-dirs (list (concat user-emacs-directory "/yasnippet-snippets/snippets"))))
(yas-global-mode)
;; Auto‑jump out of snippets
(defun yas/field-skip-once ()
  (ignore-errors (yas/next-field))
  (remove-hook 'post-command-hook #'yas/field-skip-once 'local))
(defun yas/schedule-field-skip ()
  (add-hook 'post-command-hook #'yas/field-skip-once 'append 'local))

GPTel & Ollama Integration

(use-package gptel)
(setq gptel-model 'qwen3:4b
      gptel-backend (gptel-make-ollama "Qwen 3 4B" :host "localhost:11434" :stream t :models '(qwen3:4b)))
(add-hook 'gptel-post-response-functions #'gptel-end-of-response)
(add-hook 'gptel-before-send-hook       #'elamdf/ensure-ollama-running)
(defun elamdf/advise-gptel-commands ()
  "Ensure Ollama is running before any \`gptel-' command."
  (dolist (sym (apropos-internal "^gptel-" 'commandp))
    (advice-add sym :before #'elamdf/ensure-ollama-running)))
(elamdf/advise-gptel-commands)

Bismuth Configuration

(require 'inline-cr)
(require 'brain)
;; Enable inline‑cr in common prose modes
(dolist (hook '(markdown-mode-hook org-mode-hook c-mode-hook))
  (add-hook hook #'inline-cr-mode))

RSS & Elfeed

        (use-package elfeed)
(use-package olivetti) ; nice formatting for text
        (setq elfeed-feeds '("https://people.csail.mit.edu/rachit/post/atom.xml"
                             "https://semianalysis.com/feed/"
                             "https://taylor.town/feed.xml"
                             "http://yummymelon.com/devnull/feeds/tags/emacs.atom.xml"
                             "https://www.chinatalk.media/feed"
                             "https://geohot.github.io/blog/feed"
                             "https://www.sinification.com/feed"
                             "https://elam.day/post/atom.xml"
                             "https://irreal.org/blog/?feed=rss2"))

  (add-hook 'elfeed-show-mode-hook 'olivetti-mode)

    (define-key elfeed-show-mode-map (kbd "w") #'elamdf/org-capture-elfeed)

Miscellaneous

;; Fun motivational quote when opening files
(add-hook 'find-file-hook #'elamdf/show-random-org-quote)
;; Allow 'list-timers' command
(put 'list-timers 'disabled nil)

OS Config things

on macos, invoke scripts/capture.sh by creating an automator script and binding it (under keyboard -> shortcuts -> services -> general) add to ~/.authinfo.gpg

machine <workspace>.slack.com  login token  password xoxc-…    # API token
machine <workspace>.slack.com  login cookie password "xoxd-…; d-s=…; lc=…"  # full cookie header

also run

defaults write org.gnu.Emacs AppleFontSmoothing -int 0

to get cleaner fonts

External dependencies I remember adding

rust-analyzer

update this by doing an install from a fresh mac/windows machine

About

Elam's emacs config

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published