Skip to content

Latest commit

 

History

History
2014 lines (1654 loc) · 63.9 KB

emacs.org

File metadata and controls

2014 lines (1654 loc) · 63.9 KB

Emacs Conf

;; supress debugger by default
;; (setq debug-on-error t)
(setq user-full-name "Richard Hunter"
      user-mail-address "")

Quick Links

Out of Band Deps

  • plantuml (jar file)
  • nerd fonts (monospace for terminal)
  • git
  • nodejs
  • typescript toolchain
  • copilot lang server
  • rust toolchain
  • python toolchain
  • go toolchain
  /Users/<user>/.nvm/versions/node/v20.np15.0/lib
├── @devcontainers/[email protected]
├── @techdocs/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

Early Init

See early-init.org

Startup Config

Basic Internals

  • set default window sizes for GUI emacs
; (setq package-enable-at-startup nil)
(setq frame-inhibit-implied-resize t)

;; (if (fboundp 'fringe-mode) (set-fringe-mode 0))
(if (display-graphic-p)
    (progn
      (setq initial-frame-alist
            '(
              (tool-bar-lines . 0)
              (width . 180) ; chars
              (height . 80) ; lines
              (left . 0)
              (vertical-scroll-bars . nil)
              (horizontal-scroll-bars . nil)
              (top . 20)))
      (setq default-frame-alist
            '(
              (width . 180)
              (height . 80)
              (left . 0)
              (top . 20)
              (vertical-scroll-bars . nil)
              (horizontal-scroll-bars . nil)
              (tool-bar-lines . 0))))
  (progn
    (setq initial-frame-alist '( (tool-bar-lines . 0)))
    (setq default-frame-alist '( (tool-bar-lines . 0)))))

Macros

;; Taken from Prot
(defmacro rh-emacs-keybind (keymap &rest definitions)
  "Expand key binding DEFINITIONS for the given KEYMAP.
DEFINITIONS is a sequence of string and command pairs."
  (declare (indent 1))
  (unless (zerop (% (length definitions) 2))
    (error "Uneven number of key+command pairs"))
  (let ((keys (seq-filter #'stringp definitions))
        ;; We do accept nil as a definition: it unsets the given key.
        (commands (seq-remove #'stringp definitions)))
    `(when-let (((keymapp ,keymap))
                (map ,keymap))
       ,@(mapcar
          (lambda (pair)
            (unless (and (null (car pair))
                         (null (cdr pair)))
              `(define-key map (kbd ,(car pair)) ,(cdr pair))))
          (cl-mapcar #'cons keys commands)))))

;; Sample of `rh-emacs-keybind'

;; (rh-emacs-keybind global-map
;;   "C-z" nil
;;   "C-x b" #'switch-to-buffer
;;   "C-x C-c" nil
;;   "C-x k" #'kill-buffer)

Repeat mode

;;; Repeatable key chords (repeat-mode)
(setq repeat-on-final-keystroke t
      repeat-exit-timeout 3
      repeat-exit-key "<escape>"
      repeat-keep-prefix nil
      repeat-check-key t
      repeat-echo-function 'ignore
      ;; Technically, this is not in repeal.el, though it is the
      ;; same idea.
      set-mark-command-repeat-pop t)
(repeat-mode 1)

GUI Emacs add env path for gui

Set PATH for GUI emacs

(setq exec-path (append exec-path '("/usr/local/bin")))
(setq exec-path (append exec-path '("/opt/homebrew/bin")))
(setq exec-path (append exec-path '("/opt/homebrew/lib")))
(setq exec-path (append exec-path '("/opt/homebrew/lib/gcc/14")))
(setq exec-path (append exec-path '("/opt/homebrew/sbin")))
(setq exec-path (append exec-path '("/Users/hunterri/go/bin")))
(setq exec-path (append exec-path '("/Users/hunterri/.cargo/bin")))
(setq exec-path (append exec-path '("/Users/hunterri/.nvm/versions/node/v20.15.0/bin")))
(setq exec-path (append exec-path '("/Users/hunterri/.pyenv/shims")))

(setenv "PATH" (concat (getenv "PATH") ":/usr/local/bin"))
(setenv "PATH" (concat (getenv "PATH") ":/opt/homebrew/bin"))
(setenv "PATH" (concat (getenv "PATH") ":/opt/homebrew/lib"))
(setenv "PATH" (concat (getenv "PATH") ":/opt/homebrew/lib/gcc/14"))
(setenv "PATH" (concat (getenv "PATH") ":/opt/homebrew/sbin"))
(setenv "PATH" (concat (getenv "PATH") ":/Users/hunterri/go/bin"))
(setenv "PATH" (concat (getenv "PATH") ":/Users/hunterri/.cargo/bin"))
(setenv "PATH" (concat (getenv "PATH") ":/Users/hunterri/.pyenv/shims"))
(setenv "PATH" (concat (getenv "PATH") ":/Users/hunterri/.nvm/versions/node/v20.15.0/bin"))

Require some internal libs

(require 'paren)

Activate some internal features

  • auto-compression:: automatically handle decompressing/compressing of zipped files
  • column-number-mode:: display column number in the mode line
  • global-auto-revert-mode:: automatically update buffers when they are changed on disk
  • global-font-lock-mode:: syntax highlighting
  • global-hl-line-mode:: enables highlighting
  • display-line-number-mode:: display line numbers by default. See section on Line Numbers for a list of modes where this is disabled
  • show-paren-mode:: highlight matching parens/brackets etc
  • transient-mark-mode:: highlighting regions
  • which-function-mode:: display current function name in the mode line (TODO: disabled for causing errors)
(auto-compression-mode 1)
(column-number-mode 1)
(setq auto-revert-verbose t)
(global-auto-revert-mode 1)
(global-font-lock-mode 1)
(global-hl-line-mode 1)
;; Lately I've come to dislike line numbers unless pair programming, so leave off
;; (global-display-line-numbers-mode 1)
(setq display-line-numbers-type 'relative)
(show-paren-mode 1)
(transient-mark-mode 1)
;; (which-function-mode 1)
;;;; Delete selection
(delete-selection-mode 1)

No need to backup. Let’s be brave.

(setq backup-inhibited t
      make-backup-files nil
      auto-save-default nil
      create-lockfiles nil)

Location and settings for temp files

  • Don’t delink hardlinks
  • Use version numbers on backups
  • Automatically delete excess backuos
  • Keep only 20 versions
  • Keep only 5 old versions
(setq backup-directory-alist '(("." . "~/.emacs.d/backup"))
    backup-by-copying t
    version-control t
    delete-old-versions t
    kept-new-versions 20
    kept-old-versions 5)

Warn when opening files over 150MB (q)

(setq-default large-file-warning-threshold 150000000)

Startup message setup

(setq initial-scratch-message (format ";; Scratch buffer - started on %s\n\n" (current-time-string)))

Uniquify the buffer’s name

(setq uniquify-buffer-name-style 'forward uniquify-separator "/")

Reset some standard keybindings

;; In GUI emacs, C-z minimizes window, which is useless.
(if (display-graphic-p)
    (global-unset-key (kbd "C-z")))

Auto refresh buffers

(global-auto-revert-mode 1)
;; Disable the *Messages* Buffer
;; (setq-default message-log-max nil)
;; (kill-buffer "*Messages*")

;; Disable the *Completions* buffer
(add-hook 'minibuffer-exit-hook
          (lambda ()
             (let ((buffer "*Completions*"))
               (and (get-buffer buffer)
                    (kill-buffer buffer)))))

Kill all processes automatically on exit w/out prompting

(setq confirm-kill-processes nil)

Open file system read-only files as read-only in Emacs as well

(setq view-read-only t)

UX Customizations

  ;; don't auto split vertically
(setq split-height-threshold nil)

;; (require 'move-text)
(fset 'yes-or-no-p 'y-or-n-p)

;; replace line wrap char with whitespace
(set-display-table-slot standard-display-table 'wrap ?\ )

;; Disable tab characters in indentation
(setq-default indent-tabs-mode nil)

;; Remove extra check for killing processes
(setq confirm-kill-processes nil)

;; Don't ring the bell
(setq ring-bell-function 'ignore)

;; default font
(set-frame-font "Menlo 14" nil t)

;; scale text in smallerl steps
;; (setq text-scale-mode-step 1.1)

;; set face size of minibuffer
(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup)
(defun my-minibuffer-setup ()
  (set (make-local-variable 'face-remapping-alist)
       '((default :height 1.2))))

Package System Setup

Setup the package manager

Configure use-package

  ;; Configure `use-package' prior to loading it.
  (eval-and-compile
    (setq use-package-always-ensure nil)
    ;;(setq use-package-always-defer nil)
    (setq use-package-always-demand nil)
    ;; Toggle to view errors with use-package
    (setq use-package-expand-minimally t)
    ;; (setq use-package-enable-imenu-support t)
    (setq use-package-compute-statistics nil)
    ;; The following is VERY IMPORTANT.  Write hooks using their real name
    ;; instead of a shorter version: after-init ==> `after-init-hook'.
    (setq use-package-hook-name-suffix nil))


;; Uncomment this to get a reading on packages that get loaded at startup
(setq use-package-verbose t)
(add-to-list 'load-path "~/.emacs.d/straight/build")

Appearance & UI

Mouse & Scroll Preferences

Enable smooth scroll and scroll window under mouse

(setq hscroll-step 1)
(setq scroll-conservatively 1000)
(setq mouse-wheel-follow-mouse 't)
(setq use-dialog-box t)               ; only for mouse events
(setq use-file-dialog nil)

;; smooth scroll (requires emacs 29)
;; still cant tell if it makes me dizzy...
(setq pixel-scroll-precision-mode t)

Extended Display Preferences

  • Set default size of the window frame on load
  • Padding between buffer and line number
; (setq initial-frame-alist '((top . 20) (left . 300) (width . 180) (height . 70)))
(setq linum-format "%d ")

OSX Specific Settings

Improve appearance of title bar on osx GUI emacs, white on black

(add-to-list 'initial-frame-alist '(ns-transparent-titlebar . t))
(add-to-list 'initial-frame-alist '(ns-appearance . dark))
(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
(add-to-list 'default-frame-alist '(ns-appearance . dark))

Cursory

Lightweight package for easily creating cursor presets

 (use-package cursory)
 (setq cursory-presets
        '((bar
           :cursor-type (bar . 2)
           :cursor-in-non-selected-windows hollow
           :blink-cursor-blinks 10
           :blink-cursor-interval 0.5
           :blink-cursor-delay 0.2)
          (box
           :cursor-type box
           :cursor-in-non-selected-windows hollow
           :blink-cursor-blinks 10
           :blink-cursor-interval 0.5
           :blink-cursor-delay 0.2)
          (underscore
           :cursor-type (hbar . 3)
           :cursor-in-non-selected-windows hollow
           :blink-cursor-blinks 50
           :blink-cursor-interval 0.2
           :blink-cursor-delay 0.2)))
(setq cursory-latest-state-file (locate-user-emacs-file "cursory-latest-state"))
;; Set last preset or fall back to desired style from `cursory-presets'.
(cursory-set-preset (or (cursory-restore-latest-preset) 'bar))
;; The other side of `cursory-restore-latest-preset'.
(add-hook 'kill-emacs-hook #'cursory-store-latest-preset)
;; We have to use the "point" mnemonic, because C-c c is often the
;; suggested binding for `org-capture'.
(define-key global-map (kbd "C-c p") #'cursory-set-preset)

Popper.el

Cool thing that helps with window management

(use-package popper
:ensure t ; or :straight t
:bind (("C-`"   . popper-toggle)
       ("M-`"   . popper-cycle)
       ("C-M-`" . popper-toggle-type))
:init
(setq popper-reference-buffers
      '("\\*Messages\\*"
        "Output\\*$"
        "\\*Async Shell Command\\*"
        help-mode
        compilation-mode))
(popper-mode +1)
(popper-echo-mode +1))

Themes

EF Themes

(use-package ef-themes
  ;; load some random ef-theme
  :bind ("<f6>" . ef-themes-load-random))

Standard Themes

(use-package standard-themes)

Configure modus-vivendi theme and other themes. Manual and configuration details can be found here.

(use-package modus-themes
  :init
  (setq modus-themes-slanted-constructs t
        modus-themes-bold-constructs nil
        modus-themes-subtle-line-numbers t
        modus-themes-fringes 'subtle
        modus-themes-completions (quote ((matches . (background intense))
                (selection . (accented intense))
                (popup . (accented))))
        modus-themes-mode-line '(padding accented 3d)
        modus-themes-org-agenda
        '((header-block . (variable-pitch scale-title))
          (header-date . (grayscale workaholic bold-today))
          (scheduled . uniform))
        ))

I like doom-themes also…

(use-package doom-themes
  :demand t)

Humanoid themes

(use-package humanoid-themes)

Declare all themes as safe

(setq custom-safe-themes t)

Default Theme

Set the default theme here:

;;(load-theme 'doom-xcode t)
(load-theme 'ef-maris-dark)

Tab Bar

Don’t show the buttons on tabs

(setq tab-bar-close-button-show nil)
(setq tab-bar-new-button-show nil)

Customize Tab Bar face

(set-face-attribute 'tab-bar-tab nil :overline "dark cyan" :box nil)

Modeline

  • TODO: customize modeline, see below (however, liking doom-modeline)
  • Customizing Modeline

    doom-modeline is a very sensible default modeline, so sticking with it for a while

(use-package doom-modeline
:config (doom-modeline-mode))

doom-modeline requires nerd-fonts

(straight-use-package '(nerd-fonts :type git :host github :repo "twlz0ne/nerd-fonts.el"))

Buffer Display

  • an alist is just a “list of lists” in elisp
  • each element in the list takes the form:
( BUFFER-MATCHER
  LIST-OF-DISPLAY-FUNCTIONS
  PARAMETERS)

See this video for a nice tutorial on setting this variable.

(setq display-buffer-alist
    '(
      ;; no window
      ("\\`\\*Async Shell Command\\*\\'"
       (display-buffer-no-window))

      ("\\`\\*\\(Warnings\\|Compile-Log\\|Org Links\\)\\*\\'"
       (display-buffer-no-window)
       (allow-no-window . t))

      ("\\*vterm\\*"
       (display-buffer-reuse-mode-window)
       (dedicated . t))

      ("\\*Org \\(Select\\|Note\\)\\*" ; the `org-capture' key selection and `org-add-log-note'
         (display-buffer-in-side-window)
         (dedicated . t)
         (side . bottom)
         (slot . 0)
         (window-parameters . ((mode-line-format . none))))

      ;; bottom buffer (NOT side window)
      ((or . ((derived-mode . flymake-diagnostics-buffer-mode)
              (derived-mode . flymake-project-diagnostics-mode)
              (derived-mode . messages-buffer-mode)
              (derived-mode . backtrace-mode)))
       (display-buffer-reuse-mode-window display-buffer-at-bottom)
       (window-height . 0.3)
       (dedicated . t)
       (preserve-size . (t . t)))

      ("\\*Occur\\*"
       ;; list of display functions
       (display-buffer-reuse-mode-window
        display-buffer-below-selected)
       ;; Parameters
       (window-height . fit-window-to-buffer)
       (dedicated . t)
       )

      ))

Custom Utility Functions

Here we add custom utility functions

;; Remove tabs
(defun untabify-buffer ()
  (interactive)
  (untabify (point-min) (point-max)))

;; Indent a region
(defun indent-buffer ()
  (interactive)
  (indent-region (point-min) (point-max)))

(defun cleanup-buffer ()
  "Perform a bunch of operations on the whitespace content of a buffer.
  Including indent-buffer, which should not be called automatically on save."
  (interactive)
  (untabify-buffer)
  (delete-trailing-whitespace)
  (indent-buffer))

(defun func/open-package-installer ()
  (interactive)
  (package-refresh-contents)
  (package-list-packages))

Custom Keybindings

Configuration

  • Make ESC quit prompts
  • set modifier keys for Apple keyboard, for emacs in OS X
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)

(setq mac-command-modifier 'super) ; make cmd key do super
(setq ns-function-modifier 'hyper)  ; make Fn key do Hyper

Function Key Bindings

;; [F1] -- Go to a specific line number in the current buffer (file)
(global-set-key [f1] 'goto-line)

;; [F2] -- Comment out a Marked (highlighted) region of text
(global-set-key [f2] 'comment-region)

;; [F3] -- Comment out a Marked (highlighted) region of text
(global-set-key [f3] 'uncomment-region)

;; [F4] -- Cleanup all trailing whitespace
(global-set-key [f4] 'whitespace-cleanup)

;; [F5] -- Switch to next buffer (file), burying current
(global-set-key [f5] 'bury-buffer)

;; [F8] -- Toggle Treemacs
(global-set-key [f8] 'treemacs)

;; [F12] -- Toggle Breakpoint
;; (global-set-key [f12] 'dap-breakpoint-toggle)

Marking Regions and Navigating

;; [Ctrl+c -> TAB] -- Mark the entire file
;; Hint: Useful for auto-formatting the entire file by pressing (Ctrl+c -> TAB -> TAB)
(global-set-key (kbd "C-c TAB") 'mark-whole-buffer)
(global-set-key (kbd "<C-s-up>")     'buf-move-up)
(global-set-key (kbd "<C-s-down>")   'buf-move-down)
(global-set-key (kbd "<C-s-left>")   'buf-move-left)
(global-set-key (kbd "<C-s-right>")  'buf-move-right)
(global-set-key (kbd "M-n") (lambda() (interactive) (scroll-up 1)))
(global-set-key (kbd "M-p") (lambda() (interactive) (scroll-down 1)))

Additional Key Bindings

  ;; [Ctrl+c -> l -- Org store link]
  ;; [Ctrl+c -> a -- Org open agenda]
  (define-key global-map "\C-cl" 'org-store-link)
  (define-key global-map "\C-ca" 'org-agenda)
    (global-set-key "\C-cc" 'org-capture)
  (global-set-key "\C-cb" 'org-switchb)
  (setq org-log-done t)

  (global-set-key (kbd "C-c i") 'func/open-package-installer)

  ;; [Ctrl+c -> TAB] -- Mark the entire file
  ;; Hint: Useful for auto-formatting the entire file by pressing (Ctrl+c -> TAB -> TAB)
  (global-set-key (kbd "C-c TAB") 'mark-whole-buffer)

  ;; [Ctrl+x -> Ctrl+b -- Open iBuffer instead of buffers]
  (global-set-key (kbd "C-x C-b")  'ibuffer)

  ;; By default, killing a word backward will put it in the ring, I don't want this
  (defun backward-kill-word-noring (arg)
    (interactive "p")
    (let ((kr kill-ring))
      (backward-kill-word arg)
      (setq kill-ring (reverse kr))))

  (global-set-key (kbd "C-M-<backspace>") 'backward-kill-word-noring)

  ;; Special keys
  (customize-set-variable mac-right-option-modifier nil)
  (customize-set-variable mac-command-modifier 'super)
  (customize-set-variable ns-function-modifier 'hyper)

(rh-emacs-keybind global-map
   "C-c C-z" nil
    "C-h h" nil
    "M-`" nil
    "M-z" #'zap-up-to-char ; NOT `zap-to-char'
    "C-h K" #'describe-keymap ; overrides `Info-goto-emacs-key-command-node'
    "M-o" #'delete-blank-lines   ; alias for C-x C-o
    "C-x k" #'kill-buffer)

  ;; Keybinds
  (global-set-key (kbd "s-W") 'delete-frame) ; ⌘-W = Close window
  (global-set-key (kbd "s-}") 'tab-bar-switch-to-next-tab) ; ⌘-} = Next tab
  (global-set-key (kbd "s-{") 'tab-bar-switch-to-prev-tab) ; ⌘-{ = Previous tab
  (global-set-key (kbd "s-t") 'tab-bar-new-tab) ;⌘-t = New tab
  (global-set-key (kbd "s-w") 'tab-bar-close-tab) ; ⌘-w = Close tab

  (unless (< emacs-major-version 28)
    (global-set-key (kbd "s-Z") 'undo-redo)) ; ⌘-Z = Redo

DWIM Commands

(defun rh/keyboard-quit-dwim ()
  "Do-What-I-Mean behaviour for a general `keyboard-quit'.

The generic `keyboard-quit' does not do the expected thing when
the minibuffer is open.  Whereas we want it to close the
minibuffer, even without explicitly focusing it.

The DWIM behaviour of this command is as follows:

- When the region is active, disable it.
- When a minibuffer is open, but not focused, close the minibuffer.
- When the Completions buffer is selected, close it.
- In every other case use the regular `keyboard-quit'."
  (interactive)
  (cond
   ((region-active-p)
    (keyboard-quit))
   ((derived-mode-p 'completion-list-mode)
    (delete-completion-window))
   ((> (minibuffer-depth) 0)
    (abort-recursive-edit))
   (t
    (keyboard-quit))))

(define-key global-map (kbd "C-g") #'rh/keyboard-quit-dwim)

Completions

Orderless & Helm

Install and configure orderless a completetions framework helper. I use it in tandem with the built-in icomplete.

( use-package orderless
 ;;  :init (icomplete-mode) ; optional but recommended!
   :custom (completion-styles '(orderless)))
(use-package helm)

Minibuffer

Vertico

Lists minibuffer completion options vertically as opposed to a grid

(use-package vertico
:custom
(vertico-scroll-margin 0) ;; Different scroll margin
(vertico-count 15) ;; Show more candidates
(vertico-resize nil) ;; Grow and shrink the Vertico minibuffer
(vertico-cycle t) ;; Enable cycling for `vertico-next/previous'
:init
(vertico-mode))

Marginalia

Provides rich information in minibuffer for various commands

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

Consult

(use-package consult)

Magit

Set up magit and launch it with C-x g

(use-package magit)

;; Don't ask me to save unsaved buffers on every action
(setq magit-save-repository-buffers nil)
(global-set-key (kbd "C-x g") 'magit-status)

Configure ediff

(custom-set-variables
 '(ediff-split-window-function (quote split-window-horizontally)))

Multiple Cursors

https://github.com/magnars/multiple-cursors.el

(use-package multiple-cursors
  :bind (("H-SPC" . set-rectangular-region-anchor)
         ("C-M-SPC" . set-rectangular-region-anchor)
         ("C->" . mc/mark-next-like-this)
         ("C-<" . mc/mark-previous-like-this)
         ("C-c C->" . mc/mark-all-like-this)
         ("C-c C-SPC" . mc/edit-lines)))

Dired

Configuration

Setup dired the way I like it.

  (require 'dired-x) ;; enable extra features by default
  (setq insert-directory-program "gls" dired-use-ls-dired t)
  (use-package dired
    :straight nil
    :config
    (setq dired-dwim-target t)
    (setq dired-listing-switches
          "-GFhlva --group-directories-first --time-style=long-iso")
    :hook ((dired-mode-hook . dired-hide-details-mode)
           (dired-mode-hook . (lambda() (display-line-numbers-mode -1)))
           (dired-mode-hook . hl-line-mode)))
;;           (dired-mode-hook . treemacs-icons-dired))

Also auto refresh dired, but be quiet about it

(setq global-auto-revert-non-file-buffers t)
(setq auto-revert-verbose nil)
(if (display-graphic-p)
    (use-package nerd-icons-dired
      :hook
      (dired-mode-hook . nerd-icons-dired-mode)))

Custom Functions

Use “F” to open all marked files in dired. Code lifted from here.

(eval-after-load "dired"
  '(progn
     (define-key dired-mode-map "F" 'my-dired-find-file)
     (defun my-dired-find-file (&optional arg)
       "Open each of the marked files, or the file under the point, or when prefix arg, the next N files "
       (interactive "P")
       (let* ((fn-list (dired-get-marked-files nil arg)))
         (mapc 'find-file fn-list)))))

Debugging: dap-mode

;; (use-package dap-mode
;;   :custom
;;     (dap-auto-configure-features '(sessions locals expressions controls tooltip))
;;   :config
;;   )

Treemacs Add Ons

(use-package treemacs-icons-dired)

(dolist (face '(treemacs-root-face
                treemacs-git-unmodified-face
                treemacs-git-modified-face
                treemacs-git-renamed-face
                treemacs-git-ignored-face
                treemacs-git-untracked-face
                treemacs-git-added-face
                treemacs-git-conflict-face
                treemacs-directory-face
                treemacs-directory-collapsed-face
                treemacs-file-face
                treemacs-tags-face))
  (set-face-attribute face nil :family "SF Pro" :height 140))

Projectile

(use-package projectile
  :diminish projectile-mode
  :config (projectile-mode)
  :custom ((projectile-completion-system 'ivy))
  :bind-keymap
  ("C-c p" . projectile-command-map)
  :init
  (when (file-directory-p "~/git")
    (setq projectile-project-search-path '("~/git")))
  (setq projectile-switch-project-action #'projectile-dired))

Treesitter

See: https://github.com/renzmann/treesit-auto

;;(straight-use-package 'tree-sitter)
;;(straight-use-package 'tree-sitter-langs)
(straight-use-package 'treesit-auto)

Language grammars that don’t seem to auto install with treesit-auto

(setq treesit-language-source-alist
 '((cmake "https://github.com/uyha/tree-sitter-cmake")
   (elisp "https://github.com/Wilfred/tree-sitter-elisp")
   (json "https://github.com/tree-sitter/tree-sitter-json")
   (make "https://github.com/alemuller/tree-sitter-make")
   (dockerfile "https://github.com/camdencheek/tree-sitter-dockerfile")
   (markdown "https://github.com/ikatyang/tree-sitter-markdown")))

;; install them please - keep commented out because it runs every time
;; (mapc #'treesit-install-language-grammar (mapcar #'car treesit-language-source-alist))
  ;;(global-tree-sitter-mode)
  (use-package treesit-auto
    :custom
    (treesit-auto-install 'prompt)
    :config
    ;; prefer web-mode for html for now as it has better mixed syntax support
    (delete 'html treesit-auto-langs)
    ;; this adds the rest to the auto-mode-alist
    (treesit-auto-add-to-auto-mode-alist 'all)
    (global-treesit-auto-mode))

  ;; this fixes a problem where v0.20.4 of this grammar blows up with emacs
  ;;(defvar rh/tsx-treesit-auto-recipe
  ;;  (make-treesit-auto-recipe
  ;;   :lang 'tsx
  ;;   :ts-mode 'tsx-ts-mode
  ;;   :remap '(typescript-tsx-mode)
  ;;   :requires 'typescript
  ;;   :url "https://github.com/tree-sitter/tree-sitter-typescript"
  ;;   :revision "v0.20.3"
 ;;    :source-dir "tsx/src"
 ;;    :ext "\\.tsx\\'")
 ;;   "Recipe for libtree-sitter-tsx.dylib")
  ;;(add-to-list 'treesit-auto-recipe-list rh/tsx-treesit-auto-recipe)

;  (defvar rh/typescript-treesit-auto-recipe
;    (make-treesit-auto-recipe
;     :lang 'typescript
;     :ts-mode 'typescript-ts-mode
;     :remap 'typescript-mode
;     :requires 'tsx
;     :url "https://github.com/tree-sitter/tree-sitter-typescript"
;     :revision "v0.20.3"
;     :source-dir "typescript/src"
;     :ext "\\.ts\\'")
;    "Recipe for libtree-sitter-typescript.dylib")
  ;;(add-to-list 'treesit-auto-recipe-list rh/typescript-treesit-auto-recipe)

LSP & Company

Company

(use-package company
  :custom
  (company-idle-delay 0.0)
  (company-tooltip-align-annotations t)
  (company-minimum-prefix-length 1))

I prefer the more emacs-like “C-n” keybinding for cycling between completion options. Remove “tab” from doing this so as to reserve it for Copilot completion

(define-key company-active-map (kbd "<tab>") nil)
(define-key company-active-map (kbd "TAB") nil)

LSP

(defun setup-lsp-mode ()
  (message "setting up lsp mode..."))

(defun setup-flycheck ()
   (message "setting up flycheck mode...")
   (lsp-diagnostics-flycheck-enable)
   (flycheck-mode)
   (setq-default flycheck-disabled-checkers '(lsp))
   ;; tsserver returns markdown doc for eldoc
   ;; which requires lsp-eldoc-render-all to be fully shown
   (setq-local lsp-eldoc-render-all t)
   (unless (derived-mode-p 'json-mode)
    (flycheck-add-next-checker 'javascript-eslint 'lsp))
  ;; run flycheck on save and on opening a new line
  (setq flycheck-check-syntax-automatically '(save new-line mode-enabled))
   ;; prefer eslint over all checkers if it can be enabled, do it
  (unless (derived-mode-p 'json-mode)
    (flycheck-select-checker 'javascript-eslint))
   (message "using eslint if available")
   ((lambda () (if (flycheck-may-enable-checker 'javascript-eslint)
                   (message "eslint IS available, attempting to set checker")
                (flycheck-select-checker 'javascript-eslint)))))



(use-package lsp-mode
  :commands lsp
  :custom
  ;; DISABLED while debugging react prop completion
  ;;(lsp-enable-snippet nil)
  (lsp-enable-flycheck nil)
  :init (setq
         lsp-idle-delay 0.5
         read-process-output-max (* 1024 1024))
   :hook ((lsp-mode-hook . setup-lsp-mode)))
         ;; run flycheck setup so that it gets initialized when first starting the server
         ;; this results in the setup being run twice when opening the first file in a ts/js project

          ;; (lsp-after-initialize-hook . setup-flycheck)))

(use-package lsp-ui :commands lsp-ui-mode)
(use-package lsp-treemacs :commands lsp-treemacs-errors-list)
(use-package helm-lsp :commands helm-lsp-workspace-symbol)
(use-package helm-xref)
(use-package yasnippet)
(use-package avy)
(use-package hydra)
(use-package lsp-ivy :commands lsp-ivy-workspace-symbol)
(use-package which-key :config (which-key-mode))
(require 'helm-xref)
(yas-global-mode)
;;(define-key global-map [remap find-file] #'helm-find-files)
;;(define-key global-map [remap execute-extended-command] #'helm-M-x)
;;(define-key global-map [remap switch-to-buffer] #'helm-mini)

LSP Booster Stuff

See: https://github.com/blahgeek/emacs-lsp-booster

LSP UI

github

;; hide lsp ui code actions
;; (setq lsp-ui-sideline-show-code-actions nil)

Additional Hooks

Prog Mode

Set the prog-mode hook. prog-mode is a major mode provided by Emacs. Typically, it is not used directly, instead many programming-related major modes are derived from this mode. Any hooks defined here will be applied to all modes that derive from it, inluding js-mode and more.

(defun hook-prog-mode ()
  "Hook for Prog mode."
  (local-set-key (kbd "C-c <right>") 'hs-show-block)
  (local-set-key (kbd "C-c <left>")  'hs-hide-block)
  (local-set-key (kbd "C-c <up>")    'hs-hide-all)
  (local-set-key (kbd "C-c <down>")  'hs-show-all)
  (hs-minor-mode t))

(add-hook 'prog-mode-hook #'hook-prog-mode)

Text Mode

Set the text-mode hook. We increase the “padding” between line numbers with the linum-format variable.

(defun hook-text-mode ()
  "Hook  for Text mode."
  ;; (linum-mode 1)
  (make-local-variable 'linum-format)
  (setq linum-format " %d "))

(add-hook 'text-mode-hook #'hook-text-mode)

Ibuffer

I prefer Ibuffer to buffer window. Pretty colors and such. The keybinding C-b is overridden to open Ibuffer instead of vanilla buffer window.

(use-package ibuffer
  :config
  (setq ibuffer-expert t)
  (setq ibuffer-display-summary nil)
  (setq ibuffer-use-other-window nil)
  (setq ibuffer-show-empty-filter-groups nil)
  (setq ibuffer-movement-cycle nil)
  (setq ibuffer-default-sorting-mode 'filename/process)
  (setq ibuffer-use-header-line t)
  (setq ibuffer-default-shrink-to-minimum-size nil)
  (setq ibuffer-formats
        '((mark modified read-only locked " "
                (name 30 30 :left :elide)
                " "
                (size 9 -1 :right)
                " "
                (mode 16 16 :left :elide)
                " " filename-and-process)
          (mark " "
                (name 16 -1)
                " " filename)))
  (setq ibuffer-saved-filter-groups nil)
  (setq ibuffer-old-time 48)
  :hook ((ibuffer-mode-hook . (lambda() (display-line-numbers-mode -1)))
  (ibuffer-mode-hook . auto-revert-mode)))

Line numbers

Disable line numbers for the following modes regardless of global setting

(dolist (mode '(org-mode-hook
                org-agenda-mode-hook
                treemacs-mode-hook
                term-mode-hook
                eshell-mode-hook
                shell-mode-hook
                image-mode-hook
                helm-mode-hook
                markdown-mode-hook))
  (add-hook mode (lambda() (display-line-numbers-mode -1))))

Opt in line numbers on these modes regardless of global setting

(dolist (mode '(dockerfile-mode-hook))(add-hook mode (lambda() (display-line-numbers-mode 1))))

SmartParens

(use-package smartparens)

Languages

Code Formatting

Prettier

(use-package prettier
  :defer)

Emacs Lisp

HTML

(use-package web-mode
:mode
(("\\.html\\'" . web-mode)
 ("\\.php\\'" . web-mode)))

(setq web-mode-markup-indent-offset 2)
(setq web-mode-css-indent-offset 2)
(setq web-mode-code-indent-offset 2)
(setq web-mode-enable-current-element-highlight t)
(setq web-mode-enable-current-column-highlight t)
(defun setup-html-mode ()
  (interactive)
  (company-mode)
  (prettier-mode)
  (lsp))

(add-hook 'web-mode-hook #'setup-html-mode)

NodeJs

(use-package add-node-modules-path)
(setq add-node-modules-path-command "echo \"$(npm root)/.bin\"")
;;(use-package add-node-modules-path
;;  :custom
;;  (add-node-modules-path-command '("npm root")))

;;(use-package prettier-js)

CSS

(defun setup-css-mode ()
  (interactive)
  (prettier-mode)
  (company-mode))

(add-hook 'css-ts-mode-hook #'setup-css-mode)

JavaScript

Testing out lsp-tailwindcss

;;  (straight-use-package
;;   '(lsp-tailwindcss :type git :host github :repo "merrickluo/lsp-tailwindcss"))
;;(straight-use-package
;; `(lsp-biome :type git :host github :repo "cxa/lsp-biome"))
;; Make it so all '.js' files auto load 'js-mode'
(add-to-list 'auto-mode-alist '("\\.js\\'" . js-ts-mode))

;; Make it so all '.jsx' files auto load 'js-jsx-mode'
(add-to-list 'auto-mode-alist '("\\.jsx\\'" . js-jsx-mode))

;; Make it so all '.html' files auto load html-mode'
(add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
;; (add-to-list 'auto-mode-alist '("\\.html\\'" . html-ts-mode))

;; Use 2 spaces when tabbing HTML elements
(setq-default sgml-basic-offset 2)

;; Use 2 spaces when tabbing JS elements
(setq-default js-indent-level 2)

;; Indent switch statements normally
(setq js2-indent-switch-body t)
(defun setup-js-ts-mode ()
  ;; json-mode runs js-mode hooks so don't run
  (interactive)
  (unless (derived-mode-p 'json-ts-mode)
  (message "Setting up js/ts mode")
  (lsp)
  (require 'lsp-diagnostics)
  (add-node-modules-path)
  (prettier-mode)
  (smartparens-mode)
  (eldoc-mode +1)
  (setq lsp-disagnostics-provider :none)))
  ;;(setup-flycheck)))


(add-hook 'js-ts-mode-hook #'setup-js-ts-mode)
(add-hook 'js-jsx-mode-hook #'setup-js-ts-mode)
(add-hook 'typescript-ts-mode-hook #'setup-js-ts-mode)
(add-hook 'tsx-ts-mode-hook #'setup-js-ts-mode)

TypeScript

;; (use-package typescript-mode)

;; tsx-mode
;; install deps
;;(use-package coverlay)
;;(use-package origami)
;;(straight-use-package '(css-in-js-mode :type git :host github :repo "orzechowskid/tree-sitter-css-in-js"))
;;(straight-use-package '(tsx-mode :type git :host github :repo "orzechowskid/tsx-mode.el"))
;; Make it so all '.ts' files auto load 'typescript-mode'
(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))

;; Make it so all '.tsx' files auto load 'typescript-mode'
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))

;; Use 2 spaces when tabbing TS elements
(setq-default typescript-indent-level 2)

Go

(use-package go-mode)
(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
(defun setup-go-mode ()
  (message "Setting up go mode")
  (interactive)
  (lsp)
  (eldoc-mode +1)
  ;; set tab-width
  (lambda ()
    (setq-default)
    (setq tab-width 2)
    (setq standard-indent 2)
    (setq indent-tabs-mode nil))
  ((lambda () (flycheck-select-checker 'go-gofmt)))
  (setq lsp-disagnostics-provider :none))


(add-hook 'go-ts-mode-hook #'setup-go-mode)


;; Set up before-save hooks to format buffer and add/delete imports.
;; Make sure you don't have other gofmt/goimports hooks enabled.
(defun lsp-go-install-save-hooks ()
   (add-hook 'before-save-hook #'lsp-format-buffer t t)
   (add-hook 'before-save-hook #'lsp-organize-imports t t))

(add-hook 'go-ts-mode-hook #'lsp-go-install-save-hooks)

Rust

See:

(use-package rust-mode
  :hook (rust-ts-mode-hook . lsp))

(defun lsp-rust-install-save-hooks ()
   (add-hook 'before-save-hook #'lsp-format-buffer t t)
   (add-hook 'before-save-hook #'lsp-organize-imports t t))

(add-hook 'rust-ts-mode-hook #'lsp-rust-install-save-hooks)

Python

(use-package python-mode
  :hook (python-ts-mode-hook . (lambda ()
                                 (pyenv-mode-set "3.11.6")
                                 (eglot-ensure)
                                 (company-mode))))

(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
               '(python-ts-mode . ("pyenv" "exec" "poetry" "run" "pyright-langserver" "--stdio"))))

(use-package pyenv-mode
  :hook (python-ts-mode-hook . pyenv-mode))

(use-package poetry
  :ensure t)
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-ts-mode))

Flycheck

Flycheck Manual

(use-package flycheck
  :defer)

(defun rh/use-eslint-from-node-modules ()
  (let* ((root (locate-dominating-file
                (or (buffer-file-name) default-directory)
                "node_modules/eslint"))
         (eslint
          (and root
               (expand-file-name "node_modules/.bin/eslint"
                                 root))))
    (when (and eslint (file-executable-p eslint))
      (setq-local flycheck-javascript-eslint-executable eslint))))

  ;;(defun setup-flycheck ())
  ;;(interactive)
  ;;(message "setting up flycheck mode...")
  ;;(setq-default flycheck-disabled-checkers '(lsp))
  ;;(rh/use-eslint-from-node-modules)
  ;;(lsp-diagnostics-flycheck-enable)
  ;;(flycheck-select-checker 'javascript-eslint))
;; this guy will run a check for eslint every time flycheck runs
;;(add-hook 'flycheck-mode-hook #'my/use-eslint-from-node-modules)

JSON

(defun setup-json-mode ()
  (message "Setting up json mode")
  (interactive)
  ;(flycheck-select-checker 'json-python-json)
  (prettier-mode))

(use-package json-ts-mode)
(add-hook 'json-ts-mode-hook #'setup-json-mode)

YAML

(use-package yaml-mode)
(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-mode))

Docker

(use-package dockerfile-mode)

JenkinsFile

(use-package jenkinsfile-mode)

Rego

(use-package rego-mode)

Markdown

Define a function my-markdown-preview for conveniently previewing markdown files in the GitHub style.

;; this is not working
;;(add-hook 'markdown-mode-hook '((set-window-margins (get-buffer-window) 10 10)))
  (setq markdown-preview-stylesheets (list "~/github-markdown.css"))

  (use-package markdown-mode
    :mode ("\\.md\\'" . gfm-mode)
    :commands (markdown-mode gfm-mode)
    :config (setq markdown-command "pandoc -t html5"))
    ;;(setq markdown-command "markdown"))

  (use-package simple-httpd
    :config
    (setq httpd-port 7070)
    (setq httpd-host (system-name)))

  (use-package impatient-mode
    :commands impatient-mode)

  (defun my-markdown-filter (buffer)
    (princ
     (with-temp-buffer
       (let ((tmp (buffer-name)))
         (set-buffer buffer)
         (set-buffer (markdown tmp))
         (format "<!DOCTYPE html><html><title>Markdown preview</title><link rel=\"stylesheet\" href = \"https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css\"/>
  <body><article class=\"markdown-body\" style=\"box-sizing: border-box;min-width: 200px;max-width: 980px;margin: 0 auto;padding: 45px;\">%s</article></body></html>" (buffer-string))))
     (current-buffer)))


(defun my-imp-visit-buffer ()
"Visit the buffer in a browser."
(interactive)
(browse-url
(format "http://localhost:%d/imp/live/%s/"
httpd-port (url-hexify-string (buffer-name)))))


  (defun rh/markdown-preview ()
    "Preview markdown."
    (interactive)
    (unless (process-status "httpd")
      (httpd-start))
    (impatient-mode)
    (imp-set-user-filter 'my-markdown-filter)
    ;;(my-imp-visit-buffer))
    (imp-visit-buffer))

GitHub Copilot

Install dependencies and package

(use-package editorconfig)
(use-package jsonrpc)
(use-package copilot
  :straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
  :defer t
  :config (define-key copilot-mode-map (kbd "TAB") 'copilot-accept-completion))

Enable copilot when prog mode is on (disabled)

;; (add-hook 'prog-mode-hook 'copilot-mode)

Use Enter for accepting completions

;; (define-key copilot-mode-map (kbd "TAB") 'copilot-accept-completion)
;; (define-key copilot-completion-map (kbd "M-s-p") 'copilot-accept-completion)

copilot chat

(use-package copilot-chat
:straight (:host github :repo "chep/copilot-chat.el" :files ("*.el"))
:after (request))

Org Mode

Default Settings

  • Follow links
  • Associate all org files with org mode
  • Activate org-indent-mode nicer indents
  • Activate visual-line-mode for readability
(setq org-return-follows-link t)
(add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode))
(add-hook 'org-mode-hook 'org-indent-mode)
(add-hook 'org-mode-hook 'visual-line-mode)

;; Ellipsis styling
(setq org-ellipsis "")
(set-face-attribute 'org-ellipsis nil :inherit 'default :box nil)

Org Eval

Don’t ask for confirmation when evaluating code blocks. Could be changed to a function that returns bool with more complex logic if desired.

(setq org-confirm-babel-evaluate 'nil)

Visual Settings

Set maximum indentation for description lists

(setq org-list-description-max-indent 5)

Hide emphasis markup (e.g. for italics, for bold, etc.)

(setq org-hide-emphasis-markers t)
(setq org-pretty-entities t)
(setq
 ;; Edit settings
 org-auto-align-tags nil
 org-tags-column 0
 org-catch-invisible-edits 'show-and-error
 org-special-ctrl-a/e t
 org-insert-heading-respect-content t)

Visual fill mode, visual fill column mode settings

;; set up display of org mode docs
(defun org-mode-visual-fill ()
  (setq visual-fill-column-width 160
        visual-fill-column-center-text t
        visual-fill-column-mode 1))

(use-package visual-fill-column
  :defer t
  :hook (org-mode-hook . org-mode-visual-fill))

Org-Capture

(setq org-directory "~/org")
(setq org-default-notes-file "~/org/refile.org")

(setq org-refile-targets '((org-agenda-files :maxlevel . 1)))

(setq org-refile-use-outline-path 'file)
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-allow-creating-parent-nodes 'confirm)

;; I use C-c c to start capture mode
(global-set-key (kbd "C-c c") 'org-capture)

;; Capture templates for: TODO tasks, Notes, appointments, phone calls, meetings, and org-protocol
(setq org-capture-templates
      (quote (("g" "General To-Do"
               entry (file+headline "~/org/todos.org" "General Tasks")
               "* TODO [#B] %?\n:Created: %T\n "
               :empty-lines 0)
              ("j" "Work Log Entry"
               entry (file+datetree "~/org/log.org")
               "* %?"
               :empty-lines 0)
              ("n" "Note"
               entry (file+headline "~/org/notes.org" "Notes")
               "** %?"
               :empty-lines 0)
              ("q" "Question"
               entry (file+headline "~/org/questions.org" "General Question")
               "* QUESTION %?\n:Created: %T\n Answer: "
               :empty-lines 0)
              ("c" "Code To-Do"
               entry (file+headline "~/org/todos.org" "Code Related Tasks")
               "* TODO [#B] %?\n;; :Created: %T\n%i\n%a\nProposed Solution: "
               :empty-lines 0)
              ("m" "Meeting"
               entry (file+datetree "~/org/meetings.org")
               "* %? :meeting:%^g \n:Created: %T\n** Attendees\n*** \n** Notes\n** Action Items"
               :tree-type week
               :clock-in t
               :clock-resume t
               :empty-lines 0)
              ("t" "Ticket"
               entry (file+headline "~/org/tickets.org" "Tickets")
               "* TODO [#B] %? %^g\nCreated: %T\n** Jira Link: \n** Notes\n** Status\n - [ ] Research\n - [ ] PR\n - [ ] Verifying\n** Subtasks"
               :empty-lines 0)
              ("p" "Sprint"
               entry (file "~/org/sprints.org" )
               "** Kraken Sprint %?\n:Created: %T\nSCHEDULED: %T\nDEADLINE: %T\n*** GOAL\n*** Notes\n*** Review\n*** Planning\n*** Retrospective "))))

Tags

(setq org-tag-alist '(
                      ;; Ticket types
                      (:startgroup . nil)
                      ("@bug" . ?b)
                      ("@story" . ?u)
                      ("@spike" . ?j)
                      (:endgroup . nil)

                      ;; Ticket flags
                      ("@write_ticket" . ?w)

                      ;; Meeting types
                      (:startgroup . nil)
                      ("dsu" . ?d)
                      ("scrum" . ?g)
                      (:endgroup . nil)

                      ;; Code TODOs tags
                      (:startgroup . nil)
                      ("backend" . ?k)
                      ("ui" . ?f)
                      (:endgroup . nil)

                      ;; Special tags
                      ("CRITICAL" . ?y)
                      ("obstacle" . ?o)

                      ;; Meeting tags
                      ("HPE" . ?h)
                      ("LEAP" . ?z)
                      ("mark" . ?0)
                      ("kalki" . ?7)
                      ("cox" . ?9)
                      ("CDS" . ?l)
                      ("meeting" . ?m)

                      ;; Work Log Tags
                      ("accomplishment" . ?a)))
(setq org-tag-faces
      '(
        ("planning"  . (:foreground "mediumPurple1" :weight bold))
        ("LEAP"      . (:foreground "royalblue1"    :weight bold))
        ("ui"        . (:foreground "forest green"  :weight bold))
        ("testing"   . (:foreground "sienna"        :weight bold))
        ("meeting"   . (:foreground "yellow1"       :weight bold))
        ("CRITICAL"  . (:foreground "red1"          :weight bold))
        ))

Org Plot

See: https://thearjunmdas.github.io/entries/plot-graphs-in-emacs-org-mode/

gnuplot binary must be installed for these to work: https://formulae.brew.sh/formula/gnuplot

(use-package gnuplot)
(use-package gnuplot-mode)

Org Agenda

;; (setq org-agenda-files (quote ("~/org/notes.org"
;;                                "~/org/todos.org"
;;                                "~/org/dev-adv.org"
;;                                "~/org/log.org"
;;                                "~/org/leap.org"
;;                                "~/org/sprints.org"
;;                                "~/org/tickets.org"
;;                                "~/org/meetings.org")))

(setq org-agenda-files '("~/org"))
(setq org-agenda-sticky t)
(setq org-agenda-inhibit-startup nil)
(setq org-agenda-window-setup "other-tab")

;; Compact the block agenda view (disabled)
(setq org-agenda-compact-blocks nil)
(setq org-deadline-warning-days 10)

;; (setq org-agenda-custom-commands
;;       '(("W" "Weekly Review"
;;          ((agenda "" ((org-agenda-span 7)))
;;           (todo "GOAL"
;;                 ((org-agenda-overriding-header "Sprint Goals")))
;;           (todo "KAIZEN"
;;                 ((org-agenda-overriding-header "Kaizen")))
;;           (todo "TODO|IN PROGRESS"
;;                 ((org-agenda-overriding-header "My Todos")))
;;           (todo "TASK"
;;                 ((org-agenda-overriding-header "Team Tasks")))
;;           ))))

Custom Agenda Commands

  ;; Agenda View "d"
  (defun air-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)))

  (setq org-agenda-skip-deadline-if-done t)

  ;; Agenda View "d"
(defun air-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)))

(setq org-agenda-skip-deadline-if-done t)

(setq org-agenda-custom-commands
      '(
        ;; Daily Agenda & TODOs
        ("d" "Daily agenda and all TODOs"

         ;; Display items with priority A
         ((tags "PRIORITY=\"A\""
                ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                 (org-agenda-overriding-header "High-priority Todos:")))

          ;; View 7 days in the calendar view
          ;; (agenda "" ((org-agenda-span 5)))

          ;; Display items with priority B (really it is view all items minus A & C)
          (todo "TODO"
                   ((org-agenda-skip-function '(or (air-org-skip-subtree-if-priority ?A)
                                                   (air-org-skip-subtree-if-priority ?C)
                                                   (org-agenda-skip-if nil '(scheduled deadline))))
                    (org-agenda-overriding-header "ALL normal priority tasks:")))

          ;; Display items with pirority C
          (tags "PRIORITY=\"C\""
                ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                 (org-agenda-overriding-header "Low-priority Unfinished tasks:")))

          (todo "TASK|GAP"
                ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                 (org-agenda-overriding-header "Tasks and Organizational Gaps:")))

          (todo "QUESTION"
                ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                 (org-agenda-overriding-header "Questions needing Answers")))


          ) ;; end agenda sections



         ;; Don't compress things (change to suite your tastes)
         ((org-agenda-compact-blocks nil)))
        ))

Todo states

(setq org-todo-keywords
      '((sequence "TODO(t)" "IN PROGRESS(i@/!)" "BLOCKED(b@)" "|" "DONE(d!)" "WONT-DO(w@/!)")
        (sequence "TASK(f)"  "GAP(p)" "|" "OBE(w@/!)" "DONE(d)")
        (sequence "KAIZEN(k)"  "|" "DONE(d)")
        (sequence "QUESTION(q)"  "|" "ANSWERED(a)")
        (sequence "GOAL(g)" "|" "DELIVERED(y!)")))

(setq org-todo-keyword-faces
      '(("TODO" . (:foreground "DarkOrange1" :weight bold))
        ("IN PROGRESS" . (:foreground "sea green"))
        ("PLANNING" . (:foreground "DeepPink" :weight bold))
        ("BLOCKED" . (:foreground "Red" :weight bold))
        ("DONE" . (:foreground "light sea green"))
        ("TASK" . (:foreground "magenta"))
        ("QUESTION" . (:foreground "maroon2"))
        ("GAP" . (:foreground "IndianRed1"))))

Visual settings

Define headline fonts, disabled for now…TODO https://zzamboni.org/post/beautifying-org-mode-in-emacs/

;; (let* ((variable-tuple
;;          (cond ((x-list-fonts "Optima Regular")  '(:font "Optima Regular"))
;;                ((x-list-fonts "Lucida Grande")   '(:font "Lucida Grande"))
;;                ((x-list-fonts "Verdana")         '(:font "Verdana"))
;;                ((x-family-fonts "Sans Serif")    '(:family "Sans Serif"))
;;                (nil (warn "Cannot find a Sans Serif Font.  Install Source Sans Pro."))))
;;         (base-font-color     (face-foreground 'default nil 'default))
;;         (headline           `(face-foreground 'default nil 'default)))

;;    (custom-theme-set-faces
;;     'user
;;     `(org-level-8 ((t (,@headline ,@variable-tuple))))
;;     `(org-level-7 ((t (,@headline ,@variable-tuple))))
;;     `(org-level-6 ((t (,@headline ,@variable-tuple))))
;;     `(org-level-5 ((t (,@headline ,@variable-tuple))))
;;     `(org-level-4 ((t (,@headline ,@variable-tuple :height 1.03))))
;;     `(org-level-3 ((t (,@headline ,@variable-tuple :height 1.05))))
;;     `(org-level-2 ((t (,@headline ,@variable-tuple :height 1.07))))
;;     `(org-level-1 ((t (,@headline ,@variable-tuple :height 1.1))))
;;     `(org-document-title ((t (,@headline ,@variable-tuple :height 1.2 :underline nil))))))

;; '(variable-pitch ((t (:family "ETBembo" :height 180 :weight thin))))
;; '(fixed-pitch ((t ( :family "Fira Code Retina" :height 160)))))

;; (add-hook 'org-mode-hook 'variable-pitch-mode)

Org Modern

  ;; (use-package org-bullets
  ;; ;  :after org
  ;; ;  :hook (org-mode . org-bullets-mode)
  ;;   :custom
  ;;   (org-bullets-bullet-list '("⁖" "◉" "○" "✸" "✿")))

(use-package org-modern
  :straight (org-modern :type git :flavor melpa :host github :repo "minad/org-modern" :commit 63372bda43a9d0dd9940c1ec3c53f752b642ac41))
(setq org-modern-star "replace")
(with-eval-after-load 'org (global-org-modern-mode))

Bootstrap Org

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

PlantUML

(use-package plantuml-mode)

(setq plantuml-output-type "png")
(setq org-plantuml-jar-path "~/plantuml.jar")
(setq plantuml-jar-path "~/plantuml.jar")
(setq plantuml-default-exec-mode 'jar)

;; Make it so all '.puml' files auto load 'plantuml-mode'
(add-to-list 'auto-mode-alist '("\\.puml\\'" . plantuml-mode))

Org Babel Language Support

;; load language support
(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (python . t)
   (shell . t)
   (js . t)
   (plantuml . t)
   ))

Org Mode Custom Keybindings

macOS swallows certain keybindings in terminal mode. Redfining the most important ones to me here

(global-set-key (kbd "C-c y") 'org-insert-structure-template)

Org JIRA

Install

;;(use-package org-jira)

Set the Org JIRA base URL and authenticate

;; Uncomment next two lines to debug connection issues w/ JIRA
;;(setq request-log-level 'blather)
;;(setq request-message-level 'blather)

;;(setq jiralib-url "https://nimblejira.nimblestorage.com")

;; pull token from .authinfo
;;(setq jiralib-token
;;      (cons "Authorization"
;;            (concat "Bearer " (auth-source-pick-first-password
;;                :host "nimblejira.nimblestorage.com"))))

Custom JIRA Queries

;;(setq org-jira-custom-jqls
;;  '(
;;    (:jql " assignee = currentUser() AND (status = \"To Do\" OR status = \"In Progress\") order by updated DESC "
;;          :limit 100
;;          :filename "my-open-issues")))

Define how tickets progress

;(defconst org-jira-progress-issue-flow
;'(("To Do" . "In Progress"
;  ("In Progress" . "Done"))))

Custom Interface Interactions

(defun rh-reload-emacs-init ()
  (interactive)
  (load-file "~/.emacs.d/init.el"))

vTerm

(use-package vterm
  :straight (:post-build ((setq vterm-always-compile-module t)
                          (require 'vterm)))
  ;;:init ;;(setq
         ;;vterm-kill-buffer-on-exit t
         ;;vterm-max-scrollback 10000
         ;;vterm-min-window-width 40)
  :commands (vterm vterm-other-window))

(use-package vterm-toggle
    :defer)
  ;; (use-package multi-vterm)
(global-set-key (kbd "<f9>") 'vterm-toggle)
(global-set-key (kbd "C-<f9>") 'vterm-toggle-cd)

Custom Commands

Here are little commands/macros that kind of thing that keep me more productive

(defun rh/kill-buffer-and-window ()
"Kill the current buffer and close its window if it's not the only window in the frame."
 (interactive)
 (let ((window (selected-window)))
   (kill-buffer)
   (when (> (count-windows) 1)
     (delete-window window))))

 ;; replace kill-buffer keybinding
 ;; (global-set-key (kbd "C-x k") 'rh/kill-buffer-and-window)

Experiments

Here are packages and things I’m experimenting with…

Spacious Padding

(use-package spacious-padding
  :if (display-graphic-p))

Beframed

(use-package beframe)

(setq beframe-global-buffers '("*scratch*" "*Messages*" "*Backtrace*"))

(beframe-mode 1)

(define-key global-map (kbd "C-c C-b") #'beframe-prefix-map)

Bootstrap

We create a bootstrap file to load all the lisp files that were generated by the code blocks above

(add-to-list 'load-path "~/.emacs.d/lisp")
(load-library "common")
(load-library "packages")
(load-library "modes")
(load-library "hooks")
(load-library "keybindings")
(load-library "commands")

Finally

All we can do is try.