diff --git a/init.el b/init.el index 046a37b..8580e1f 100644 --- a/init.el +++ b/init.el @@ -168,9 +168,11 @@ ;; recentf (use-package recentf :init - (setq recentf-exclude '("^/tmp/.*" + (setq recentf-exclude `("^/tmp/.*" "^~/.mail/[^/]/Drafts/.*" - (format "^%svar/elpa/.*" user-emacs-directory))) + ,(format "^%svar/elpa/.*" user-emacs-directory) + ,(format "^%svar/gnus/.*" user-emacs-directory) + ,(format "^%setc/gnus/.*" user-emacs-directory))) :bind ("C-c r" . recentf) :config (recentf-mode 1)) @@ -243,7 +245,8 @@ visual states." :predicate '((not magit-mode dired-mode proced-mode mu4e-main-mode mu4e-view-mode mu4e-headers-mode - ibuffer-mode calc-mode calc-trail-mode) t)) + ibuffer-mode calc-mode calc-trail-mode + gnus-group-mode) t)) (my/evil-avy-global-mode 1) :config (avy-setup-default)) @@ -288,20 +291,51 @@ visual states." ;; face minibuffer-prompt)) ;; (vertico-mode 1)) +;; icomplete (use-package icomplete :ensure nil + :demand t :bind (:map icomplete-minibuffer-map ("C-S-s" . kill-line) ("C-j" . icomplete-forward-completions) ("C-k" . icomplete-backward-completions) ("DEL" . icomplete-fido-backward-updir) - ("M-DEL". delete-backward-char)) + ("M-DEL". delete-backward-char) + ("M-RET" . icomplete-force-complete-and-exit) + ("TAB" . icomplete-force-complete) + ("" . abort-recursive-edit) + ("C-;" . embark-dwim) + ("C-." . embark-act) + ("" . backward-char) + ("" . forward-char)) + :hook (icomplete-minibuffer-setup . my/icomplete-setup-hook-func) :init + (defun my/icomplete-setup-hook-func () + (setq truncate-lines t)) (setq completion-ignore-case t read-file-name-completion-ignore-case t read-buffer-completion-ignore-case t + enable-recursive-minibuffers t + minibuffer-prompt-properties '(read-only t + cursor-intangible t + face minibuffer-prompt) + ;;completions-detailed t + icomplete-compute-delay 0 icomplete-scroll t) + (defun my/crm-indicator (args) + (cons (format "[CRM%s] %s" + (replace-regexp-in-string + "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" + crm-separator) + (car args)) + (cdr args))) + (advice-add #'completing-read-multiple :filter-args #'my/crm-indicator) + (defun my/marginalia-trim-right (list) + (cl-loop for (cand prefix suffix) in list collect + (list cand prefix (string-trim-right suffix)))) + (advice-add #'marginalia--align :filter-return #'my/marginalia-trim-right) :config + (set-face-attribute 'icomplete-selected-match nil :inherit 'region) (fido-mode 1) (fido-vertical-mode 1)) @@ -464,11 +498,6 @@ visual states." :init (setq-default eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit)) -;; dumb-jump -(use-package dumb-jump - :init - (add-hook 'xref-backend-functions #'dumb-jump-xref-activate)) - ;; eglot (use-package eglot :demand t @@ -770,35 +799,61 @@ Take directly from doom-modeline." (doom-modeline-spc) "IAlg")))))))) +(use-package with-editor) + ;; vterm -(use-package vterm - :hook (vterm-mode . with-editor-export-editor) - :init - (defvar my/project-vterm-hash-table (make-hash-table :test 'equal) - "Hash table that maps project root dirs to vterm buffers.") - (defun my/project-vterm (prompt) - "Switch to or create a vterm buffer in the current projects root." +;; (use-package vterm +;; :hook (vterm-mode . with-editor-export-editor) +;; :init +;; (defvar my/project-vterm-hash-table (make-hash-table :test 'equal) +;; "Hash table that maps project root dirs to vterm buffers.") +;; (defun my/project-vterm (prompt) +;; "Switch to or create a vterm buffer in the current projects root." +;; (interactive (list t)) +;; (if-let ((proj (project-current prompt)) +;; (default-directory (project-root proj))) +;; (if-let ((vterm-buff (gethash default-directory +;; my/project-vterm-hash-table)) +;; ((buffer-live-p vterm-buff))) +;; (switch-to-buffer vterm-buff) +;; (puthash default-directory +;; (vterm (concat "*vterm for project " default-directory "*")) +;; my/project-vterm-hash-table)))) +;; (defun my/project-vterm-or-default () +;; "Open a vterm for the current project, otherwise, open a normal vterm." +;; (interactive) +;; (unless (my/project-vterm nil) +;; (if-let ((vterm-buff (gethash nil my/project-vterm-hash-table)) +;; ((buffer-live-p vterm-buff))) +;; (switch-to-buffer vterm-buff) +;; (puthash nil (vterm vterm-buffer-name) my/project-vterm-hash-table))))) + +;; eat +(use-package eat + :config + (defvar my/project-eat-hash-table (make-hash-table :test 'equal) + "Hash table that maps project root dirs to eat buffers.") + (defun my/project-eat (prompt) + "Switch to or create a eat buffer in the current projects root." (interactive (list t)) (if-let ((proj (project-current prompt)) (default-directory (project-root proj))) - (if-let ((vterm-buff (gethash default-directory - my/project-vterm-hash-table)) - ((buffer-live-p vterm-buff))) - (switch-to-buffer vterm-buff) - (puthash default-directory - (vterm (concat "*vterm for project " default-directory "*")) - my/project-vterm-hash-table)))) - (defun my/project-vterm-or-default () - "Open a vterm for the current project, otherwise, open a normal vterm." + (if-let ((eat-buff (gethash default-directory + my/project-eat-hash-table)) + ((buffer-live-p eat-buff))) + (switch-to-buffer eat-buff) + (let ((eat-buffer-name (concat "*eat for project " default-directory "*"))) + (puthash default-directory + (eat) + my/project-vterm-hash-table))))) + (defun my/project-eat-or-default () + "Open an eat for the current project, otherwise, open a normal eat." (interactive) - (unless (my/project-vterm nil) - (if-let ((vterm-buff (gethash nil my/project-vterm-hash-table)) - ((buffer-live-p vterm-buff))) - (switch-to-buffer vterm-buff) - (puthash nil (vterm vterm-buffer-name) my/project-vterm-hash-table))))) - -;; eat (mostly for eshell purposes) -(use-package eat) + (unless (my/project-eat nil) + (if-let ((eat-buff (gethash nil my/project-eat-hash-table)) + ((buffer-live-p eat-buff))) + (switch-to-buffer eat-buff) + (puthash nil (eat) my/project-eat-hash-table))))) ;; eshell stuff (use-package eshell @@ -860,11 +915,11 @@ If no name is given, list all bookmarks instead." (string-join (last parts num) "/")))) (defun my/-eshell-prompt-get-dir () "Get dir for `my/-eshell-prompt-function'" - (my/-eshell-prompt-cut-path - 3 (if-let ((worktree (car-safe (car-safe (magit-list-worktrees)))) - (parent (file-name-parent-directory worktree))) - (file-relative-name default-directory parent) - (my/-replace-home-with-tilda default-directory)))) + (my/-eshell-prompt-cut-path 3 + (if-let ((worktree (vc-root-dir)) + (parent (file-name-parent-directory worktree))) + (file-relative-name default-directory parent) + (my/-replace-home-with-tilda default-directory)))) (defun my/-eshell-prompt-status-char-for-branch (branch remote) "Get the status char representing the relation between BRANCH and REMOTE." (let ((lines (process-lines vc-git-program @@ -883,109 +938,109 @@ If no name is given, list all bookmarks instead." ((and to-remote to-local) ?󰹺) (to-remote ?󰜷) (to-local ?󰜮)))) - (defun my/-eshell-prompt-current-branch-status () - "Get the status char for the current branch and its remote." - (let ((refs (process-lines vc-git-program - "for-each-ref" - "--format=%(HEAD)%00%(refname:short)%00%(upstream:short)" - "refs/heads"))) - (catch 'break - (dolist (ref refs) - (if-let ((split-ref (split-string ref "\0" nil nil)) - ((equal (car split-ref) "*"))) - (throw 'break (my/-eshell-prompt-status-char-for-branch - (cadr split-ref) - (caddr split-ref)))))))) - (defun my/-eshell-prompt-git-state-chars () - "Get chars, like + and ✘ for `my/-eshell-prompt-function'." - (let ((lines (process-lines vc-git-program "status" "--porcelain=v1")) - (branch-status (my/-eshell-prompt-current-branch-status)) - (status-arr)) - (dolist (line lines) - (cl-loop with fields = (string-split line " " t " *") - with status-str = (car-safe fields) - for status-char across status-str - do - (cond ((or (= status-char ?M) (= status-char ?T)) - (add-to-list 'status-arr ?!)) - ((= status-char ??) - (add-to-list 'status-arr ??)) - ((or (= status-char ?A) (= status-char ?C)) - (add-to-list 'status-arr ?+)) - ((= status-char ?D) - (add-to-list 'status-arr ?)) - ((= status-char ?R) - (add-to-list 'status-arr ?»))))) - (sort status-arr #'<) - (when branch-status - (push branch-status status-arr)) - (apply 'string status-arr))) - (defun my/-eshell-prompt-git-status () - "Get git status for `my/-eshell-prompt-function'" - (let ((branch (car (vc-git-branches))) - (state (my/-eshell-prompt-git-state-chars))) - (concat - (propertize (concat " 󰊢 " branch) 'face '(:foreground "medium purple")) - (unless (string-empty-p state) - (propertize (concat " [" state "]") 'face '(:foreground "red")))))) - (defun my/-eshell-prompt-vc-status () - "Get vc status for `my/-eshell-prompt-function'." - (if-let (backend (vc-responsible-backend default-directory t)) - (if (eq backend 'Git) - (my/-eshell-prompt-git-status) - (my/-eshell-prompt-set-face-color - (concat "  " (downcase (symbol-name backend))) - "purple")))) - (defvar-local my/-eshell-prompt-last-start-time nil - "Start time of last eshell command.") - (defun my/-eshell-prompt-timer-pre-cmd () - "Command run before each eshell program to record the time." - (setq my/-eshell-prompt-last-start-time (current-time))) - (add-hook 'eshell-pre-command-hook #'my/-eshell-prompt-timer-pre-cmd) - (defun my/-eshell-prompt-format-span (span) - "Format SPAN as \"XhXms.\"" - (let* ((hours (/ span 3600)) - (mins (% (/ span 60) 60)) - (secs (% span 60))) - (concat (unless (= hours 0) - (format "%dh" hours)) - (unless (= mins 0) - (format "%dm" mins)) - (format "%ds" secs)))) - (defun my/-eshell-prompt-last-command-time (end-time) - "Return the prompt component for the time of the last command." - (if-let ((my/-eshell-prompt-last-start-time) - (len (time-subtract end-time - my/-eshell-prompt-last-start-time)) - (float-len (float-time len)) - ((< 3 float-len)) - (int-len (round float-len))) - (concat " time " - (propertize (my/-eshell-prompt-format-span int-len) - 'face '(:foreground "gold1"))))) - (defun my/-eshell-prompt-function () - "Function for `eshell-prompt-function'" - (let* ((end-time (current-time)) - (dir (my/-eshell-prompt-get-dir)) - (prompt (concat - "\n" - (propertize dir 'face '(:foreground "dark turquoise")) - (unless (file-writable-p dir) - " ") - (my/-eshell-prompt-vc-status) - (my/-eshell-prompt-last-command-time end-time) - (propertize "\n" 'read-only t 'rear-nonsticky t) - (propertize - "❯ " 'face `(:foreground - ,(if (= eshell-last-command-status 0) - "lime green" - "red")) - 'rear-nonsticky t)))) - (setq my/-eshell-prompt-last-start-time nil) - prompt)) - (setq eshell-prompt-function #'my/-eshell-prompt-function - eshell-prompt-regexp "^❯ " - eshell-highlight-prompt nil)) + (defun my/-eshell-prompt-current-branch-status () + "Get the status char for the current branch and its remote." + (let ((refs (process-lines vc-git-program + "for-each-ref" + "--format=%(HEAD)%00%(refname:short)%00%(upstream:short)" + "refs/heads"))) + (catch 'break + (dolist (ref refs) + (if-let ((split-ref (split-string ref "\0" nil nil)) + ((equal (car split-ref) "*"))) + (throw 'break (my/-eshell-prompt-status-char-for-branch + (cadr split-ref) + (caddr split-ref)))))))) + (defun my/-eshell-prompt-git-state-chars () + "Get chars, like + and ✘ for `my/-eshell-prompt-function'." + (let ((lines (process-lines vc-git-program "status" "--porcelain=v1")) + (branch-status (my/-eshell-prompt-current-branch-status)) + (status-arr)) + (dolist (line lines) + (cl-loop with fields = (string-split line " " t " *") + with status-str = (car-safe fields) + for status-char across status-str + do + (cond ((or (= status-char ?M) (= status-char ?T)) + (add-to-list 'status-arr ?!)) + ((= status-char ??) + (add-to-list 'status-arr ??)) + ((or (= status-char ?A) (= status-char ?C)) + (add-to-list 'status-arr ?+)) + ((= status-char ?D) + (add-to-list 'status-arr ?)) + ((= status-char ?R) + (add-to-list 'status-arr ?»))))) + (sort status-arr #'<) + (when branch-status + (push branch-status status-arr)) + (apply 'string status-arr))) + (defun my/-eshell-prompt-git-status () + "Get git status for `my/-eshell-prompt-function'" + (let ((branch (car (vc-git-branches))) + (state (my/-eshell-prompt-git-state-chars))) + (concat + (propertize (concat " 󰊢 " branch) 'face '(:foreground "medium purple")) + (unless (string-empty-p state) + (propertize (concat " [" state "]") 'face '(:foreground "red")))))) + (defun my/-eshell-prompt-vc-status () + "Get vc status for `my/-eshell-prompt-function'." + (if-let (backend (vc-responsible-backend default-directory t)) + (if (eq backend 'Git) + (my/-eshell-prompt-git-status) + (my/-eshell-prompt-set-face-color + (concat "  " (downcase (symbol-name backend))) + "purple")))) + (defvar-local my/-eshell-prompt-last-start-time nil + "Start time of last eshell command.") + (defun my/-eshell-prompt-timer-pre-cmd () + "Command run before each eshell program to record the time." + (setq my/-eshell-prompt-last-start-time (current-time))) + (add-hook 'eshell-pre-command-hook #'my/-eshell-prompt-timer-pre-cmd) + (defun my/-eshell-prompt-format-span (span) + "Format SPAN as \"XhXms.\"" + (let* ((hours (/ span 3600)) + (mins (% (/ span 60) 60)) + (secs (% span 60))) + (concat (unless (= hours 0) + (format "%dh" hours)) + (unless (= mins 0) + (format "%dm" mins)) + (format "%ds" secs)))) + (defun my/-eshell-prompt-last-command-time (end-time) + "Return the prompt component for the time of the last command." + (if-let ((my/-eshell-prompt-last-start-time) + (len (time-subtract end-time + my/-eshell-prompt-last-start-time)) + (float-len (float-time len)) + ((< 3 float-len)) + (int-len (round float-len))) + (concat " time " + (propertize (my/-eshell-prompt-format-span int-len) + 'face '(:foreground "gold1"))))) + (defun my/-eshell-prompt-function () + "Function for `eshell-prompt-function'" + (let* ((end-time (current-time)) + (dir (my/-eshell-prompt-get-dir)) + (prompt (concat + "\n" + (propertize dir 'face '(:foreground "dark turquoise")) + (unless (file-writable-p dir) + " ") + (my/-eshell-prompt-vc-status) + (my/-eshell-prompt-last-command-time end-time) + (propertize "\n" 'read-only t 'rear-nonsticky t) + (propertize + "❯ " 'face `(:foreground + ,(if (= eshell-last-command-status 0) + "lime green" + "red")) + 'rear-nonsticky t)))) + (setq my/-eshell-prompt-last-start-time nil) + prompt)) + (setq eshell-prompt-function #'my/-eshell-prompt-function + eshell-prompt-regexp "^❯ " + eshell-highlight-prompt nil)) (use-package esh-help :hook (eshell-mode . my/-setup-eshell-help-func) :init @@ -1021,11 +1076,11 @@ If no name is given, list all bookmarks instead." :bind ("C-x C-b" . ibuffer)) ;; magit -(use-package magit - :init - (evil-define-key '(normal visual motion) magit-mode-map - "s" #'magit-stage-file - "S" #'magit-stage-modified)) +;; (use-package magit +;; :init +;; (evil-define-key '(normal visual motion) magit-mode-map +;; "s" #'magit-stage-file +;; "S" #'magit-stage-modified)) ;; org-mode (use-package org @@ -1121,7 +1176,7 @@ If no name is given, list all bookmarks instead." (mu4e t) (mu4e-context-switch nil "Personal") -;; rainbow-delimiters +;; RAINBOW-delimiters (use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode))