Emacs config file
This literate emacs configuration file init.el is maintained in org mode . org-babel tangles this to ~/.config/emacs/init.el↗ , available as part of dotfiles . Pablo Stafforini’s post↗ inspired this move to org mode.
Initialization
To future proof↗ configuration file, set lexical-binding as true.
;;; init.el -*- lexical-binding: t; -*-
files and folders
(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
(add-to-list 'load-path (expand-file-name "better-defaults" user-emacs-directory))
(add-to-list 'load-path (expand-file-name "beancount-mode" user-emacs-directory))
better-defaults
There are multiple versions of better-defaults. The version i use is from technomancy↗ .
(use-package better-defaults
:ensure nil
:demand t)
backup settings
;; Based on https://git.sr.ht/~technomancy/better-defaults
(setq backup-directory-alist `(("." . ,(concat user-emacs-directory
"backups"))))
(setq version-control t)
(setq delete-old-versions t)
(setq kept-new-versions 5)
(setq backup-by-copying t)
(setq create-lockfiles nil) ;; Prevents .# creation
package sources
; Define the package archives
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")))
;; Set priorities to prefer GNU over MELPA
(setq package-archive-priorities '(("gnu" . 10)
("melpa" . 5)))
;; Initialize the package system
(package-initialize)
use-package
As use-package is built into emacs 29 onwards simplified the version. Originally used the version from ianyepan.github.io↗ . Later made some changes based on official guide↗ and this↗ and steckemacs↗ .
(require 'use-package)
(setq use-package-always-ensure t)
use-feature
This function is from use-package-extras as explained in Pablo Stafforini’s post↗ . He has attributed this to radian↗ .
(defmacro use-feature (name &rest args)
"Like `use-package' but for built-in features (sets :ensure nil).
NAME and ARGS as in `use-package'."
(declare (indent defun))
`(use-package ,name
:ensure nil
,@args))
Settings
trailing whitespace
;; Remove trailing whitespace before saving
(add-hook 'before-save-hook 'delete-trailing-whitespace)
smooth scrolling
;;https://batsov.com/articles/2021/12/19/building-emacs-from-source-with-pgtk/
(pixel-scroll-precision-mode)
column number mode
(column-number-mode 1)
consistency
;; To change default font or size in Emacs https://stackoverflow.com/questions/294664/how-to-set-the-font-size-in-emacs
;; (set-face-attribute 'default nil :height 130)
;; (set-face-attribute 'default nil :font "Monaco-16" )
;; (set-face-attribute 'default nil :font "Hack-13:embolden=true" )
;; (set-face-attribute 'default nil :font "Roboto Mono-13" )
(set-face-attribute 'default nil :font "Hack-13" )
spelling
Suddenly corfu started reporting a lot of errors. So added spellchecker name.
;; (advice-add 'ispell-completion-at-point :override #'ignore)
(with-eval-after-load 'ispell
(setq ispell-program-name "hunspell")
(setenv "DICPATH" "/usr/share/hunspell")
(remove-hook 'completion-at-point-functions #'ispell-completion-at-point))
transparency
(setq window-divider-default-places t)
(set-face-background 'internal-border (face-background 'default))
;; For PGTK, use alpha-background instead of alpha
(add-to-list 'default-frame-alist '(alpha-background . 85))
(defun toggle-transparency ()
"Toggle between transparent and opaque background."
(interactive)
(let ((current-alpha (frame-parameter nil 'alpha-background)))
(set-frame-parameter
nil 'alpha-background
(if (< (or current-alpha 100) 100) 100 85))))
(global-set-key (kbd "C-c t") 'toggle-transparency)
scratch buffer
;; Turn off the startup screen, splash screen and puts straight into
;; the scratch buffer to quickly type or paste in emacs instead of
;; standard emacs startpage
(setq inhibit-startup-screen t)
(setq inhibit-startup-message t)
(setq initial-scratch-message "")
(setq initial-major-mode 'fundamental-mode)
theme
(use-package nord-theme
:ensure t
:init
(setq nord-region-highlight "frost")
:config
(load-theme 'nord t))
custom functions
(defun now ()
"Insert string for the current time formatted like '2:34 PM'."
(interactive) ; permit invocation in minibuffer
;; (insert (format-time-string "%-I:%M %p"))
(insert (format-time-string "%R")))
(defun today ()
"Insert string for today's date nicely formatted in American style,
e.g. Sunday, September 17, 2000."
(interactive) ; permit invocation in minibuffer
;; (insert (format-time-string "%A, %B %e, %Y"))
(insert (format-time-string "%F")))
(defun my/doasedit ()
"Re-open current file with doas (elevated) privileges."
(interactive)
(if (buffer-file-name)
(let ((cursor-pos (point))
(truename (file-truename (buffer-file-name))))
(find-alternate-file (concat "/doas::" truename))
(goto-char cursor-pos))
(message "This buffer is not visiting a file!")))
;; https://emacs.stackexchange.com/questions/77295/org-roam-case-insensitive-search
(defun case-insensitive-org-roam-node-read (orig-fn &rest args)
"Make org-roam node search case-insensitive."
(let ((completion-ignore-case t))
(apply orig-fn args)))
;; (defun build/export-all ()
;; (dolist (org-file (directory-files-recursively org-roam-directory "\.org$"))
;; (with-current-buffer (find-file org-file)
;; (message (format "[build] Exporting %s" org-file))
;; (org-hugo-export-wim-to-md :all-subtrees nil nil nil))))
;; Define a reusable function for general programming mode setup
(defun my-programming-setup ()
"General settings for ALL programming modes"
(display-line-numbers-mode 1)
(setq-local display-line-numbers-type 'relative)
;; The below two disabled as they break PEP
;; (setq-local tab-width 4)
;; (setq-local indent-tabs-mode t)
)
;; Apply this to every programming language automatically
(add-hook 'prog-mode-hook #'my-programming-setup)
Packages
helpful
(use-package helpful
:ensure t
:init
(require 'bind-key)
:bind
(("C-h f" . helpful-callable) ; Replace describe-function
("C-h v" . helpful-variable) ; Replace describe-variable
("C-h k" . helpful-key) ; Replace describe-key
("C-h x" . helpful-command))) ; Replace describe-command
tramp
(use-feature tramp
:defer t
:config
(setq tramp-auto-save-directory (expand-file-name "tramp-autosave" user-emacs-directory)
password-cache-expiry 3600))
outshine
Outshine brings Org Mode to the world outside of Org;;
(use-package outshine
:ensure t
:diminish outline-minor-mode
:commands outshine-hook-function
:hook (emacs-lisp-mode . outshine-mode)
:init
(setq outshine-imenu-show-headlines-p nil))
diminish
Diminished modes are minor modes with no modeline display
(use-package diminish
:ensure t
)
vertico
vertico, consult, marginalia, orderless, embark, corfu and cape together have replaced helm , org-rifle , helm-swoop , Company etc
(use-package vertico
:ensure t
:init
(vertico-mode)
;; Settings for a minimal UI.
(setq vertico-cycle t)
(setq vertico-count 10)
:config
(vertico-mouse-mode 1))
(use-package consult
:ensure t
:bind (
("C-x b" . consult-buffer)
("C-s" . consult-line)
("C-c r" . consult-ripgrep)
:map isearch-mode-map
("M-s s" . consult-line))
)
(use-package marginalia
:ensure t
:init
(marginalia-mode))
(use-package orderless
:ensure t
:custom
(completion-styles '(orderless basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles . (partial-completion)))))
:init
;; Orderless provides powerful fuzzy-matching
(setq completion-ignore-case t)
(setq completion-flex-enable t))
(use-package embark
:ensure t
:bind (("C-." . embark-act)
("C-S-y" . embark-consult-kill-ring))
:init
(setq prefix-help-command #'embark-prefix-help-command)
)
(use-package embark-consult
:ensure t
:after (embark consult))
corfu
(use-package corfu
:ensure t
:if (display-graphic-p)
:custom
(corfu-auto t) ; Enable auto-completion
(corfu-auto-prefix 3) ; Wait for 3 characters
(corfu-auto-delay 0.2) ; Wait 0.2s
:bind (:map corfu-map
("M-p" . corfu-popupinfo-scroll-down)
("M-n" . corfu-popupinfo-scroll-up)
("M-d" . corfu-popupinfo-toggle))
:init
(global-corfu-mode)
:config
;; Enable the documentation popup
(corfu-popupinfo-mode 1)
;; Visual tweaks for the documentation child-frame
(setq corfu-popupinfo-parameters
'((vertical-scroll-bars . nil)
(horizontal-scroll-bars . nil)
(inner-border-width . 1)
(left-fringe . 8)
(right-fringe . 8))))
cape
Cape provides in-buffer drop-down completion
(defun my-cape-keyword-setup ()
"Add keyword completion to the current buffer."
(add-to-list 'completion-at-point-functions #'cape-keyword t))
(use-package cape
:ensure t
:bind ("C-c p f" . cape-file)
:init
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
:hook (prog-mode . my-cape-keyword-setup)
)
ediff
;; Define a function to quit ediff with a single 'q' press
;; Enhanced settings for ediff in Emacs
(use-feature ediff
:config
(setq ediff-split-window-function 'split-window-horizontally
ediff-window-setup-function 'ediff-setup-windows-plain
ediff-diff-options "-w")
(defun my-ediff-quit-session ()
(interactive)
(ediff-quit 'no-confirm))
(add-hook 'ediff-keymap-setup-hook
(lambda ()
(define-key ediff-mode-map (kbd "q") 'my-ediff-quit-session))))
magit
magit is one nice front end for git
(use-package magit
:ensure t
:bind (
("C-x g" . magit-status)
("C-x M-g" . magit-dispatch)
("C-c M-g" . magit-file-dispatch)))
org mode
Org Mode is used to maintain this file and used to create this site using Org Roam . To extend the auto-tangle for additional org files, a defvar list is used. For single init file, string was used. Now member is used to match the filename.
(defvar my/auto-tangle-files
'("20260510115218-emacs_config_file.org"
"20260529152048-graph_js.org"
"20260529114550-gen_graph.org"
"20260531212337-neighbour-loader_js.org"
"20260601134637-neighbour_utils_js.org"
"20260601135932-mobile_menu_js.org"
"20260601144841-search_js.org"))
(defun my-org-mode-setup ()
(electric-indent-local-mode -1)
(when (and buffer-file-name
(member (file-name-nondirectory buffer-file-name)
my/auto-tangle-files))
(add-hook 'after-save-hook #'org-babel-tangle nil t)))
(use-feature org
:custom
(org-return-follows-link t) ;;Allows links to be opened without C-c C-o in emacs
(org-id-link-to-org-use-id t) ;; Adds properties to record org ID's to non-roam files too
(org-agenda-files '("/data/myhome/prabu/org/agenda"
"/data/myhome/prabu/org/Resources/daily_journal.org"))
(org-log-done t)
(org-todo-keywords '((sequence "TODO(t)" "WAIT(w@/!)" "|" "DONE(d!)" "CANCELED(c@)")))
(org-tag-alist '((:startgroup . nil)
("@kpm" . ?k) ("@home" . ?h)
("@errands" . ?e)
(:endgroup . nil)
("@computer" . ?c) ("@phone" . ?p) ("@reading" . ?r)))
(org-structure-template-alist '(("el" . "src emacs-lisp")
("py" . "src python")
("js" . "src javascript")
("s" . "src")
("e" . "example")
("q" . "quote")))
:bind (
("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c c" . org-capture)
)
:config
(keymap-set org-mode-map "C-c [" nil)
(keymap-set org-mode-map "C-c ]" nil)
;; (setq time-stamp-active t)
;; (setq time-stamp-line-limit 10) ; Plenty of room for line 4
;; (setq time-stamp-start "^#\\+date:[ \t]*") ; Just find the header
;; (setq time-stamp-end "$") ; Replace everything until end of line
;; (setq time-stamp-format "[%Y-%m-%d %a %H:%M:%S]")
:hook (org-mode . my-org-mode-setup))
org-tempo
(use-feature org-tempo
:after org)
org-roam
This site is generated from Org Roam . I installed and configured org-roam as per the sources mentioned.
;; --- Custom Helper Functions ---
(defun my/org-roam-publish-site ()
"Runs the graph gen, hugo build, and syncthing scan."
(interactive)
(message "Publishing site...")
(shell-command "/data/myhome/prabu/org/my_hugo_site/scripts/publish_hugo_site.sh &"))
(defun my/set-daily-export-file-name ()
(let* ((target-buf (org-capture-get :buffer))
(target-file (when target-buf (buffer-file-name target-buf))))
(when (and target-file
(string-match-p "daily_journal\\.org$" target-file))
(save-excursion
(org-up-heading-safe)
;; (message "Hook fired at: %s" (org-entry-get nil "EXPORT_FILE_NAME"))
(org-entry-get nil "EXPORT_FILE_NAME")
(unless (org-entry-get nil "EXPORT_FILE_NAME")
(org-entry-put nil "EXPORT_FILE_NAME"
(format-time-string "%Y-%m-%d" (org-capture-get :default-time))))
(unless (org-entry-get nil "EXPORT_DATE")
;; (message "Setting EXPORT_DATE")
(org-entry-put nil "EXPORT_DATE"
(or (org-entry-get nil "EXPORT_FILE_NAME")
(format-time-string "%Y-%m-%d" (org-capture-get :default-time)))))))))
(use-package org-roam
:ensure t
:init
(setq org-roam-database-connector 'sqlite-builtin)
:custom
(org-roam-v2-ack t)
(org-roam-completion-everywhere t)
(org-roam-directory (file-truename "/data/myhome/prabu/org/Resources"))
(org-roam-dailies-directory ".")
;; (org-roam-dailies-directory "daily/")
;; ;; Daily Template
;; (org-roam-dailies-capture-templates
;; '(("d" "default" entry
;; "* %^{Title}\n%?"
;; :target (file+head "%<%Y-%m-%d>.org"
;; "#+title: %<%Y-%m-%d %A>\n"))))
(org-roam-dailies-capture-templates
'(("d" "default" entry
"* %^{Title}\n%?"
;; "* %^{Title}\n:PROPERTIES:\n:EXPORT_FILE_NAME: %(format-time-string \"%Y-%m-%d\" (org-capture-get :default-time))\n:END:\n%?"
:target (file+datetree "daily_journal.org" day)
:empty-lines 1
:no-id t)));;either day|week|month is allowed
:bind
(("C-c n f" . org-roam-node-find)
("C-c n r" . org-roam-node-random)
("C-c n j" . org-roam-dailies-capture-today)
("C-c n g" . org-roam-dailies-goto-today)
:map org-mode-map
;; org-mode-specific keybindings
("C-c n i" . org-roam-node-insert)
("C-c n o" . org-id-get-create)
("C-c n t" . org-roam-tag-add)
("C-c n a" . org-roam-alias-add)
("C-c n l" . org-roam-buffer-toggle)
("C-M-i" . completion-at-point))
:config
(require 'org-roam-dailies)
(global-set-key (kbd "C-c n d") org-roam-dailies-map)
;; Dailies Keymap definitions
(define-key org-roam-dailies-map (kbd "Y") #'org-roam-dailies-capture-yesterday)
(define-key org-roam-dailies-map (kbd "T") #'org-roam-dailies-capture-tomorrow)
;; Notes Template
(setq org-roam-capture-templates
'(("d" "default" plain
"%?"
:target (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
"#+title: ${title}\n#+date: %<%Y-%m-%dT%H:%M:%S%:z>\n#+filetags: :draft:\n")
:unnarrowed t)))
;; org-Roam Database and Sync
(org-roam-db-autosync-mode)
(setq org-id-extra-files (org-roam--list-files org-roam-directory))
(setq org-roam-db-node-include-function
(lambda () (= (org-outline-level) 0)))
;; Refresh the list automatically whenever node is changed or saved
(add-hook 'org-roam-db-sync-hook
(lambda ()
(setq org-id-extra-files (org-roam--list-files org-roam-directory))))
(add-hook 'org-capture-before-finalize-hook #'my/set-daily-export-file-name)
(advice-add 'org-roam-node-read :around #'case-insensitive-org-roam-node-read)
(message "org-roam loaded"))
;; #for ox-hugo# https://hugocisneros.com/org-config/#org-roam
(use-package org-roam-ui
:ensure t)
ox-hugo
ox-hugo is used to export Org files to md format files for use with hugo .
(defun my/ox-hugo-export-all-org-to-md ()
"Force export all Org-roam notes to Hugo Markdown."
(interactive)
(let ((org-export-with-broken-links t))
(dolist (org-file (directory-files-recursively org-roam-directory "\\.org$"))
(with-current-buffer (find-file-noselect org-file)
(message (format "[build] Exporting %s" org-file))
(org-hugo-export-wim-to-md :all-subtrees nil nil nil)))))
(use-package ox-hugo
;; uses /data/myhome/prabu/org/Resources/.dir-locals.el
:ensure t ;;Auto-install the package from Melpa
:pin melpa ;;`package-archives' should already have ("melpa" . "https://melpa.org/packages/")
:after ox
:config
(setq org-hugo-auto-set-lastmod t)
(setq org-hugo-export-with-section-modified-time t)
(setq org-hugo-allow-all-export-keywords t)
;; (setq org-hugo-link-desc-insert-type 'id)
;; (setq org-id-extra-files
;; (directory-files-recursively org-roam-directory "\\.org$"))
;; (citeproc-org-org-bib-header "* Bibliography\n<ol class=\"biblio-list\">")
;; (citeproc-org-org-bib-footer "</ol>")
)
org-transclusion
(use-package org-transclusion
:ensure t ;;Auto-install the package from Melpa
:hook (org-mode . org-transclusion-mode)
)
org-noter
(use-package org-noter
:ensure t
)
markdown-mode
Installed markdown package in the OS for previewing the markdown files.
(use-package markdown-mode
:ensure t
)
flymake
This package is inbuilt within emacs
(use-feature flymake
;; https://www.gnu.org/software/emacs/manual/html_node/flymake/Finding-diagnostics.html
:bind(
:map flymake-mode-map
("M-n" . flymake-goto-next-error)
("M-p" . flymake-goto-prev-error)
("<f2>" . flymake-show-buffer-diagnostics)))
eglot
In alpine installed py3-lsp-server, ruff-lsp and beancount-language-server through the package manager.
- https://github.com/joaotavora/eglot↗ .
- https://www.adventuresinwhy.com/post/eglot/↗
- https://www.reddit.com/r/emacs/comments/106oq11/eglot_flymake_eldoc/↗
- https://www.reddit.com/r/emacs/comments/16fvmow/disable_eglotinlayhintsmode_in_every_buffer/↗
(use-feature eglot
:defer t
:hook ((html-mode . eglot-ensure)
(mhtml-mode . eglot-ensure))
:bind(
:map eglot-mode-map
("C-c o" . eglot-code-action-organize-imports)
("C-c h" . eldoc))
:config
(add-to-list 'eglot-server-programs
'((html-mode mhtml-mode) . ("superhtml" "lsp")))
(add-hook 'eglot-managed-mode-hook
(lambda ()
;; Show flymake diagnostics first.
(setq eldoc-documentation-functions
(cons #'flymake-eldoc-function
(remove #'flymake-eldoc-function eldoc-documentation-functions)))
;; Show all eldoc feedback.
(setq eldoc-documentation-strategy #'eldoc-documentation-compose)))
)
beancount
This mode is useful for Beancount , plain text accounting system. To ensure that PET finds the venv, a link has been created as follows in the beancount folder:
prabu@homepc2 /d/m/p/beancount> ls -al /data/myhome/prabu/beancount/ .venv
lrwxrwxrwx 1 prabu prabu 28 May 20 15:41 .venv -> /data/myhome/prabu/bean_venv/
(use-package beancount
:ensure nil
:commands beancount-mode
:mode ("\\.beancount\\'" . beancount-mode)
:hook
(beancount-mode . (lambda ()
(setq-local electric-indent-chars nil)
(outline-minor-mode)
(flymake-mode) ; Enable flymake-mode here
(flymake-bean-check-enable)))
:bind (:map beancount-mode-map
("C-c C-n" . outline-next-visible-heading)
("C-c C-p" . outline-previous-visible-heading)
("C-c C-u" . outline-up-heading)
("C-c C-b" . outline-backward-same-level)
("C-c C-f" . outline-forward-same-level)
("C-c C-a" . outline-show-all)
([backtab] . beancount-outline-cycle)))
(use-package flymake-bean-check
:ensure nil
:after (flymake beancount))
python
Currently using inbuilt Python, flymake and eglot along with hide-mode-line, live-py-mode. Earlier i started with Elpy . Eglot connects to python-lsp and ruff.
References:
- https://gitlab.com/nathanfurnal/dotemacs/-/snippets/2060535↗
- https://robbmann.io/emacsd/#language-specific-major-modes↗
- https://www.adventuresinwhy.com/post/eglot/↗
- https://stackoverflow.com/questions/1259873/how-can-i-use-emacs-flymake-mode-for-python-with-pyflakes-and-pylint-checking-co↗
(use-feature python
:config
(setq python-indent-guess-indent-offset-verbose nil) ;; Remove guess indent python message
(add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode)) ;; Remap python-mode to python-ts-mode
(add-hook 'python-ts-mode-hook
(lambda ()
(setq python-indent-offset 4) ;; Use 4 spaces for indentation (PEP 8)
(setq-local eglot-workspace-configuration
'((:pylsp :plugins
(:autopep8 (:enabled :json-false)
:yapf (:enabled :json-false)
:pycodestyle (:enabled :json-false)
:mccabe (:enabled :json-false)
:flake8 (:enabled :json-false)
:pylint (:enabled :json-false)))))))) ;; do not use pylsp for linting
(use-package ruff-format
:ensure t
:hook (python-base-mode . ruff-format-on-save-mode))
(use-package pet
:ensure t
:config
;; (add-hook 'python-base-mode-hook 'pet-mode -10)
(add-hook 'python-base-mode-hook 'pet-mode +1)
(add-hook 'beancount-mode-hook 'pet-mode +1)
(add-hook 'python-base-mode-hook
(lambda ()
(when-let* ((python (pet-executable-find "python")))
(setq-local python-shell-interpreter python
python-shell-virtualenv-root (pet-virtualenv-root)))
(pet-eglot-setup)
(eglot-ensure)))
(add-hook 'beancount-mode-hook
(lambda ()
(setq-local beancount-accounts-files
(directory-files default-directory t "\\.beancount$"))
(when-let* ((root (pet-virtualenv-root))
(venv-bin (expand-file-name "bin" root))
(_ (file-directory-p venv-bin)))
(setq-local exec-path (append (list venv-bin) exec-path))))))
hide-mode-line
hide-mode-line package↗ hides 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.
(use-package hide-mode-line
:ensure t
:hook (inferior-python-mode . hide-mode-line-mode)
)
live-py-mode
(use-package live-py-mode
:ensure t
)
shell scripts
(defun my-sh-mode-setup ()
"Specific settings for shell scripts."
;; sh-mode-hook inherits prog-mode-hook!
(setq-local sh-basic-offset 4)
(setq-local indent-tabs-mode t)
(setq-local tab-width 4)
)
;; Use custom function if sh-mode is activated anywhere
(add-hook 'sh-mode-hook #'my-sh-mode-setup)
;; Ensure APKBUILD files open in sh-mode so the hook above triggers
(add-to-list 'auto-mode-alist '("APKBUILD\\'" . sh-mode))
c/c++ configuration
(defun my-c-common-setup ()
"Standardized settings for C-family languages."
;; Standards: PEP 8 (Python) and modern C++ (LLVM/Google) prefer spaces.
;; Install clangd or clang-extra-tools package for LSP features with eglot
(setq-local indent-tabs-mode nil)
(setq-local c-basic-offset 4) ; 4 is the modern industry standard
(when (executable-find "clangd")
(eglot-ensure)))
(add-hook 'c-mode-common-hook #'my-c-common-setup)
arduino
Useful for editing source files for arduino
;; (use-package arduino-mode
;; :ensure t
;; :mode ("\\.ino$" . arduino-mode)
;; )
platformio
Useful for editing source files for IOT devices like esp32
;; (use-package platformio-mode
;; :ensure t
;; :hook ((c-mode . platformio-conditionally-enable)
;; (c++-mode . platformio-conditionally-enable))
;; )
projectile
This package was needed for platformio-mode
;; (use-package projectile
;; :ensure t
;; :init
;; (projectile-mode +1)
;; :bind (:map projectile-mode-map
;; ("s-p" . projectile-command-map)
;; ("C-c p" . projectile-command-map)))
rainbow-delimiters
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))
custom
Redirects the “Custom” stuff to a separate file
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file))
© Prabu Anand K 2020-2026