(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)
;;)
;; 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)
(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)
(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))))
(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))
;; --- 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
(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)
(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)
(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))
(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))
(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)
(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))
))
(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)))
(use-package conda)
(conda-env-initialize-interactive-shells)
(conda-env-initialize-eshell)
(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:")))
(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")
(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))
(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)
(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))
(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)
;; 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)
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
rust-analyzer