diff --git a/emacs/.emacs.d/init.el b/emacs/.emacs.d/init.el index 07f631a..47fe086 100644 --- a/emacs/.emacs.d/init.el +++ b/emacs/.emacs.d/init.el @@ -91,22 +91,28 @@ ;; ------------------------------------------------------------------- ;; Buffer Tabs (LazyVim-style bufferline) ;; ------------------------------------------------------------------- -;; Every open buffer is shown as a numbered tab in a bar at the top of -;; each window. Click a tab, or press M-1 .. M-9 (M-0 for the tenth), -;; to switch to it. +;; The numbered tabs at the top of each window show the Org agenda and +;; buffers visiting a file. Emacs' internal `*...*' buffers (scratch, +;; messages, native-compile log, ...) are hidden. Click a tab, or press +;; M-1 .. M-9 (M-0 for the tenth), to switch to it. (defvar marc/tab-line-order nil "Stable display order of buffers shown in the tab line.") +(defun marc/tab-line-buffer-p (buffer) + "Return non-nil when BUFFER should be shown as a tab." + (and (buffer-live-p buffer) + (let ((name (buffer-name buffer))) + (and (not (string-prefix-p " " name)) + (or (not (string-prefix-p "*" name)) + (and (boundp 'org-agenda-buffer-name) + (string= name org-agenda-buffer-name))))))) + (defun marc/tab-line-buffers () - "Return live, non-hidden buffers in a stable display order." + "Return the buffers to show as tabs, in a stable display order." (setq marc/tab-line-order - (seq-filter (lambda (b) - (and (buffer-live-p b) - (not (string-prefix-p " " (buffer-name b))))) - marc/tab-line-order)) + (seq-filter #'marc/tab-line-buffer-p marc/tab-line-order)) (dolist (b (buffer-list)) - (when (and (buffer-live-p b) - (not (string-prefix-p " " (buffer-name b))) + (when (and (marc/tab-line-buffer-p b) (not (memq b marc/tab-line-order))) (setq marc/tab-line-order (append marc/tab-line-order (list b))))) marc/tab-line-order) @@ -132,7 +138,8 @@ :ensure nil :config (setq tab-line-tabs-function #'marc/tab-line-buffers - tab-line-tab-name-function #'marc/tab-line-tab-name) + tab-line-tab-name-function #'marc/tab-line-tab-name + tab-line-close-tab-function 'kill-buffer) (global-tab-line-mode 1) (dotimes (i 9) (let ((n (1+ i))) @@ -246,6 +253,8 @@ "pp" '(counsel-projectile-switch-project :which-key "switch project") "m" '(:ignore t :which-key "magit") "mm" '(magit-status :which-key "magit status") + "b" '(:ignore t :which-key "buffers") + "bd" '(kill-current-buffer :which-key "close buffer/tab") "." '(find-file :which-key "find file")) (general-define-key @@ -548,10 +557,28 @@ jumps to the selected match." ;; A brand-new frame with no file to open (e.g. `emacsclient -c') shows ;; today's agenda. Using `initial-buffer-choice' lets Emacs swap the ;; frame's buffer in place instead of opening a second frame. +(defcustom marc/agenda-keep-files '("todo.org") + "Basenames of agenda files to keep open after building the agenda. +The other files that `org-agenda-list' opens while scanning are killed." + :type '(repeat string) + :group 'org-agenda) + (defun marc/agenda-buffer () "Return today's Org agenda buffer, creating it if necessary." (require 'org-agenda) - (org-agenda-list 1) + (let ((before (buffer-list))) + (org-agenda-list 1) + (dolist (buf (buffer-list)) + (let ((file (buffer-file-name buf))) + (when (and (not (memq buf before)) + file + (not (buffer-modified-p buf)) + (not (get-buffer-window buf)) + (member (expand-file-name file) + (mapcar #'expand-file-name (org-agenda-files))) + (not (member (file-name-nondirectory file) + marc/agenda-keep-files))) + (kill-buffer buf))))) (or (get-buffer org-agenda-buffer-name) (get-buffer-create "*scratch*")))