emacs/init.el

2236 lines
76 KiB
EmacsLisp

;;; init.el -*- lexical-binding: t; -*-
(defun chris/display-startup-time ()
(message "Emacs loaded in %s with %d garbage collections."
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done))
(add-hook 'emacs-startup-hook #'chris/display-startup-time)
(setq inhibit-startup-message t)
(scroll-bar-mode -1)
(tool-bar-mode -1)
(tooltip-mode -1)
(set-fringe-mode +1)
(menu-bar-mode -1)
(blink-cursor-mode -1)
(column-number-mode +1)
(setq-default indent-tabs-mode nil)
(setq comp-deferred-compilation-deny-list nil)
(setq frame-resize-pixelwise t)
(if (string-equal (system-name) "syl")
(defvar chris/default-font-size 120)
(defvar chris/default-font-size 120))
(defun chris/set-font-faces ()
"Set the faces for our fonts"
(message "Setting faces!")
(set-face-attribute 'default nil :font "VictorMono Nerd Font"
:height chris/default-font-size)
(set-face-attribute 'fixed-pitch nil :font "VictorMono Nerd Font"
:height chris/default-font-size)
(set-face-attribute 'variable-pitch nil :font "Noto Sans"
:height (+ chris/default-font-size (/ chris/default-font-size 12))
:weight 'regular))
(defun chris/set-transparency ()
"Set the frame to be transparent on Wayland compositors"
(set-frame-parameter (selected-frame) 'alpha '(100 . 100))
(add-to-list 'default-frame-alist '(alpha . (100 . 100)))
(add-to-list 'initial-frame-alist '(alpha . (100 . 100))))
(if (daemonp)
(add-hook 'after-make-frame-functions
(lambda (frame)
(with-selected-frame frame
(chris/set-font-faces)
(chris/set-transparency)
(tool-bar-mode -1)))
(chris/set-font-faces)))
(setq display-line-numbers-type 'relative)
(global-display-line-numbers-mode +1)
(add-hook 'prog-mode-hook (display-line-numbers-mode +1))
(global-visual-line-mode +1)
(defun on-frame-open (frame)
(if (not (display-graphic-p frame))
(set-face-background 'default "unspecified-bg" frame)))
(add-hook 'after-make-frame-functions 'on-frame-open)
;; always avoid GUI
(setq use-dialog-box nil)
;; Don't display floating tooltips; display their contents in the echo-area,
;; because native tooltips are ugly.
(when (bound-and-true-p tooltip-mode)
(tooltip-mode -1))
;; ...especially on linux
(setq x-gtk-use-system-tooltips nil)
;; Favor vertical splits over horizontal ones. Screens are usually wide.
(setq split-width-threshold 160
split-height-threshold nil)
(setq doc-view-resolution 192)
(fset 'evil-redirect-digit-argument 'ignore)
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
(recentf-mode +1)
(server-start)
(add-to-list 'exec-path "/home/chris/scripts")
(setq initial-major-mode 'org-mode)
(setq initial-scratch-message "#+TITLE: SCRATCH\n#+DESCRIPTION: This buffer is for temporary things")
(setq straight-fix-org t)
(setq straight-check-for-modifications '(check-on-save find-when-checking))
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(setq straight-use-package-by-default t)
(straight-use-package 'use-package)
(setq use-package-verbose t)
(defalias 'yes-or-no-p 'y-or-n-p)
(use-package command-log-mode
:commands command-log-mode)
(use-package all-the-icons)
(use-package doom-modeline
:ensure t
:init
(doom-modeline-mode 1)
(setq doom-modeline-height 35
doom-modeline-bar-width 3
all-the-icons-scale-factor 0.9)
(if (daemonp)
(add-hook 'after-make-frame-functions
(lambda (frame)
(with-selected-frame frame
(setq doom-modeline-icon t))))))
(use-package doom-themes
:ensure t
:init (load-theme 'doom-snazzy t))
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
(use-package smartparens
:defer 1
:config
(smartparens-global-mode +1))
(use-package aggressive-indent
:defer 1
:config
(aggressive-indent-mode -1))
(use-package adaptive-wrap
:defer t)
(use-package which-key
:config
(setq which-key-idle-delay 0.3)
(which-key-mode)
:defer 1)
(executable-find "ssh")
(setq ispell-program-name "hunspell"
ispell-local-dictionary "en_US"
ispell-local-dictionary-alist
;; Please note the list `("-d" "en_US")` contains ACTUAL parameters passed to hunspell
;; You could use `("-d" "en_US,en_US-med")` to check with multiple dictionaries
'(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)))
(use-package no-littering)
;; no-littering doesn't set this by default so we must place
;; auto save files in the same path as it uses for sessions
(setq auto-save-file-name-transforms
`((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))
(let ((alist '((?! . "\\(?:!\\(?:==\\|[!=]\\)\\)")
(?# . "\\(?:#\\(?:###?\\|_(\\|[!#(:=?[_{]\\)\\)")
(?$ . "\\(?:\\$>\\)")
(?& . "\\(?:&&&?\\)")
(?* . "\\(?:\\*\\(?:\\*\\*\\|[/>]\\)\\)")
(?+ . "\\(?:\\+\\(?:\\+\\+\\|[+>]\\)\\)")
(?- . "\\(?:-\\(?:-[>-]\\|<<\\|>>\\|[<>|~-]\\)\\)")
(?. . "\\(?:\\.\\(?:\\.[.<]\\|[.=?-]\\)\\)")
(?/ . "\\(?:/\\(?:\\*\\*\\|//\\|==\\|[*/=>]\\)\\)")
(?: . "\\(?::\\(?:::\\|\\?>\\|[:<-?]\\)\\)")
(?\; . "\\(?:;;\\)")
(?< . "\\(?:<\\(?:!--\\|\\$>\\|\\*>\\|\\+>\\|-[<>|]\\|/>\\|<[<=-]\\|=\\(?:=>\\|[<=>|]\\)\\||\\(?:||::=\\|[>|]\\)\\|~[>~]\\|[$*+/:<=>|~-]\\)\\)")
(?= . "\\(?:=\\(?:!=\\|/=\\|:=\\|=[=>]\\|>>\\|[=>]\\)\\)")
(?> . "\\(?:>\\(?:=>\\|>[=>-]\\|[]:=-]\\)\\)")
(?? . "\\(?:\\?[.:=?]\\)")
(?\[ . "\\(?:\\[\\(?:||]\\|[<|]\\)\\)")
(?\ . "\\(?:\\\\/?\\)")
(?\] . "\\(?:]#\\)")
(?^ . "\\(?:\\^=\\)")
(?_ . "\\(?:_\\(?:|?_\\)\\)")
(?{ . "\\(?:{|\\)")
(?| . "\\(?:|\\(?:->\\|=>\\||\\(?:|>\\|[=>-]\\)\\|[]=>|}-]\\)\\)")
(?~ . "\\(?:~\\(?:~>\\|[=>@~-]\\)\\)"))))
(dolist (char-regexp alist)
(set-char-table-range composition-function-table (car char-regexp)
`([,(cdr char-regexp) 0 font-shape-gstring]))))
(use-package evil
:init
(setq evil-want-integration t
evil-want-keybinding nil
evil-want-C-i-jump nil
evil-want-C-u-scroll t
evil-respect-visual-line-mode t
evil-want-C-u-delete t
evil-undo-system 'undo-redo
scroll-conservatively 101
hscroll-margin 2
scroll-margin 0
scroll-preserve-screen-position t
hscroll-step 1
evil-vsplit-window-right t)
:config
(evil-mode +1))
(use-package evil-collection
:after evil
:config (evil-collection-init))
(use-package general
:init
(general-evil-setup)
:config
(defun chris/edit-emacs-config ()
"open the emacs config to edit"
(interactive)
(find-file (expand-file-name "README.org" user-emacs-directory)))
(defun chris/open-bible ()
"find a bible to open"
(interactive)
(find-file "~/org/bibles/"))
(general-create-definer chris/leader-keys
:keymaps '(normal visual emacs)
:prefix "SPC")
(chris/leader-keys
:states 'normal
:keymaps 'override
"b" '(:ignore t :which-key "buffer")
"t" '(:ignore t :which-key "toggle")
"f" '(:ignore t :which-key "file")
"w" '(:ignore t :which-key "window")
"s" '(:ignore t :which-key "search")
"i" '(:ignore t :which-key "insert")
"o" '(:ignore t :which-key "open")
"oa" '(:ignore t :which-key "org agenda")
"of" '(:ignore t :which-key "elfeed")
"h" '(:ignore t :which-key "help")
"n" '(:ignore t :which-key "notes")
"m" '(:ignore t :which-key "music")
"l" '(:ignore t :which-key "lsp")
"sp" '(:ignore t :which-key "passwords")
"bs" '(consult-buffer :which-key "buffer search")
"bd" '(kill-this-buffer :which-key "kill buffer")
"bi" '(ibuffer :which-key "ibuffer")
"tt" '(consult-theme :which-key "choose theme")
"tl" '(toggle-truncate-lines :which-key "truncate lines")
"ff" '(find-file :which-key "find file")
"fb" '(chris/open-bible :which-key "find bible book")
"fr" '(consult-recent-file :which-key "recent file")
"fs" '(save-buffer :which-key "save")
"fE" '(consult-file-externally :which-key "find file externally")
"fe" '(chris/edit-emacs-config :which-key "open config")
"hf" '(helpful-callable :which-key "describe-function")
"hv" '(helpful-variable :which-key "describe-variable")
"hk" '(helpful-key :which-key "describe-key")
"hF" '(describe-face :which-key "describe-face")
"hb" '(general-describe-keybindings :which-key "describe-bindings")
"hi" '(info :which-key "info manual")
"ht" '(which-key-show-top-level :which-key "show top-level keybindings")
"ss" '(consult-line :which-key "consult search")
"sr" '(consult-ripgrep :which-key "consult ripgrep")
"oP" '(proced :which-key "proced")
"wo" '(other-window :which-key "other window")
"wd" '(delete-window :which-key "other window")
"wv" '(evil-window-vsplit :which-key "split window vertically")
"ws" '(evil-window-split :which-key "split window horizontally")
"wj" '(evil-window-down :which-key "down window")
"wk" '(evil-window-up :which-key "up window")
"wh" '(evil-window-left :which-key "left window")
"wl" '(evil-window-right :which-key "right window")
";" '(execute-extended-command :which-key "execute command")
":" '(eval-expression :which-key "evaluate expression"))
(general-def 'minibuffer-local-map
"C-v" 'evil-paste-after)
(general-def 'normal
"gcc" 'comment-line
"K" 'helpful-at-point
"C-S-l" 'evil-window-increase-width
"C-S-j" 'evil-window-decrease-height
"C-S-k" 'evil-window-increase-height
"C-S-h" 'evil-window-decrease-width)
(general-def 'normal Info-mode-map
"RET" 'Info-follow-nearest-node
"p" 'Info-prev
"n" 'Info-next))
(use-package evil-escape
:after evil
:init (evil-escape-mode +1)
:config
(setq evil-escape-key-sequence "fd"
evil-escape-delay 0.3))
(use-package evil-surround
:after evil
:config
(global-evil-surround-mode +1))
(defun chris/org-mode-setup ()
(interactive)
(org-indent-mode +1)
(toc-org-mode +1)
(visual-fill-column-mode +1)
(display-line-numbers-mode -1)
(variable-pitch-mode +1)
(flyspell-mode +1)
(setq visual-fill-column-width 100
visual-fill-column-center-text t)
;;Let's make sure org-mode faces are inheriting fixed pitch faces.
(dolist (face '(org-block
org-block-begin-line
org-block-end-line
org-code
org-document-info-keyword
org-meta-line
org-table
org-date
org-verbatim))
(set-face-attribute `,face nil :inherit 'fixed-pitch))
(set-face-attribute 'org-block-end-line nil :inherit 'org-block-begin-line)
(set-face-attribute 'org-quote nil :background "#242631" :inherit 'fixed-pitch))
(defun chris/org-agenda-setup ()
(interactive)
(org-indent-mode +1)
(toc-org-mode +1)
(visual-fill-column-mode +1)
(display-line-numbers-mode -1)
(variable-pitch-mode -1)
(toggle-truncate-lines +1)
(evil-normal-state)
(setq visual-fill-column-width 120
visual-fill-column-center-text t))
(use-package org
:straight t
:defer 1
:config
(setq org-startup-indented t
org-edit-src-content-indentation 0
org-agenda-sticky t
org-fontify-quote-and-verse-blocks t
org-src-preserve-indentation t
org-src-window-setup 'other-window
org-agenda-current-time-string "⭠ now ────────────────")
(add-hook 'org-mode-hook 'chris/org-mode-setup)
(org-babel-do-load-languages 'org-babel-load-languages
'((emacs-lisp . t)
(python . t)
(ditaa . t)
(shell . t)))
(setq org-ditaa-jar-path "/usr/bin/ditaa")
(require 'org-tempo)
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("cl" . "src common-lisp"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("yaml" . "src yaml"))
(add-to-list 'org-structure-template-alist '("yml" . "src yaml"))
(add-to-list 'org-structure-template-alist '("q" . "quote"))
(add-to-list 'org-structure-template-alist '("rc" . "src restclient"))
(setq org-capture-templates
'(("t" "Personal todo" entry
(file "todo/todo.org")
(file ".templates/tasks.org") :prepend t)
("n" "Personal notes" entry
(file "todo/notes.org")
"* %u %?\n%i\n%a" :prepend t)
("j" "Journal" entry
(file+olp+datetree +org-capture-journal-file)
"* %U %?\n%i\n%a" :prepend t)
("p" "TFC Plan" entry
(function chris/org-roam-capture-lesson-file)
(file ".templates/tfcplantemplate.org")
:prepend nil
:jump-to-captured t
:empty-lines 1)
("P" "TFC Posts" entry
(file+headline "nvtfc_social_media.org" "Posts")
(file ".templates/posts.org")
:prepend t
:jump-to-captured t)
("r" "Templates for projects")
("rt" "Project-local todo" entry
(file+headline chris/project-todo "Inbox")
"* TODO %?\n%a\n%i\n\n" :prepend t)
("rn" "Project-local notes" entry
(file+headline chris/project-todo "Notes")
"* %U %?\n%a\n%i\n\n" :prepend t)
("rc" "Project-local changelog" entry
(file+headline chris/project-changelog "Changelog")
"* %U %?\n%a\n%i\n\n" :prepend t))
org-capture-use-agenda-date t
org-agenda-timegrid-use-ampm t
org-agenda-show-inherited-tags nil
org-agenda-tags-column -100)
(setq org-agenda-prefix-format '((agenda . " %i %?-12t% s")
(todo . " %i %-12:c")
(tags . " %i %-12:c")
(search . " %i %-12:c")))
(setq org-agenda-category-icon-alist
'(("todo" "~/org/icons/task.png" nil nil :ascent center)
("lesson" "~/org/icons/book.png" nil nil :ascent center)
("dev" "~/org/icons/coding.png" nil nil :ascent center)
("TODO" "~/org/icons/coding.png" nil nil :ascent center)))
(setq org-imenu-depth 4
org-odt-styles-file "/home/chris/org/style.odt"
org-export-with-toc nil
org-export-with-author nil
org-todo-keywords
'((sequence "TODO(t)" "PROJ(p)" "STRT(s)" "WAIT(w)" "HOLD(h)" "|" "DONE(d)" "CNCL(c)")
(sequence "[ ](T)" "[-](S)" "[?](W)" "|" "[X](D)"))
org-agenda-files
'("/home/chris/org/todo/inbox.org"
"/home/chris/org/todo/notes.org"
"/home/chris/org/repetition.org"
"/home/chris/org/tfc_plans.org"
"/home/chris/org/ministry_team.org"
"/home/chris/org/todo/todo.org"
"/home/chris/org/newsletter.org"
"/home/chris/org/archive.org"
"/home/chris/org/nvtfc_social_media.org"
"/home/chris/dev/church-presenter/TODO.org"
"/home/chris/org/lessons/")
org-id-method 'ts
org-agenda-tags-column -75)
(defun chris/org-columns-view ()
"Turn on org-columns overlay and turn off olivetti-mode"
(interactive)
(goto-char (point-min))
(org-content)
(org-columns)
(setq visual-fill-column-width 150))
(defun chris/org-columns-quit ()
"Remove the org-columns overlay and turn on olivetti-mode"
(interactive)
(org-columns-quit)
(chris/org-mode-setup)
(setq visual-fill-column-width 100)
(setq visual-fill-column-width 100))
;; (add-hook 'org-agenda-finalize-hook 'evil-normal-state)
(add-hook 'org-agenda-finalize-hook 'chris/org-agenda-setup)
(advice-add 'org-agenda-todo :after #'org-save-all-org-buffers)
(setq org-refile-targets '((org-agenda-files . (:maxlevel . 6))))
(setq org-agenda-window-setup 'current-window)
(defun chris/org-agenda ()
"create a window that houses my org-agenda"
(interactive)
(with-selected-frame (make-frame
'((name . "org-agenda")
(width . 100)))
(org-agenda-list)))
(setq org-latex-packages-alist '(("margin=2cm" "geometry" nil)))
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"c" 'org-capture
"rr" 'org-refile
"e" 'org-export-dispatch
"oa" 'org-agenda-list
"gt" 'org-babel-tangle)
('normal org-agenda-mode-map
"q" 'org-agenda-quit
"r" 'org-agenda-redo
"d" 'org-agenda-deadline
"s" 'org-agenda-schedule
"t" 'org-agenda-todo
"c" 'org-agenda-capture)
('normal org-columns-map
"j" 'outline-next-heading
"h" 'outline-previous-heading
"q" 'chris/org-columns-quit)
('normal org-mode-map
"RET" 'chris/org-dwim-at-point
"gC" 'chris/org-columns-view
"ge" 'org-edit-src-code
"gr" 'revert-buffer
"ze" 'org-emphasize
"S" 'org-schedule
"t" 'org-todo)
('insert org-mode-map
"C-i" 'completion-at-point)
('normal 'org-src-mode-map
"q" 'org-edit-src-abort))
(defun chris/org-roam-capture-lesson-file ()
"Function to return the lesson file that is needed for TFC plan capture and move to correct position for plan insertion"
(interactive)
;; (unless org-roam-mode (org-roam-mode +1))
(let ((node (org-roam-node-read)))
(org-roam-node-visit node)
(goto-char (point-min))
(search-forward "PLAN")))
(defun chris/project-todo ()
(concat (projectile-project-root) "TODO.org"))
(defun chris/project-changelog ()
(concat (projectile-project-root) "CHANGELOG.org"))
(defun chris/org-babel-tangle-config ()
(when (string-equal (buffer-file-name)
(expand-file-name "README.org" user-emacs-directory))
(let ((org-confirm-babel-evaluate nil))
(org-babel-tangle))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'chris/org-babel-tangle-config
:append :local)))
(use-package evil-org
:ensure t
:after org
:hook (org-mode . (lambda () evil-org-mode))
:config
;; (add-to-list 'evil-digit-bound-motions 'evil-org-beginning-of-line)
;; (evil-define-key 'motion 'evil-org-mode
;; (kbd "0") 'evil-org-beginning-of-line)
(require 'evil-org-agenda)
(evil-org-agenda-set-keys))
(use-package org-super-agenda
:after org
:init
(setq org-super-agenda-groups '((:name "📅 Today"
:time-grid t
:scheduled today)
(:name "Due Today"
:deadline today)
(:name "Important"
:priority "A")
(:name "Development"
:category "TODO"
:category "dev")
(:name "Overdue"
:time-grid t
:scheduled past
:deadline past)
(:name "Due soon"
:deadline future)))
:config
(org-super-agenda-mode +1)
(setq org-super-agenda-header-map nil))
(use-package org-roam
:after org
:ensure t
:init
(setq org-roam-v2-ack t)
:config
(setq org-roam-directory "~/org"
org-roam-buffer-width 0.25
org-roam-file-exclude-regexp ".stversion.*\|.stfolder.*\|.*~.*\|.*sync.*"
org-roam-db-location "~/.dotemacs/org-roam.db"
org-roam-completion-everywhere t
org-roam-capture-templates
'(("d" "default" plain "%?"
:if-new (file+head "${slug}.org"
"#+TITLE: ${title}\n#+AUTHOR: Chris Cochrun\n#+CREATED: %<%D - %I:%M %p>\n\nj ")
:unnarrowed t)
("b" "bible" plain "%?"
:if-new (file+head "${slug}.org"
"#+TITLE: ${title}\n#+AUTHOR: Chris Cochrun\n#+CREATED: %<%D - %I:%M %p>\n- tags %^G\n\n* %?")
:unnarrowed t)
("l" "TFC Lesson" plain (file ".templates/lessontemplate.org")
:if-new (file+head "lessons/${slug}.org"
"#+TITLE: ${title}\n#+AUTHOR: Chris Cochrun\n#+CREATED: %<%D - %I:%M %p>\n")
:unnarrowed t))
org-roam-dailies-capture-templates
'(("d" "daily" plain #'org-roam-capture--get-point ""
:immediate-finish t
:file-name "%<%Y-%m-%d>"
:head "#+TITLE: %<%Y-%m-%d>\n#+AUTHOR: Chris Cochrun\n#+CREATED: %<%D - %I:%M %p>\n\n* HFL\n* Tasks\n* Family\n** How Do I Love Abbie?")
("b" "biblical daily" plain #'org-roam-capture--get-point ""
:immediate-finish t
:file-name "%<%Y-%m-%d>-bib"
:head "#+TITLE: %<%Y-%m-%d> - Biblical\n#+AUTHOR: Chris Cochrun")))
(org-roam-setup)
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"nf" '(org-roam-node-find :which-key "org roam ff")
"nr" 'org-roam-buffer-toggle
"ni" 'org-roam-node-insert
"nc" 'org-roam-capture
"njt" 'org-roam-dailies-capture-today
"ng" 'org-roam-graph))
(use-package websocket)
(use-package org-roam-ui
:straight (:host github :repo "org-roam/org-roam-ui" :files ("*.el" "out"))
:after org-roam
:config
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-update-on-save t
org-roam-ui-open-on-start t))
(use-package org-modern
:straight (:host github :repo "minad/org-modern")
:config
(custom-set-faces
'(org-modern-tag ((t :background "#9aedfe" :foreground "#282a36")))
)
(global-org-modern-mode +1)
)
(defun chris/org-dwim-at-point (&optional arg)
"Do-what-I-mean at point.
If on a:
- checkbox list item or todo heading: toggle it.
- clock: update its time.
- headline: cycle ARCHIVE subtrees, toggle latex fragments and inline images in
subtree; update statistics cookies/checkboxes and ToCs.
- footnote reference: jump to the footnote's definition
- footnote definition: jump to the first reference of this footnote
- table-row or a TBLFM: recalculate the table's formulas
- table-cell: clear it and go into insert mode. If this is a formula cell,
recaluclate it instead.
- babel-call: execute the source block
- statistics-cookie: update it.
- latex fragment: toggle it.
- link: follow it
- otherwise, refresh all inline images in current tree."
(interactive "P")
(let* ((context (org-element-context))
(type (org-element-type context)))
;; skip over unimportant contexts
(while (and context (memq type '(verbatim code bold italic underline strike-through subscript superscript)))
(setq context (org-element-property :parent context)
type (org-element-type context)))
(pcase type
(`headline
(cond ((memq (bound-and-true-p org-goto-map)
(current-active-maps))
(org-goto-ret))
((and (fboundp 'toc-org-insert-toc)
(member "TOC" (org-get-tags)))
(toc-org-insert-toc)
(message "Updating table of contents"))
((string= "ARCHIVE" (car-safe (org-get-tags)))
(org-force-cycle-archived))
((or (org-element-property :todo-type context)
(org-element-property :scheduled context))
(org-todo
(if (eq (org-element-property :todo-type context) 'done)
(or (car (chris/org-get-todo-keywords-for (org-element-property :todo-keyword context)))
'todo)
'done))))
;; Update any metadata or inline previews in this subtree
(org-update-checkbox-count)
(org-update-parent-todo-statistics)
(when (and (fboundp 'toc-org-insert-toc)
(member "TOC" (org-get-tags)))
(toc-org-insert-toc)
(message "Updating table of contents"))
(let* ((beg (if (org-before-first-heading-p)
(line-beginning-position)
(save-excursion (org-back-to-heading) (point))))
(end (if (org-before-first-heading-p)
(line-end-position)
(save-excursion (org-end-of-subtree) (point))))
(overlays (ignore-errors (overlays-in beg end)))
(latex-overlays
(cl-find-if (lambda (o) (eq (overlay-get o 'org-overlay-type) 'org-latex-overlay))
overlays))
(image-overlays
(cl-find-if (lambda (o) (overlay-get o 'org-image-overlay))
overlays)))
(chris/org--toggle-inline-images-in-subtree beg end)
(if (or image-overlays latex-overlays)
(org-clear-latex-preview beg end)
(org--latex-preview-region beg end))))
(`clock (org-clock-update-time-maybe))
(`footnote-reference
(org-footnote-goto-definition (org-element-property :label context)))
(`footnote-definition
(org-footnote-goto-previous-reference (org-element-property :label context)))
((or `planning `timestamp)
(org-follow-timestamp-link))
((or `table `table-row)
(if (org-at-TBLFM-p)
(org-table-calc-current-TBLFM)
(ignore-errors
(save-excursion
(goto-char (org-element-property :contents-begin context))
(org-call-with-arg 'org-table-recalculate (or arg t))))))
(`table-cell
(org-table-blank-field)
(org-table-recalculate arg)
(when (and (string-empty-p (string-trim (org-table-get-field)))
(bound-and-true-p evil-local-mode))
(evil-change-state 'insert)))
(`babel-call
(org-babel-lob-execute-maybe))
(`statistics-cookie
(save-excursion (org-update-statistics-cookies arg)))
((or `src-block `inline-src-block)
(org-babel-execute-src-block))
((or `latex-fragment `latex-environment)
(org-latex-preview))
(`link
(let* ((lineage (org-element-lineage context '(link) t))
(path (org-element-property :path lineage)))
(if (or (equal (org-element-property :type lineage) "img")
(and path (image-type-from-file-name path)))
(chris/org--toggle-inline-images-in-subtree
(org-element-property :begin lineage)
(org-element-property :end lineage))
(org-open-at-point arg))))
(`paragraph
(let ((match (and (org-at-item-checkbox-p) (match-string 1))))
(org-toggle-checkbox)))
(_
(if (or (org-in-regexp org-ts-regexp-both nil t)
(org-in-regexp org-tsr-regexp-both nil t)
(org-in-regexp org-link-any-re nil t))
(call-interactively #'org-open-at-point)
(chris/org--toggle-inline-images-in-subtree
(org-element-property :begin context)
(org-element-property :end context)))))))
(defun chris/org-get-todo-keywords-for (&optional keyword)
"Returns the list of todo keywords that KEYWORD belongs to."
(when keyword
(cl-loop for (type . keyword-spec)
in (cl-remove-if-not #'listp org-todo-keywords)
for keywords =
(mapcar (lambda (x) (if (string-match "^\\([^(]+\\)(" x)
(match-string 1 x)
x))
keyword-spec)
if (eq type 'sequence)
if (member keyword keywords)
return keywords)))
(defun chris/org--toggle-inline-images-in-subtree (&optional beg end refresh)
"Refresh inline image previews in the current heading/tree."
(let ((beg (or beg
(if (org-before-first-heading-p)
(line-beginning-position)
(save-excursion (org-back-to-heading) (point)))))
(end (or end
(if (org-before-first-heading-p)
(line-end-position)
(save-excursion (org-end-of-subtree) (point)))))
(overlays (cl-remove-if-not (lambda (ov) (overlay-get ov 'org-image-overlay))
(ignore-errors (overlays-in beg end)))))
(dolist (ov overlays nil)
(delete-overlay ov)
(setq org-inline-image-overlays (delete ov org-inline-image-overlays)))
(when (or refresh (not overlays))
(org-display-inline-images t t beg end)
t)))
(use-package unicode-fonts
:ensure t
:config
(unicode-fonts-setup))
(use-package emojify
:ensure t
:hook (after-init . global-emojify-mode)
:config
(setq emojify-display-style 'image)
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"ie" '(emojify-insert-emoji :which-key "insert emoji")))
(global-auto-revert-mode 1)
(setq global-auto-revert-non-file-buffers t)
(use-package visual-fill-column
:after org
:config
(setq visual-fill-column-width 100
visual-fill-column-center-text t))
(use-package toc-org
:after org)
(use-package pulsar
:config
(setq pulsar-pulse-functions
;; NOTE 2022-04-09: The commented out functions are from before
;; the introduction of `pulsar-pulse-on-window-change'. Try that
;; instead.
'(recenter-top-bottom
move-to-window-line-top-bottom
reposition-window
;; bookmark-jump
;; other-window
;; delete-window
;; delete-other-windows
forward-page
backward-page
scroll-up-command
scroll-down-command
;; windmove-right
;; windmove-left
;; windmove-up
;; windmove-down
;; windmove-swap-states-right
;; windmove-swap-states-left
;; windmove-swap-states-up
;; windmove-swap-states-down
;; tab-new
;; tab-close
;; tab-next
org-next-visible-heading
org-previous-visible-heading
org-forward-heading-same-level
org-backward-heading-same-level
outline-backward-same-level
outline-forward-same-level
outline-next-visible-heading
outline-previous-visible-heading
outline-up-heading))
(setq pulsar-pulse-on-window-change t)
(setq pulsar-pulse t)
(setq pulsar-delay 0.055)
(setq pulsar-iterations 10)
(setq pulsar-face 'ffap)
(setq pulsar-highlight-face 'pulsar-yellow)
(pulsar-global-mode 1)
;; integration with the `consult' package:
(add-hook 'consult-after-jump-hook #'pulsar-recenter-top)
(add-hook 'consult-after-jump-hook #'pulsar-reveal-entry)
;; integration with the built-in `imenu':
(add-hook 'imenu-after-jump-hook #'pulsar-recenter-top)
(add-hook 'imenu-after-jump-hook #'pulsar-reveal-entry))
(use-package vertico
:init
(vertico-mode)
;; Different scroll margin
;; (setq vertico-scroll-margin 0)
;; Show more candidates
(setq vertico-count 10)
;; Grow and shrink the Vertico minibuffer
(setq vertico-resize t)
;; Optionally enable cycling for `vertico-next' and `vertico-previous'.
(setq vertico-cycle t)
:general
(general-def 'vertico-map
"C-j" 'vertico-next
"C-k" 'vertico-previous)
)
;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
:init
(savehist-mode))
;; A few more useful configurations...
(use-package emacs
:init
;; Add prompt indicator to `completing-read-multiple'.
;; Alternatively try `consult-completing-read-multiple'.
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
;; (setq read-extended-command-predicate
;; #'command-completion-default-include-p)
;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t))
(use-package consult
:after vertico
:config
(setq consult-narrow-key "'"
consult-project-root-function 'projectile-project-root)
(defun chris/consult-ripgrep-for-stepdata ()
"Make ripgrep search hidden files for stepdata"
(interactive)
(let ((consult-ripgrep-args
(concat "rg "
"--null "
"--line-buffered "
"--color=never "
"--max-columns=1000 "
"--path-separator / "
"--no-heading "
"--line-number "
;; adding these to default
"--smart-case "
"--hidden "
;; defaults
"."
)))
(consult-ripgrep)))
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"si" 'consult-imenu
"so" 'consult-org-heading
"sm" 'bookmark-jump
"sy" 'consult-yank-from-kill-ring))
(use-package marginalia
:bind (:map minibuffer-local-map
("C-M-a" . marginalia-cycle)
;; :map embark-general-map
;; ("A" . marginalia-cycle)
)
;; The :init configuration is always executed (Not lazy!)
:init
;; Must be in the :init section of use-package such that the mode gets
;; enabled right away. Note that this forces loading the package.
(marginalia-mode)
;; When using Selectrum, ensure that Selectrum is refreshed when cycling annotations.
;; (advice-add #'marginalia-cycle :after
;; (lambda () (when (bound-and-true-p selectrum-mode) (selectrum-exhibit))))
;; Prefer richer, more heavy, annotations over the lighter default variant.
(setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
:after vertico
:config
(setq marginalia--cache-size 60000))
(use-package all-the-icons-completion
:after vertico
:config
(all-the-icons-completion-mode))
(use-package embark
:ensure t
:general
('vertico-map
"C-'" 'embark-act)
('normal 'org-mode-map
"C-'" 'embark-act)
:config
(defun embark-which-key-indicator ()
"An embark indicator that displays keymaps using which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
targets."
(lambda (&optional keymap targets prefix)
(if (null keymap)
(which-key--hide-popup-ignore-command)
(which-key--show-keymap
(if (eq (plist-get (car targets) :type) 'embark-become)
"Become"
(format "Act on %s '%s'%s"
(plist-get (car targets) :type)
(embark--truncate-target (plist-get (car targets) :target))
(if (cdr targets) "" "")))
(if prefix
(pcase (lookup-key keymap prefix 'accept-default)
((and (pred keymapp) km) km)
(_ (key-binding prefix 'accept-default)))
keymap)
nil nil t (lambda (binding)
(not (string-suffix-p "-argument" (cdr binding))))))))
(setq embark-indicators
'(embark-which-key-indicator
embark-highlight-indicator
embark-isearch-highlight-indicator))
(defun embark-hide-which-key-indicator (fn &rest args)
"Hide the which-key indicator immediately when using the completing-read prompter."
(which-key--hide-popup-ignore-command)
(let ((embark-indicators
(remq #'embark-which-key-indicator embark-indicators)))
(apply fn args)))
(advice-add #'embark-completing-read-prompter
:around #'embark-hide-which-key-indicator)
)
(use-package embark-consult)
(use-package corfu
:ensure t
;; 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-no-match 'separator) ;; Never quit, even if there is no match
(corfu-preview-current 'insert) ;; Enable current candidate preview
(corfu-preselect-first nil) ;; Enable candidate preselection
(corfu-on-exact-match 'insert) ;; Configure handling of exact matches
(corfu-echo-documentation '(1.0 . 0.2)) ;; Disable documentation in the echo area
(corfu-scroll-margin 5) ;; Use scroll margin
(corfu-count 15)
(corfu-auto-prefix 2)
;; You may want to 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-/).
:init
(global-corfu-mode)
:general
('corfu-map
"C-j" 'corfu-next
"C-k" 'corfu-previous
"M-SPC" 'corfu-insert-separator))
;; Optionally use the `orderless' completion style. See `+orderless-dispatch'
;; in the Consult wiki for an advanced Orderless style dispatcher.
;; Enable `partial-completion' for files to allow path expansion.
;; You may prefer to use `initials' instead of `partial-completion'.
(use-package orderless
:ensure t
: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)
completion-category-defaults nil
completion-category-overrides '((file (styles . (partial-completion)))))
(defun flex-if-twiddle (pattern _index _total)
(when (string-suffix-p "~" pattern)
`(orderless-flex . ,(substring pattern 0 -1))))
(defun first-initialism (pattern index _total)
(if (= index 0) 'orderless-initialism))
(defun without-if-bang (pattern _index _total)
(cond
((equal "!" pattern)
'(orderless-literal . ""))
((string-prefix-p "!" pattern)
`(orderless-without-literal . ,(substring pattern 1)))))
(setq orderless-matching-styles '(orderless-literal orderless-regexp)
orderless-style-dispatchers '(flex-if-twiddle
without-if-bang))
)
;; Use dabbrev with Corfu!
(use-package dabbrev
:after corfu
;; Swap M-/ and C-M-/
:bind (("M-/" . dabbrev-completion)
("C-M-/" . dabbrev-expand)))
(use-package cape
:ensure t
;; Bind dedicated completion commands
:bind (("C-c p p" . completion-at-point) ;; capf
("C-c p t" . complete-tag) ;; etags
("C-c p d" . cape-dabbrev) ;; or dabbrev-completion
("C-c p f" . cape-file)
("C-c p k" . cape-keyword)
("C-c p s" . cape-symbol)
("C-c p a" . cape-abbrev)
("C-c p i" . cape-ispell)
("C-c p l" . cape-line)
("C-c p w" . cape-dict)
("C-c p \\" . cape-tex)
("C-c p _" . cape-tex)
("C-c p ^" . cape-tex)
("C-c p &" . cape-sgml)
("C-c p r" . cape-rfc1345))
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
(add-to-list 'completion-at-point-functions #'cape-file)
;; (add-to-list 'completion-at-point-functions #'cape-tex)
(add-to-list 'completion-at-point-functions #'cape-keyword)
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
;;(add-to-list 'completion-at-point-functions #'cape-sgml)
;;(add-to-list 'completion-at-point-functions #'cape-rfc1345)
;;(add-to-list 'completion-at-point-functions #'cape-abbrev)
(add-to-list 'completion-at-point-functions #'cape-ispell)
;;(add-to-list 'completion-at-point-functions #'cape-dict)
;; (add-to-list 'completion-at-point-functions #'cape-symbol)
;;(add-to-list 'completion-at-point-functions #'cape-line)
:config
(setq cape-dabbrev-min-length 2)
)
(use-package devdocs
:general
(chris/leader-keys 'normal
"hd" 'devdocs-lookup))
(use-package yasnippet
:config
(setq yas-snippet-dirs (list (expand-file-name "yasnippets/" user-emacs-directory)))
(yas-global-mode 1))
(use-package tempel
:bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
("M-'" . tempel-insert)
("C-M-<return>" . tempel-done))
:init
;; Setup completion at point
(defun tempel-setup-capf ()
;; Add the Tempel Capf to `completion-at-point-functions'. `tempel-expand'
;; only triggers on exact matches. Alternatively use `tempel-complete' if
;; you want to see all matches, but then Tempel will probably trigger too
;; often when you don't expect it.
;; NOTE: We add `tempel-expand' *before* the main programming mode Capf,
;; such that it will be tried first.
(setq-local completion-at-point-functions
(cons #'tempel-complete
completion-at-point-functions)))
(add-hook 'prog-mode-hook 'tempel-setup-capf)
(add-hook 'text-mode-hook 'tempel-setup-capf)
;; Optionally make the Tempel templates available to Abbrev,
;; either locally or globally. `expand-abbrev' is bound to C-x '.
;; (add-hook 'prog-mode-hook #'tempel-abbrev-mode)
;; (tempel-global-abbrev-mode)
:general
(chris/leader-keys
"it" 'tempel-insert)
)
(use-package projectile
:ensure t
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"op" 'projectile-switch-open-project
"gc" 'projectile-compile-project
"gr" 'projectile-run-project
"fp" 'project-find-file
"fP" 'project-switch-project))
(use-package simple-httpd
:ensure t)
(use-package avy
:after evil)
(use-package evil-avy
:after avy
:general
(general-define-key
:states 'normal
:keymaps '(override magit-mode-map)
"F" 'magit-pull)
(general-def 'normal
"gl" 'avy-goto-line))
(use-package ace-link
:after avy
:general
(general-def 'normal
"gL" 'ace-link))
(setq display-buffer-alist
'(("\\*e?shell\\*"
(display-buffer-in-side-window)
(side . bottom)
(window-height . 0.25))
("*helpful*"
(display-buffer-in-side-window)
(side . right)
(window-width . 0.4))
("*compilation*"
(display-buffer-in-side-window)
(side . right)
(window-width . 0.4))
("*org-roam*"
(display-buffer-in-side-window)
(side . right)
(window-width . 0.4))
("\\*elfeed-entry\\*"
(display-buffer-in-side-window)
(side . bottom)
(window-height . 0.60))
("*Agenda Commands*"
(display-buffer-in-side-window)
(side . right)
(window-width . 0.30))
("\\*Bongo-Elfeed Queue\\*"
(display-buffer-in-side-window)
(side . bottom)
(window-height . 0.25))))
(defun chris/kill-buffer-frame ()
"Kills the active buffer and frame"
(interactive)
(kill-this-buffer)
(delete-frame))
(use-package ace-window
:config (ace-window-display-mode)
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"ww" '(ace-window :which-key "select window")))
(use-package helpful
:ensure nil
:commands (helpful-callable helpful-variable helpful-command helpful-key)
:general
(general-def 'normal 'helpful-mode-map
"q" 'helpful-kill-buffers)
:config
(defun helpful--autoloaded-p (sym buf)
"Return non-nil if function SYM is autoloaded."
(-when-let (file-name (buffer-file-name buf))
(setq file-name (s-chop-suffix ".gz" file-name))
(help-fns--autoloaded-p sym file-name)))
(defun helpful--skip-advice (docstring)
"Remove mentions of advice from DOCSTRING."
(let* ((lines (s-lines docstring))
(relevant-lines
(--take-while
(not (or (s-starts-with-p ":around advice:" it)
(s-starts-with-p "This function has :around advice:" it)))
lines)))
(s-trim (s-join "\n" relevant-lines)))))
(use-package format-all
:config
(format-all-mode +1)
(setq format-all-formatters '("Emacs Lisp" emacs-lisp))
:defer 1)
(defvar read-symbol-positions-list nil)
(add-hook 'comint-mode-hook 'ansi-color-for-comint-mode-on)
(add-hook 'comint-mode-hook 'hl-line-mode)
(add-hook 'prog-mode-hook 'hl-line-mode)
(add-hook 'prog-mode-hook 'hs-minor-mode)
(add-hook 'c++-mode-hook 'lsp)
(use-package lua-mode
:mode ("\\.lua\\'" . lua-mode))
(use-package nix-mode
:mode "\\.nix\\'")
(use-package lsp-mode
:commands (lsp lsp-deferred)
:custom
(lsp-completion-provider :none)
:hook
(c++-mode . lsp-deferred)
(lsp-completion-mode . my/lsp-mode-setup-completion)
:init
(setq lsp-keymap-prefix "C-c l")
(defun my/lsp-mode-setup-completion ()
(setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
'(flex)))
:config
(setq lsp-lens-enable t
lsp-signature-auto-activate nil
read-process-output-max (* 1024 1024))
(lsp-enable-which-key-integration t)
(add-to-list 'lsp-language-id-configuration '(qml-mode . "qml"))
(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection "qml-lsp")
:activation-fn (lsp-activate-on "qml")
:server-id 'qml))
:general
(general-def 'normal c++-mode-map
"gf" 'lsp-clangd-find-other-file))
(use-package lsp-ui
:hook (lsp-mode . lsp-ui-mode)
:custom
(lsp-ui-doc-position 'at-point))
(use-package lsp-treemacs
:after lsp)
(use-package fennel-mode
:mode ("\\.fnl\\'" . fennel-mode))
(use-package friar
:straight (:host github :repo "warreq/friar" :branch "master"
:files (:defaults "*.lua" "*.fnl"))
:after fennel-mode)
(use-package yaml-mode
:mode ("\\.yml\\'" . yaml-mode))
(use-package docker
:defer t
:config
(setq docker-run-as-root t))
(use-package docker-tramp
:after docker)
(use-package fish-mode
:mode ("\\.fish\\'" . fish-mode))
(use-package markdown-mode
:mode ("\\.md\\'" . markdown-mode)
:config
(setq markdown-fontify-code-blocks-natively t))
(use-package qml-mode
:mode ("\\.qml\\'" . qml-mode))
;; (use-package company-qml
;; :after qml-mode
;; :config
;; ;; (add-to-list 'company-backends 'company-qml)
;; )
;; (setq company-backends
;; '(company-bbdb company-semantic company-cmake company-capf company-clang company-files
;; (company-dabbrev-code company-gtags company-etags company-keywords)
;; company-oddmuse company-dabbrev))
;; (use-package qt-pro-mode
;; :after qml-mode)
(use-package csv-mode
:mode ("\\.csv\\'" . csv-mode))
(use-package restclient
:commands (restclient-mode))
(use-package ob-restclient
:after org)
(use-package dart-mode
:mode ("\\.dart\\'" . dart-mode)
:hook (dart-mode . lsp-deferred)
:general
(general-def 'normal dart-mode-map
"gr" 'flutter-run-or-hot-reload
"gR" 'lsp-dart-dap-flutter-hot-restart))
(use-package lsp-dart)
(use-package flutter
:after dart
:general
(chris/leader-keys dart-mode-map
"rf" 'flutter-run-or-hot-reload))
(use-package hover
:after dart)
(add-to-list 'exec-path "/opt/android-sdk/cmdline-tools/latest/bin")
(use-package dired
:ensure nil
:straight nil
:config
(defun chris/dired-open-xdg ()
"Open the file-at-point in the appropriate program"
(interactive)
(let ((file (file-truename (ignore-errors (dired-get-file-for-visit)))))
(message file)
(call-process "xdg-open" nil 0 nil file)))
(setq dired-dwim-target t
delete-by-moving-to-trash t)
(setq dired-listing-switches "-aoh --group-directories-first")
(setq dired-hide-details-hide-symlink-targets nil
dired-kill-when-opening-new-dired-buffer t)
(add-hook 'dired-mode-hook #'dired-hide-details-mode)
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"od" '(dired-jump :which-key "open dired here")
"oD" '(dired :which-key "open dired select"))
('normal dired-mode-map
"q" 'kill-this-buffer
"C-<return>" 'chris/dired-open-xdg
"C-'" 'embark-act))
(defun chris/dired-yank-filename ()
"Get the full filename from file at point and put into kill-ring"
(interactive)
(let* ((file (dired-get-filename)))
(clipboard-kill-ring-save nil nil file)))
(use-package all-the-icons-dired
:hook (dired-mode . all-the-icons-dired-mode))
(use-package dired-single
:after dired
:general
(general-def 'normal dired-mode-map
"h" 'dired-single-up-directory
"l" 'dired-single-buffer))
(use-package dired-rainbow
:after dired
:config
(defconst chris/dired-media-files-extensions
'("mp3" "mp4" "MP3" "MP4" "avi" "mpg" "flv" "ogg" "opus")
"Media files.")
(defconst chris/dired-image-files-extensions
'("png" "jpg" "PNG" "JPG" "jpeg" "JPEG" "gif" "GIF")
"image files")
(dired-rainbow-define html "#4e9a06" ("htm" "html" "xhtml"))
(dired-rainbow-define media "#f3f99d" chris/dired-media-files-extensions)
(dired-rainbow-define image "#5af78e" chris/dired-image-files-extensions)
(dired-rainbow-define log (:inherit default :italic t) ".*\\.log"))
(use-package diredfl
:after dired
:config (diredfl-global-mode +1))
(use-package dired-rsync
:general
(general-def 'normal dired-mode-map
"C" 'dired-rsync))
(require 'tramp)
(add-to-list 'tramp-default-proxies-alist
'(nil "\\`root\\'" "/ssh:%h:"))
(add-to-list 'tramp-default-proxies-alist
'((regexp-quote (system-name)) nil nil))
(use-package ledger-mode)
(use-package mu4e
:ensure nil
:config
(setq mail-user-agent 'mu4e-user-agent)
(setq mu4e-maildir "~/Maildir"
user-full-name "Chris Cochrun"
mu4e-change-filenames-when-moving t
mu4e-get-mail-command "mbsync -a"
mu4e-update-interval (* 15 60)
mu4e-attachment-dir "/home/chris/nextcloud/home/Documents/attachments"
mu4e-completing-read-function #'completing-read)
(setq mu4e-contexts
(list
(make-mu4e-context
:name "work"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/office" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "chris@tfcconnection.org")
(mu4e-sent-folder . "/office/Sent Items/")
(mu4e-drafts-folder . "/office/Drafts")
(mu4e-trash-folder . "/office/Deleted Items")
(mu4e-refile-folder . "/office/Archive")
(smtpmail-smtp-user . "chris@tfcconnection.org")
(smtpmail-starttls-credentials . '(("smtp.office365.com" 587 nil nil)))
(smtpmail-auth-credentials . '(("smtp.office365.com" 587 "chris@tfcconnection.org" nil)))
(smtpmail-smtp-server . "smtp.office365.com")
(mu4e-compose-signature . "Praising God in all things,\nChris Cochrun")))
(make-mu4e-context
:name "outlook"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/outlook" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "chris.cochrun@outlook.com")
(mu4e-sent-folder . "/outlook/Sent/")
(mu4e-drafts-folder . "/outlook/Drafts")
(mu4e-trash-folder . "/outlook/Deleted")
(mu4e-refile-folder . "/outlook/Archive")
(smtpmail-smtp-user . "chris.cochrun@outlook.com")
(mu4e-compose-signature . "Praising God in all things,\nChris Cochrun")))
(make-mu4e-context
:name "personal"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/cochrun" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "chris@cochrun.xyz")
(mu4e-sent-folder . "/cochrun/Sent/")
(mu4e-drafts-folder . "/cochrun/Drafts")
(mu4e-trash-folder . "/cochrun/Trash")
(mu4e-refile-folder . "/cochrun/Archive")
(smtpmail-smtp-user . "chris@cochrun.xyz")
(smtpmail-starttls-credentials . '(("mail.cochrun.xyz" 587 nil nil)))
(smtpmail-auth-credentials . '(("mail.cochrun.xyz" 587 "chris@cochrun.xyz" nil)))
(smtpmail-smtp-server . "mail.cochrun.xyz")
(mu4e-compose-signature . "Praising God in all things,\nChris Cochrun")))
(make-mu4e-context
:name "gmail"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/gmail" (mu4e-message-field msg :maildir))))
:vars '((user-mail-address . "ccochrun21@gmail.com")
(mu4e-sent-folder . "/gmail/[Gmail].Sent Mail/")
(smtpmail-smtp-user . "ccochrun21@gmail.com")
(mu4e-compose-signature . "Praising God in all things,\nChris Cochrun")))))
;; Add the ability to send email
(setq message-send-mail-function 'smtpmail-send-it
starttls-use-gnutls t
smtpmail-default-smtp-server "mail.cochrun.xyz"
smtpmail-smtp-service 587)
;; shortcuts in the jumplist by pressing "J" in the mu4e buffer
(setq mu4e-maildir-shortcuts
'((:maildir "/office/Archive" :key ?a)
(:maildir "/office/INBOX" :key ?i)
(:maildir "/cochrun/INBOX" :key ?p)
(:maildir "/outlook/INBOX" :key ?l)
(:maildir "/office/Junk Email" :key ?j)
(:maildir "/office/INBOX/Website Forms" :key ?f)
(:maildir "/gmail/INBOX" :key ?g)
(:maildir "/office/Sent Items" :key ?s)))
;; (add-to-list mu4e-headers-actions ("org capture message" . mu4e-org-store-and-capture))
(setq mu4e-bookmarks
'((:name "Unread messages"
:query "flag:unread AND NOT flag:trashed AND NOT maildir:\"/outlook/Junk\" AND NOT maildir:\"/office/Junk Email\" AND NOT maildir:\"/outlook/Deleted\" AND NOT maildir:\"/office/Deleted Items\""
:key 117)
(:name "Today's messages"
:query "date:today..now"
:key 116)
(:name "Last 7 days"
:query "date:7d..now"
:hide-unread t
:key 119)
(:name "Messages with images"
:query "mime:image/*"
:key 112)))
(setq mu4e-mu-binary "/usr/bin/mu"
mu4e-view-prefer-html nil
shr-color-visible-luminance-min 80)
(setq mu4e-use-fancy-chars t
mu4e-headers-draft-mark '("D" . "")
mu4e-headers-flagged-mark '("F" . "")
mu4e-headers-new-mark '("N" . "")
mu4e-headers-passed-mark '("P" . "")
mu4e-headers-replied-mark '("R" . "")
mu4e-headers-seen-mark '("S" . "")
mu4e-headers-trashed-mark '("T" . "")
mu4e-headers-attach-mark '("a" . "")
mu4e-headers-encrypted-mark '("x" . "")
mu4e-headers-signed-mark '("s" . "")
mu4e-headers-unread-mark '("u" . ""))
(setq mu4e-headers-fields
'((:human-date . 12)
(:flags . 6)
(:from . 22)
(:subject)))
(setq mu4e-view-actions
'(("capture message" . mu4e-action-capture-message)
("view in browser" . mu4e-action-view-in-browser)
("show this thread" . mu4e-action-show-thread)))
(defun chris/setup-mu4e-headers ()
(toggle-truncate-lines +1)
(display-line-numbers-mode -1))
(defun chris/setup-mu4e-view ()
(display-line-numbers-mode -1)
(toggle-truncate-lines +1)
(setq visual-fill-column-center-text t)
(setq visual-fill-column-width 100)
(visual-fill-column-mode +1))
(remove-hook 'mu4e-main-mode-hook '(display-line-numbers-mode -1))
(add-hook 'mu4e-headers-mode-hook #'chris/setup-mu4e-headers)
(add-hook 'mu4e-view-mode-hook #'chris/setup-mu4e-view)
(mu4e t)
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"om" 'mu4e)
(general-def 'normal mu4e-view-mode-map
"ga" 'mu4e-view-save-attachments))
(use-package org-msg
:hook (mu4e-compose-mode . org-msg-edit-mode)
:config
(org-msg-mode)
(setq org-msg-startup "inlineimages"
org-msg-greeting-name-limit 3
org-msg-default-alternatives '(html text)))
(use-package calfw
:commands chris/calfw-calendar-open
:config
(defun chris/calfw-calendar-open ()
(interactive)
(cfw:open-calendar-buffer
:contents-sources
(list
(cfw:org-create-source
"Cyan") ; org-agenda source
(cfw:ical-create-source
"NV" "https://www.nvhuskies.org/vnews/display.v?ical" "Green") ; School Calendar
(cfw:ical-create-source
"Outlook" "https://outlook.office365.com/owa/calendar/62a0d491bec4430e825822afd2fd1c01@tfcconnection.org/9acc5bc27ca24ce7a900c57284959f9d8242340735661296952/S-1-8-2197686000-2519837503-3687200543-3873966527/reachcalendar.ics" "Yellow") ; Outlook Calendar
)))
(custom-set-faces
'(cfw:face-title ((t (:weight bold :height 2.0 :inherit fixed-pitch))))
'(cfw:face-header ((t (:slant italic :weight bold))))
'(cfw:face-sunday ((t :weight bold)))
'(cfw:face-saturday ((t :weight bold)))
'(cfw:face-holiday ((t :weight bold)))
;; '(cfw:face-grid ((t :foreground "DarkGrey")))
;; '(cfw:face-default-content ((t :foreground "#bfebbf")))
;; '(cfw:face-periods ((t :foreground "cyan")))
'(cfw:face-day-title ((t :background nil)))
'(cfw:face-default-day ((t :weight bold :inherit cfw:face-day-title)))
'(cfw:face-annotation ((t :inherit cfw:face-day-title)))
'(cfw:face-disable ((t :inherit cfw:face-day-title)))
'(cfw:face-today-title ((t :weight bold)))
'(cfw:face-today ((t :weight bold)))
;; '(cfw:face-select ((t :background "#2f2f2f")))
'(cfw:face-toolbar ((t :foreground "Steelblue4" :background "Steelblue4")))
'(cfw:face-toolbar-button-off ((t :weight bold)))
'(cfw:face-toolbar-button-on ((t :weight bold))))
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"oc" 'chris/calfw-calendar-open)
(general-def cfw:calendar-mode-map
"q" 'kill-this-buffer
"RET" 'cfw:show-details-command)
(general-def 'normal cfw:details-mode-map
"q" 'cfw:details-kill-buffer-command))
(use-package calfw-org
:after calfw)
(use-package calfw-ical
:after calfw)
(use-package org-caldav
:after org
:config
(setq org-caldav-url "https://staff.tfcconnection.org/remote.php/dav/calendars/chris"
org-caldav-calendar-id "org"
org-caldav-inbox "/home/chris/org/todo/inbox.org"
org-caldav-files '("/home/chris/org/todo/todo.org"
"/home/chris/org/todo/notes.org"
"/home/chris/org/todo/prayer.org")
org-icalendar-alarm-time 15
org-icalendar-use-scheduled '(todo-start event-if-todo)))
(use-package org-wild-notifier
:after org
:config
(setq alert-default-style 'libnotify)
(org-wild-notifier-mode +1))
(use-package magit
:ensure nil
:commands (magit-status magit-get-current-branch)
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"g g" 'magit-status)
:custom
(magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))
(use-package eshell
:ensure nil
:straight nil
:config
(require 'em-tramp)
(with-eval-after-load 'esh-module ;; REVIEW: It used to work, but now the early `provide' seems to backfire.
(unless (boundp 'eshell-modules-list)
(load "esh-module")) ;; Don't print the banner.
(push 'eshell-tramp eshell-modules-list))
(setq password-cache t
password-cache-expiry 3600)
(setq eshell-history-size 1024)
;;; Extra execution information
(defvar chris/eshell-status-p t
"If non-nil, display status before prompt.")
(defvar chris/eshell-status--last-command-time nil)
(make-variable-buffer-local 'chris/eshell-status--last-command-time)
(defvar chris/eshell-status-min-duration-before-display 0
"If a command takes more time than this, display its duration.")
(defun chris/eshell-status-display ()
(if chris/eshell-status--last-command-time
(let ((duration (time-subtract (current-time) chris/eshell-status--last-command-time)))
(setq chris/eshell-status--last-command-time nil)
(when (> (time-to-seconds duration) chris/eshell-status-min-duration-before-display)
(format "  %.3fs %s"
(time-to-seconds duration)
(format-time-string "| %F %T" (current-time)))))
(format "  0.000s")))
(defun chris/eshell-status-record ()
(setq chris/eshell-status--last-command-time (current-time)))
(add-hook 'eshell-pre-command-hook 'chris/eshell-status-record)
(setq eshell-prompt-function
(lambda nil
(let ((path (abbreviate-file-name (eshell/pwd))))
(concat
(if (or (string= system-name "archdesktop") (string= system-name "syl"))
nil
(format
(propertize "\n(%s@%s)" 'face '(:foreground "#606580"))
(propertize (user-login-name) 'face '(:inherit compilation-warning))
(propertize (system-name) 'face '(:inherit compilation-warning))))
(if (and (require 'magit nil t) (or (magit-get-current-branch) (magit-get-current-tag)))
(let* ((root (abbreviate-file-name (magit-rev-parse "--show-toplevel")))
(after-root (substring-no-properties path (min (length path) (1+ (length root))))))
(format
(propertize "\n[ %s | %s@%s ]" 'face font-lock-comment-face)
(propertize root 'face `(:inherit org-warning))
(propertize after-root 'face `(:inherit org-level-1))
(propertize (or (magit-get-current-branch) (magit-get-current-tag)) 'face `(:inherit org-macro))))
(format
(propertize "\n[%s]" 'face font-lock-comment-face)
(propertize path 'face `(:inherit org-level-1))))
(when chris/eshell-status-p
(propertize (or (chris/eshell-status-display) "") 'face font-lock-comment-face))
(propertize "\n" 'face '(:inherit org-todo :weight ultra-bold))
" "))))
;;; If the prompt spans over multiple lines, the regexp should match
;;; last line only.
(setq-default eshell-prompt-regexp "^ ")
(setq eshell-destroy-buffer-when-process-dies t)
(defun chris/pop-eshell ()
"Make an eshell frame on the bottom"
(interactive)
(unless pop-eshell
(setq pop-eshell (eshell 100))
(with-current-buffer pop-eshell
(eshell/clear-scrollback)
(rename-buffer "*eshell-pop*")
(display-buffer-in-side-window pop-eshell '((side . bottom))))))
(setq eshell-banner-message "")
(setq eshell-path-env "/usr/local/bin:/usr/bin:/opt/android-sdk/cmdline-tools/latest/bin")
;; this makes it so flutter works properly
(setenv "ANDROID_SDK_ROOT" "/opt/android-sdk")
(setenv "CHROME_EXECUTABLE" "/usr/bin/qutebrowser")
(setenv "JAVA_HOME" "/usr/lib/jvm/default")
(add-hook 'eshell-mode-hook '(display-line-numbers-mode -1))
(setq eshell-command-aliases-list
'(("q" "exit")
("f" "find-file $1")
("ff" "find-file $1")
("d" "dired $1")
("bd" "eshell-up $1")
("rg" "rg --color=always $*")
("ll" "ls -lah $*")
("gg" "magit-status")
("clear" "clear-scrollback")
("!c" "eshell-previous-input 2")
("yay" "paru $1")
("yeet" "paru -Rns $1")))
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"oe" 'eshell)
(general-def '(normal insert) eshell-mode-map
"C-d" 'kill-buffer-and-window))
(use-package sly
:mode
("\\.lisp\\'" . sly-mode)
("\\.lisp\\'" . lisp-mode)
:config
(defun chris/start-nyxt-repl ()
"Start the repl and sly connection for nyxt"
(interactive)
(sly-connect "localhost" 4006)))
(use-package pdf-tools
:straight (:host github
:repo "flatwhatson/pdf-tools"
:branch "fix-macros")
:defer 1
:config
(pdf-tools-install)
(custom-set-variables '(pdf-misc-print-program "/usr/bin/lpr")
'(pdf-misc-print-program-args (quote ("-o media=Letter" "-o fitplot"))))
(add-hook 'pdf-view-mode 'pdf-view-fit-page-to-window))
(use-package nov
:mode ("\\.epub\\'" . nov-mode)
:config
(defun chris/setup-nov-mode
(interactive)
(visual-fill-column-mode)
(display-line-numbers-mode -1)
(variable-pitch-mode +1)
(setq visual-fill-column-width 100
visual-fill-column-center-text t))
(add-hook 'nov-mode-hook 'chris/setup-nov-mode))
(use-package elfeed
:commands (elfeed)
:config
(defvar chris/elfeed-bongo-playlist "*Bongo-Elfeed Queue*"
"Name of the Elfeed+Bongo multimedia playlist.")
(defun chris/elfeed-bongo-insert-item ()
"Insert `elfeed' multimedia links in `bongo' playlist buffer.
The playlist buffer has a unique name so that it will never
interfere with the default `bongo-playlist-buffer'."
(interactive)
(let* ((entry (elfeed-search-selected :ignore-region))
(link (elfeed-entry-link entry))
(enclosure (elt (car (elfeed-entry-enclosures entry)) 0))
(url (if (string-prefix-p "https://thumbnails" enclosure)
link
(if (string= enclosure nil)
link
enclosure)))
(title (elfeed-entry-title entry))
(bongo-pl chris/elfeed-bongo-playlist)
(buffer (get-buffer-create bongo-pl)))
(message "link is %s" link)
(message "enclosure is %s" enclosure)
(message "url is %s" url)
(message "title is %s" title)
(elfeed-search-untag-all-unread)
(unless (bongo-playlist-buffer)
(bongo-playlist-buffer))
(display-buffer buffer)
(with-current-buffer buffer
(when (not (bongo-playlist-buffer-p))
(bongo-playlist-mode)
(setq-local bongo-library-buffer (get-buffer "*elfeed-search*"))
(setq-local bongo-enabled-backends '(mpv))
(bongo-progressive-playback-mode))
(goto-char (point-max))
(bongo-insert-uri url (format "%s ==> %s" title url))
(let ((inhibit-read-only t))
(delete-duplicate-lines (point-min) (point-max)))
(bongo-recenter))
(message "Enqueued %s “%s” in %s"
(if enclosure "podcast" "video")
(propertize title 'face 'italic)
(propertize bongo-pl 'face 'bold))))
(defun chris/elfeed-bongo-insert-link ()
"Inserts the hovered link into bongo for playback in mpv"
(interactive)
(let* ((link (shr--current-link-region))
(entry elfeed-show-entry)
(title (elfeed-entry-title entry))
(url (get-text-property (point) 'shr-url))
(bongo-pl chris/elfeed-bongo-playlist)
(buffer (get-buffer-create bongo-pl)))
(message "url is %s" url)
(message "title is %s" title)
(unless (bongo-playlist-buffer)
(bongo-playlist-buffer))
(display-buffer buffer)
(with-current-buffer buffer
(when (not (bongo-playlist-buffer-p))
(bongo-playlist-mode)
(setq-local bongo-library-buffer (get-buffer "*elfeed-search*"))
(setq-local bongo-enabled-backends '(mpv))
(bongo-progressive-playback-mode))
(goto-char (point-max))
(bongo-insert-uri url (format "%s ==> %s" title url))
(let ((inhibit-read-only t))
(delete-duplicate-lines (point-min) (point-max)))
(bongo-recenter))
(message "Enqueued item “%s” in %s"
(propertize title 'face 'italic)
(propertize bongo-pl 'face 'bold))))
(defun chris/elfeed-bongo-switch-to-playlist ()
(interactive)
(let* ((bongo-pl chris/elfeed-bongo-playlist)
(buffer (get-buffer bongo-pl)))
(if buffer
(switch-to-buffer buffer)
(message "No `bongo' playlist is associated with `elfeed'."))))
(setq elfeed-search-filter "@6-days-ago +unread")
(defun chris/elfeed-ui-setup ()
(display-line-numbers-mode -1)
(toggle-truncate-lines +1))
(defun chris/elfeed-show-ui-setup ()
(display-line-numbers-mode -1)
(setq visual-fill-column-width 130
visual-fill-column-center-text t)
(toggle-truncate-lines -1)
(visual-fill-column-mode +1))
(add-hook 'elfeed-search-mode-hook 'chris/elfeed-ui-setup)
(add-hook 'elfeed-show-mode-hook 'chris/elfeed-show-ui-setup)
(setq shr-use-colors nil)
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"of" 'elfeed)
(general-def 'normal elfeed-search-mode-map
"v" 'chris/elfeed-bongo-insert-item
"h" 'chris/elfeed-bongo-switch-to-playlist))
(use-package elfeed-org
:after elfeed
:config
(setq rmh-elfeed-org-files (list "~/org/elfeed.org"))
(elfeed-org)
(elfeed-update))
(use-package bongo
:commands (bongo bongo-playlist-buffer)
:config
(setq bongo-default-directory "~/Music"
bongo-prefer-library-buffers nil
bongo-insert-whole-directory-trees t
bongo-logo nil
bongo-display-playback-mode-indicator t
bongo-display-inline-playback-progress t
bongo-field-separator (propertize " · " 'face 'shadow))
(define-bongo-backend mpv
:constructor 'bongo-start-mpv-player
:program-name 'mpv
:extra-program-arguments '("--profile=fast --input-ipc-server=/tmp/mpvsocket")
:matcher '((local-file "file:" "http:" "ftp:" "lbry:")
"mpg" "mpeg" "vob" "avi" "ogm" "mp4"
"mkv" "mov" "asf" "wmv" "rm" "rmvb" "ts")
:matcher '(("mms:" "mmst:" "rtp:" "rtsp:" "udp:" "unsv:"
"dvd:" "vcd:" "tv:" "dvb:" "mf:" "cdda:" "cddb:"
"cue:" "sdp:" "mpst:" "tivo:") . t)
:matcher '(("http:" "https:" "lbry:") . t))
(define-bongo-backend mpv-music
:constructor 'bongo-start-mpv-player
:program-name-variable 'mpv
:extra-program-arguments '("--profile=slow --input-ipc-server=/tmp/mpvsocket")
:matcher '((local-file "file:" "http:" "ftp:" "lbry:")
"mka" "wav" "wma" "ogm" "opus"
"ogg" "flac" "mp3" "mka" "wav")
:matcher '(("http:" "https:" "lbry:") . t))
(setq bongo-custom-backend-matchers '((mpv-music local-file
"mka" "wav" "wma" "ogm" "opus"
"ogg" "flac" "mp3" "mka" "wav")
(mpv local-file
"mpg" "mpeg" "vob" "avi" "ogm" "mp4"
"mkv" "mov" "asf" "wmv" "rm" "rmvb" "ts")))
(setq bongo-enabled-backends '(mpv mpv-music)
bongo-track-mark-icon-file-name "track-mark-icon.png")
(defun chris/bongo-mark-line-forward ()
(interactive)
(bongo-mark-line)
(goto-char (bongo-point-after-object))
(next-line))
(defun chris/bongo-mpv-pause/resume ()
(interactive)
(bongo-mpv-player-pause/resume bongo-player))
(defun chris/bongo-mpv-speed-up ()
(interactive)
(bongo--run-mpv-command bongo-player "speed" "set" "speed" "1.95"))
(defun chris/bongo-open-elfeed-queue-buffer ()
(interactive)
(display-buffer "*Bongo-Elfeed Queue*"))
:general
(chris/leader-keys
"ob" 'bongo
"oB" 'chris/bongo-open-elfeed-queue-buffer
"mi" 'bongo-insert-enqueue
"mp" 'bongo-pause/resume)
(general-def 'normal bongo-playlist-mode-map
"RET" 'bongo-dwim
"d" 'bongo-kill-line
"u" 'bongo-unmark-region
"p" 'bongo-pause/resume
"P" 'bongo-yank
"H" 'bongo-switch-buffers
"q" 'bury-buffer
"+" 'chris/bongo-mpv-speed-up
"m" 'chris/bongo-mark-line-forward)
(general-def 'normal bongo-library-mode-map
"RET" 'bongo-dwim
"d" 'bongo-kill-line
"u" 'bongo-unmark-region
"e" 'bongo-insert-enqueue
"p" 'bongo-pause/resume
"H" 'bongo-switch-buffers
"q" 'bury-buffer))
(use-package emms
:config
(emms-all)
(evil-collection-emms-setup)
(emms-default-players)
(setq emms-source-file-default-directory "~/Music/")
(defun chris/emms-delete-song ()
"Deletes files in the emms browser by default. Maybe I'll have a yes or no thingy..."
(interactive)
(if (yes-or-no-p "delete the file too?")
(emms-browser-remove-tracks t)
(emms-browser-remove-tracks)))
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"mo" 'emms
"mb" 'emms-browser
"mp" 'emms-pause
"ma" 'emms-add-dired)
(general-def 'normal emms-playlist-mode-map
"q" 'bury-buffer
"d" 'emms-playlist-mode-kill-track
"D" 'emms-playlist-mode-goto-dired-at-point)
(general-def 'normal emms-browser-mode-map
"q" 'bury-buffer
"d" 'chris/emms-delete-song
"D" 'emms-browser-view-in-dired))
(use-package transmission
:commands (transmission)
:config
(if (string-equal (system-name) "archdesktop")
(setq transmission-host "home.cochrun.xyz"
transmission-rpc-path "/transmission/rpc"
transmission-refresh-modes '(transmission-mode
transmission-files-mode
transmission-info-mode
transmission-peers-mode))
(setq transmission-host "192.168.1.2"
transmission-rpc-path "/transmission/rpc"
transmission-refresh-modes '(transmission-mode
transmission-files-mode
transmission-info-mode
transmission-peers-mode)))
:general
(chris/leader-keys
:states 'normal
:keymaps 'override
"ot" 'transmission))
(use-package auth-source-pass
:defer 1
:config (auth-source-pass-enable))
(use-package pass
:defer 1)
(use-package password-store
:after pass
:general
(chris/leader-keys
"sp" 'password-store-copy))
(use-package password-store-otp
:after password-store
:general
(chris/leader-keys
"st" 'password-store-otp-token-copy))
(use-package plz
:straight (plz :type git :host github :repo "alphapapa/plz.el"))
(use-package ement
:straight (ement :type git :host github :repo "alphapapa/ement.el")
:config
(setq ement-room-images t
ement-save-sessions t)
:general
(general-def 'normal ement-room-mode-map
"q" 'bury-buffer
"RET" 'ement-room-send-message
"r" 'ement-room-send-reply
"gr" 'ement-room-sync
"R" 'ement-room-send-reaction)
(chris/leader-keys
"oM" 'ement-list-rooms))
;; Reduce rendering/line scan work for Emacs by not rendering cursors or regions
;; in non-focused windows.
(setq-default cursor-in-non-selected-windows nil)
(setq highlight-nonselected-windows nil)
;; More performant rapid scrolling over unfontified regions. May cause brief
;; spells of inaccurate syntax highlighting right after scrolling, which should
;; quickly self-correct.
(setq fast-but-imprecise-scrolling t)
;; Don't ping things that look like domain names.
(setq ffap-machine-p-known 'reject)
;; Emacs "updates" its ui more often than it needs to, so we slow it down
;; slightly from 0.5s:
(setq idle-update-delay 1.0)
;; Font compacting can be terribly expensive, especially for rendering icon
;; fonts on Windows. Whether disabling it has a notable affect on Linux and Mac
;; hasn't been determined, but we inhibit it there anyway. This increases memory
;; usage, however!
;; (setq inhibit-compacting-font-caches t)
;; Introduced in Emacs HEAD (b2f8c9f), this inhibits fontification while
;; receiving input, which should help with performance while scrolling.
(setq redisplay-skip-fontification-on-input t)
(setq gc-cons-threshold (* 32 1024 1024))
(setq garbage-collection-messages nil)
(use-package gcmh
:ensure t
:init
(gcmh-mode)
:config
(setq gcmh-idle-delay 5
gcmh-high-cons-threshold (* 128 1024 1024) ; 128mb
gcmh-verbose nil))
(setq warning-suppress-types '((comp)))