;;; 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) (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" (if (string-search "wayland" x-display-name) '((set-frame-parameter (selected-frame) 'alpha '(80 . 80)) (add-to-list 'default-frame-alist '(alpha . (80 . 80))) (add-to-list 'initial-frame-alist '(alpha . (80 . 80)))))) (if (daemonp) (add-hook 'after-make-frame-functions (lambda (frame) (with-selected-frame frame (chris/set-font-faces))) (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) ;; 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) (global-set-key (kbd "") 'keyboard-escape-quit) (recentf-mode +1) (server-start) (add-to-list 'exec-path "/home/chris/scripts") (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) (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 (global-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) (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) :config (evil-mode +1)) (use-package evil-collection :after evil :config (evil-collection-init)) (use-package general :init (general-evil-setup) :config (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") "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") "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" '((find-file ~/org/bibles/) :which-key "find bible book") "fr" '(consult-recent-file :which-key "recent file") "fs" '(save-buffer :which-key "save") "hf" '(helpful-callable :which-key "describe-function") "hv" '(helpful-variable :which-key "describe-variable") "hk" '(helpful-key :which-key "describe-key") "hb" '(general-describe-keybindings :which-key "describe-bindings") "hi" '(info :which-key "info manual") "ss" '(consult-line :which-key "consult search") "sr" '(consult-ripgrep :which-key "consult ripgrep") "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") ";" '(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) (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)) (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 "se" '(emojify-insert-emoji :which-key "insert emoji"))) (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 selectrum :init (selectrum-mode +1) :config (setq selectrum-max-window-height 8) (add-hook 'selectrum-mode-hook 'selectrum-exhibit) ;; We need to fix selectrums minibuffer handling for Emacs 28 (defun selectrum--set-window-height (window &optional height) "Set window height of WINDOW to HEIGHT pixel. If HEIGHT is not given WINDOW will be updated to fit its content vertically." (let* ((lines (length (split-string (overlay-get selectrum--candidates-overlay 'after-string) "\n" t))) (dheight (or height (* lines selectrum--line-height))) (wheight (window-pixel-height window)) (window-resize-pixelwise t)) (window-resize window (- dheight wheight) nil nil 'pixelwise))) :general ('selectrum-minibuffer-map "C-j" 'selectrum-next-candidate "C-k" 'selectrum-previous-candidate "C-S-j" 'selectrum-goto-end "C-S-k" 'selectrum-goto-beginning "TAB" 'selectrum-insert-current-candidate) :commands completing-read) (use-package prescient :config (prescient-persist-mode +1) :after selectrum) (use-package selectrum-prescient :init (selectrum-prescient-mode +1) :after selectrum) (use-package consult :after selectrum :config (setq consult-narrow-key "'") :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 selectrum :config (setq marginalia--cache-size 60000)) (use-package embark) (use-package company :config (global-company-mode +1) :custom (company-dabbrev-other-buffers t) (company-minimum-prefix-length 1) (company-idle-delay 0.1) :general (general-def '(normal insert) company-active-map "TAB" 'company-complete-selection "RET" 'company-complete-selection) (general-def '(normal insert) lsp-mode-map "TAB" 'company-indent-or-complete-common)) ;; (use-package company-box ;; :hook (company-mode . company-box-mode)) (use-package company-dict :after company) (use-package yasnippet :config (setq yas-snippet-dirs (list (expand-file-name "yasnippets/" user-emacs-directory))) (yas-global-mode 1)) (use-package projectile) (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)) ("*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 :commands (helpful-callable helpful-variable helpful-command helpful-key) :general (general-def 'normal 'helpful-mode-map "q" 'chris/kill-buffer-frame)) (use-package format-all :config (format-all-mode +1) (setq format-all-formatters '("Emacs Lisp" emacs-lisp)) :defer 1) (use-package lua-mode :mode ("\\.lua\\'" . lua-mode)) (use-package lsp-mode :commands (lsp lsp-deferred) :init (setq lsp-keymap-prefix "C-c l") :config (setq lsp-lens-enable t lsp-signature-auto-activate nil read-process-output-max (* 1024 1024)) (lsp-enable-which-key-integration t)) (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) :config (use-package company-qml :after qml-mode :config (add-to-list 'company-backends 'company-qml) (setq company-qml-extra-qmltypes-files '("/home/chris/dev/Felgo/Felgo/gcc_64/import/VPlayPlugins/vplayplugins.qmltypes" "/home/chris/dev/Felgo/Felgo/gcc_64/import/VPlayApps/vplayapps.qmltypes" "/home/chris/dev/Felgo/Felgo/gcc_64/import/VPlay/vplay.qmltypes" "/home/chris/dev/Felgo/Felgo/gcc_64/import/Felgo/felgo.qmltypes")) (setq company-idle-delay 0.1))) (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 "C-c r" 'lsp-dart-dap-flutter-hot-reload "C-c R" '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) (setq dired-listing-switches "-aoh --group-directories-first") (setq dired-hide-details-hide-symlink-targets nil) (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 here")) (general-def 'normal dired-mode-map "q" 'kill-this-buffer "C-" 'chris/dired-open-xdg)) (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)) (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) (setq visual-fill-column-width 100 visual-fill-column-center-text t)) (use-package org :straight t :ensure t :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) (restclient . 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+headline "todo/todo.org" "Inbox") (file ".templates/tasks.org") :prepend t) ("n" "Personal notes" entry (file+headline "todo/notes.org" "Inbox") "* %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 +org-capture-project-todo-file "Inbox") "* TODO %?\n%i\n%a" :prepend t) ("rn" "Project-local notes" entry (file+headline +org-capture-project-notes-file "Inbox") "* %U %?\n%i\n%a" :prepend t) ("rc" "Project-local changelog" entry (file+headline +org-capture-project-changelog-file "Unreleased") "* %U %?\n%i\n%a" :prepend t) ("o" "Centralized templates for projects") ("ot" "Project todo" entry #'+org-capture-central-project-todo-file "* TODO %?\n %i\n %a" :heading "Tasks" :prepend nil) ("on" "Project notes" entry #'+org-capture-central-project-notes-file "* %U %?\n %i\n %a" :heading "Notes" :prepend t) ("oc" "Project changelog" entry #'+org-capture-central-project-changelog-file "* %U %?\n %i\n %a" :heading "Changelog" :prepend t)) org-capture-use-agenda-date t org-agenda-timegrid-use-ampm t org-agenda-tags-column -100) (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/org/lessons/") org-id-method 'ts) (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) ;;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) (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) ('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 "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/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 :after org) (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 "Overdue" :time-grid t :scheduled today) (:name "Due soon" :deadline future))) :config (org-super-agenda-mode) (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-superstar :after org :config (org-superstar-mode +1) (setq org-superstar-headline-bullets-list '("\u25c9" "\u25c8" "盛" "\u25ce" "\u272c" "\u25c7" "\u2749" "\u2719" "\u2756")) (setq org-superstar-item-bullet-alist '((?- . ?\u25b8) (?+ . ?\u2749) (?* . ?\u25c9))) (set-face-attribute 'org-superstar-item nil :inherit 'org-level-3) (add-hook 'org-mode-hook 'org-superstar-mode)) (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 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 "office" :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") (mu4e-compose-signature . "---\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 . "---\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 . "---\nChris Cochrun"))))) ;; Add the ability to send email for o365 (setq message-send-mail-function 'smtpmail-send-it starttls-use-gnutls t smtpmail-starttls-credentials '(("smtp.office365.com" 587 nil nil)) smtpmail-auth-credentials '(("smtp.office365.com" 587 "chris@tfcconnection.org" nil)) smtpmail-default-smtp-server "smtp.office365.com" smtpmail-smtp-server "smtp.office365.com" 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 "/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) (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) (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 magit :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") (setenv "PATH" "/usr/local/bin:/usr/bin:/opt/android-sdk/cmdline-tools/latest/bin") (add-hook 'eshell-mode-hook '(hscroll-margin 0)) (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"))))) (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 eaf :straight (:host github :repo "manateelazycat/emacs-application-framework" :files ("*.el" "*.py" "core" "app")) :defer 1 :config (setq eaf-browser-dark-mode t)) (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-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") :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 (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:") "mka" "wav" "wma" "ogm" "opus" "ogg" "flac" "mp3" "mka" "wav" "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)) (setq bongo-enabled-backends '(mpv) bongo-mpv-extra-arguments '("--profile=fast") 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 :states 'normal "ob" 'bongo "oB" 'chris/bongo-open-elfeed-queue-buffer) (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 transmission :commands (transmission) :config (if (string-equal (system-name) "syl") (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) :general (general-def 'normal ement-room-mode-map "q" 'bury-buffer "RET" 'ement-room-send-message) (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)))