Skip to content

Latest commit

 

History

History
2734 lines (2361 loc) · 104 KB

emacs-config.org

File metadata and controls

2734 lines (2361 loc) · 104 KB

#+header-args: :noweb yes :results none

Emacs Config

Package setup

We will use melpa and elpa as our package archives, and load use-package, which will be used extensively everywhere else.

     (require 'package)
     (setq package-archives nil)
     ;;; Auto add packages
     (setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")))
     (add-to-list 'package-archives
		   '("melpa" . "https://melpa.org/packages/") t)
     (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/"))

     (package-initialize)

     (unless (package-installed-p 'use-package)
	(package-install 'use-package))

     (require 'use-package)
     (use-package diminish :ensure t)
     (use-package general :ensure t)

     ;;; Let's make all bindings follow C-c, and C-x prefix for
     ;;; single key commands

     (general-unbind "C-c")                  ; we will C-c as base for all modules
     (general-unbind "C-x v")                ; unbind vc map
     (general-unbind "C-x r")                ; unbind bookmark and register

     (general-create-definer fconfig-C-c-bind
       :prefix "C-c"
       :name "Global shortcuts with C-c prefix")

     (general-create-definer fconfig-C-x-bind
       :prefix "C-x"
       :name "Global shortcuts with C-x prefix")

     ;;; inhibit cl warning
     (setq byte-compile-warnings '(cl-functions))

Load the config manager fconfig, so it will be easier to load utility function from .el files.

(require 'fconfig)

(use-package doom-themes :ensure t)

;; this is ugly
(setq notes-dir (expand-file-name "~/notes/"))

(fconfig/init)
(fconfig! utils)
Install straight
;; Install straight.el
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (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))

Fundamentals

Setup packages and utility functions
	(defun fconfig-load (file)
	  "This function is to be used to load files. If a filename has org
	extension babel will be used to load the file, or else just plain load-file"
	  (let ((filename (expand-file-name file config-dir)))
	    (if (file-exists-p filename)
		(if (string= (file-name-extension filename) "org")
		    (org-babel-load-file filename)
		  (load-file filename))
	      (message (format "file not found: %s" filename)))))
Custom file

Lets have a separate custom file.

(setq custom-file "~/.emacs.d/custom.el")
Don’t show startup
	(setq inhibit-startup-screen t
	      initial-scratch-message nil
	      inhibit-startup-message t)
All about backups

I would to keep backups and not delete the old ones, even if a file is part of a VC.

	(setq
	 backup-directory-alist '(("." . "~/.emacs.d/backups"))
	 delete-old-versions -1
	 version-control t
	 vc-make-backup-files t
	 auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t)))
No bars

No menu bar, tool bar or scroll bar

	(when (fboundp 'menu-bar-mode) (menu-bar-mode -1))
	(when (fboundp 'tool-bar-mode) (tool-bar-mode -1))
	(when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
	(when (fboundp  'tooltip-mode) (tooltip-mode -1))
Lets prefer utf-8

That’s specifically for cygwin and windows

	(set-default-coding-systems 'utf-8-unix)
	(prefer-coding-system 'utf-8-unix)
	(set-default buffer-file-coding-system 'utf-8-unix)
Interact with the system clipboard
	(setq select-enable-clipboard t
	      select-enable-primary t)
Load location settings

This should be loaded early; and this cannot be part of the person config load section, since it is loaded at the end.

     (let ((location-file (expand-file-name "location.el" "~/.emacs.d")))
	 (when (file-exists-p location-file)
	   (load-file location-file)))

Let have some space between lines, make the text more legible.

	(setq-default line-spacing 3)
Mode line

A minimilatic, non-cluttering mode line is what is needed. Doom mode line does that job.

	(use-package minions
	  :ensure t
	  :hook (doom-modeline-mode . minions-mode))

	(use-package doom-modeline
	  :ensure t
	  :hook (emacs-startup . doom-modeline-mode)
	  :custom-face
	  (mode-line ((t (:height 1.20))))
	  :custom
	  (doom-modeline-height 15)
	  (doom-modeline-bar-width 6)
	  (doom-modeline-lsp t)
	  (doom-modeline-github nil)
	  (doom-modeline-irc nil)
	  (doom-modeline-persp-name nil)
	  (doom-modeline-buffer-file-name-style 'relative-from-project)
	  (doom-modeline-major-mode-icon t))
Misc

Don’t ask when opening a symlink, always follow it.

	(setq vc-follow-symlinks t)

Enable auto-revert of buffers

	(global-auto-revert-mode)
Window Management

Enable winner mode

	(winner-mode)
Fonts
	(set-fontset-font t 'devanagari "Noto Serif Devanagiri")

Completions

     (use-package vertico
	:ensure t
	:init (vertico-mode)
	:config (general-def vertico-map "<tab>" 'vertico-insert))

     ;;; This is really slow, disable if it is very noticeable
     (use-package vertico-posframe
	:ensure t
	:after vertico
	:init (vertico-posframe-mode)
	:config
	(setq vertico-posframe-parameters
	      '((alpha . 0)
		(left-fringe . 9)
		(right-fringe . 9))
	      vertico-posframe-font "Monospace-14"))

     (use-package marginalia
	:ensure t
	:after vertico
	:init (marginalia-mode))

     (use-package orderless
	:ensure t
	:after vertico
	:custom (completion-styles '(orderless flex)))

     (use-package savehist
	:init
	(savehist-mode))

Frame

Window

Jump to different windows quickly using ace-window

(use-package ace-window
  :defer 3
  :ensure t
  :init (ace-window-display-mode)
  :config
  (setq aw-scope 'frame)
  (setq aw-ignore-current t)
  (setq ace-window-posframe-mode t))

Don’t create too many windows, and create small splits.

(setq split-width-threshold 200)

Shell

Setup completion in eshell

;; (use-package bash-completion
;;   :init (bash-completion-setup)
;;   (add-hook 'shell-dynamic-complete-functions
;;             'bash-completion-dynamic-complete))

Buffer

To move through buffers, I used to use the cycle-buffer package. But I rarely use the cycle-buffer-permissive and cycle-buffer-backward-permissive functions. So now moved to the builtin functions for cycling.

(general-def "<f11>" 'bs-cycle-previous)
(general-def "<f12>" 'bs-cycle-next)

Show a line at the 80 character column, helps while coding.

(use-package fill-column-indicator
  :ensure t
  :commands fci-mode)

Whitespace mode setup, show when there are trailing whitespaces in a line and also when there is space in empty lines.

     ;;; Whitespace mode setup
     (use-package whitespace
	:diminish whitespace-mode
	:commands whitespace-mode
	:init
	(progn
	  (setq whitespace-style '(face lines-tail trailing empty space-before-tab))))

Avoid window resizing and reuse windows when possible.

(setq display-buffer-base-action
      '((display-buffer-reuse-window
         display-buffer-reuse-mode-window
         display-buffer-same-window
         display-buffer-in-previous-window)
))

(setq display-buffer-alist '())
;;; https://www.gnu.org/software/emacs/manual/html_node/elisp/The-Zen-of-Buffer-Display.html
(add-to-list 'display-buffer-alist
             '("\\*Help\\*"
               (display-buffer-reuse-window display-buffer-pop-up-frame)
               (reusable-frames . visible)))

(add-to-list 'display-buffer-alist
             '(".*"
               (display-buffer-reuse-window display-buffer-pop-up-window)
               '((mode . (org-mode helpful-mode help-mode c-mode rust-mode go-mode)))
               (reusable-frames . visible)))

(setq even-window-sizes nil)

A function to create a temporary buffer

(defun create-temp-buffer-with-timestamp ()
  "Create a temporary buffer with a unique name based on the current date and time."
  (interactive)
  (let* ((timestamp (format-time-string "%Y-%m-%d %H:%M:%S"))
         (buffer-name (format "*Temp %s*" timestamp)))
    (with-current-buffer (get-buffer-create buffer-name)
      (insert (format "This is a temporary buffer created on %s.\nFeel free to use it and discard when done." timestamp))
      (goto-char (point-min))
      (display-buffer (current-buffer)))))

A general key binding definer for buffer operations

;; key bindings
(general-create-definer fconfig-buffer-bind
  :name "Buffer related bindings"
  :prefix "C-c b"
  "" '(:ignore t :which-key "Buffer related"))

(fconfig-buffer-bind
  "g" 'writegood-mode
  "w" 'whitespace-mode
  "l" 'recenter-top-bottom
  "p" 'reposition-window
  "s" 'flyspell-buffer
  "b" 'bury-buffer
  "r" 'revert-buffer
  "f" 'fci-mode
  "t" 'create-temp-buffer-with-timestamp)

Org-mode

Don’t want to see markers for italics and bold and underline, and let’s have only odd heading levels, with UT8 characters, makes for a slightly cleaner look.

(use-package org
  :mode ("\\.org$" . org-mode)
  :commands (org
             org-capture
             org-mode
             org-store-link
             update-org-hours
             my-term-agenda
             dired-notes)
  :init

  (add-to-list 'org-modules 'org-habit 'drill)
  (setq
   org-directory (expand-file-name "org" notes-dir)
   org-default-notes-file (expand-file-name "notes" org-directory)
   org-clock-sound t))

(general-create-definer fconfig-org-config-bind
  :prefix "C-c o"
  :name "Org mode bindings"
  "" '(:ignore t :which-key "Org-mode bindings"))

(setq org-hide-emphasis-markers t
      org-odd-levels-only t
      org-pretty-entities t
      org-adapt-indentation t
      org-enforce-todo-checkbox-dependencies t
      org-duration-format (quote h:mm))

(add-hook 'org-mode-hook (lambda ()
  "Beautify Org Checkbox Symbol"
  (push '("[ ]" .  "") prettify-symbols-alist)
  (push '("[X]" . "" ) prettify-symbols-alist)
  (push '("[-]" . "" ) prettify-symbols-alist)
  (prettify-symbols-mode)))

(defface org-checkbox-done-text
  '((t (:foreground "#71696A" :strike-through t)))
  "Face for the text part of a checked org-mode checkbox.")

(font-lock-add-keywords
 'org-mode
 `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)"
    1 'org-checkbox-done-text prepend))
 'append)

Use a org-bullets to show custom unicode bullets.

;; (use-package org-bullets
;;   :ensure t
;;   :hook (org-mode . org-bullets-mode)
;;   :custom
;;   (org-bullets-bullet-list '("◉" "○" "■" "◆" "▲" "▶"))
;;   (org-ellipsis "⤵"))

Always show latex previews, and pretty entities

(setq org-startup-with-latex-preview t)
(add-hook 'org-brain-visualize-text-hook 'org-latex-preview)

Let the syntax highlight be enabled in the source blocks. Also editing in the same window is less distracting.

 (setq org-src-fontify-natively t
	    org-src-window-setup 'current-window
	    org-src-strip-leading-and-trailing-blank-lines t)

Exiting org code block edit buffer, I see leading whitespaces in the file, which is not in the code blocks itself, but at a file level. I don’t like seeing leading/trailing whitespaces in the git diff output.

(advice-add 'org-edit-src-exit :after 'whitespace-cleanup)

Also get multiple lines to be parsed for markups like italic and bold.

;;; 5 lines maximum to markup
(setcar (nthcdr 4 org-emphasis-regexp-components) 5)
(org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components)

Move the point to the beginning of the agenda

; (add-hook 'org-agenda-finalize-hook #'org-agenda-find-same-or-today-or-agenda 90)

Always show org files in the same windows, especially useful when browsing through org-roam files. If needed I can explicitly split windows and open another buffer.

(setf (cdr (assoc 'file org-link-frame-setup)) 'find-file)
Fundamental org-mode settings
(setq
 org-hide-leading-stars t
 org-clock-persist 'history
 org-agenda-span 'day
 org-agenda-skip-deadline-if-done t
 org-agenda-skip-scheduled-if-done t
 org-agenda-skip-timestamp-if-done t
 org-clock-idle-time 30
 org-deadline-warning-days 7
 org-agenda-skip-scheduled-if-deadline-is-shown t
 org-return-follows-link t
 org-enforce-todo-dependencies t
 org-agenda-dim-blocked-tasks t
 org-habit-preceding-days 7
 org-habit-following-days 1
 org-habit-show-done-always-green t
 org-habit-show-habits-only-for-today nil
 org-habit-graph-column 75
 org-agenda-start-on-weekday 1
 org-agenda-todo-ignore-deadlines t
 org-agenda-include-diary t
 org-insert-mode-line-in-empty-file t
 org-use-speed-commands t
 org-clock-out-remove-zero-time-clocks t
 org-clock-out-when-done t
 org-clock-persist-query-resume nil
 org-clock-auto-clock-resolution (quote when-no-clock-is-running)
 org-clock-report-include-clocking-task t
 org-clock-history-length 20
 org-drawers (quote ("PROPERTIES" "LOGBOOK"))
 org-clock-into-drawer t
 org-log-into-drawer t
 org-log-state-notes-insert-after-drawers t
 org-export-with-sub-superscripts "{}"
 org-catch-invisible-edits t
 org-outline-path-complete-in-steps nil
 org-refile-use-outline-path t
 org-log-note-clock-out nil
 org-password-file "~/.passwds/credentials.gpg"
 org-agenda-show-future-repeats 'next
 org-agenda-sorting-strategy '((agenda habit-down time-up priority-down
                                       effort-up category-up)
                               (todo priority-down)
                               (tags priority-down))

 ;; a 8 hour, 5 day work week
 org-duration-units
 `(("min" . 1)
   ("h" . 60)
   ("d" . ,(* 60 8))
   ("w" . ,(* 60 8 5))
   ("m" . ,(* 60 8 5 4))
   ("y" . ,(* 60 8 5 4 10)))

 ;; Any single task cannot be spanning for weeks, otherwise it becomes a habit
 ;; task. Ordinarily a task (subtask mostly), shouldn't be spanning more than a
 ;; day. So the maximum subtask effort is set to 1d hours.
 org-global-properties (quote
                        (("Effort_ALL" . "0:15 0:30 0:40 1:00 1:40 2:00 2:40 3:00 3:40 4:00 4:40 5:00 6:00 1d")))

 org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM"
 keep-clock-running nil

 ;; Some calendar holiday tweaks
 calendar-view-diary-initially-flag t
 calendar-mark-diary-entries-flag t
 diary-number-of-entries 7
 holiday-general-holidays nil
 holiday-christian-holidays nil
 holiday-islamic-holidays nil
 holiday-hebrew-holidays nil
 holiday-bahai-holidays nil
 holiday-oriental-holidays nil
 holiday-solar-holidays nil

 org-latex-pdf-process
 '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
   "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
   "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f")

 org-format-latex-options (plist-put org-format-latex-options :scale 2.5)
 org-clock-mode-line-total 'today)
Setup org modules

The two most important org packages that we need are org-agenda and org-capture, set those up first. Also load org-contrib

	(use-package org-agenda)
	(use-package org-contrib :ensure t)
Make org-mode a bit more modern looking
(use-package "org-modern"
  :ensure t
  :config (global-org-modern-mode))
Reproducible research

After a source block is executed, and if that has a image as a result, by default the image is not displayed. One has to run org-display-inline-images after every source block evaluation to view the image result. To avoid that, add a hook to run the display command after every babel execution and load images by when org file startups. We also don’t want org to show the actual width of the image, let us have the option to resize them.

(setq org-startup-with-inline-images t)
(eval-after-load 'org
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images))

(setq org-image-actual-width nil)

Load library of babel file at init time.

(org-babel-lob-ingest (expand-file-name "org/lob/lob.org" notes-dir))

Some of the languages that I use with org-babel.

(use-package ob-go :ensure t)
(use-package ob-rust :ensure t)
(use-package gnuplot :ensure t)

(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (python . t)
   (go . t)
   (dot . t)
   (ditaa . t)
   (latex . t)
   (ledger .t)
   (shell . t)
   (rust . t)
   (scheme . t)
   (gnuplot . t)
   (sql . t)
   (plantuml . t)
   (calc . t)))

(setq org-plantuml-jar-path (expand-file-name "~/bin/plantuml.jar")
      org-ditaa-jar-path (expand-file-name "~/bin/ditaa-0.11.0-standalone.jar")
      ;; Don't ask when I evaluate code
      org-confirm-babel-evaluate nil)

Show colors in the results block

(defun ek/babel-ansi ()
  (when-let ((beg (org-babel-where-is-src-block-result nil nil)))
    (save-excursion
      (goto-char beg)
      (when (looking-at org-babel-result-regexp)
        (let ((end (org-babel-result-end))
              (ansi-color-context-region nil))
          (ansi-color-apply-on-region beg end))))))

(add-hook 'org-babel-after-execute-hook 'ek/babel-ansi)
Export Settings

Add a horizantal line before the footer when exporting to HTML

(setq org-html-postamble
      '((
         "en" "<hr/><p class=\"author\">Author: %a (%e)</p>\n<p class=\"date\">Date: %d</p>\n<p class=\"creator\">%c</p>\n<p class=\"validation\">%v</p>"))
      )
Presentation using org-mode

The slides for a presentation are usually generated from org file, through beamer and $\LaTeX$. Instead of doing that, org-present combined with hide-mode-line gives a nice interface to show slides directly from emacs.

	(use-package hide-mode-line
	  :ensure t)

	(use-package org-present
	  :ensure t
	  :config
	  (add-hook 'org-present-mode-hook
		    (lambda ()
		      (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
					     (header-line (:height 4.5) variable-pitch)
					     (org-code (:height 1.5) org-code)
					     (org-verbatim (:height 1.5) org-verbatim)
					     (org-block (:height 1.20) org-block)
					     (org-block-begin-line (:height 0.7) org-block)))
		      (org-display-inline-images)
		      (org-present-hide-cursor)
		      (hide-mode-line-mode 1)))

	  (add-hook 'org-present-mode-quit-hook
		    (lambda ()
		      (setq-local face-remapping-alist '((default variable-pitch default)))
		      (org-remove-inline-images)
		      (org-present-show-cursor)
		      (org-present-small)
		      (hide-mode-line-mode -1))))

Sometimes presentation using reveal.js does make an impact

	(use-package ox-reveal :ensure t)
For using beamer
; allow for export=>beamer by placing

;; #+LaTeX_CLASS: beamer in org files
(unless (boundp 'org-export-latex-classes)
  (setq org-export-latex-classes nil))
(add-to-list 'org-export-latex-classes
  ;; beamer class, for presentations
  '("beamer"
     "\\documentclass[11pt]{beamer}\n
      \\mode<{{{beamermode}}}>\n
      \\usetheme{{{{beamertheme}}}}\n
      \\usecolortheme{{{{beamercolortheme}}}}\n
      \\beamertemplateballitem\n
      \\setbeameroption{show notes}
      \\usepackage[utf8]{inputenc}\n
      \\usepackage[T1]{fontenc}\n
      \\usepackage{hyperref}\n
      \\usepackage{color}
      \\usepackage{listings}
      \\lstset{numbers=none,language=[ISO]C++,tabsize=4,
  frame=single,
  basicstyle=\\small,
  showspaces=false,showstringspaces=false,
  showtabs=false,
  keywordstyle=\\color{blue}\\bfseries,
  commentstyle=\\color{red},
  }\n
      \\usepackage{verbatim}\n
      \\institute{{{{beamerinstitute}}}}\n
       \\subject{{{{beamersubject}}}}\n"

     ("\\section{%s}" . "\\section*{%s}")

     ("\\begin{frame}[fragile]\\frametitle{%s}"
       "\\end{frame}"
       "\\begin{frame}[fragile]\\frametitle{%s}"
       "\\end{frame}")))

  ;; letter class, for formal letters

  (add-to-list 'org-export-latex-classes

  '("letter"
     "\\documentclass[11pt]{letter}\n
      \\usepackage[utf8]{inputenc}\n
      \\usepackage[T1]{fontenc}\n
      \\usepackage{color}"

     ("\\section{%s}" . "\\section*{%s}")
     ("\\subsection{%s}" . "\\subsection*{%s}")
     ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
     ("\\paragraph{%s}" . "\\paragraph*{%s}")
     ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
  
Note taking

Everything related to note taking, currently org-roam.

I like to clock-in to org-roam daily journal entries, which would nicely keep each clocked items and also the notes taken during that event in that particular day’s org file. This will also avoid cramming the agenda files with clock entries. End of the day, the work done can be viewed in a single place along with the notes.

https://d12frosted.io/posts/2021-01-16-task-management-with-roam-vol5.html

  • Keep each project in a separate file
  • Keep work project items in a subfolder
  • Dynamically add only those project files to the agenda list
org-roam
(general-create-definer fconfig-notes-bind
  :prefix "C-c n"
  :name "Notes actions"
  "" '(:ignore t :which-key "Notes options"))

(use-package websocket
  :ensure t
  :after org-roam)

(use-package emacsql
  :ensure t)

(use-package org-roam
  :ensure t
  :init
  (setq org-roam-v2-ack t
        org-roam-directory "~/notes/org/roam"
        org-roam-completion-everywhere t
        org-roam-dailies-directory "journal/"
        org-roam-node-display-template "${title:*} ${tags:20}")
  (org-roam-db-autosync-mode)

  :config
  (add-hook 'org-roam-mode-hook #'turn-on-visual-line-mode)
  (use-package org-roam-protocol)
  (org-roam-setup)
  (add-to-list 'aw-ignored-buffers 'org-roam-mode)
  (defun org-roam-node-insert-immediate (arg &rest args)
    (interactive "P")
    (let ((args (cons arg args))
          (org-roam-capture-templates (list (append (car org-roam-capture-templates)
                                                    '(:immediate-finish t)))))
      (apply #'org-roam-node-insert args))))

(add-to-list 'display-buffer-alist
             '("\\*org-roam\\*"
               (display-buffer-in-side-window)
               (dedicated . t)
               (side . right)
               (slot . 0)
               (window-width . 0.25)
               (preserve-size . (t nil))
               (window-parameters . ((no-other-window . t)
                                     (no-delete-other-windows . t)))))

(add-hook 'org-roam-mode-hook
          (lambda ()
            (setq-local display-buffer--same-window-action
                        '(display-buffer-use-some-window
                          (main)))))

(general-def org-mode-map "C-M-i" 'completion-at-point)

(use-package org-roam-ui
  :ensure t
  :after org-roam
  :config
  (setq org-roam-ui-sync-theme t
        org-roam-ui-follow t
        org-roam-ui-update-on-save t
        org-roam-ui-open-on-start nil))

;;; https://github.com/org-roam/org-roam/issues/1934#issuecomment-979735048
(defun santosh/preview-fetcher ()
  (let* ((elem (org-element-context))
         (parent (org-element-property :parent elem)))
    ;; TODO: alt handling for non-paragraph elements
    (string-trim-right (buffer-substring-no-properties
                        (org-element-property :begin parent)
                        (org-element-property :end parent)))))

(setq org-roam-preview-function #'santosh/preview-fetcher)

(defun org-capture-get-new-bug-auto-analysis ()
  "Run an external program asynchronously to add additional content to the captured entry."
  (async-shell-command "nvbug show path/to/external/program"))

(defun my-org-capture-additional-content ()
  "Capture additional content after the external program has finished."
  ;; Process the captured additional content here
  (let ((additional-content (with-current-buffer "*Async Shell Command*"
                              (buffer-string))))
    (when (stringp additional-content)
      (goto-char (org-capture-get :end))
      (insert additional-content))))

(setq org-roam-capture-templates
      '(("d" "Default" plain "%?" :target
         (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n\n")
         :jump-to-captured)
        ("b" "Book" plain "- %?\n\n" :if-new
         (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: :book:\n\n")
         :jump-to-captured)
        ("p" "Work Project" plain "%?"
         :target (file+head "work/%<%Y%m%d%H%M%S>-${slug}.org"
                            "#+title: ${title}\n#+filetags: :work:\n\n")
         :unnarrowed t
         :jump-to-captured)))

(setq org-roam-dailies-capture-templates
      (let ((head "#+title: %<%Y-%m-%d (%A)>\n#+category: Tasks\n#+startup: showall\n"))
        `(("d" "default" plain "%?"
           :target (file+head "%<%Y-%m-%d>.org" ,head))
          ("t" "Task" entry "* TODO %^{Task}   %^g\n"
           :target (file+head+olp "inbox.org" ,head ("Tasks"))
           :immediate-finish t)
          ("u" "Urgent Tasks" entry
           "*** TODO %^{Task}%?"
           :target (file+head+olp "%<%Y-%m-%d>.org" ,head ("Tasks")))
          ("b" "Bug" entry
           "*** TODO [[https://nvbugswb.nvidia.com/NvBugs5/SWBug.aspx?bugid=%^{Bug ID}][%^{System} - %^{Bug Title}]] :bug:\n    :PROPERTIES:\n    :CAPTURED: %U\n    :CATEGORY: Bug\n    :END:\n%?"
           :target (file+head+olp "%<%Y-%m-%d>.org" ,head ("Tasks"))
           :jump-to-captured)
          ("j" "Journal" entry "* %U %^{Summary}  %^g\n"
           :target (file+head+olp "%<%Y-%m-%d>.org" ,head ("Journal"))
           :jump-to-captured)
          ("c" "Team Call" entry
           "* %U %^{Title} :work:call:%^g\n"
           :target (file+head+olp "%<%Y-%m-%d>.org" ,head ("Journal"))
           :clock-in t :clock-resume t)
          ("r" "Morning Work Routine" entry
           "* %U Morning mail and bug sweep :work:\n"
           :target (file+head+olp "%<%Y-%m-%d>.org" ,head ("Journal"))
           :clock-in t :clock-resume t)
          )))

(defun org-roam-dailies-goto-previous-week ()
  (interactive)
  (let ((date (org-read-date nil nil "-7d")))
    (org-roam-dailies-goto-week date)))

(defun org-roam-dailies-goto-next-week ()
  (interactive)
  (let ((date (org-read-date nil nil "+7d")))
    (org-roam-dailies-goto-week date)))

(defun org-roam-dailies-goto-week (date)
  "Navigate to the dailies entry for the week containing DATE."
  (let ((weekly-file (format-time-string "%Y-W%W.org" (org-time-string-to-time date))))
    (find-file (concat (file-name-as-directory (concat (file-name-as-directory org-roam-directory) org-roam-dailies-directory)) weekly-file))))

(defun org-roam-dailies-goto-this-week ()
  (interactive)
  (let ((date (org-read-date nil nil "0d")))
    (org-roam-dailies-goto-week date)))

(defun org-roam-dailies-goto-day-in-week (date)
  "Navigate to the dailies entry for the week containing DATE, then jump to the day."
  (interactive (list (org-read-date)))
  (org-roam-dailies-goto-week date)
  (search-forward (format-time-string "%Y-%m-%d" (org-time-string-to-time date)) nil t))

(defun santosh/org-roam-dailies-goto-today ()
  "Don't prompt for a roam template, use the first entry from the template list"
  (interactive)
  (let ((org-roam-dailies-capture-templates (list (append (car org-roam-dailies-capture-templates)))))
    (org-roam-dailies-goto-today)))

(defun santosh/org-roam-dailies-goto-date ()
  "Don't prompt for a roam template, use the first entry from the template list"
  (interactive)
  (let ((org-roam-dailies-capture-templates (list (append (car org-roam-dailies-capture-templates)))))
    (org-roam-dailies-goto-date)))

(fconfig-notes-bind
  "b" 'org-roam-buffer-toggle
  "T" 'org-roam-dailies-capture-today
  "t" 'santosh/org-roam-dailies-goto-today
  "D" 'org-roam-dailies-capture-date
  "d" 'santosh/org-roam-dailies-goto-date
  "c" 'org-roam-capture
  "g" 'org-roam-graph
  "u" 'org-roam-ui-mode
  "i" 'org-roam-node-insert
  "I" 'org-roam-node-insert-immediate
  "o i" 'org-id-get-create
  ";" 'org-roam-tag-add
  "/" 'org-roam-tag-remove
  "s" 'consult-org-roam-search
  "f" 'consult-org-roam-file-find
  "o b" 'consult-org-roam-backlinks
  "o f" 'consult-org-roam-forward-links
  "r" 'org-roam-node-random)
  
Org-roam and agenda Taken from Task Management with org-roam series
            (use-package vulpea
              :ensure t
              ;; hook into org-roam-db-autosync-mode you wish to enable
              ;; persistence of meta values (see respective section in README to
              ;; find out what meta means)
              :hook ((org-roam-db-autosync-mode . vulpea-db-autosync-enable)))

            (use-package vulpea-buffer)

            (defun vulpea-project-p ()
              "Return non-nil if current buffer has any todo entry.

            TODO entries marked as done are ignored, meaning the this
            function returns nil if current buffer contains only completed
            tasks."
              (seq-find                                 ; (3)
               (lambda (type)
                 (eq type 'todo))
               (org-element-map                         ; (2)
                   (org-element-parse-buffer 'headline) ; (1)
                   'headline
                 (lambda (h)
                   (org-element-property :todo-type h)))))

            (defun vulpea-project-update-tag ()
                "Update PROJECT tag in the current buffer."
                (when (and (not (active-minibuffer-window))
                           (vulpea-buffer-p))
                  (save-excursion
                    (goto-char (point-min))
                    (let* ((tags (vulpea-buffer-tags-get))
                           (original-tags tags))
                      (if (vulpea-project-p)
                          (setq tags (cons "tasks" tags))
                        (setq tags (remove "tasks" tags)))

                      ;; cleanup duplicates
                      (setq tags (seq-uniq tags))

                      ;; update tags if changed
                      (when (or (seq-difference tags original-tags)
                                (seq-difference original-tags tags))
                        (apply #'vulpea-buffer-tags-set tags))))))

            (defun vulpea-buffer-p ()
              "Return non-nil if the currently visited buffer is a note."
              (and buffer-file-name
                   (string-prefix-p
                    (expand-file-name (file-name-as-directory org-roam-directory))
                    (file-name-directory buffer-file-name))))

            (defun vulpea-project-files ()
                "Return a list of note files containing 'tasks' tag." ;
                (seq-uniq
                 (seq-map
                  #'car
                  (org-roam-db-query
                   [:select [nodes:file]
                    :from tags
                    :left-join nodes
                    :on (= tags:node-id nodes:id)
                    :where (like tag (quote "%\"tasks\"%"))]))))

            (defun vulpea-agenda-files-update (&rest _)
              "Update the value of `org-agenda-files'."
              (setq org-agenda-files (seq-uniq (append
                                                (list (concat org-directory "/todo.org")
                                                      (concat org-directory "/calendars/work.org")
                                                      (concat org-directory "/calendars/personal.org"))
                                                (vulpea-project-files)))))

            (add-hook 'find-file-hook #'vulpea-project-update-tag)
            (add-hook 'before-save-hook #'vulpea-project-update-tag)

            (advice-add 'org-agenda :before #'vulpea-agenda-files-update)
            (advice-add 'org-todo-list :before #'vulpea-agenda-files-update)

            (defun vulpea-agenda-category (&optional len)
              "Get category of item at point for agenda.

            Category is defined by one of the following items:

            - CATEGORY property
            - TITLE keyword
            - TITLE property
            - filename without directory and extension

            When LEN is a number, resulting string is padded right with
            spaces and then truncated with ... on the right if result is
            longer than LEN.

            Usage example:

              (setq org-agenda-prefix-format
                    '((agenda . \" %(vulpea-agenda-category) %?-12t %12s\")))

            Refer to `org-agenda-prefix-format' for more information."
              (let* ((file-name (when buffer-file-name
                                  (file-name-sans-extension
                                   (file-name-nondirectory buffer-file-name))))
                     (title (vulpea-buffer-prop-get "title"))
                     (category (org-get-category))
                     (result
                      (or (if (and
                               title
                               (string-equal category file-name))
                              title
                            category)
                          "")))
                (if (numberp len)
                    (s-truncate len (s-pad-right len " " result))
                  result)))

            (setq org-agenda-prefix-format
                  '((agenda . " %i \
%(vulpea-agenda-category 12)%?-12t% s")
                    (todo . " %i %(vulpea-agenda-category 12) ")
                    (tags . " %i %(vulpea-agenda-category 12) ")
                    (search . " %i %(vulpea-agenda-category 12) ")))

  
Search notes Using deft
;;; From https://github.com/jrblevin/deft/issues/75#issuecomment-905031872
(defun cm/deft-parse-title (file contents)
  "Parse the given FILE and CONTENTS and determine the title.
  If `deft-use-filename-as-title' is nil, the title is taken to
  be the first non-empty line of the FILE.  Else the base name of the FILE is
  used as title."
  (let ((begin (string-match "^#\\+[tT][iI][tT][lL][eE]: .*$" contents)))
    (if begin
        (string-trim (substring contents begin (match-end 0)) "#\\+[tT][iI][tT][lL][eE]: *" "[\n\t ]+")
      (deft-base-filename file))))

(use-package deft
  :ensure t
  :bind ("<f8>" . deft)
  :commands (deft)
  :config (progn
            (setq deft-directory "~/.deft"
                        deft-recursive t
                        deft-strip-summary-regexp ":PROPERTIES:\n\\(.+\n\\)+:END:\n"
                        deft-default-extension "org"
                        deft-strip-summary-regexp
      (concat "\\("
              "[\n\t]" ;; blank
              "\\|^#\\+[[:alpha:]_]+:.*$" ;; org-mode metadata
              "\\|^:PROPERTIES:\n\\(.+\n\\)+:END:\n"
              "\\)"))
            (advice-add 'deft-parse-title :override #'cm/deft-parse-title)
            ))

(general-def [f8] 'deft)
(general-def :keymaps 'deft-mode-map
  "C-r" 'deft-refresh
  "C-n" 'next-line
  "C-D" 'deft-delete-file)
  

Using consult-org-roam

	  (use-package consult-org-roam
	     :ensure t
	     :after org-roam
	     :init
	     (require 'consult-org-roam)
	     ;; Activate the minor mode
	     (consult-org-roam-mode 1)
	     :custom
	     ;; Use `ripgrep' for searching with `consult-org-roam-search'
	     (consult-org-roam-grep-func #'consult-ripgrep)
	     ;; Configure a custom narrow key for `consult-buffer'
	     (consult-org-roam-buffer-narrow-key ?r)
	     ;; Display org-roam buffers right after non-org-roam buffers
	     ;; in consult-buffer (and not down at the bottom)
	     (consult-org-roam-buffer-after-buffers t)
	     :config
	     ;; Eventually suppress previewing for certain functions
	     (consult-customize
	      consult-org-roam-forward-links
	      :preview-key "M-."))
  
org-transclusion To seamlessly view and add notes and files into a org-buffer without copying them.
(use-package org-transclusion
  :ensure t
  :init
  (general-create-definer fconfig-transclude-bind
    :prefix "C-c c"
    :name "Transclusion actions"
    "" '(:ignore t :which-key "Transclusion options"))
  :config
  (fconfig-transclude-bind
    "m" 'org-transclusion-make-from-link
    "a" 'org-transclusion-add
    "r" 'org-transclusion-remove
    "A" 'org-transclusion-add-all
    "R" 'org-transclusion-remove-all
    "g" 'org-transclusion-refresh
    "o" 'org-transclusion-open-source
    "l" 'org-transclusion-live-sync-start
    "s" 'org-store-link))
  
Utilities While taking notes, avoid splitting the frames, which can be distracting sometimes.
(defun santosh/notes-mode ()
  (interactive)
  (org-roam-buffer-toggle)
  (set-frame-parameter nil 'unsplittable t))
  
Searching
Publishing notes
(use-package ox-hugo
  :ensure t
  :defer t
  :commands (santosh/org-roam-publish-to-hugo)
  :init
  (setq org-hugo-base-dir (expand-file-name "~/dev/repos/forest"))
  :config
  (defun santosh/note-modified? (orgfile)
    "Test if the orgfile is newer than the generated markdown file.
The markdown file is generated from the org-hugo-base-dir
variable."
    (let ((mdfile (concat (file-name-as-directory org-hugo-base-dir) (concat "content/posts/" (file-name-directory (file-relative-name orgfile org-roam-directory)) (file-name-base orgfile) ".md"))))
      (or (not (file-exists-p mdfile))
          (not (time-less-p (nth 5 (file-attributes orgfile))
                          (nth 5 (file-attributes mdfile)))))))

  (defun santosh/mv-journal-md-to-subdir ()
    "ox-hugo doesn't create sub-directories, so move the journal files
into a subdirectory in org-hugo-base-dir"
    (let ((journal-files (org-roam-dailies--list-files)))
      (dolist (file journal-files)
        (let ((exportedmd (concat (file-name-as-directory org-hugo-base-dir) (concat "content/posts/" (file-name-base file) ".md")))
              (mdfile (concat (file-name-as-directory org-hugo-base-dir) (concat "content/posts/" (file-name-directory (file-relative-name file org-roam-directory)) (file-name-base file) ".md"))))
          (if  (file-exists-p exportedmd)
            (rename-file exportedmd mdfile t))))))

  (defun santosh/org-roam-publish-to-hugo (arg)
    "Publish the org-roam files into hugo markdown using ox-hugo exporter.
The function exports only modified files by default; call the
function with a prefix key to force re-generation of all org-roam
files, regardless of the file modification time."

    (interactive "P")
    (let ((notes-files (org-roam-list-files)))
      (dolist (file notes-files)
        (if (or (santosh/note-modified? file) arg)
            (with-current-buffer (find-file-noselect file)
              (org-hugo-export-wim-to-md)))))
    (santosh/mv-journal-md-to-subdir)))
Calendar Sync

Sync personal calendar into org-mode

(use-package org-caldav
  :init
  (setq org-caldav-url "https://nc.fossix.org/remote.php/dav/calendars/santosh")
  (setq org-caldav-calendars
        '((:calendar-id "personal" :files ()
           :inbox "~/notes/org/calendars/personal.org"))))
Agenda

Add agenda files

(use-package org-agenda
  :bind (:map org-agenda-mode-map ([C-f9] . org-agenda-goto-today))
  :commands org-agenda
  :hook (org-agenda-mode . hl-line-mode)

  :init
  (setq org-refile-targets
        '((nil :maxlevel . 5)
          (org-agenda-files :maxlevel . 5)))

  :config
  (appt-activate t)

  ;; org appointments
  ;; Get appointments for today
  (defun ss/org-agenda-to-appt ()
    (interactive)
    (setq appt-time-msg-list nil)
    (let ((org-deadline-warning-days 0))
      (org-agenda-to-appt)))

  (defun ss/appt-disp-window (min-to-app new-time msg)
    (save-window-excursion (notifications-notify
                            :title "Appointment"
                            :body msg)))

  (setq appt-message-warning-time '30
        appt-display-interval '5
        appt-display-format 'window
        appt-disp-window-function 'ss/appt-disp-window)

  (defadvice org-agenda-redo (after org-agenda-redo-add-appts)
    "Pressing `r' on the agenda will also add appointments."
    (progn
      (setq appt-time-msg-list nil)
      (org-agenda-to-appt)))

  (ad-activate 'org-agenda-redo)

  (add-hook 'org-finalize-agenda-hook 'ss/org-agenda-to-appt)
  (add-hook 'org-finalize-agenda-hook 'ss/notify-on-clocked-time)

  (run-at-time "24:01" nil 'ss/org-agenda-to-appt))

(setq org-agenda-time-grid '((daily today remove-match)
                             (800 1000 1200 1400 1600 1800 2000)
                             "......" "----------------")
      org-agenda-sort-noeffort-is-high nil
      org-agenda-clockreport-parameter-plist '(:stepskip0 t :link t :maxlevel 2 :fileskip0 t :tags t :hidefiles t :compact t))


;; functions to remind me to stop working for the day

(defun ss/org-clock-total-sum-today ()
  "Get the total clocked time today across all agenda files in minutes."
  (let ((files (org-agenda-files))
        (total 0))
    (org-agenda-prepare-buffers files)
    (dolist (file files)
      (with-current-buffer (find-buffer-visiting file)
        (setq total (+ total (org-clock-sum-today)))))
    total))

(defvar ss/clocked-notify-limit
  "The duration in hours, after which org-timeout should send notification")

(defalias 'clocked-notify-ok-callback-fn nil
  "The callback function to be called when notification ok is clicked")

(defalias 'clocked-notify-cancel-callback-fn nil
  "The callback function to be called when notification cancel is clicked")

(setq ss/clocked-notify-limit 8)

(defun ss/clocked-time-notify ()
  (if (>= (/ (ss/org-clock-total-sum-today) 60) ss/clocked-notify-limit)
      (notifications-notify
       :title "Time to leave"
       :body "Clocked time exceeded."
       :timeout -1)))
  ;; :actions '("Confirm" "OK" "Refuse" "Cancel")
  ;; :on-action 'clocked-notify-ok-callback-fn
  ;; :on-close 'clocked-notify-cancel-callback-fn)))


(defun ss/notify-on-clocked-time ()
  "Notify if total clocked time exceeds `clocked-notify-limit`"
  (run-with-timer 0 1800 'ss/clocked-time-notify))
Planning Five todo states, TODO, PROG, DONE, CANCELLED. Additionally for bug management two states, HOLD and DEFERRED.
(setq org-log-done 'note)
(setq org-todo-keywords
      '((sequence "TODO(t)" "PROG(p)" "|" "DONE(d)")
        (sequence "HOLD(h)" "DEFERRED(f)" "DELEGATED" "|" "CANCELLED(c)")))

(setq org-todo-keyword-faces
      '(("PROG" . (:foreground "deepskyblue" :weight bold))
        ("HOLD" . (:foreground "LightGoldenrod4" :weight bold))
        ("DELEGATED" . (:foreground "IndianRed" :weight bold))))
  
Color tagged lines
;; from: https://lists.gnu.org/archive/html/emacs-orgmode/2014-01/msg00637.html

(setq org-agenda-tag-line-face
      '(("bug" . (:foreground "IndianRed"))
        ("meeting" . (:foreground "DeepSkyBlue" :weight bold))))

(defun org-agenda-fontify-tagged-line ()
  "Use `org-agenda-face-for-tagged-lines' to fontify lines with certain tags."
  (goto-char (point-min))
  (let (tags)
    (while (progn (forward-line 1) (not (eobp)))
      (if (setq tags (get-text-property (point) 'tags))
          (mapc
           (lambda (pair)
             (if (member (car pair) tags)
                 (add-text-properties (point-at-bol) (point-at-eol) `(face ,(cdr pair)))))
           org-agenda-tag-line-face)))))

(add-hook 'org-agenda-finalize-hook 'org-agenda-fontify-tagged-line)
  
Custom agenda

We will have three blocks in agenda. The first block will show the scheduled items for today, deadlines, meetings etc.

The second block shows issues (assigned bugs) that are not updated for more than N days.

The third block shows the “Pending tasks”, and finally “Pending items”, to show the remaining tasks with effort estimate.

(setq org-agenda-start-with-log-mode t)
(defun day-agenda-skip ()
  "Skip trees that are of priority A and has a meeting tag"
  (let ((subtree-end (save-excursion (org-end-of-subtree t)))
        (pri-value (* 1000 (- org-lowest-priority ?A)))
        (pri-current (org-get-priority (thing-at-point 'line t)))
        (case-fold-search t))
    (if (or (re-search-forward ":meeting:" subtree-end t)
            (= pri-value pri-current))
        subtree-end
      nil)))

(defun org-agenda-skip-if-blocked ()
  (let ((next-headline (save-excursion
                         (or (outline-next-heading) (point-max)))))
    (if (org-entry-blocked-p) next-headline)))

(defun org-agenda-tasks-skip-if-future ()
  "Skip tasks in future files."
  (let* ((today (format-time-string "%Y-%m-%d")) ; Today's date string
         (filename (buffer-file-name))
         (date-string (and filename (string-match "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}" filename)
                           (match-string 0 filename))))
    (when (and date-string (string> date-string today))
      (message "Skipping task in future file: %s" filename)
      (org-agenda-skip-entry-if 'todo '("TODO" "DONE")))))

(defun skip-future-timestamped-todos ()
  "Skip TODO entries with timestamps in the future or today."
  (let ((end (save-excursion (or (outline-next-heading) (point-max)))))
    (if (re-search-forward org-ts-regexp end t)
        (let ((timestamp (match-string 0)))
          (if (org-time>= timestamp (org-read-date nil nil "now"))
              end
            nil))
      nil)))

;;; show number of days a task from the org-roam daily has been pending
(defun org-agenda-tasks-display-delay ()
  "Display delay in days based on the date string in the file name."
  (let* ((today (format-time-string "%Y-%m-%d")) ; Today's date string
         (filename (buffer-file-name))
         (date-string (and filename (string-match "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}" filename)
                           (match-string 0 filename)))
         (delay (and date-string (org-time-stamp-to-now date-string))))
    (cond
     ((and delay (not (zerop delay)))
      (concat "(" (format "%dd" (-  delay))")"))
     (t "(--)"))))

;; From here: http://doc.norang.ca/org-mode.html

(defun bh/skip-habits ()
  "Skip habits"
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (if (org-is-habit-p)
          next-headline
        nil))))

;; (defun ss/org-skip-sunrise ()
;;   (if (and (not (equal date (calendar-current-date)))
;;            (string= (org-get-category) "Sunrise"))
;;       (org-end-of-subtree t)
;;     nil))

;; https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html

(defun ss/org-agenda-skip-subtree-if-priority (priority)
  "Skip an agenda subtree if it has a priority of PRIORITY.

        PRIORITY may be one of the characters ?A, ?B, or ?C."
  (let ((subtree-end (save-excursion (org-end-of-subtree t)))
        (pri-value (* 1000 (- org-lowest-priority priority)))
        (pri-current (org-get-priority (thing-at-point 'line t))))
    (if (= pri-value pri-current)
        subtree-end
      nil)))

(defun santosh/since-last-update (days)
  "Checks if headline update is older than DAYS.
        If no timestamps, then return nil."
  (interactive)
  (let ((next-headline (save-excursion (or (org-end-of-subtree t) (point-max)))))
    (let ((timestamp (ignore-errors (santosh/org-logbook-last-state-update next-headline))))
      (if timestamp (if (>= (org-time-stamp-to-now timestamp) (- days))
                        next-headline)
        nil))))

(defun santosh/org-logbook-last-state-update (bound)
  (interactive)
  (save-match-data ; is usually a good idea
    (if (re-search-forward ":LOGBOOK:.*\n.*\\(\\[.*\\]\\)" bound)
        (match-string 1))))

;; Easy basic searches. Get a quick view of next actions, etc
(setq org-agenda-custom-commands
      ;; NOTE: Since blocked items won't be shown, make sure the children are
      ;; TODO items, if they are check boxes, set the NOBLOCKING property.
      '(("d" "Agenda and TODOs"
         ((agenda ""
                  ((org-agenda-overriding-header "Today's Agenda")
                   (org-agenda-span 'day)
                   (org-agenda-prefix-format " %i %?:e %?-12t% s")
                   (org-agenda-scheduled-leaders '("" "%2dx "))
                   (org-agenda-use-time-grid t)
                   (org-deadline-warning-days 7)
                   (org-agenda-show-log t)
                   (org-agenda-skip-scheduled-if-deadline-is-shown 'not-today)
                   (org-agenda-skip-deadline-prewarning-if-scheduled 3)
                   (org-agenda-skip-scheduled-delay-if-deadline t)
                   (org-agenda-skip-timestamp-if-deadline-is-shown nil)
                   (org-agenda-sorting-strategy
                    '(time-up todo-state-up priority-down))
                   (org-agenda-skip-function 'org-agenda-skip-if-blocked)))

          (tags-todo "bug/TODO"
                     ((org-agenda-overriding-header "Issues getting stale (> 2)")
                      (org-agenda-prefix-format "%i %s")
                      (org-agenda-skip-function (progn '(or
                                                         (santosh/since-last-update 2)
                                                         (org-agenda-skip-entry-if 'scheduled))
                                                       ))))
          (tags-todo "/PROG"
                     ((org-agenda-sorting-strategy
                       '(priority-down effort-down todo-state-down))
                      (org-agenda-skip-function
                       (progn '(or
                                (org-agenda-skip-if nil '(deadline))
                                (skip-future-timestamped-todos))))

                      (org-agenda-prefix-format " %i %s")
                      (org-agenda-overriding-header "Ongoing Tasks & Projects")))

          (tags-todo "-someday-bug/TODO"
                     ((org-agenda-overriding-header "Pending tasks")
                      (org-agenda-skip-function
                       (progn '(or
                                (org-agenda-skip-if-blocked)
                                (org-agenda-tasks-skip-if-future)
                                (org-agenda-skip-if nil '(deadline))
                                (skip-future-timestamped-todos))))
                      (org-agenda-sorting-strategy
                       '(priority-down effort-up todo-state-down))
                      (org-agenda-prefix-format "%i %(org-agenda-tasks-display-delay) [%e] ")
                      (org-agenda-files
                       (cl-remove-if-not
                        (lambda (file)
                          (and
                           (or
                            (file-in-directory-p file (f-join org-roam-directory org-roam-dailies-directory))
                            (file-in-directory-p file (f-join org-roam-directory "work")))
                           (member file (vulpea-project-files))))
                        (vulpea-project-files)))))))

        ("p" "All pending todos"
         ((alltodo ""
                   ((org-agenda-overriding-header "Pending items")
                    (org-agenda-prefix-format " %i [%e] ")
                    (org-agenda-sorting-strategy
                     '(priority-down effort-up todo-state-down category-keep))
                    (org-agenda-skip-function
                     (progn
                       '(or (org-agenda-skip-if-blocked)
                            (org-agenda-skip-entry-if 'regexp "\\[#A\\]")
                            (org-agenda-skip-if nil '(scheduled deadline timestamp))
                            (org-agenda-skip-entry-if 'scheduled 'todo '("DONE" "PROG" "DEFERRED" "HOLD")))))))))

        ("h" "Bugs on hold"
         ((tags-todo "bug/HOLD"
                     ((org-agenda-overriding-header "Bugs on hold")
                      (org-agenda-prefix-format "%i %s")))))

        ("i" "Tasks to be refiled" tags "refile"
         ((org-agenda-files '("~/notes/org/inbox"))))

        ("W" "Week review"
         ((agenda ""
                  ((org-agenda-start-on-weekday 1)
                   (org-agenda-show-log t)
                   (org-agenda-time-grid nil)
                   (org-agenda-start-with-log-mode t)
                   (org-agenda-include-diary nil)
                   (org-agenda-log-mode-items '(state clock closed))
                   (org-agenda-files (append (vulpea-project-files) '("~/notes/org/todo.org")))
                  (org-agenda-skip-function
                   (progn
                     '(or (org-agenda-skip-entry-if 'scheduled 'deadline)
                          (org-agenda-skip-subtree-if 'regexp ":habit:"))))
                   (org-agenda-start-with-clockreport-mode t)
                   (org-agenda-span 'week)
                   (org-agenda-start-day "-7")
                   (org-agenda-clockreport-parameter-plist '(:link t :maxlevel 3))
                   (org-agenda-overriding-header "Work week in Review")))))

        ("X" agenda ""
         ((org-agenda-prefix-format " [ ] ")
          (org-agenda-with-colors nil)
          (org-agenda-remove-tags t)
         ("~//tmp/agenda.html")))))

The above custom agenda can produce empty sections in some cases, like when there are not PROG tasks. So let delete it. This code was taken from a Reditt Post.

(defun org-agenda-delete-empty-blocks ()
  "Remove empty agenda blocks.
  A block is identified as empty if there are fewer than 2
  non-empty lines in the block (excluding the line with
  `org-agenda-block-separator' characters)."
  (when org-agenda-compact-blocks
    (user-error "Cannot delete empty compact blocks"))
  (setq buffer-read-only nil)
  (save-excursion
    (goto-char (point-min))
    (let* ((blank-line-re "^\\s-*$")
           (content-line-count (if (looking-at-p blank-line-re) 0 1))
           (start-pos (point))
           (block-re (format "%c\\{10,\\}" org-agenda-block-separator)))
      (while (and (not (eobp)) (forward-line))
        (cond
         ((looking-at-p block-re)
          (when (< content-line-count 2)
            (delete-region start-pos (1+ (point-at-bol))))
          (setq start-pos (point))
          (forward-line)
          (setq content-line-count (if (looking-at-p blank-line-re) 0 1)))
         ((not (looking-at-p blank-line-re))
          (setq content-line-count (1+ content-line-count)))))
      (when (< content-line-count 2)
        (delete-region start-pos (point-max)))
      (goto-char (point-min))
      ;; The above strategy can leave a separator line at the beginning
      ;; of the buffer.
      (when (looking-at-p block-re)
        (delete-region (point) (1+ (point-at-eol))))))
  (setq buffer-read-only t))

(add-hook 'org-agenda-finalize-hook #'org-agenda-delete-empty-blocks)

Super agenda

(use-package "org-super-agenda"
  :init
  (setq org-super-agenda-groups
        '((:name "Today" :time-grid t :log t)
          (:scheduled today)
          (:habit t)
          (:name "Overdue"
                 :deadline past)
          (:name "Due soon"
                 :deadline future)
          (:name "Scheduled earlier"
                 :scheduled past)
          (:name ""
                 :tag "bug")
          (:name ""
                 :anything t)))
  :config
  (org-super-agenda-mode))

Setup category icons

(use-package all-the-icons
  :ensure t)

(setq org-agenda-category-icon-alist
      `(("Work" ,(list (all-the-icons-material "work" :face 'all-the-icons-blue)) nil nil :ascent center)
        ("Personal" ,(list (all-the-icons-material "person" :face 'all-the-icons-purple)) nil nil :ascent center)
        ("Kernel" ,(list (all-the-icons-octicon "terminal" :face 'all-the-icons-cyan)) nil nil :ascent center)
        ("Learning" ,(list (all-the-icons-material "book" :face 'all-the-icons-silver)) nil nil :ascent center)
        ("Language" ,(list (all-the-icons-material "language" :face 'all-the-icons-green)) nil nil :ascent center)
        ("Default" ,(list (all-the-icons-material "alarm_off" :face 'all-the-icons-dsilver)) nil nil :ascent center)
        ("Sun" ,(list (all-the-icons-material "wb_sunny" :face 'all-the-icons-yellow)) nil nil :ascent center)
        ("Diary" ,(list (all-the-icons-material "date_range")) nil nil :ascent center)
        ("Moon" ,(list (all-the-icons-faicon "moon-o" :face 'all-the-icons-silver)) nil nil :ascent center)
        ("Books" ,(list (all-the-icons-material "library_books" :face 'all-the-icons-silver)) nil nil :ascent center)
        ("Technical" ,(list (all-the-icons-material "code" :face 'all-the-icons-silver)) nil nil :ascent center)
        ("Meeting" ,(list (all-the-icons-material "group" :face 'all-the-icons-silver)) nil nil :ascent center)
        ("Bug" ,(list (all-the-icons-octicon "bug" :face 'all-the-icons-red)) nil nil :ascent center)
        ("Project" ,(list (all-the-icons-octicon "diff" :face 'all-the-icons-green)) nil nil :ascent center)
        ("Tasks" ,(list (all-the-icons-octicon "checklist" :face 'all-the-icons-green)) nil nil :ascent center)
        ("Writing" ,(list (all-the-icons-faicon "pencil" :face 'all-the-icons-green)) nil nil :ascent center)
        ))
Capture notes and tasks

I use capture to track time spent on short meetings & calls, and also to log into my day journal.

	(use-package org-capture
	  :requires org
	  :commands org-capture
	  :config
	  (add-hook 'org-capture-mode-hook
		    (lambda ()
		      (setq-local org-tag-alist (org-global-tags-completion-table))))
	  (add-hook 'org-capture-mode-hook (lambda () (org-align-tags t)))

	  (defun org-journal-find-location ()
	    ;; Open today's journal, but specify a non-nil prefix argument in order to
	    ;; inhibit inserting the heading; org-capture will insert the heading.
	    (org-journal-new-entry t)
	    (unless (eq org-journal-file-type 'daily)
	      (org-narrow-to-subtree))
	    (goto-char (point-max)))
	  (setq org-capture-templates nil)
	  (setq org-capture-templates
		'(;; Entry for random quote for the day file
		  ("u" "Quotes" entry
		   (file+headline (concat notes-dir "/quotes") "Quotes")
		   "* %^{Quote} -- %^{Author}")))

	  ;; system wide org-capture
	  ;; https://www.reddit.com/r/emacs/comments/74gkeq/system_wide_org_capture/
	  (defadvice org-switch-to-buffer-other-window
	      (after supress-window-splitting activate)
	    "Delete the extra window if we're in a capture frame"
	    (if (equal "capture" (frame-parameter nil 'name))
		(delete-other-windows)))

	  (defadvice org-capture-finalize
	      (after delete-capture-frame activate)
	    "Advise capture-finalize to close the frame"
	    (when (and (equal "capture" (frame-parameter nil 'name))
		       (not (eq this-command 'org-capture-refile)))
	      (delete-frame)))

	  (defadvice org-capture-refile
	      (after delete-capture-frame activate)
	    "Advise org-refile to close the frame"
	    (delete-frame))

	  (defun activate-capture-frame ()
	    "run org-capture in capture frame"
	    (select-frame-by-name "capture")
	    (switch-to-buffer (get-buffer-create "*scratch*"))
	    (org-capture)))
Keybindings
(use-package which-key-posframe
  :ensure t
  :init (which-key-posframe-mode 1))
(fconfig-org-config-bind
  "I" 'punch-in
  "O" 'punch-out
  "l" 'clock-in-last-task
  "c" 'org-capture
  "a" 'org-agenda
  "l" 'org-store-link
  "t" 'org-todo-list
  "b" 'org-brain-goto
  "v" 'org-brain-visualize
  "o" 'org-occur-in-agenda-files
  "s" 'org-search-view
  "r" 'org-refile
  "m" 'org-timer-set-timer
  "p" 'org-present)
Useful functions

Sometimes its useful to get a count of the sub-headings under a tree, like getting the number of bugs I am working on.

(defun count-subheadings ()
  (interactive)
  (message (format "Number of sub-headings are: %d."
                   (1-  (length (org-map-entries nil nil 'tree))))))

(defun count-tasks ()
  (interactive)
  (message
   (format "Number of tasks in file: %d"
           (length
            (org-map-entries t "/+TODO|PROG|HOLD|DONE|CANCELLED" 'file)))))

(defun count-headings ()
  (interactive)
  (message (format "Number of headings in file: %d"
                   (length (org-map-entries t nil nil)))))

(defun count-top-level-headlines ()
  "Count the number of top-level headlines in the current org-mode buffer."
  (interactive)
  (let ((count 0))
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward "^\\* " nil t)
        (when (= (org-outline-level) 1)
          (setq count (1+ count)))))
    (message "Number of top-level headlines: %d" count)))

Biblography

(use-package citar
  :no-require
  :custom
  (org-cite-global-bibliography '("~/notes/bib/references.bib"))
  (org-cite-insert-processor 'citar)
  (org-cite-follow-processor 'citar)
  (org-cite-activate-processor 'citar)
  (citar-bibliography org-cite-global-bibliography))

Calendar View

(require 'calfw)
(require 'calfw-cal)
(require 'calfw-org)

(defun my-open-calendar ()
  (interactive)
  (cfw:open-calendar-buffer
   :contents-sources
   (list
    (cfw:org-create-source "Green")
    (cfw:cal-create-source "Orange"))))

Mail

Notmuch mail setup

     (use-package notmuch
	:ensure t
	:config
	(setq notmuch-show-logo nil
	      notmuch-column-control t
	      notmuch-mua-compose-in 'new-frame)

	;; Load all the defuns which will be used later
	(fconfig! mail))

Consult and notmuch hello. The saved searches for notmuch-hello are defined in personal config file.

     (use-package consult-notmuch
	:ensure t
	:after (consult notmuch)
	:commands consult-notmuch)

	 ;;; from http://www.coli.uni-saarland.de/~slemaguer/emacs/main.html
     (use-package notmuch-hello
	:commands (notmuch notmuch-hello)
	:config

	(setq notmuch-hello-thousands-separator ",") ;; Add a thousand separator
	(general-def notmuch-hello-mode-map "h" 'consult-notmuch)

	(add-hook 'notmuch-hello-refresh-hook
		  (lambda ()
		    (whitespace-mode -1)))

	(setq notmuch-hello-sections '())
	(add-to-list 'notmuch-hello-sections 'fconfig/notmuch-hello-insert-others)
	(add-to-list 'notmuch-hello-sections 'fconfig/notmuch-hello-insert-important))

Let’s autoload mail-hist and and sendmail

(autoload 'mail-hist-forward-header "mail-hist")
(autoload 'mail-text-start          "sendmail")

I use msmtp to send mail, and use a script which will queue mails when unable to send. I lost the source where I copied the script from.

 (setq sendmail-program "msmtp"
	    message-sendmail-f-is-evil t
	    message-interactive t
	    message-send-mail-function 'message-send-mail-with-sendmail
	    notmuch-fcc-dirs nil
	    message-sendmail-extra-arguments '("--read-envelope-from")
	    mail-envelope-from 'header
	    message-sendmail-envelope-from 'header
	    message-signature nil
	    message-kill-buffer-on-exit t
	    message-mail-alias-type 'ecomplete
	    message-auto-save-directory nil)

Use w3m for HTML mail reading.

(setq mm-text-html-renderer 'w3m)
Email Workflow

Use org to store links from notmuch, and setup a capture template for mails.

Follow up
Capture the mail link and insert a deadline entry
Read later
capture template similar to ‘Follow up’ but without a

deadline.

(use-package ol-notmuch :ensure t)

(defun ss/mail-follow-up()
  "Capture mail to org mode."
  (interactive)
  (org-store-link nil)
  (org-capture nil "Mf"))

(defun ss/mail-read-later()
  "Capture mail to org mode."
  (interactive)
  (org-store-link nil)
  (org-capture nil "Mr"))
Keybindings

Keybindings for deleting, toggling states and flagging.

All bindings in the search mode map

	(general-def notmuch-search-mode-map "!" 'fconfig/notmuch-toggle-flagged)
	(general-def notmuch-search-mode-map "#" 'fconfig/notmuch-toggle-unread)
	(general-def notmuch-search-mode-map "<C-tab>" 'notmuch-tree-from-search-current-query)
	(general-def notmuch-search-mode-map "<down>" 'next-line)
	(general-def notmuch-search-mode-map "<tab>" 'notmuch-tree-from-search-thread)
	(general-def notmuch-search-mode-map "<up>" 'previous-line)
	(general-def notmuch-search-mode-map "d" 'fconfig/notmuch-delete-thread)
	(general-def notmuch-search-mode-map "]" 'ss/mail-read-later)
	(general-def notmuch-search-mode-map "," 'ss/mail-follow-up)

Bindings in the show mode map

	(general-def notmuch-show-mode-map "!" 'fconfig/notmuch-toggle-flagged)
	(general-def notmuch-show-mode-map "#" 'fconfig/notmuch-toggle-unread)
	(general-def notmuch-show-mode-map "<down>" 'next-line)
	(general-def notmuch-show-mode-map "<left>" 'backward-char)
	(general-def notmuch-show-mode-map "<right>" 'forward-char)
	(general-def notmuch-show-mode-map "<up>" 'previous-line)
	(general-def notmuch-show-mode-map "D" 'fconfig/notmuch-delete-thread)
	(general-def notmuch-show-mode-map "\C-c\C-o" 'browse-url-at-point)
	(general-def notmuch-show-mode-map "b" 'notmuch-show-browse-urls)
	(general-def notmuch-show-mode-map "B" 'fconfig/notmuch-bounce-message)
	(general-def notmuch-show-mode-map "d" 'fconfig/notmuch-delete-message)
	(general-def notmuch-show-mode-map "," 'ss/mail-follow-up)
	(general-def notmuch-show-mode-map "]" 'ss/mail-read-later)
	(general-def notmuch-show-mode-map "X"
	  '(lambda ()
	     (interactive)
	     (fconfig/notmuch-export-patch (notmuch-show-get-message-id)
					   (notmuch-show-get-prop :headers))))

Bindings in the tree mode (threaded view)

	(general-def notmuch-tree-mode-map "!" 'fconfig/notmuch-toggle-flagged)
	(general-def notmuch-tree-mode-map "#" 'fconfig/notmuch-toggle-unread)
	(general-def notmuch-tree-mode-map "<down>" 'next-line)
	(general-def notmuch-tree-mode-map "<up>" 'previous-line)
	(general-def notmuch-tree-mode-map "d" 'fconfig/notmuch-delete-message)
	(general-def notmuch-tree-mode-map "X" '(lambda () (interactive) (notmuch-tree-thread-mapcar 'fconfig/notmuch-tree-get-patch)))

Bindings to show patch in diff mode

	(general-def notmuch-show-part-map "d" 'fconfig/notmuch-show-view-as-patch)
Utility functions
(defun mail/copy-bug-details ()
  "Extracts the number and the last string within square brackets from INPUT-STRING and copies them to the kill ring."
  (interactive)
  (let ((input-string (notmuch-show-get-subject)))
    (when (string-match "\\[B\\] \\([0-9]+\\).*\\[\\([^]]+\\)\\]$"  input-string)
      (let ((number (match-string 1 input-string))
            (last-string (match-string 2 input-string)))
        (kill-new number)
        (kill-new last-string)
        (message "Bug: %s, Summary: %s" number last-string)))))

Programming

Compilation

Always scroll to the first error

	(setq compilation-scroll-output 'first-error)

Show compilation buffer in colors

(use-package xterm-color
  :ensure t
  :init
  (setq compilation-environment '("TERM=xterm-256color"))
  (defun my/advice-compilation-filter (f proc string)
    (funcall f proc (xterm-color-filter string)))
  (advice-add 'compilation-filter :around #'my/advice-compilation-filter))
Scheme

Let us use guile which is the default in fedora distributions. The default guile is old, and geiser is not happy with it.

(use-package geiser-guile
  :ensure t
  :config
  (setq geiser-defauslt-implementation 'guile
        geiser-guile-binary "guile2.2"))
LSP
(setq read-process-output-max fconfig/1MB)

(use-package lsp-mode
  :diminish
  :commands (lsp lsp-deferred)
  :hook ((c-mode rust-mode go-mode python-mode) . lsp-deferred)
  :bind (:map prog-mode-map
              ("M-g r" . lsp-rename))
  :config
  (setq lsp-file-watch-threshold nil
        lsp-idle-delay 0.5)

  (add-hook 'lsp-mode-hook #'lsp-enable-which-key-integration))

(use-package consult-lsp
  :ensure t
  :after lsp-mode)

(use-package lsp-ui
  :ensure t
  :hook (lsp-mode . lsp-ui-mode)
  :after lsp-mode)

(use-package lsp-ui-doc
  :after lsp-ui
  :config
  (setq lsp-ui-doc-include-signature t
        lsp-ui-doc-delay 1.5
        lsp-ui-sideline-delay 1.5))

(use-package company-capf
  :requires company
  :after lsp-mode
  :config
  (push 'company-capf company-backends)
  (setq company-minimum-prefix-length 1
        company-idle-delay 0.0)
  (global-company-mode))

(general-def lsp-mode-map [remap xref-find-apropos] #'consult-lsp-symbols)
Misc

Add a keybinding for recompile

(general-def "C-c RET" 'recompile)

;;; Add gtags to xref backend
(use-package gxref
  :ensure t
  :config
  (add-to-list 'xref-backend-functions 'gxref-xref-backend))
Project
(use-package projectile
  :diminish
  :defer 5
  :init
  (projectile-mode +1)
  (define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map))

(use-package consult-projectile
  :ensure t)
Treesit major modes
(setq major-mode-remap-alist
 '((yaml-mode . yaml-ts-mode)
   (bash-mode . bash-ts-mode)
   (json-mode . json-ts-mode)
   (css-mode . css-ts-mode)
   (python-mode . python-ts-mode)
   (rust-mode . rust-ts-mode)))

Version Control

Magit

     (use-package magit
	:ensure t
	:defer t
	:diminish
	:commands magit-get-top-dir
	:config
	(progn
	  (setq magit-commit-signoff t)))

     (use-package git-timemachine :ensure t :defer 3)

     (use-package gist :defer 3)

     (general-create-definer fconfig-vc-bind
	:prefix "C-c v"
	:name "Version control"
	"" '(:ignore t :which-key "Version control"))

Lets show the change history while browsing the file

     (use-package blamer
	:ensure t
	:defer 20
	:custom
	(blamer-idle-time 0.3)
	(blamer-min-offset 70)
	:custom-face
	(blamer-face ((t :foreground "#7a88cf"
			  :background nil
			  :height 90
			  :italic t))))
Keybindings
	(fconfig-vc-bind
	  "d" 'magit-diff-buffer-file
	  "D" 'magit-diff-dwim
	  "C-d" 'magit-diff-staged
	  "F" 'magit-file-dispatch
	  "M" 'magit-dispatch
	  "l" 'magit-log-buffer-file
	  "L" 'magit-log-all
	  "b" 'magit-blame-addition
	  "s" 'magit-status
	  "t" 'git-timemachine-toggle
	  "g" 'consult-git-grep
	  "c" 'magit-branch-checkout
	  "i" 'gist-region-or-buffer-private
	  "I" 'gist-region-or-buffer
	  "M-p" 'magit-pull-from-upstream
	  "M-P" 'magit-pull
	  "M-f" 'magit-fetch-from-upstream
	  "M-F" 'magit-fetch-all
	  "M-u" 'magit-push-current-to-upstream
	  "M-U" 'magit-push-current
	  "M-b" 'magit-rebase-branch
	  "M-B" 'magit-rebase
	  "M-r" 'magit-reset-worktree)

Blogging

Hugo
	(use-package easy-hugo
	  :init

	  (setq easy-hugo-basedir "~/work/blog/")
	  (setq easy-hugo-url "https://ssivaraj.gitlab-master-pages.nvidia.com/notes")
	  (setq easy-hugo-postdir "content/posts")
	  (setq easy-hugo-previewtime "300")
	  :bind ("C-c b h" . easy-hugo))

Appearance

Will theme customisation till I integrate with the theme (aanila).

(custom-theme-set-faces
 'user
 '(org-block ((t (:inherit t))))
 '(org-meta-line ((t (:foreground "dim gray"))))
 '(org-block-end-line ((t (:foreground "gray20" :overline t :extend t))))
 '(org-block-begin-line ((t (:foreground "gray20" :underline t :extend t))))
 '(show-paren-match ((t (:foreground "light gray" :background "gray10" :extend t))))
 '(bookmark-face ((t (:foreground nil :background "DodgerBlue4")))))

Some transparency won’t hurt

     (defun toggle-transparency ()
	(interactive)
	(let ((alpha (frame-parameter nil 'alpha)))
	  (set-frame-parameter
	   nil 'alpha
	   (if (eql (cond ((numberp alpha) alpha)
			  ((numberp (cdr alpha)) (cdr alpha))
			  ;; Also handle undocumented (<active> <inactive>) form.
			  ((numberp (cadr alpha)) (cadr alpha)))
		    100)
	       '(95 . 50) '(100 . 100)))))

     (general-def "C-c f f" 'toggle-frame-fullscreen)
     (general-def "C-c f t" 'toggle-transparency)

A function to display the ansi color sequences in log files.

     (defun display-ansi-colors ()
	(interactive)
	(ansi-color-apply-on-region (point-min) (point-max)))

Dashboard

(use-package page-break-lines
  :ensure t
  :defer t
  :diminish page-break-lines-mode
  :hook (dashboard-after-initialize . page-break-lines-mode))

(setq gita-verses
      '(
        "अन्तवन्त इमे देहा नित्यस्योक्ता: शरीरिण:।\nअनाशिनोऽप्रमेयस्य तस्माद्युध्यस्व भारत ।।२ - १८।।"
        "प्रजहाति यदा कामान्सर्वान्पार्थ मनोगतान्।\nआत्मन्येवात्मना तुष्ट: स्थितप्रज्ञस्तदोच्यते ।।२ - ५५।।"
        ))

(use-package dashboard
  :ensure t
  :custom
  (dashboard-set-heading-icons t)
  (dashboard-set-file-icons t)
  (dashboard-icon-type 'nerd-icons)
  (dashboard-display-icons-p t)
  (dashboard-center-content t)
  :config
  (dashboard-setup-startup-hook)

  (defun dashboard-insert-random-note (list-size)

    (dashboard-insert-section
     "Random notes"

     (dashboard-shorten-paths
      (list (org-roam-node-file (cdr (seq-random-elt (org-roam-node-read--completions)))))
      'dashboard-note-alist
      'note)
     list-size
     'note
     "n"
     `(lambda (&rest _)
        (find-file-existing (dashboard-expand-path-alist ,el dashboard-note-alist)))
     (format "%s" (cdr (car dashboard-note-alist)))))

  (add-to-list 'dashboard-item-generators '(note . dashboard-insert-random-note))

  (setq
   dashboard-set-init-info nil
   dashboard-page-separator "\n\f\n"
   dashboard-startup-banner "~/Pictures/flute-and-feather.png"
   initial-buffer-choice #'(lambda () (get-buffer-create "*dashboard*"))
   dashboard-set-navigator t
   dashboard-items '((projects . 10)
                     (recents . 5)
                     (bookmarks . 5)
                     (registers . 5)
                     (note . 1))
   dashboard-banner-logo-title (format "Welcome %s! Happy hacking ♥!" (user-login-name))
   dashboard-footer-icon (all-the-icons-octicon "book"
                                                :height 1.00
                                                :v-adjust 0.05)
   dashboard-footer-messages gita-verses
   dashboard-projects-switch-function 'projectile-switch-project-by-name
   dashboard-navigator-buttons
   `(;; line1
     (
      ;; Open kernel source directory
      (,(all-the-icons-faicon "calendar" :height 1.0 :v-adjust 0.0)
       nil "Today's agenda and todo"
       (lambda (&rest _) (if (get-buffer "*Org Agenda*")
                        (switch-to-buffer-other-window "*Org Agenda*")
                      (org-agenda "a" "A"))))
      ;; Mails
      (,(all-the-icons-octicon "mail" :height 1.0 :v-adjust 0.0)
       nil "Unread Mails"
       (lambda (&rest _) (notmuch)))
      (,(all-the-icons-octicon "star" :height 1.0 :v-adjust 0.0)
       ,(fconfig/notmuch-count-query "tag:flagged") "Starred Mails"
       (lambda (&rest _) (notmuch-search "tag:flagged")))))))

;; (defun santosh/dashboard-open ()
;;   (interactive)
;;   (dashboard-insert-startupify-lists)
;;   (switch-to-buffer "*dashboard*")
;;   (dashboard-mode))

(defun santosh/dashboard-open ()
  "Jump to the dashboard buffer, if doesn't exists create one."
  (interactive)
  (switch-to-buffer dashboard-buffer-name)
  (dashboard-mode)
  (dashboard-insert-startupify-lists)
  (dashboard-refresh-buffer))

Media

Bongo
	(use-package bongo
	  :ensure t)

	(org-link-set-parameters "audio"
				 :follow #'org-play-media-file)

	(defun org-play-media-file (path _)
	  (with-bongo-buffer
	    (bongo-insert-file (expand-file-name path))
	    (backward-char)
	    (bongo-play)))

Help

(use-package helpful :ensure t)
(global-set-key (kbd "C-h f") #'helpful-callable)
(global-set-key (kbd "C-h v") #'helpful-variable)
(global-set-key (kbd "C-h k") #'helpful-key)

Quick websearch

(use-package engine-mode
  :ensure t
  :config
  (engine-mode t)
  (defengine github
    "https://github.com/search?ref=simplesearch&q=%s"
    :keybinding "i")

  (defengine google
    "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s"
    :browser 'eww-browse-url
    :keybinding "g")

  (defengine duckduckgo
    "https://duckduckgo.com/?q=%s"
    :keybinding "d")

  (defengine amazon
    "https://www.amazon.in/s?k=%s"
    :keybinding "a")

  (defengine youtube
    "http://www.youtube.com/results?aq=f&oq=&search_query=%s"
    :keybinding "y")

  (defengine golang
    "https://pkg.go.dev/search?q=%s"
    :keybinding "l")

  (defengine rust
    "https://docs.rs/releases/search?query=%s"
    :keybinding "r")

  (defengine stack-overflow
    "https://stackoverflow.com/search?q=%s"
    :keybinding "s")

  (defengine rfcs
    "http://pretty-rfc.herokuapp.com/search?q=%s"
    :keybinding "c")

  (defengine nvbug
    "https://nvbugswb.nvidia.com/NvBugs5/SWBug.aspx?bugid=%s"
    :keybinding "n")

  (defengine gitlab
    "https://gitlab.com/search?search=%s"
    :keybinding "b"))

Assistant

(use-package c3po
  :straight (:host github :repo "d1egoaz/c3po.el")
  :config
  (setq c3po-api-key "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"))

;; (use-package org-ai
;;   :ensure
;;   :commands (org-ai-mode org-ai-global-mode)
;;   :init
;;   (add-hook 'org-mode-hook #'org-ai-mode)
;;   (org-ai-global-mode))

General Keybindings

Enable use of arrows in read-mode

     (general-def read-mode-map "<down>" 'next-line)
     (general-def read-mode-map "<up>" 'previous-line)

     ;;; switch between light and dark themes
     (general-def "C-c l t l" '(lambda()
				  (interactive)
				  (disable-theme 'doom-nord)
				  (load-theme 'doom-nord-light t)))

     (general-def "C-c l t d" '(lambda()
				  (interactive)
				  (disable-theme 'doom-nord-light)
				  (load-theme 'doom-nord t)))
     ;; searching and jumping
     (general-create-definer fconfig-search-bind
	:prefix "M-g"
	:name "Search and jump"
	"" '(:ignore t :which-key "Search and jump"))

     (fconfig-search-bind
	"o" 'consult-line
	"O" 'consult-line-multi
	"g" 'consult-goto-line
	"s" 'consult-ripgrep
	"SPC" 'ace-jump-mode
	"C-x SPC" 'ace-jump-mode-pop-mark
	"w" 'ace-window)

     ;; (when (featurep 'fconfig-mm)
     ;;   (fconfig-mm-bind
     ;;     "," #'spotify-previous
     ;;     "." #'spotify-next
     ;;     "<return>" #'spotify-playpause))

     ;;; setting this with general-def doesn't work!
     (global-set-key "\C-l" 'backward-kill-line)
     (general-def "C-x C-\\" 'save-buffers-kill-emacs)
     (general-def "C-x C-c" (lambda () (interactive) (kill-buffer (current-buffer))))
     (general-def "C-x C-b" 'ibuffer)
     (general-def "<S-f3>" 'match-paren)

     ;; remap C-a to `smarter-move-beginning-of-line'
     (general-def [remap move-beginning-of-line]
	'smarter-move-beginning-of-line)

     (general-def "M-o" 'ace-window)

     ;; type-break
     (general-def "M-S-<f10>" 'type-break-statistics)
     (general-def "C-<f11>" 'santosh/dashboard-open)

     ;; notmuch
     (general-def "C-<f3>" 'notmuch)
     (general-def "C-<f4>" 'consult-notmuch)

     ;;; treemacs
     (general-def "C-c t t" 'treemacs)
     (general-def "C-c t s" 'treemacs-select-window)
     (general-def "C-c t e" 'lsp-treemacs-errors-list)
     (general-def "C-c t y" 'lsp-treemacs-symbols-toggle)
     (general-def "C-c t r" 'lsp-treemacs-references)
     (general-def "C-c t i" 'lsp-treemacs-implementations)
     (general-def "C-c t h c" 'lsp-treemacs-call-hierarchy)
     (general-def "C-c t h t" 'lsp-treemacs-type-hierarchy)

     (fconfig-C-c-bind
	"x s" 'vterm
	"x r" 'projectile-run-async-shell-command-in-root
	"s" 'projectile-run-vterm)

     (general-create-definer fconfig-bookmark-bind
	:prefix "C-c r"
	"" '(:ignore t :which-key "Bookmark and registers")
	:name "Bookmark and registers")

     (fconfig-bookmark-bind
	"B" 'bookmark-set
	"b" 'bookmark-set-no-overwrite
	"l" 'list-bookmarks
	"j" 'bookmark-jump
	"J" 'bookmark-jump-other-window
	"r" 'view-register
	"C-l" 'list-registers
	"d" 'register-describe-oneline
	"p" 'point-to-register
	"." 'jump-to-register
	"s" 'copy-to-register
	"i" 'insert-register
	"a" 'append-to-register
	"C-p" 'prepend-to-register
	"R" 'copy-rectangle-to-register
	"w" 'window-configuration-to-register
	"f" 'frame-configuration-to-register
	"n" 'number-to-register
	"+" 'increment-register
	"m" 'kmacro-to-register
	"C-s" 'bookmark-save)

Some keybindings for hideshow minor mode

(general-def "C-c h h" 'hs-toggle-hiding)

Misc

(use-package speed-type
  :ensure t)

Solar

From here: https://www.reddit.com/r/orgmode/comments/a1z26t/sunrise_sunset_as_separate_entries_on_agenda_view/

;; Sunrise (edits by Eph Zero)
;; Brady Trainor
;; http://stackoverflow.com/questions/22889036/custom-diary-sunrise-function-not-working-autoload-diary-emacs
(require 'solar)
(require 'cl-lib)

(defun solar-sunrise-string (date &optional nolocation)
  "String of *local* time of sunrise and daylight on Gregorian DATE."
  (let ((l (solar-sunrise-sunset date)))
    (format
     "%s"
     (if (car l)
         (concat "Sunrise " (apply 'solar-time-string (car l)))
       "no sunrise")
     (nth 2 l))))

;; To be called from diary-list-sexp-entries, where DATE is bound.
;;;###diary-autoload
(defun diary-sunrise ()
  "Local time of sunrise as a diary entry.
  Accurate to a few seconds."
  (or (and calendar-latitude calendar-longitude calendar-time-zone)
      (solar-setup))
  (solar-sunrise-string date))

;; Sunset
;; Brady Trainor
;; http://stackoverflow.com/questions/22889036/custom-diary-sunrise-function-not-working-autoload-diary-emacs

(defun solar-sunset-string (date &optional nolocation)
  "String of *local* time of sunset and daylight on Gregorian DATE."
  (let ((l (solar-sunrise-sunset date)))
    (format
     "%s (%s hours daylight)"
     (if (cadr l)
         (concat "Sunset " (apply 'solar-time-string (cadr l)))
       "no sunset")
     (nth 2 l))))

;; To be called from diary-list-sexp-entries, where DATE is bound.
;;;###diary-autoload
(defun diary-sunset ()
  "Local time of sunset as a diary entry.
  Accurate to a few seconds."
  (or (and calendar-latitude calendar-longitude calendar-time-zone)
      (solar-setup))
  (solar-sunset-string date))

Utilities

(general-create-definer fconfig-utils-bind
  :prefix "C-c u"
  :name "Utilities"
  "" '(:ignore t :which-key "Utilities"))
Finance

A lot to be done here.

	(defun future-value (amount rate years)
	  (* amount (expt (+ 1 (/ (float rate) 100)) years)))

	(defun calculate-compounded-value (amount rate tenure-start tenure-end)
	  "Calculate the total compounded value of AMOUNT compounded at a
	RATE for TENURE-START to TENURE-END years. This can be used to
	calculate future value of an investment or to get how much you
	need when you retire, considering inflation.

	If you want to calculate how much your monthly invest of 10000
	will be after 10 years with a interest rate of 8 percent

	    (calculate-compounded-value (* 12 10000) 8 0 10)

	TENURE-START is 0 before we are calculating from this year.

	Again if a retirement fund needed is to be calculated, the RATE
	will be the inflation rate, and tenure start will be \"number of
	years from today you want to retire\", and tenure end is number
	years from today that one is expected to live. So a monthly need
	of 20000 for 20 years after retiring around 25 years from now,
	with inflation of 4%

	    (calculate-compounded-value (* 12 20000) 4 25 40)
	"

	  (let ((total 0)
		(x 0))
	    (while (< x (- tenure-end tenure-start))
	      (setq total (+ total (future-value amount rate (+ tenure-start x))))
	      (incf x))
	    total))
Speak

A simple function to convert text to speech using OpenAI API.

(defvar openai-tts-cache-directory "~/.emacs.d/openai-tts-cache/")
(defvar openai-tts-playback-process nil "Process used for playing TTS audio.")

(defun get-openai-api-token ()
  "Retrieve the OpenAI API token from the .authinfo file."
  (let ((credential (car (auth-source-search :host "api.openai.com" :require '(:secret)))))
    (if credential
        (let ((token (plist-get credential :secret)))
          (if (functionp token)
              (funcall token) ; If the token is stored as a function, call it to retrieve the value
            token))           ; Otherwise, return the token directly
      (error "No OpenAI API token found in .authinfo"))))

(defun openai-tts (start end)
  "Send the selected text to OpenAI's TTS API, save the speech as an MP3 file and play."
  (interactive "r")
  (lexical-let* ((text (buffer-substring-no-properties start end))
                 (api-key (get-openai-api-token))
                 (api-url "https://api.openai.com/v1/audio/speech")
                 (hashed-text (md5 text))
                 (output-file (expand-file-name
                               (concat openai-tts-cache-directory hashed-text ".mp3"))))

    (if (file-exists-p output-file)
        (progn
          (message "Playing from cache")
          (setq openai-tts-playback-process (start-process "openai-tts-audio" "*#openai-tts-audio*" "mpg123" output-file)))

      ;; Prepare the API request
      (let ((url-request-method "POST")
            (url-request-extra-headers `(("Content-Type" . "application/json")
                                         ("Authorization" . ,(concat "Bearer " api-key))))
            (url-request-data (json-encode `(("model" . "tts-1")
                                             ("input" . ,text)
                                             ("voice" . "alloy")))))

        ;; Send the request
        (url-retrieve api-url (lambda (status)
                                ;; Handle the response
                                ;; Check for errors in `status`
                                (when (equal :error (car status))
                                  (let ((error-message (plist-get (cdr status) :error)))
                                    (error "Error in API request: %s" error-message))
                                  )

                                ;; Save the response to a file
                                (goto-char url-http-end-of-headers)
                                (write-region (point) (point-max) output-file)
                                (message "Speech saved to: %s" output-file)
                                ;; Play the audio file
                                ;; This assumes you have a command-line utility like `mpg123` to play MP3 files
                                (setq openai-tts-playback-process (start-process "openai-tts-audio" nil "mpg123" output-file)))
                      nil t)))))

(defun openai-tts-playback-stop ()
  "Stop the TTS audio playback."
  (interactive)
  (when (process-live-p openai-tts-playback-process)
    (kill-process openai-tts-playback-process)
    (setq openai-tts-playback-process nil)
    (message "Stopped TTS playback.")))

(fconfig-utils-bind "s" 'openai-tts)
(fconfig-utils-bind "S" 'openai-tts-playback-stop)
Read mode
(require 'view)
(require 'hide-mode-line)

(make-variable-buffer-local
 (defvar rm/read-frame nil))

(make-variable-buffer-local
 (defvar rm/line-spacing 0.50))

(make-variable-buffer-local
 (defvar rm/old-line-spacing))

(defun ss/center-window (frame)
  (let ((margin-size (/ (- (frame-width frame) 100) 2)))
    (set-window-margins (frame-root-window frame) 38)))

(defun enable-read-mode ()
  (interactive)
  (setq rm/read-frame (make-frame))
  (set-frame-parameter rm/read-frame 'fullscreen  'fullboth)
  (view-mode-enable)
  (variable-pitch-mode 1)
  (setq-local rm/old-line-spacing line-spacing)
  (setq-local line-spacing rm/line-spacing)
  (ss/center-window rm/read-frame)
  (turn-on-hide-mode-line-mode))

(defun disable-read-mode ()
  (turn-off-hide-mode-line-mode)
  (setq-local line-spacing rm/old-line-spacing)
  (variable-pitch-mode -1)
  (view-mode-disable)
  (delete-frame rm/read-frame))

(define-minor-mode read-mode
  "Minor mode to enhance reading experience"

  :init-value nil
  :lighter " reading"
  :keymap (let ((read-map (make-sparse-keymap)))
            read-map)

  :after-hook (define-key read-mode-map (kbd "q")
                (lambda () (interactive) (read-mode -1)))

  (if read-mode
      (enable-read-mode)
    (disable-read-mode)))

Temporary

The following is a paste of a exiting config file, from which I will slowly move everything to org files.

     (let ((file-name-handler-alist nil))
	 (fconfig! core)
	 (fconfig! packages)
	 (fconfig! org-config)
	 (fconfig! progmode)
     )

     (defun santosh/org-agenda-open ()
	 (interactive)
	 (if (get-buffer "*Org Agenda*")
	     (progn
	       (switch-to-buffer-other-frame "*Org Agenda*")
	       (org-agenda-redo))
	   (progn
	     (let (
		   (org-agenda-window-setup 'only-window)
		   (org-frame (make-frame
			       '((no-other-frame . t)
				 (unsplittable . t)
				 (height . 30)
				 (buffer-list . '("*Org Agenda*"))
				 (minibuffer . nil)
				 (undecorated . t)))))
	       (set-frame-font "monospace-9" t nil)
	       (org-agenda nil "A")
	       (org-agenda-goto-today)
	       (set-window-dedicated-p (selected-window) t)
	       (delete-other-windows)))))

     (global-map! "C-c o RET" 'santosh/org-agenda-open)

     (if (not (server-running-p))
	   (server-start))

     (fconfig/finish)

Load personal setup

Load personal setup file, which can have personal information like email address, location etc, and load host specific setup file, which I only use for setting up font.

(org-babel-load-file (expand-file-name
			    (concat (user-login-name) ".org") "~/.emacs.d"))
(org-babel-load-file (expand-file-name
			    (concat (system-name) ".org") "~/.emacs.d"))
(load custom-file)

(require ‘ox-json)