3183 lines
109 KiB
EmacsLisp
3183 lines
109 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 Propo"
|
||
:height chris/default-font-size)
|
||
(set-face-attribute 'fixed-pitch nil :font "VictorMono Nerd Font Propo"
|
||
: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 but not the text"
|
||
(set-frame-parameter (selected-frame) 'alpha-background 100)
|
||
(add-to-list 'default-frame-alist '(alpha-background . 100))
|
||
(add-to-list 'initial-frame-alist '(alpha-background . 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 t)
|
||
(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)
|
||
|
||
(add-to-list 'exec-path "/home/chris/bin")
|
||
|
||
(setq initial-major-mode 'org-mode)
|
||
(setq initial-scratch-message "#+TITLE: SCRATCH\n#+DESCRIPTION: This buffer is for temporary things")
|
||
|
||
(dolist (path load-path)
|
||
(when (string-match-p "/nix/store/[a-z0-9]\\{32\\}-emacs-packages-deps.*" path)
|
||
(dolist (autoload-file (directory-files path t "-autoloads.el"))
|
||
(with-demoted-errors "init.el error: %s"
|
||
(load autoload-file nil t)))))
|
||
|
||
(eval-when-compile (require '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 25
|
||
doom-modeline-bar-width 3
|
||
all-the-icons-scale-factor 0.9
|
||
doom-modeline-hud nil
|
||
doom-modeline-buffer-file-name-style 'file-name
|
||
doom-modeline-buffer-encoding nil
|
||
doom-modeline-mu4e t
|
||
doom-modeline-enable-word-count nil)
|
||
(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 aggressive-indent
|
||
:config
|
||
(aggressive-indent-mode -1))
|
||
|
||
(use-package adaptive-wrap)
|
||
|
||
(use-package which-key
|
||
:config
|
||
(setq which-key-idle-delay 0.3)
|
||
(which-key-mode))
|
||
|
||
(setenv "WAYLAND_DISPLAY" (if (string= (getenv "XDG_CURRENT_DESKTOP") "Hyprland")
|
||
"wayland-1"
|
||
"wayland-0"))
|
||
|
||
(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)))
|
||
(add-hook 'org-mode-hook 'chris/org-mode-setup)
|
||
|
||
(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)))
|
||
|
||
(setq backup-directory-alist '(("." . "~/.emacs.d/backup"))
|
||
backup-by-copying t ; Don't delink hardlinks
|
||
version-control t ; Use version numbers on backups
|
||
delete-old-versions t ; Automatically delete excess backups
|
||
kept-new-versions 20 ; how many of the newest versions to keep
|
||
kept-old-versions 5 ; and how many of the old
|
||
)
|
||
|
||
(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")
|
||
"ts" '(ispell :which-key "spell check")
|
||
"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")
|
||
"sd" '(dictionary-search :which-key "search the dictionary")
|
||
"sv" '(imenu :which-key "imenu")
|
||
"oP" '(proced :which-key "proced")
|
||
"ov" '(vterm :which-key "vterm")
|
||
"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")
|
||
"wH" '(evil-window-move-far-left :which-key "right window")
|
||
"wK" '(evil-window-move-very-top :which-key "right window")
|
||
"wJ" '(evil-window-move-very-bottom :which-key "right window")
|
||
"wL" '(evil-window-move-far-right :which-key "right window")
|
||
";" '(execute-extended-command :which-key "execute command")
|
||
":" '(eval-expression :which-key "evaluate expression"))
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'lisp-mode
|
||
"e" '(sly-eval-defun :which-key "evaluate top level"))
|
||
(general-def 'minibuffer-local-map
|
||
"C-v" 'evil-paste-after)
|
||
(general-def 'normal
|
||
"gcc" 'comment-line
|
||
"K" 'helpful-at-point
|
||
"C-+" 'text-scale-increase
|
||
"C-_" 'text-scale-decrease
|
||
"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
|
||
"zi" 'text-scale-increase
|
||
"zd" 'text-scale-decrease)
|
||
(general-def 'normal Info-mode-map
|
||
"RET" 'Info-follow-nearest-node
|
||
"p" 'Info-prev
|
||
"n" 'Info-next)
|
||
(general-def 'normal prog-mode-map
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"go" 'ff-find-other-file
|
||
"TAB" 'indent-according-to-mode)
|
||
(general-def 'visual prog-mode-map
|
||
:states 'visual
|
||
:keymaps 'override
|
||
"TAB" 'indent-region)
|
||
(general-def 'insert prog-mode-map
|
||
:states 'insert
|
||
:keymaps 'override
|
||
"TAB" 'indent-according-to-mode))
|
||
|
||
(use-package evil-escape
|
||
:after evil
|
||
:init (evil-escape-mode +1)
|
||
:config
|
||
(setq evil-escape-key-sequence (kbd "fd")
|
||
evil-escape-delay 0.3))
|
||
|
||
(use-package evil-surround
|
||
:after evil
|
||
:config
|
||
(global-evil-surround-mode +1))
|
||
|
||
(setq lpr-command "lpr -o sides=two-sided-long-edge -# ")
|
||
(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)
|
||
|
||
;;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))
|
||
|
||
;; changing height and boldness
|
||
(dolist (face
|
||
'((org-level-1 1.4 ultra-bold)
|
||
(org-level-2 1.2 extra-bold)
|
||
(org-level-3 1.1 bold)
|
||
(org-level-4 1.0 semi-bold)
|
||
(org-level-5 1.0 normal)
|
||
(org-column 1.0 normal)))
|
||
(set-face-attribute (nth 0 face) nil :weight (nth 2 face) :height (nth 1 face)))
|
||
|
||
;; changing colors
|
||
(dolist (face
|
||
'((outline-2 "#5af78e")
|
||
(outline-3 "#ffb86c")
|
||
(outline-4 "#f3f99d")))
|
||
(set-face-attribute (nth 0 face) nil :foreground (nth 1 face)))
|
||
|
||
(set-face-attribute 'org-block-end-line nil :inherit 'org-block-begin-line)
|
||
(set-face-attribute 'org-column nil :background "#242631" :inherit 'fixed-pitch)
|
||
(set-face-attribute 'org-quote nil :background "#242631" :inherit 'fixed-pitch))
|
||
|
||
(defun chris/org-convert-csv-table (beg end)
|
||
(interactive (list (mark) (point)))
|
||
(org-table-convert-region beg end ","))
|
||
|
||
(defun chris/org-cycle-hide-drawers (state)
|
||
"Re-hide all drawers after a visibility state change."
|
||
(interactive)
|
||
(when (and (derived-mode-p 'org-mode)
|
||
(not (memq state '(overview folded contents))))
|
||
(save-excursion
|
||
(let* ((globalp (memq state '(contents all)))
|
||
(beg (if globalp
|
||
(point-min)
|
||
(point)))
|
||
(end (if globalp
|
||
(point-max)
|
||
(if (eq state 'children)
|
||
(save-excursion
|
||
(outline-next-heading)
|
||
(point))
|
||
(org-end-of-subtree t)))))
|
||
(goto-char beg)
|
||
(while (re-search-forward org-drawer-regexp end t)
|
||
(save-excursion
|
||
(beginning-of-line 1)
|
||
(when (looking-at org-drawer-regexp)
|
||
(let* ((start (1- (match-beginning 0)))
|
||
(limit
|
||
(save-excursion
|
||
(outline-next-heading)
|
||
(point)))
|
||
(msg (format
|
||
(concat
|
||
"org-cycle-hide-drawers: "
|
||
"`:END:`"
|
||
" line missing at position %s")
|
||
(1+ start))))
|
||
(if (re-search-forward "^[ \t]*:END:" limit t)
|
||
(outline-flag-region start (point-at-eol) t)
|
||
(user-error msg))))))))))
|
||
|
||
(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))
|
||
|
||
(defun chris/org-mpv (&optional url)
|
||
(interactive)
|
||
(if (string-empty-p url)
|
||
(let (url url-get-url-at-point)
|
||
(bongo-insert-uri url (format "%s ==> %s" title url)))
|
||
(bongo-insert-uri url (format "%s ==> %s" title url))))
|
||
|
||
(defun chris/bible-imenu ()
|
||
"This is a special call on consult-imenu that will utilize
|
||
orderless with a better dispatcher so that we can find our verses
|
||
much faster. The hope is to also make this a faster version of imenu."
|
||
(interactive)
|
||
(consult-imenu))
|
||
|
||
(use-package org
|
||
:defer 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-export-with-broken-links t
|
||
org-agenda-current-time-string "⭠ now ────────────────"
|
||
org-log-into-drawer t
|
||
org-latex-active-timestamp-format "\\textit{%s}"
|
||
org-enforce-todo-dependencies t
|
||
org-export-preserve-breaks t)
|
||
|
||
(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)
|
||
("s" "TFC Supporter" entry
|
||
(file "tfc_supporters.org")
|
||
(file ".templates/supporter.org")
|
||
:prepend t
|
||
:jump-to-captured t)
|
||
("r" "Templates for projects")
|
||
("rt" "Project-local todo" entry
|
||
(file+headline chris/project-todo "Tasks")
|
||
"* 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/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
|
||
org-columns-summary-types '(("+" . org-columns--summary-sum)
|
||
("$" . org-columns--summary-currencies)
|
||
("X" . org-columns--summary-checkbox)
|
||
("X/" . org-columns--summary-checkbox-count)
|
||
("X%" . org-columns--summary-checkbox-percent)
|
||
("max" . org-columns--summary-max)
|
||
("mean" . org-columns--summary-mean)
|
||
("min" . org-columns--summary-min)
|
||
(":" . org-columns--summary-sum-times)
|
||
(":max" . org-columns--summary-max-time)
|
||
(":mean" . org-columns--summary-mean-time)
|
||
(":min" . org-columns--summary-min-time)
|
||
("@max" . org-columns--summary-max-age)
|
||
("@mean" . org-columns--summary-mean-age)
|
||
("@min" . org-columns--summary-min-age)
|
||
("est+" . org-columns--summary-estimate)))
|
||
|
||
(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))
|
||
|
||
;; (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
|
||
"il" 'org-insert-link
|
||
"it" 'org-insert-todo-subheading)
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'org-mode-map
|
||
"is" 'org-time-stamp
|
||
"tp" (chris/org-cycle-hide-drawers 'children))
|
||
(chris/leader-keys
|
||
:states 'visual
|
||
:keymaps 'override
|
||
"il" 'org-insert-link)
|
||
('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" '+org/dwim-at-point
|
||
"gC" 'chris/org-columns-view
|
||
"ge" 'org-edit-src-code
|
||
"gr" 'revert-buffer
|
||
"ze" 'org-emphasize
|
||
"zn" 'org-narrow-to-subtree
|
||
"zw" 'widen
|
||
"zp" 'org-set-property
|
||
"zh" (chris/org-cycle-hide-drawers 'subtree)
|
||
"S" 'org-schedule
|
||
"t" 'org-todo
|
||
"gf" 'org-footnote-action
|
||
"gl" 'org-id-copy
|
||
"gk" 'languagetool-correct-at-point
|
||
"C-M-k" 'org-priority-up
|
||
"C-M-j" 'org-priority-down)
|
||
('visual org-mode-map
|
||
"gf" 'org-footnote-action)
|
||
('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" entry "\n* %?"
|
||
:if-new (file+head "${slug}.org"
|
||
"#+TITLE: ${title}\n#+AUTHOR: Chris Cochrun\n#+CREATED: %<%D - %I:%M %p>\n\n")
|
||
:unnarrowed t)
|
||
("b" "bible" entry "\n* %?"
|
||
:if-new (file+head "${slug}.org"
|
||
"#+TITLE: ${title}\n#+AUTHOR: Chris Cochrun\n#+CREATED: %<%D - %I:%M %p>\n- tags :biblestudy:%^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 "%?"
|
||
:immediate-finish nil
|
||
: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?"
|
||
:target (file+head "%<%Y-%m-%d>.org"
|
||
"#+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?\n* Bible")
|
||
:unnarrowed t
|
||
)
|
||
("b" "biblical daily" plain "%?"
|
||
:file-name "%<%Y-%m-%d>-bib"
|
||
:target (file+head "%<%Y-%m-%d>-bib.org" "#+TITLE: %<%Y-%m-%d> - Biblical\n#+AUTHOR: Chris Cochrun\n#+CREATED: %<%D - %I:%M %p>\n\n* Notes")
|
||
:unnarrowed t)))
|
||
(defun chris/org-roam-node-create ()
|
||
"Create an org roam node underneath this org node"
|
||
(interactive)
|
||
(+org/insert-item-below 1)
|
||
(org-id-get-create))
|
||
(defun chris/org-roam-node-id-create ()
|
||
"Make the basic org node and org roam one by adding an id and creating an alias"
|
||
(interactive)
|
||
(org-id-get-create)
|
||
(org-roam-alias-add))
|
||
;; (set-face-attribute 'magit-section-highlight nil :inherit 'variable-pitch)
|
||
(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" 'chris/org-roam-node-create
|
||
"nl" 'org-roam-node-insert
|
||
"nc" 'org-roam-capture
|
||
"nt" 'org-roam-dailies-goto-today
|
||
"ng" 'org-roam-graph
|
||
"na" 'org-roam-alias-add
|
||
"in" 'org-roam-node-insert
|
||
"nA" 'chris/org-roam-node-id-create)
|
||
(chris/leader-keys
|
||
:states 'visual
|
||
:keymaps 'override
|
||
"in" 'org-roam-node-insert))
|
||
|
||
(use-package websocket)
|
||
(use-package org-roam-ui
|
||
: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-present
|
||
:commands org-present
|
||
:config
|
||
(add-hook 'org-present-mode-hook
|
||
(lambda ()
|
||
(org-present-big)
|
||
(org-present-hide-cursor)))
|
||
(add-hook 'org-present-mode-quit-hook
|
||
(lambda ()
|
||
(org-present-small)
|
||
(org-present-show-cursor)))
|
||
:general
|
||
(chris/leader-keys 'normal
|
||
"oo" 'org-present)
|
||
('normal org-present-mode-map
|
||
"q" 'org-present-quit
|
||
"j" 'org-present-next
|
||
"k" 'org-present-prev
|
||
))
|
||
|
||
(use-package org-modern
|
||
:config
|
||
|
||
(setq org-modern-timestamp nil
|
||
org-modern-table nil)
|
||
|
||
(custom-set-faces
|
||
'(org-modern-tag ((t :background "#9aedfe" :foreground "#282a36")))
|
||
)
|
||
(global-org-modern-mode +1)
|
||
)
|
||
|
||
;;; lang/org/autoload/org.el -*- lexical-binding: t; -*-
|
||
|
||
;;
|
||
;;; Helpers
|
||
|
||
(defun +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)
|
||
(save-excursion (point-min))
|
||
(save-excursion (org-back-to-heading) (point)))))
|
||
(end (or end
|
||
(if (org-before-first-heading-p)
|
||
(save-excursion (org-next-visible-heading 1) (point))
|
||
(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)))
|
||
|
||
(defun +org--insert-item (direction)
|
||
(let ((context (org-element-lineage
|
||
(org-element-context)
|
||
'(table table-row headline inlinetask item plain-list)
|
||
t)))
|
||
(pcase (org-element-type context)
|
||
;; Add a new list item (carrying over checkboxes if necessary)
|
||
((or `item `plain-list)
|
||
(let ((orig-point (point)))
|
||
;; Position determines where org-insert-todo-heading and `org-insert-item'
|
||
;; insert the new list item.
|
||
(if (eq direction 'above)
|
||
(org-beginning-of-item)
|
||
(end-of-line))
|
||
(let* ((ctx-item? (eq 'item (org-element-type context)))
|
||
(ctx-cb (org-element-property :contents-begin context))
|
||
;; Hack to handle edge case where the point is at the
|
||
;; beginning of the first item
|
||
(beginning-of-list? (and (not ctx-item?)
|
||
(= ctx-cb orig-point)))
|
||
(item-context (if beginning-of-list?
|
||
(org-element-context)
|
||
context))
|
||
;; Horrible hack to handle edge case where the
|
||
;; line of the bullet is empty
|
||
(ictx-cb (org-element-property :contents-begin item-context))
|
||
(empty? (and (eq direction 'below)
|
||
;; in case contents-begin is nil, or contents-begin
|
||
;; equals the position end of the line, the item is
|
||
;; empty
|
||
(or (not ictx-cb)
|
||
(= ictx-cb
|
||
(1+ (point))))))
|
||
(pre-insert-point (point)))
|
||
;; Insert dummy content, so that `org-insert-item'
|
||
;; inserts content below this item
|
||
(when empty?
|
||
(insert " "))
|
||
(org-insert-item (org-element-property :checkbox context))
|
||
;; Remove dummy content
|
||
(when empty?
|
||
(delete-region pre-insert-point (1+ pre-insert-point))))))
|
||
;; Add a new table row
|
||
((or `table `table-row)
|
||
(pcase direction
|
||
('below (save-excursion (org-table-insert-row t))
|
||
(org-table-next-row))
|
||
('above (save-excursion (org-shiftmetadown))
|
||
(+org/table-previous-row))))
|
||
|
||
;; Otherwise, add a new heading, carrying over any todo state, if
|
||
;; necessary.
|
||
(_
|
||
(let ((level (or (org-current-level) 1)))
|
||
;; I intentionally avoid `org-insert-heading' and the like because they
|
||
;; impose unpredictable whitespace rules depending on the cursor
|
||
;; position. It's simpler to express this command's responsibility at a
|
||
;; lower level than work around all the quirks in org's API.
|
||
(pcase direction
|
||
(`below
|
||
(let (org-insert-heading-respect-content)
|
||
(goto-char (line-end-position))
|
||
(org-end-of-subtree)
|
||
(insert "\n" (make-string level ?*) " ")))
|
||
(`above
|
||
(org-back-to-heading)
|
||
(insert (make-string level ?*) " ")
|
||
(save-excursion (insert "\n"))))
|
||
(run-hooks 'org-insert-heading-hook)
|
||
(when-let* ((todo-keyword (org-element-property :todo-keyword context))
|
||
(todo-type (org-element-property :todo-type context)))
|
||
(org-todo
|
||
(cond ((eq todo-type 'done)
|
||
;; Doesn't make sense to create more "DONE" headings
|
||
(car (+org-get-todo-keywords-for todo-keyword)))
|
||
(todo-keyword)
|
||
('todo)))))))
|
||
|
||
(when (org-invisible-p)
|
||
(org-show-hidden-entry))
|
||
(when (and (bound-and-true-p evil-local-mode)
|
||
(not (evil-emacs-state-p)))
|
||
(evil-insert 1))))
|
||
|
||
;;;###autoload
|
||
(defun +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)))
|
||
|
||
|
||
;;
|
||
;;; Modes
|
||
|
||
;;;###autoload
|
||
(define-minor-mode +org-pretty-mode
|
||
"Hides emphasis markers and toggles pretty entities."
|
||
:init-value nil
|
||
:lighter " *"
|
||
:group 'evil-org
|
||
(setq org-hide-emphasis-markers +org-pretty-mode)
|
||
(org-toggle-pretty-entities)
|
||
(with-silent-modifications
|
||
;; In case the above un-align tables
|
||
(org-table-map-tables 'org-table-align t)))
|
||
|
||
|
||
;;
|
||
;;; Commands
|
||
|
||
;;;###autoload
|
||
(defun +org/return ()
|
||
"Call `org-return' then indent (if `electric-indent-mode' is on)."
|
||
(interactive)
|
||
(org-return electric-indent-mode))
|
||
|
||
;;;###autoload
|
||
(defun +org/dwim-at-point (&optional arg)
|
||
"Do-what-I-mean at point.
|
||
|
||
If on a:
|
||
- checkbox list item or todo heading: toggle it.
|
||
- citation: follow it
|
||
- headline: cycle ARCHIVE subtrees, toggle latex fragments and inline images in
|
||
subtree; update statistics cookies/checkboxes and ToCs.
|
||
- clock: update its time.
|
||
- footnote reference: jump to the footnote's definition
|
||
- footnote definition: jump to the first reference of this footnote
|
||
- timestamp: open an agenda view for the time-stamp date/range at point.
|
||
- 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.
|
||
- src block: execute it
|
||
- latex fragment: toggle it.
|
||
- link: follow it
|
||
- otherwise, refresh all inline images in current tree."
|
||
(interactive "P")
|
||
(if (button-at (point))
|
||
(call-interactively #'push-button)
|
||
(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
|
||
((or `citation `citation-reference)
|
||
(org-cite-follow context arg))
|
||
|
||
(`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 (+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)))
|
||
(+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 arg))
|
||
|
||
((or `latex-fragment `latex-environment)
|
||
(org-latex-preview arg))
|
||
|
||
(`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)))
|
||
(+org--toggle-inline-images-in-subtree
|
||
(org-element-property :begin lineage)
|
||
(org-element-property :end lineage))
|
||
(org-open-at-point arg))))
|
||
|
||
(`paragraph
|
||
(+org--toggle-inline-images-in-subtree))
|
||
|
||
((guard (org-element-property :checkbox (org-element-lineage context '(item) t)))
|
||
(let ((match (and (org-at-item-checkbox-p) (match-string 1))))
|
||
(org-toggle-checkbox (if (equal match "[ ]") '(16)))))
|
||
|
||
(_
|
||
(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)
|
||
(+org--toggle-inline-images-in-subtree
|
||
(org-element-property :begin context)
|
||
(org-element-property :end context))))))))
|
||
|
||
;;;###autoload
|
||
(defun +org/shift-return (&optional arg)
|
||
"Insert a literal newline, or dwim in tables.
|
||
Executes `org-table-copy-down' if in table."
|
||
(interactive "p")
|
||
(if (org-at-table-p)
|
||
(org-table-copy-down arg)
|
||
(org-return nil arg)))
|
||
|
||
|
||
;; I use these instead of `org-insert-item' or `org-insert-heading' because they
|
||
;; impose bizarre whitespace rules depending on cursor location and many
|
||
;; settings. These commands have a much simpler responsibility.
|
||
;;;###autoload
|
||
(defun +org/insert-item-below (count)
|
||
"Inserts a new heading, table cell or item below the current one."
|
||
(interactive "p")
|
||
(dotimes (_ count) (+org--insert-item 'below)))
|
||
|
||
;;;###autoload
|
||
(defun +org/insert-item-above (count)
|
||
"Inserts a new heading, table cell or item above the current one."
|
||
(interactive "p")
|
||
(dotimes (_ count) (+org--insert-item 'above)))
|
||
|
||
|
||
;;;###autoload
|
||
(defun +org/toggle-last-clock (arg)
|
||
"Toggles last clocked item.
|
||
|
||
Clock out if an active clock is running (or cancel it if prefix ARG is non-nil).
|
||
|
||
If no clock is active, then clock into the last item. See `org-clock-in-last' to
|
||
see how ARG affects this command."
|
||
(interactive "P")
|
||
(require 'org-clock)
|
||
(cond ((org-clocking-p)
|
||
(if arg
|
||
(org-clock-cancel)
|
||
(org-clock-out)))
|
||
((and (null org-clock-history)
|
||
(or (org-on-heading-p)
|
||
(org-at-item-p))
|
||
(y-or-n-p "No active clock. Clock in on current item?"))
|
||
(org-clock-in))
|
||
((org-clock-in-last arg))))
|
||
|
||
|
||
;;; Folds
|
||
;;;###autoload
|
||
(defalias #'+org/toggle-fold #'+org-cycle-only-current-subtree-h)
|
||
|
||
;;;###autoload
|
||
(defun +org/open-fold ()
|
||
"Open the current fold (not but its children)."
|
||
(interactive)
|
||
(+org/toggle-fold t))
|
||
|
||
;;;###autoload
|
||
(defalias #'+org/close-fold #'outline-hide-subtree)
|
||
|
||
;;;###autoload
|
||
(defun +org/close-all-folds (&optional level)
|
||
"Close all folds in the buffer (or below LEVEL)."
|
||
(interactive "p")
|
||
(outline-hide-sublevels (or level 1)))
|
||
|
||
;;;###autoload
|
||
(defun +org/open-all-folds (&optional level)
|
||
"Open all folds in the buffer (or up to LEVEL)."
|
||
(interactive "P")
|
||
(if (integerp level)
|
||
(outline-hide-sublevels level)
|
||
(outline-show-all)))
|
||
|
||
(defun +org--get-foldlevel ()
|
||
(let ((max 1))
|
||
(save-restriction
|
||
(narrow-to-region (window-start) (window-end))
|
||
(save-excursion
|
||
(goto-char (point-min))
|
||
(while (not (eobp))
|
||
(org-next-visible-heading 1)
|
||
(when (outline-invisible-p (line-end-position))
|
||
(let ((level (org-outline-level)))
|
||
(when (> level max)
|
||
(setq max level))))))
|
||
max)))
|
||
|
||
;;;###autoload
|
||
(defun +org/show-next-fold-level (&optional count)
|
||
"Decrease the fold-level of the visible area of the buffer. This unfolds
|
||
another level of headings on each invocation."
|
||
(interactive "p")
|
||
(let ((new-level (+ (+org--get-foldlevel) (or count 1))))
|
||
(outline-hide-sublevels new-level)
|
||
(message "Folded to level %s" new-level)))
|
||
|
||
;;;###autoload
|
||
(defun +org/hide-next-fold-level (&optional count)
|
||
"Increase the global fold-level of the visible area of the buffer. This folds
|
||
another level of headings on each invocation."
|
||
(interactive "p")
|
||
(let ((new-level (max 1 (- (+org--get-foldlevel) (or count 1)))))
|
||
(outline-hide-sublevels new-level)
|
||
(message "Folded to level %s" new-level)))
|
||
|
||
|
||
;;
|
||
;;; Hooks
|
||
|
||
;;;###autoload
|
||
(defun +org-indent-maybe-h ()
|
||
"Indent the current item (header or item), if possible.
|
||
Made for `org-tab-first-hook' in evil-mode."
|
||
(interactive)
|
||
(cond ((not (and (bound-and-true-p evil-local-mode)
|
||
(evil-insert-state-p)))
|
||
nil)
|
||
((and (bound-and-true-p org-cdlatex-mode)
|
||
(or (org-inside-LaTeX-fragment-p)
|
||
(org-inside-latex-macro-p)))
|
||
nil)
|
||
((org-at-item-p)
|
||
(if (eq this-command 'org-shifttab)
|
||
(org-outdent-item-tree)
|
||
(org-indent-item-tree))
|
||
t)
|
||
((org-at-heading-p)
|
||
(ignore-errors
|
||
(if (eq this-command 'org-shifttab)
|
||
(org-promote)
|
||
(org-demote)))
|
||
t)
|
||
((org-in-src-block-p t)
|
||
(save-window-excursion
|
||
(org-babel-do-in-edit-buffer
|
||
(call-interactively #'indent-for-tab-command)))
|
||
t)
|
||
((and (save-excursion
|
||
(skip-chars-backward " \t")
|
||
(bolp))
|
||
(org-in-subtree-not-table-p))
|
||
(call-interactively #'tab-to-tab-stop)
|
||
t)))
|
||
|
||
;;;###autoload
|
||
(defun +org-cycle-only-current-subtree-h (&optional arg)
|
||
"Toggle the local fold at the point, and no deeper.
|
||
`org-cycle's standard behavior is to cycle between three levels: collapsed,
|
||
subtree and whole document. This is slow, especially in larger org buffer. Most
|
||
of the time I just want to peek into the current subtree -- at most, expand
|
||
*only* the current subtree.
|
||
|
||
All my (performant) foldings needs are met between this and `org-show-subtree'
|
||
(on zO for evil users), and `org-cycle' on shift-TAB if I need it."
|
||
(interactive "P")
|
||
(unless (or (eq this-command 'org-shifttab)
|
||
(and (bound-and-true-p org-cdlatex-mode)
|
||
(or (org-inside-LaTeX-fragment-p)
|
||
(org-inside-latex-macro-p))))
|
||
(save-excursion
|
||
(org-beginning-of-line)
|
||
(let (invisible-p)
|
||
(when (and (org-at-heading-p)
|
||
(or org-cycle-open-archived-trees
|
||
(not (member org-archive-tag (org-get-tags))))
|
||
(or (not arg)
|
||
(setq invisible-p (outline-invisible-p (line-end-position)))))
|
||
(unless invisible-p
|
||
(setq org-cycle-subtree-status 'subtree))
|
||
(org-cycle-internal-local)
|
||
t)))))
|
||
|
||
;;;###autoload
|
||
(defun +org-make-last-point-visible-h ()
|
||
"Unfold subtree around point if saveplace places us in a folded region."
|
||
(and (not org-inhibit-startup)
|
||
(not org-inhibit-startup-visibility-stuff)
|
||
;; Must be done on a timer because `org-show-set-visibility' (used by
|
||
;; `org-reveal') relies on overlays that aren't immediately available
|
||
;; when `org-mode' first initializes.
|
||
(run-at-time 0.1 nil #'org-reveal '(4))))
|
||
|
||
;;;###autoload
|
||
(defun +org-remove-occur-highlights-h ()
|
||
"Remove org occur highlights on ESC in normal mode."
|
||
(when org-occur-highlights
|
||
(org-remove-occur-highlights)
|
||
t))
|
||
|
||
;;;###autoload
|
||
(defun +org-enable-auto-update-cookies-h ()
|
||
"Update statistics cookies when saving or exiting insert mode (`evil-mode')."
|
||
(when (bound-and-true-p evil-local-mode)
|
||
(add-hook 'evil-insert-state-exit-hook #'org-update-parent-todo-statistics nil t))
|
||
(add-hook 'before-save-hook #'org-update-parent-todo-statistics nil t))
|
||
|
||
(general-def 'normal org-mode-map
|
||
"C-<return>" '+org/insert-item-below)
|
||
(general-def 'insert org-mode-map
|
||
"C-<return>" '+org/insert-item-below)
|
||
|
||
(use-package org-re-reveal
|
||
:ensure nil
|
||
:config
|
||
(setq org-re-reveal-root "file:///home/chris/org/presentations/reveal.js/"
|
||
org-re-reveal-theme "serif"
|
||
org-re-reveal-transition "slide"
|
||
org-re-reveal-mobile-app t)
|
||
)
|
||
|
||
(use-package ox-zola
|
||
:load-path "ox-zola/"
|
||
:config
|
||
(setq org-hugo-base-dir "/home/chris/dev/cochrun.xyz"
|
||
org-hugo-section "blog"))
|
||
|
||
(use-package gptel
|
||
:ensure t
|
||
:commands (gptel-send
|
||
gptel)
|
||
:config
|
||
(setq gptel-default-mode 'org-mode
|
||
gptel-api-key "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"))
|
||
|
||
(use-package jinx
|
||
:hook (emacs-startup . global-jinx-mode)
|
||
:init (flyspell-mode -1)
|
||
:config (flyspell-mode -1)
|
||
:bind (("M-c" . jinx-correct)
|
||
("C-M-$" . Jinx-Languages)))
|
||
|
||
(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))
|
||
|
||
(setq home-directory "~/")
|
||
(defun chris/eww-mpv ()
|
||
"Launch the url in mpv"
|
||
(interactive)
|
||
(let ((pt (avy-with ace-link-eww
|
||
(avy-process
|
||
(mapcar #'cdr (ace-link--eww-collect))
|
||
(avy--style-fn avy-style)))))
|
||
|
||
(when (number-or-marker-p pt)
|
||
(goto-char pt)
|
||
(let ((url (get-text-property (point) 'shr-url)))
|
||
(if (start-process "mpv" "mpv-output" "mpv" url)
|
||
(message (concat "mpv started => " url))
|
||
(message "mpv failed, maybe this isn't a link?"))))))
|
||
|
||
;; (defun chris/)
|
||
|
||
(defun chris/eww-video-dl ()
|
||
"Download the video at the url"
|
||
(interactive)
|
||
(let ((pt (avy-with ace-link-eww
|
||
(avy-process
|
||
(mapcar #'cdr (ace-link--eww-collect))
|
||
(avy--style-fn avy-style)))))
|
||
|
||
(when (number-or-marker-p pt)
|
||
(goto-char pt)
|
||
(let ((url (get-text-property (point) 'shr-url)))
|
||
(if (start-process
|
||
"yt-dlp"
|
||
"yt-dlp-output"
|
||
"yt-dlp" "-o" (concat home-directory "Videos/%(title)s.%(ext)s") url)
|
||
(message (concat "downloading => " url))
|
||
(message "idk this failed I guess..."))
|
||
(pop-to-buffer "yt-dlp-output")
|
||
(comint-mode)
|
||
(evil-normal-state)
|
||
(general-def 'normal comint-mode-map
|
||
"q" 'kill-buffer-and-window)))))
|
||
|
||
(setq eww-search-prefix "https://search.tfcconnection.org/search?q=")
|
||
|
||
(general-def 'normal eww-mode-map
|
||
"gv" 'chris/eww-mpv
|
||
"gV" 'chris/eww-video-dl)
|
||
|
||
(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 "C-n"
|
||
consult-project-root-function 'projectile-project-root)
|
||
|
||
(consult-customize
|
||
consult-org-heading :preview-key nil)
|
||
|
||
(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
|
||
"sf" 'consult-find
|
||
"sm" 'bookmark-jump
|
||
"sf" 'consult-flymake
|
||
"sy" 'consult-yank-from-kill-ring
|
||
"sb" 'consult-eglot-symbols))
|
||
|
||
(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 wgrep)
|
||
|
||
(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)
|
||
(corfu-auto-delay 0.5)
|
||
|
||
;; 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-prefix-p "~" pattern)
|
||
`(orderless-flex . ,(substring pattern 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 4)
|
||
)
|
||
|
||
(use-package kind-icon
|
||
:ensure t
|
||
:after corfu
|
||
:custom
|
||
(kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
|
||
:config
|
||
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
|
||
|
||
(use-package devdocs
|
||
:config
|
||
(evil-collection-devdocs-setup)
|
||
:general
|
||
(chris/leader-keys 'normal
|
||
"hd" 'devdocs-lookup))
|
||
|
||
(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
|
||
"ic" '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
|
||
"gd" 'projectile-run-gdb
|
||
"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
|
||
(if (string= system-name "syl")
|
||
'(("\\*e?shell\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.25))
|
||
("\\*e?shell-terminal\\*"
|
||
(display-buffer-same-window))
|
||
("*helpful*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("*compilation*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("*rustic-compilation*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("*gud-presenter*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("*dired-side*"
|
||
(display-buffer-in-side-window)
|
||
(side . left)
|
||
(window-width . 0.3))
|
||
("*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))
|
||
("\\*Async Shell Command\\*"
|
||
(display-buffer-no-window))
|
||
)
|
||
|
||
'(("\\*e?shell\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.25))
|
||
("\\*e?shell-terminal\\*"
|
||
(display-buffer-same-window))
|
||
("*helpful*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.25))
|
||
("*compilation*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.25))
|
||
("*rustic-compilation*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.25))
|
||
("*gud-presenter*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.25))
|
||
("*org-roam*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.3))
|
||
("\\*elfeed-entry\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.70))
|
||
("*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))
|
||
("\\*Async Shell Command\\*"
|
||
(display-buffer-no-window))
|
||
)
|
||
))
|
||
|
||
(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))
|
||
(condition-case nil
|
||
(help-fns--autoloaded-p sym file-name)
|
||
; new in Emacs 29.0.50
|
||
; see https://github.com/Wilfred/helpful/pull/283
|
||
(error (help-fns--autoloaded-p sym)))))
|
||
|
||
(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 t)
|
||
|
||
(defvar read-symbol-positions-list nil)
|
||
(add-to-list 'comint-output-filter-functions 'ansi-color-process-output)
|
||
(add-hook 'comint-mode-hook 'ansi-color-for-comint-mode-on)
|
||
(add-hook 'compilation-filter-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)
|
||
|
||
(use-package smartparens
|
||
:config
|
||
(smartparens-global-mode +1)
|
||
:general
|
||
('normal lisp-mode-map
|
||
"gl" 'sp-forward-slurp-sexp
|
||
"gh" 'sp-backward-slurp-sexp
|
||
"C-l" 'sp-forward-sexp
|
||
"C-h" 'sp-backward-sexp)
|
||
('normal lisp-shared-mode-map
|
||
"gl" 'sp-forward-slurp-sexp
|
||
"gh" 'sp-backward-slurp-sexp
|
||
"C-l" 'sp-forward-sexp
|
||
"C-h" 'sp-backward-sexp)
|
||
('normal sly-mrepl-mode-map
|
||
"gl" 'sp-forward-slurp-sexp
|
||
"gh" 'sp-backward-slurp-sexp
|
||
"C-l" 'sp-forward-sexp
|
||
"C-h" 'sp-backward-sexp)
|
||
('normal cider-repl-mode-map
|
||
"gl" 'sp-forward-slurp-sexp
|
||
"gh" 'sp-backward-slurp-sexp
|
||
"C-l" 'sp-forward-sexp
|
||
"C-h" 'sp-backward-sexp)
|
||
('normal clojurescript-mode-map
|
||
"gl" 'sp-forward-slurp-sexp
|
||
"gh" 'sp-backward-slurp-sexp
|
||
"C-l" 'sp-forward-sexp
|
||
"C-h" 'sp-backward-sexp))
|
||
|
||
(add-to-list 'auto-mode-alist '("\\.yuck?\\'" . lisp-data-mode))
|
||
|
||
|
||
|
||
(defun astyle-this-buffer ()
|
||
"Use astyle command to auto format c/c++ code."
|
||
(interactive "r")
|
||
(let* ((original-point (point))) ;; save original point before processing, thanks to @Scony
|
||
(progn
|
||
(if (executable-find "astyle")
|
||
(shell-command-on-region
|
||
(point-min) (point-max)
|
||
(concat
|
||
"astyle"
|
||
" --style=" cc-mode-code-style
|
||
" --indent=spaces=" (number-to-string c-basic-offset)
|
||
" --pad-oper"
|
||
" --pad-header"
|
||
" --break-blocks"
|
||
" --delete-empty-lines"
|
||
" --align-pointer=type"
|
||
" --align-reference=name")
|
||
(current-buffer) t
|
||
(get-buffer-create "*Astyle Errors*") t)
|
||
(message "Cannot find binary \"astyle\", please install first."))
|
||
(goto-char original-point)))) ;; restore original point
|
||
|
||
(defun astyle-before-save ()
|
||
"Auto styling before saving."
|
||
(interactive)
|
||
(when (member major-mode '(cc-mode c++-mode c-mode))
|
||
(astyle-this-buffer)))
|
||
|
||
(add-hook 'c-mode-common-hook (lambda () (add-hook 'before-save-hook 'astyle-before-save)))
|
||
|
||
(use-package rustic
|
||
:config
|
||
;; comment to disable rustfmt on save
|
||
(setq rustic-format-on-save t
|
||
rustic-lsp-client 'eglot)
|
||
:general
|
||
(general-def 'normal rustic-mode-map
|
||
"!" 'rustic-run-shell-command
|
||
"gC" 'rustic-cargo-check
|
||
"gA" 'rustic-cargo-add)
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"gc" 'rustic-compile))
|
||
|
||
(use-package web-mode
|
||
:mode "\\.html\\'"
|
||
:config
|
||
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.phtml?\\'" . web-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
|
||
(add-to-list 'auto-mode-alist '("\\.djhtml?\\'" . web-mode))
|
||
|
||
(setq web-mode-enable-auto-pairing t
|
||
web-mode-enable-auto-expanding t
|
||
web-mode-enable-auto-closing t
|
||
web-mode-enable-current-column-highlight t
|
||
web-mode-enable-current-element-highlight t)
|
||
|
||
:general
|
||
(general-def 'normal web-mode-map
|
||
"TAB" 'indent-according-to-mode)
|
||
(general-def 'insert web-mode-map
|
||
"TAB" 'indent-according-to-mode)
|
||
)
|
||
|
||
(use-package lua-mode
|
||
:mode ("\\.lua\\'" . lua-mode))
|
||
|
||
(use-package nix-mode
|
||
:mode "\\.nix\\'")
|
||
|
||
(use-package eglot
|
||
:commands eglot
|
||
:hook
|
||
(c++-mode . eglot-ensure)
|
||
(c++-ts-mode . eglot-ensure)
|
||
(rust-mode . eglot-ensure)
|
||
(rustic-mode . eglot-ensure)
|
||
(rust-ts-mode . eglot-ensure)
|
||
:general
|
||
(general-def 'normal eglot-mode-map
|
||
"ga" 'eglot-code-actions))
|
||
|
||
(use-package consult-eglot
|
||
:general
|
||
(general-def 'normal eglot-mode-map
|
||
"gs" 'consult-eglot-symbols))
|
||
|
||
(use-package cmake-mode
|
||
:mode ("\\CMakeLists.txt\\'" . cmake-mode))
|
||
|
||
(use-package fennel-mode
|
||
:mode ("\\.fnl\\'" . fennel-mode))
|
||
|
||
;; First install the package:
|
||
(use-package flycheck-clj-kondo
|
||
:ensure t)
|
||
|
||
;; then install the checker as soon as `clojure-mode' is loaded
|
||
(use-package clojure-mode
|
||
:ensure t
|
||
:config
|
||
(require 'flycheck-clj-kondo))
|
||
|
||
(use-package cider
|
||
:after clojure-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)
|
||
("\\.rmd\\'". markdown-mode))
|
||
:config
|
||
(setq markdown-fontify-code-blocks-natively t)
|
||
(add-hook 'markdown-mode-hook 'chris/org-mode-setup)
|
||
:general
|
||
(general-def 'normal markdown-mode-map
|
||
"C-j" 'markdown-next-visible-heading
|
||
"M-j" 'markdown-move-down
|
||
"C-k" 'markdown-previous-visible-heading
|
||
"M-k" 'markdown-move-up))
|
||
|
||
(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 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 php-mode
|
||
:mode ("\\.php\\'" . php-mode))
|
||
|
||
(use-package direnv
|
||
:config
|
||
(direnv-mode))
|
||
|
||
(use-package dired
|
||
:ensure 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)))
|
||
|
||
(defun chris/dired-open-wm ()
|
||
"Open dired as file-manager in wm"
|
||
(interactive)
|
||
(with-selected-frame (make-frame '((name . "dired")))
|
||
(dired-jump)
|
||
(toggle-truncate-lines +1)))
|
||
|
||
(defun chris/dired-open-videos ()
|
||
"Open dired in Videos as file-manager in wm"
|
||
(interactive)
|
||
(with-selected-frame (make-frame '((name . "dired")))
|
||
(dired "~/Videos/")
|
||
(toggle-truncate-lines +1)))
|
||
|
||
(defun chris/setup-dired ()
|
||
"setup dired"
|
||
(setq truncate-lines t)
|
||
(visual-line-mode nil)
|
||
(dired-hide-details-mode t))
|
||
|
||
(defun chris/open-dired-sidewindow ()
|
||
"Open dired as a side window to the main window on the left"
|
||
(interactive)
|
||
(with-current-buffer (get-buffer-create "dired-side")
|
||
(dired-jump)))
|
||
|
||
(setq dired-dwim-target t
|
||
delete-by-moving-to-trash t
|
||
dired-mouse-drag-files 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 'chris/setup-dired)
|
||
|
||
: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
|
||
"M-<return>" 'ffap-other-window
|
||
"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 dired-sidebar
|
||
:ensure t
|
||
:commands (dired-sidebar-toggle-sidebar)
|
||
:general
|
||
(general-def 'normal
|
||
"gD" 'dired-sidebar-toggle-sidebar))
|
||
|
||
(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 fd-dired)
|
||
|
||
(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
|
||
:load-path "/usr/share/emacs/site-lisp/mu4e/"
|
||
:init
|
||
(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
|
||
mu4e-mu-binary "/etc/profiles/per-user/chris/bin/mu"
|
||
mu4e-compose-signature-auto-include nil
|
||
mu4e-headers-fields
|
||
'((:human-date . 12)
|
||
(:flags . 10)
|
||
(:from . 22)
|
||
(:subject))
|
||
mu4e-headers-flagged-mark '("F" . " ")
|
||
mu4e-headers-replied-mark '("R" . " ")
|
||
mu4e-headers-personal-mark '("p" . " ")
|
||
mu4e-headers-list-mark '("s" . " "))
|
||
|
||
:config
|
||
(setq mail-user-agent 'mu4e-user-agent)
|
||
|
||
(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\nchris@tfcconnection.org\nchris@cochrun.xyz")))
|
||
(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\" AND NOT maildir:\"/office/Archive\" AND NOT maildir:\"/outlook/Archive\" AND NOT maildir:\"/cochrun/Archive\" AND NOT maildir:\"/cochrun/Junk\""
|
||
: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-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 mail-user-agent 'mu4e-user-agent
|
||
org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil \\n:t"
|
||
org-msg-startup "hidestars indent inlineimages"
|
||
org-msg-greeting-fmt "\n%s\n"
|
||
org-msg-recipient-names '(("chris@tfcconnection.org" . "Chris Cochrun"))
|
||
org-msg-greeting-name-limit 3
|
||
org-msg-default-alternatives '((new . (text html))
|
||
(reply-to-html . (text html))
|
||
(reply-to-text . (text)))
|
||
org-msg-convert-citation t
|
||
org-msg-signature "
|
||
|
||
#+begin_signature
|
||
--
|
||
*Chris*
|
||
/Praising God in all things!/
|
||
#+end_signature"))
|
||
|
||
(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://thrillshare-cmsv2.services.thrillshare.com/api/v4/o/6958/cms/events/generate_ical?filter_ids§ion_ids" "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 :height 0.7)))
|
||
;; '(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))))
|
||
(setq cfw:fchar-junction ?╋
|
||
cfw:fchar-vertical-line ?┃
|
||
cfw:fchar-horizontal-line ?━
|
||
cfw:fchar-left-junction ?┣
|
||
cfw:fchar-right-junction ?┫
|
||
cfw:fchar-top-junction ?┯
|
||
cfw:fchar-top-left-corner ?┏
|
||
cfw:fchar-top-right-corner ?┓)
|
||
: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 t
|
||
: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 :height 1.0))
|
||
(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 (lambda () (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 $*")
|
||
("less" "view-file $1")
|
||
("gg" "magit-status")
|
||
("clear" "clear-scrollback")
|
||
("!!" "eshell-previous-input 2")
|
||
("yay" "paru $1")
|
||
("yeet" "paru -Rns $1")
|
||
("nixs" "nix search nixpkgs $1")
|
||
("myip" "curl icanhazip.com")
|
||
("ytd" "yt-dlp -o ~/Videos/%(title)s.%(ext)s $1")
|
||
("nupg" "upgrade-nix")
|
||
("nupd" "update-nix")
|
||
("ksb" "/home/chris/dev/kde/src/kdesrc-build/kdesrc-build")
|
||
("ws" "rsync -avzP public/ chris@staff.tfcconnection.org:tfcconnection")
|
||
("wttr" "curl wttr.in/@home.cochrun.xyz")))
|
||
|
||
(defun chris/eshell-new()
|
||
"Open a new eshell buffer"
|
||
(interactive)
|
||
(eshell 'N))
|
||
|
||
(defun chris/eshell-switch()
|
||
"interactively switch between eshell buffers"
|
||
(interactive)
|
||
(consult-buffer))
|
||
|
||
(defun chris/eshell-window ()
|
||
"Open a new emacs window with eshell as a sole buffer"
|
||
(interactive)
|
||
(with-selected-frame (make-frame '((name . "*eshell-terminal*")))
|
||
(setq eshell-terminal (eshell 100))
|
||
(display-buffer-same-window
|
||
(generate-new-buffer-name "*eshell-terminal*") '())
|
||
(eshell 100)
|
||
(other-window 1)
|
||
(switch-to-buffer "*eshell*<100>")
|
||
(other-window 1)
|
||
(delete-window)))
|
||
|
||
(add-hook 'eshell-load-hook #'eat-eshell-mode)
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"oe" 'chris/eshell-new
|
||
"be" 'eshell)
|
||
(general-def '(normal insert) eshell-mode-map
|
||
"C-d" 'kill-buffer-and-window))
|
||
|
||
(add-hook 'eshell-load-hook #'eat-eshell-mode)
|
||
|
||
(setq vterm-buffer-name-string "vterm %s")
|
||
(defun chris/vterm-setup ()
|
||
"Setup vterm with my preferred settings"
|
||
(display-line-numbers-mode -1))
|
||
(add-hook 'vterm-mode-hook 'chris/vterm-setup)
|
||
|
||
(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))
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'lisp-mode-shared-map
|
||
"os" 'sly)
|
||
|
||
(general-def 'normal lisp-mode-shared-map
|
||
"gcr" 'sly))
|
||
|
||
(use-package pdf-tools
|
||
:mode ("\\.pdf\\'" . pdf-view-mode)
|
||
:init
|
||
;; (setq pdf-info-epdfinfo-program "/nix/store/6pc8vs42xbfah1h8h050a77p7vpr12kc-emacs-packages-deps/share/emacs/site-lisp/elpa/pdf-tools-20220823/epdfinfo"
|
||
;; pdf-tools-directory "/nix/store/6pc8vs42xbfah1h8h050a77p7vpr12kc-emacs-packages-deps/share/emacs/site-lisp/elpa/pdf-tools-20220823/")
|
||
(pdf-tools-install)
|
||
:config
|
||
(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 130
|
||
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)
|
||
|
||
(defun chris/elfeed-eww-browse ()
|
||
(interactive)
|
||
(let* ((entry (elfeed-search-selected :ignore-region))
|
||
(link (elfeed-entry-link entry)))
|
||
(message link)
|
||
(eww link)))
|
||
|
||
: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
|
||
"b" 'chris/elfeed-eww-browse)
|
||
(general-def 'normal elfeed-show-mode-map
|
||
"b" 'eww))
|
||
|
||
(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*"))
|
||
|
||
(defun chris/bongo-ytdlp ()
|
||
"Download the video or item using yt-dlp"
|
||
(interactive)
|
||
(while bongo-uri-p
|
||
(message bongo-file-name)))
|
||
|
||
: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)
|
||
(setq emms-player-list '(emms-player-vlc))
|
||
(setq emms-source-file-default-directory "~/Music/"
|
||
emms-tag-editor-tag-ogg-program "mid3v2")
|
||
|
||
(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
|
||
"ml" 'emms-browser
|
||
"mp" 'emms-pause
|
||
"ma" 'emms-add-dired
|
||
"mr" 'emms-toggle-repeat-track
|
||
"mn" 'emms-next
|
||
"mb" 'emms-previous
|
||
"m]" 'emms-seek-forward
|
||
"m[" 'emms-seek-backward)
|
||
(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 t
|
||
:config (auth-source-pass-enable))
|
||
|
||
(use-package pass
|
||
:defer t)
|
||
|
||
(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
|
||
:ensure t)
|
||
|
||
(use-package ement
|
||
:ensure t
|
||
: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))
|
||
|
||
(use-package mastodon
|
||
:config
|
||
(setq mastodon-instance-url "https://mastodon.online"
|
||
mastodon-active-user "chriscochrun")
|
||
:general
|
||
(chris/leader-keys
|
||
"oF" 'mastodon)
|
||
(general-def 'normal mastodon-mode-map
|
||
:states 'normal
|
||
"q" 'bury-buffer
|
||
"p" 'mastodon-toot
|
||
"r" 'mastodon-tl--update
|
||
"b" 'mastodon-toot--toggle-boost
|
||
"H" 'mastodon-tl--get-home-timeline
|
||
"F" 'mastodon-tl--get-federated-timeline
|
||
"v" 'chris/elfeed-bongo-insert-item
|
||
"N" 'mastodon-notifications--timeline))
|
||
|
||
(use-package qrencode)
|
||
|
||
;; 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 2
|
||
gcmh-high-cons-threshold (* 128 1024 1024) ; 128mb
|
||
gcmh-verbose nil))
|
||
|
||
(setq warning-suppress-types '((comp)))
|