Modeline cleanup, agenda bindings, dynamic tab helpers etc

This commit is contained in:
Curt Spark 2026-04-13 22:05:48 +01:00
parent e381030890
commit 0edb7ab98f
2 changed files with 154 additions and 86 deletions

View File

@ -3,4 +3,4 @@
This is a modernised GNU Emacs Configuration, an evolution of my old emacs configuration:
`https://git.cspark.dev/cspark/Emacs-Configuration`
It is intended to be more focused and clean, using modern more modular/simpler packages or the builtins.
Using more modern packages (Switching from company, lsp mode, EXWM to consult/vertico, eglot mode, EWM for example) and personal built emacs lisp.

164
init.el
View File

@ -61,6 +61,14 @@
(`(:propertize (,_ minor-mode-alist . ,_) . ,_) "")
(t elem)))
mode-line-modes))
; Hide other items
(line-number-mode -1)
(column-number-mode -1)
(setq mode-line-percent-position nil)
(with-eval-after-load 'evil
(setq evil-mode-line-format nil))
; Emacs 31 feature only - Collapse minor modes into one
(setq mode-line-collapse-minor-modes '(not))
;; Clipboard config
(setopt select-active-regions nil)
@ -204,6 +212,7 @@
(evil-define-key* '(normal) org-mode-map (kbd "M-h") nil)
(evil-define-key* '(normal) org-mode-map (kbd "M-l") nil)))
(with-eval-after-load 'org-agenda
(with-eval-after-load 'evil
(setq org-agenda-files '("~/Nextcloud/Agenda"))
;This is will integrate the Calendar/Diary into Org-Agenda, so you can get access to dates on public holidays etc. Set diary to true:
(setq org-agenda-include-diary t)
@ -219,13 +228,28 @@
;Autostart in day view
(setq org-agenda-span 'day)
;Auto save agenda buffers on refresh
(advice-add 'org-agenda-redo :before #'org-save-all-org-buffers)
(add-hook 'org-agenda-mode-hook #'(lambda ()
(org-agenda-entry-text-mode 1)))
(define-key org-agenda-mode-map (kbd "C-j") 'evil-next-line)
(define-key org-agenda-mode-map (kbd "C-k") 'evil-previous-line)
(define-key org-agenda-mode-map "d" 'org-agenda-toggle-day-view)
(define-key org-agenda-mode-map "p" 'org-pomodoro))
(define-key org-agenda-mode-map (kbd "C-j") 'org-agenda-goto-date)
(define-key org-agenda-mode-map "j" 'evil-next-line)
(define-key org-agenda-mode-map "k" 'evil-previous-line)
(define-key org-agenda-mode-map (kbd "V") nil)
(define-key org-agenda-mode-map (kbd "V") 'evil-visual-line)
(define-key org-agenda-mode-map "g" nil)
(define-key org-agenda-mode-map (kbd "g g") 'evil-goto-first-line)
(define-key org-agenda-mode-map (kbd "G") 'evil-goto-line)
(define-key org-agenda-mode-map "s" 'org-agenda-schedule)
(define-key org-agenda-mode-map "d" 'org-agenda-schedule)
(define-key org-agenda-mode-map (kbd "C-d") 'org-agenda-toggle-day-view)
(define-key org-agenda-mode-map "p" 'org-pomodoro)))
; For Org Pomodoro notification sound
(use-package sound-wav
@ -292,7 +316,7 @@
; Upcoming agenda items in modeline
(use-package org-upcoming-modeline
:ensure t
:after org-agenda ; if you don't want it to start until org has been loaded
:after org-agenda
:config
(org-upcoming-modeline-mode))
@ -741,12 +765,17 @@
(setq emms-source-file-directory-tree-function 'emms-source-file-directory-tree-find)
(setq emms-cache-set-all-from-mpd t)
(setq emms-browser-makes-thumbnails t)
(setq emms-browser-thumbnail-small-width 100)
(setq emms-mode-line-length-limit 20)
(emms-all)
(emms-player-mpd-connect)
(add-hook 'emms-playlist-cleared-hook 'emms-player-mpd-clear)
(setq emms-player-list '(emms-player-mpd))
(setq emms-player-mpd-supported-regexp ".")
(setq emms-player-mpd-supported-regexp "\\`http[s]?://\\|\\.\\([Mm]3[Uu]\\|[Oo][Gg][Gg]\\|[Ff][Ll][Aa][Cc]\\|[Mm][Pp]3\\|[Ww][Aa][Vv]\\|[Mm][Oo][Dd]\\|[Aa][Uu]\\|[Aa][Ii][Ff][Ff]\\|[Oo][Pp][Uu][Ss]\\)\\'")
(add-to-list 'emms-info-functions 'emms-info-mpd)
(define-key emms-playlist-mode-map (kbd "d") nil)
@ -1053,7 +1082,7 @@
(setq tab-bar-show 1) ; Hide the bar if only 1 tab exists
(setq tab-bar-new-tab-choice "*scratch*")
(defun dynamic-tab-ensure-scratch-tab (&rest _)
(defun dynamic-tab--ensure-scratch-tab (&rest _)
"Ensure dynamic scratch tab available if there are active buffers."
(let* ((tabs (funcall tab-bar-tabs-function))
(tab-names (mapcar (lambda (tab) (alist-get 'name tab)) tabs))
@ -1081,28 +1110,28 @@
;; Return to original tab if we were just initializing
(tab-bar-select-tab (1+ current-tab))))))
(defvar dynamic-tab-is-already-redirecting-p nil
(defvar dynamic-tab--is-already-redirecting-p nil
"Whether we are already redirecting to scratch tab or not.")
(defun dynamic-tab-redirect-to-scratch-tab ()
(defun dynamic-tab--redirect-to-scratch-tab ()
"Redirect to dedicated scratch tab if scratch buffer accessed on other tab."
(when (and (not dynamic-tab-is-already-redirecting-p)
(when (and (not dynamic-tab--is-already-redirecting-p)
(string= (buffer-name) "*scratch*")
(string= (buffer-name) "dynamic *scratch*"))
(setq dynamic-tab-is-already-redirecting-p t)
(setq dynamic-tab--is-already-redirecting-p t)
(unwind-protect
(switch-to-buffer nil)
(tab-bar-select-tab-by-name "dynamic *scratch*")
(setq dynamic-tab-is-already-redirecting-p nil))))
(setq dynamic-tab--is-already-redirecting-p nil))))
(defvar dynamic-tab-soft-kill-p nil
(defvar dynamic-tab--soft-kill-p nil
"When t, do not kill buffers only send them to background unless one tab open.")
(defun dynamic-tab-handle-buffer-check-and-close-tab ()
(defun dynamic-tab--handle-buffer-check-and-close-tab ()
"Check if we need to close the tab and action accordingly."
(let* ((is-last-tab (<= (length (tab-bar-tabs)) 2))
(is-last-buffer (<= (length (tab-line-tabs-window-buffers)) 1)))
(when (and (not is-last-tab) is-last-buffer)
(tab-close))))
(defun dynamic-tab-handle-tab-cleanup-kill ()
(defun dynamic-tab--handle-tab-cleanup-kill ()
"Check if we can kill buffer and free tab if no more reserved buffers in tab."
(let* ((is-last-tab (<= (length (tab-bar-tabs)) 2))
(is-last-buffer (<= (length (tab-line-tabs-window-buffers)) 2))
@ -1111,27 +1140,27 @@
;((and is-last-tab (not is-last-buffer)) t)
;((and is-last-tab (not is-last-buffer) (bury-buffer)))
((and (not is-last-tab) (not is-last-buffer) dynamic-tab-soft-kill-p) (bury-buffer))
((and (not is-last-tab) (not is-last-buffer) dynamic-tab--soft-kill-p) (bury-buffer))
(t t))))
(dynamic-tab-handle-buffer-check-and-close-tab)
(dynamic-tab--handle-buffer-check-and-close-tab)
is-marked-to-kill))
(defun dynamic-tab-block-buffer-kill ()
(defun dynamic-tab--block-buffer-kill ()
"Block buffer from being killed."
(message "You cannot kill the dynamic buffer")
nil)
(defun dynamic-tab-mark-buffer-unkillable ()
(defun dynamic-tab--mark-buffer-unkillable ()
"Mark buffer as unkillable."
(add-hook 'kill-buffer-query-functions #'dynamic-tab-block-buffer-kill nil t))
(defun dynamic-tab-mark-buffer-reserved ()
(add-hook 'kill-buffer-query-functions #'dynamic-tab--block-buffer-kill nil t))
(defun dynamic-tab--mark-buffer-reserved ()
"Mark buffer as reserved."
(add-hook 'kill-buffer-query-functions #'dynamic-tab-handle-tab-cleanup-kill nil t))
(defun dynamic-tab-unmark-buffer-reserved ()
(add-hook 'kill-buffer-query-functions #'dynamic-tab--handle-tab-cleanup-kill nil t))
(defun dynamic-tab--unmark-buffer-reserved ()
"Unmark buffer as reserved."
(remove-hook 'kill-buffer-query-functions #'dynamic-tab-handle-tab-cleanup-kill t))
(defun dynamic-tab-refresh-listeners ()
(remove-hook 'kill-buffer-query-functions #'dynamic-tab--handle-tab-cleanup-kill t))
(defun dynamic-tab--refresh-listeners ()
"Refresh hooks to listen on reserved buffers."
(dolist (buf (tab-line-tabs-window-buffers))
(with-current-buffer buf
@ -1142,33 +1171,57 @@
(cond
(is-child-buffer nil)
(is-mini-buffer nil)
(is-dynamic-buffer (dynamic-tab-mark-buffer-unkillable))
(is-scratch-buffer (dynamic-tab-mark-buffer-unkillable))
(is-dynamic-buffer (dynamic-tab--mark-buffer-unkillable))
(is-scratch-buffer (dynamic-tab--mark-buffer-unkillable))
(t (dynamic-tab-mark-buffer-reserved)))))))
(defun dynamic-tab-remove-listeners ()
(t (dynamic-tab--mark-buffer-reserved)))))))
(defun dynamic-tab--remove-listeners ()
"Remove all hooks on reserved buffers."
(dolist (buf (buffer-list))
(with-current-buffer buf
(dynamic-tab-unmark-buffer-reserved))))
(dynamic-tab--unmark-buffer-reserved))))
(defvar dynamic-tab-last-buffer nil)
(defun dynamic-tab-handle-buffer-switch (&rest _)
(defvar dynamic-tab--last-buffer nil)
(defun dynamic-tab--handle-buffer-switch (&rest _)
"Checks to run when buffer is switched."
(unless (eq (current-buffer) dynamic-tab-last-buffer)
(setq dynamic-tab-last-buffer (current-buffer))
(unless (eq (current-buffer) dynamic-tab--last-buffer)
(setq dynamic-tab--last-buffer (current-buffer))
;; Put your "on switch" logic here
(dynamic-tab-ensure-scratch-tab)
(dynamic-tab-redirect-to-scratch-tab)))
(defun dynamic-tab-handle-buffer-create (&rest _)
(dynamic-tab--ensure-scratch-tab)
(dynamic-tab--redirect-to-scratch-tab)))
(defun dynamic-tab--handle-buffer-create (&rest _)
"Checks to run when buffer is created."
(dynamic-tab-ensure-scratch-tab)
(dynamic-tab-refresh-listeners))
(dynamic-tab--ensure-scratch-tab)
(dynamic-tab--refresh-listeners))
(defun dynamic-tab-init ()
"Initialise dynamic tabs."
(add-hook 'window-buffer-change-functions #'dynamic-tab-handle-buffer-switch)
(add-hook 'after-change-major-mode-hook #'dynamic-tab-handle-buffer-create))
(add-hook 'window-buffer-change-functions #'dynamic-tab--handle-buffer-switch)
(add-hook 'after-change-major-mode-hook #'dynamic-tab--handle-buffer-create))
(defun dynamic-tab-move-tab-left ()
"Move tab left, no wrapping or moving the dedicated dynamic tab."
(let* ((is-first-tab (= (tab-bar--current-tab-index) 0))
(is-dynamic-tab-focused (string= (alist-get 'name (tab-bar--current-tab)) "dynamic *scratch*")))
(when (and (not is-first-tab)
(not is-dynamic-tab-focused))
(tab-bar-move-tab-backward))))
(defun dynamic-tab-move-tab-right ()
"Move tab right, no wrapping or moving past the dedicated dynamic tab."
(let* ((is-last-tab (= (tab-bar--current-tab-index) (- (length (tab-bar-tabs)) 2)))
(is-dynamic-tab-focused (string= (alist-get 'name (tab-bar--current-tab)) "dynamic *scratch*")))
(when (and (not is-last-tab)
(not is-dynamic-tab-focused))
(tab-bar-move-tab 1))))
; Generic tab helper functions
(defun delete-window-override (&rest _)
"Override for delete window, close tab if only one window instead."
(if (<= (length (window-list)) 1)
(progn
(tab-close)
nil)
t))
;; Helper functions for EWM
; Switch monitor
@ -1228,12 +1281,12 @@
"grim -g \"$(slurp)\" - | wl-copy")))
("M-w" . (lambda ()
(interactive)
(setq dynamic-tab-soft-kill-p t)
(setq dynamic-tab--soft-kill-p t)
(kill-buffer)
(setq dynamic-tab-soft-kill-p nil)))
(setq dynamic-tab--soft-kill-p nil)))
("C-x k" . (lambda ()
(interactive)
(setq dynamic-tab-soft-kill-p nil)
(setq dynamic-tab--soft-kill-p nil)
(call-interactively 'kill-buffer)))
; Monitor switching, find current focused monitor name via
@ -1254,6 +1307,12 @@
("M-h" . tab-bar-switch-to-prev-tab)
("M-l" . tab-bar-switch-to-next-tab)
("M-H" . (lambda ()
(interactive)
(dynamic-tab-move-tab-left)))
("M-L" . (lambda ()
(interactive)
(dynamic-tab-move-tab-right)))
("M-k" . windmove-up)
("M-j" . windmove-down))
:config
@ -1264,13 +1323,16 @@
(add-to-list 'ewm-intercept-prefixes ?\M-p)
(add-to-list 'ewm-intercept-prefixes ?\M-h)
(add-to-list 'ewm-intercept-prefixes ?\M-j)
(add-to-list 'ewm-intercept-prefixes ?\M-H)
(add-to-list 'ewm-intercept-prefixes ?\M-J)
(add-to-list 'ewm-intercept-prefixes ?\M-k)
(add-to-list 'ewm-intercept-prefixes ?\M-l)
(ewm--send-intercept-keys)
:init
;; Dynamic Tabs
(dynamic-tab-init)
(advice-add 'delete-window :before-while #'delete-window-override))
(with-eval-after-load 'ewm
;; Autostart
(ewm-autostart-application "qpwgraph")
(ewm-autostart-application "kdeconnect-indicator")
@ -1286,7 +1348,8 @@
:after posframe
:init
(defun simple-notification-popup (old-notification new-notification)
(unless (eq old-notification new-notification)
(ignore-errors
(when new-notification
(posframe-show
" *simple-notification-popup-alert*"
:string (concat
@ -1297,8 +1360,7 @@
:poshandler #'posframe-poshandler-frame-top-right-corner
:background-color "gold"
:foreground-color "black"
:timeout 5)))
:timeout 5))))
(add-hook 'ednc-notification-presentation-functions
#'simple-notification-popup)
(ednc-mode))
@ -1315,6 +1377,12 @@
(setq kdeconnect-devices '(("My Phone" . "378230a2e3c24b9a9904e7ffb0dfeb07")))
(setq kdeconnect-active-device '("My Phone" . "378230a2e3c24b9a9904e7ffb0dfeb07"))))
;(use-package elcord
; :ensure t
; :config
; (setq elcord-display-buffer-details nil)
; (elcord-mode)))
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.