Skip to content

Latest commit

 

History

History
1321 lines (1147 loc) · 50.3 KB

gmacs.org

File metadata and controls

1321 lines (1147 loc) · 50.3 KB

About

This is my personal config for Emacs. It is constructed in literate programming using Org-mode for a documented configuration.

If you’re viewing the Org file, you can open source code blocks (those are the ones in begin_src) in a separate buffer by moving your point inside them and typing ` C-c ’ ` (org-edit-special). This opens another buffer in emacs-lisp-mode, so you can use M-x eval-buffer to load the changes. If you want to explore how functions work, use M-x edebug-defun to set up debugging for that function, and then call it.

Packages

I use `use-package` and Straight so that all packages are automatically installed if cloning this repo for another machine.

Theme

My current configuration uses doom-theme, specifically doom-dracula (everywhere!) and some default settings.

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

  ;; Enable flashing mode-line on errors
  (doom-themes-visual-bell-config)

  ;; Corrects (and improves) org-mode's native fontification.
  (doom-themes-org-config)
  (load-theme 'doom-dracula t))

Windows Configuration

Hide things when emacs starts up, namely the tooltips, toolbar and scrollbar. Also set `C-z` and `C-x C-z` to nil. `C-z` minimizes/hides emacs and it’s enfuriating when I accidently hit that key combo.

(use-package emacs
  :init
  (menu-bar-mode -1)
  (tool-bar-mode -1)
  (scroll-bar-mode -1)
  (tooltip-mode -1)
  :config
  (setq inhibit-splash-screen t)
  :bind (("C-z" . nil)
         ("C-x C-z" . nil)))

Font handling

(set-face-attribute 'default nil :font "Monaspace Neon" :weight 'light :height 120)
(set-face-attribute 'fixed-pitch nil :font "Fira Code" :weight 'light :height 120)
(set-face-attribute 'variable-pitch nil :font "Monaspace Neon" :weight 'light :height 1.0)

One liners preferences

Small settings and packages that really don’t have a place anywhere else in this document that warrants it’s own section heading for each one. These are important in how I like my emacs to perform.

(fset 'yes-or-no-p 'y-or-n-p)
(set-frame-font "Monaspace Neon 12")
(setq user-full-name "Greg Newman"
      user-mail-address "[email protected]")
(setq-default indent-tabs-mode nil)
(setq ring-bell-function (lambda ()))
(setq confirm-kill-emacs 'yes-or-no-p)
(setq require-final-newline t)
(setq-default line-spacing 0.15)
(setq explicit-shell-file-name "/bin/zsh")
(setq backup-directory-alist `(("." . "~/.saves")))
(setq backup-by-copying t)
(setq delete-old-versions t)
(setq kept-new-versions 10)
(setq kept-old-versions 10)
(setq version-control t)
(global-display-line-numbers-mode)
(setq-default display-fill-column-indicator-column 80)
;; always show paren highlights
(show-paren-mode 1)
; highlight current line
(global-hl-line-mode 1)
;; javascript indents.  This can probably be removed once I settle on a "good" js config
(setq js-indent-level 2)
; Desktop setup.
(desktop-save-mode 1)
(setq desktop-dirname "~/.emacs.d/desktops/")
(setq desktop-base-file-name (concat ".desktop." (system-name)))
(setq desktop-path (list desktop-dirname))
(setq desktop-base-lock-name "lock")
(setq desktop-load-locked-desktop t)
; Very useful if dealing with git repos and also files that can change from Dropbox
(global-auto-revert-mode 1)
(setq auto-revert-use-notify nil)
(setq auto-revert-interval 5)
;; Configure where TAGS are stored
(setq tags-table-list (list "~/.emacs.d/TAGS"))
;; isearch improvements
(setq isearch-lazy-count t)
(setq lazy-count-prefix-format nil)
(setq lazy-count-suffix-format "   (%s/%s)")

;; some useful settings found in http://yummymelon.com/devnull/surprise-and-emacs-defaults.html
(setq sentence-end-double-space nil)
(setq delete-selection-mode t)
(setq dired-auto-revert-buffer t)

;; associate some of these files with modes
(add-to-list 'auto-mode-alist '("\\.astro\\'" . js-ts-mode))
;; (add-to-list 'auto-mode-alist '("\\.mdx\\'" . markdown-ts-mode))

Transparency

;; set default to 95% opaque
(set-frame-parameter (selected-frame) 'alpha '(95 95))
(add-to-list 'default-frame-alist '(alpha 95 95))

;; convenience function to toggle transparency given a value
(defun gn/transparency (value)
   "Sets the transparency of the frame window. 0=transparent/100=opaque"
   (interactive "nTransparency Value 0 - 100 opaque:")
   (set-frame-parameter (selected-frame) 'alpha value))

(global-set-key (kbd "C-c t") 'gn/transparency)

Markdown

(use-package markdown-mode
  :ensure t
  :config
  (add-to-list 'auto-mode-alist
           '("\\.\\(?:md\\|markdown\\|mkd\\|mdown\\|mkdn\\|mdwn\\)\\'" . markdown-mode))
  )

Icons, Git Gutter and Recent files

;; icons
(use-package all-the-icons)

;; ;; Git Gutter
(use-package git-gutter
  :diminish git-gutter-mode
  :config (global-git-gutter-mode)
  :init
  (progn
    (setq git-gutter:separator-sign " "
          git-gutter:lighter " GG"))
  :config
  (progn 
    (set-face-foreground 'git-gutter:deleted "#990A1B")
    (set-face-foreground 'git-gutter:modified "#00736F")
    (set-face-foreground 'git-gutter:added "#546E00"))
  :bind (("C-x p" . git-gutter:previous-hunk)
         ("C-x n" . git-gutter:next-hunk)
         ("C-x v =" . git-gutter:popup-hunk)
         ("C-x v r" . git-gutter:revert-hunk)))

;; Recent files
(setq recentf-save-file (concat user-emacs-directory "recentf")
      recentf-max-saved-items 200
      recentf-max-menu-items 15)
(recentf-mode t)

Saveplace

Remember my place in files across sessions

(save-place-mode +1)
(setq-default save-place t)

Custom function to move to beginning of line

Copied from http://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/

(defun my/smarter-move-beginning-of-line (arg)
  "Move point back to indentation of beginning of line.

   Move point to the first non-whitespace character on this line.
   If point is already there, move to the beginning of the line.
   Effectively toggle between the first non-whitespace character and
   the beginning of the line.

   If ARG is not nil or 1, move forward ARG - 1 lines first.  If
   point reaches the beginning or end of the buffer, stop there."
  (interactive "^p")
  (setq arg (or arg 1))

  ;; Move lines first
  (when (/= arg 1)
    (let ((line-move-visual nil))
      (forward-line (1- arg))))

  (let ((orig-point (point)))
    (back-to-indentation)
    (when (= orig-point (point))
      (move-beginning-of-line 1))))

  ;; remap C-a to `smarter-move-beginning-of-line'
  (global-set-key [remap move-beginning-of-line]
                  'my/smarter-move-beginning-of-line)

Which-key

I forget bindings for modes I don’t use regularly. Which-key provides nice reminders.

(use-package which-key
  :init
  (which-key-mode)
  :config
  (which-key-setup-side-window-right-bottom)
  (setq which-key-sort-order 'which-key-key-order-alpha
    which-key-side-window-max-width 0.33
    which-key-idle-delay 0.5)
  :diminish which-key-mode)

(provide 'init-which-key)

iBuffer

I use ibuffer a lot for switching between buffers from a list of available open buffers. These settings help to organize that list.

(global-set-key (kbd "C-x C-b") 'ibuffer)
(autoload 'ibuffer "ibuffer" "List buffers." t)

(setq ibuffer-saved-filter-groups
      (quote (("default"
               ("Python"
                (mode . python-ts-mode))
               ("HTML"
                (mode . mhtml-mode))
               ("JS"
                (or (mode . js-ts-mode)
                    (filename . ".js")))
               ("TXT"
                (mode . text-mode))
               ("YAML"
                (filename . "yaml"))
               ("Org" ;; all org-related buffers
                (mode . org-mode))
               ("Lisp"
                (mode . emacs-lisp-mode))))))

;; don't show empty groups
(setq ibuffer-show-empty-filter-groups nil)

(add-hook 'ibuffer-mode-hook
          (lambda ()
            (ibuffer-switch-to-saved-filter-groups "default")))

;; Add full path to buffer title
(setq frame-title-format
      (list (format "%s %%S: %%j " (system-name))
            '(buffer-file-name "%f" (dired-directory dired-directory "%b"))))

Hydra

(use-package hydra)

(defhydra hydra-zoom (global-map "<f2>")
  "zoom"
  ("g" text-scale-increase "in")
  ("l" text-scale-decrease "out"))

System packages

The :ensure-system-package keyword allows you to ensure system binaries exist alongside your package declarations.

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

Justfiles

(use-package just-mode
  :ensure t)

Copilot

(use-package copilot
  :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))
  :ensure t
  :diminish)
(add-hook 'prog-mode-hook 'copilot-mode)
(define-key copilot-completion-map (kbd "<tab>") 'copilot-accept-completion)
(define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion)

Org-mode

Getting Things Done (GTD), is a grouping of productivity processes following five basic principles.

  • Capture - Everything in your mind needs to be captured because your mind is “a horrible office”. This is typically the inbox.org file in my setup but is also done in analog notebooks, email and voice memos.
  • Clarify - Every task that doesn’t take two minutes to do should be broken down into actionable tasks that simplify the larger scope of the project.
  • Organize - All projects and next actions are organized into areas, assigned due dates if needed, prioritized and effort estimates added to them. If the tasks/projects are not something to do right now they are still organized for later consumption. Anything that needs to be on the calendar should be added but keep the calendar sacred. Calendars should only be for appointments or hard-carved blocks of time.
  • Reviews - Reviews should be handled on a regular basis. I do a daily review of what should be the priorities for the day but I also do weekly and monthly reviews to keep my systems from getting stale and/or stuck.
  • Engage - Choose the next action and get to work.

Fontification and Beautification

Use C-u C-x = (which runs the command what-cursor-position with a prefix argument) to show information about the character under the cursor, including the face which is being used for it.

;; Load org-faces to make sure we can set appropriate faces
(require 'org-faces)

;; Hide emphasis markers on formatted text
(setq org-hide-emphasis-markers t)
;; When Visual Line mode is enabled, `word-wrap' is turned on in this buffer, and simple editing commands are redefined to act on visual lines, not logical lines. 
(add-hook 'org-mode-hook 'visual-line-mode)
(add-hook 'org-mode-hook 'variable-pitch-mode)

;; Resize Org headings
(dolist (face '((org-level-1 . 1.1)
                (org-level-2 . 1.0)
                (org-level-3 . 1.0)
                (org-level-4 . 1.0)
                (org-level-5 . 1.0)
                (org-level-6 . 1.0)
                (org-level-7 . 1.0)
                (org-level-8 . 1.0)))
  (set-face-attribute (car face) nil :font "Monaspace Neon" :weight 'medium :height (cdr face)))

;; Make the document title a bit bigger
(set-face-attribute 'org-document-title nil :font "Monaspace Neon" :weight 'bold :height 1.1)

;; Make sure certain org faces use the fixed-pitch face when variable-pitch-mode is on
(custom-theme-set-faces
 'user
 '(variable-pitch ((t (:family "Monaspace Neon" :height 120 :weight thin))))
 '(fixed-pitch ((t ( :family "Fira Code" :height 115))))
 '(org-block ((t (:inherit fixed-pitch))))
 '(org-code ((t (:inherit (shadow fixed-pitch)))))
 '(org-formula ((t (:inherit fixed-pitch))))
 '(org-checkbox ((t (:inherit fixed-pitch))))
 '(org-document-info ((t (:foreground "dark orange"))))
 '(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))))
 '(org-indent ((t (:inherit (org-hide fixed-pitch)))))
 '(org-link ((t (:foreground "cyan" :underline t :weight light))))
 '(org-meta-line ((t (:inherit (font-lock-comment-face fixed-pitch)))))
 '(org-property-value ((t (:inherit fixed-pitch))) t)
 '(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
 '(org-table ((t (:inherit fixed-pitch :foreground "#83a598"))))
 '(org-tag ((t (:inherit (shadow fixed-pitch) :weight bold :height 0.9))))
 '(org-verbatim ((t (:inherit (shadow fixed-pitch))))))

Configuration

This will be a expanding collection of org customization. I live in text files throughout my days and orgmode gives me a nice interface for collecting notes. I use org from the git repo to stay up to date with fixes and new features. I can probably move this to be installed via Straight but for now this works fine.

(setq org-modules '(org-protocol))
(eval-after-load 'org
  '(org-load-modules-maybe t))

;; respects splits
(setq org-agenda-window-setup 'current-window)

;; agenda files
(setq org-agenda-files (directory-files-recursively "~/Dropbox/Org/" "\\.org$"))

;; Start the weekly agenda on Monday
(setq org-agenda-start-on-weekday 1)

;; Display tags farther right
(setq org-agenda-tags-column -102)
(setq org-agenda-span 7)
(setq org-tags-column 150)
(setq org-agenda-sticky nil)
(setq org-agenda-inhibit-startup t)
(setq org-agenda-use-tag-inheritance t)
(setq org-agenda-show-log t)
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-deadline-if-done t)
(setq org-use-speed-commands t)
(setq org-agenda-skip-deadline-prewarning-if-scheduled 'pre-scheduled)
(setq org-columns-default-format "%14SCHEDULED %Effort{:} %CLOCKSUM_T{:} %1PRIORITY %TODO %50ITEM %TAGS")

;; The following lines are always needed.  Choose your own keys.
(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)

;; enable line breaks
(add-hook 'org-mode-hook (lambda () (setq truncate-lines nil)))

;; Don't allow parent to be marked done unless children are done
(setq org-enforce-todo-dependencies t)
(setq org-enforce-todo-checkbox-dependencies t)

(setq org-fontify-done-headline t)
(setq org-startup-folded t)
(setq org-src-fontify-natively nil)

;; Refiling
(setq org-refile-targets '((org-agenda-files :maxlevel . 5)))
(setq org-refile-allow-creating-parent-nodes 'confirm)

;; Visual Line Mode
(add-hook 'org-mode-hook 'visual-line-mode)

;; Org indent mode
(add-hook 'org-mode-hook 'org-indent-mode)

;; Line numbers
(defun gn/orgmode-ignore-line-numbers-mode ()
  (interactive)
  "turns off line numbers mode in org buffers"
  (display-line-numbers-mode -1))

(add-hook 'org-mode-hook #'gn/orgmode-ignore-line-numbers-mode)

(defun gn/orgmode-ignore-whitespace-mode ()
  (interactive)
  "turns off whitespace mode in org buffers"
  (whitespace-mode -1))

;; Turn off whitespace-mode since my linters will handle them anyway and it's annoying
(whitespace-mode -1)

Alerts

(use-package org-alert
  :straight t 
  :ensure t 
  :config 
      (setq org-alert-interval 60 
            org-alert-notify-cutoff 5
            org-alert-notify-after-event-cutoff 2) 
      (org-alert-enable))

(use-package alert 
  :straight t 
  :config
  (setq alert-default-style 'osx-notifier
        alert-fade-time 120))

Todo Keywords

Setting up my todo keywords which are global and their relative colors.

;; Keywords
(setq org-todo-keywords
  (quote ((sequence "PROJECT(p)" "TODO(t)" "NEXT(n)" "|" "DONE(d)")
          (sequence "WAITING(w@/!)" "SOMEDAY(s@/!)" "|" "CANCELLED(c@/!)"))))

;; Anytime a task is marked done the line states `CLOSED: [timestamp]
(setq org-log-done 'time)

(setq org-todo-keyword-faces
  (quote (("PROJECT" :foreground "orange" :weight bold)
          ("TODO" :foreground "lime green" :weight bold)
          ("NEXT" :foreground "cyan" :weight bold)
          ("DONE" :foreground "dim gray" :weight bold)
          ("WAITING" :foreground "tomato" :weight bold)
          ("SOMEDAY" :foreground "magenta" :weight bold)
          ("CANCELLED" :foreground "dim gray" :weight bold))))

Capture mode keybinding

I use C-c c to start capture mode

(global-set-key (kbd "C-c c") 'org-capture)

Capture templates

Capture template are critical for keeping focused on the current work and not getting sent down the proverbial rabbit hole. It’s also handy for knowledge investements while working. For instance, a method in a python library I need to understand more deeply, I can trigger the capture template for Knowledge Investments with `C=c c k`, add some context and with `C=c C=c` close and save the capture without leaving my position in the file. The link to where I found the method is captured in the template and I can visit that later in the day when I have time to dive deep.

For my reference the syntax is as follows

("t" "Todo" entry (file "~/Dropbox/Org/inbox.org")
             "* TODO %?\n%U\n%a\n" :clock-keep t)

`t` is the trigger key for Todo. Todo entry is layman’s term for the capture followed by what file to store it in. The instruction regex starts with the tag or keyword then template expansions.

  • %? Position the cursor where I was
  • %u, %U Inactive timestamp
  • %a annotation, normally the link created with org-store-link
  • :clock-keep keeps the clock running if I’m clocking a task
;; Capture templates
(setq org-indent-indentation-per-level 2)
(setq org-capture-templates
    (quote (("t" "Todo" entry (file "~/Dropbox/Org/inbox.org")
            "* TODO %?\n%U\n%a\n" :clock-keep t)
            ("k" "Knowledge Investment" entry (file "~/Dropbox/Org/inbox.org")
             "* %? :KI:\n%U\n%a\n" :clock-keep t)
            ("n" "Note" entry (file "~/Dropbox/Org/inbox.org")
             "* %? :NOTE:\n%U\n%a\n" :clock-keep t)
            ("d" "Daybook" entry (file+olp+datetree "~/Dropbox/Org/daybook.org")
             "* %?" :clock-keep t)
            ("o" "OBTF" entry (file+olp+datetree "~/Dropbox/Org/OBTF.org")
             "* %<%H:%M> %?" :jump-to-captured t)
            ("m" "Meeting" entry (file "~/Dropbox/Org/inbox.org")
             "* Meeting with %? :MEETING:\n%U" :clock-keep t)
            ("p" "Phone call" entry (file "~/Dropbox/Org/inbox.org")
             "* PHONE %? :PHONE:\n%U" :clock-keep t))))

Org Babel

(org-babel-do-load-languages
 'org-babel-load-languages
 '(
   (python . t)
   (emacs-lisp . t)
   (org . t)
   (sql . t)
   (ditaa . t)
   ))
;; Syntax highlight in #+BEGIN_SRC blocks
(setq org-src-fontify-natively t)
;; Don't prompt before running code in org
(setq org-confirm-babel-evaluate nil)

Agenda commands

Pulled some ideas from https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html Some of these have been yanked from bnb-emacs

(defun gn/org-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 gn/org-agenda-with-tip (arg)
  (org-agenda-list arg)
  (let ((inhibit-read-only t)
     (pos (point)))
  (goto-char (point-max))
  (goto-char pos)))

;; Reset everything to nil
(setq org-agenda-custom-commands nil)

(add-to-list 'org-agenda-custom-commands
          '("b" "Agenda" gn/org-agenda-with-tip))

(add-to-list 'org-agenda-custom-commands
     '("N" "Notes" tags "NOTE"
            ((org-agenda-overriding-header "Notes")
             (org-tags-match-list-sublevels t))))

(add-to-list 'org-agenda-custom-commands
   '("k" "Knowledge Investments" tags "KI"
          ((org-agenda-overriding-header "Knowledge Investments")
           (org-tags-match-list-sublevels t))))

;; Taken from doc.norang.ca/org-mode.html
(add-to-list 'org-agenda-custom-commands
     '("c" "Simple agenda view"
          ((agenda "")
          (tags "PRIORITY=\"A\""
            ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
             (org-agenda-overriding-header "HIGH PRIORITY ITEMS")))
          (alltodo ""
            ((org-agenda-skip-function
             '(or (gn/org-skip-subtree-if-priority ?A)
              (org-agenda-skip-if nil '(scheduled deadline)))))))))

(add-to-list 'org-agenda-custom-commands
          '("f" . "FOCUS...") t)

(add-to-list 'org-agenda-custom-commands
          '("d" "All Tasks (grouped by Due Date)"
            ((tags-todo "DEADLINE<\"<+0d>\""
                        ((org-agenda-overriding-header "OVERDUE")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'notdeadline))))
             (tags-todo "DEADLINE=\"<+0d>\""
                        ((org-agenda-overriding-header "DUE TODAY")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'notdeadline))))
             (tags-todo "DEADLINE=\"<+1d>\""
                        ((org-agenda-overriding-header "DUE TOMORROW")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'notdeadline))))
             (tags-todo "DEADLINE>\"<+1d>\"+DEADLINE<=\"<+7d>\""
                        ((org-agenda-overriding-header "DUE WITHIN A WEEK")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'notdeadline))))
             (tags-todo "DEADLINE>\"<+7d>\"+DEADLINE<=\"<+28d>\""
                        ((org-agenda-overriding-header "DUE WITHIN A MONTH")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'notdeadline))))
             (tags-todo "DEADLINE>\"<+28d>\""
                        ((org-agenda-overriding-header "DUE LATER")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'notdeadline))))
             (tags-todo "TODO={WAIT}"
                        ((org-agenda-overriding-header "WAITING FOR")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'deadline))))
             (todo ""
                   ((org-agenda-overriding-header "UNSCHEDULED")
                    (org-agenda-skip-function
                     '(org-agenda-skip-entry-if 'deadline)))))
            ((org-agenda-sorting-strategy '(priority-down))
             (org-agenda-write-buffer-name "All Tasks (grouped by Due Date)"))
            "~/Dropbox/Org/all-tasks-by-due-date.pdf") t)

(add-to-list 'org-agenda-custom-commands
          `("f." "Today"
            ((agenda ""
                     ((org-agenda-entry-types '(:timestamp :sexp))
                      (org-agenda-overriding-header
                       (concat "CALENDAR Today: "
                               (format-time-string "%a %d" (current-time))))
                      (org-agenda-span 'day)))
             (tags-todo "LEVEL=1+REFILE"
                        ((org-agenda-overriding-header "COLLECTBOX (Unscheduled)")))
             (tags-todo "DEADLINE=\"<+0d>\""
                        ((org-agenda-overriding-header "DUE TODAY")
                         (org-agenda-skip-function
                          '(org-agenda-skip-entry-if 'notedeadline))
                         (org-agenda-sorting-strategy '(priority-down))))
             (tags-todo "DEADLINE<\"<+0d>\""
                        ((org-agenda-overriding-header "OVERDUE")
                         (org-qagenda-skip-function
                          '(org-agenda-skip-entry-if 'notedeadline))
                         (org-agenda-sorting-strategy '(priority-down))))
             (agenda ""
                     ((org-agenda-entry-types '(:scheduled))
                      (org-agenda-overriding-header "SCHEDULED")
                      (org-agenda-skip-function
                       '(org-agenda-skip-entry-if 'todo 'done))
                      (org-agenda-sorting-strategy
                       '(priority-down time-down))
                      (org-agenda-span 'day)
                      (org-agenda-start-on-weekday nil)
                      (org-agenda-time-grid nil)))
             (todo "DONE"
                   ((org-agenda-overriding-header "COMPLETED"))))
            ((org-agenda-format-date "")
             (org-agenda-start-with-clockreport-mode nil))) t)

(add-to-list 'org-agenda-custom-commands
          '("fh" "Hotlist"
            ((tags-todo "DEADLINE<\"<+0d>\""
                        ((org-agenda-overriding-header "OVERDUE")))
             (tags-todo "DEADLINE>=\"<+0d>\"+DEADLINE<=\"<+1w>\""
                        ((org-agenda-overriding-header "DUE IN NEXT 7 DAYS")))
             (tags-todo "DEADLINE=\"\"+FLAGGED|DEADLINE>\"<+1w>\"+FLAGGED"
                        ((org-agenda-overriding-header "FLAGGED"))))
            ((org-agenda-todo-ignore-scheduled 'future)))  t)

(add-to-list 'org-agenda-custom-commands
          '("r" . "REVIEW...") t)

(add-to-list 'org-agenda-custom-commands
          '("ra" . "All Tasks...") t)

(add-to-list 'org-agenda-custom-commands
          '("rt" . "Timesheet...") t)

;; Show what happened today.
(add-to-list 'org-agenda-custom-commands
          '("rtd" "Daily Timesheet"
            ((agenda ""))
            ((org-agenda-log-mode-items '(clock closed))
             (org-agenda-overriding-header "DAILY TIMESHEET")
             (org-agenda-show-log 'clockcheck)
             (org-agenda-span 'day)
             (org-agenda-start-with-clockreport-mode t)
             (org-agenda-time-grid nil))) t)

;; Show what happened this week.
(add-to-list 'org-agenda-custom-commands
          '("rtw" "Weekly Timesheet"
            ((agenda ""))
            (
             ;; (org-agenda-format-date "")
             (org-agenda-overriding-header "WEEKLY TIMESHEET")
             (org-agenda-skip-function '(org-agenda-skip-entry-if 'timestamp))
             (org-agenda-span 'week)
             (org-agenda-start-on-weekday 1)
             (org-agenda-start-with-clockreport-mode t)
             (org-agenda-time-grid nil))) t)

(add-to-list 'org-agenda-custom-commands
          '("rw" "Weekly review"
            ((tags "CATEGORY={@REFILE}&LEVEL<=2"
                   ((org-agenda-overriding-header "NEW TASKS")))
             (agenda ""
                     ((org-agenda-clockreport-mode t)
                      (org-agenda-format-date
                       (concat "\n"
                               "%Y-%m-%d" " %a "
                               (make-string (window-width) ?_)))
                      (org-agenda-overriding-header "PAST WEEK")
                      (org-agenda-prefix-format " %?-11t %i %-12:c% s")
                      (org-agenda-show-log 'clockcheck)
                      (org-agenda-span 7)
                      (org-agenda-start-day "-1w")
                      (org-deadline-warning-days 0)))
             (agenda ""
                     ((org-agenda-overriding-header "NEXT MONTH")
                      (org-agenda-span 'month)
                      (org-agenda-start-day "+0d")
                      (org-deadline-warning-days 0)))
             (todo "PROJECT"
                   ((org-agenda-overriding-header "PROJECT LIST")))
             (todo "DONE|PROJECTDONE"
                   ((org-agenda-overriding-header
                     "Candidates to be archived"))))))

Org-Super-Agenda commands

(use-package org-super-agenda
  :straight
  (org-super-agenda
   :type git
   :host github
   :repo "alphapapa/org-super-agenda")
  :config
  (org-super-agenda-mode t)
  (add-to-list 'org-agenda-custom-commands
               '("gt" "All Tasks - Grouped"
                 ((todo "" ((org-super-agenda-groups
                             '((:name "All Tasks" :auto-category t)))))))))

Org bullets and misc settings’

Using org buillets and hiding leading stars. I’m also fontifying headings, quotes and done headlines.

(use-package org-bullets
  :commands org-bullets-mode
  :init
  (add-hook 'org-mode-hook 'org-bullets-mode))
  (progn
   (require 'org-indent)
   (org-indent-mode t))
(setq org-hide-leading-stars t)
(setq org-fontify-whole-heading-line t)
(setq org-fontify-quote-and-verse-blocks t)
(setq org-fontify-done-headline t)

(use-package org-download)
(setq-default org-download-image-dir "~/Dropbox/Org/img")

(use-package org-fancy-priorities
  :ensure t
  :hook
  (org-mode . org-fancy-priorities-mode)
  :config
  (setq org-fancy-priorities-list '("🅰️" "🅱️" "1️⃣" "")))

Org-Roam

(use-package org-roam ;; :straight t (org-roam :type git :host github :repo “org-roam/org-roam”) :straight t :init (setq org-roam-directory (file-truename “~/Dropbox/Org/”)) (setq org-roam-file-extensions ‘(“org” “md”)) (setq org-roam-dailies-directory “dailies”) (setq find-file-visit-truename t) (setq org-roam-mode-sections (list #’org-roam-backlinks-section #’org-roam-reflinks-section #’org-roam-unlinked-references-section )) :custom (org-roam-dailies-capture-templates ‘((“d” “default” entry “* %<%I:%M %p>: %?” :if-new (file+head “%<%Y-%m-%d>.org” “#+title: %<%Y-%m-%d>\n”)))) ;;(org-roam-database-connector ‘sqlite-builtin)

:bind ((“C-c n l” . org-roam-buffer-toggle) (“C-c n t” . org-roam-dailies-goto-today) (“C-c n f” . org-roam-node-find) (“C-c n i” . org-roam-node-insert)) :config (org-roam-setup) )

;; Documenation: https://github.com/nobiot/md-roam (use-package md-roam :straight (:host github :repo “nobiot/md-roam”) :after org-roam ) (md-roam-mode 1) (setq md-roam-file-extension “md”)

(org-roam-db-autosync-mode)

Denote

Denote for taking notes and consult-notes for quickly searching

(use-package denote
  :custom
  ((denote-directory "~/Dropbox/Org/denote/")
   (denote-prompts '(title keywords))
   ;; Use orgmode format by default
   (denote-file-type 'org)
   (denote-date-prompt-use-org-read-date t))
  :hook
  (dired-mode . denote-dired-mode))

(use-package consult-notes
  :commands (consult-notes
             consult-notes-search-in-all-notes
             ;; if using org-roam 
             consult-notes-org-roam-find-node
             consult-notes-org-roam-find-node-relation)
  :config
  (setq consult-notes-file-dir-sources '(("Org"  ?o  "~/Dropbox/Org/")
                                         ("Denote" ?d "~/Dropbox/Org/denote/")))

  (consult-notes-org-headings-mode)
  (consult-notes-denote-mode)
  ;; search only for text files in denote dir
  (setq consult-notes-denote-files-function (function denote-directory-text-only-files)))

Path from shell

When starting emacs gui on Mac OS, the paths are not read from .zshrc Using `exec-path-from-shell` fixes this.

(use-package exec-path-from-shell
  :config
  (when (memq window-system '(mac ns x))
  (exec-path-from-shell-initialize)))

Pyenv

(use-package pyenv-mode-auto)

(defun pyenv-activate-current-project ()
  "Automatically activates pyenv version if .python-version file exists."
  (interactive)
  (let ((python-version-directory (locate-dominating-file (buffer-file-name) ".python-version")))
  (if python-version-directory
     (let* ((pyenv-version-path (f-expand ".python-version" python-version-directory))
            (pyenv-current-version (s-trim (f-read-text pyenv-version-path 'utf-8))))
       (pyenv-mode-set pyenv-current-version)
       (message (concat "Setting virtualenv to " pyenv-current-version))))))

(defvar pyenv-current-version nil nil)

(defun pyenv-init()
"Initialize pyenv's current version to the global one."
(let ((global-pyenv (replace-regexp-in-string "\n" "" (shell-command-to-string "pyenv global"))))
 (message (concat "Setting pyenv version to " global-pyenv))
 (pyenv-mode-set global-pyenv)
 (setq pyenv-current-version global-pyenv)))

(add-hook 'after-init-hook 'pyenv-init)

(use-package pyenv-mode)

;; Fixes an issue where pyenv conflicts with org-mode
(eval-after-load 'pyenv-mode
  '(progn
   (define-key pyenv-mode-map (kbd "C-c C-s") nil)))

(add-hook 'python-ts-mode-hook #'display-fill-column-indicator-mode)

Eglot, Eldoc and Tree-sitter

Automatically install and use tree-sitter major modes in Emacs 29+. If the tree-sitter version can’t be used, fall back to the original major mode.

(setq major-mode-remap-alist
      '((yaml-mode . yaml-ts-mode)
        (bash-mode . bash-ts-mode)
        (js-mode . js-ts-mode)
        (js2-mode . js-ts-mode)
        (js-base-mode . js-ts-mode)
        (typescript-mode . typescript-ts-mode)
        (json-mode . json-ts-mode)
        (css-mode . css-ts-mode)
        (python-mode . python-ts-mode)))

;; Eglot
(use-package eglot
  :hook ((python-ts-mode . eglot-ensure)
         (js-ts-mode . eglot-ensure)
         (typescript-ts-mode . eglot-ensure)
         (python-ts-mode . superword-mode)
         (python-ts-mode . hs-minor-mode)
         (python-ts-mode . (lambda () (set-fill-column 80))))
  :bind (:map eglot-mode-map
              ("C-c l a" . eglot-code-actions)
              ("C-c l qr" . eglot-rename)
              ("C-c l f" . eglot-format)
              ("C-c l d" . eldoc)))

;; Tree-sitter
  (use-package treesit-auto
    :straight (:host github :repo "renzmann/treesit-auto")
    :config
    (setq treesit-auto-install 'prompt)
    (treesit-auto-add-to-auto-mode-alist 'all)
    (global-treesit-auto-mode)
    (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode))

;; Eldoc 
(use-package eldoc
  :init
  (global-eldoc-mode))

Vertico, Marginalia, Savehist, Orderless, Embark, Embark Consult

;; Enable vertico
(use-package vertico
   :custom
   (vertico-count 13)                    ; Number of candidates to display
   (vertico-resize t)
   (vertico-cycle nil) ; Go from last to first candidate and first to last (cycle)?
   :init
   (vertico-mode))

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

 ;; Optionally use the `orderless' completion style.
 (use-package orderless
   :init
   ;; Configure a custom style dispatcher (see the Consult wiki)
   ;; (setq orderless-style-dispatchers '(+orderless-dispatch)
   ;;       orderless-component-separator #'orderless-escapable-split-on-space)
   (setq completion-styles '(orderless basic)
         completion-category-defaults nil
         completion-category-overrides '((file (styles partial-completion)))))

 ;; Enable rich annotations using the Marginalia package
 (use-package marginalia
   ;; Either bind `marginalia-cycle' globally or only in the minibuffer
   :bind (("M-A" . marginalia-cycle)
          :map minibuffer-local-map
          ("M-A" . marginalia-cycle))

   :custom
   (marginalia-max-relative-age 0)
   (marginalia-align 'right)

   :init
   (marginalia-mode))

 ;; borrowed from Jeremy https://github.com/jeremyf/dotemacs/blob/4bdb58ea43e5dfcdd2025d54193598be0a9dd5b9/emacs.d/jf-completing.el#L219-L227
 (require 'consult-imenu)
 (dolist (python '(python-mode python-ts-mode))
   (add-to-list 'consult-imenu-config
                `(,python
                  :toplevel "Method"
                  :types ((?f "Field" font-lock-variable-name-face)
                          (?c "Class" font-lock-property-use-face)
                          (?m "Method" font-lock-function-name-face)
                          (?M "Module" font-lock-builtin-face)
                          (?v "Variable" font-lock-variable-name-face)
                         ))))

(use-package consult-projectile
  :straight (consult-projectile :type git :host gitlab :repo "OlMon/consult-projectile" :branch "master")
  :commands (consult-projectile)
  :bind (("C-x 4 p" . consult-projectile-find-file-other-window)))
         ;;("M-s r" . consult-ripgrep)
         ;;("M-s f" . projectile-ripgrep)))

(use-package consult-dir
  ;; This package helps ease traveling across directories by providing directory
  ;; candidates related to current buffers, bookmarks, and projects.  Further,
  ;; like other ~consult.el~ functions, you can use narrowing keys.  See
  ;; https://github.com/karthink/consult-dir.
  :straight t
  :after (consult)
  :bind (("C-x C-d" . consult-dir)
         :map minibuffer-local-completion-map
         ("C-x C-d" . consult-dir)
         ("C-x C-j" . consult-dir-jump-file)))

 ;; Embark - this config is taken directly from https://github.com/oantolin/embark
 (use-package embark
   :ensure t

   :bind
   (("C-." . embark-act)         ;; pick some comfortable binding
    ("C-;" . embark-dwim)        ;; good alternative: M-.
    ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'

   :init

   ;; Optionally replace the key help with a completing-read interface
   (setq prefix-help-command #'embark-prefix-help-command)

   ;; Show the Embark target at point via Eldoc. You may adjust the
   ;; Eldoc strategy, if you want to see the documentation from
   ;; multiple providers. Beware that using this can be a little
   ;; jarring since the message shown in the minibuffer can be more
   ;; than one line, causing the modeline to move up and down:

   ;; (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
   ;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)

   :config

   ;; Hide the mode line of the Embark live/completions buffers
   (add-to-list 'display-buffer-alist
                '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                  nil
                  (window-parameters (mode-line-format . none)))))

;; Consult users will also want the embark-consult package.
(use-package embark-consult
  :ensure t ; only need to install it, embark loads it after consult if found
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))

 (use-package all-the-icons-completion
   :after (marginalia all-the-icons)
   :hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
   :init
   (all-the-icons-completion-mode))

Cape and Corfu

  (use-package cape
    ;; Completion at point functions, with the amazing `cape-capf-super' for
    ;; granular configuration of specific mode completion behavior.
    :straight t
    :init
    (add-to-list 'completion-at-point-functions #'cape-dabbrev)
    (add-to-list 'completion-at-point-functions #'cape-file)
    (add-to-list 'completion-at-point-functions #'cape-keyword)
    :bind (("C-c h d" . cape-dabbrev)
           ("C-c h e" . cape-elisp-block)
           ("C-c h f" . cape-file)
           ("C-c h h" . cape-history)
           ;; ("C-c h s" . cape-symbol)
           ("C-c h w" . cape-dict)))

  (use-package corfu
    ;; Optional customizations
    ;; :custom
    ;; (corfu-cycle t)                ;; Enable cycling for `corfu-next/previous'
    ;; (corfu-auto t)                 ;; Enable auto completion
    ;; (corfu-separator ?\s)          ;; Orderless field separator
    ;; (corfu-quit-at-boundary nil)   ;; Never quit at completion boundary
    ;; (corfu-quit-no-match nil)      ;; Never quit, even if there is no match
    ;; (corfu-preview-current nil)    ;; Disable current candidate preview
    ;; (corfu-preselect 'prompt)      ;; Preselect the prompt
    ;; (corfu-on-exact-match nil)     ;; Configure handling of exact matches
    ;; (corfu-scroll-margin 5)        ;; Use scroll margin

    ;; Enable Corfu only for certain modes.
    ;; :hook ((prog-mode . corfu-mode)
    ;;        (shell-mode . corfu-mode)
    ;;        (eshell-mode . corfu-mode))

    ;; Recommended: Enable Corfu globally.  This is recommended since Dabbrev can
    ;; be used globally (M-/).  See also the customization variable
    ;; `global-corfu-modes' to exclude certain modes.
    :init
    (global-corfu-mode))

;; A few more useful configurations...
(use-package emacs
  :init
  ;; TAB cycle if there are only few candidates
  ;; (setq completion-cycle-threshold 3)

  ;; Enable indentation+completion using the TAB key.
  ;; `completion-at-point' is often bound to M-TAB.
  (setq tab-always-indent 'complete)

  ;; Emacs 30 and newer: Disable Ispell completion function. As an alternative,
  ;; try `cape-dict'.
  (setq text-mode-ispell-word-completion nil)

  ;; Emacs 28 and newer: Hide commands in M-x which do not apply to the current
  ;; mode.  Corfu commands are hidden, since they are not used via M-x. This
  ;; setting is useful beyond Corfu.
  (setq read-extended-command-predicate #'command-completion-default-include-p))

Projectile and RG (Ripgrep)

It looks like rg.el has more options for regex when searching

(use-package projectile
  :bind-keymap
  ("C-c p" . projectile-command-map))

(use-package rg
  :ensure-system-package rg)

Company

(use-package company
  :config
  (setq company-minimum-prefix-length 1
        company-idle-delay 0
        company-tooltip-limit 10
        company-transformers nil
        company-show-numbers t)
  (global-company-mode +1))

; (use-package company-lsp
;  :after company
;  :config
;  (setq company-lsp-enable-snippet nil)
;  :init (add-to-list 'company-backends 'company-capf))

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

Magit

(use-package magit
  :bind ("C-x g" . magit-status))

(use-package magit-todos
  :after magit
  :after hl-todo
  :config
  (setq magit-todos-depth 2)
  (setq magit-todos-exclude-globs '("*.js.map"))
  (magit-todos-mode))

(use-package hl-todo
  :config
  ;; Adding a new keyword: TEST.
  (add-to-list 'hl-todo-keyword-faces '("TODO" . "gold"))
  (add-to-list 'hl-todo-keyword-faces '("Fixme" . "orange"))
  :init
  (add-hook 'python-ts-mode-hook (lambda () (hl-todo-mode t)))
  )

Docker

Repo and documentation https://github.com/Silex/docker.el

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

Winner Mode

(use-package winner
  :ensure t
  :commands (winner-undo winner-redo)
  :custom
  (winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")))
(winner-mode 1)

Avy

Avy makes searching and selecting so much easier. `M-s` is my keybinding, type a string and choose the selection in buffer.

(use-package avy
  :ensure t
  :config
  (avy-setup-default)
  :bind ("M-s" . avy-goto-char-timer))

Rainbow Mode

(use-package rainbow-mode
  :hook (emacs-lisp-mode web-mode python-ts-mode))

Yasnippet

(use-package yasnippet)
(use-package yasnippet-snippets)
(yas-global-mode 1)

Indent bars

Trying out some nicer looking indent bars from jdtsmith/indent-bars

(use-package indent-bars
  :straight (indent-bars :type git :host github :repo "jdtsmith/indent-bars")
  :custom
  (indent-bars-treesit-support t)
  (indent-bars-no-descend-string t)
   (indent-bars-treesit-ignore-blank-lines-types '("module"))
   (indent-bars-treesit-wrap '((python argument_list parameters ; for python, as an example
       			              list list_comprehension
       			              dictionary dictionary_comprehension
       			              parenthesized_expression subscript)))
  :config
  (setq
   indent-bars-color '(highlight :face-bg t :blend 0.2)
   indent-bars-prefer-character 1
   indent-bars-pattern ".*.*.*.*"
   indent-bars-width-frac 0.5
   indent-bars-pad-frac 0.2
   indent-bars-zigzag 0.1
   indent-bars-color-by-depth '(:palette ("red" "green" "orange" "cyan") :blend 1)
   indent-bars-highlight-current-depth '(:blend 0.5))
  :hook
  ((python-base-mode yaml-mode js-base-mode web-mode) . indent-bars-mode))

Mac Link

;; Org-mac-link is being pulled from Jeremy's fork. I was getting errors with the main repo.
(use-package org-mac-link
  ;; Similar to `grab-mac-link' but a bit specific to `org-mode'.
  :straight (org-mac-link :type git :host github :repo "jeremyf/org-mac-link")
  :bind (:map org-mode-map (("C-c g" . org-mac-grab-link))))

Golden Ratio

(use-package golden-ratio
  :ensure t
  :diminish golden-ratio-mode
  :init
  (golden-ratio-mode 0))

Logos (writing) and Olivetti

(use-package logos
  :ensure t
  :config
  (setq logos-outlines-are-pages t)
  )

(use-package olivetti
  :ensure t)

Nov Mode for epub

(use-package nov
  :ensure t
  :config
  (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)))

Casual Stuff

;; Casual Avy
;; https://github.com/kickingvegas/casual-avy
(use-package casual-avy
  :straight
  (casual-avy
   :type git
   :host github
   :repo "kickingvegas/casual-avy")
  :bind ("M-g" . casual-avy-tmenu))

;; Casual Dired
;; https://github.com/kickingvegas/casual-dired
(use-package casual-dired
  :straight
  (casual-dired
   :type git
   :host github
   :repo "kickingvegas/casual-dired")
  :bind (:map dired-mode-map ("C-o" . 'casual-dired-tmenu)))

Emojis

(use-package emojify
  :hook (after-init . global-emojify-mode))