/emacs

Ayush's Emacs Config

Primary LanguageEmacs Lisp

Ayush’s Emacs Config

Index

Package Manager

I use Melpa Package manager to manage my packages.

(require 'package)
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
                         ("org" . "https://orgmode.org/elpa/")
                         ("elpa" . "https://elpa.gnu.org/packages/")))
(package-initialize)

Ensure Package Manager Installs

(setq use-package-always-ensure t)

Appearance

My Emacs must have killer looks. The code of this section is responsible for it.

Theme

When my crush rejected me saying you are ugly. I learned that looks matter alot. My emacs will not be ugly like me and no one will dump my config for this. So I decided to use doom-themes.

(use-package doom-themes
  :config
  ;; Global settings (defaults)
  (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
        doom-themes-enable-italic t) ; if nil, italics is universally disabled
  (load-theme 'doom-gruvbox t)
  (doom-themes-visual-bell-config)
  (doom-themes-neotree-config)
  (setq doom-themes-treemacs-theme "doom-gruvbox") ; use "doom-colors" for less minimal icon theme
  (doom-themes-treemacs-config)
  (doom-themes-org-config))
(setq doom-theme 'doom-gruvbox)

Font

Just like with power comes great responsibility, with great theme comes great font.

(set-face-attribute 'default nil
                    :font "Mononoki Nerd Font"
                    :height 150
                    :weight 'medium)
(set-face-attribute 'variable-pitch nil
                    :font "Mononoki Nerd Font"
                    :height 180
                    :weight 'medium)
(set-face-attribute 'fixed-pitch nil
                    :font "Hack Nerd Font"
                    :height 150
                    :weight 'medium)
;; Makes commented text and keywords italics.
;; This is working in emacsclient but not emacs.
;; Your font must have an italic face available.
(set-face-attribute 'font-lock-comment-face nil
                    :slant 'italic)
(set-face-attribute 'font-lock-keyword-face nil
                    :slant 'italic)
;; This sets the default font on all graphical frames created after restarting Emacs.
;; Does the same thing as 'set-face-attribute default' above, but emacsclient fonts
;; are not right unless I also add this method of setting the default font.
(add-to-list 'default-frame-alist '(font . "Hack Nerd Font-15"))
;; Uncomment the following line if line spacing needs adjusting.
(setq-default line-spacing 0.12)

Packages

Beacon

While changing buffers or workspaces, the first thing you do is look for you cursor. Unless you know its position, you can not move it efficiently. Every time you change buffers, the current position of your cursor will be briefly highlighted now.

(use-package beacon
  :ensure t
  :config
  (beacon-mode 1))

Bottom Menu

Ivy provides a performant and minimalistic vertical completion UI based on the default completion system. The focus of Ivy is to provide a UI which behaves correctly under all circumstances. And if you use Vertico, Don’t use this config.

(use-package counsel
  :after ivy
  :diminish
  :config (counsel-mode))

(use-package ivy
  :bind
  ;; ivy-resume resumes the last Ivy-based completion.
  (("C-c C-r" . ivy-resume)
   ("C-x B" . ivy-switch-buffer-other-window))
  :diminish
  :custom
  (setq ivy-use-virtual-buffers t)
  (setq ivy-count-format "(%d/%d) ")
  (setq enable-recursive-minibuffers t)
  :config
  (ivy-mode))

(use-package all-the-icons-ivy-rich
  :ensure t
  :init (all-the-icons-ivy-rich-mode 1))
(use-package ivy-rich
  :after counsel
  :init (setq ivy-rich-path-style 'abbrev
              ivy-virtual-abbreviate 'full)
  :config (ivy-rich-mode))

Company

Who doesn’t want those nice auto-completions!

(use-package company
  :defer 2
  :diminish
  :custom
  (company-begin-commands '(self-insert-command))
  (company-idle-delay .1)
  (company-minimum-prefix-length 2)
  (company-show-numbers t)
  (company-tooltip-align-annotations 't)
  (global-company-mode t))

(use-package company-box
  :after company
  :diminish
  :hook (company-mode . company-box-mode))

Dashboard

An extensible emacs startup screen showing you what’s most important.

(use-package dashboard
  :config
  (dashboard-setup-startup-hook))
(setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*")))
(setq dashboard-banner-logo-title "EMACS")
(setq dashboard-startup-banner "~/.config/emacs/avatar.png")
(setq dashboard-center-content t)
(setq dashboard-display-icons-p nil) ;; display icons on both GUI and terminal
(setq dashboard-icon-type 'nerd-icons) ;; use `nerd-icons' package
(setq dashboard-set-heading-icons t)
(setq dashboard-set-file-icons t)
(setq dashboard-set-navigator t)
(dolist (mode '(dashboard-mode-hook))
  (add-hook mode (lambda () (display-line-numbers-mode 0)))) ;; Don't show line numbers, Obviosly

Flycheck

Modern on-the-fly syntax checking extension for GNU Emacs.

(use-package flycheck
  :ensure t
  :init (global-flycheck-mode))

Load Evil Mode

I don’t have a very strong Pinky, and I love vim too …

(use-package evil
  :init      ;; tweak evil's configuration before loading it
  (setq evil-want-integration t) ;; This is optional since it's already set to t by default.
  (setq evil-want-keybinding nil)
  (setq evil-vsplit-window-right t)
  (setq evil-split-window-below t)
  (evil-mode))
(use-package evil-collection
  :after evil
  :config
  (setq evil-collection-mode-list '(dashboard dired ibuffer))
  (evil-collection-init))
(use-package evil-tutor)

Modeline

It’s Important for no reason but looks.

(use-package doom-modeline
  :init (doom-modeline-mode 1)
  :hook (after-init . doom-modeline-mode))
(setq doom-modeline-height 30)
;; Don't Show Evil Mode State in Modeline
(with-eval-after-load 'evil
  (setq evil-normal-state-tag   nil
        evil-emacs-state-tag    nil
        evil-insert-state-tag   nil
        evil-motion-state-tag   nil
        evil-visual-state-tag   nil
        evil-operator-state-tag nil))

Rainbow Delimiters

Never get confused by Brackets again.

(use-package rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))

Rainbow Mode

(use-package rainbow-mode
  :diminish
  :hook org-mode prog-mode)

Vterm

If emacs fails, you’ll need a terminal to run vim.

(use-package vterm)
(setq vterm-toggle-fullscreen-p nil)
(add-to-list 'display-buffer-alist
             '((lambda (buffer-or-name _)
                 (let ((buffer (get-buffer buffer-or-name)))
                   (with-current-buffer buffer
                     (or (equal major-mode 'vterm-mode)
                         (string-prefix-p vterm-buffer-name (buffer-name buffer))))))
               (display-buffer-reuse-window display-buffer-at-bottom)
               (reusable-frames . visible)
               (window-height . 0.3)))
;; Disable line numbers for some modes
(dolist (mode '(vterm-mode-hook))
  (add-hook mode (lambda () (display-line-numbers-mode 0))))
(use-package vterm-toggle)

Which key

So that you don’t have to keep a hard-copy of cheatsheet at all times.

(use-package which-key
  :init
  (which-key-mode 1)
  :diminish
  :config
  (setq which-key-side-window-location 'bottom
        which-key-sort-order #'which-key-key-order
        which-key-allow-imprecise-window-fit nil
        which-key-sort-uppercase-first nil
        which-key-add-column-padding 1
        which-key-max-display-columns nil
        which-key-min-display-lines 6
        which-key-side-window-slot -10
        which-key-side-window-max-height 0.25
        which-key-idle-delay 0.8
        which-key-max-description-length 25
        which-key-allow-imprecise-window-fit nil
        which-key-separator "" ))

Basic Interface Settings

These are settings that do not depend on packages and built-in enchancements to the UI.

Looks

Disable bell

This is annoying, remove this line if you like being visually reminded of events.

;  (setq ring-bell-function 'ignore)

Disable menus and scrollbars

If you like using any of those, change -1 to 1.

(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)

Display Line Numbers and Truncated Lines

Following codeblock enables Line Numbers, Truncates Lines and Highlights current lines.

(global-display-line-numbers-mode 1)
(global-visual-line-mode t)
(global-hl-line-mode t)

No Gui Dialogs

This is not MS Word or VS Code that you will get GUI Dialog Boxes.

(setq use-dialog-box nil)  ;; Don't use gui dialog boxes.

Remove lame startup screen

We use an actual replacement for it, keep reading or head directly to dashboard

(setq inhibit-startup-message t)

Set UTF-8 encoding

(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)

Transparency

;;(set-frame-parameter nil 'alpha-background 90)
;;(add-to-list 'default-frame-alist '(alpha-background . 90))
;;(set-frame-parameter (selected-frame) 'alpha '(<active> . <inactive>))
;;(set-frame-parameter (selected-frame) 'alpha <both>)
;;  (set-frame-parameter (selected-frame) 'alpha '(90 . 80))
(add-to-list 'default-frame-alist '(alpha . (90 . 80)))

Functionality

Automatic Pairing

VS Code magically completes quote marks, Why should emacs lag behind?

(electric-pair-mode 1)     ;; Enable automatic insertion of matching brackets

Change yes-or-no questions into y-or-n questions

Why write “yes” when you can write “y”

(defalias 'yes-or-no-p 'y-or-n-p)

Disable backups and auto-saves

I don’t use either, you might want to turn those from nil to t if you do.

(setq make-backup-files nil)
(setq auto-save-default nil)

Global Escape

Use escape key to leave anything.

(global-set-key (kbd "<escape>") 'keyboard-escape-quit) ;;

Show Columns too

Columns are important too, don’t ignore their utility.

(column-number-mode)       ;; Show Column numbers too.

Zooming In/Out

You can use the bindings CTRL plus =/- for zooming in/out. You can also use CTRL plus the mouse wheel for zooming in/out.

(global-set-key (kbd "C-=") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
(global-set-key (kbd "<C-wheel-up>") 'text-scale-increase)
(global-set-key (kbd "<C-wheel-down>") 'text-scale-decrease)

Cool Icons

Why use vim, when emacs can render icons better.

(use-package all-the-icons
  :ensure t
  :init)
(use-package all-the-icons-dired
  :ensure t
  :init (add-hook 'dired-mode-hook 'all-the-icons-dired-mode))
(use-package all-the-icons-ibuffer
  :ensure t
  :init (all-the-icons-ibuffer-mode 1))

Minor Conveiniences

Emacs is at it’s best when it just does things for you, shows you the way, guides you so to speak. This can be best achieved using a number of small extensions. While on their own they might not be particularly impressive.

Auto Org Babel Tangle

(use-package org-auto-tangle
  :ensure t
  :load-path "site-lisp/org-auto-tangle/"    ;; this line is necessary only if you cloned the repo in your site-lisp directory
  :defer t
  :hook (org-mode . org-auto-tangle-mode)
  :config
  (setq org-auto-tangle-default t))

Subwords

subword will remaps word-based editing commands to subword-based commands that handle symbols with mixed uppercase and lowercase letters.

(global-subword-mode 1)

Quick Compile And Run

Compile

C compilation

(defun compile-c-cpp-program ()
  (interactive)
  (let* ((file-name (buffer-file-name))
         (program-name (file-name-sans-extension file-name))
         (compile-cmd (format "gcc -Wall -Wextra -o %s %s -lm" program-name file-name)))
    ;; Compile the C program
    (compile compile-cmd))
  ;; Switch to the *compilation* buffer
  (pop-to-buffer "*compilation*"))

Run

C programs

(defun run-c-cpp-program ()
  (interactive)
  (let* ((file-name (buffer-file-name))
         (program-name (file-name-sans-extension file-name))
         (executable program-name))

    (if (file-exists-p executable)
        (progn
          ;; Run the executable in a comint-run buffer
          (async-shell-command executable (format "*%s*" program-name))
          (pop-to-buffer (format "*%s*" program-name)))
      (message "Executable not found. Please compile the program first. Also, Make sure executable has same name as C source code without extension and in same directory as well."))))

Python Programs

(defun run-python-program ()
  (interactive)
  (let* ((file-name (buffer-file-name))
         (executable "python")
         (args (list executable file-name)))

    ;; Run the Python program in a comint-run buffer
    (if (file-exists-p executable)
        (progn
          (pop-to-buffer (format "Python: %s" (buffer-name)))
          (comint-mode)
          (erase-buffer)
          (apply 'make-comint-in-buffer "Python" nil executable nil args)))
    (message "Python executable not found. Please make sure Python is installed.")))

Git Integration

Countless are the times where I opened vterm and use git on something. These times are also something that I’d prefer stay in the past, since magit is great. It’s easy and intuitive to use, shows it’s options at a keypress and much more.

Magit

magit is a amazing melpa package which allow me to use git within emacs more better way.

(use-package magit
  :ensure t
  :config
  (setq magit-push-always-verify nil)
  (setq git-commit-summary-max-length 50)
  :bind
  ("M-g" . magit-status))

General Keybindings

(use-package general
  :config
  (general-evil-setup)
  ;; set up 'SPC' as the global leader key
  (general-create-definer emacs/leader-keys
    :states '(normal insert visual emacs)
    :keymaps 'override
    :prefix "SPC" ;; set leader
    :global-prefix "M-SPC") ;; access leader in insert mode
  (emacs/leader-keys
    "f" '(:ignore t :wk "File Options")
    "." '(find-file :wk "Find file")
    "SPC" '(counsel-M-x :wk "Counsel M-x")
    "f f" '(find-file :wk "Find file")
    "f c" '((lambda () (interactive) (find-file "~/.config/emacs/README.org")) :wk "Edit emacs config")
    "f t" '((lambda () (interactive) (find-file "~/dox/orgs/org-agenda/tasks.org")) :wk "Open TODO File")
    "TAB TAB" '(comment-line :wk "Comment lines"))
  (emacs/leader-keys
    "o" '(:ignore t :wk "Org-Mode Commands")
    "o a" '(org-agenda :wk "Org Agenda")
    "o o" '(org-mode :wk "Org Mode"))
  (emacs/leader-keys
    "c" '(:ignore t :wk "Compile Commands")
    "c c" '(compile-c-cpp-program :wk "Compile C/C++ Prorgam"))
  (emacs/leader-keys
    "r" '(:ignore t :wk "Run Commands")
    "r c" '(run-c-cpp-program :wk "Run C/C++ Executable")
    "r p" '(run-python-program :wk "Run Python Program"))
  (emacs/leader-keys
    ";" '(:ignore t :wk "Bookmark Options")
    "; b" '(bookmark-jump :wk "Quickly Jump to a Bookmark")
    "; a" '(bookmark-set :wk "Create a Bookmark")
    "; d" '(bookmark-delete :wk "Delete a Saved Bookmark"))
  (emacs/leader-keys
    "b" '(:ignore t :wk "buffer")
    "b b" '(switch-to-buffer :wk "Switch buffer")
    "b i" '(ibuffer :wk "Ibuffer")
    "b k" '(kill-this-buffer :wk "Kill this buffer")
    "b n" '(next-buffer :wk "Next buffer")
    "b p" '(previous-buffer :wk "Previous buffer")
    "b r" '(revert-buffer :wk "Reload buffer"))
  (emacs/leader-keys
    "q" '(:ignore t :wk "Quit Something")
    "q b" '(kill-this-buffer :wk "Quit current Buffer") 
    "q w" '(quit-window :wk "Quit Window and bury its Buffer"))
  (emacs/leader-keys
    "e" '(:ignore t :wk "Evaluate")    
    "e b" '(eval-buffer :wk "Evaluate elisp in buffer")
    "e d" '(eval-defun :wk "Evaluate defun containing or after point")
    "e e" '(eval-expression :wk "Evaluate and elisp expression")
    "e l" '(eval-last-sexp :wk "Evaluate elisp expression before point")
    "e r" '(eval-region :wk "Evaluate elisp in region")) 
  (emacs/leader-keys
    "s" '(:ignore t :wk "Swiper Search")
    "s s" '(swiper :wk "Search current Buffer") 
    "s a" '(swiper-all :wk "Search all Active Buffers"))
  (emacs/leader-keys
    "h" '(:ignore t :wk "Help")
    "h f" '(describe-function :wk "Describe function")
    "h v" '(describe-variable :wk "Describe variable")
    "h r r" '((lambda () (interactive) (load-file "~/.config/emacs/init.el")) :wk "Reload emacs config"))
  (emacs/leader-keys
    "t" '(:ignore t :wk "Toggle")
    "t l" '(display-line-numbers-mode :wk "Toggle line numbers")
    "t t" '(vterm-toggle :wk "Toggle Terminal")
    "t v" '(visual-line-mode :wk "Toggle to View truncated lines")))

Sudo Edit

Opening nano to edit files which require root permission is pain in the butt. This package sudo-edit allow us to edit files which require root permission with emacs.

(use-package sudo-edit
  :ensure t
  :bind ("s-e" . sudo-edit))

Org Mode

Org Agenda

(setq org-directory "~/dox/orgs/org-agenda")
(setq org-agenda-files '("tasks.org"))
;; If you only want to see the agenda for today
;; (setq org-agenda-span 'day)
(setq org-agenda-start-with-log-mode t)
(setq org-log-done 'time)
(setq org-todo-keywords
      '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
        (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)")))
(setq org-agenda-custom-commands
      '(("d" "Dashboard"
         ((agenda "" ((org-deadline-warning-days 7)))
          (todo "NEXT"
                ((org-agenda-overriding-header "Next Tasks")))
          (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects")))))

        ("n" "Next Tasks"
         ((todo "NEXT"
                ((org-agenda-overriding-header "Next Tasks")))))


        ("W" "Work Tasks" tags-todo "+work")

        ;; Low-effort next actions
        ("e" tags-todo "+TODO=\"NEXT\"+Effort<15&+Effort>0"
         ((org-agenda-overriding-header "Low Effort Tasks")
          (org-agenda-max-todos 20)
          (org-agenda-files org-agenda-files)))

        ("w" "Workflow Status"
         ((todo "WAIT"
                ((org-agenda-overriding-header "Waiting on External")
                 (org-agenda-files org-agenda-files)))
          (todo "REVIEW"
                ((org-agenda-overriding-header "In Review")
                 (org-agenda-files org-agenda-files)))
          (todo "PLAN"
                ((org-agenda-overriding-header "In Planning")
                 (org-agenda-todo-list-sublevels nil)
                 (org-agenda-files org-agenda-files)))
          (todo "BACKLOG"
                ((org-agenda-overriding-header "Project Backlog")
                 (org-agenda-todo-list-sublevels nil)
                 (org-agenda-files org-agenda-files)))
          (todo "READY"
                ((org-agenda-overriding-header "Ready for Work")
                 (org-agenda-files org-agenda-files)))
          (todo "ACTIVE"
                ((org-agenda-overriding-header "Active Projects")
                 (org-agenda-files org-agenda-files)))
          (todo "COMPLETED"
                ((org-agenda-overriding-header "Completed Projects")
                 (org-agenda-files org-agenda-files)))
          (todo "CANC"
                ((org-agenda-overriding-header "Cancelled Projects")
                 (org-agenda-files org-agenda-files)))))))

Variable Fonts

(setq org-hide-emphasis-markers t)
(require 'org)
;; Function to set Liberation Sans font for Org mode buffers
(defun set-org-buffer-font ()
  (face-remap-add-relative 'default '(:family "Liberation Sans")))

;; Add the hook to apply the font for Org mode buffers
(add-hook 'org-mode-hook 'set-org-buffer-font)


;; Define font faces
(defface org-title-face
  '((t (:inherit default :height 600 :underline nil :weight bold :font "Rothenburg Decorative")))
  "Face for the org document title")
(defface org-heading-face
  '((t (:inherit default :family "URW Gothic")))
  "Face for org headings")

;; Set font faces for org levels
(custom-theme-set-faces
 'user
 '(org-level-8 ((t (:inherit org-heading-face :height 1.2))))
 '(org-level-7 ((t (:inherit org-heading-face :height 1.2))))
 '(org-level-6 ((t (:inherit org-heading-face :height 1.2))))
 '(org-level-5 ((t (:inherit org-heading-face :height 1.2))))
 '(org-level-4 ((t (:inherit org-heading-face :height 1.4))))
 '(org-level-3 ((t (:inherit org-heading-face :height 1.4))))
 '(org-level-2 ((t (:inherit org-heading-face :height 1.6))))
 '(org-level-1 ((t (:inherit org-heading-face :weight bold :height 1.9))))
 '(org-document-author ((t (:inherit org-author-face))))
 '(org-document-title ((t (:inherit org-title-face)))))

Todo

(setq org-todo-keywords
      '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
        (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)")))

Org Roam

(use-package org-roam
  :ensure t
  :init
  (setq org-roam-v2-ack t)
  :custom
  (org-roam-directory "~/dox/orgs/roam-notes")
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n i" . org-roam-node-insert))
  :config
  (org-roam-setup))
(use-package org-roam-ui)

Enabling Table of Contents

(use-package toc-org
  :commands toc-org-enable
  :init (add-hook 'org-mode-hook 'toc-org-enable))

Enabling Org Bullets

Org-bullets gives us attractive bullets rather than asterisks.

(add-hook 'org-mode-hook 'org-indent-mode) 
(add-hook 'org-mode-hook 'variable-pitch-mode) 
(use-package org-bullets)
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))

Source Code Block Tag Expansion

Org-tempo is not a separate package but a module within org that can be enabled. Org-tempo allows for ‘<s’ followed by TAB to expand to a begin_src tag. Other expansions available include:

Typing the below + TABExpands to …
<a’#+begin_export ascii’ … ‘#+end_export
<c’#+begin_center’ … ‘#+end_center’
<c’#+begin_comment’ … ‘#+end_comment’
<e’#+begin_example’ … ‘#+end_example’
<e’#+begin_export’ … ‘#+end_export’
<h’#+begin_export html’ … ‘#+end_export’
<l’#+begin_export latex’ … ‘#+end_export’
<q’#+begin_quote’ … ‘#+end_quote’
<s’#+begin_src’ … ‘#+end_src’
<v’#+begin_verse’ … ‘#+end_verse’
(require 'org-tempo)

LSP Integration

These are several packages that provide Language Server Protocol Features for Several Languages.

(use-package lsp-mode
  :commands (lsp lsp-deferred)
  :init
  (setq lsp-keymap-prefix "C-c l")
  :config
  (lsp-enable-which-key-integration t)
  :hook (prog-mode . lsp-mode)
  )
(use-package lsp-ui
  :commands lsp-ui-mode)
(setq lsp-ui-sideline-show-diagnostics t)
(setq lsp-ui-sideline-show-code-actions t)
(use-package lsp-pyright
  :hook (python-mode . (lambda ()
                         (require 'lsp-pyright)
                         (lsp))))