Email: contact@adchari.dev
Sourcehut: adchari
LinkedIn: adithyachari
Résumé: Click Here
;; Let's start with some things that directly change how Emacs works...
;; Increase GC limit to 10MB and enable garbage collection on loss of focus
(setq gc-cons-threshold 100000000)
(add-function :after after-focus-change-function 'garbage-collect)
;; Natively compile .emacs.el when the file is saved
(defun autocompile nil
"Compile itself if ~/.emacs.el."
(interactive)
(require 'comp)
(let ((dotemacs (file-truename user-init-file)))
(if (string= (buffer-file-name) (file-chase-links dotemacs))
(native-compile dotemacs))))
(add-hook 'after-save-hook 'autocompile)
;; Store all backup and autosave files in the tmp dir
(setq backup-directory-alist `((".*" . ,temporary-file-directory))
auto-save-file-name-transforms `((".*" ,temporary-file-directory t)))
;; Make sure Emacs auto-reverts files
(global-auto-revert-mode)
;; Move custom.el bindings to an .emacs.d/ file
(setq custom-file "~/.emacs.d/custom.el")
(load custom-file :noerror)
;; Enable some disabled features
(put 'narrow-to-region 'disabled nil)
;; Now, time to configure package management...
;; Add MELPA support and require use-package
(require 'package)
(require 'use-package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
;; Enable no-littering to clean up .emacs.d
(use-package no-littering)
;; Aaand, let's make things look pretty...
;; First, maximize Emacs on open
(setq initial-frame-alist '((fullscreen . maximized))
default-frame-alist '((fullscreen . maximized)))
;; Now, let's get rid of the cruft
(tool-bar-mode -1)
(scroll-bar-mode -1)
(menu-bar-mode -1)
(setq inhibit-startup-screen t
initial-major-mode 'fundamental-mode
use-short-answers t)
(setq-default cursor-type 'bar
indent-tabs-mode nil
tab-width 4)
;; Emacs 29 comes with fancy smooth-scrolling, enable it
(setq pixel-scroll-precision-large-scroll-height 40.0
pixel-scroll-precision-interpolation-factor 30)
(pixel-scroll-precision-mode)
;; Emacs 28+ has modus-vivendi, set up dark mode theme
(setq modus-themes-italic-constructs t
modus-themes-toggle '(modus-vivendi modus-operandi))
(load-theme 'modus-vivendi)
;; The bell sound is horrible, give a visual cue instead
(setq visible-bell nil
ring-bell-function 'flash-mode-line)
(defun flash-mode-line ()
"Temporarily invert mode line."
(invert-face 'mode-line)
(run-with-timer 0.1 nil #'invert-face 'mode-line))
;; How about some quality-of-life keybindings...
(global-set-key (kbd "C-c r") #'rgrep) ; Get easy access to rgrep
(global-set-key (kbd "C-c q") #'modus-themes-toggle) ; Flip the theme to light-mode and back
(global-set-key (kbd "C-c y") #'calc) ; Quick call to the calculator
(global-set-key (kbd "C-c #") #'display-line-numbers-mode) ; Create a toggle for line numbers
(global-set-key (kbd "C-x C-b") #'ibuffer) ; Use ibuffer over the regular buffer menu
;; Package time, let's start with necessities...
;; Ace-Window makes it very easy to jump between buffers
(use-package
ace-window
:bind ("C-<tab>" . ace-window)
:init (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
;; Aggressive-indent is self-explanatory, always indent everything
(use-package
aggressive-indent
:config
(global-aggressive-indent-mode 1))
;; Avy allows a bunch of different jump commands
(use-package
avy
:bind (("C-c j j" . avy-goto-char-2)
("C-c j l" . avy-goto-line)))
;; bm enables visual bookmarks that you can jump to
(use-package
bm
:bind (("C-c b b" . bm-toggle)
("C-c b n" . bm-next)
("C-c b p" . bm-previous)
("C-c b l" . bm-show-all)
("C-c b s" . bm-buffer-save))
:init
(setq-default bm-buffer-persistence t)
(setq bm-highlight-style 'bm-highlight-only-fringe
bm-restore-repository-on-load t
bm-repository-file "~/.emacs.d/bm-repository"
bm-cycle-all-buffers t))
;; Cape to extend emacs' completion-at-point capabilities
(use-package
cape
:init
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-keyword)
(add-to-list 'completion-at-point-functions #'cape-history)
(add-to-list 'completion-at-point-functions #'cape-dict))
;; Corfu as a light auto-complete platform
(use-package
corfu
:init
(setq corfu-auto t
corfu-quit-no-match 'separator
tab-always-indent 'complete
completion-cycle-threshold 5)
(global-corfu-mode)
(corfu-popupinfo-mode))
;; Deadgrep (requires ripgrep) is a fast file search tool
(use-package
deadgrep
:commands deadgrep
:bind ("C-c s" . deadgrep))
;; eglot is a LSP program for Emacs-lisp-mode
(use-package eglot)
;; God Mode makes it easy to enter long command strings
(use-package
god-mode
:bind (([escape] . god-mode-all)
:map god-local-mode-map
("." . repeat))
:init (setq god-mode-enable-function-key-translation nil)
:config
(add-hook 'god-mode-enabled-hook (lambda () (setq cursor-type 'hbar)))
(add-hook 'god-mode-disabled-hook (lambda () (setq cursor-type 'bar))))
;; Magit for git integration because it's amazing
(use-package
magit
:bind ("C-c g" . magit-status)
:init (setq smerge-command-prefix "\C-cv"))
;; Multiple-cursors is self explanatory
(use-package
multiple-cursors
:bind (("C-c m" . mc/edit-lines)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
("C-c C->" . mc/mark-all-like-this)))
;; Neotree is a sidebar file window
(use-package
neotree
:bind ("C-c n" . neotree-toggle)
:config
(setq neo-window-fixed-size t
neo-theme 'arrow))
;; Smartparens pairs all parentheses for you and highlights them
(use-package
smartparens
:config (smartparens-global-mode t))
;; Vterm is a better Emacs terminal
(use-package
vterm
:bind (("C-c t" . vterm-other-window)
:map vterm-mode-map
("C-q" . vterm-send-next-key)))
;; Vundo exposes a visual tree of all the available undo paths
(use-package
vundo
:commands vundo
:bind ("C-c u" . vundo)
:init (setq vundo-compact-display t))
;; Which-key pops up a buffer with command completions
(use-package
which-key
:config
(which-key-mode)
(which-key-setup-side-window-bottom))
;; Yasnippet lets you make little text snippets and insert them everywhere
(use-package
yasnippet
:init (setq yas-snippet-dirs '("~/.emacs.d/snippets/"))
:config (yas-global-mode 1))
;; Zoom-mode automatically resizes windows to focus on the point
(use-package
zoom
:init
(setq zoom-size '(0.618 . 0.618)
zoom-ignored-major-modes '(dired-mode vundo-mode)
zoom-ignored-buffer-name-regexps '("^*calc"))
:config (zoom-mode 1))
;; Now, let's get some language support for writing code...
;; First, let's set up Rust support
(use-package
rust-mode
:mode ("\\.rs\\'")
:hook (rust-mode . eglot-ensure)
:config
(setq rust-format-on-save t)
(add-hook 'flycheck-mode-hook #'flycheck-rust-setup)
(cargo-minor-mode))
;; Setting up Python support
(use-package
python
:mode ("\\.py\\'" . python-mode)
:hook (python-mode . eglot-ensure))
;; Set up ein for iPython notebooks
(use-package
ein
:commands (ein:run ein:login)
:init (setq ein:output-area-inlined-images t))
;; Set up Julia support
(use-package
julia-mode
:mode ("\\.jl\\'")
:hook (julia-mode . eglot-ensure))
(use-package
julia-repl
:hook (julia-repl-mode . julia-mode))
(use-package
eglot-jl
:config (eglot-jl-init))
;; Set up LaTeX mode
(use-package
tex
:mode ("\\.tex\\'" . latex-mode)
:hook (latex-mode . eglot-ensure)
:config
(setq TeX-auto-save t
TeX-parse-self t
TeX-save-query nil)
(TeX-global-PDF-mode t)
(flymake-mode))
;; Markup Language Modes
(use-package
csv-mode
:mode ("\\.csv\\'"))
(use-package
json-mode
:mode ("\\.json\\'")
:init (setq js-indent-level 2))
(use-package
yaml-mode
:mode ("\\.yaml\\'"))
;; PDF/EPUB support
(use-package
nov
:mode ("\\.epub\\'" . nov-mode))
(use-package
pdf-tools
:mode ("\\.pdf\\'" . pdf-view-mode)
:config (pdf-tools-install))
;; Finally, set up all the other applications I use Emacs for...
;; Org mode is a all-in-one life management system
(use-package
org
:mode ("\\.org\\'" . org-mode)
:bind (("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c c" . org-capture))
:init
(setq org-agenda-files '("~/org")
org-default-notes-file "~/org/inbox.org"
org-refile-targets '((org-agenda-files :maxlevel . 2))
org-support-shift-select t
org-startup-indented t
org-agenda-skip-deadline-prewarning-if-scheduled t
org-agenda-skip-deadline-if-done t)
(setq org-agenda-time-grid
'((daily today require-timed remove-match)
(800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000)
"......" "----------------"))
(setq org-babel-load-languages
'((python . t)
(emacs-lisp . t)))
(setq org-capture-templates
'(("t" "todo" entry (file+headline "~/org/inbox.org" "Inbox")
"*** TODO %?\nSCHEDULED: %t")
("l" "Linked todo" entry (file+headline "~/org/inbox.org" "Inbox")
"*** TODO %?\nSCHEDULED: %t\n%a")
("s" "Scheduled todo" entry (file+headline "~/org/inbox.org" "Inbox")
"*** TODO %?\nSCHEDULED: %^t")
("a" "Assignment" entry (file+headline "~/org/inbox.org" "Inbox")
"*** TODO %?\nDEADLINE: %^t SCHEDULED: %^t")
("c" "Calendar Event" entry (file+headline "~/org/inbox.org" "Inbox")
"*** %?\n%^T")
("g" "Weekly Goal" entry (file+headline "~/org/goals.org" "Weekly")
"*** Goal %(org-insert-time-stamp (org-read-date nil t \"+1w\"))\n - [ ] %?")
("n" "Note" entry (file+olp+datetree "~/org/notes.org")
"* %? %^G\n%U")))
(setq org-agenda-custom-commands
'(("T" "Tasks" agenda ""
((org-agenda-overriding-header "Tasks")
(org-agenda-span 'week)
(org-agenda-time-grid nil)
(org-agenda-show-all-dates nil)
(org-agenda-entry-types
'(:deadline :scheduled))))
("W" "Upcoming Week" agenda ""
((org-agenda-overriding-header "Upcoming Week")
(org-agenda-span 'week)
(org-agenda-start-on-weekday nil)
))
("M" "Upcoming Month" agenda ""
((org-agenda-overriding-header "Upcoming Month")
(org-agenda-span 'month)
(org-agenda-show-all-dates nil)
))
("L" "Look Around" agenda ""
((org-agenda-overriding-header "Look Around")
(org-agenda-span 5)
(org-agenda-start-on-weekday nil)
(org-agenda-start-day "-2d")
)))))
;; Ledger mode allows financial tracking in Emacs
(use-package
ledger-mode
:mode ("\\.dat\\'"
"\\.ledger\\'")
:config
(flycheck-mode)
(setq ledger-clear-whole-transactions t
ledger-complete-in-steps t)
(setq ledger-reports
'(("SOTU" "%(binary) -f %(ledger-file) -V --price-db prices.db --sort \"-abs(T)\" --cleared bal Assets Liabilities")
("SOTF" "%(binary) -f %(ledger-file) -V --price-db prices.db --sort \"-abs(T)\" bal Assets Liabilities")
("SOTB" "%(binary) -f %(ledger-file) -V --price-db prices.db --sort \"-abs(T)\" bal Assets:Schwab:Checking Liabilities")
("ThisMonth" "%(binary) -f %(ledger-file) -p \"this month\" --monthly --budget bal expenses")
("LastMonth" "%(binary) -f %(ledger-file) -p \"last month\" --monthly --budget bal expenses")
("NetBudget" "%(binary) -f %(ledger-file) -p \"this year\" --budget bal expenses")
("Expenses" "%(binary) -f %(ledger-file) -p \"this month\" bal Expenses")
("LastExpenses" "%(binary) -f %(ledger-file) -p \"last month\" bal Expenses")
("NetExpenses" "%(binary) -f %(ledger-file) -p \"this year\" bal Expenses")
("Balance" "%(binary) -f %(ledger-file) -V --price-db prices.db --cleared bal")
("equity" "%(binary) -f %(ledger-file) equity"))))
;; Notmuch is an email client for Emacs
(use-package notmuch
:commands notmuch
:bind ("C-c e" . notmuch)
:init
(setq user-full-name "Adithya Chari"
user-mail-address "adithya.chari@gmail.com"
mail-user-agent 'message-user-agent
smtpmail-smtp-server "smtp.gmail.com"
smtpmail-stream-type 'ssl
smtpmail-smtp-service 465
smtpmail-debug-info t
message-directory "~/mail/"
message-auto-save-directory "~/mail/drafts"
message-default-mail-headers "Cc: \nBcc: \n"
message-send-mail-function 'message-smtpmail-send-it
message-kill-buffer-on-exit t
notmuch-show-logo nil)
:config
(define-key notmuch-show-mode-map "d"
(lambda () (interactive)
(if (member "trash" (notmuch-show-get-tags))
(notmuch-show-tag (list "-trash"))
(notmuch-show-tag (list "+trash")))))
(define-key notmuch-search-mode-map "d"
(lambda (&optional beg end)
"toggle deleted tag for message"
(interactive (notmuch-interactive-region))
(if (member "trash" (notmuch-search-get-tags))
(notmuch-search-tag (list "-trash") beg end)
(notmuch-search-tag (list "+trash") beg end))))
(setq notmuch-saved-searches
'((:name "inbox" :query "tag:inbox" :key "i")
(:name "unread" :query "tag:unread" :key "u")
(:name "action" :query "tag:action" :key "a")
(:name "receipt" :query "tag:receipt" :key "r")
(:name "cal" :query "tag:cal" :key "c")
(:name "notifications" :query "tag:notifications" :key "n")
(:name "drafts" :query "tag:drafts" :key "d")
(:name "all mail" :query "*" :key "m"))))
;; Elfeed is a newsfeed/RSS reader
(use-package
elfeed
:commands elfeed
:bind ("C-c w" . elfeed)
:config
(setq-default elfeed-search-filter "@1-day-ago +unread -list #50 ")
(define-key elfeed-search-mode-map "l" #'(lambda () (interactive) (elfeed-search-set-filter "+unread +list ")))
(define-key elfeed-search-mode-map "k" #'(lambda () (interactive) (elfeed-search-set-filter nil)))
(define-key elfeed-search-mode-map "m" #'(lambda () (interactive) (elfeed-search-tag-all 'list)))
(define-key elfeed-search-mode-map "," #'(lambda () (interactive) (elfeed-search-untag-all 'list)))
(define-key elfeed-search-mode-map (kbd "SPC") #'elfeed-search-untag-all-unread)
(setq elfeed-feeds
'(("https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml" news NYT)
("https://rss.nytimes.com/services/xml/rss/nyt/US.xml" news NYT)
("https://rss.nytimes.com/services/xml/rss/nyt/World.xml" news NYT)
("https://rss.nytimes.com/services/xml/rss/nyt/Politics.xml" news NYT)
("https://rss.nytimes.com/services/xml/rss/nyt/Economy.xml" economy NYT)
("https://rss.nytimes.com/services/xml/rss/nyt/Technology.xml" tech NYT)
("https://rss.nytimes.com/services/xml/rss/nyt/EnergyEnvironment.xml" NYT)
("https://rss.nytimes.com/services/xml/rss/nyt/YourMoney.xml" NYT)
("https://www.nytimes.com/svc/collections/v1/publish/www.nytimes.com/column/thomas-l-friedman/rss.xml" NYT ThomasFriedman)
("https://www.nytimes.com/svc/collections/v1/publish/www.nytimes.com/column/ezra-klein/rss.xml" NYT EzraKlein)
("https://www.nytimes.com/svc/collections/v1/publish/www.nytimes.com/column/paul-krugman/rss.xml" NYT PaulKrugman)
("https://feeds.a.dj.com/rss/RSSWorldNews.xml" news WSJ)
("https://feeds.a.dj.com/rss/RSSMarketsMain.xml" economy WSJ)
("https://feeds.a.dj.com/rss/WSJcomUSBusiness.xml" economy WSJ)
("https://feeds.a.dj.com/rss/RSSWSJD.xml" tech WSJ)
("https://feeds.a.dj.com/rss/RSSOpinion.xml" opinion WSJ)
("https://www.reddit.com/.rss" Reddit)
("https://www.reddit.com/r/emacs/.rss" emacs Reddit)
("https://www.reddit.com/r/news/.rss" news Reddit)
("https://www.reddit.com/r/finance/.rss" economy Reddit)
("https://www.reddit.com/r/technology/.rss" tech Reddit)
("https://news.ycombinator.com/rss" HN)
("https://astralcodexten.substack.com/feed" AstralCodexTen)
("https://www.notboring.co/feed" NotBoring)
("https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine.rss" economy MattLevine)
("https://sachachua.com/blog/category/emacs-news/feed/" emacs SachaChua)
("https://braddelong.substack.com/feed" economy BradDelong)
("https://cms.zerohedge.com/fullrss2.xml" ZeroHedge)
("https://effectiveaccelerationism.substack.com/feed" tech BeffJezos)
("https://chamath.substack.com/feed" tech Chamath)
("https://robertreich.substack.com/feed" politics RobReich)
("https://www.messageboxnews.com/feed" politics DanPfeiffer)
("https://adamtooze.substack.com/feed" economics ChartBook)
("https://danjones.substack.com/feed" history DanJones))))