4365 lines
155 KiB
EmacsLisp
4365 lines
155 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)
|
||
|
||
(setq default-frame-alist '((undecorated . t)))
|
||
(tool-bar-mode -1)
|
||
(tooltip-mode -1)
|
||
(set-fringe-mode +1)
|
||
(scroll-bar-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)
|
||
(set-frame-parameter nil 'undecorated 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"
|
||
(interactive)
|
||
(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 85)
|
||
(add-to-list 'default-frame-alist '(alpha-background . 85))
|
||
(add-to-list 'initial-frame-alist '(alpha-background . 85)))
|
||
|
||
(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)
|
||
;; (savehist-mode +1)
|
||
;; (add-to-list 'savehist-additional-variables 'register-alist)
|
||
;; (add-to-list 'savehist-additional-variables kill-ring)
|
||
|
||
(add-to-list 'exec-path "/home/chris/bin")
|
||
(add-to-list 'exec-path "/home/chris/.cargo/bin")
|
||
|
||
(setq initial-major-mode 'org-mode)
|
||
(setq initial-scratch-message "#+TITLE: SCRATCH\n#+DESCRIPTION: This buffer is for temporary things\n")
|
||
|
||
(setq require-final-newline nil)
|
||
|
||
(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)))))
|
||
|
||
(require 'package)
|
||
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
|
||
(package-initialize)
|
||
|
||
(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)
|
||
|
||
(defun chris/home-manager-reload ()
|
||
(interactive)
|
||
(let* ((which-emacs (shell-command-to-string "nix-store --query $(which emacs)"))
|
||
(pattern (rx "newLoadPath+=(/nix/store/"
|
||
(group (* any))
|
||
"-emacs-packages-deps/share/emacs/site-lisp)"))
|
||
(current-deps (when (string-match pattern which-emacs)
|
||
(match-string 1 which-emacs)))
|
||
(subdirs (concat "/nix/store/" current-deps "-emacs-packages-deps/share/emacs/site-lisp/subdirs.el"))
|
||
(native (concat "/nix/store/" current-deps "-emacs-packages-deps/share/emacs/native-lisp/")))
|
||
(load-file subdirs)
|
||
(when (boundp 'native-comp-eln-load-path)
|
||
(add-to-list 'native-comp-eln-load-path native))))
|
||
|
||
(use-package all-the-icons)
|
||
|
||
(use-package doom-modeline
|
||
:init
|
||
(doom-modeline-mode 0)
|
||
(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))
|
||
|
||
(use-package mini-echo
|
||
:init
|
||
(mini-echo-mode 1)
|
||
(setq mini-echo-default-segments '(:long
|
||
("evil" "major-mode" "buffer-name" "vcs" "buffer-position" "buffer-size"
|
||
"flymake" "process" "selection-info" "narrow" "macro" "profiler")
|
||
:short
|
||
("buffer-name-short" "buffer-position" "process" "profiler"
|
||
"selection-info" "narrow" "macro"))
|
||
mini-echo-rules '((org-mode :long
|
||
(("evil" . 1)
|
||
("major-mode" . 2)
|
||
("buffer-name" . 3)
|
||
("word-count" . 4))))
|
||
mini-echo-right-padding 2
|
||
mini-echo-buffer-status-style 'both
|
||
mini-echo-update-interval 0.2)
|
||
|
||
(set-face-foreground 'mini-echo-blue "#57c7ff")
|
||
(set-face-foreground 'mini-echo-red "#ff5c57")
|
||
(set-face-foreground 'mini-echo-magenta "#ff6ac1")
|
||
(set-face-foreground 'mini-echo-green "#5af78e")
|
||
(set-face-foreground 'mini-echo-gray "#848688")
|
||
(set-face-foreground 'mini-echo-yellow "#f3f99d")
|
||
(set-face-foreground 'mini-echo-cyan "#9aedfe")
|
||
|
||
(defun chris/mini-echo-minibuffer-width-lessp ()
|
||
"Return non-nil if current minibuffer window width less than 120."
|
||
(< (mini-echo-minibuffer-width) 100))
|
||
|
||
(setq mini-echo-short-style-predicate 'chris/mini-echo-minibuffer-width-lessp)
|
||
|
||
:config
|
||
(defun chris/toggle-mode-lines ()
|
||
"Switch between doom and mini-echo"
|
||
(interactive)
|
||
(if mini-echo-mode
|
||
(eval (mini-echo-mode 0) (doom-modeline-mode 1))
|
||
(eval (doom-modeline-mode 0) (mini-echo-mode 1)))))
|
||
|
||
(setq xref-search-program 'ripgrep)
|
||
|
||
(add-to-list 'exec-path "/usr/bin")
|
||
(add-to-list 'exec-path "~/.cargo/bin")
|
||
(setenv "NIX_CONF_DIR" "/etc/nix")
|
||
(setenv "NIX_REMOTE" "daemon")
|
||
(setenv "XCURSOR_THEME" "phinger-cursors-light")
|
||
(setenv "QT_SCALE_FACTOR" "1")
|
||
(setenv "QT_QPA_PLATFORM" "wayland;xcb")
|
||
(setenv "CLUTTER_BACKEND" "wayland")
|
||
(setenv "GDK_BACKEND" "wayland,x11")
|
||
(setenv "SDL_VIDEODRIVER" "wayland")
|
||
(setenv "XDG_SESSION_TYPE" "wayland")
|
||
|
||
(defun chris/nix-reload ()
|
||
(interactive)
|
||
(let* ((query (shell-command-to-string "nix-store --query $(which emacs)"))
|
||
(store-path (expand-file-name "share/emacs" (string-trim query))))
|
||
(load-file (expand-file-name "site-lisp/subdirs.el" store-path))
|
||
(when (boundp 'native-comp-eln-load-path)
|
||
(add-to-list 'native-comp-eln-load-path (expand-file-name "native-lisp/" store-path)))))
|
||
|
||
(setenv "WAYLAND_DISPLAY" "wayland-1")
|
||
|
||
(executable-find "ssh")
|
||
(setq ispell-program-name "hunspell"
|
||
ispell-local-dictionary "en_US"
|
||
ispell-local-dictionary-alist
|
||
;; Please note the list `("-d" "en_US")` contains ACTUAL parameters passed to hunspell
|
||
;; You could use `("-d" "en_US,en_US-med")` to check with multiple dictionaries
|
||
'(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)))
|
||
(add-hook 'org-mode-hook 'chris/org-mode-setup)
|
||
|
||
(setq proced-auto-update-flag t)
|
||
|
||
(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
|
||
)
|
||
|
||
(use-package ligature
|
||
:load-path "path-to-ligature-repo"
|
||
:config
|
||
;; Enable the "www" ligature in every possible major mode
|
||
(ligature-set-ligatures 't '("www"))
|
||
;; Enable traditional ligature support in eww-mode, if the
|
||
;; `variable-pitch' face supports it
|
||
(ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
|
||
;; Enable all Cascadia and Fira Code ligatures in programming modes
|
||
(ligature-set-ligatures 'prog-mode
|
||
'(;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~
|
||
;; =:= =!=
|
||
("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "="))))
|
||
;; ;; ;;;
|
||
(";" (rx (+ ";")))
|
||
;; && &&&
|
||
("&" (rx (+ "&")))
|
||
;; !! !!! !. !: !!. != !== !~
|
||
("!" (rx (+ (or "=" "!" "\." ":" "~"))))
|
||
;; ?? ??? ?: ?= ?.
|
||
("?" (rx (or ":" "=" "\." (+ "?"))))
|
||
;; %% %%%
|
||
("%" (rx (+ "%")))
|
||
;; |> ||> |||> ||||> |] |} || ||| |-> ||-||
|
||
;; |->>-||-<<-| |- |== ||=||
|
||
;; |==>>==<<==<=>==//==/=!==:===>
|
||
("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]"
|
||
"-" "=" ))))
|
||
;; \\ \\\ \/
|
||
("\\" (rx (or "/" (+ "\\"))))
|
||
;; ++ +++ ++++ +>
|
||
("+" (rx (or ">" (+ "+"))))
|
||
;; :: ::: :::: :> :< := :// ::=
|
||
(":" (rx (or ">" "<" "=" "//" ":=" (+ ":"))))
|
||
;; // /// //// /\ /* /> /===:===!=//===>>==>==/
|
||
("/" (rx (+ (or ">" "<" "|" "/" "\\" "\*" ":" "!"
|
||
"="))))
|
||
;; .. ... .... .= .- .? ..= ..<
|
||
("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\."))))
|
||
;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-|
|
||
("-" (rx (+ (or ">" "<" "|" "~" "-"))))
|
||
;; *> */ *) ** *** ****
|
||
("*" (rx (or ">" "/" ")" (+ "*"))))
|
||
;; www wwww
|
||
("w" (rx (+ "w")))
|
||
;; <> <!-- <|> <: <~ <~> <~~ <+ <* <$ </ <+> <*>
|
||
;; <$> </> <| <|| <||| <|||| <- <-| <-<<-|-> <->>
|
||
;; <<-> <= <=> <<==<<==>=|=>==/==//=!==:=>
|
||
;; << <<< <<<<
|
||
("<" (rx (+ (or "\+" "\*" "\$" "<" ">" ":" "~" "!"
|
||
"-" "/" "|" "="))))
|
||
;; >: >- >>- >--|-> >>-|-> >= >== >>== >=|=:=>>
|
||
;; >> >>> >>>>
|
||
(">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-"))))
|
||
;; #: #= #! #( #? #[ #{ #_ #_( ## ### #####
|
||
("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_"
|
||
(+ "#"))))
|
||
;; ~~ ~~~ ~= ~- ~@ ~> ~~>
|
||
("~" (rx (or ">" "=" "-" "@" "~>" (+ "~"))))
|
||
;; __ ___ ____ _|_ __|____|_
|
||
("_" (rx (+ (or "_" "|"))))
|
||
;; Fira code: 0xFF 0x12
|
||
;; ("0" (rx (and "x" (+ (in "A-F" "a-f" "0-9")))))
|
||
;; Fira code:
|
||
;; "Fl" "Tl" "fi" "fj" "fl" "ft"
|
||
;; The few not covered by the regexps.
|
||
"{|" "[|" "]#" "(*" "}#" "$>" "^="))
|
||
;; Enables ligature checks globally in all buffers. You can also do it
|
||
;; per mode with `ligature-mode'.
|
||
(global-ligature-mode t))
|
||
|
||
(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 evil-escape
|
||
:after evil
|
||
:init (evil-escape-mode +1)
|
||
:config
|
||
(defun chris/toggle-evil-escape-sequence ()
|
||
(interactive)
|
||
(if (string= evil-escape-key-sequence "ae")
|
||
(setq evil-escape-key-sequence "fd")
|
||
(setq evil-escape-key-sequence "ae")))
|
||
|
||
(setq evil-escape-key-sequence (kbd "ae")
|
||
evil-escape-delay 0.3))
|
||
|
||
(use-package evil-surround
|
||
:after evil
|
||
:config
|
||
(global-evil-surround-mode +1))
|
||
|
||
(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/find-videos ()
|
||
(interactive)
|
||
(find-file (expand-file-name "vids" "~")))
|
||
|
||
(defun chris/open-bible ()
|
||
"find a bible to open"
|
||
(interactive)
|
||
(find-file "~/docs/bibles/esv.org")
|
||
)
|
||
|
||
(defun chris/transpose-lines (arg)
|
||
"Moves the current line or region and follows"
|
||
(interactive)
|
||
(cond
|
||
((and mark-active transient-mark-mode)
|
||
(if (> (point) (mark))
|
||
(exchange-point-and-mark))
|
||
(let ((column (current-column))
|
||
(text (delete-and-extract-region (point) (mark))))
|
||
(forward-line arg)
|
||
(move-to-column column t)
|
||
(set-mark (point))
|
||
(insert text)
|
||
(exchange-point-and-mark)
|
||
(setq deactivate-mark nil)))
|
||
(t
|
||
(beginning-of-line)
|
||
(when (or (> arg 0) (not (bobp)))
|
||
(forward-line)
|
||
(when (or (< arg 0) (not (eobp)))
|
||
(transpose-lines arg))
|
||
(forward-line -1)))))
|
||
|
||
(defun chris/transpose-lines-up ()
|
||
"Moves the lines up"
|
||
(interactive)
|
||
(transpose-lines 1)
|
||
(forward-line -2)
|
||
(indent-according-to-mode))
|
||
|
||
(defun chris/transpose-lines-down ()
|
||
"Moves the lines down"
|
||
(interactive)
|
||
(forward-line 1)
|
||
(transpose-lines 1)
|
||
(forward-line -1)
|
||
(indent-according-to-mode))
|
||
|
||
(defun chris/find-todo ()
|
||
"opens my todo file"
|
||
(interactive)
|
||
(find-file "/home/chris/docs/todo/todo.org"))
|
||
|
||
(general-create-definer chris/leader-keys
|
||
:keymaps '(normal visual emacs)
|
||
:prefix "SPC")
|
||
(chris/leader-keys
|
||
:states 'visual
|
||
:keymaps 'override
|
||
"d" '(execute-extended-command :which-key "execute command"))
|
||
(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")
|
||
"p" '(:ignore t :which-key "project")
|
||
"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")
|
||
"x" '(:ignore t :which-key "guix")
|
||
"v" '(:ignore t :which-key "mpv")
|
||
"xx" '(guix :which-key "guix")
|
||
"sp" '(:ignore t :which-key "passwords")
|
||
"bs" '(consult-buffer :which-key "buffer search")
|
||
"bd" '(kill-current-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")
|
||
"fv" '(chris/find-videos :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")
|
||
"ft" '(chris/find-todo :which-key "open todo file")
|
||
"fE" '(consult-file-externally :which-key "find file externally")
|
||
"fe" '(chris/edit-emacs-config :which-key "open config")
|
||
"hf" '(helpful-function :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" '(org-bible-jump :which-key "imenu")
|
||
"oP" '(proced :which-key "proced")
|
||
"ov" '(vterm :which-key "vterm")
|
||
"wo" '(other-window :which-key "other window")
|
||
"wn" '(evil-window-next :which-key "other window")
|
||
"wm" '(maximize-window :which-key "maximize 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")
|
||
"d" '(execute-extended-command :which-key "execute command")
|
||
"&" '(async-shell-command :which-key "async shell command")
|
||
":" '(eval-expression :which-key "evaluate expression")
|
||
"gc" '(project-compile :which-key "compile project"))
|
||
(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 'visual
|
||
"<down>" 'evil-next-visual-line
|
||
"<up>" 'evil-previous-visual-line)
|
||
(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
|
||
"<down>" 'evil-next-visual-line
|
||
"<up>" 'evil-previous-visual-line)
|
||
(general-def 'normal
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"C-M-j" 'chris/transpose-lines-down
|
||
"C-M-k" 'chris/transpose-lines-up)
|
||
(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
|
||
"C-<tab>" 'indent-for-tab-command))
|
||
|
||
(use-package hydra)
|
||
|
||
(use-package bluetooth
|
||
:after general
|
||
:general
|
||
(chris/leader-keys
|
||
"oT" 'bluetooth-list-devices))
|
||
|
||
(setq lpr-command "lpr -o sides=two-sided-long-edge -# ")
|
||
(defun chris/org-mode-setup ()
|
||
(interactive)
|
||
;; (org-indent-mode +1)
|
||
(toc-org-mode +1)
|
||
(smartparens-mode +1)
|
||
(visual-fill-column-mode +1)
|
||
(display-line-numbers-mode -1)
|
||
(variable-pitch-mode +1)
|
||
(jinx-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)
|
||
(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
|
||
|
||
;; Setup better completion functions for org mode
|
||
(setq-local completion-at-point-functions
|
||
(list (cape-capf-super #'cape-elisp-block #'cape-dabbrev #'cape-dict)))
|
||
(tempel-setup-capf))
|
||
|
||
(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)
|
||
(if (string= org-agenda-this-buffer-name "*Org Agenda(fa:area+LEVEL=1)*")
|
||
(org-agenda-columns)))
|
||
|
||
(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
|
||
:config
|
||
(setq org-startup-indented t
|
||
org-edit-src-content-indentation 0
|
||
org-indent-turns-on-hiding-stars nil
|
||
org-indent-mode-turns-on-hiding-stars nil
|
||
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
|
||
org-directory "~/docs/notes"
|
||
org-pretty-entities t)
|
||
|
||
(add-hook 'org-mode-hook 'chris/org-mode-setup)
|
||
(setq org-refile-targets '((org-agenda-files :maxlevel . 6) ("/home/chris/docs/todo/archive.org" :maxlevel . 6)))
|
||
|
||
(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 "~/docs/todo/todo.org")
|
||
(file ".templates/tasks.org") :prepend t)
|
||
("n" "Personal notes" plain
|
||
(file denote-last-path)
|
||
#'denote-org-capture
|
||
:no-save t
|
||
:immediate-finish nil
|
||
:kill-buffer t
|
||
:jump-to-captured t)
|
||
("p" "TFC Plan" entry
|
||
(function chris/denote-capture-lesson-file)
|
||
(file ".templates/tfcplantemplate.org")
|
||
:prepend nil
|
||
:jump-to-captured t
|
||
:empty-lines 1)
|
||
("l" "TFC Lesson" plain
|
||
(function chris/org-capture-denote-file-path)
|
||
(file ".templates/lessontemplate.org")
|
||
:prepend nil
|
||
:jump-to-captured t
|
||
:empyt-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" "~/docs/notes/icons/task.png" nil nil :ascent center)
|
||
("lesson" "~/docs/notes/icons/book.png" nil nil :ascent center)
|
||
("dev" "~/docs/notes/icons/coding.png" nil nil :ascent center)
|
||
("TODO" "~/docs/notes/icons/coding.png" nil nil :ascent center)))
|
||
|
||
(setq org-imenu-depth 4
|
||
org-odt-styles-file "/home/chris/docs/style.odt"
|
||
org-export-with-toc nil
|
||
org-export-with-author t
|
||
org-export-with-section-numbers 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
|
||
'("~/docs/todo/todo.org"
|
||
"~/dev/lumina/TODO.org"
|
||
"~/dev/tfcconnection/TODO.org"
|
||
"~/docs/notes/lessons/"
|
||
"~/docs/notes/20230919T090157--house-renovation__area.org")
|
||
org-id-method 'ts
|
||
org-agenda-tags-column -75
|
||
org-agenda-dim-blocked-tasks nil
|
||
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)))
|
||
|
||
(setq org-agenda-custom-commands
|
||
'(("w" todo "WAIT")
|
||
("f" . "Second brain")
|
||
("fa" tags "area+LEVEL=1")
|
||
("fr" tags "resource+LEVEL=1")
|
||
("fp" . "Projects")
|
||
("fpp" "All projects" tags-todo "project+LEVEL=1")
|
||
("fpt" "All TFC projects" tags-todo "project+tfc+LEVEL=1")
|
||
("fpd" "All Dev projects" tags-todo "project+dev")
|
||
("fA" tags "archive+LEVEL=1")
|
||
("h" . "Family searches")
|
||
("ha" tags "abbie")
|
||
("hl" tags "luke")
|
||
("hy" tags "ty")
|
||
("hj" tags "josiah")))
|
||
|
||
(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)))
|
||
(setq org-latex-title-command "\\maketitle\\vspace{-4em}")
|
||
|
||
(defun chris/org-publish-site ()
|
||
"Publish my website by pushing files to specific locations"
|
||
(interactive)
|
||
|
||
(let ((notes (directory-files "~/docs/notes" t ".*.org"))
|
||
(lessons (directory-files "~/docs/notes/lessons" t ".*.org"))
|
||
(denote-directory "~/docs/site/content"))
|
||
(cl-loop for file in notes
|
||
do (let ((filename (f-filename file)))
|
||
(copy-file file (concat "~/docs/site/content/notes/" filename) t)))
|
||
(cl-loop for file in lessons
|
||
do (let ((filename (f-filename file)))
|
||
(copy-file file (concat "~/docs/site/content/teaching/" filename) t)))
|
||
(find-file "~/docs/site/content/index.org")
|
||
(org-update-all-dblocks)
|
||
(save-buffer)
|
||
(org-publish "cochrun.xyz")))
|
||
|
||
|
||
(defun chris/website-dynamic-block ()
|
||
"A function to load up the links on the homepage for the website"
|
||
(let (files (directory-files "~/docs/site/content/notes/" t ".*.org"))
|
||
(cl-loop for file in files
|
||
do (insert (denote--link-get-description file)))))
|
||
|
||
(defun org-dblock-write:chris-site-notes ()
|
||
"A function to load up the links on the homepage for the website"
|
||
(let (files (directory-files "~/docs/site/content/notes/" t ".*.org"))
|
||
(cl-loop for file in files
|
||
do (insert (denote--link-get-description file)))))
|
||
|
||
(add-to-list 'org-dynamic-block-alist '("chris-site-notes" . chris/website-dynamic-block))
|
||
|
||
(setq org-publish-project-alist
|
||
`(("home"
|
||
:base-directory "~/docs/site/content"
|
||
:base-extension "org"
|
||
:recursive nil
|
||
:html-doctype "html5"
|
||
:html-html5-fancy t
|
||
:html-self-link-headlines t
|
||
:html-head "<link rel=\"stylesheet\" href=\"pico.css\" type=\"text/css\"/>"
|
||
:html-head "<link rel=\"stylesheet\" href=\"my.css\" type=\"text/css\"/>"
|
||
:publishing-directory "~/docs/notes/site/public/"
|
||
:publishing-function org-html-publish-to-html)
|
||
("posts"
|
||
:base-directory "~/docs/site/content/notes"
|
||
:base-extension "org"
|
||
:recursive nil
|
||
:html-doctype "html5"
|
||
:html-html5-fancy t
|
||
:html-self-link-headlines t
|
||
:htmlized-source t
|
||
:html-head "<link rel=\"stylesheet\" href=\"../pico.css\" type=\"text/css\"/>"
|
||
:publishing-directory "~/docs/site/public/notes/"
|
||
:publishing-function org-html-publish-to-html)
|
||
("teaching/preaching"
|
||
:base-directory "~/docs/site/content/teaching"
|
||
:base-extension "org"
|
||
:recursive nil
|
||
:html-doctype "html5"
|
||
:html-html5-fancy t
|
||
:html-self-link-headlines t
|
||
:htmlized-source t
|
||
:html-head "<link rel=\"stylesheet\" href=\"../pico.css\" type=\"text/css\"/>"
|
||
:publishing-directory "~/docs/site/public/teaching/"
|
||
:publishing-function org-html-publish-to-html)
|
||
("static"
|
||
:base-directory "~/docs/site/assets/"
|
||
:base-extension "css\\|txt\\|jpg\\|gif\\|png"
|
||
:recursive t
|
||
:html-doctype "html5"
|
||
:html-html5-fancy t
|
||
:publishing-directory "~/docs/site/public/static/"
|
||
:publishing-function org-publish-attachment)
|
||
("cochrun.xyz" :components ("home" "posts" "static" "teaching/preaching"))))
|
||
|
||
(setq org-html-postamble t
|
||
org-html-postamble-format '(("en"
|
||
"<footer> <p>Author: %a (%e)</p></footer>")))
|
||
|
||
(defun chris/org-cycle-hide-drawers-all ()
|
||
(interactive)
|
||
(chris/org-cycle-hide-drawers 'all))
|
||
|
||
(defun chris/org-cycle-hide-drawers-sub ()
|
||
(interactive)
|
||
(chris/org-cycle-hide-drawers 'subtree))
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"c" 'org-capture
|
||
"rr" 'org-refile
|
||
"E" 'org-export-dispatch
|
||
"oa" 'org-agenda
|
||
"gt" 'org-babel-tangle
|
||
"td" 'org-toggle-link-display
|
||
"tp" 'org-toggle-pretty-entities
|
||
"il" 'org-insert-link
|
||
"it" 'org-insert-todo-subheading)
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'org-mode-map
|
||
"is" 'org-time-stamp
|
||
"ta" 'chris/org-cycle-hide-drawers-all
|
||
"tp" (chris/org-cycle-hide-drawers 'children)
|
||
"th" 'chris/org-cycle-hide-drawers-sub
|
||
"iw" 'org-web-tools-insert-web-page-as-entry)
|
||
(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
|
||
"ga" 'jinx-correct
|
||
"ge" 'org-edit-src-code
|
||
"gr" 'revert-buffer
|
||
"gt" 'org-set-tags-command
|
||
"ze" 'org-emphasize
|
||
"zn" 'org-narrow-to-subtree
|
||
"zh" (chris/org-cycle-hide-drawers 'subtree)
|
||
"zw" 'widen
|
||
"zp" 'org-set-property
|
||
"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
|
||
"gs" 'org-time-stamp)
|
||
('visual org-mode-map
|
||
"gf" 'org-footnote-action
|
||
"gm" 'org-emphasize)
|
||
('insert org-mode-map
|
||
"C-i" 'completion-at-point)
|
||
('normal 'org-src-mode-map
|
||
"q" 'org-edit-src-abort))
|
||
|
||
(defun chris/denote-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* ((files (denote-directory-files))
|
||
(lessons (remove nil
|
||
(cl-loop for file in files
|
||
collect (if (string-match "lessons/" file) file))))
|
||
(lesson (completing-read "Select Lesson: " lessons nil nil '(".*_lesson" . 0))))
|
||
(find-file lesson)
|
||
(goto-char (point-min))
|
||
(search-forward "* PLAN")))
|
||
|
||
(defun chris/org-capture-denote-file-path ()
|
||
"Function returning the file placement using denote for capture"
|
||
(interactive)
|
||
(denote-subdirectory)
|
||
(save-buffer))
|
||
|
||
(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 'after-save-hook #'chris/org-babel-tangle-config)
|
||
|
||
(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"
|
||
:scheduled nil)
|
||
(: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 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 denote
|
||
:config
|
||
(require 'denote-org-extras)
|
||
(setq denote-directory "/home/chris/docs/notes"
|
||
denote-dired-directories '("/home/chris/docs/notes" "/home/chris/docs/notes/lessons")
|
||
denote-dired-directories-include-subdirectories t
|
||
denote-modules '(project xref ffap)
|
||
denote-known-keywords '("emacs" "bible" "jesus" "tfc" "lesson" "it" "dev"))
|
||
|
||
(setq denote-rename-buffer-format "[D] %>t")
|
||
(denote-rename-buffer-mode +1)
|
||
(setq denote-org-front-matter
|
||
"#+TITLE: %1$s\n#+AUTHOR: Chris Cochrun\n#+CREATED: %2$s\n#+filetags: %3$s\n#+identifier: %4$s\n")
|
||
(add-hook 'dired-mode-hook #'denote-dired-mode-in-directories)
|
||
|
||
;; (defvar denote-faces--file-name-regexp
|
||
;; (concat "\\(?1:[0-9]\\{8\\}\\)\\(?2:T[0-9]\\{6\\}\\)"
|
||
;; "\\(?:\\(?3:==\\)\\(?4:[[:alnum:][:nonascii:]=]*?\\)\\)?"
|
||
;; "\\(?:\\(?5:--\\)\\(?6:[[:alnum:][:nonascii:]-]*?\\)\\)?"
|
||
;; "\\(?:\\(?7:__\\)\\(?8:[[:alnum:][:nonascii:]_-]*?\\)\\)?"
|
||
;; "\\(?9:\\..*\\)?$")
|
||
;; "Regexp of file names for fontification.")
|
||
|
||
;; (defconst denote-faces-file-name-keywords
|
||
;; `((,(concat "[\t\s]+" denote-faces--file-name-regexp)
|
||
;; (1 'denote-faces-date)
|
||
;; (2 'denote-faces-time)
|
||
;; (3 'denote-faces-delimiter nil t)
|
||
;; (4 'denote-faces-signature nil t)
|
||
;; (5 'denote-faces-delimiter nil t)
|
||
;; (6 'denote-faces-title nil t)
|
||
;; (7 'denote-faces-delimiter nil t)
|
||
;; (8 'denote-faces-keywords nil t)
|
||
;; (9 'denote-faces-extension nil t )))
|
||
;; "Keywords for fontification of file names.")
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"nf" 'denote-open-or-create
|
||
"nb" 'denote-backlinks
|
||
"nk" 'denote-keywords-add
|
||
"nl" 'denote-link-or-create))
|
||
|
||
(use-package consult-denote
|
||
:config
|
||
(setq consult-denote-find-command 'consult-fd
|
||
consult-denote-grep-command 'consult-ripgrep)
|
||
(consult-denote-mode +1))
|
||
|
||
(defun chris/docx-to-denote-lesson ()
|
||
"Converts the docx file at point in dired to a denote
|
||
lesson file in my notes/lessons folder"
|
||
(interactive)
|
||
(let* ((file (expand-file-name (dired-file-name-at-point)))
|
||
(filename (f-filename file))
|
||
(orgname (string-replace "docx" "org" filename))
|
||
(process (call-process
|
||
"pandoc" nil nil nil "--wrap=none" "-o" orgname file)))
|
||
;; (cl-loop while (not (eq 'run (process-status process)))
|
||
;; do (message ""))
|
||
(save-excursion
|
||
(find-file orgname)
|
||
(revert-buffer t t nil)
|
||
(with-current-buffer (buffer-name)
|
||
(goto-char (point-min))
|
||
(replace-regexp " " " ")
|
||
(goto-char (point-min))
|
||
(replace-regexp "\n \n" "")
|
||
(save-buffer)
|
||
(goto-char (point-min))
|
||
(kill-ring-save (point-min) (point-max))
|
||
(org-capture)))))
|
||
|
||
(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
|
||
org-modern-star '("◉" "○" "◈" "◇" "✳"))
|
||
|
||
(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/docs/presentations/reveal.js/"
|
||
;; org-re-reveal-theme "serif"
|
||
org-re-reveal-transition "slide"
|
||
org-re-reveal-mobile-app t
|
||
org-re-reveal-width "90%")
|
||
(add-to-list 'org-re-reveal-plugin-config '(audio-slideshow "RevealAudioSlideshow" "plugin/audio-slideshow/plugin.js"))
|
||
|
||
(defun chris/org-re-reveal-export-to-html
|
||
(&optional async subtreep visible-only body-only ext-plist backend)
|
||
"Export current buffer to a reveal.js HTML file with a different name
|
||
so that it can exists within a static site showing the file as a document
|
||
as well as a presentation.
|
||
Optional ASYNC, SUBTREEP, VISIBLE-ONLY, BODY-ONLY, EXT-PLIST are passed
|
||
to `org-export-to-file'.
|
||
Optional BACKEND must be `re-reveal' or a backend derived from it."
|
||
(interactive)
|
||
(let* ((backend (or backend 're-reveal))
|
||
(extension (concat "-presentation" "." org-html-extension))
|
||
(client-ext (concat org-re-reveal-multiplex-client-ext extension))
|
||
(file (org-export-output-file-name extension subtreep))
|
||
(clientfile (org-export-output-file-name client-ext subtreep))
|
||
(org-html-container-element "div"))
|
||
|
||
(setq org-re-reveal-client-multiplex nil)
|
||
(org-export-to-file backend file
|
||
async subtreep visible-only body-only ext-plist)
|
||
|
||
;; Export the client HTML file if org-re-reveal-client-multiplex is set true
|
||
;; by previous call to org-export-to-file
|
||
(if org-re-reveal-client-multiplex
|
||
(org-export-to-file backend clientfile
|
||
async subtreep visible-only body-only ext-plist))
|
||
file)))
|
||
|
||
(use-package ox-hugo)
|
||
|
||
(use-package ox-zola
|
||
:load-path "ox-zola/"
|
||
:config
|
||
(setq org-hugo-base-dir "/home/chris/dev/cochrun.xyz"
|
||
org-hugo-section "blog"))
|
||
|
||
(defun chris/window-delete-popup-frame (&rest _)
|
||
"Kill selected selected frame if it has parameter `chris/window-popup-frame'.
|
||
Use this function via a hook."
|
||
(when (frame-parameter nil 'chris/window-popup-frame)
|
||
(delete-frame)))
|
||
|
||
(defmacro chris/window-define-with-popup-frame (command)
|
||
"Define interactive function which calls COMMAND in a new frame.
|
||
Make the new frame have the `chris/window-popup-frame' parameter."
|
||
`(defun ,(intern (format "chris/window-popup-%s" command)) ()
|
||
,(format "Run `%s' in a popup frame with `chris/window-popup-frame' parameter.
|
||
Also see `chris/window-delete-popup-frame'." command)
|
||
(interactive)
|
||
(let ((frame (make-frame '((chris/window-popup-frame . t)))))
|
||
(select-frame frame)
|
||
(switch-to-buffer " chris/window-hidden-buffer-for-popup-frame")
|
||
(condition-case nil
|
||
(call-interactively ',command)
|
||
((quit error user-error)
|
||
(delete-frame frame))))))
|
||
|
||
(chris/window-define-with-popup-frame org-capture)
|
||
(add-hook 'org-capture-after-finalize-hook #'chris/window-delete-popup-frame)
|
||
|
||
(use-package gptel
|
||
:init
|
||
(setq gptel-model "llama3.2:3b-instruct-fp16"
|
||
gptel-backend (gptel-make-ollama "ollama"
|
||
:host "ai.tfcconnection.org"
|
||
:protocol "https"
|
||
:stream t
|
||
:models '("deepseek-r1"))
|
||
gptel-default-mode #'org-mode)
|
||
(setq gptel-directives '((default
|
||
. "You are a large language model living in Emacs and a helpful assistant. Respond concisely.")
|
||
(programming
|
||
. "You are a large language model and a careful programmer. Provide code and thorough explanation to what you are doing. Please be thorough and teach me what you are trying to get across.")
|
||
(writing
|
||
. "You are a large language model and a writing assistant. Respond concisely.")
|
||
(chat
|
||
. "You are a large language model and a conversation partner. Respond concisely.")
|
||
(dnd . "Assume the role of an expert fantasy writer that specializes in interactive fiction, as well as the storyline, characters, locations, descriptions, groups and organizations, stories, events, and magical objects of Baldur’s Gate, Tales of the Sword Coast, Baldur’s Gate 2: Shadows of Amn, Throne of Bhaal, and Baldur’s Gate 3. The adventure takes place on the continent of Faerun.
|
||
|
||
Describe everything that follows in the present tense, in response to what I type, while accurately following the established lore of Baldur’s Gate, Tales of the Sword Coast, Baldur’s Gate 2: Shadows of Amn, Throne of Bhaal, and Baldur’s Gate 3, written in the descriptive style of R.A Salvatore. Provide names for characters, locations, groups and organizations, events, and magical objects. Characters should always use dialogue, enclosed in quotation marks when interacting with me or my party members, written in the conversational style of R.A Salvatore. Do not type, compose, dictate, influence, script, generate, control, or describe what me or my party members are doing, saying, acting, behaving, thinking, feeling, experiencing, or any other aspect concerning me or my party members throughout the entire adventure, scenario, story, location, quest, mission, scene, event, description, dialogue, and conversation. Use only one paragraph consisting of less than 80 words for all replies, descriptions, conversations, dialogue and text.")))
|
||
:general
|
||
(chris/leader-keys
|
||
:states '(normal visual)
|
||
:keymaps 'override
|
||
"la" 'gptel-send
|
||
"lm" 'gptel-menu))
|
||
|
||
(use-package aidermacs
|
||
:config
|
||
(setq aidermacs-default-model "ollama_chat/llama3.2:latest"
|
||
aidermacs-backend 'comint
|
||
aidermacs-watch-files t)
|
||
(add-hook 'aidermacs-before-run-backend-hook
|
||
((lambda ()
|
||
(setenv "OLLAMA_API_BASE" "https://ai.tfcconnection.org")))))
|
||
|
||
(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))
|
||
:general
|
||
(general-def jinx-mode-map
|
||
"C-S-f" 'jinx-correct))
|
||
|
||
(use-package emojify
|
||
:ensure t
|
||
:hook (after-init . global-emojify-mode)
|
||
:config
|
||
(setq emojify-display-style 'image)
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"ie" '(emojify-insert-emoji :which-key "insert emoji")))
|
||
|
||
(global-auto-revert-mode 1)
|
||
(setq global-auto-revert-non-file-buffers t)
|
||
|
||
(use-package visual-fill-column
|
||
:after org
|
||
:config
|
||
(setq visual-fill-column-width 100
|
||
visual-fill-column-center-text t))
|
||
|
||
(use-package toc-org
|
||
:after org)
|
||
|
||
(use-package pulsar
|
||
:config
|
||
(setq pulsar-pulse-functions
|
||
;; NOTE 2022-04-09: The commented out functions are from before
|
||
;; the introduction of `pulsar-pulse-on-window-change'. Try that
|
||
;; instead.
|
||
'(recenter-top-bottom
|
||
move-to-window-line-top-bottom
|
||
reposition-window
|
||
;; bookmark-jump
|
||
;; other-window
|
||
;; delete-window
|
||
;; delete-other-windows
|
||
forward-page
|
||
backward-page
|
||
scroll-up-command
|
||
scroll-down-command
|
||
;; windmove-right
|
||
;; windmove-left
|
||
;; windmove-up
|
||
;; windmove-down
|
||
;; windmove-swap-states-right
|
||
;; windmove-swap-states-left
|
||
;; windmove-swap-states-up
|
||
;; windmove-swap-states-down
|
||
;; tab-new
|
||
;; tab-close
|
||
;; tab-next
|
||
org-next-visible-heading
|
||
org-previous-visible-heading
|
||
org-forward-heading-same-level
|
||
org-backward-heading-same-level
|
||
outline-backward-same-level
|
||
outline-forward-same-level
|
||
outline-next-visible-heading
|
||
outline-previous-visible-heading
|
||
outline-up-heading))
|
||
|
||
(setq pulsar-pulse-on-window-change t)
|
||
(setq pulsar-pulse t)
|
||
(setq pulsar-delay 0.055)
|
||
(setq pulsar-iterations 10)
|
||
(setq pulsar-face 'ffap)
|
||
(setq pulsar-highlight-face 'pulsar-yellow)
|
||
|
||
(pulsar-global-mode 1)
|
||
;; integration with the `consult' package:
|
||
(add-hook 'consult-after-jump-hook #'pulsar-recenter-top)
|
||
(add-hook 'consult-after-jump-hook #'pulsar-reveal-entry)
|
||
|
||
;; integration with the built-in `imenu':
|
||
(add-hook 'imenu-after-jump-hook #'pulsar-recenter-top)
|
||
(add-hook 'imenu-after-jump-hook #'pulsar-reveal-entry))
|
||
|
||
(use-package posframe)
|
||
|
||
(use-package vertico-posframe
|
||
:after vertico
|
||
:config
|
||
(setq vertico-posframe-min-height 15)
|
||
(vertico-posframe-mode +1))
|
||
|
||
(setq home-directory "~/")
|
||
(defun chris/eww-empv ()
|
||
"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)))
|
||
(empv-play-or-enqueue (string-replace "inv.cochrun.xyz" "youtube.com" url))))))
|
||
|
||
(defun chris/search-yt ()
|
||
"Search youtube in my own invidious instance
|
||
and show the results in eww."
|
||
(interactive)
|
||
(let* ((search (completing-read "YT Search: " nil))
|
||
(url (url-encode-url (concat "https://inv.cochrun.xyz/search?q=" search))))
|
||
(eww url)))
|
||
|
||
;; (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-empv
|
||
"gV" 'chris/eww-video-dl)
|
||
(chris/leader-keys
|
||
:state 'normal
|
||
:keymap 'eww-mode-map
|
||
"fs" '(eww-browse :which-key "browse"))
|
||
(chris/leader-keys
|
||
:state 'normal
|
||
"sY" '(chris/search-yt :which-key "search youtube"))
|
||
|
||
(use-package vertico
|
||
:init
|
||
(vertico-mode)
|
||
|
||
;; Different scroll margin
|
||
;; (setq vertico-scroll-margin 0)
|
||
|
||
;; Show more candidates
|
||
(setq vertico-count 15)
|
||
|
||
;; 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)
|
||
)
|
||
|
||
;; A few more useful configurations...
|
||
(use-package emacs
|
||
:init
|
||
;; Add prompt indicator to `completing-read-multiple'.
|
||
;; Alternatively try `consult-completing-read-multiple'.
|
||
(defun crm-indicator (args)
|
||
(cons (concat "[CRM] " (car args)) (cdr args)))
|
||
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
|
||
|
||
;; Do not allow the cursor in the minibuffer prompt
|
||
(setq minibuffer-prompt-properties
|
||
'(read-only t cursor-intangible t face minibuffer-prompt))
|
||
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
|
||
|
||
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
|
||
;; Vertico commands are hidden in normal buffers.
|
||
;; (setq read-extended-command-predicate
|
||
;; #'command-completion-default-include-p)
|
||
|
||
;; Enable recursive minibuffers
|
||
(setq enable-recursive-minibuffers t))
|
||
|
||
(use-package consult
|
||
:after vertico
|
||
:config
|
||
(setq consult-narrow-key "<"
|
||
consult-project-root-function 'projectile-project-root)
|
||
|
||
(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)))
|
||
|
||
(setq consult-imenu-config
|
||
'((emacs-lisp-mode :toplevel "Functions" :types
|
||
((102 "Functions" font-lock-function-name-face)
|
||
(109 "Macros" font-lock-function-name-face)
|
||
(112 "Packages" font-lock-constant-face)
|
||
(116 "Types" font-lock-type-face)
|
||
(118 "Variables" font-lock-variable-name-face)))))
|
||
|
||
(setq xref-show-xrefs-function 'consult-xref)
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"si" 'consult-imenu
|
||
"so" 'consult-org-heading
|
||
"sf" 'consult-fd
|
||
"sm" 'bookmark-jump
|
||
"sF" 'consult-flymake
|
||
"sx" 'xref-show-xrefs
|
||
"sy" 'consult-yank-from-kill-ring
|
||
"sb" 'consult-eglot-symbols))
|
||
|
||
(use-package consult-omni
|
||
:load-path "/home/chris/.emacs.d/consult-omni/"
|
||
:load-path "/home/chris/.emacs.d/consult-omni/sources/"
|
||
:after consult
|
||
:config
|
||
(require 'consult-omni-sources)
|
||
(require 'consult-omni-embark)
|
||
(setq consult-omni-sources-modules-to-load '(consult-omni-brave-autosuggest consult-omni-wikipedia consult-omni-apps))
|
||
(consult-omni-sources-load-modules))
|
||
|
||
(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 nil) ;; Never quit, even if there is no match
|
||
(corfu-preview-current nil) ;; 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 10)
|
||
(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
|
||
(add-hook 'global-corfu-mode-hook #'evil-collection-corfu-setup)
|
||
(global-corfu-mode)
|
||
(corfu-echo-mode)
|
||
(advice-remove 'corfu--setup 'evil-normalize-keymaps)
|
||
(advice-remove 'corfu--teardown 'evil-normalize-keymaps)
|
||
|
||
(advice-add 'corfu--setup :after (lambda (&rest r) (evil-normalize-keymaps)))
|
||
(advice-add 'corfu--teardown :after (lambda (&rest r) (evil-normalize-keymaps)))
|
||
: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)
|
||
;; (defvar completion-at-point-functions '(cape-dabbrev cape-keyword cape-file tempel-complete
|
||
;; pcomplete-completions-at-point
|
||
;; ispell-completion-at-point))
|
||
|
||
;; (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)
|
||
;; (remove #'cape-ispell completion-at-point-functions)
|
||
;; (remove #'cape-symbol completion-at-point-functions)
|
||
|
||
: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)))
|
||
(setq tempel-path "/home/chris/.emacs.d/templates")
|
||
|
||
(add-hook 'conf-mode-hook 'tempel-setup-capf)
|
||
(add-hook 'prog-mode-hook 'tempel-setup-capf)
|
||
(add-hook 'text-mode-hook 'tempel-setup-capf)
|
||
(add-hook 'org-mode-hook 'tempel-setup-capf)
|
||
(add-hook 'ledger-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)
|
||
(general-def 'insert tempel-map
|
||
"C-l" 'tempel-next
|
||
"C-h" 'tempel-previous))
|
||
|
||
(use-package tempel-collection)
|
||
|
||
(use-package eglot-tempel
|
||
:init
|
||
(eglot-tempel-mode t))
|
||
|
||
(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))
|
||
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"p!" 'project-shell-command
|
||
"p&" 'project-async-shell-command
|
||
"pD" 'project-dired
|
||
"pF" 'project-or-external-find-file
|
||
"pG" 'project-or-external-find-regexp
|
||
"pb" 'project-switch-to-buffer
|
||
"pc" 'project-compile
|
||
"pd" 'project-find-dir
|
||
"pe" 'project-eshell
|
||
"pf" 'project-find-file
|
||
"pg" 'project-find-regexp
|
||
"pk" 'project-kill-buffers
|
||
"pp" 'project-switch-project
|
||
"pr" 'project-query-replace-regexp
|
||
"ps" 'project-shell
|
||
"pv" 'project-vc-dir
|
||
"px" 'project-execute-extended-command)
|
||
(general-def 'normal
|
||
"p" 'evil-paste-after)
|
||
|
||
(use-package lab
|
||
:config
|
||
(defun chris/gitlab-token ()
|
||
(interactive)
|
||
(string-clean-whitespace (shell-command-to-string "rbw get 'gitlab token'")))
|
||
|
||
(setq lab-host "https://gitlab.com"
|
||
lab-token (chris/gitlab-token)))
|
||
|
||
(use-package simple-httpd
|
||
:ensure t)
|
||
|
||
(use-package avy
|
||
:after evil
|
||
:config
|
||
(setq avy-keys '(99 105 101 97 104 116 115 110))
|
||
:general
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps '(override rustic-mode)
|
||
"gh" 'avy-goto-word-0))
|
||
|
||
(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\\*<20>"
|
||
(display-buffer-same-window))
|
||
("\\*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))
|
||
("*sly-mrepl for sbcl*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("*cargo-clippy*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("*cargo-test*"
|
||
(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))
|
||
("*Denote FILE backlinks.**"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.3))
|
||
("*org-roam*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("\\*Agenda Commands\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.30))
|
||
("\\*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))
|
||
("*Ledger Report*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.40))
|
||
("\\*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\\*"
|
||
(display-buffer-same-window))
|
||
("\\*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))
|
||
("*sly-mrepl for sbcl*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("*rustic-compilation*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.40))
|
||
("*cargo-clippy*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.40))
|
||
("*cargo-test*"
|
||
(display-buffer-in-side-window)
|
||
(side . right)
|
||
(window-width . 0.4))
|
||
("\\*Agenda Commands\\*"
|
||
(display-buffer-in-side-window)
|
||
(side . bottom)
|
||
(window-height . 0.30))
|
||
("*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.4))
|
||
("\\*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-current-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)
|
||
(setq compilation-environment '("TERM=xterm-256color")
|
||
compilation-scroll-output t)
|
||
|
||
(defun my/advice-compilation-filter (f proc string)
|
||
(funcall f proc (xterm-color-filter string)))
|
||
|
||
(advice-add 'compilation-filter :around #'my/advice-compilation-filter)
|
||
|
||
(add-hook 'comint-mode-hook 'hl-line-mode)
|
||
(add-hook 'prog-mode-hook 'hl-line-mode)
|
||
(add-hook 'prog-mode-hook 'hs-minor-mode)
|
||
|
||
(setq gdb-many-windows t
|
||
gdb-show-main t)
|
||
|
||
(use-package smartparens
|
||
:config
|
||
(smartparens-global-mode +1)
|
||
:general
|
||
('normal emacs-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-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 scheme-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))
|
||
|
||
(use-package paredit
|
||
:hook ((lisp-mode . enable-paredit-mode)
|
||
(emacs-lisp-mode . enable-paredit-mode)
|
||
(scheme-mode . enable-paredit-mode))
|
||
:general
|
||
('normal lisp-mode-map
|
||
"gl" 'paredit-forward-slurp-sexp
|
||
"gh" 'paredit-backward-slurp-sexp
|
||
"C-M-l" 'paredit-forward-barf-sexp
|
||
"C-M-h" 'paredit-backward-barf-sexp
|
||
"C-l" 'paredit-forward
|
||
"C-h" 'paredit-backward)
|
||
('normal emacs-lisp-mode-map
|
||
"gl" 'paredit-forward-slurp-sexp
|
||
"gh" 'paredit-backward-slurp-sexp
|
||
"C-M-l" 'paredit-forward-barf-sexp
|
||
"C-M-h" 'paredit-backward-barf-sexp
|
||
"C-l" 'paredit-forward
|
||
"C-h" 'paredit-backward)
|
||
('normal lisp-shared-mode-map
|
||
"gl" 'paredit-forward-slurp-sexp
|
||
"gh" 'paredit-backward-slurp-sexp
|
||
"C-M-l" 'paredit-forward-barf-sexp
|
||
"C-M-h" 'paredit-backward-barf-sexp
|
||
"C-l" 'paredit-forward
|
||
"C-h" 'paredit-backward)
|
||
('normal sly-mrepl-mode-map
|
||
"gl" 'paredit-forward-slurp-sexp
|
||
"gh" 'paredit-backward-slurp-sexp
|
||
"C-M-l" 'paredit-forward-barf-sexp
|
||
"C-M-h" 'paredit-backward-barf-sexp
|
||
"C-l" 'paredit-forward
|
||
"C-h" 'paredit-backward)
|
||
('normal scheme-mode-map
|
||
"gl" 'paredit-forward-slurp-sexp
|
||
"gh" 'paredit-backward-slurp-sexp
|
||
"C-M-l" 'paredit-forward-barf-sexp
|
||
"C-M-h" 'paredit-backward-barf-sexp
|
||
"C-l" 'paredit-forward
|
||
"C-h" 'paredit-backward)
|
||
('normal geiser-mode-map
|
||
"gl" 'paredit-forward-slurp-sexp
|
||
"gh" 'paredit-backward-slurp-sexp
|
||
"C-M-l" 'paredit-forward-barf-sexp
|
||
"C-M-h" 'paredit-backward-barf-sexp
|
||
"C-l" 'paredit-forward
|
||
"C-h" 'paredit-backward)
|
||
('normal cider-repl-mode-map
|
||
"gl" 'paredit-forward-slurp-sexp
|
||
"gh" 'paredit-backward-slurp-sexp
|
||
"C-M-l" 'paredit-forward-barf-sexp
|
||
"C-M-h" 'paredit-backward-barf-sexp
|
||
"C-l" 'paredit-forward
|
||
"C-h" 'paredit-backward))
|
||
;; (remove-hook 'prog-mode-hook 'enable-paredit-mode)
|
||
|
||
(load (if (string= system-name "kaladin")
|
||
"/home/chris/quicklisp/clhs-use-local.el"
|
||
"/home/chris/.local/share/quicklisp/clhs-use-local.el") t)
|
||
|
||
(add-to-list 'auto-mode-alist '("\\.yuck?\\'" . lisp-data-mode))
|
||
|
||
(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))
|
||
(setq sly-connection-poll-interval 0.1)
|
||
|
||
(defun sly-critique-file ()
|
||
"Lint this file with lisp-critic"
|
||
(interactive)
|
||
(sly-eval-async '(ql:quickload :lisp-critic))
|
||
(sly-eval-async
|
||
`(lisp-critic:critique-file ,(buffer-file-name))))
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"os" 'sly
|
||
"gc" 'compile)
|
||
|
||
(general-def 'normal lisp-mode-shared-map
|
||
"gcr" 'sly
|
||
"ge" 'sly-eval-defun
|
||
"gE" 'sly-eval-last-expression
|
||
"gp" 'sly-pprint-eval-last-expression))
|
||
|
||
;; (general-def 'normal scheme-mode-map
|
||
;; "gl" 'paredit-)
|
||
|
||
(use-package geiser
|
||
:ensure t
|
||
:config
|
||
:general
|
||
(general-def 'normal geiser-mode-map
|
||
"gcr" 'geiser
|
||
"ge" 'geiser-eval-definition-and-go
|
||
"gE" 'geiser-eval-last-sexp
|
||
"gp" 'geiser-eval-last-sexp-and-print
|
||
"gl" 'paredit-forward-slurp-sexp))
|
||
|
||
(general-def 'normal emacs-lisp-mode-map
|
||
"ge" 'eval-defun
|
||
"gE" 'eval-last-sexp
|
||
"gp" 'pp-eval-last-sexp)
|
||
|
||
|
||
|
||
(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
|
||
rustic-clippy-arguments "-- -W clippy::pedantic -W clippy::perf -W clippy::nursery -W clippy::unwrap_used"
|
||
rustic-rustfmt-args "--edition 2021"
|
||
rust-format-on-save t
|
||
rustic-cargo-clippy-trigger-fix t
|
||
rustic-cargo-clippy-fix-args "--allow-dirty"
|
||
rustic-test-arguments "--benches --tests --all-features -- --nocapture")
|
||
(advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
|
||
(add-to-list 'compilation-error-regexp-alist rustic-compilation-error)
|
||
(add-to-list 'compilation-error-regexp-alist rustic-compilation-warning)
|
||
:general
|
||
(general-def 'normal rustic-mode-map
|
||
"!" 'rustic-run-shell-command
|
||
"gC" 'rustic-cargo-clippy
|
||
"gA" 'rustic-cargo-add
|
||
"gt" 'rustic-cargo-test-dwim
|
||
"gT" 'rustic-cargo-current-test)
|
||
(chris/leader-keys 'normal rustic-mode-map
|
||
"gc" 'rustic-compile
|
||
"gr" 'projectile-run-project
|
||
"si" 'consult-imenu-multi
|
||
"ga" 'rustic-cargo-add
|
||
"gC" 'rustic-cargo-clippy
|
||
"gt" 'rustic-cargo-test))
|
||
|
||
(use-package slint-mode
|
||
:mode "\\.slint\\'"
|
||
:general
|
||
(general-def 'normal slint-mode-map
|
||
"!" 'rustic-run-shell-command
|
||
"gC" 'rustic-cargo-clippy
|
||
"gA" 'rustic-cargo-add
|
||
"gt" 'rustic-cargo-test
|
||
"gT" 'rustic-cargo-current-test)
|
||
(chris/leader-keys 'normal slint-mode-map
|
||
"gc" 'rustic-compile
|
||
"gr" 'projectile-run-project
|
||
"si" 'consult-imenu-multi
|
||
"ga" 'rustic-cargo-add
|
||
"gC" 'rustic-cargo-clippy
|
||
"gt" 'rustic-cargo-test))
|
||
|
||
(use-package ron-mode
|
||
:mode "\\.ron\\'")
|
||
|
||
;; (load-file "./wgsl-ts-mode.el")
|
||
|
||
(defun chris/web-mode-setup ()
|
||
"some setup for web development"
|
||
(setq-local completion-at-point-functions
|
||
(list #'cape-dabbrev #'cape-keyword #'tempel-complete)))
|
||
(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)
|
||
(add-to-list 'web-mode-hook #'chris/web-mode-setup)
|
||
|
||
: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\\'"
|
||
:general
|
||
(chris/leader-keys 'normal 'override
|
||
"xf" 'nix-flake))
|
||
|
||
(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)
|
||
:config
|
||
|
||
(setq eglot-autoshutdown t)
|
||
|
||
(defun chris/eglot-capf ()
|
||
(setq-local completion-at-point-functions
|
||
(list (cape-capf-super
|
||
#'eglot-completion-at-point
|
||
#'tempel-expand
|
||
#'cape-file))))
|
||
|
||
(add-hook 'eglot-managed-mode-hook #'chris/eglot-capf)
|
||
|
||
:general
|
||
(general-def 'normal eglot-mode-map
|
||
"ga" 'eglot-code-actions
|
||
"gi" 'eglot-find-implementation
|
||
"gr" 'eglot-rename
|
||
"gR" 'xref-find-references))
|
||
|
||
(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-ts-mode
|
||
:ensure t
|
||
:config
|
||
(require 'flycheck-clj-kondo))
|
||
|
||
(use-package cider
|
||
:after clojure-ts-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 just-mode
|
||
:mode ("\\.just\\'" . just-mode))
|
||
|
||
(use-package justl
|
||
:config
|
||
(defun chris/justl-exec-recipe ()
|
||
"Execute a recipe in the justfile from the minibuffer"
|
||
(interactive)
|
||
(let* ((justfile (justl--find-justfile (project-root (eglot--current-project))))
|
||
(recipes (cl-loop for recipe in (justl--get-recipes justfile)
|
||
collect (cdr (assoc 'name recipe))))
|
||
(recipe (completing-read "Which recipe to run: " recipes)))
|
||
(if (get-buffer "*just*")
|
||
(justl--exec "just1" recipe `(,recipe))
|
||
(justl--exec justl-executable recipe `(,recipe)))
|
||
(message "%s" recipe)))
|
||
:general
|
||
(general-def 'normal justl-mode-map
|
||
"e" 'justl-exec-recipe
|
||
"E" 'justl-exec-eshell
|
||
"<return>" 'justl-exec-recipe)
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'rustic-mode-map
|
||
"gj" 'chris/justl-exec-recipe))
|
||
|
||
(use-package fish-mode
|
||
:mode ("\\.fish\\'" . fish-mode))
|
||
|
||
(use-package markdown-mode
|
||
:mode (("\\.md\\'" . markdown-mode)
|
||
("\\.rmd\\'". markdown-mode))
|
||
:config
|
||
|
||
(setq markdown-regex-yaml-metadata-border "\\(-\\{3\\}\\|+\\{3\\}\\)$")
|
||
|
||
(dolist (face
|
||
'((markdown-header-face-1 1.4 ultra-bold)
|
||
(markdown-header-face-2 1.2 extra-bold)
|
||
(markdown-header-face-3 1.1 bold)
|
||
(markdown-header-face-4 1.0 semi-bold)
|
||
(markdown-header-face-5 1.0 normal)))
|
||
(set-face-attribute (nth 0 face) nil :weight (nth 2 face) :height (nth 1 face)))
|
||
|
||
(setq markdown-fontify-code-blocks-natively t)
|
||
(add-hook 'markdown-mode-hook 'chris/org-mode-setup)
|
||
(custom-set-faces '(markdown-code-face ((t (:inherit org-block)))))
|
||
: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
|
||
"C-<return>" 'markdown-insert-list-item)
|
||
(general-def 'insert markdown-mode-map
|
||
"C-<return>" 'markdown-insert-list-item))
|
||
|
||
(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 verb
|
||
: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 (concat "Opening ==> " 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 "/home/chris/vids/")
|
||
(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)
|
||
|
||
(defun chris/convert-doc-to-org ()
|
||
"Convert a word doc to an org file"
|
||
(interactive)
|
||
(let* ((file (dired-get-filename))
|
||
(out (string-replace "docx" "org" file)))
|
||
(async-shell-command (format "pandoc --wrap=preserve -o '%s' '%s'" out file))))
|
||
|
||
(custom-set-faces '(dired-directory ((t :foreground "#57c7ff" :inherit dired-header))))
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"od" '(dired-jump :which-key "open dired here")
|
||
"oD" '(dired :which-key "open dired select"))
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"sF" '(fd-dired :which-key "search in directory with fd"))
|
||
('normal dired-mode-map
|
||
"q" 'kill-current-buffer
|
||
"C-<return>" 'chris/dired-open-xdg
|
||
"M-<return>" 'ffap-other-window
|
||
"h" 'dired-up-directory
|
||
"l" 'dired-find-file
|
||
"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)))
|
||
|
||
(defun chris/dired-yank-fullpath ()
|
||
"get the fill file path at point and put into kill-ring"
|
||
(interactive)
|
||
(let* ((file (dired-get-filename)))
|
||
(message file)))
|
||
|
||
(use-package dired-sidebar
|
||
:ensure t
|
||
:commands (dired-sidebar-toggle-sidebar)
|
||
:general
|
||
(general-def 'normal
|
||
"gD" 'dired-sidebar-toggle-sidebar)
|
||
(general-def 'normal dired-sidebar-mode-map
|
||
"l" 'dired-sidebar-find-file
|
||
"h" 'dired-sidebar-up-directory))
|
||
|
||
(use-package all-the-icons-dired
|
||
:hook (dired-mode . all-the-icons-dired-mode))
|
||
|
||
(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))
|
||
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
|
||
|
||
(connection-local-set-profile-variables
|
||
'guix-system
|
||
'((tramp-remote-path . (tramp-own-remote-path))))
|
||
(connection-local-set-profiles
|
||
'(:application tramp :protocol "sudo" :machine "hostname")
|
||
'guix-system)
|
||
|
||
(setq tramp-default-proxies-alist '())
|
||
|
||
(use-package ledger-mode
|
||
:config
|
||
(setq-mode-local ledger-mode
|
||
completion-at-point-functions (list
|
||
(cape-capf-super
|
||
#'cape-file
|
||
#'cape-abbrev))
|
||
tab-always-indent 'complete
|
||
completion-cycle-threshold t
|
||
ledger-complete-in-steps t)
|
||
|
||
(defun chris/ledger-clean ()
|
||
(interactive)
|
||
(when (eq major-mode #'ledger-mode)
|
||
(ledger-mode-clean-buffer)))
|
||
(add-hook 'after-save-hook #'chris/ledger-clean)
|
||
|
||
(setq ledger-default-date-format "%Y-%m-%d")
|
||
|
||
:general
|
||
(general-def 'normal ledger-mode-map
|
||
"ga" 'ledger-add-transaction
|
||
"gr" 'ledger-report
|
||
"gp" 'ledger-toggle-current
|
||
"C-j" 'ledger-navigate-next-xact-or-directive
|
||
"C-k" 'ledger-navigate-prev-xact-or-directive
|
||
"S-k" 'ledger-date-up
|
||
"S-j" 'ledger-date-down))
|
||
|
||
(use-package mu4e
|
||
;; :load-path "~/.guix-home/profile/share/emacs/site-lisp/mu4e/"
|
||
:init
|
||
|
||
(setq mu4e-maildir "~/mail"
|
||
user-full-name "Chris Cochrun"
|
||
mu4e-change-filenames-when-moving t
|
||
mu4e-get-mail-command "mailsync"
|
||
mu4e-update-interval (* 15 60)
|
||
mu4e-attachment-dir "/home/chris/docs/attachments"
|
||
mu4e-completing-read-function #'completing-read
|
||
mu4e-notification-support t
|
||
;; mu4e-mu-binary "/home/chris/.guix-home/profile/bin/mu"
|
||
;; 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)
|
||
|
||
(defun mu4e--main-action-str (name func)
|
||
"This seems to be needed until evil-collection supports the latest
|
||
version of mu4e."
|
||
"mu4e--main-action")
|
||
(remove-hook 'mu4e-main-mode-hook 'evil-collection-mu4e-update-main-view)
|
||
|
||
(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 . "")))
|
||
(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 . "")))))
|
||
|
||
;; 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 "/cochrun/Archive" :key ?a)
|
||
(:maildir "/cochrun/Inbox" :key ?i)
|
||
(:maildir "/office/Inbox" :key ?w)
|
||
(:maildir "/office/Junk Email" :key ?j)
|
||
(:maildir "/office/INBOX/Website Forms" :key ?f)
|
||
(:maildir "/office/Inbox/Money" :key ?m)
|
||
(: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\"0 AND NOT maildir:\"/outlook/Deleted\" AND NOT maildir:\"/office/Deleted Items\" AND NOT maildir:\"/office/Archive\" AND NOT maildir:\"/office/INBOX/Website Forms\" 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)
|
||
(:name "Lists"
|
||
:query "flag:list AND NOT flag:trashed"
|
||
:key 108)))
|
||
|
||
(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 ()
|
||
(display-line-numbers-mode -1)
|
||
(toggle-truncate-lines +1))
|
||
|
||
|
||
(defun chris/setup-mu4e-view ()
|
||
(display-line-numbers-mode -1)
|
||
(setq visual-fill-column-center-text t)
|
||
(setq visual-fill-column-width 120)
|
||
(visual-fill-column-mode +1)
|
||
(visual-line-mode -1)
|
||
(toggle-truncate-lines +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-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)
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'mu4e-headers-mode
|
||
"c" 'mu4e-org-store-and-capture)
|
||
(general-def 'normal mu4e-headers-mode-map
|
||
"f" 'mu4e-headers-mark-for-flag)
|
||
(general-def 'normal mu4e-view-mode-map
|
||
"ga" 'mu4e-view-save-attachments
|
||
"q" 'mu4e-view-quit))
|
||
|
||
(use-package org-msg
|
||
:hook (mu4e-compose-mode . org-msg-edit-mode)
|
||
:config
|
||
(org-msg-mode)
|
||
|
||
(defun org-msg-edit-mode-mu4e ()
|
||
"Setup mu4e faces, addresses completion and run mu4e."
|
||
(mu4e--compose-remap-faces)
|
||
(unless (mu4e-running-p)
|
||
(if (fboundp #'mu4e~start) (mu4e~start) (mu4e--start)))
|
||
(when mu4e-compose-complete-addresses
|
||
(mu4e--compose-setup-completion)))
|
||
|
||
(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 "\nHey%s\n\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-current-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 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))
|
||
|
||
(add-to-list 'load-path (file-truename (concat user-emacs-directory "fj/")))
|
||
(use-package fj
|
||
:custom
|
||
(fj-host "https://git.tfcconnection.org")
|
||
(fj-user "chris")
|
||
(fj-token "b170996c9d2989d749fdb3702385e84f7d2ae8fc")
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"ri" 'fj-list-issues
|
||
"rp" 'fj-list-own-repos)
|
||
(general-def 'normal fj-issue-tl-mode-map
|
||
"c" 'fj-issue-compose))
|
||
|
||
(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 "kaladin") (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 0.7))
|
||
(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 "")
|
||
|
||
(add-to-list 'eshell-path-env-list "/home/chris/.cargo/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)))
|
||
|
||
(defun chris/upgrade-nix ()
|
||
"A function for updating my nix config"
|
||
(interactive)
|
||
(let* ((default-directory (file-truename (concat home-directory ".dotfiles/"))))
|
||
(async-shell-command
|
||
"sudo nixos-rebuild switch --show-trace --verbose --impure --flake .#"
|
||
"*upgrade*"
|
||
"*upgrade-errors*")))
|
||
|
||
(defun chris/eshell-current-window ()
|
||
"Open eshell in the current directory using the current window"
|
||
(interactive)
|
||
(same-window-prefix)
|
||
(eshell))
|
||
|
||
(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")
|
||
("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")
|
||
("dup" "sudo docker compose up -d")
|
||
("ddown" "sudo docker compose down")
|
||
("dpull" "sudo docker compose pull")
|
||
("dlogs" "sudo docker compose logs --follow")
|
||
("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")
|
||
("gh" "guix home -L ~/.dotfiles/guix reconfigure /home/chris/.dotfiles/guix/home.scm")
|
||
("gs" ,(concat "sudo guix system -L ~/.dotfiles/guix reconfigure /home/chris/.dotfiles/guix/" (system-name) ".scm"))))
|
||
|
||
(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)))
|
||
|
||
(defun chris/btop ()
|
||
"Run btop in eshell"
|
||
(interactive)
|
||
(eshell 101)
|
||
(with-current-buffer "*eshell*<101>"
|
||
(eshell-return-to-prompt)
|
||
(insert "btop")
|
||
(eshell-send-input)))
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"oe" 'chris/eshell-new
|
||
"oE" 'chris/eshell-current-window
|
||
"be" 'eshell)
|
||
(general-def '(normal insert) eshell-mode-map
|
||
"C-d" 'kill-buffer-and-window
|
||
"C-l" 'eshell/clear
|
||
"<up>" 'eshell-previous-input))
|
||
|
||
(use-package eat
|
||
:init
|
||
(add-hook 'eshell-load-hook #'eat-eshell-mode))
|
||
|
||
(use-package eshell-syntax-highlighting
|
||
:config
|
||
(eshell-syntax-highlighting-global-mode +1)
|
||
:init
|
||
(defface eshell-syntax-highlighting-invalid-face
|
||
'((t :inherit diff-error))
|
||
"Face used for invalid Eshell commands."
|
||
:group 'eshell-syntax-highlighting))
|
||
|
||
(setq vterm-buffer-name-string "vterm %s"
|
||
vterm-shell "/run/current-system/sw/bin/nu")
|
||
(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 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
|
||
|
||
(defun chris/list-printers ()
|
||
"Lists the printers that are available for the computer"
|
||
(interactive)
|
||
(split-string (shell-command-to-string "lpstat -p | awk '{print $2}'")))
|
||
|
||
(defun chris/print-multi-pdf ()
|
||
"Print the pdf in as many copies as needed"
|
||
(interactive)
|
||
(let* ((copies (completing-read "How many copies: " '("1" "2" "3")))
|
||
(sides (completing-read "Print both sides or one? " '("two sided" "one sided")))
|
||
(printer (completing-read "Which printer do you want to use?" (chris/list-printers)))
|
||
(pdf-misc-print-program-args `("-o media=Letter" ,(format "-# %s" copies) ,(format "-P %s" printer) "-o fit-to-page"
|
||
,(if (string= sides "two sided")
|
||
"-o sides=two-sided-long-edge"
|
||
""))))
|
||
(message "printing %s copies." copies)
|
||
(async-shell-command (format "lpr %s '%s'" (string-join pdf-misc-print-program-args " ") (buffer-file-name)))))
|
||
|
||
(custom-set-variables '(pdf-misc-print-program-executable "lpr")
|
||
'(pdf-misc-print-program-args (quote ("-o media=Letter" "-o fit-to-page" "-o sides=two-sided-long-edge"))))
|
||
(add-hook 'pdf-view-mode-hook 'pdf-view-fit-page-to-window)
|
||
(defun chris/display-line-numbers-off ()
|
||
(display-line-numbers-mode -1))
|
||
(add-hook 'pdf-view-mode-hook 'chris/display-line-numbers-off)
|
||
:general
|
||
(general-def
|
||
:states 'normal
|
||
:keymaps 'pdf-view-mode-map
|
||
"C-p" 'chris/print-multi-pdf))
|
||
|
||
(use-package nov
|
||
:mode ("\\.epub\\'" . nov-mode)
|
||
:config
|
||
(setq nov-text-width 80)
|
||
|
||
(defun chris/setup-nov-mode ()
|
||
(interactive)
|
||
(setq visual-fill-column-width 90
|
||
visual-fill-column-center-text t)
|
||
(visual-fill-column-mode +1)
|
||
(display-line-numbers-mode -1)
|
||
(variable-pitch-mode +1))
|
||
|
||
(add-hook 'nov-mode-hook 'chris/setup-nov-mode))
|
||
|
||
(use-package empv
|
||
:config
|
||
(setq empv-invidious-instance "https://inv.cochrun.xyz/api/v1"
|
||
empv-video-file-extensions '("mkv" "mp4" "avi" "mov" "webm")
|
||
empv-mpv-args '("--no-terminal" "--idle" "--input-ipc-server=/tmp/empv-socket")
|
||
empv-audio-dir "~/music"
|
||
empv-video-dir "~/vids")
|
||
(empv-embark-initialize-extra-actions)
|
||
(general-auto-unbind-keys)
|
||
(add-hook 'empv-youtube-results-mode-hook #'evil-normal-state)
|
||
|
||
(defun mpv-start (args video)
|
||
"Load a video from mast into empv"
|
||
(message video)
|
||
(message args)
|
||
(empv-play-or-enqueue video))
|
||
|
||
(defun chris/empv-yt-dlp (&optional file)
|
||
"Download the current video and and play it"
|
||
(interactive)
|
||
(setq lexical-binding t)
|
||
(let* ((item (when (not file) (empv-youtube-results--current-item)))
|
||
(video-id (when (not file) (alist-get 'videoId item)))
|
||
(playlist-id (when (not file) (alist-get 'playlistId item)))
|
||
(url (if file
|
||
(progn
|
||
(message file)
|
||
(string-replace "inv.cochrun.xyz" "youtube.com" file))
|
||
(format
|
||
"https://youtube.com/%s=%s"
|
||
(if video-id "watch?v" "playlist?list")
|
||
(or video-id playlist-id))))
|
||
(title (if file (shell-command-to-string
|
||
(format "yt-dlp --no-warnings --quiet --get-title %s" url))
|
||
(alist-get 'title item)))
|
||
(output-buffer (generate-new-buffer "*yt-dlp*"))
|
||
(process (progn
|
||
(message "Starting to download %s at %s" title url)
|
||
(make-process
|
||
:name "yt-dlp"
|
||
:buffer output-buffer
|
||
:command `("yt-dlp" "-o"
|
||
"~/vids/%(title)s.%(ext)s"
|
||
"-f best[ext=mp4]"
|
||
,(cl-coerce url 'string)
|
||
"--embed-thumbnail"
|
||
"--sponsorblock-remove=sponsor,intro,outro"))
|
||
(get-buffer-process output-buffer)))
|
||
(enqueue `(lambda (process event)
|
||
(when (eq (process-status process) 'exit)
|
||
(progn (message "running %s because %s" process event)
|
||
(empv-enqueue (concat "/home/chris/vids/" (string-trim ,title) ".mp4"))
|
||
;; (kill-buffer ,output-buffer)
|
||
)))))
|
||
(message url)
|
||
(if (process-live-p process)
|
||
(set-process-sentinel
|
||
process enqueue)
|
||
(message "No process running"))))
|
||
|
||
;; (chris/empv-yt-dlp "https://inv.cochrun.xyz/watch?v=mNYcUMZfSP0")
|
||
|
||
(defun chris/empv-yt-dlp-jellyfin ()
|
||
"Grabs the current video at point and downloads it to my jellyfin server"
|
||
(interactive)
|
||
(let* ((server "jelly.cochrun.xyz")
|
||
(item (empv-youtube-results--current-item))
|
||
(video-id (alist-get 'videoId item))
|
||
(playlist-id (alist-get 'playlistId item))
|
||
(title (alist-get 'title item))
|
||
(location (completing-read "location: " '("dev" "house" "ministry" "misc")))
|
||
(url (format
|
||
"https://youtube.com/%s=%s"
|
||
(if video-id "watch?v" "playlist?list")
|
||
(or video-id playlist-id))))
|
||
(async-shell-command (concat
|
||
"ssh " server " \"" "yt-dlp"
|
||
" -o '/storage/media/media/chris/extras/yt/"
|
||
location
|
||
"/%(title)s.%(ext)s'"
|
||
" '" url "'" "\""))
|
||
(message (format "%s is downloading to the %s folder on jellyfin" url location))))
|
||
|
||
(defun chris/empv-org-play-link (&optional link)
|
||
"Play link in empv from either supplied link or link at point in org-mode"
|
||
(interactive)
|
||
(let ((link (if link
|
||
link
|
||
(org-babel-read-link))))
|
||
(empv-play link)))
|
||
|
||
(defun chris/dired-empv-play-or-enqueue ()
|
||
"Play file at point in dired"
|
||
(interactive)
|
||
(let* ((file (dired-get-filename)))
|
||
(empv-play-or-enqueue file)))
|
||
|
||
(defun chris/empv-seek-forward ()
|
||
"Seek forward 20 seconds"
|
||
(interactive)
|
||
(empv-seek "20"))
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"vo" 'empv-play-or-enqueue
|
||
"vt" 'empv-toggle
|
||
"vv" 'empv-play-video
|
||
"vx" 'empv-chapter-select
|
||
"vy" 'empv-youtube-tabulated
|
||
"vn" 'empv-playlist-next
|
||
"vp" 'empv-playlist-prev
|
||
"vs" 'empv-playlist-select
|
||
"vS" 'chris/empv-seek-forward)
|
||
(general-def
|
||
:states 'normal
|
||
:keymaps 'empv-youtube-results-mode-map
|
||
"q" 'kill-current-buffer
|
||
"RET" 'empv-youtube-results-play-or-enqueue-current
|
||
"i" 'empv-youtube-results-inspect
|
||
"d" 'chris/empv-yt-dlp
|
||
"D" 'chris/empv-yt-dlp-jellyfin)
|
||
(general-def
|
||
:states 'normal
|
||
:keymaps 'dired-mode-map
|
||
"vi" 'chris/dired-empv-play-or-enqueue))
|
||
|
||
(use-package elfeed
|
||
:commands (elfeed)
|
||
:config
|
||
(defvar chris/elfeed-bongo-playlist "*Bongo-Elfeed Queue*"
|
||
"Name of the Elfeed+Bongo multimedia playlist.")
|
||
|
||
(defun chris/elfeed-empv-play ()
|
||
"Play elfeed video or podcast link in empv"
|
||
(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)))
|
||
(final-url (if (string-prefix-p "https://inv.cochrun.xyz/" url)
|
||
(string-replace "https://inv.cochrun.xyz/" "https://youtube.com/" url)
|
||
url))
|
||
(title (elfeed-entry-title entry)))
|
||
(empv-play-or-enqueue final-url)
|
||
(message "Playing: %s from %s" title final-url)
|
||
(elfeed-search-untag-all-unread)))
|
||
|
||
(defun chris/empv-ytdlp-play-or-enqueue (process signal video)
|
||
"play or enqueue a video after ytdlp is done"
|
||
(when (memq (process-status process) '(exit signal)
|
||
(empv-play-or-enqueue video)
|
||
(shell-command-sentinel process signal))))
|
||
|
||
(defun chris/elfeed-ytdlp-empv ()
|
||
"Download the video at point and add to empv"
|
||
(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))
|
||
(output-buffer (generate-new-buffer "*yt-dlp*"))
|
||
(proc (progn
|
||
(message url)
|
||
(make-process
|
||
:name "yt-dlp"
|
||
:buffer output-buffer
|
||
:command `("yt-dlp"
|
||
"-o" "/home/chris/vids/%(title)s.%(ext)s"
|
||
,(cl-coerce url 'string)))
|
||
(get-buffer-process output-buffer))))
|
||
|
||
(elfeed-search-untag-all-unread)
|
||
(if (process-live-p proc)
|
||
(set-process-sentinel
|
||
proc `(empv-enqueue
|
||
,(concat "/home/chris/vids/" title ".webm")))
|
||
(message "No process running"))))
|
||
|
||
(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)
|
||
(elfeed-search-fetch))
|
||
|
||
(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)
|
||
(hide-mode-line-mode +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/efleed-org-view ()
|
||
"Display the url of the entry as an org-mode buffer"
|
||
(interactive)
|
||
(let ((link (elfeed-entry-link elfeed-show-entry)))
|
||
(message link)
|
||
(org-web-tools-read-url-as-org link)))
|
||
|
||
(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-empv-play
|
||
"b" 'chris/elfeed-eww-browse
|
||
"o" 'chris/elfeed-org-view
|
||
"d" 'chris/elfeed-ytdlp-empv)
|
||
(general-def 'normal elfeed-show-mode-map
|
||
"o" 'chris/elfeed-org-view
|
||
"b" 'eww))
|
||
|
||
(use-package elfeed-org
|
||
:after elfeed
|
||
:config
|
||
(setq rmh-elfeed-org-files (list "~/docs/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-mpv-remote-option "--input-ipc-server=/tmp/bongo-mpv.socket"
|
||
bongo-field-separator (propertize " · " 'face 'shadow))
|
||
|
||
(define-bongo-backend mpv
|
||
:constructor 'bongo-start-mpv-player
|
||
:program-name 'mpv
|
||
:program-arguments '("--profile=fast")
|
||
:extra-program-arguments nil
|
||
: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-mpv)
|
||
emms-player-mpv-parameters '("--quiet" "--really-quiet" "--no-audio-display" "--speed=1"))
|
||
(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)))
|
||
|
||
(defun chris/emms-mpv-video-playlist ()
|
||
"Create a playlist for mpv videos."
|
||
(interactive)
|
||
(emms-playlist-new "*emms-videos*"))
|
||
|
||
(defun chris/emms-add-video (&optional video)
|
||
"adds the given video to the emms playlist"
|
||
(interactive)
|
||
(if video
|
||
(emms-add-url video)
|
||
(emms-add-url)))
|
||
|
||
: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
|
||
"ms" 'emms-shuffle
|
||
"m]" 'emms-seek-forward
|
||
"m[" 'emms-seek-backward)
|
||
(general-def 'normal emms-playlist-mode-map
|
||
"q" 'bury-buffer
|
||
"d" 'emms-playlist-mode-kill-track
|
||
"m" 'emms-mark-track
|
||
"D" 'emms-playlist-mode-goto-dired-at-point
|
||
"]" 'emms-seek-forward
|
||
"[" 'emms-seek-backward
|
||
"C-k" 'emms-mark-kill-marked-tracks
|
||
"p" 'emms-pause
|
||
"e" 'emms-tag-editor-edit)
|
||
(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) "kaladin")
|
||
(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
|
||
"el" 'ement-list-rooms
|
||
"ec" 'ement-connect
|
||
"ev" 'ement-view-room
|
||
"es" 'ement-directory-search
|
||
"em" 'ement-send-direct-message
|
||
"en" 'ement-notifications))
|
||
|
||
(ement-connect :uri-prefix "http://127.0.0.1:8008" :user-id "@chriscochrun:tfcconnection.org" :password "UtK4ik#sRx^GVqr@J3YVZ@#m")
|
||
|
||
(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))
|
||
|
||
(load (concat user-emacs-directory "bible.el"))
|
||
(add-to-list 'warning-suppress-types '(org-element))
|
||
(add-to-list 'warning-suppress-log-types '(org-element))
|
||
|
||
(add-to-list 'load-path "/home/chris/dev/emacs-rpgdm/")
|
||
(use-package rpgdm
|
||
:config
|
||
(setq chris/dnd-character "althorien")
|
||
|
||
(defun chris/dnd-get-table (table range)
|
||
"Get a list of the contents of any `table' and use `range' to get the info"
|
||
(with-current-buffer
|
||
(find-file-noselect "~/docs/notes/20240804T132141--dungeons-and-dragons__area_fun_personal.org")
|
||
(org-table-get-remote-range table range)))
|
||
|
||
(defun chris/dnd-skill-check (&optional skill)
|
||
"Roll for a skill check using skill or prompting for one."
|
||
(interactive)
|
||
(let* ((skills (with-current-buffer
|
||
(find-file-noselect "~/docs/notes/20240804T132141--dungeons-and-dragons__area_fun_personal.org")
|
||
(org-table-get-remote-range
|
||
(concat "skills" "-" chris/dnd-character) "@I$1..@II$2")))
|
||
(skill (completing-read "Which skill: "
|
||
(seq-filter
|
||
'stringp
|
||
(cl-loop for e in skills
|
||
collect
|
||
(if (= 0 (string-to-number
|
||
(substring-no-properties e)))
|
||
(substring-no-properties e))))))
|
||
(value (substring-no-properties
|
||
(nth (+ 1 (cl-position
|
||
skill skills
|
||
:test 'string=))
|
||
skills))))
|
||
(rpgdm-roll (concat "1d20" value))))
|
||
|
||
(defun chris/dnd-spell-attack-check ()
|
||
"roll for a spell attack"
|
||
(interactive)
|
||
(rpgdm-roll "1d20+9"))
|
||
|
||
:general
|
||
(chris/leader-keys
|
||
:states 'normal
|
||
:keymaps 'override
|
||
"a" '(:ignore t :which-key "RPGDM")
|
||
"ar" '(rpgdm-roll :which-key "roll")
|
||
"aa" '(hydra-rpgdm/body :which-key "hydra")
|
||
"as" '(chris/dnd-skill-check :which-key "check skill")
|
||
"ap" '(chris/dnd-spell-attack-check :which-key "Spell attack")))
|
||
|
||
;; 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)))
|