Skip to content

Latest commit

 

History

History
1668 lines (1519 loc) · 58.6 KB

config.org

File metadata and controls

1668 lines (1519 loc) · 58.6 KB

srijan’s emacs configuration

Configuration

Header

This will generate a header at the top of the tangled file to indicate it is generated and is not meant to be modified directly.

;; -*- lexical-binding: t -*-
;; This file has been generated from config.org file. DO NOT EDIT.

Starting up

Here’s how we start:

;; For speedup.
;; (setq straight-check-for-modifications nil)
;; Setup straight
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (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))

(straight-use-package 'use-package)
(use-package straight
  :custom
  (straight-use-package-by-default t)
  (straight-host-usernames '((github    . "srijan"))))

;; Move customization variables to a separate file and load it
(setq custom-file (locate-user-emacs-file "custom-vars.el"))
(load custom-file 'noerror 'nomessage)
(setq-default native-comp-async-report-warnings-errors 'silent)

System information

(defvar my-linux-p (equal (system-name) "GGN001944"))
(defvar my-windows-p (equal (system-name) "SHADOW"))
;; (defvar my-server-p (and (equal (system-name) "localhost") (equal user-login-name "sacha")))
(defvar my-phone-p (not (null (getenv "ANDROID_ROOT")))
  "If non-nil, GNU Emacs is running on Termux.")
(when my-phone-p (setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3"))
(global-auto-revert-mode)  ; simplifies syncing

Personal Information

(setq user-full-name "Srijan Choudhary"
    user-mail-address "[email protected]")

Basics / Misc

;; Recent files
(recentf-mode 1)

;; Minibuffer history
(setq history-length 100)
(savehist-mode 1)

;; Remember and restore the last cursor location in opened files
(save-place-mode 1)

;; Revert buffers when the underlying file has changed
(global-auto-revert-mode 1)
;; Revert Dired and other buffers
(setq global-auto-revert-non-file-buffers t)

;; Kill current buffer (instead of asking first buffer name)
(global-set-key (kbd "C-x k") 'kill-current-buffer)

;; M-n for new frame (M-n is unbound in vanilla emacs)
(defun new-frame ()
  (interactive)
  (select-frame (make-frame))
  (switch-to-buffer "*scratch*"))
(global-set-key (kbd "M-n") 'new-frame)

;; Fill column at 120
(setq fill-column 120)

(add-hook 'text-mode-hook
          'variable-pitch-mode)

Looks & Themes

;; Basic Visuals
(setq inhibit-startup-message t)
(tool-bar-mode -1)
(tooltip-mode -1)
(scroll-bar-mode -1)
(menu-bar-mode -1)
(set-fringe-mode 10)
(hl-line-mode 1)
(blink-cursor-mode -1)
(add-to-list 'default-frame-alist '(height . 35))
(add-to-list 'default-frame-alist '(width . 140))


;; Fonts
;; (set-face-attribute 'default nil :font "RobotoMono Nerd Font" :height 140)
;; (set-face-attribute 'default nil :font "FiraCode Nerd Font Mono" :height 140)
;; (set-face-attribute 'default nil :font "Hack Nerd Font Mono" :height 140)
;; (set-face-attribute 'default nil :font "Iosevka Comfy Duo" :height 140)
;; (when my-linux-p
;;   (set-face-attribute 'default nil :font "Berkeley Mono" :height 140))

  (use-package fontaine
    :custom
    (fontaine-presets
     '(
       (iosevka-regular
        :default-family "Iosevka Comfy"
        :default-height 120
        :variable-pitch-family "Iosevka Comfy Duo"
        )
       (berkeley-regular
        :default-family "Berkeley Mono"
        :default-height 120
        :line-spacing 0.1
        :variable-pitch-family "Berkeley Mono Variable"
        ;; :variable-pitch-family "Merriweather Sans Light"
        ;; :variable-pitch-height 0.96
        )
       (berkeley-large
        :inherit berkeley-regular
        :default-height 160
        )
       (t
        :default-family "Iosevka Comfy"
        :default-weight regular
        :default-height 120
        :fixed-pitch-family nil ; falls back to :default-family
        :fixed-pitch-weight nil ; falls back to :default-weight
        :fixed-pitch-height 1.0
        :fixed-pitch-serif-family nil ; falls back to :default-family
        :fixed-pitch-serif-weight nil ; falls back to :default-weight
        :fixed-pitch-serif-height 1.0
        :variable-pitch-family "Iosevka Comfy Duo"
        :variable-pitch-weight nil
        :variable-pitch-height 1.0
        :bold-family nil ; use whatever the underlying face has
        :bold-weight bold
        :italic-family nil
        :italic-slant italic
        :line-spacing nil)))
    :config
    (fontaine-set-preset 'berkeley-regular)
    )




;; Themes
;; (use-package doom-themes
;;   :disabled t
;;   ;; :ensure t
;;   :config
;;   (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-Iosvkem t)
;;   (doom-themes-visual-bell-config)
;;   (setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
;;   (doom-themes-treemacs-config)
;;   ;; Corrects (and improves) org-mode's native fontification.
;;   (doom-themes-org-config))

;; (use-package catppuccin-theme
;;   :straight (:type git :host github :repo "catppuccin/emacs"))


;; (load-theme 'modus-operandi t)
;; (load-theme 'modus-operandi-tinted t)
(use-package ef-themes
  :demand
  :custom
  (ef-themes-to-toggle '(ef-elea-light ef-elea-dark))
  (ef-themes-headings
   '((0 . (variable-pitch semibold 1.2))
     (1 . (variable-pitch semibold 1.1))
     (agenda-date . (variable-pitch 1.2))
     (agenda-structure . (variable-pitch 1.4))
     (t . (variable-pitch))
     ))
  (ef-themes-mixed-fonts t)
  (ef-themes-variable-pitch-ui t)
  :hook ((ef-themes-post-load . my-ef-themes-mode-line)
         (ef-themes-post-load . fontaine-apply-current-preset))
  :config
  (defun my-ef-themes-mode-line ()
    "Tweak the style of the mode lines."
    (ef-themes-with-colors
      (custom-set-faces
       `(mode-line ((,c :background ,bg-mode-line :foreground ,fg-mode-line :box (:line-width 1 :color ,fg-dim))))
       `(mode-line-inactive ((,c :box (:line-width 1 :color ,bg-active)))))))
  )
(ef-themes-select 'ef-elea-dark)
(use-package olivetti
  :custom
  (olivetti-style 'fancy)
  (setq olivetti-fringe '(:background "#e5e5e5"))
  )
(use-package spacious-padding)

;; (use-package nano-theme
;;   :custom
;;   (nano-fonts-use nil)
;;   :config
;;   (load-theme 'nano t)
;;   (nano-mode)
;;   (nano-dark)
;;   )

;; No message in scratch buffer
(setq initial-scratch-message nil)

Windows

;; Switching between windows. Use `ace-window`, configure using :init and :bind
(use-package ace-window
  :ensure t
  :init
  (setq aw-scope 'frame)
  :bind ("M-o" . ace-window))
;; Open the config file
(global-set-key (kbd "C-x ,") (lambda() (interactive) (find-file (locate-user-emacs-file "config.org"))))

Backups

;; Backup
(setq backup-directory-alist '(("." . "~/.backups"))
      make-backup-files t     ; backup of a file the first time it is saved.
      backup-by-copying t     ; don't clobber symlinks
      version-control t       ; version numbers for backup files
      delete-old-versions t   ; delete excess backup files silently
      kept-old-versions 6     ; oldest versions to keep when a new numbered
                              ;  backup is made (default: 2)
      kept-new-versions 9     ; newest versions to keep when a new numbered
                              ;  backup is made (default: 2)
      auto-save-default t     ; auto-save every buffer that visits a file
      auto-save-timeout 20    ; number of seconds idle time before auto-save
                              ;  (default: 30)
      auto-save-interval 200)  ; number of keystrokes between auto-saves
                              ;  (default: 300)

Evil

(use-package undo-fu)

(use-package evil
  :init
  (setq evil-respect-visual-line-mode t)
  (setq evil-want-integration t) ;; This is optional since it's already set to t by default.
  (setq evil-want-keybinding nil)
  (setq evil-undo-system 'undo-fu)

  :config
  (evil-mode 1)

  ;; Prevents esc-key from translating to meta-key in terminal mode.
  (setq evil-esc-delay 0)

  (setq-default evil-shift-width 2)
  (setq-default evil-symbol-word-search t)
  (customize-set-variable 'evil-want-Y-yank-to-eol t)

  (evil-add-command-properties #'org-open-at-point :jump t)

  (evil-declare-key 'normal org-mode-map
    "gk" 'outline-up-heading
    "gj" 'outline-next-visible-heading
    "H" 'org-beginning-of-line
    "L" 'org-end-of-line
    "t" 'org-todo
    (kbd "<tab>") 'org-cycle
    ",c" 'org-cycle
    ",e" 'org-export-dispatch
    ",n" 'outline-next-visible-heading
    ",p" 'outline-previous-visible-heading
    ",t" 'org-set-tags-command
    ",u" 'outline-up-heading
    "$" 'org-end-of-line
    "^" 'org-beginning-of-line
    "-" 'org-ctrl-c-minus ; change bullet style
    ))

(use-package evil-collection
  :straight (:type git :host github :repo "emacs-evil/evil-collection")
  :diminish (evil-collection-unimpaired-mode)
  :after evil mu4e
  :ensure t
  :config
  (evil-collection-init))

(use-package evil-org
  :ensure t
  :after org
  :hook (org-mode . (lambda () evil-org-mode))
  :config
  (require 'evil-org-agenda)
  (evil-org-agenda-set-keys))

Term Mode Stuff

(defun bb/setup-term-mode ()
  (evil-local-set-key 'insert (kbd "C-r") 'bb/send-C-r))

(defun bb/send-C-r ()
  (interactive)
  (term-send-raw-string "\C-r"))

(add-hook 'term-mode-hook 'bb/setup-term-mode)

(when my-linux-p
  (use-package vterm))

(when my-windows-p
  (use-package powershell))

Modeline

(use-package diminish
  :config (require 'diminish))
(use-package eldoc :diminish eldoc-mode)
(use-package all-the-icons)
(use-package nerd-icons)
(use-package doom-modeline
  :ensure t
  :init
  (doom-modeline-mode 1))

Dirvish

(use-package dirvish
  :init
  (dirvish-override-dired-mode)
  :custom
  (dirvish-quick-access-entries ; It's a custom option, `setq' won't work
   '(("h" "~/"                          "Home")
     ("d" "~/Downloads/"                "Downloads")
     ("n" "~/ndxrd-uxxs3/notes/"        "Notes")
     ("o" "~/ndxrd-uxxs3/org/"          "GTD Org")
     ("c" "~/.config/s-emacs/"          "Config")))
  :config
  ;; (dirvish-peek-mode) ; Preview files in minibuffer
  ;; (dirvish-side-follow-mode) ; similar to `treemacs-follow-mode'
  (setq dirvish-mode-line-format
        '(:left (sort symlink) :right (omit yank index)))
  (setq dirvish-attributes
        '(all-the-icons file-time file-size collapse subtree-state vc-state git-msg))
  (setq delete-by-moving-to-trash t)
  (setq dired-listing-switches
        "-l --almost-all --human-readable --group-directories-first --no-group")
  (evil-make-overriding-map dirvish-mode-map 'normal)
  :bind ; Bind `dirvish|dirvish-side|dirvish-dwim' as you see fit
  (("C-c f" . dirvish)
   :map dirvish-mode-map ; Dirvish inherits `dired-mode-map'
   ("a"   . dirvish-quick-access)
   ("f"   . dirvish-file-info-menu)
   ("y"   . dirvish-yank-menu)
   ("N"   . dirvish-narrow)
   ("^"   . dirvish-history-last)
   ("h"   . dirvish-history-jump) ; remapped `describe-mode'
   ("s"   . dirvish-quicksort)    ; remapped `dired-sort-toggle-or-edit'
   ("v"   . dirvish-vc-menu)      ; remapped `dired-view-file'
   ("TAB" . dirvish-subtree-toggle)
   ("M-f" . dirvish-history-go-forward)
   ("M-b" . dirvish-history-go-backward)
   ("M-l" . dirvish-ls-switches-menu)
   ("M-m" . dirvish-mark-menu)
   ("M-t" . dirvish-layout-toggle)
   ("M-s" . dirvish-setup-menu)
   ("M-e" . dirvish-emerge-menu)
   ("M-j" . dirvish-fd-jump)))

Org and GTD

(use-package org
  :straight (:type built-in)
  :ensure org-plus-contrib
  :hook ((org-capture-mode . delete-other-windows)
         (org-capture-mode . evil-insert-state))
  :custom
  (org-support-shift-select t)
  (org-agenda-files nil) ;; Will be set automatically by org-gtd
  (org-ellipsis "")
  (org-cycle-separator-lines 1)
  ;; (org-pretty-entities t)

  (org-agenda-start-with-log-mode t)
  (org-agenda-window-setup 'only-window)
  (org-startup-folded 'content)
  (org-startup-indented t)
  (org-startup-with-inline-images t)
  (org-clock-persist 'history)
  (org-log-into-drawer t)
  (org-log-done 'time)
  (org-tag-persistent-alist '((:startgroup . nil)
                              ("@computer") ("@mail") ("@errands") ("@calls")
                              (:endgroup . nil) (:startgroup . nil)
                              ("@home") ("@office") ("@anywhere")
                              (:endgroup . nil)
                              ("@fun") ("@agenda")
                              ))

  :config
  ;; (setq org-agenda-prefix-format '((agenda . " %i %-12:c%?-12t%-6e% s")))
  ;; So that we can jump back
  (advice-add 'org-open-at-point :before #'evil-set-jump)

  ;; Clock stuff
  (when my-linux-p
    (org-clock-persistence-insinuate)
    (defun current-clock-time-to-file ()
      (interactive)
      (with-temp-file "~/.local/state/task"
        (if (org-clocking-p)
            (insert (org-clock-get-clock-string))
          (insert "No Task"))))
    (run-with-timer 1 60 'current-clock-time-to-file)
    (add-hook 'org-clock-in-hook 'current-clock-time-to-file)
    (add-hook 'org-clock-out-hook 'current-clock-time-to-file))

  ;; Custom functions
  (defun org-capture-inbox ()
    (interactive)
    (call-interactively 'org-store-link)
    (org-capture nil "i"))
  (defun org-capture-mail ()
    (interactive)
    (call-interactively 'org-store-link)
    (org-capture nil "@"))
  :bind
  ("C-c i" . org-capture-inbox)
  ("C-c a" . org-agenda)
  ("C-c l" . org-store-link)
  )
(defun my/org-gtd-maybe-set-tags ()
  "Use as a hook when decorating items after clarifying them."
  (unless (org-gtd-organize-type-member-p '(trash knowledge quick-action incubated project-heading))
    (org-set-tags-command)))
(defun my/org-gtd-maybe-set-effort ()
  "Use as a hook when decorating items after clarifying them."
  (unless (org-gtd-organize-type-member-p '(trash knowledge quick-action incubated project-heading))
    (org-set-effort)))

(use-package org-gtd
  :straight (:type git :host github :repo "Trevoke/org-gtd.el")
  :after org
  ;; :ensure t
  :demand t
  :init
  (setq org-gtd-update-ack "3.0.0")
  (setq org-gtd-areas-of-focus '("Work Leadership" "Work Architecture" "Work Support"
                                 "Productivity" "Personal Development" "Personal Services"
                                 "Family" "Health" "Finances"))
  :custom
  (org-gtd-directory "~/ndxrd-uxxs3/org/")
  (org-edna-use-inheritance t)
  (org-gtd-organize-hooks '(org-gtd-areas-of-focus--set my/org-gtd-maybe-set-tags my/org-gtd-maybe-set-effort))
  (org-gtd-refile-to-any-target nil)
  (org-gtd-engage-prefix-width 24)
  :config
  (org-edna-mode 1)
  (org-gtd-mode 1)
  :bind
  (("C-c d c" . org-gtd-capture)
   ("C-c c"   . org-gtd-capture)
   ("C-c d e" . org-gtd-engage)
   ("C-c d p" . org-gtd-process-inbox)
   ("C-c d n" . org-gtd-show-all-next)
   ("C-c d x" . org-gtd-clarify-item)
   ("C-c d w" . org-gtd-delegate-item-at-point)
   ("C-c d a" . org-gtd-area-of-focus-set-on-item-at-point)
   ("C-c d s" . org-save-all-org-buffers)
   :map org-gtd-clarify-map
   ("C-c c" . org-gtd-organize)
   :map org-agenda-mode-map
   ("C-c d a" . org-gtd-area-of-focus-set-on-agenda-item)
   ("C-c d x" . org-gtd-clarify-agenda-item)
   ))

Notes

(use-package denote
  ;; :demand
  :custom
  (denote-directory (expand-file-name "~/ndxrd-uxxs3/notes/"))
  (denote-known-keywords '("emacs" "philosophy" "politics" "economics"))
  (denote-file-type 'markdown-yaml)
  (denote-infer-keywords t)
  (denote-sort-keywords t)
  (denote-date-prompt-use-org-read-date t)
  (denote-backlinks-show-context t)
  (denote-templates
   `((weekly-review . ,(f-read (expand-file-name
                                "templates/weekly-review.md"
                                user-emacs-directory)))))
  :config
  (defun my-weekly-review-journal ()
    "Create an entry tagged 'weeklyreview' with the year and week as
       its title using the 'weekly-review' template. If a note for
       the current week exists, visit it.  If multiple entries
       exist, prompt with completion for a choice between them.
       Else create a new file."
    (interactive)
    (let* ((denote-directory (concat denote-directory "journals/"))
           ;; Year corresponding to ISO week + ISO week
           (week (format-time-string "%G W%V"))
           (string (denote-sluggify week))
           (files (denote-directory-files-matching-regexp string))
           )
      (cond
       ((> (length files) 1)
        (find-file (completing-read "Select file: " files nil :require-match)))
       (files
        (find-file (car files)))
       (t
        (denote week '("weeklyreview") nil nil nil 'weekly-review)))))
  (defun my-denote-journal ()
    "Create an entry tagged 'journal' with the date as its title.
       If a journal for the current day exists, visit it.  If multiple
       entries exist, prompt with completion for a choice between them.
       Else create a new file."
    (interactive)
    (let* ((denote-directory (concat denote-directory "journals/"))
           (today (format-time-string "%A %e %B %Y"))
           (string (denote-sluggify today))
           (files (denote-directory-files-matching-regexp string)))
      (cond
       ((> (length files) 1)
        (find-file (completing-read "Select file: " files nil :require-match)))
       (files
        (find-file (car files)))
       (t
        (denote today '("journal"))))))
  :hook (dired-mode . denote-dired-mode)
  ;; :bind (map :global-map
  ;;            ("C-c n d" . (dired-jump denote-directory)))
  :bind
  ("C-c n n" . denote)
  ("C-c n j" . my-denote-journal)
  ("C-c n r" . my-weekly-review-journal)
  )
(use-package denote-menu
  :after denote)
(use-package consult-notes
  :init
  (require 'denote)
  :config
  (consult-notes-denote-mode 1)
  :bind
  ("C-c n f" . consult-notes)
  )

Ediff

(use-package ediff
  :config
  (setq ediff-split-window-function 'split-window-horizontally)
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
  (defun my/command-line-diff (switch)
    (setq initial-buffer-choice nil)
    (let ((file1 (pop command-line-args-left))
      (file2 (pop command-line-args-left)))
      (ediff file1 file2)))
  ;; show the ediff command buffer in the same frame
  (add-to-list 'command-switch-alist '("-diff" . my/command-line-diff)))

File tree

(use-package treemacs
  :init
  (with-eval-after-load 'winum
    (define-key winum-keymap (kbd "M-0") #'treemacs-select-window))
  :config
  (defun my-treemacs-toggle ()
    "Initialize or toggle treemacs.
Ensures that only the current project is present and all other projects have
been removed.
Use `treemacs' command for old functionality."
    (interactive)
    (pcase (treemacs-current-visibility)
      (`visible (delete-window (treemacs-get-local-window)))
      (_ (treemacs-add-and-display-current-project))))
  :custom
  (treemacs-follow-after-init t)
  (treemacs-is-never-other-window t)
  (treemacs-follow-mode -1)
  :bind
  (:map global-map
        ("M-0"       . treemacs-select-window)
        ("C-x t 1"   . treemacs-delete-other-windows)
        ("C-x t t"   . my-treemacs-toggle)
        ("C-x t d"   . treemacs-select-directory)
        ("C-x t B"   . treemacs-bookmark)
        ("C-x t C-t" . treemacs-find-file)
        ("C-x t M-t" . treemacs-find-tag))
  )
(use-package treemacs-evil
  :after (treemacs evil)
  :ensure t)

(use-package treemacs-icons-dired
  :hook (dired-mode . treemacs-icons-dired-enable-once)
  :ensure t)

(use-package treemacs-magit
  :after (treemacs magit)
  :ensure t)

Presentations

(use-package org-tree-slide)

(use-package visual-fill-column
  :custom
  (visual-fill-column-width 90)
  (visual-fill-column-center-text t))

(defun my/org-present-start ()
  ;; Center the presentation and wrap lines
  (visual-fill-column-mode 1)
  (visual-line-mode 1)
  (setq-local face-remapping-alist
              '((default (:height 1.5) variable-pitch)
                (header-line (:height 4.0) variable-pitch)
                (org-document-title (:height 1.75) org-document-title)
                (org-code (:height 1.55) org-code)
                (org-verbatim (:height 1.55) org-verbatim)
                (org-block (:height 1.25) org-block)
                (org-block-begin-line (:height 0.7) org-block)))
  (setq header-line-format " ")
  )
(defun my/org-present-end ()
  ;; Stop centering the document
  (visual-fill-column-mode 0)
  (visual-line-mode 0)
  ;; (setq-local face-remapping-alist '((default variable-pitch default)))
  (setq-local face-remapping-alist 'nil)
  (setq header-line-format nil)
  )

(use-package org-present
  :hook
  (org-present-mode . my/org-present-start)
  (org-present-mode-quit . my/org-present-end)
  )

Tab line

(use-package intuitive-tab-line
  :straight (:type git :host github :repo "thread314/intuitive-tab-line-mode")
  :custom
  (tab-line-tabs-function 'intuitive-tab-line-buffers-list)
  (tab-line-switch-cycling t)
  :config
  (global-tab-line-mode 1)
  (recentf-mode 1)
  (setq
   tab-line-new-button-show nil  ;; do not show add-new button
   tab-line-close-button-show nil  ;; do not show close button
   tab-line-separator " "  ;; delimitation between tabs
   ))

(global-set-key (kbd "C-<prior>") 'tab-line-switch-to-prev-tab)
(global-set-key (kbd "C-<iso-lefttab>") 'tab-line-switch-to-prev-tab)
(global-set-key (kbd "C-<next>") 'tab-line-switch-to-next-tab)
(global-set-key (kbd "C-<tab>") 'tab-line-switch-to-next-tab)
(global-set-key (kbd "C-S-<prior>") 'intuitive-tab-line-shift-tab-left)
(global-set-key (kbd "C-S-<next>") 'intuitive-tab-line-shift-tab-right)
(global-set-key (kbd "C-S-t") 'recentf-open-most-recent-file)

Workspaces - beframe

(use-package beframe
  :demand
  :custom
  (beframe-functions-in-frames '(project-prompt-project-dir))
  :config
  (beframe-mode 1)
  (defvar consult-buffer-sources)
  (declare-function consult--buffer-state "consult")

  (with-eval-after-load 'consult
    (defface beframe-buffer
      '((t :inherit font-lock-string-face))
      "Face for `consult' framed buffers.")

    (defun my-beframe-buffer-names-sorted (&optional frame)
      "Return the list of buffers from `beframe-buffer-names' sorted by visibility.
  With optional argument FRAME, return the list of buffers of FRAME."
      (beframe-buffer-names frame :sort #'beframe-buffer-sort-visibility))

    (defvar beframe-consult-source
      `( :name     "Frame-specific buffers (current frame)"
         :narrow   ?F
         :category buffer
         :face     beframe-buffer
         :history  beframe-history
         :items    ,#'my-beframe-buffer-names-sorted
         :action   ,#'switch-to-buffer
         :state    ,#'consult--buffer-state))

    (add-to-list 'consult-buffer-sources 'beframe-consult-source))

  (define-key global-map (kbd "C-c b") #'beframe-prefix-map)
  (global-set-key (kbd "C-b") 'consult-buffer)
  (define-key evil-normal-state-map (kbd "C-b") 'consult-buffer)
  )

Learning & Discovering

(use-package command-log-mode
  :config
  (global-command-log-mode))

(use-package which-key
  :config (which-key-mode 1))

(defun my-reload-emacs-configuration ()
  (interactive)
  (load-file "~/.config/s-emacs/init.el"))

Completions - consult, vertico & friends

(use-package savehist
  :config
  (setq history-length 25)
  (savehist-mode 1))

(defun dw/minibuffer-backward-kill (arg)
  "When minibuffer is completing a file name delete up to parent
           folder, otherwise delete a word"
  (interactive "p")
  (if minibuffer-completing-file-name
      ;; Borrowed from https://github.com/raxod502/selectrum/issues/498#issuecomment-803283608
      (if (string-match-p "/." (minibuffer-contents))
          (zap-up-to-char (- arg) ?/)
        (delete-minibuffer-contents))
    (backward-kill-word arg)))

(use-package vertico
  :straight '(vertico :host github
                      :repo "minad/vertico"
                      :branch "main")
  :bind (:map vertico-map
              ("C-j" . vertico-next)
              ("C-k" . vertico-previous)
              ("C-f" . vertico-exit)
              :map minibuffer-local-map
              ("M-h" . dw/minibuffer-backward-kill))
  :custom
  (vertico-cycle t)
  ;; :custom-face
  ;; (vertico-current ((t (:background "#3a3f5a"))))
  :init
  (vertico-mode))

(use-package corfu
  :straight '(corfu :host github
                    :repo "minad/corfu")
  :bind (:map corfu-map
              ("C-j" . corfu-next)
              ("C-k" . corfu-previous)
              ("C-f" . corfu-insert))
  :custom
  (corfu-cycle t)
  :config
  (corfu-global-mode))

(use-package orderless
  :custom
  ;; (completion-styles '(orderless))
  ;; (completion-category-defaults nil)
  ;; (completion-category-overrides '((file (styles . (partial-completion)))))
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles basic partial-completion))))
  )

(defun dw/get-project-root ()
  (when (fboundp 'projectile-project-root)
    (projectile-project-root)))

(use-package consult
  :straight t
  :demand t
  ;; Replace bindings. Lazily loaded due by `use-package'.
  :bind (
         ;; My bindings
         ("C-s" . consult-line)
         ;; C-c bindings in `mode-specific-map'
         ("C-c M-x" . consult-mode-command)
         ("C-c h" . consult-history)
         ("C-c k" . consult-kmacro)
         ("C-c m" . consult-man)
         ("C-c i" . consult-info)
         ([remap Info-search] . consult-info)
         ;; C-x bindings in `ctl-x-map'
         ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
         ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
         ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
         ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
         ("C-x r b" . consult-bookmark)            ;; orig. bookmark-jump
         ("C-x p b" . consult-project-buffer)      ;; orig. project-switch-to-buffer
         ;; Custom M-# bindings for fast register access
         ("M-#" . consult-register-load)
         ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
         ("C-M-#" . consult-register)
         ;; Other custom bindings
         ("M-y" . consult-yank-pop)                ;; orig. yank-pop
         ;; M-g bindings in `goto-map'
         ("M-g e" . consult-compile-error)
         ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck
         ("M-g g" . consult-goto-line)             ;; orig. goto-line
         ("M-g M-g" . consult-goto-line)           ;; orig. goto-line
         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ("M-g i" . consult-imenu)
         ("M-g I" . consult-imenu-multi)
         ;; M-s bindings in `search-map'
         ("M-s d" . consult-find)
         ("M-s D" . consult-locate)
         ("M-s g" . consult-grep)
         ("M-s G" . consult-git-grep)
         ("M-s r" . consult-ripgrep)
         ("M-s l" . consult-line)
         ("M-s L" . consult-line-multi)
         ("M-s k" . consult-keep-lines)
         ("M-s u" . consult-focus-lines)
         ;; Isearch integration
         ("M-s e" . consult-isearch-history)
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string
         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch
         ("M-s L" . consult-line-multi)            ;; needed by consult-line to detect isearch
         ;; Minibuffer history
         :map minibuffer-local-map
         ("M-s" . consult-history)                 ;; orig. next-matching-history-element
         ("M-r" . consult-history))                ;; orig. previous-matching-history-element

  ;; Enable automatic preview at point in the *Completions* buffer. This is
  ;; relevant when you use the default completion UI.
  :hook (completion-list-mode . consult-preview-at-point-mode)

  ;; The :init configuration is always executed (Not lazy)
  :init

  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (setq register-preview-delay 0.5
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)

  :custom
  (consult-project-root-function #'dw/get-project-root)
  (completion-in-region-function #'consult-completion-in-region)

  ;; Configure other variables and modes in the :config section,
  ;; after lazily loading the package.
  :config

  ;; Optionally configure preview. The default value
  ;; is 'any, such that any key triggers the preview.
  ;; (setq consult-preview-key 'any)
  ;; (setq consult-preview-key "M-.")
  ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
  ;; For some commands and buffer sources it is useful to configure the
  ;; :preview-key on a per-command basis using the `consult-customize' macro.
  (consult-customize
   consult-theme :preview-key '(:debounce 0.2 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-bookmark consult--source-file-register
   consult--source-recent-file consult--source-project-recent-file
   ;; :preview-key "M-."
   :preview-key '(:debounce 0.4 any))

  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (setq consult-narrow-key "<") ;; "C-+"

  ;; Optionally make narrowing help available in the minibuffer.
  ;; You may want to use `embark-prefix-help-command' or which-key instead.
  ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
  )

(use-package marginalia
  :after vertico
  :straight t
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
  :init
  (marginalia-mode))

(use-package embark
  :straight t
  :bind (("C-S-a" . embark-act)
         :map minibuffer-local-map
         ("C-d" . embark-act))
  :config

  ;; Show Embark actions via which-key
  (setq embark-action-indicator
        (lambda (map)
          (which-key--show-keymap "Embark" map nil nil 'no-paging)
          #'which-key--hide-popup-ignore-command)
        embark-become-indicator embark-action-indicator))

Project Root

From: https://andreyorst.gitlab.io/posts/2022-07-16-project-el-enhancements/ WARN: This makes emacs on Windows extremely slow

(when my-linux-p
  (use-package project
    :config
    (defcustom project-root-markers
      '(".project")
      "Files or directories that indicate the root of a project."
      :type '(repeat string)
      :group 'project)
    (defun project-root-p (path)
      "Check if the current PATH has any of the project root markers."
      (catch 'found
        (dolist (marker project-root-markers)
          (when (file-exists-p (concat path marker))
            (throw 'found marker)))))
    ;; (defun project-find-root (path)
    ;;   "Search up the PATH for `project-root-markers'."
    ;;   (when-let ((root (locate-dominating-file path #'project-root-p)))
    ;;     (cons 'transient (expand-file-name root))))
    (defun project-find-root (path)
      "Search up the PATH for `project-root-markers'."
      (let ((path (expand-file-name path)))
        (catch 'found
          (while (not (equal "/" path))
            (if (not (project-root-p path))
                (setq path (file-name-directory (directory-file-name path)))
              (throw 'found (cons 'transient path)))))))
    (add-to-list 'project-find-functions #'project-find-root)
    ))

Dictionary and spelling

(when my-linux-p
  (setq dictionary-server "localhost")
  (use-package flyspell
    :hook ((text-mode . flyspell-mode)
           (org-mode . flyspell-mode)
           (prog-mode . flyspell-prog-mode)))
  )

AI Assistants

(use-package copilot
  :diminish
  :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))
  :ensure t
  :hook (prog-mode . copilot-mode)
  :bind (
         ;; ("C-TAB" . 'copilot-accept-completion-by-word)
         ;; ("C-<tab>" . 'copilot-accept-completion-by-word)
         :map copilot-completion-map
         ("<tab>" . 'copilot-accept-completion)
         ("TAB" . 'copilot-accept-completion))
  )

(use-package auth-source-1password
  :config
  (auth-source-1password-enable))

(use-package chatgpt-shell
  :ensure t
  :custom
  ((chatgpt-shell-openai-key
    (lambda ()
      (auth-source-pick-first-password :host "openai-key" :user "credential")))))

Misc for software dev

Language Modes

(use-package markdown-mode
  :mode ("README\\.md\\'" . gfm-mode)
  :init (setq markdown-command '("pandoc" "--from=markdown" "--to=html5"))
  )
(use-package magit)
(use-package json-mode)
(when my-windows-p
  (use-package ahk-mode))
(use-package php-mode)

Erlang & LSP

(use-package yasnippet
  :diminish (yas-minor-mode)
  :config
  (yas-global-mode t)
  )

;; Install the official Erlang mode
(when my-linux-p
  (add-to-list
   'load-path (car (file-expand-wildcards
                    "/usr/lib/erlang/lib/tools-*/emacs"))))
(when my-windows-p
  (add-to-list
   'load-path (car (file-expand-wildcards
                    "/Program Files/Erlang OTP/lib/tools-*/emacs"))))
(use-package erlang
  :straight nil
  :hook ((erlang-mode . linum-mode)
         (erlang-mode . column-number-mode))
  :init
  )
(require 'erlang-start)
(use-package elixir-mode)

(use-package eglot
  :hook (erlang-mode . eglot-ensure)
  :config
  (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)))
  )

Docker and Kubernetes

(use-package dockerfile-mode)
(use-package yaml-mode)
(use-package kubernetes
  :ensure t
  :commands (kubernetes-overview)
  :config
  (setq kubernetes-poll-frequency 3600
        kubernetes-redraw-frequency 3600))
(use-package kubernetes-evil
  :ensure t
  :after kubernetes)

Mastodon

(use-package emojify)
;; (:hook (after-init . global-emojify-mode))
(use-package mastodon
  :straight (:package mastodon :host nil :type git :repo "https://codeberg.org/martianh/mastodon.el.git" :branch "develop")
  :ensure t
  :config
  (setq mastodon-instance-url "https://fedi.srijan.dev"
        mastodon-active-user "srijan")
  )

mu4e

(use-package mu4e
  :straight nil
  :if my-linux-p
  :hook (evil-collection-setup . (lambda (&rest a)
                                   (evil-define-key 'normal mu4e-headers-mode-map "z%" 'mu4e-headers-mark-thread)
                                   ))
  :config
  (setq
   ;; mu4e-use-maildirs-extension nil
   mu4e-get-mail-command "systemctl --user start mbsync.service" ;; "mbsync fastmail-all"
   mu4e-view-prefer-html t
   ;; mu4e-update-interval 180
   mu4e-headers-auto-update t
   mu4e-search-include-related nil
   mu4e-compose-signature-auto-include nil
   mu4e-compose-format-flowed t
   mu4e-use-fancy-chars t
   mu4e-headers-visible-flags '(draft flagged new passed replied trashed attach encrypted signed)
   mu4e-headers-fields '((:human-date . 12)
                         (:flags . 6)
                         (:from-or-to . 32)
                         (:subject))
   mu4e-headers-date-format "%Y-%m-%d"
   mu4e-headers-from-or-to-prefix '("" . "To: ")
   mu4e-headers-leave-behavior 'apply
   mu4e-hide-index-messages t
   message-kill-buffer-on-exit t
   )


  (defun my-mu4e-refile-folder-fun (msg)
    "Set the refile folder for MSG."
    (let ((date (mu4e-message-field msg :date)))
      (cond
       (date
        (format "/fastmail/Archive/%s" (format-time-string "%Y" date)))
       (t
        "/fastmail/Archive"))))

  (setq user-full-name "Srijan Choudhary"
        mu4e-sent-folder "/fastmail/Sent Items"
        mu4e-drafts-folder "/fastmail/Drafts"
        mu4e-trash-folder "/fastmail/Trash"
        ;; mu4e-refile-folder "/fastmail/Archive"
        mu4e-refile-folder 'my-mu4e-refile-folder-fun
        mu4e-attachment-dir  "~/Downloads"
        )

  ;; enable inline images
  (setq mu4e-view-show-images t)

  ;; use imagemagick, if available
  (when (fboundp 'imagemagick-register-types)
    (imagemagick-register-types))

  ;; every new email composition gets its own frame!
  ;; (setq mu4e-compose-in-new-frame t)

  ;; don't save message to Sent Messages, IMAP takes care of this
  (setq mu4e-sent-messages-behavior 'sent)

  (add-hook 'mu4e-view-mode-hook #'visual-line-mode)

  ;; <tab> to navigate to links, <RET> to open them in browser
  (add-hook 'mu4e-view-mode-hook
            (lambda()
              ;; try to emulate some of the eww key-bindings
              (local-set-key (kbd "<RET>") 'mu4e~view-browse-url-from-binding)
              (local-set-key (kbd "<tab>") 'shr-next-link)
              (local-set-key (kbd "<backtab>") 'shr-previous-link)))

  ;; spell check
  (add-hook 'mu4e-compose-mode-hook
            (defun my-do-compose-stuff ()
              "My settings for message composition."
              (visual-line-mode)
              ;; (org-mu4e-compose-org-mode)
              (use-hard-newlines -1)
              ;; (flyspell-mode)
              ))

  ;;rename files when moving
  ;;NEEDED FOR MBSYNC
  (setq mu4e-change-filenames-when-moving t)

  ;; bookmarks
  (add-to-list 'mu4e-bookmarks
               '( :name  "Inbox GO"
                  :query "maildir:\"/fastmail/Inbox GO\""
                  :key   ?g))
  (add-to-list 'mu4e-bookmarks
               '( :name  "Inbox Personal"
                  :query "maildir:\"/fastmail/Inbox\""
                  :key   ?p))
  (add-to-list 'mu4e-bookmarks
               '( :name  "Sent Items"
                  :query "maildir:\"/fastmail/Sent Items\""
                  :key   ?s))
  (add-to-list 'mu4e-bookmarks
               '( :name  "Waiting For Support"
                  :query "\"maildir:/fastmail/@Waiting For Support\""
                  :key   ?f))
  (add-to-list 'mu4e-bookmarks
               '( :name  "Action Support"
                  :query "\"maildir:/fastmail/@Action Support\""
                  :key   ?a))
  (add-to-list 'mu4e-bookmarks
               '( :name  "Inbox"
                  :query "\"maildir:/fastmail/Inbox\" or \"maildir:/fastmail/Inbox GO\""
                  :key   ?i))

  ;; set mail user agent
  (setq mail-user-agent 'mu4e-user-agent
        message-mail-user-agent 'mu4e-user-agent)

  ;; Setup mu4e contexts. This is to enable adding multiple email contexts if needed in the future.
  ;; I will initially only enable my fastmail context but adding a new one shouldn't be harder than copying
  ;; the existing context and modifying the settings.
  (setq mu4e-context-policy 'pick-first)
  (setq mu4e-compose-context-policy 'ask)
  (setq mu4e-contexts
        (list
         (make-mu4e-context
          :name "fastmail"
          :enter-func (lambda () (mu4e-message "Entering context fastmail"))
          :leave-func (lambda () (mu4e-message "Leaving context fastmail"))
          :match-func (lambda (msg)
                        (when msg
                          (mu4e-message-contact-field-matches
                           msg '(:from :to :cc :bcc) "[email protected]")))
          :vars '((user-mail-address . "[email protected]")
                  ;; (mu4e-compose-signature . (concat "Srijan Choudhary\n" "https://www.srijn.net\n"))
                  (mu4e-compose-format-flowed . t)
                  ))
         (make-mu4e-context
          :name "personal"
          :enter-func (lambda () (mu4e-message "Entering context personal"))
          :leave-func (lambda () (mu4e-message "Leaving context personal"))
          :match-func (lambda (msg)
                        (when msg
                          (mu4e-message-contact-field-matches
                           msg '(:from :to :cc :bcc) "[email protected]")))
          :vars '((user-mail-address . "[email protected]")
                  ;; (mu4e-compose-signature . (concat "Srijan Choudhary\n" "https://www.srijn.net\n"))
                  (mu4e-compose-format-flowed . t)
                  ))
         (make-mu4e-context
          :name "greyorange"
          :enter-func (lambda () (mu4e-message "Entering context greyorange"))
          :leave-func (lambda () (mu4e-message "Leaving context greyorange"))
          :match-func (lambda (msg)
                        (when msg
                          (mu4e-message-contact-field-matches
                           msg '(:from :to :cc :bcc) "[email protected]")))
          :vars '((user-mail-address . "[email protected]")
                  ;; (mu4e-compose-signature . (concat "Srijan Choudhary\n" "https://www.srijn.net\n"))
                  (mu4e-compose-format-flowed . t)
                  ))
         ))

  ;; Allow replying to calendar events
  ;; https://www.djcbsoftware.nl/code/mu/mu4e/iCalendar.html
  (require 'mu4e-icalendar)
  (mu4e-icalendar-setup)
  (setq mu4e-icalendar-trash-after-reply t)

  )
(use-package org
  :if my-linux-p
  :bind (
         :map mu4e-headers-mode-map
         ("C-c i" . org-capture-mail)
         ;; ("z m" . mu4e-view-mark-thread)
         :map mu4e-view-mode-map
         ("C-c i" . org-capture-mail))
  )

(use-package org-msg
  :if my-linux-p
  :config
  (setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
        org-msg-startup "hidestars indent inlineimages"
        org-msg-default-alternatives '((new             . (text html))
                                       (reply-to-html   . (text html))
                                       (reply-to-text   . (text)))
        org-msg-convert-citation t
        org-msg-signature "

#+begin_signature
--
*Srijan Choudhary*
#+end_signature")
  (org-msg-mode)
  )

(use-package smtpmail
  :if my-linux-p
  :config

  (setq sendmail-program "/usr/bin/msmtp"
        send-mail-function 'smtpmail-send-it
        message-sendmail-f-is-evil t
        ;; This allows msmtp to automatically choose the correct account
        ;; based on from header.
        message-sendmail-extra-arguments '("--read-envelope-from")
        message-send-mail-function 'message-send-mail-with-sendmail
        smtpmail-debug-info t
        smtpmail-debug-verbose t
        )

  (setq smtpmail-queue-mail nil)
  (setq smtpmail-queue-dir "~/Maildir/queue/cur")
  )

Ending Stuff

(setq gc-cons-threshold (* 2 1000 1000))
(add-hook 'emacs-startup-hook
          (lambda ()
            (message "Emacs ready in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))

(let ((inhibit-message t))
  (message "Welcome to GNU Emacs / N Λ N O edition")
  (message (format "Initialization time: %s" (emacs-init-time))))