Skip to content

Latest commit

 

History

History
3196 lines (2895 loc) · 101 KB

README.org

File metadata and controls

3196 lines (2895 loc) · 101 KB

Emacs Configuration

My Emacs Configuration as an org file cause I wanna be like the cool kids 😎

NOTE

This is a mess, unorganized but it works for me. No plan to clean this up. This config will most likely not work for you since its made for me. We are all different. Thanks for coming to my Ted Talk

Recommended Packages/Snippets to Have As Early as Possible

(setq load-prefer-newer t)
(use-package no-littering
  :ensure t)

(use-package quelpa :ensure t)
(use-package quelpa-use-package :ensure t)

Built-Ins

Going to configure all the built in packages first And any third party lib that are related to it will go under them.

Emacs Defaults

Customizing some things that should be defaults ¯\_(ツ)_/¯

;; Customize default emacs
(use-package emacs
  :ensure nil
  :defer
  :hook ((after-init . pending-delete-mode)
         (after-init . toggle-frame-maximized)
         (after-init . (lambda () (scroll-bar-mode -1)))
         (after-init . (lambda () (window-divider-mode -1)))
         (after-init . gopar/add-env-vars))
  :custom
  ;; flash the frame to represent a bell.
  (visible-bell t)
  (debugger-stack-frame-as-list t)
  (narrow-to-defun-include-comments t)
  (use-short-answers t)
  (confirm-nonexistent-file-or-buffer nil)
  ;; Treat manual switching of buffers the same as programatic
  (switch-to-buffer-obey-display-actions t)
  (switch-to-buffer-in-dedicated-window nil)
  (window-sides-slots '(3 0 3 1))
  ;; Sentences end with 1 space not 2
  (sentence-end-double-space nil)
  ;; make cursor the width of the character it is under
  ;; i.e. full width of a TAB
  (x-stretch-cursor t)
  ;; Stop cursor from going into minibuffer prompt text
  (minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt))
  (history-delete-duplicates t)
  ;; Completion stuff for consult
  (completion-ignore-case t)
  (read-buffer-completion-ignore-case t)
  (completion-cycle-threshold nil)
  (tab-always-indent 'complete)
  (use-dialog-box nil) ; Lets be consistent and use minibuffer for everyting
  (scroll-conservatively 100)
  (frame-inhibit-implied-resize t)
  (custom-file "~/.emacs.d/ignoreme.el")

  :config
  (load custom-file)
  (when (eq system-type 'darwin)
    (setq mac-option-key-is-meta nil
          mac-command-key-is-meta t
          mac-command-modifier 'meta
          mac-option-modifier 'none)
    )
  (setq-default c-basic-offset 4
                c-default-style "linux"
                indent-tabs-mode nil
                fill-column 120
                tab-width 4)
  ;; Replaced in favor for `use-short-answers`
  ;; (fset 'yes-or-no-p 'y-or-n-p)
  (prefer-coding-system 'utf-8)
  ;; Uppercase is same as lowercase
  (define-coding-system-alias 'UTF-8 'utf-8)
  ;; Enable some commands
  (put 'upcase-region 'disabled nil)
  (put 'downcase-region 'disabled nil)
  (put 'erase-buffer 'disabled nil)
  ;; C-x n <key> useful stuff
  (put 'narrow-to-region 'disabled nil)
  (tool-bar-mode -1)
  (menu-bar-mode -1)
  (command-query 'save-buffers-kill-terminal "Do you really want to kill emacs?")

  :bind (("C-z" . nil)
         ("C-x C-z" . nil)
         ("C-x C-k RET" . nil)
         ("RET" . newline-and-indent)
         ("C-j" . newline)
         ("M-\\" . cycle-spacing)
         ("C-x \\" . align-regexp)
         ("C-x C-b" . ibuffer)
         ("M-u" . upcase-dwim)
         ("M-l" . downcase-dwim)
         ("M-c" . capitalize-dwim)
         ("C-S-k" . gopar/delete-line-backward)
         ("C-k" . gopar/delete-line)
         ("M-d" . gopar/delete-word)
         ("<M-backspace>" . gopar/backward-delete-word)
         ("M-e" . gopar/next-sentence)
         ("M-a" . gopar/last-sentence)
         (";" . gopar/easy-underscore)
         ("C-x k" . (lambda () (interactive) (kill-buffer)))
         ("C-x C-k" . (lambda () (interactive) (bury-buffer))))

  :init
  (defun gopar/copy-filename-to-kill-ring ()
    (interactive)
    (kill-new (buffer-file-name))
    (message "Copied to file name kill ring"))

  (defun gopar/easy-underscore (arg)
    "Convert all inputs of semicolon to an underscore.
If given ARG, then it will insert an acutal semicolon."
    (interactive "P")
    (if arg
        (insert ";")
      (insert "_")))

  (defun easy-camelcase (arg)
    (interactive "c")
    ;; arg is between a-z
    (cond ((and (>= arg 97) (<= arg 122))
           (insert (capitalize (char-to-string arg))))
          ;; If it's a new line
          ((= arg 13)
           (newline-and-indent))
          ((= arg 59)
           (insert ";"))
          ;; We probably meant a key command, so lets execute that
          (t (call-interactively
              (lookup-key (current-global-map) (char-to-string arg))))))

  (defun sudo-edit (&optional arg)
    "Edit currently visited file as root.
With a prefix ARG prompt for a file to visit.
Will also prompt for a file to visit if current
buffer is not visiting a file."
    (interactive "P")
    (if (or arg (not buffer-file-name))
        (find-file (concat "/sudo:root@localhost:"
                           (completing-read "Find file(as root): ")))
      (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))

  ;; Stolen from https://emacs.stackexchange.com/a/13096/8964
  (defun gopar/reload-dir-locals-for-current-buffer ()
    "Reload dir locals for the current buffer"
    (interactive)
    (let ((enable-local-variables :all))
      (hack-dir-local-variables-non-file-buffer)))

  (defun gopar/delete-word (arg)
    "Delete characters forward until encountering the end of a word.
With argument, do this that many times.
This command does not push text to `kill-ring'."
    (interactive "p")
    (delete-region
     (point)
     (progn
       (forward-word arg)
       (point))))

  (defun gopar/backward-delete-word (arg)
    "Delete characters backward until encountering the beginning of a word.
With argument, do this that many times.
This command does not push text to `kill-ring'."
    (interactive "p")
    (gopar/delete-word (- arg)))

  (defun gopar/delete-line ()
    "Delete text from current position to end of line char.
This command does not push text to `kill-ring'."
    (interactive)
    (delete-region
     (point)
     (progn (end-of-line 1) (point)))
    (delete-char 1))

  (defadvice gopar/delete-line (before kill-line-autoreindent activate)
    "Kill excess whitespace when joining lines.
If the next line is joined to the current line, kill the extra indent whitespace in front of the next line."
    (when (and (eolp) (not (bolp)))
      (save-excursion
        (forward-char 1)
        (just-one-space 1))))

  (defun gopar/delete-line-backward ()
    "Delete text between the beginning of the line to the cursor position.
This command does not push text to `kill-ring'."
    (interactive)
    (let (p1 p2)
      (setq p1 (point))
      (beginning-of-line 1)
      (setq p2 (point))
      (delete-region p1 p2)))

  (defun gopar/next-sentence ()
    "Move point forward to the next sentence.
Start by moving to the next period, question mark or exclamation.
If this punctuation is followed by one or more whitespace
characters followed by a capital letter, or a '\', stop there. If
not, assume we're at an abbreviation of some sort and move to the
next potential sentence end"
    (interactive)
    (re-search-forward "[.?!]")
    (if (looking-at "[    \n]+[A-Z]\\|\\\\")
        nil
      (gopar/next-sentence)))

  (defun gopar/list-git-authors-for-file ()
    "Display all the authors for a given file.
If file is not in a git repo or file is not a real file (aka buffer), then do nothing."
    (interactive)
    (let* ((file (buffer-file-name))
           (root (when (vc-root-dir) (expand-file-name (vc-root-dir))))
           (file (when (and file root) (s-chop-prefix root file))))
      (when (and root file)
        (message (format "Contributors for %s:\n%s" file (shell-command-to-string
          (format "git shortlog HEAD -s -n %s" file)))))))

  (defun gopar/last-sentence ()
    "Does the same as 'gopar/next-sentence' except it goes in reverse"
    (interactive)
    (re-search-backward "[.?!][   \n]+[A-Z]\\|\\.\\\\" nil t)
    (forward-char))

  (defvar gopar-ansi-escape-re
    (rx (or ?\233 (and ?\e ?\[))
        (zero-or-more (char (?0 . ?\?)))
        (zero-or-more (char ?\s ?- ?\/))
        (char (?@ . ?~))))

  (defun gopar/nuke-ansi-escapes (beg end)
    (save-excursion
      (goto-char beg)
      (while (re-search-forward gopar-ansi-escape-re end t)
        (replace-match ""))))

  (defun gopar/toggle-window-dedication ()
    "Toggles window dedication in the selected window."
    (interactive)
    (set-window-dedicated-p (selected-window)
                            (not (window-dedicated-p (selected-window)))))

  (defun gopar/add-env-vars ()
    "Setup environment variables that I will need."
    (load-file "~/.emacs.d/etc/eshell/set_env.el")
    (setq-default eshell-path-env (getenv "PATH"))

    (setq exec-path (append exec-path
                            `("/usr/local/bin"
                              "/usr/bin"
                              "/usr/sbin"
                              "/sbin"
                              "/bin"
                              "/Users/gopar/.nvm/versions/node/v16.14.2/bin/"
                              )
                            (split-string (getenv "PATH") ":")))))

Diary

(use-package calendar
  :ensure nil
  :mode ("\\diary\\'" . diary-mode)
  :custom
  (diary-file (concat user-emacs-directory "etc/diary"))
  (diary-display-function 'ignore)
  (calendar-mark-diary-entries-flat t)
  (diary-comment-start ";;")
  (diary-comment-end ""))

Org Mode

Org

Main configuration

;; https://stackoverflow.com/a/10091330/2178312
(use-package org
  :defer
  :custom
  (org-agenda-include-diary t)
  ;; Where the org files live
  (org-directory "~/.emacs.d/org/")
  ;; Where archives should go
  (org-archive-location (concat (expand-file-name "~/.emacs.d/org/private/org-roam/gtd/archives.org") "::"))
  ;; Make sure we see syntax highlighting
  (org-src-fontify-natively t)
  ;; I dont use it for subs/super scripts
  (org-use-sub-superscripts nil)
  ;; Should everything be hidden?
  (org-startup-folded 'content)
  (org-M-RET-may-split-line '((default . nil)))
  ;; Don't hide stars
  (org-hide-leading-stars nil)
  (org-hide-emphasis-markers nil)
  ;; Show as utf-8 chars
  (org-pretty-entities t)
  ;; put timestamp when finished a todo
  (org-log-done 'time)
  ;; timestamp when we reschedule
  (org-log-reschedule t)
  ;; Don't indent the stars
  (org-startup-indented nil)
  (org-list-allow-alphabetical t)
  (org-image-actual-width nil)
  ;; Save notes into log drawer
  (org-log-into-drawer t)
  ;;
  (org-fontify-whole-heading-line t)
  (org-fontify-done-headline t)
  ;;
  (org-fontify-quote-and-verse-blocks t)
  ;; See down arrow instead of "..." when we have subtrees
  ;; (org-ellipsis "⤵")
  ;; catch invisible edit
  ( org-catch-invisible-edits 'show-and-error)
  ;; Only useful for property searching only but can slow down search
  (org-use-property-inheritance t)
  ;; Count all children TODO's not just direct ones
  (org-hierarchical-todo-statistics nil)
  ;; Unchecked boxes will block switching the parent to DONE
  (org-enforce-todo-checkbox-dependencies t)
  ;; Don't allow TODO's to close without their dependencies done
  (org-enforce-todo-dependencies t)
  (org-track-ordered-property-with-tag t)
  ;; Where should notes go to? Dont even use them tho
  (org-default-notes-file (concat org-directory "notes.org"))
  ;; The right side of | indicates the DONE states
  (org-todo-keywords
   '((sequence "TODO(t)" "NEXT(n)" "IN-PROGRESS(i!)" "WAITING(w!)" "|" "DONE(d!)" "CANCELED(c!)" "DELEGATED(p!)")))
  ;; Needed to allow helm to compute all refile options in buffer
  (org-outline-path-complete-in-steps nil)
  (org-deadline-warning-days 2)
  (org-log-redeadline t)
  (org-log-reschedule t)
  ;; Repeat to previous todo state
  ;; If there was no todo state, then dont set a state
  (org-todo-repeat-to-state t)
  ;; Refile options
  (org-refile-use-outline-path 'file)
  (org-refile-allow-creating-parent-nodes 'confirm)
  (org-refile-targets '(("~/.emacs.d/org/private/org-roam/gtd/gtd.org" :maxlevel . 3)
                        ("~/.emacs.d/org/private/org-roam/gtd/someday.org" :level . 1)
                        ("~/.emacs.d/org/private/org-roam/gtd/tickler.org" :maxlevel . 1)
                        ("~/.emacs.d/org/private/org-roam/gtd/repeat.org" :maxlevel . 1)
                        ))
  ;; Lets customize which modules we load up
  (org-modules '(;; ol-eww
                 ;; Stuff I've enabled below
                 org-habit
                 ;; org-checklist
                 ))
  (org-special-ctrl-a/e t)
  (org-insert-heading-respect-content t)
  :hook ((org-mode . org-indent-mode)
         (org-mode . org-display-inline-images))
  :custom-face
  (org-scheduled-previously ((t (:foreground "orange"))))
  :config
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((sql . t)
     (sqlite . t)
     (python . t)
     (java . t)
     ;; (cpp . t)
     (C . t)
     (emacs-lisp . t)
     (shell . t)))
  ;; Save history throughout sessions
  (org-clock-persistence-insinuate))

Org Tempo

(use-package org-tempo
  :after org
  :config
  (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
  (add-to-list 'org-structure-template-alist '("p" . "src python"))
  (add-to-list 'org-structure-template-alist '("j" . "src java"))
  (add-to-list 'org-structure-template-alist '("k" . "src kotlin"))
  (add-to-list 'org-structure-template-alist '("sh" . "src sh")))

Org Clock

(use-package org-clock
  :after org
  :custom
  ;; Save clock history accross emacs sessions (read var for required info)
  (org-clock-persist t)
  ;; If idle for more than 15 mins, resolve by asking what to do with clock
  (org-clock-idle-time 15)
  ;; Don't show current clocked in task
  (org-clock-clocked-in-display nil)
  ;; Show more clocking history
  (org-clock-history-length 10)
  ;; Include running time in clock reports
  (org-clock-report-include-clocking-task t)
  ;; Put all clocking info int the "CLOCKING" drawer
  (org-clock-into-drawer "CLOCKING")
  ;; Setup default clocktable summary
  (org-clock-clocktable-default-properties
   '(:maxlevel 2 :scope file :formula % ;; :properties ("Effort" "Points")
               :sort (5 . ?t) :compact t :block today))
  :bind (:map global-map
              ("C-c j" . (lambda () (interactive) (org-clock-jump-to-current-clock)))
              :map org-mode-map
              ("C-c C-x r" . (lambda () (interactive) (org-clock-report)))))

Org Agenda

(use-package org-agenda
  :after org
  :bind (("C-c a" . org-agenda))
  :hook ((org-agenda-finalize . hl-line-mode)
         ;; (org-agenda-finalize . org-agenda-entry-text-mode)
         )
  :custom
  (org-agenda-current-time-string (if (and (display-graphic-p)
           (char-displayable-p ?←)
           (char-displayable-p ?─))
      "⬅️ now"
    "now - - - - - - - - - - - - - - - - - - - - - - - - -"))
  (org-agenda-timegrid-use-ampm t)
  (org-agenda-tags-column 0)
  (org-agenda-window-setup 'only-window)
  (org-agenda-restore-windows-after-quit t)
  (org-agenda-log-mode-items '(closed clock state))
  (org-agenda-time-grid '((daily today require-timed)
                          (600 800 1000 1200 1400 1600 1800 2000)
                          " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄"))
  ;; (org-agenda-start-with-log-mode '(closed clock state))
  (org-agenda-files "~/.emacs.d/org/agenda-files.org")
  ;; (org-agenda-todo-ignore-scheduled 'future)
  ;; TODO entries that can't be marked as done b/c of children are shown as dimmed in agenda view
  (org-agenda-dim-blocked-tasks 'invisible)
  ;; Start the week view on whatever day im on
  (org-agenda-start-on-weekday nil)
  ;; How to identify stuck/non-stuck projects
  ;; Projects are identified by the 'project' tag and its always the first level
  ;; Next any of these todo keywords means it's not a stuck project
  ;; 3rd, theres no tags that I use to identify a stuck Project
  ;; Finally, theres no special text that signify a non-stuck project
  (org-stuck-projects
   '("+project+LEVEL=1"
     ("IN-PROGRESS" "WAITING" "DONE" "CANCELED" "DELEGATED")
     nil
     ""))
  (org-agenda-prefix-format
   '((agenda . " %-4e %i %-12:c%?-12t% s ")
     (todo . " %i %-10:c %-5e %(gopar/get-schedule-or-deadline-if-available)")
     (tags . " %i %-12:c")
     (search . " %i %-12:c")))
  ;; Lets define some custom cmds in agenda menu
  (org-agenda-custom-commands
   '(("h" "Agenda and Home tasks"
      ((agenda "" ((org-agenda-span 1)))
       (todo "WAITING|IN-PROGRESS")
       (tags-todo "inbox|break")
       (todo "NEXT"))
      ((org-agenda-sorting-strategy '(time-up habit-up priority-down category-up))))

     ("i" "In-Progress Tasks"
      ((todo "IN-PROGRESS|WAITING")
       (agenda ""))
      ((org-agenda-sorting-strategy '(time-up habit-up priority-down category-up))))

     ("g" "Goals: 12 Week Year"
      ((agenda "")
       (todo "IN-PROGRESS|WAITING"))
      ((org-agenda-sorting-strategy '(time-up habit-up priority-down category-up))
       (org-agenda-tag-filter-preset '("+12WY"))
       (org-agenda-start-with-log-mode '(closed clock state))
       (org-agenda-archives-mode t)
       ))

     ("r" "Weekly Review"
      ((agenda "" ((org-agenda-span 14)))
       (todo))
      ((org-agenda-sorting-strategy '(time-up habit-up category-up priority-down ))
       (org-agenda-files "~/.emacs.d/org/weekly-reivew-agenda-files.org")
       (org-agenda-include-diary nil)))))
  :init
  ;; Originally from here: https://stackoverflow.com/a/59001859/2178312
  (defun gopar/get-schedule-or-deadline-if-available ()
    (let ((scheduled (org-get-scheduled-time (point)))
          (deadline (org-get-deadline-time (point))))
      (if (not (or scheduled deadline))
          (format "🗓️ ")
        "   "))))

Org Capture

(use-package org-capture
  :after org
  :bind (("C-c c" . org-capture))
  :custom
  ;; dont create a bookmark when calling org-capture
  (org-capture-bookmark nil)
  ;; also don't create bookmark in other things
  (org-bookmark-names-plist nil)
  (org-capture-templates
   '(
     ("c" "Inbox" entry (file "~/.emacs.d/org/private/org-roam/gtd/inbox.org")
      "* TODO %?\n:PROPERTIES:\n:DATE_ADDED: %u\n:END:")
     ("p" "Project" entry (file "~/.emacs.d/org/private/org-roam/gtd/gtd.org")
      "* %? [%] :project: \n:PROPERTIES: \n:TRIGGER: next-sibling todo!(NEXT) scheduled!(copy)\n:ORDERED: t \n:DATE_ADDED: %u\n:END:\n** TODO Add entry")
     ("t" "Tickler" entry (file "~/.emacs.d/org/private/org-roam/gtd/tickler.org")
      "* TODO %? \nSCHEDULED: %^{Schedule}t\n:PROPERTIES:\n:DATE_ADDED: %u\n:END:\n")
     ("k" "Contact" entry (file "~/.emacs.d/org/private/org-roam/references/contacts.org")
      "* %? \n%U
:PROPERTIES:
:EMAIL:
:PHONE:
:NICKNAME:
:NOTE:
:ADDRESS:
:BIRTHDAY:
:Blog:
:END:"))))

Org OL

(use-package ol
  :after org
  :custom
  (org-link-shell-confirm-function 'y-or-n-p)
  (org-link-elisp-confirm-function 'y-or-n-p))

Org Src

(use-package org-src
  :after org
  :custom
  (org-src-preserve-indentation nil)
  ;; Don't ask if we already have an open Edit buffer
  (org-src-ask-before-returning-to-edit-buffer nil)
  (org-edit-src-content-indentation 0))

Ob Core

(use-package ob-core
  :after org
  :custom
  ;; Don't ask every time when I run a code block
  (org-confirm-babel-evaluate nil))

Org Habit

(use-package org-habit
  :ensure nil
  :custom
  (org-habit-graph-column 45))

Org indent

(use-package org-indent
  :ensure nil
  :diminish
  :custom
  (org-indent-mode-turns-on-hiding-stars nil))

I know this isn’t built in but putting it here w/ org mode stuff

(use-package org-pomodoro
  :ensure t
  :after org
  :bind (("<f12>" . org-pomodoro))
  :hook ((org-pomodoro-started . gopar/load-window-config-and-close-home-agenda)
         (org-pomodoro-finished . gopar/save-window-config-and-show-home-agenda))
  :custom
  (org-pomodoro-manual-break t)
  (org-pomodoro-short-break-length 20)
  (org-pomodoro-long-break-length 30)
  (org-pomodoro-length 60)
  :init
  (defun gopar/home-pomodoro ()
    (interactive)
    (setq org-pomodoro-length 25
          org-pomodoro-short-break-length 5))

  (defun gopar/work-pomodoro ()
    (interactive)
    (setq org-pomodoro-length 60
          org-pomodoro-short-break-length 20))

  (defun gopar/save-window-config-and-show-home-agenda ()
    (interactive)
    (window-configuration-to-register ?`)
    (delete-other-windows)
    (org-save-all-org-buffers)
    (org-agenda nil "h"))

  (defun gopar/load-window-config-and-close-home-agenda ()
    (interactive)
    (org-save-all-org-buffers)
    (jump-to-register ?`)))

Also not built in but putting it here

(use-package org-edna
  :ensure t
  :diminish
  :custom
  (org-edna-use-inheritance t)
  ;; Global minor mode, lets enable it once
  :hook (after-init . org-edna-mode))
(use-package org-roam
  :ensure t
  :defer
  :custom
  (org-roam-directory (expand-file-name "~/.emacs.d/org/private/org-roam"))
  (org-roam-db-location (expand-file-name "~/.emacs.d/org/private/org-roam.db"))
  (org-roam-capture-templates
   '(("d" "default" plain "%?"
      :target (file+head "./references/${slug}.org" "#+title: ${title}\n")
      :unnarrowed t)))
  (org-roam-dailies-directory (expand-file-name "~/.emacs.d/org/private/journal/"))
  (org-roam-dailies-capture-templates
   `(("d" "daily" plain (file "/Users/gopar/.emacs.d/org/templates/dailies-daily.template")
      :target (file+head "daily/%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))

     ("w" "weekly" plain (file "/Users/gopar/.emacs.d/org/templates/dailies-weekly.template")
      :target (file+head "weekly/%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))

     ("m" "monthly" plain (file "/Users/gopar/.emacs.d/org/templates/dailies-monthly.template")
      :target (file+head "monthly/%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))))

  :bind (:map global-map
              (("C-c n i" . org-roam-node-insert)
               ("C-c n f" . org-roam-node-find)
               ("C-c n g" . org-roam-graph)
               ("C-c n n" . org-roam-capture)
               ("C-c n d" . org-roam-dailies-capture-today)
               ("C-c n s" . consult-org-roam-search)))
  :hook (after-init . org-roam-db-autosync-mode))

Org Annotate File

;; Belongs from the org-contrib pkg?
(use-package org-annotate-file
  :ensure nil
  :load-path "lisp/org"
  :defer
  :custom
  (org-annotate-file-add-search t)
  (org-annotate-file-storage-file (concat user-emacs-directory "var/.org-annotate-file.org"))
  :bind (:map prog-mode-map
              ("C-c C-s" . gopar/org-annotate-file)
         :map python-mode-map
              ("C-c C-s" . gopar/org-annotate-file)
         :map python-ts-mode-map
              ("C-c C-s" . gopar/org-annotate-file)
         :map web-mode-map
              ("C-c C-s" . gopar/org-annotate-file))
  :init
  (defun gopar/org-annotate-file (&optional arg)
    "Annotate current line.
When called with a prefix aurgument, it will open annotations file."
    (interactive "P")
    (require 'org-annotate-file)
    (let* ((root (projectile-project-root))
           (org-annotate-file-storage-file
            (if root
                (format "%s.org-annotate.org" root)
              org-annotate-file-storage-file)))
      (if arg
          (find-file org-annotate-file-storage-file)
        (org-annotate-file)))))

Org Misc

(defun gopar/daily-log ()
  "Insert a new daily log entry with the current date."
  (interactive)
  (goto-char (point-max))
  (org-insert-heading-respect-content)
  (insert (format-time-string "[%Y-%m-%d %a]") "\n")
  (insert "- Accomplishments:\n")
  (insert "  - Task 1\n")
  (insert "  - Task 2\n")
  (insert "- Challenges:\n")
  (insert "  - Issue 1\n")
  (insert "  - Issue 2\n")
  (insert "- Learnings:\n")
  (insert "  - Insight 1\n")
  (insert "  - Insight 2\n")
  (insert "- Plans for Tomorrow:\n")
  (insert "  - Task 1\n")
  (insert "  - Task 2\n"))

(defalias 'gopar/journal-eng-entry 'gopar/daily-log)

Eshell

Some of the following are stolen from https://github.com/manateelazycat/aweshell

(use-package eshell
  :ensure nil
  :hook ((eshell-directory-change . gopar/sync-dir-in-buffer-name)
         (eshell-mode . gopar/eshell-specific-outline-regexp)
         (eshell-mode . gopar/eshell-setup-keybinding)
         (eshell-banner-load . (lambda ()
                                 (setq eshell-banner-message
                                       (concat (shell-command-to-string "fortune -s | cowsay") "\n\n"))))
         (eshell-mode . (lambda ()
                          (setq-local completion-styles '(basic)) ; maybe emacs21?
                          (setq-local corfu-count 10)
                          (setq-local corfu-auto nil)
                          (setq-local corfu-preview-current nil)
                          (setq-local completion-at-point-functions '(pcomplete-completions-at-point cape-file)))))
  :custom
  (eshell-scroll-to-bottom-on-input t)
  (eshell-highlight-prompt nil)
  (eshell-history-size 1024)
  (eshell-hist-ignoredups t)
  (eshell-input-filter 'gopar/eshell-input-filter)
  (eshell-cd-on-directory t)
  (eshell-list-files-after-cd nil)
  (eshell-pushd-dunique t)
  (eshell-last-dir-unique t)
  (eshell-last-dir-ring-size 32)
  :config
  (advice-add #'eshell-add-input-to-history
                :around
                #'gopar/adviced-eshell-add-input-to-history)

  :init
  (defun gopar/eshell-setup-keybinding ()
    ;; Workaround since bind doesn't work w/ eshell??
    (define-key eshell-mode-map (kbd "C-c >") 'gopar/eshell-redirect-to-buffer)
    (define-key eshell-hist-mode-map (kbd "M-r") 'consult-history))

  (defun gopar/adviced-eshell-add-input-to-history (orig-fun &rest r)
      "Cd to relative paths aren't that useful in history. Change to absolute paths."
      (require 'seq)
      (let* ((input (nth 0 r))
             (args (progn
                     (set-text-properties 0 (length input) nil input)
                     (split-string input))))
        (if (and (equal "cd" (nth 0 args))
                 (not (seq-find (lambda (item)
                                  ;; Don't rewrite "cd /ssh:" in history.
                                  (string-prefix-p "/ssh:" item))
                                args))
                 (not (seq-find (lambda (item)
                                  ;; Don't rewrite "cd -" in history.
                                  (string-equal "-" item))
                                args)))
            (apply orig-fun (list (format "cd %s"
                                          (expand-file-name (concat default-directory
                                                                    (nth 1 args))))))
          (apply orig-fun r))))

  (defun gopar/eshell-input-filter (input)
    "Do not save on the following:
       - empty lines
       - commands that start with a space, `ls`/`l`/`lsd`"
    (and
     (eshell-input-filter-default input)
     (eshell-input-filter-initial-space input)
     (not (string-prefix-p "ls " input))
     (not (string-prefix-p "lsd " input))
     (not (string-prefix-p "l " input))))

  (defun eshell/cat-with-syntax-highlighting (filename)
    "Like cat(1) but with syntax highlighting.
Stole from aweshell"
    (let ((existing-buffer (get-file-buffer filename))
          (buffer (find-file-noselect filename)))
      (eshell-print
       (with-current-buffer buffer
         (if (fboundp 'font-lock-ensure)
             (font-lock-ensure)
           (with-no-warnings
             (font-lock-fontify-buffer)))
         (let ((contents (buffer-string)))
           (remove-text-properties 0 (length contents) '(read-only nil) contents)
           contents)))
      (unless existing-buffer
        (kill-buffer buffer))
      nil))
  (advice-add 'eshell/cat :override #'eshell/cat-with-syntax-highlighting)

  (defun gopar/sync-dir-in-buffer-name ()
    "Update eshell buffer to show directory path.
Stolen from aweshell."
    (let* ((root (projectile-project-root))
           (root-name (projectile-project-name root)))
      (if root-name
          (rename-buffer (format "*eshell %s* %s" root-name (s-chop-prefix root default-directory)) t)
        (rename-buffer (format "*eshell %s*" default-directory) t))))

  (defun gopar/eshell-redirect-to-buffer (buffer)
    "Auto create command for redirecting to buffer."
    (interactive (list (read-buffer "Redirect to buffer: ")))
    (insert (format " >>> #<%s>" buffer)))

(defun gopar/eshell-specific-outline-regexp ()
  (setq-local outline-regexp eshell-prompt-regexp)))
(use-package eshell-syntax-highlighting
  :ensure t
  :config
  (eshell-syntax-highlighting-global-mode +1)
  :init
  (defface eshell-syntax-highlighting-invalid-face
    '((t :inherit diff-error))
    "Face used for invalid Eshell commands."
    :group 'eshell-syntax-highlighting))
(use-package eshell-git-prompt
  :after eshell
  :ensure t)

(use-package powerline-with-venv
  :ensure nil
  :after eshell-git-prompt
  :load-path "lisp/themes/powerline-with-venv"
  :config
  (add-to-list 'eshell-git-prompt-themes
               '(powerline-plus eshell-git-prompt-powerline-venv eshell-git-prompt-powerline-regexp))
  (eshell-git-prompt-use-theme 'powerline-plus))
(use-package capf-autosuggest
  :ensure t
  :hook ((eshell-mode . capf-autosuggest-mode))
  :custom
  (capf-autosuggest-dwim-next-line nil))

Python

Run on every fresh virtualenv install pip install jedi epc importmagic ruff mypy coverage pytest-cov pytest

I get some weird auto completion in inferior python shell mode when I leave the default completion function. Lets just have in buffer completion

(use-package python
  :ensure nil
  :bind (:map python-mode-map
              ("C-c C-p" . nil)
              ("C-c C-e" . nil)
              ("C-c C-s" . nil)
              ("C-c C-z" . gopar/run-python)
         :map python-ts-mode-map
              ("C-c C-p" . nil)
              ("C-c C-e" . nil)
              ("C-c C-s" . nil)
              ("C-c C-z" . gopar/run-python))
  :hook ((python-ts-mode . (lambda ()
                          (setq-local forward-sexp-function nil)
                          (make-local-variable 'python-shell-virtualenv-root)
                          (setq-local comment-inline-offset 2)
                          (setq-local completion-at-point-functions
                                      '(cape-file
                                        ;; python-completion-at-point
                                        gopar/cape-yasnippet-keyword-dabbrev
                                        gopar/cape-dict-only-in-strings
                                        gopar/cape-dict-only-in-comments
                                        ))))
         (inferior-python-mode . (lambda ()
                                   (setq-local completion-at-point-functions '(t)))))

  :init
  (defun gopar/run-python ()
    "Wrapper function for `run-python` that checks if the current project is a Django project."
    (interactive)
    (let* ((manage-directory (locate-dominating-file default-directory "manage.py"))
           (default-directory (or manage-directory default-directory)))
      (if manage-directory
          (run-python (format "python manage.py shell_plus" manage-directory) python-shell-dedicated 0)
        (run-python (python-shell-calculate-command) python-shell-dedicated 0))))
  :custom
  (python-shell-dedicated 'project)
  (python-shell-interpreter "python")
  (python-shell-interpreter-args "")
  (python-forward-sexp-function nil)
  (python-shell-completion-native-disabled-interpreters '("python" "pypy")))

Virtualenv

Handy mode that takes care of envs for me. Downside is that I have to explicitly set where to find venvs instead of auto finding them

(use-package virtualenvwrapper
  :ensure t
  :init
  (venv-initialize-eshell))

Pyvenv

I’m keeping this function around since it’s convineint to be able to create venvs from `pyvenv-create` and then do `venv-workon` in dir locals.

(use-package pyvenv
  :ensure t
  :defer
  :commands (pyvenv-create)
  )
(use-package ruff-format
  :ensure t
  :defer
  :hook ((python-mode python-ts-mode) . gopar/enable-ruff-if-found)
  :init
  (defun gopar/enable-ruff-if-found ()
    "Format the current buffer using the 'ruff` program, if available."
    (interactive)
    (if (executable-find "ruff")
        (ruff-format-on-save-mode))))

Required Jedi to work properly

(use-package pydoc
  :ensure t
  :defer
  :bind (:map python-mode-map
              ("C-c C-d" . gopar/pydoc-at-point))
  :init
  (add-to-list 'display-buffer-alist
            '("^\\*pydoc" display-buffer-in-side-window
              (slot . 1)
              (side . right)
              (window-parameters . ((no-delete-other-windows . t)))
              (dedicated . t)
              ;; (window-width . 80)
              ))

  (defun gopar/pydoc-at-point ()
    "Display pydoc in a dedicated window.
Calling `gopar/pydoc-at-point' displays the pydoc in a new dedicated window.
Calling `C-u gopar/pydoc-at-point' closes the dedicated window."
    (interactive)
    (let ((default-directory (file-name-directory (buffer-file-name))))
      (if (not (eq current-prefix-arg nil))
          (when (get-buffer-window "*pydoc*")
            (delete-window (get-buffer-window "*pydoc*")))
        (pydoc-at-point)
        (set-window-dedicated-p (get-buffer-window "*pydoc*") t)))))

Jedi

Only use this for ‘eldoc’ documentation. Works most of the time. I say ‘eldoc’ in quotes b/c this doens’t really use eldoc. It echos out the method/func signature instead of using eldoc.

Requires pip install jedi epc in all virtualenvs

NOTE: Needs this PR in order to work in newer python versions

(use-package jedi
  :ensure t
  :defer
  :commands (jedi-mode)
  :hook ((python-mode python-ts-mode) . jedi-mode)
  :custom
  (jedi:tooltip-method nil)
  (jedi:mode-function nil)
  (jedi:setup-function nil))

Kotlin

(use-package kotlin-mode :ensure t :defer)

Tree Sitter Auto Magic

(use-package treesit-auto
  :ensure t
  :custom
  (treesit-auto-install 'prompt)
  :config
  (treesit-auto-add-to-auto-mode-alist 'all)
  (global-treesit-auto-mode))

Flycheck Kotlin

(use-package flycheck-kotlin
  :ensure t
  :defer
  :hook (kotlin-mode . (lambda () (flycheck-mode 1) (flycheck-kotlin-setup))))

GUD (Debugger)

(use-package gud
  :ensure nil
  :defer
  :custom
  (gud-pdb-command-name "PYTHONBREAKPOINT=pdb.set_trace python -m pdb"))

Compile

(use-package compile
  :ensure nil
  :defer
  :custom
  (compilation-scroll-output 'first-error)
  (compilation-ask-about-save nil)
  (compilation-always-kill t)
  (compilation-max-output-line-length nil)
  (compilation-buffer-name-function 'gopar/compilation-buffer-name-function)
  :hook (compilation-mode . hl-line-mode)
  :init
  (defun gopar/compilation-buffer-name-function (compilation-mode)
    "Rename buffer to whatever command was used.
eg. *python main.py*"
    (concat "*" (downcase compilation-mode)
          (when (projectile-project-p) (concat " " (projectile-project-name))) "* "
          compile-command))

  ; from enberg on #emacs
  (add-hook 'compilation-finish-functions
            (lambda (buf str)
              (if (null (string-match ".*exited abnormally.*" str))
                  ;;no errors, make the compilation window go away in a few seconds
                  (progn
                    (run-at-time
                     "1 sec" nil 'delete-windows-on
                     (buffer-name))
                    (message "No Compilation Errors!"))))))
(use-package fancy-compilation
  :ensure t
  :defer 3
  :config
  (fancy-compilation-mode)
  :custom
  (fancy-compilation-scroll-output 'first-error))

For TDD development

(use-package recompile-on-save
  :ensure t
  ;; Kill the buffer message that pops up after running advice on compile
  :hook (after-init . (lambda () (run-at-time 1 nil
     (lambda ()
        (when (get-buffer "*Compile-Log*")
           (kill-buffer "*Compile-Log*"))
        (delete-other-windows)))))

  :init
  (recompile-on-save-advice compile))

Winner

Window Management

(use-package winner
  :ensure nil
  :hook after-init
  :commands (winner-undo winnner-redo)
  :custom
  (winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*"
                           "*Buffer List*" "*info*" "*Compile-Log*")))

Window

(use-package window
  :ensure nil
  :defer
  :custom
  (recenter-positions '(middle top bottom)))

Midnight

(use-package midnight
  :ensure nil
  :hook (after-init . midnight-mode)
  :custom
  (clean-buffer-list-delay-general 0)
  (clean-buffer-list-delay-special 0)
  (clean-buffer-list-kill-regexps '("\\`\\*Man " "\\`\\*helpful" "\\`\\magit")))

Executeable

(use-package executable
  :ensure nil
  :hook (after-save . executable-make-buffer-file-executable-if-script-p))

Jinx Spelling

If on new system, might need to install enchant and pkg-config

(use-package jinx
  :ensure t
  :hook (after-init . global-jinx-mode)
  :bind (("C-." . jinx-correct)
         ("C-," . jinx-next)
         :map jinx-mode-map
         ("M-$" . nill)
         ))

Dictionary

Look up word at point using dict.org in readme/text/org-mode buffers

(use-package dictionary
  :defer
  :ensure nil
  :bind (:map text-mode-map
              ("M-." . dictionary-lookup-definition)
         :map org-mode-map
              ("M-." . dictionary-lookup-definition)
         :map dictionary-mode-map
              ("M-." . dictionary-lookup-definition))
  :init
  (add-to-list 'display-buffer-alist
               '("^\\*Dictionary\\*" display-buffer-in-side-window
                 (side . left)
                 (window-width . 50)))
  :custom
  (dictionary-server "dict.org"))

Minibuffer

;; It may also be wise to raise gc-cons-threshold while the minibuffer is active,
;; so the GC doesn't slow down expensive commands (or completion frameworks, like
;; helm and ivy. The following is taken from doom-emacs
(use-package minibuffer
  :ensure nil
  :custom
  (completion-styles '(initials partial-completion flex)))

Time

(use-package time
  :ensure nil
  ;; :hook (after-init . display-time-mode) ;; Usually just look at the OS time
  :custom
  (world-clock-time-format "%A %d %B %r %Z")
  (display-time-day-and-date t)
  (display-time-default-load-average nil)
  (display-time-mail-string "")
  (zoneinfo-style-world-list
  '(("America/Los_Angeles" "Seattle")
    ("America/New_York" "New York")
    ("America/Halifax" "Nova Scotia")
    ("Asia/Tokyo" "Tokyo"))))

Proced

(use-package proced
  :ensure nil
  :defer t
  :custom
  (proced-enable-color-flag t)
  (proced-tree-flag t))

Browse URL

(use-package browse-url
  :ensure nil
  :custom
  ;; Emacs can't find browser binaries
  (browse-url-chrome-program "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome")
  (browse-url-firefox-program "/Applications/Firefox.app/Contents/MacOS/firefox")
  ;; Neat trick to open that route to different places
  (browse-url-firefox-new-window-is-tab t)
  ;; Default to using eww for browsing
  (browse-url-browser-function 'eww-browse-url)
  :config
  (put 'browse-url-handlers 'safe-local-variable (lambda (x) t))
  (put 'browse-url-browser-function 'safe-local-variable (lambda (x) t)))

Eww

(use-package eww
  :defer t
  :init
  (add-hook 'eww-after-render-hook #'shrface-mode)
  ;; (add-hook 'eww-mode-hook 'ewnium-mode)
  :config
  (require 'shrface))

SHR

(use-package shrface
  :ensure t
  :defer t
  :config
  (shrface-basic)
  (shrface-trial)
  (shrface-default-keybindings) ; setup default keybindings
  (setq shrface-href-versatile t))
(use-package shr-tag-pre-highlight
  :ensure t
  :after shr
  :config
  (add-to-list 'shr-external-rendering-functions
               '(pre . shr-tag-pre-highlight)))

Prog Mode

(use-package prog-mode
  :ensure nil
  :defer
  :hook ((prog-mode . subword-mode)
         (prog-mode . hl-line-mode)
         (prog-mode . (lambda () (setq-local fill-column 120)))))

Which Function

(use-package which-func
  :ensure nil
  :defer
  :hook (prog-mode . which-function-mode))

Projectile

(use-package projectile
  :ensure
  :load t
  :commands projectile-project-root
  :hook (after-init . projectile-global-mode)
  :bind-keymap
  ("C-c p" . projectile-command-map)

  :custom
  (projectile-indexing-method 'hybrid)  ;; Not sure if this still needed?
  (projectile-per-project-compilation-buffer nil)
  :config
  (setq frame-title-format '(:eval (if (projectile-project-root) (projectile-project-root) "%b")))
  (advice-add 'projectile--run-project-cmd :override #'gopar/projectile--run-project-cmd)
  :init
  ;; Redefinig with my changes since projectil overwrites `compilation-buffer-name-function`
  (cl-defun gopar/projectile--run-project-cmd
    (command command-map &key show-prompt prompt-prefix save-buffers use-comint-mode)
  "Run a project COMMAND, typically a test- or compile command.

Cache the COMMAND for later use inside the hash-table COMMAND-MAP.

Normally you'll be prompted for a compilation command, unless
variable `compilation-read-command'.  You can force the prompt
by setting SHOW-PROMPT.  The prompt will be prefixed with PROMPT-PREFIX.

If SAVE-BUFFERS is non-nil save all projectile buffers before
running the command.

The command actually run is returned."
  (let* ((project-root (projectile-project-root))
         (default-directory (projectile-compilation-dir))
         (command (projectile-maybe-read-command show-prompt
                                                 command
                                                 prompt-prefix)))
    (when command-map
      (puthash default-directory command command-map)
      (let ((hist (projectile--get-command-history project-root)))
        (cond
         ((eq projectile-cmd-hist-ignoredups t)
          (unless (string= (car-safe (ring-elements hist)) command)
            (ring-insert hist command)))
         ((eq projectile-cmd-hist-ignoredups 'erase)
          (let ((idx (ring-member hist command)))
            (while idx
              (ring-remove hist idx)
              (setq idx (ring-member hist command))))
          (ring-insert hist command))
         (t (ring-insert hist command)))))
    (when save-buffers
      (save-some-buffers (not compilation-ask-about-save)
                         (lambda ()
                           (projectile-project-buffer-p (current-buffer)
                                                        project-root))))
    (when projectile-per-project-compilation-buffer
      (setq compilation-buffer-name-function #'projectile-compilation-buffer-name)
      (setq compilation-save-buffers-predicate #'projectile-current-project-buffer-p))
    (unless (file-directory-p default-directory)
      (mkdir default-directory))
    (projectile-run-compilation command use-comint-mode)
    command))
  )

Repeat Mode

Allows repeating via `C-x z` (pressing z multiple times keeps repeating) or by pressing last keybinding of previous command

(use-package repeat
  :ensure nil
  :hook (after-init . repeat-mode)
  :custom
  (repeat-too-dangerous '(kill-this-buffer))
  (repeat-exit-timeout 5))

Save Place

(use-package saveplace
  :ensure nil
  :hook (after-init . save-place-mode))

Save History

(use-package savehist
  :ensure nil
  :hook (after-init . savehist-mode)
  :custom
  (savehist-additional-variables '(abbrev-minor-mode-table-alist)))

Grep

(use-package grep
  :ensure nil
  :defer
  :custom
  (grep-find-ignored-directories (append grep-find-ignored-directories '(".mypy_cache" ".pytest_cache" "htmlcov"))))

wgrep

(use-package wgrep-ag :ensure t :defer)

Code Completion

A collection of packages that act as ‘smart’ completion in which really are not :) Also includes displaying of them

(use-package vertico
  :ensure t
  :hook (rfn-eshadow-update-overlay . vertico-directory-tidy)
  :init
  (vertico-mode)
  (setq vertico-cycle t))

(use-package vertico-multiform
  :ensure nil
  :hook (after-init . vertico-multiform-mode)
  :init
  (setq vertico-multiform-commands
        '((consult-line (:not posframe))
          (gopar/consult-line (:not posframe))
          (consult-ag (:not posframe))
          (consult-grep (:not posframe))
          (consult-imenu (:not posframe))
          (xref-find-definitions (:not posframe))
          (t posframe))))

;; just for looks
(use-package vertico-posframe
  :ensure t
  :hook (after-init . vertico-posframe-mode)
  :custom
  (vertico-posframe-parameters
   '((left-fringe . 8)
     (right-fringe . 8))))

(use-package dabbrev
  :custom
  (dabbrev-upcase-means-case-search t)
  (dabbrev-check-all-buffers nil)
  (dabbrev-check-other-buffers t)
  (dabbrev-friend-buffer-function 'dabbrev--same-major-mode-p)
  (dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'")))

(use-package corfu
  :ensure t
  ;; Originally, I liked the idea of `corfu-send` but this makes it behave
  ;; in way that is different from 'fish' shell. So lets disable and see
  ;; how we feel about it in the future
  ;; :bind (:map corfu-map
  ;;             ("RET" . corfu-send))
  :custom
  (corfu-cycle t)                ;; Enable cycling for `corfu-next/previous'
  (corfu-auto t)                 ;; Enable auto completion
  (corfu-on-exact-match 'insert) ;; Insert when there's only one match
  (corfu-quit-no-match t)        ;; Quit when ther is no match
  :init
  (global-corfu-mode)

  (defun corfu-enable-always-in-minibuffer ()
    "Enable Corfu in the minibuffer if Vertico/Mct are not active."
    (unless (or (bound-and-true-p mct--active)
                (bound-and-true-p vertico--input)
                (eq (current-local-map) read-passwd-map))
      ;; (setq-local corfu-auto nil) ;; Enable/disable auto completion
      (setq-local corfu-echo-delay nil ;; Disable automatic echo and popup
                  corfu-popupinfo-delay nil)
      (corfu-mode 1)))

  (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1))

(use-package cape
  :ensure t
  :bind ("C-c SPC" . cape-dabbrev)
  :custom
  (cape-dict-case-replace nil)
  :init
  (setq cape-dabbrev-min-length 2)
  (setq cape-dabbrev-check-other-buffers 'cape--buffers-major-mode)

  (defun gopar/cape-dict-only-in-comments ()
    (cape-wrap-inside-comment 'cape-dict))

  (defun gopar/cape-dict-only-in-strings ()
    (cape-wrap-inside-string 'cape-dict))

  (defun gopar/cape-yasnippet-keyword-dabbrev ()
    (cape-wrap-super #'yasnippet-capf #'cape-keyword #'cape-dabbrev))

  (add-to-list 'completion-at-point-functions #'cape-file)
  (add-to-list 'completion-at-point-functions #'gopar/cape-yasnippet-keyword-dabbrev)
  (add-to-list 'completion-at-point-functions #'gopar/cape-dict-only-in-strings)
  (add-to-list 'completion-at-point-functions #'gopar/cape-dict-only-in-comments))

(use-package orderless
  :ensure t
  :after consult
  :custom
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles basic partial-completion)))))

(use-package consult
  :ensure
  :after projectile
  :bind (("C-s" . gopar/consult-line)
         ("C-c M-x" . consult-mode-command)
         ("C-x b" . consult-buffer)
         ("C-x r b" . consult-bookmark)
         ("M-y" . consult-yank-pop)
         ;; M-g bindings (goto-map)
         ("M-g M-g" . consult-goto-line)
         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ("C-z" . consult-theme)
         :map minibuffer-local-map
         ("M-s" . consult-history)                 ;; orig. next-matching-history-element
         ("M-r" . consult-history)
         :map projectile-command-map
         ("b" . consult-project-buffer)
         :map prog-mode-map
         ("M-g o" . consult-imenu))

  :init
  (defun remove-items (x y)
    (setq y (cl-remove-if (lambda (item) (memq item x)) y))
    y)

  ;; Any themes that are incomplete/lacking don't work with centaur tabs/solair mode
  (setq gopar/themes-blacklisted '(
                                   ;; doom-tomorrow-night
                                   ayu-dark
                                   ayu-light
                                   doom-acario-dark
                                   doom-acario-light
                                   doom-homage-black
                                   doom-lantern
                                   doom-manegarm
                                   doom-meltbus
                                   doom-rougue
                                   light-blue
                                   manoj-black
                                   tao
                                   ))
  (setq consult-themes (remove-items gopar/themes-blacklisted (custom-available-themes)))
  (setq consult-project-function (lambda (_) (projectile-project-root)))
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)
  (setq consult-narrow-key "<")
  (setq consult-line-start-from-top nil)

  (defun gopar/consult-line (&optional arg)
    "Start consult search with selected region if any.
If used with a prefix, it will search all buffers as well."
    (interactive "p")
    (let ((cmd (if current-prefix-arg '(lambda (arg) (consult-line-multi t arg)) 'consult-line)))
      (if (use-region-p)
          (let ((regionp (buffer-substring-no-properties (region-beginning) (region-end))))
            (deactivate-mark)
            (funcall cmd regionp))
        (funcall cmd "")))))

(use-package consult-ag
  :ensure
  :defer
  :bind (:map projectile-command-map
              ("s s" . consult-ag)
              ("s g" . consult-grep)))

(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
  (consult-org-roam-grep-func #'consult-ag)
  ;; 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 nil)
  :config
  ;; Eventually suppress previewing for certain functions
  (consult-customize
   consult-org-roam-forward-links
   :preview-key (kbd "M-.")))

(use-package marginalia
  :ensure
  :init
  ;; Must be in the :init section of use-package such that the mode gets
  ;; enabled right away. Note that this forces loading the package.
  (marginalia-mode))

;; (use-package embark
;;   :ensure t
;;   :defer
;;   :bind (("C-." . embark-act)))

;; (use-package embark-consult
;;   :ensure t
;;   :after embark)

pcomplete

(use-package pcmpl-args
  :ensure t
  :load t
  :hook (eshell-first-time-mode . gopar/add-pcmpl-custom-commands)
  :init
  (defun gopar/add-pcmpl-custom-commands ()
                                     (dolist (command '("lsd" "pip3" "docker" "docker-compose" "ffmpeg"))
                                       (let ((alias-name (intern (concat "pcomplete/" command))))
                                         (eval `(defalias ',alias-name 'pcmpl-args-pcomplete-on-help))))

                                     (dolist (command '())
                                       (let ((alias-name (intern (concat "pcomplete/" command))))
                                         (eval `(defalias ',alias-name 'pcmpl-args-pcomplete-on-man))))

                                     (defalias 'pcomplete/pip 'pcomplete/pip3)))

(use-package pcmpl-homebrew :ensure t :after eshell)

Dumb Jump

A basic ‘go to’ functionality that works really well. So I don’t need LSP

(use-package dumb-jump
  :ensure t
  :defer
  :custom
  (dumb-jump-prefer-searcher 'ag)
  (dumb-jump-force-searcher 'ag)
  (dumb-jump-selector 'completing-read)
  (dumb-jump-default-project "~/work")
  :init
  (add-hook 'xref-backend-functions #'dumb-jump-xref-activate))

Xref

(use-package xref
  :ensure nil
  :defer t
  :init
  (defun gopar/xref-backend-html-template ()
    "Xref backend for jumping to HTML template definitions."
    (when (and (thing-at-point 'filename t) (string-suffix-p ".html" (thing-at-point 'filename t)))
      'gopar-html-template))

  (cl-defmethod xref-backend-identifier-at-point ((_backend (eql gopar-html-template)))
    (thing-at-point 'filename t))

  (cl-defmethod xref-backend-definitions ((_backend (eql gopar-html-template)) identifier)
    (let ((path (cl-find-if (lambda (x) (string-match-p identifier x))
                            (projectile-project-files (projectile-project-root)))))
      (when path
        (list (xref-make identifier (xref-make-file-location (format "%s%s" (projectile-project-root) path) 1 0))))))
  (add-hook 'xref-backend-functions #'gopar/xref-backend-html-template))

Web Mode

(use-package web-mode
  :ensure t
  :defer
  :init
  (setq-default web-mode-code-indent-offset 2)
  (setq web-mode-engines-alist '(("django"    . "\\.html\\'")))
  (setq web-mode-content-types-alist '(("jsx"  . "\\.js[x]?\\'")))

  :hook (web-mode . (lambda ()
                      (highlight-indentation-mode -1)
                      (electric-pair-local-mode -1)))
  :custom
  (web-mode-script-padding 0)
  (web-mode-enable-html-entities-fontification t)
  (web-mode-enable-element-content-fontification t)
  (web-mode-enable-current-element-highlight t)
  (web-mode-enable-current-column-highlight t)
  (web-mode-markup-indent-offset 2)
  (web-mode-css-indent-offset 2)
  (web-mode-sql-indent-offset 2)
  :mode (("\\.vue\\'" . web-mode)
         ("\\.html\\'" . web-mode)
         ("\\.js[x]?\\'" . web-mode)
         ))

Emmet-mode

(use-package emmet-mode
  :ensure t
  :defer t
  :config
  (defun emmet-jsx-supported-mode? ()
    "Is the current mode we're on enabled for jsx class attribute expansion?"
    (or (member major-mode emmet-jsx-major-modes)
        (and (string= major-mode "web-mode") (string= web-mode-content-type "jsx"))))
  :hook (web-mode . emmet-mode))

TypeScript

(use-package typescript-mode
  :ensure t
  :defer
  :bind (:map typescript-mode-map
              (";" . easy-camelcase))
  :custom
  (typescript-indent-level 2))

Markdown

(use-package markdown-mode
  :defer t
  :ensure t
  :bind (:map markdown-mode-map
              ("M-." . dictionary-lookup-definition)))

Dockerfile

(use-package dockerfile-mode
  :ensure t
  :defer)
(use-package docker
  :ensure t
  :defer
  :bind ("C-c d" . docker))

YAML

(use-package yaml-mode
  :ensure t
  :defer)

Rainbow mode

Color the string of whatever color code they are holding

(use-package rainbow-mode
  :defer
  :ensure t
  :hook (prog-mode . rainbow-mode))

Alert

(use-package alert
  :ensure t
  :defer
  :custom
  (alert-default-style 'message)
  (alert-fade-time 5))

Which Key

(use-package which-key
  :ensure t
  :hook (after-init . which-key-mode)
  :custom
  (which-key-idle-delay 2))

Helpful

(use-package helpful
  :ensure t
  :defer
  :bind (("C-h f" . helpful-callable)
         ("C-h v" . helpful-variable)
         ("C-h k" . helpful-key)))

Corral

(use-package corral
  :ensure t
  :defer
  :bind (("M-9" . corral-parentheses-backward)
         ("M-0" . corral-parentheses-forward)
         ("M-[" . corral-brackets-backward)
         ("M-]" . corral-brackets-forward)
         ("M-\"" . corral-single-quotes-backward)
         ("M-'" . corral-single-quotes-forward)))

Highlight Indentation

(use-package highlight-indentation
  :ensure t
  :defer
  :hook ((prog-mode . highlight-indentation-mode)
         (prog-mode . highlight-indentation-current-column-mode)))

Highlight TODO

(use-package hl-todo
  :ensure t
  :defer t
  :hook (prog-mode . hl-todo-mode))

Move Text

(use-package move-text
  :ensure t
  :defer
  :init (move-text-default-bindings))

Iedit

(use-package iedit
  :ensure t
  :defer
  :bind (("C-c o" . iedit-mode))
  :custom
  (iedit-toggle-key-default nil))

Expand Region

(use-package expand-region
  :ensure t
  :defer
  :bind (("C-\\" . er/expand-region)))

So Long

(use-package so-long
  :ensure nil
  :hook (after-init . global-so-long-mode))

Avy

(use-package avy
  :ensure t
  :defer
  :bind (("M-g c" . avy-goto-char-2)
         ("M-g g" . avy-goto-line)
         ("M-g w" . avy-goto-word-1)))

All The Icons

(use-package all-the-icons
  :ensure t
  :defer
  :if (display-graphic-p))

(use-package all-the-icons-completion
  :ensure t
  :defer
  :hook (marginalia-mode . #'all-the-icons-completion-marginalia-setup)
  :init
  (all-the-icons-completion-mode))

Ibuffer

;; Ibuffer Icons sets it's own local buffer format and overrides the =ibuffer-formats= variable.
;; So in order for ibuffer-vc to work, I have to include it in the icons-buffer format -_-
(use-package all-the-icons-ibuffer
  :ensure t
  :defer
  :custom
  (all-the-icons-ibuffer-formats
   `((mark modified read-only locked vc-status-mini
           ;; Here you may adjust by replacing :right with :center or :left
           ;; According to taste, if you want the icon further from the name
           " " ,(if all-the-icons-ibuffer-icon
                    '(icon 2 2 :left :elide)
                  "")
           ,(if all-the-icons-ibuffer-icon
                (propertize " " 'display `(space :align-to 8))
              "")
           (name 18 18 :left :elide)
           " " (size-h 9 -1 :right)
           " " (mode+ 16 16 :left :elide)
           " " (vc-status 16 16 :left)
           " " vc-relative-file)
     (mark " " (name 16 -1) " " filename)))

  :hook (ibuffer-mode . all-the-icons-ibuffer-mode))

;; https://github.com/purcell/ibuffer-vc/blob/master/ibuffer-vc.el
(use-package ibuffer-vc
  :ensure t
  :hook (ibuffer . (lambda ()
                     (ibuffer-vc-set-filter-groups-by-vc-root)
                     (unless (eq ibuffer-sorting-mode 'alphabetic)
                       (ibuffer-do-sort-by-vc-status)
                       ;; (ibuffer-do-sort-by-alphabetic)
                       )
                     )))

Webjump

(use-package webjump
  :defer
  :ensure nil
  :bind ("C-x /" . webjump)
  :config
  (setq webjump-sites
        '(("DuckDuckGo" . [simple-query "www.duckduckgo.com" "www.duckduckgo.com/?q=" ""])
          ("Google" . [simple-query "www.google.com" "www.google.com/search?q=" ""])
          ("YouTube" . [simple-query "www.youtube.com/feed/subscriptions" "www.youtube.com/results?search_query=" ""])
          ("CCBV" . [simple-query "https://ccbv.co.uk/" "https://ccbv.co.uk/" ""]))))

RFC Browsing

(use-package rfc-mode
  :defer
  :ensure t)

Electric Pair

(use-package elec-pair
  :ensure nil
  :defer
  :hook (after-init . electric-pair-mode))

Version Control

(use-package magit
  :ensure t
  :commands magit-get-current-branch
  :defer
  :bind ("C-x g" . magit)
  :hook (magit-mode . magit-wip-mode)
  :custom
  (magit-diff-refine-hunk 'all)
  (magit-process-finish-apply-ansi-colors t)
  :init
  (setq magit-process-finish-apply-ansi-colors t)
  (defun magit/undo-last-commit (number-of-commits)
    "Undoes the latest commit or commits without loosing changes"
    (interactive "P")
    (let ((num (if (numberp number-of-commits)
                   number-of-commits
                 1)))
      (magit-reset-soft (format "HEAD^%d" num)))))

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

;; Part of magit
(use-package git-commit
  :ensure nil
  :after magit
  :hook (git-commit-setup . gopar/auto-insert-jira-ticket-in-commit-msg)
  :custom
  (git-commit-summary-max-length 80)
  :init
  (defun gopar/auto-insert-jira-ticket-in-commit-msg ()
    (let ((has-ticket-title (string-match "^[A-Z]+-[0-9]+" (magit-get-current-branch)))
          (words (s-split-words (magit-get-current-branch))))
      (if has-ticket-title
          (insert (format "[%s-%s] " (car words) (car (cdr words))))))))

(use-package git-gutter
  :ensure t
  :hook (after-init . global-git-gutter-mode))

Parens

(use-package paren
  :ensure nil
  :hook (after-init . show-paren-mode)
  :custom
  (show-paren-style 'mixed)
  (show-paren-context-when-offscreen t))

Battery

(use-package battery
  :ensure nil
  :hook (after-init . display-battery-mode))

Yasnippet

;; After adding or updating a snippet run:
;; =M-x yas-recompile-all=
;; =M-x yas-reload-all=
(use-package yasnippet
  :ensure t
  :defer
  :hook ((prog-mode . yas-minor-mode)
         (org-mode . yas-minor-mode)
         (fundamental-mode . yas-minor-mode)
         (text-mode . yas-minor-mode)
         (eshell-mode . yas-minor-mode)
         (after-init . yas-reload-all))
  :bind (:map yas-minor-mode-map
              ("C-c C-SPC" . yas-insert-snippet)))

Actual Snippets

(use-package yasnippet-snippets
  :ensure t
  :defer)

To use as a super capf with a few others

(use-package yasnippet-capf
  :ensure t
  :quelpa (yasnippet-capf :fetcher github :repo "elken/yasnippet-capf"))
(use-package dashboard
  :ensure t
  :custom
  (dashboard-startup-banner 'logo)
  (dashboard-center-content t)
  (dashboard-show-shortcuts nil)
  (dashboard-set-heading-icons t)
  (dashboard-icon-type 'all-the-icons)
  (dashboard-set-file-icons t)
  (dashboard-projects-backend 'projectile)
  (dashboard-items '(
                     (vocabulary)
                     (recents . 5)
                     (bookmarks . 5)
                     ;; (monthly-balance)
                     ))
  (dashboard-item-generators '(;; (monthly-balance . gopar/dashboard-ledger-monthly-balances)
                              (vocabulary . gopar/dashboard-insert-vocabulary)
                              (recents . dashboard-insert-recents)
                              (bookmarks . dashboard-insert-bookmarks)
                              ))
  :init
  (defun gopar/dashboard-insert-vocabulary (list-size)
    (dashboard-insert-heading "Word of the Day:"
                              nil
                              (all-the-icons-faicon "newspaper-o"
                                                    :height 1.2
                                                    :v-adjust 0.0
                                                    :face 'dashboard-heading))
    (insert "\n")
    (let ((random-line nil)
          (lines nil))
      (with-temp-buffer
        (insert-file-contents (concat user-emacs-directory "words"))
        (goto-char (point-min))
        (setq lines (split-string (buffer-string) "\n" t))
        (setq random-line (nth (random (length lines)) lines))
        (setq random-line (string-join (split-string random-line) " ")))
      (insert "    " random-line)))

  (defun gopar/dashboard-ledger-monthly-balances (list-size)
    (interactive)
    (dashboard-insert-heading "Monthly Balance:"
                              nil
                              (all-the-icons-faicon "money"
                                                    :height 1.2
                                                    :v-adjust 0.0
                                                    :face 'dashboard-heading))
    (insert "\n")
    (let* ((categories '("Expenses:Food:Restaurants"
                         "Expenses:Food:Groceries"
                         "Expenses:Misc"))
           (current-month (format-time-string "%Y/%m"))
           (journal-file (expand-file-name "~/personal/finances/main.dat"))
           (cmd (format "ledger bal --flat --monthly --period %s %s -f %s"
                        current-month
                        (mapconcat 'identity categories " ")
                        journal-file)))

      (insert (shell-command-to-string cmd))))
  :config
  (dashboard-setup-startup-hook))

Display Fill Column

Collides with compact-docstrings so turning off for programming modes

(use-package display-fill-column-indicator
  :ensure nil
  :hook (;; (python-mode . display-fill-column-indicator-mode)
         (org-mode . display-fill-column-indicator-mode))
  )

Dired

(use-package dired
  :ensure nil
  :defer
  :hook ((dired-mode . dired-hide-details-mode)
         (dired-mode . hl-line-mode))
  :custom
  (dired-do-revert-buffer t)
  (dired-auto-revert-buffer t)
  (delete-by-moving-to-trash t)
  (dired-mouse-drag-files t)
  (dired-dwim-target t)
  ;; (dired-guess-shell-alist-user)
  (dired-listing-switches "-AlhoF --group-directories-first"))

(use-package all-the-icons-dired
  :ensure t
  :defer
  :hook (dired-mode . all-the-icons-dired-mode)
  :custom
  (all-the-icons-dired-monochrome nil))

(use-package files
  :ensure nil
  :custom
  (insert-directory-program "gls") ; Will not work if system does not have GNU gls installed
  ;; Don't have backup
  (backup-inhibited t)
  ;; Don't save anything.
  (auto-save-default nil)
  ;; If file doesn't end with a newline on save, automatically add one.
  (require-final-newline t)
  :config
  (add-to-list 'auto-mode-alist '("Pipfile" . conf-toml-mode)))

Dired Subtree

(use-package dired-subtree
  :ensure t
  :after dired
  :bind (:map dired-mode-map
              ("<tab>" . dired-subtree-toggle)
              ("<C-tab>" . dired-subtree-cycle)
              ("<backtab>" . dired-subtree-remove) ;; Shift + Tab
              ))

Replace/Occur

(use-package replace
  :ensure nil
  :defer
  :hook (occur-mode . (lambda () ;; (setq-local window-size-fixed 'width)
                        (occur-rename-buffer)))
  :custom
  (list-matching-lines-default-context-lines 0)
  :bind (("C-c C-o" . gopar/occur-definitions))
  :init
  ;; (add-to-list 'display-buffer-alist
  ;;              '("^\\*Occur\\*"
  ;;                display-buffer-in-side-window
  ;;                (side . left)
  ;;                (window-width . 40)))

  (defun gopar/occur-definitions ()
    "Show all the function/method/class definitions for the current language."
    (interactive)
    (cond
     ((eq major-mode 'emacs-lisp-mode)
      (occur "\(defun"))
     ((or (eq major-mode 'python-mode) (eq major-mode 'python-ts-mode))
      (occur "^\s*\\(\\(async\s\\|\\)def\\|class\\)\s"))
     ;; If no matching, then just do regular occur
     (t (call-interactively 'occur)))))

Ansi Color

(use-package ansi-color
  :ensure nil
  :defer
  :hook (compilation-filter . ansi-color-compilation-filter)
  :init
  (defun gopar/compilation-nuke-ansi-escapes ()
    (toggle-read-only)
    (gopar/nuke-ansi-escapes (point-min) (point-max))
    (toggle-read-only))

  ;; https://stackoverflow.com/questions/3072648/cucumbers-ansi-colors-messing-up-emacs-compilation-buffer
  (defun gopar/colorize-compilation-buffer ()
    "Colorize the output from compile buffer"
    (read-only-mode -1)
    (ansi-color-apply-on-region (point-min) (point-max))
    (read-only-mode 1)))

JS

(use-package js
  :defer
  :bind (:map js-mode-map
              (";" . easy-camelcase)

              :map js-jsx-mode-map
              (";" . easy-camelcase))
  :custom
  (js-indent-level 2)
  (js-jsx-indent-level 2))

Pulse

(use-package pulse
  :ensure nil
  :defer
  :init
  (defun pulse-line (&rest _)
    "Pulse the current line."
    (pulse-momentary-highlight-one-line (point)))

  (dolist (command '(scroll-up-command
                     scroll-down-command
                     windmove-left
                     windmove-right
                     windmove-up
                     windmove-down
                     move-to-window-line-top-bottom
                     recenter-top-bottom
                     other-window))
    (advice-add command :after #'pulse-line)))

Mouse Scroll

For my mouse that also has left - right mouse scroll

(use-package mwheel
  :ensure nil
  :custom
  (mouse-wheel-tilt-scroll t)
  (mouse-wheel-scroll-amount-horizontal 2)
  (mouse-wheel-flip-direction t))

Whitespace

(use-package whitespace
  :ensure nil
  :defer
  :hook (before-save . whitespace-cleanup))

Auto revert

(use-package autorevert
  :ensure nil
  :custom
  ;; auto refresh files when changed from disk
  (global-auto-revert-mode t))

Simple

Built in package that holds a few goodies

(use-package simple
  :ensure nil
  :defer
  :hook ((makefile-mode . indent-tabs-mode)
         (fundamental-mode . delete-selection-mode)
         (fundamental-mode . auto-fill-mode)
         (org-mode . auto-fill-mode))
  :custom
  (save-interprogram-paste-before-kill t)
  :init

  (defun gopar/pulse-current-region (&rest _)
  "Pulse the current implicit or active region."
  (if mark-active
      (pulse-momentary-highlight-region (region-beginning) (region-end))
    (pulse-momentary-highlight-region (mark) (point))))

  (advice-add #'kill-ring-save :before #'gopar/pulse-current-region))

Neotree

Here since treemacs keeps on breaking, and this is backup. Works pretty well

(use-package neotree
  :ensure t
  :bind ("<f5>" . neotree-toggle)
  :custom
  (neo-theme 'icons)
  (neo-smart-open t)
  (neo-autorefresh t)
  (neo-window-width (gopar/neo-width))
  ;; takes too long to update on first try
  ;; (neo-vc-integration '(face char))
  (neo-show-hidden-files t)

  :init
  (defun gopar/neo-width ()
    "Detect if the display is an ultrawide monitor or a built-in Mac display."
    (interactive)
    (let* ((display-width (display-pixel-width))
           (display-height (display-pixel-height))
           (aspect-ratio (/ (float display-width) display-height)))
      (cond
       ;; Example conditions, need to adjust based on the specific resolution
       ;; criteria you're using to differentiate displays.
       ((and (> display-width 2500)
             (> aspect-ratio 2.0))
        40) ;; ~12 percent of ultra wide screen
       ((and (<= display-width 2560)
             (<= aspect-ratio 2.0))
        30)
       (t
        (error "Unknown display type"))))))

Dizze

Unfortunately need this: davidmiller/dizzee#5

Sooo I manually copied the PR fix into the init section. Sigh.

(use-package dizzee
  :ensure t
  :defer
  :config
  (dz-defservice bfd-runserver "python"
                 :args ("manage.py" "runserver")
                 :cd "/Users/gopar/work/fiagents/")
  (dz-defservice bfd-flower "flower"
                 :args ("-A" "core" "--host=127.0.0.1" "--port=9002")
                 :cd "/Users/gopar/work/fiagents/")
  (dz-defservice bfd-bot-run "python"
                 :args ("manage.py" "bot" "run")
                 :cd "/Users/gopar/work/fiagents/")
  (dz-defservice bfd-celery-downloader-queue "celery"
                 :args ("-A" "core" "worker" "-n" "Downloader" "-Q" "Downloader" "--concurrency=8" "--purge" "-l" "info")
                 :cd "/Users/gopar/work/fiagents/")
  (dz-defservice bfd-celery-slow-downloader-queue "celery"
                 :args ("-A" "core" "worker" "-n" "SlowDownloader" "-Q" "SlowDownloader" "--concurrency=2" "--purge" "-l" "info")
                 :cd "/Users/gopar/work/fiagents/")
  (dz-defservice bfd-celery-diffbot-queue "celery"
                 :args ("-A" "core" "worker" "-n" "Diffbot" "-Q" "Diffbot" "--concurrency=8" "--purge" "-l" "info")
                 :cd "/Users/gopar/work/fiagents/")
  (dz-defservice bfd-celery-launcher-queue "celery"
                 :args ("-A" "core" "worker" "-n" "Launcher" "-Q" "Launcher" "--concurrency=8" "--purge" "-l" "info")
                 :cd "/Users/gopar/work/fiagents/")
  (dz-defservice-group bfd-celerys-flower-and-server (bfd-celery-diffbot-queue
                                                      bfd-celery-downloader-queue
                                                      bfd-celery-slow-downloader-queue
                                                      bfd-celery-launcher-queue
                                                      bfd-flower
                                                      bfd-runserver)))

String Inflection

(use-package string-inflection
  :ensure t
  :defer
  :commands string-inflection-insert
  :bind (("C-;" . gopar/string-inflection-cycle-auto))
  :init
  (defun string-inflection-web-mode-function (str)
    "foo_bar => fooBar => Foo_Bar => FOO_BAR => fooBar"
    (cond
     ((string-inflection-underscore-p str)
      (string-inflection-camelcase-function str))
     ((string-inflection-camelcase-p str)
      (string-inflection-pascal-case-function str))
     ((string-inflection-pascal-case-p str)
      (string-inflection-upcase-function str))
     (t
      (string-inflection-camelcase-function str))))

  (defun string-inflection-web-mode-style-cycle ()
    "foo_bar => FOO_BAR => FooBar => foo_bar"
    (interactive)
    (string-inflection--single-or-region #'string-inflection-web-mode-function))

  (defun gopar/string-inflection-cycle-auto ()
    "Switching by major mode."
    (interactive)
    (cond
     ((eq major-mode 'emacs-lisp-mode)
      (string-inflection-all-cycle))

     ((or (eq major-mode 'python-mode) (eq major-mode 'python-ts-mode))
      (string-inflection-python-style-cycle))

     ((or (eq major-mode 'js-mode)
          (eq major-mode 'vue-mode)
          (eq major-mode 'java-mode)
          (eq major-mode 'typescript-mode))
      (string-inflection-java-style-cycle))

     ((eq major-mode 'nxml-mode)
      (string-inflection-java-style-cycle))

     ((eq major-mode 'hy-mode)
      (string-inflection-kebab-case))

     ((eq major-mode 'web-mode)
      (string-inflection-web-mode-style-cycle))

     (t
      (string-inflection-ruby-style-cycle)))))

String Edit

Only available in 29 or higher

(use-package string-edit
  :ensure nil
  :defer
  :init
  (defun gopar/replace-str-at-point (new-str)
    (let ((bounds (bounds-of-thing-at-point 'string)))
      (when bounds
        (delete-region (car bounds) (cdr bounds))
        (insert new-str))))

  (defun gopar/edit-string-at-point ()
    (interactive)
    (let ((string (thing-at-point 'string t)))
      (string-edit "String at point:" string 'gopar/replace-str-at-point :abort-callback (lambda ()
                     (exit-recursive-edit)
                     (message "Aborted edit"))))))

Compact Docstring

(use-package compact-docstrings
  :ensure t
  :defer
  :hook (prog-mode . compact-docstrings-mode))

Transient

(use-package transient
  :ensure t
  :defer
  :bind ("C-M-o" . windows-transient-window)
  :init
  (transient-define-prefix windows-transient-window ()
   "Display a transient buffer showing useful window manipulation bindings."
    [["Resize"
     ("}" "h+" enlarge-window-horizontally :transient t)
     ("{" "h-" shrink-window-horizontally :transient t)
     ("^" "v+" enlarge-window :transient t)
     ("V" "v-" shrink-window :transient t)]
     ["Split"
    ("v" "vertical" (lambda ()
       (interactive)
       (split-window-right)
       (windmove-right)) :transient t)
    ("x" "horizontal" (lambda ()
       (interactive)
       (split-window-below)
       (windmove-down)) :transient t)
    ("wv" "win-vertical" (lambda ()
       (interactive)
       (select-window (split-window-right))
       (windows-transient-window)) :transient nil)
    ("wx" "win-horizontal" (lambda ()
       (interactive)
       (select-window (split-window-below))
       (windows-transient-window)) :transient nil)]
    ["Misc"
     ("B" "switch buffer" (lambda ()
                            (interactive)
                            (consult-buffer)
                            (windows-transient-window)))
     ("z" "undo" (lambda ()
                  (interactive)
                  (winner-undo)
                  (setq this-command 'winner-undo)) :transient t)
    ("Z" "redo" winner-redo :transient t)]]
    [["Move"
    ("h" "" windmove-left :transient t)
    ("j" "" windmove-down :transient t)
    ("l" "" windmove-right :transient t)
    ("k" "" windmove-up :transient t)]
    ["Swap"
     ("s" "Swap" ace-swap-window)
     ]
    ;; ("sh" "←" windmove-swap-states-left :transient t)
    ;; ("sj" "↓" windmove-swap-states-down :transient t)
    ;; ("sl" "→" windmove-swap-states-right :transient t)
    ;; ("sk" "↑" windmove-swap-states-up :transient t)]
    ["Delete"
    ("dh" "" windmove-delete-left :transient t)
    ("dj" "" windmove-delete-down :transient t)
    ("dl" "" windmove-delete-right :transient t)
    ("dk" "" windmove-delete-up :transient t)
    ("D" "This" delete-window :transient t)]
    ["Transpose"
    ("tt" "" (lambda ()
                (interactive)
                (transpose-frame)
                (windows-transient-window)) :transient nil)
    ("ti" "" (lambda ()
                (interactive)
                (flip-frame)
                (windows-transient-window)) :transient nil)
    ("to" "" (lambda ()
                (interactive)
                (flop-frame)
                (windows-transient-window)) :transient nil)
    ("tc" "" (lambda ()
                (interactive)
                (rotate-frame-clockwise)
                (windows-transient-window)) :transient nil)
    ("ta" "" (lambda ()
                (interactive)
                (rotate-frame-anticlockwise)
                (windows-transient-window)) :transient nil)]]))

Transient Frame

(use-package transpose-frame :after transient :ensure t)

Vterm

(use-package vterm
  :ensure t
  :defer
  :bind (:map vterm-mode-map ("C-q" . vterm-send-next-key))
  :init
  ;; Remove window if we exit vterm
  (add-hook 'vterm-exit-functions
     (lambda (_ _)
       (let* ((buffer (current-buffer))
              (window (get-buffer-window buffer)))
         (when (not (one-window-p))
           (delete-window window))
         (kill-buffer buffer))))

   (defun gopar/display-vterm-buffer (buffer alist)
    (let ((window (display-buffer-in-direction
                   buffer '((direction . bottom)
                            (split-height-threshold . 1)
                            (window-height . .33)))))
      (if window
          (select-window window)
        (message "No appropriate window found for displaying VTerm buffer"))))

   (add-to-list 'display-buffer-alist
             '("\\*vterm"
               gopar/display-vterm-buffer))
  :custom
  (vterm-max-scrollback 100000))
(use-package devdocs
  :ensure t
  :defer
  :bind ("C-c M-d" . gopar/devdocs-lookup)
  :init
  (add-to-list 'display-buffer-alist
               '("\\*devdocs\\*"
                 display-buffer-in-side-window
                 (side . right)
                 (slot . 3)
                 (window-parameters . ((no-delete-other-windows . t)))
                 (dedicated . t)))

  (defun gopar/devdocs-lookup (&optional ask-docs)
    "Light wrapper around `devdocs-lookup` which pre-populates the function input with thing at point"
    (interactive "P")
    (let ((query (thing-at-point 'symbol t)))
      (devdocs-lookup ask-docs query)))


  :hook (((python-mode python-ts-mode) . (lambda () (setq-local devdocs-current-docs
                                      '("django~4.2" "django_rest_framework" "python~3.11" "postgresql~12"))))
         (web-mode . (lambda () (setq-local devdocs-current-docs '("vue~3"
                                                                   "vue_router~4"
                                                                   "javascript"
                                                                   "typescript"
                                                                   "vitest"
                                                                   "moment"
                                                                   "tailwindcss"
                                                                   "html"
                                                                   "css"))))
         (typescript-mode . (lambda () (setq-local devdocs-current-docs '("vue~3"
                                                                          "vue_router~4"
                                                                          "javascript"
                                                                          "typescript"
                                                                          "vitest"
                                                                          "moment"))))))

Link Hint

(use-package link-hint
  :ensure t
  :defer)

Flycheck

(use-package flycheck
  :ensure
  :defer
  :hook (((python-mode python-ts-mode) . flycheck-mode))
  :bind (:map flycheck-mode-map
              ("C-c C-n" . flycheck-next-error)
              ("C-c C-p" . flycheck-previous-error))
  :custom
  (flycheck-flake8rc '(".flake8" "setup.cfg" "tox.ini" "pyproject.toml")))

AI Stuff

(use-package chatgpt-shell
  :ensure t
  :commands (chatgpt-shell--primary-buffer chatgpt-shell chatgpt-shell-prompt-compose)
  :bind (("C-x m" . chatgpt-shell)
         ("C-c C-e" . chatgpt-shell-prompt-compose)
         (:map chatgpt-shell-mode-map
               (("RET" . newline)
                ("M-RET" . shell-maker-submit)
                ("M-." . dictionary-lookup-definition)))
         (:map eshell-mode-map
               ("C-c C-e" . chatgpt-shell-prompt-compose)))
  :hook ((chatgpt-shell-mode . (lambda () (setq-local completion-at-point-functions nil)))
         (eshell-first-time-mode . chatgpt-shell-add-??-command-to-eshell))
  :init
  (setq shell-maker-root-path (concat user-emacs-directory "var/"))
  (add-to-list 'display-buffer-alist
               '("\\*chatgpt\\*"
                 display-buffer-in-side-window
                 (side . right)
                 (slot . 0)
                 (window-parameters . ((no-delete-other-windows . t)))
                 (dedicated . t)))
  (setq chatgpt-shell-model-version "chatgpt-4o-latest")
  :custom
  (chatgpt-shell-highlight-blocks t)
  (shell-maker-prompt-before-killing-buffer nil)
  (chatgpt-shell-openai-key
   (auth-source-pick-first-password :host "api.openai.com"))
  (chatgpt-shell-transmitted-context-length 5)
  (chatgpt-shell-model-versions '("gpt-4o-2024-08-06")))

Dall-E

(use-package dall-e-shell
  :ensure t
  :defer
  :bind (:map dall-e-shell-mode-map
               (("RET" . newline)
               ("M-RET" . shell-maker-submit)))
  :custom
  (dall-e-shell-openai-key
      (auth-source-pick-first-password :host "api.openai.com"))
  (dall-e-shell-image-size "1024x1024")
  (dall-e-shell-image-output-directory "~/Downloads/dall_e_output/"))

Presentation

(use-package org-present
  :ensure t
  :defer
  :hook ((org-present-mode . gopar/org-present-start)
         (org-present-mode-quit . gopar/org-present-end))
  :config
  (defun gopar/org-present-start ()
    ; Tweak font sizes
    (setq-local face-remapping-alist '((default (:height 1.5) default)
                                       (header-line (:height 4.0) header-line)
                                       (org-document-title (:height 1.75) org-document-title)
                                       (org-code org-verbatim)
                                       (org-verbatim (:height 1.55) org-verbatim)
                                       (org-block (:height 1.25) org-block)
                                       (org-block-begin-line (:height 0.7) org-block)))

    ;; Set a blank header line string to create blank space at the top
    (setq header-line-format " ")

    ;; Display inline images automatically
    (org-display-inline-images)
    (visual-fill-column-mode 1)
    (visual-line-mode 1)
    (read-only-mode))

  (defun gopar/org-present-end ()
    ;; Reset font customizations
    (setq-local face-remapping-alist '((default variable-pitch default)))

    ;; Clear the header line string so that it isn't displayed
    (setq header-line-format nil)

    ;; Stop displaying inline images
    (org-remove-inline-images)
    (visual-fill-column-mode -1)
    (visual-line-mode -1)
    (read-only-mode -1))

  (defun my/org-present-prepare-slide (buffer-name heading)
    ;; Show only top-level headlines
    (org-overview)

    ;; Unfold the current entry
    (org-show-entry)

    ;; Show only direct subheadings of the slide but don't expand them
    (org-show-children))

  (add-hook 'org-present-after-navigate-functions 'my/org-present-prepare-slide))

Visual Fill Column

Only being used with org-present

(use-package visual-fill-column
  :ensure t
  :defer
  :custom
  (visual-fill-column-width 140)
  (visual-fill-column-center-text t))

adds padding around windows and frames

(use-package spacious-padding
  :ensure t
  :defer
  :hook (after-init . spacious-padding-mode)
  )

Better UI for Modeline. Need to install fonts first by doing this

M-x all-the-icons-install-fonts
(use-package doom-modeline
  :ensure t
  :init (doom-modeline-mode 1)
  :config (column-number-mode 1)
  :custom
  (doom-modeline-height 30)
  (doom-modeline-window-width-limit nil)
  (doom-modeline-buffer-file-name-style 'truncate-with-project)
  (doom-modeline-minor-modes nil)
  (doom-modeline-enable-word-count nil)
  (doom-modeline-buffer-encoding nil)
  (doom-modeline-buffer-modification-icon t)
  (doom-modeline-env-python-executable "python")
  ;; needs display-time-mode to be one
  (doom-modeline-time t)
  (doom-modeline-vcs-max-length 50)
  )

Doom Themes

Use Doom Themes since they have built in support for Solaire Mode

(use-package doom-themes
  :ensure t
  :config
  ;; Global settings (defaults)
  (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
        doom-themes-enable-italic t) ; if nil, italics is universally disabled

  ;; Enable flashing mode-line on errors
  (doom-themes-visual-bell-config)
  ;; Enable custom neotree theme (all-the-icons must be installed!)
  (doom-themes-neotree-config)
  ;; Corrects (and improves) org-mode's native fontification.
  (doom-themes-org-config))

Themes

Most of these themes are black/white colorless themes

Leuven

(use-package leuven-theme
  :ensure t
  :custom-face
  (doom-modeline-buffer-file ((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal))))
  (doom-modeline-buffer-path ((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal))))
  (which-func ((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal :foreground "gray29"))))
  (doom-modeline-buffer-major-mode ((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal)))))

My favorite theme

(use-package tao-theme
  :ensure t
  :custom
  (tao-theme-use-boxes t)
  (tao-theme-use-height nil)
  (tao-theme-use-sepia nil)
  :init
  (defvar after-load-theme-hook nil
    "Hook run after a color theme is loaded using `load-theme'.")

  (defadvice load-theme (after run-after-load-theme-hook activate)
    "Run `after-load-theme-hook'."
    (run-hooks 'after-load-theme-hook))

  (defun update-doom-modeline-battery-faces ()
  "Customize battery faces for tao-yin and tao-yang themes."
  (cond
   ((member 'tao-yin custom-enabled-themes)
    ;; Customizations for tao-yin theme
    (custom-set-faces
     '(doom-modeline-battery-warning ((t (:foreground "black" :background "orange"))))
     '(doom-modeline-battery-critical ((t (:foreground "black" :background "red"))))
     ))
   ((member 'tao-yang custom-enabled-themes)
    ;; Customizations for tao-yang theme
    (custom-set-faces
     '(doom-modeline-battery-warning ((t (:foreground "black" :background "orange"))))
     '(doom-modeline-battery-critical ((t (:foreground "black" :background "red"))))
     ))))

  (add-hook 'after-load-theme-hook 'update-doom-modeline-battery-faces))
(use-package tok-theme :ensure t)
(use-package solaire-mode
  :ensure t
  :hook (after-init . solaire-global-mode)
  :custom
  (solaire-mode-themes-to-face-swap '(tao-yin tao-yang)))
(use-package fill-function-arguments
  :ensure t
  :defer
  :bind (:map prog-mode-map
              ("M-q" . fill-function-arguments-dwim)))
(use-package ssh-config-mode
  :ensure t
  :defer)
(use-package hide-mode-line
  :ensure t
  :defer
  :hook (;; (eshell-mode . hide-mode-line-mode)
         ;; (vterm-mode . hide-mode-line-mode)
         (occur-mode . hide-mode-line-mode)
         (treemacs-mode . hide-mode-line-mode)))

Sqlite

Built in sqlite viewer in emacs Additional goodies can be found here: https://xenodium.com/further-sqlite-mode-extensions/

(use-package sqlite-mode
  :ensure nil
  :defer
  :bind (:map sqlite-mode-map
              ("n" . next-line)
              ("p" . previous-line)))

SQL Mode

Shells for db’s

(use-package sql
  :ensure nil
  :defer
  :custom
  (sql-sqlite-options '("-header" "-box")))

Keycast

Display keystors in mode line. Useful for when making videos

(use-package keycast
  :ensure t
  :defer
  :custom
  (keycast-mode-line-format "%k%c%R ")
  (keycast-substitute-alist
   '((keycast-log-erase-buffer nil nil)
     (transient-update         nil nil)
     (self-insert-command "." "Typing…")
     (org-self-insert-command "." "Typing…")
     (mwheel-scroll nil nil)
     (mouse-movement-p nil nil)
     (mouse-event-p nil nil))))

Garbage Collection

(use-package gcmh
:ensure t
:hook (after-init . gcmh-mode)
:custom
(gc-cons-percentage .9))

1st Party Modes

Stuff I’ve made for myself that are modes

Pair Programming

(defvar gopar-pair-programming nil)
(defun gopar/pair-programming ()
  "Poor mans minor mode for setting up things that i like to make pair programming easier."
  (interactive)
  (if gopar-pair-programming
      (progn
        ;; Don't use global line numbers mode since it will turn on in other modes that arent programming
        (dolist (buffer (buffer-list))
          (with-current-buffer buffer
            (when (derived-mode-p 'prog-mode)
              (display-line-numbers-mode -1))))
        (remove-hook 'prog-mode-hook 'display-line-numbers-mode)

        ;; disable all themes change to a friendlier theme
        (mapcar 'disable-theme custom-enabled-themes)
        (setq gopar-pair-programming nil))

    (progn
      ;; display line numbers
      (dolist (buffer (buffer-list))
        (with-current-buffer buffer
          (when (derived-mode-p 'prog-mode)
            (display-line-numbers-mode 1))))
      (add-hook 'prog-mode-hook 'display-line-numbers-mode)

      ;; disable all themes change to a friendlier theme
      (mapcar 'disable-theme custom-enabled-themes)
      (load-theme 'doom-shades-of-purple)
      (neotree)
      (setq gopar-pair-programming t))))

Boolcase

(use-package boolcase
  :load-path "lisp/modes/boolcase"
  :hook ((python-mode python-ts-mode) . boolcase-mode))

YouTube

Functions that are handy for setting up recording in youtube

(defvar gopar/orginal-font-height nil)
(defvar gopar/youtube-font-height 220)
(defun gopar/youtube-setup ()
  (when (null gopar/orginal-font-height)
    (setq gopar/orginal-font-height (face-attribute 'default :height)))

  (set-face-attribute 'default nil :height gopar/youtube-font-height)
  (set-frame-size (selected-frame) 143 40)

  (delete-other-windows)
  (display-time-mode -1)
  (type-break-mode -1)
  (keycast-header-line-mode)
  (let ((dashboard-items '((vocabulary) (bookmarks . 5)))
        (dashboard-banner-logo-title "✨ Memberships are available. Thank you for the support! ✨"))
    (dashboard-open)))

(defun gopar/youtube-setup-emacs-goodies-series ()
  (interactive)
  (consult-theme 'doom-shades-of-purple)
  (gopar/youtube-setup))

(defun gopar/youtube-setup-python-series ()
  (interactive)
  (consult-theme 'doom-nord-aurora)
  (gopar/youtube-setup))

(defun gopar/youtube-setup-refactor-series ()
  (interactive)
  (consult-theme 'haki)
  (gopar/youtube-setup))

(defun gopar/youtube-setup-design-patterns-series ()
  (interactive)
  (consult-theme 'manoj-dark)
  (gopar/youtube-setup))

Private

Things that I want to keep private/out of git

(use-package private
  :load-path "lisp"
  :commands (gopar/random-friend)
  )

End

(progn
  (add-to-list 'default-frame-alist `(font . "Hack 16"))
  (set-face-attribute 'default nil :font "Hack 16"))

;;; Local Variables: *** ;;; eval: (add-hook ‘after-save-hook #’org-babel-tangle nil t) *** ;;; End: ***