This file contains all of my emacs configuration in a literate style using org-babel.
In addition to this file the configuration are split into 2 more file:
~/.emacs.d/early-init.el
~/.emacs.d/custom.el
: To avoid polluting my~/.emacs.d/init.el
with autogenerated settings from Custom
Initialize the package archive
(require 'package)
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("org" . "https://orgmode.org/elpa/")
("elpa" . "https://elpa.gnu.org/packages/")))
Have a dedicated file for the Custom settings
(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)
(add-to-list 'default-frame-alist
'(font . "DejaVu Sans Mono-12"))
Some random settings that I find helpful
(fset 'yes-or-no-p 'y-or-n-p)
(setq create-lockfiles nil)
(menu-bar-mode 0)
(tool-bar-mode 0)
(scroll-bar-mode -1)
(blink-cursor-mode 0)
(display-battery-mode 1)
(setq-default cursor-type 'bar)
(setq ring-bell-function 'ignore)
(setq backup-directory-alist `(("." . ,(concat user-emacs-directory
"backups"))))
(setq auto-save-default nil)
(global-hl-line-mode 1)
(subword-mode 1)
(electric-indent-mode +1)
(electric-pair-mode t)
(delete-selection-mode 1)
(global-display-line-numbers-mode 1)
(setq display-line-numbers-type 'relative)
(setq scroll-margin 10)
Automatically switch to the grep buffer
(add-hook 'grep-mode-hook
#'(lambda ()
(switch-to-buffer-other-window "*grep*")))
Opening tmux sessions from emacs at point or at the current directory It mainly utilizes projectile
(defun tmux-session-exists? (session)
(not (string-empty-p (shell-command-to-string (concat "tmux list-sessions 2>&1 | grep " session)))))
(defun open-tmux-session-current-directory ()
(interactive)
(let* ((name (replace-regexp-in-string "\\." "" (projectile-project-name)))
(attach-session? (tmux-session-exists? name)))
(if attach-session?
(start-process-shell-command "tmux" nil (concat "alacritty -e tmux attach -t " name))
(start-process-shell-command "tmux" nil (concat "alacritty -e tmux new-session -s " name)))))
(defun open-tmux-session-current-project-root ()
(interactive)
(let* ((name (replace-regexp-in-string "\\." "" (projectile-project-name)))
(attach-session? (tmux-session-exists? name)))
(if attach-session?
(start-process-shell-command "tmux" nil (concat "alacritty -e tmux attach -t " name))
(start-process-shell-command "tmux" nil (concat "alacritty -e tmux new-session -s " name " -c " (projectile-project-root))))))
(use-package evil
:ensure t
:custom
(evil-undo-system 'undo-redo)
(evil-want-C-u-scroll t)
(evil-want-keybinding nil)
:config
(evil-mode 1)
(evil-set-leader nil (kbd "C-SPC"))
(evil-set-leader 'normal (kbd "SPC")))
(use-package evil-collection
:ensure t
:after evil
:config
(evil-collection-init))
(evil-define-key 'normal lsp-mode-map (kbd "<leader>l") lsp-command-map)
(evil-define-key nil projectile-mode-map (kbd "<leader>p") projectile-command-map)
(evil-define-key nil 'global
(kbd "<leader>sb") 'counsel-switch-buffer
(kbd "<leader>tc") 'open-tmux-session-current-directory
(kbd "<leader>tr") 'open-tmux-session-current-project-root
(kbd "<leader>rg") 'counsel-rg
(kbd "<leader>fzf") 'counsel-fzf
(kbd "<leader>csb") 'counsel-search
(kbd "<leader>ff") 'counsel-find-file)
(use-package gptel
:ensure t
:custom
(gptel-prompt-prefix-alist
'((markdown-mode . "# ")
(org-mode . "")
(text-mode . "# ")))
:config
(setq
gptel-model "gemma2:2b"
gptel-backend (gptel-make-ollama "Ollama"
:host "localhost:11434"
:stream t
:models '("gemma2:2b"))
gptel-default-mode 'org-mode))
(use-package magit
:ensure t)
For themes, doom-themes
is the way to go for me accompanied with doom-modeline
(use-package doom-themes
:ensure t
:config
(setq doom-themes-enable-bold t
doom-themes-enable-italic t)
(load-theme 'doom-tokyo-night t)
(set-face-foreground 'line-number-current-line "#ff9e64"))
(use-package doom-modeline
:ensure t
:init
(doom-modeline-mode 1)
:config
(setq doom-modeline-battery t
doom-modeline-icon t
doom-modeline-major-mode-icon t
doom-modeline-major-mode-color-icon t))
Doom modelines uses nerd-icons
so I need that tool
(use-package nerd-icons
:ensure t)
(use-package prescient
:ensure t
:config
(prescient-persist-mode 1))
Ivy
and counsel
paired with ivy-prescient
for good fuzzy finding and sorting
(use-package ivy
:ensure t
:init
(ivy-mode 1)
(setq projectile-completion-system 'ivy)
(setq ivy-use-virtual-buffers t))
(use-package counsel
:ensure t
:after ivy
:init (counsel-mode 1))
(use-package ivy-prescient
:ensure t
:after (ivy counsel)
:init (ivy-prescient-mode 1))
Projectile, well it’s projectile
(use-package projectile
:ensure t
:init (projectile-mode +1))
Behold the beauty of treesitter
(use-package treesit
:custom
(treesit-font-lock-level 4)
(treesit-extra-load-path `(,(concat (getenv "HOME") "/.emacs.d/dist/"))))
company
and company-prescient
for code completion
(use-package company
:ensure t
:init (global-company-mode))
(use-package company-prescient
:ensure t
:after company
:init (company-prescient-mode 1))
(use-package yasnippet
:ensure t
:config
(yas-global-mode 1))
(use-package eldoc
:ensure t
:hook
(emacs-lisp-mode . turn-on-eldoc-mode)
(lisp-interaction-mode . turn-on-eldoc-mode)
(ielm-mode . turn-on-eldoc-mode))
(use-package paredit
:ensure t
:init
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
(add-hook 'ielm-mode-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)
:config
(show-paren-mode t))
LONG LIVE THE ONE AND TRUE WINDOW MANAGER
(use-package stumpwm-mode
:ensure t)
Mainly for html files
(use-package tagedit
:ensure t)
(defun web-mode-init-hook ()
"Hook for indentation in Web mode"
(setq web-mode-markup-indent-offset 2)
(setq web-mode-code-indent-offset 2)
(setq web-mode-css-indent-offset 2))
(use-package web-mode
:ensure t
:hook
(web-mode . web-mode-init-hook)
:mode ("\\.html?\\'")
:config
(setq web-mode-enable-current-column-highlight t
web-mode-enable-current-element-highlight t
web-mode-enable-auto-closing t
web-mode-enable-auto-pairing t))
Using emacs-29 built-in typescript modes
(use-package add-node-modules-path
:ensure t)
(use-package prettier-js
:ensure t)
(defun prettier-js-hook ()
(when (s-matches?
(rx (or ".js" ".ts" ".jsx" ".tsx") eos)
(buffer-file-name))
(add-node-modules-path)
(prettier-js-mode)))
(use-package typescript-ts-mode
:ensure t
:hook
(typescript-ts-mode . prettier-js-hook)
(tsx-ts-mode . prettier-js-hook)
:mode (("\\.ts\\'" . typescript-ts-mode))
:mode (("\\.tsx\\'" . tsx-ts-mode)))
THE ONE AND TRUE PROGRAMMING LANGUAGE
clojure-mode
paired with cider
(use-package clojure-mode
:ensure t
:after paredit
:mode (("\\.edn$" . clojure-mode)
("\\.boot$" . clojure-mode)
("\\.cljs.*$" . clojurescript-mode)
("\\.cljc.*$" . clojurec-mode)
("lein-env" . enh-ruby-mode)
("\\.boot\\'" . clojure-mode))
:hook
(clojure-mode . enable-paredit-mode)
:custom
(cider-repl-display-help-banner nil))
(use-package cider
:ensure t
:after (clojure-mode paredit eldoc)
:hook
(cider-mode . eldoc-mode)
(cider-repl-mode . paredit-mode)
(clojure-mode . cider-mode)
(cider-repl-mode . paredit-mode)
:config
(setq cider-repl-pop-to-buffer-on-connect t
cider-show-error-buffer t
cider-auto-select-error-buffer t
cider-repl-history-file "~/.emacs.d/cider-history"
cider-repl-wrap-history t))
zig-mode
(use-package zig-mode
:ensure t
:mode ("\\.zig$" . zig-mode))
(use-package lsp-mode
:ensure t
:commands lsp lsp-deferred
:hook
(clojure-mode . lsp-deferred)
(clojurescript-mode . lsp-deferred)
(clojurec-mode . lsp-deferred)
(typescript-ts-mode . lsp-deferred)
(tsx-ts-mode . lsp-deferred)
(python-mode . lsp-deferred)
(zig-mode . lsp-deferred)
:config
(setq lsp-headerline-breadcrumb-enable nil
lsp-enable-indentation nil
lsp-use-plists t
lsp-modeline-code-actions-enable nil
lsp-modeline-diagnostics-enable nil
lsp-modeline-diagnostics-mode nil
lsp-zig-zls-executable (concat user-emacs-directory "/zig-lsp/zls/zig-out/bin/zls")
lsp-completion-mode nil))
(use-package lsp-ivy
:ensure t)
(use-package lsp-ui
:ensure t
:hook (lsp-mode . lsp-ui-mode)
:config
(set-face-attribute 'lsp-ui-sideline-global nil
:background "black")
(setq lsp-ui-doc-enable nil)
:custom
(lsp-ui-sideline-show-diagnostics t)
(lsp-ui-doc-position 'top))
(use-package flycheck
:ensure t)
(defun org-mode-init-hook ()
(org-indent-mode)
(visual-line-mode 1))
(use-package org
:ensure t
:bind
("C-c a" . org-agenda)
:hook
(org-mode . org-mode-init-hook)
(org-agenda-mode . org-mode-init-hook)
:config
(setq org-todo-keywords '((type "TODO(t)" "PROJ(p)" "|" "DONE(d)")))
(setq org-agenda-files '("~/Dropbox/org/work.org"
"~/Dropbox/org/personal.org"
"~/Dropbox/org/calendar.org"))
(setq org-agenda-timegrid-use-ampm t)
(setq org-agenda-start-with-log-mode t)
(setq org-log-done t)
(setq org-log-into-drawer t)
(setq org-ellipsis " ▼"))
org-bullets
for nicer bullet points
(use-package org-bullets
:ensure t
:after org
:hook (org-mode . org-bullets-mode)
:custom
(org-bullets-bullet-list '("◉" "○" "●" "○" "●" "○" "●")))
org-gcal
to sync the agenda with google calendar
(use-package org-gcal
:ensure t
:after org
:init
(setq org-gcal-client-id (getenv "EMACS_GOOGLE_CALENDER_CLIENT_ID")
org-gcal-client-secret (getenv "EMACS_GOOGLE_CALENDER_SECRET_ID")
org-gcal-fetch-file-alist `((,(getenv "EMACS_GOOGLE_CALENDAR_EMAIL_1") . "~/Dropbox/org/calendar.org")))
(setq plstore-cache-passphrase-for-symmetric-encryption t))
(defconst available-targets '("work" "personal"))
(defun mtaan/current-day-heading ()
(apply 'format "Date: %s/%s/%s" (calendar-current-date)))
(defun mtaan/get-next-seven-days ()
(cl-loop for i from 1 to 7
collect (apply 'format "Date: %s/%s/%s" (calendar-current-date i))))
(defun mtaan/org-add-new-day (target day)
(when (or (string-empty-p target)
(not (member target available-targets)))
(error "Target is not valid"))
(find-file (concat "~/Dropbox/org/" target ".org"))
(let* ((heading-exists? (org-find-exact-headline-in-buffer day)))
(if heading-exists?
(message "This day is already logged")
(progn
(goto-char (point-min))
(org-insert-heading-respect-content)
(insert day)))))
(defun mtaan/org-add-new-project-with-day (proj day)
"By default this will use the work file, maybe later it could be generalized.
It will also assume that I'm adding a proj under the same day"
(when (string-empty-p proj)
(error "Project name shouldn't be empty"))
(find-file "~/Dropbox/org/work.org")
(let* ((proj-subheading (concat "PROJ " (capitalize proj)))
(heading (org-find-exact-headline-in-buffer day nil 't)))
(unless heading
(error "This day is not logged"))
(goto-char heading)
(end-of-line)
(org-insert-subheading nil)
(insert proj-subheading)
(org-set-property "ID" (concat day " - " proj-subheading))))
(defun mtaan/org-add-new-todo-under-proj-with-day (proj day)
(when (string-empty-p proj)
(error "Project name shouldn't be empty"))
(find-file "~/Dropbox/org/work.org")
(let* ((proj-subheading (concat "PROJ " (capitalize proj)))
(heading (org-find-exact-headline-in-buffer day nil 't)))
(unless heading
(error "Current day is not logged"))
(org-id-goto (concat day " - " proj-subheading))
(end-of-line)
(org-insert-heading-respect-content)
(org-demote)
(insert "TODO ")))
(defun mtaan/org-add-new-day-other-day (target day)
(interactive (list
(completing-read "Available targets: " available-targets)
(completing-read "Available Days: " (mtaan/get-next-seven-days))))
(mtaan/org-add-new-day target day))
(defun mtaan/org-add-new-project-other-day (proj day)
(interactive (list
(read-string "Project Name: ")
(completing-read "Available days: "
(mtaan/get-next-seven-days))))
(mtaan/org-add-new-project-with-day proj day))
(defun mtaan/org-add-new-todo-under-proj-other-day (proj day)
(interactive (list
(read-string "Project Name: ")
(completing-read "Available days: "
(mtaan/get-next-seven-days))))
(mtaan/org-add-new-todo-under-proj-with-day proj day))
(defun mtaan/org-add-current-day (target)
(interactive (list (completing-read "Available targets: " available-targets)))
(mtaan/org-add-new-day target (mtaan/current-day-heading)))
(defun mtaan/org-add-new-project-today (proj)
(interactive "sProject Name: ")
(mtaan/org-add-new-project-with-day proj (mtaan/current-day-heading)))
(defun mtaan/org-add-new-todo-under-proj-today (proj)
(interactive "sProject Name: ")
(mtaan/org-add-new-todo-under-proj-with-day proj (mtaan/current-day-heading)))