diff options
48 files changed, 2169 insertions, 632 deletions
diff --git a/.alias.d/00-general b/.alias.d/00-general index c9a4668..ab57817 100644 --- a/.alias.d/00-general +++ b/.alias.d/00-general @@ -17,4 +17,4 @@ alias e=$EDITOR  alias mtr='mtr --curses'  alias t='cd ~/src/' -alias by='bat -l yaml'
\ No newline at end of file +alias by='batcat -l yaml'
\ No newline at end of file diff --git a/.config/rofi/config b/.config/rofi/config deleted file mode 100644 index 0406648..0000000 --- a/.config/rofi/config +++ /dev/null @@ -1 +0,0 @@ -rofi.theme: /usr/share/rofi/themes/Arc-Dark.rasi diff --git a/.config/rofi/config.rasi b/.config/rofi/config.rasi new file mode 100644 index 0000000..3b108ba --- /dev/null +++ b/.config/rofi/config.rasi @@ -0,0 +1,7 @@ +configuration { +  font: "Iosevka 20"; +  modes: [ combi ]; +  combi-modes: [ window, drun, run ]; +} + +@theme "Arc-Dark" diff --git a/.emacs.d/early-init.el b/.emacs.d/early-init.el index ae3e189..5a34cb3 100644 --- a/.emacs.d/early-init.el +++ b/.emacs.d/early-init.el @@ -4,19 +4,30 @@  (scroll-bar-mode -1)  ;; Avoid initial flash of light. -;; Inspired on prot-emacs-avoid-initial-flash-of-light. -(setq mode-line-format nil) -(set-face-attribute 'default nil :background "#000000" :foreground "#ffffff") -(set-face-attribute 'mode-line nil :background "#000000" :foreground "#ffffff" :box 'unspecified) +(defun prot-emacs-re-enable-frame-theme (_frame) +  "Re-enable active theme, if any, upon FRAME creation. +Add this to `after-make-frame-functions' so that new frames do +not retain the generic background set by the function +`prot-emacs-avoid-initial-flash-of-light'." +  (when-let* ((theme (car custom-enabled-themes))) +    (enable-theme theme))) + +(defun prot-emacs-avoid-initial-flash-of-light () +  "Avoid flash of light when starting Emacs, if needed. +New frames are instructed to call `prot-emacs-re-enable-frame-theme'." +  (setq mode-line-format nil) +  (set-face-attribute 'default nil :background "#000000" :foreground "#ffffff") +  (set-face-attribute 'mode-line nil :background "#000000" :foreground "#ffffff" :box 'unspecified) +  (add-hook 'after-make-frame-functions #'prot-emacs-re-enable-frame-theme)) + +(prot-emacs-avoid-initial-flash-of-light)  ;; Do not resize when font size changes  (setq frame-resize-pixelwise t) -;; By default, start maximized +;; By default, start maximized, undecorated  (add-to-list 'default-frame-alist '(fullscreen . maximized)) - -;; No need for titlebar -(modify-frame-parameters nil '((undecorated . t))) +(add-to-list 'default-frame-alist '(undecorated . t))  ;; Name frames to ease switching between them  (add-hook 'after-init-hook (lambda () (set-frame-name "main"))) @@ -27,3 +38,7 @@  ;; Do not report warnings. It's too noisy.  (setq native-comp-async-report-warnings-errors 'silent) + +;; Keep things minimal +(setq inhibit-startup-screen t) +(setq inhibit-startup-echo-area-message user-login-name) diff --git a/.emacs.d/init.el b/.emacs.d/init.el index e227e57..43b9e06 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -1,116 +1,36 @@ +;; package.el +(require 'package)  (add-to-list 'package-archives               '("melpa-stable" . "https://stable.melpa.org/packages/") t)  (add-to-list 'package-archives               '("melpa" . "https://melpa.org/packages/") t) -;; Do not persist customizations -(setq custom-file (make-temp-file "emacs-custom-")) - -;; Place backups in ~/.backups/ directory, like a civilized program. -;; ------ -(if (file-directory-p "~/.backup") -    (setq backup-directory-alist '(("." . "~/.backup"))) -  (message "Directory does not exist: ~/.backup")) - -(filesets-init) - -(setq backup-by-copying t    ; Don't delink hardlinks -      delete-old-versions t  ; Clean up the backups -      version-control t      ; Use version numbers on backups, -      kept-new-versions 3    ; keep some new versions -      kept-old-versions 2)   ; and some old ones, too - -;; --------- -;; Generic keybindings -;; --------- -(global-set-key (kbd "C-c d") 'diff-buffer-with-file) -(global-set-key (kbd "C-c R") 'revert-buffer) -(global-set-key (kbd "C-c w") 'whitespace-cleanup) - -(global-set-key (kbd "C-c b s") 'bookmark-set) -(global-set-key (kbd "C-c b j") 'bookmark-jump) - -(global-set-key (kbd "<f12>") 'compile) +(let ((backup-dir "~/.backup")) +  (unless (file-directory-p backup-dir) +    (make-directory backup-dir t)) +  (setq backup-directory-alist `(("." . ,backup-dir)))) -(defun help/insert-em-dash () -  "Inserts an EM-DASH (not a HYPEN, not an N-DASH)" -  (interactive) -  (insert "—")) +(setq + backup-by-copying t    ; Don't delink hardlinks + delete-old-versions t  ; Clean up the backups + kept-new-versions 3    ; keep some new versions + kept-old-versions 2   ; and some old ones, too + version-control t)      ; Use version numbers on backups -(global-set-key (kbd "C--") #'help/insert-em-dash) - -;; ------ -;; General config -;; ------ - -(setq fill-column 79) - -;; Make sure that pressing middle mouse button pastes right at point, -;; not where the mouse cursor is. -(setq mouse-yank-at-point t) - -(setq column-number-mode 1) -(setq line-number-mode 1) -(setq-default indent-tabs-mode nil) -(setq-default tab-width 4) +;; Do not persist customizations +(setq custom-file (make-temp-file "emacs-custom-")) -(setq-default c-basic-offset 4) +(setq fill-column 79) ; Wrap lines +(setq mouse-yank-at-point t) ; Do not follow mouse curors when mouse-yanking -;; ------ -;; Initialize environment -;; ------ +(setq-default indent-tabs-mode nil) ; No tabs when indenting +(setq-default tab-width 4) ; How many spaces a tab represents -(require 'server) -(setq server-client-instructions nil) -(unless (server-running-p) -  (server-start)) - -;; Load themes early in the bootstrap process. -(load-file "~/.emacs.d/rul-init.d/themes.el") - -;; ------ -;; Helper for compilation. -;; ------ -;; Close the compilation window if there was no error at all. -(defun compilation-exit-autoclose (status code msg) -  ;; If M-x compile exists with a 0 -  (when (and (eq status 'exit) (zerop code)) -    ;; then bury the *compilation* buffer, so that C-x b doesn't go there -    (bury-buffer) -    ;; and delete the *compilation* window -    (delete-window (get-buffer-window (get-buffer "*compilation*")))) -  ;; Always return the anticipated result of compilation-exit-message-function -  (cons msg code)) - -;; Specify my function (maybe I should have done a lambda function) -(setq compilation-exit-message-function 'compilation-exit-autoclose) -(setq compilation-read-command nil) - -;; Themes -(add-to-list 'custom-theme-load-path "~/.emacs.d/themes/") - -;; Remove scratch message  (setq initial-scratch-message "") -;; Ask y or n instead of yes or no  (defalias 'yes-or-no-p 'y-or-n-p) -;; Fancier buffer selection -(global-set-key (kbd "C-x C-b") 'bs-show) - -;;; Stefan Monnier <foo at acm.org>. It is the opposite of fill-paragraph -(defun unfill-paragraph (&optional region) -  "Takes a multi-line paragraph and makes it into a single line of text." -  (interactive (progn (barf-if-buffer-read-only) '(t))) -  (let ((fill-column (point-max)) -        ;; This would override `fill-column' if it's an integer. -        (emacs-lisp-docstring-fill-column t)) -    (fill-paragraph nil region))) - -;; Handy key definition -(define-key global-map "\M-Q" 'unfill-paragraph) -  ;; Only flash the mode line  (setq ring-bell-function        (lambda () @@ -124,86 +44,53 @@  (setq show-paren-delay 0)  (show-paren-mode 1) -;; Save what you enter into minibuffer prompts -(setq history-length 25) -(savehist-mode 1) - -;; Remember and restore cursor information -(save-place-mode 1) +(savehist-mode 1) ; Save histories, including minibuffer -;; Desktop -(setq desktop-path `(,user-emacs-directory)) -(setq desktop-base-file-name "desktop") -(desktop-save-mode 1) +(save-place-mode 1) ; Remember and restore cursor information -;; It's easier to get to magit if symlinks are followed. -(setq vc-follow-symlinks t) +(setq auto-save-no-message t) ; Do not print a message when auto-saving -;; dired -(use-package dired-preview -  :ensure t -  :config +(pixel-scroll-precision-mode 1) ; Precision scrolling -  (setq dired-preview-delay 0.3) -  (setq dired-preview-max-size (expt 2 20)) -  (setq dired-preview-ignored-extensions-regexp -        (concat "\\." -                "\\(mkv\\|webm\\|mp4\\|mp3\\|ogg\\|m4a" -                "\\|gz\\|zst\\|tar\\|xz\\|rar\\|zip" -                "\\|iso\\|epub\\|pdf\\)")) -  (dired-preview-global-mode 1)) +;; Source: https://protesilaos.com/codelog/2024-12-11-emacs-diff-save-some-buffers/ +(add-to-list 'save-some-buffers-action-alist +             (list "d" +                   (lambda (buffer) (diff-buffer-with-file (buffer-file-name buffer))) +                   "show diff between the buffer and its file")) -(add-hook 'dired-mode-hook #'dired-hide-details-mode) - -(setq dired-guess-shell-alist-user -      '(("\\.\\(png\\|jpe?g\\|tiff\\)" "feh" "xdg-open") -        ("\\.\\(mp[34]\\|m4a\\|ogg\\|flac\\|webm\\|mkv\\)" "mpv" "xdg-open") -		(".*" "xdg-open"))) +;; Server +(require 'server) +(setq server-client-instructions nil) ; Keep it quiet when opening an ec -;;; Icons -(use-package nerd-icons :ensure t ) -(use-package nerd-icons-dired :ensure t -  :config -  (add-hook 'dired-mode-hook #'nerd-icons-dired-mode) -  ) +(unless (server-running-p) +  (server-start)) -(dolist (path '("~/.emacs.d/rul-lisp/config" "~/.emacs.d/rul-lisp/packages")) +(dolist (path '("~/.emacs.d/rul-lisp/packages"))    (add-to-list 'load-path path)) -(pixel-scroll-precision-mode 1) +(when-let* ((file (locate-user-emacs-file "rul-pre-init.el")) +            ((file-exists-p file))) +  (load-file file)) +(require 'rul-themes) +(require 'rul-bindings)  (require 'rul-completion) -(require 'rul-prog) -(require 'rul-elfeed) +(require 'rul-dashboard) +(require 'rul-fm) +(require 'rul-fonts) +(require 'rul-io) +(require 'rul-mail)  (require 'rul-modeline) -(require 'rul-media)  (require 'rul-org) +(require 'rul-prog) +(require 'rul-terminals) +(require 'rul-vc)  (require 'rul-wm)  (require 'rul-write) -(load-file "~/.emacs.d/rul-init.d/fonts.el") - -;; Init parts (will be deprecated in favor of packages) -(load-file "~/.emacs.d/rul-init.d/auto-fill.el") -(load-file "~/.emacs.d/rul-init.d/flycheck.el") -(load-file "~/.emacs.d/rul-init.d/flyspell.el") -(load-file "~/.emacs.d/rul-init.d/go-lang.el") -(load-file "~/.emacs.d/rul-init.d/hydra.el") -(load-file "~/.emacs.d/rul-init.d/ibuffer.el") -(load-file "~/.emacs.d/rul-init.d/imenu.el") -(load-file "~/.emacs.d/rul-init.d/latex.el") -(load-file "~/.emacs.d/rul-init.d/logos.el") -(load-file "~/.emacs.d/rul-init.d/magit.el") -(load-file "~/.emacs.d/rul-init.d/mail-mode.el") -(load-file "~/.emacs.d/rul-init.d/markdown.el") -(load-file "~/.emacs.d/rul-init.d/notmuch.el") -(load-file "~/.emacs.d/rul-init.d/vterm.el") -(load-file "~/.emacs.d/rul-init.d/which-key.el") -  (when-let* ((file (locate-user-emacs-file "rul-post-init.el"))              ((file-exists-p file)))    (load-file file))  ;; init.el ends here -(put 'dired-find-alternate-file 'disabled nil) diff --git a/.emacs.d/rul-emacs.org b/.emacs.d/rul-emacs.org index 6770536..1ba5aae 100644 --- a/.emacs.d/rul-emacs.org +++ b/.emacs.d/rul-emacs.org @@ -11,7 +11,7 @@ this file, and *not* at load time, as that would be too slow.  (org-babel-tangle)  #+end_src -* Directory and file structure +* Overview of files and directories  - =early-init.el=: quoting the [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Early-Init-File.html][Emacs documentation]], this file is "loaded    before the package system and GUI is initialized, so in it you can @@ -29,8 +29,7 @@ this file, and *not* at load time, as that would be too slow.    needed in my work computer.  - =rul-emacs.org=: this file. It (will) generate the rest of the structure. -* The early init - +* Early configuration file (=early-init.el=)  ** Graphical aspects  Customization of graphical aspects of Emacs, such as size, panels, etc. @@ -41,10 +40,23 @@ Customization of graphical aspects of Emacs, such as size, panels, etc.  (scroll-bar-mode -1)  ;; Avoid initial flash of light. -;; Inspired on prot-emacs-avoid-initial-flash-of-light. -(setq mode-line-format nil) -(set-face-attribute 'default nil :background "#000000" :foreground "#ffffff") -(set-face-attribute 'mode-line nil :background "#000000" :foreground "#ffffff" :box 'unspecified) +(defun prot-emacs-re-enable-frame-theme (_frame) +  "Re-enable active theme, if any, upon FRAME creation. +Add this to `after-make-frame-functions' so that new frames do +not retain the generic background set by the function +`prot-emacs-avoid-initial-flash-of-light'." +  (when-let* ((theme (car custom-enabled-themes))) +    (enable-theme theme))) + +(defun prot-emacs-avoid-initial-flash-of-light () +  "Avoid flash of light when starting Emacs, if needed. +New frames are instructed to call `prot-emacs-re-enable-frame-theme'." +  (setq mode-line-format nil) +  (set-face-attribute 'default nil :background "#000000" :foreground "#ffffff") +  (set-face-attribute 'mode-line nil :background "#000000" :foreground "#ffffff" :box 'unspecified) +  (add-hook 'after-make-frame-functions #'prot-emacs-re-enable-frame-theme)) + +(prot-emacs-avoid-initial-flash-of-light)  #+end_src  ** Frame configuration @@ -60,11 +72,9 @@ environment.  ;; Do not resize when font size changes  (setq frame-resize-pixelwise t) -;; By default, start maximized +;; By default, start maximized, undecorated  (add-to-list 'default-frame-alist '(fullscreen . maximized)) - -;; No need for titlebar -(modify-frame-parameters nil '((undecorated . t))) +(add-to-list 'default-frame-alist '(undecorated . t))  ;; Name frames to ease switching between them  (add-hook 'after-init-hook (lambda () (set-frame-name "main"))) @@ -78,4 +88,1537 @@ environment.  ;; Do not report warnings. It's too noisy.  (setq native-comp-async-report-warnings-errors 'silent) + +;; Keep things minimal +(setq inhibit-startup-screen t) +(setq inhibit-startup-echo-area-message user-login-name) +#+end_src + +* Main configuration file (=init.el=) +** Package matters + +I use package from both stable and bleeding-edge Melpa. + +#+begin_src emacs-lisp :tangle "init.el" +;; package.el +(require 'package) +(add-to-list 'package-archives +             '("melpa-stable" . "https://stable.melpa.org/packages/") t) + +(add-to-list 'package-archives +             '("melpa" . "https://melpa.org/packages/") t) +#+end_src +** Backups +Emacs tends to clutter the filesystem with backup files. A backup file is normally the filename with a =~= suffix. I rather have my filesystem clean, and centralize all backups in a single directory. + +#+begin_src emacs-lisp :tangle "init.el" +(let ((backup-dir "~/.backup")) +  (unless (file-directory-p backup-dir) +    (make-directory backup-dir t)) +  (setq backup-directory-alist `(("." . ,backup-dir)))) + +(setq + backup-by-copying t    ; Don't delink hardlinks + delete-old-versions t  ; Clean up the backups + kept-new-versions 3    ; keep some new versions + kept-old-versions 2   ; and some old ones, too + version-control t)      ; Use version numbers on backups +#+end_src +** Customizations +Customizations don't place nicely with version control, so I do them in a random file that won't get persisted. + +Configurations that need persisting will be added to =custom-set-variables= and =custom-set-faces=. + +#+begin_src emacs-lisp :tangle "init.el" +;; Do not persist customizations +(setq custom-file (make-temp-file "emacs-custom-")) +#+end_src + +** Editor interface +General configurations related to text editing across all modes. + +#+begin_src emacs-lisp :tangle "init.el" +(setq fill-column 79) ; Wrap lines +(setq mouse-yank-at-point t) ; Do not follow mouse curors when mouse-yanking + +(setq-default indent-tabs-mode nil) ; No tabs when indenting +(setq-default tab-width 4) ; How many spaces a tab represents + +(setq initial-scratch-message "") + +(defalias 'yes-or-no-p 'y-or-n-p) + +;; Only flash the mode line +(setq ring-bell-function +      (lambda () +        (let ((orig-fg (face-foreground 'mode-line))) +          (set-face-foreground 'mode-line "#F2804F") +          (run-with-idle-timer 0.1 nil +                               (lambda (fg) (set-face-foreground 'mode-line fg)) +                               orig-fg)))) + +;; Highlight parens +(setq show-paren-delay 0) +(show-paren-mode 1) + +(savehist-mode 1) ; Save histories, including minibuffer + +(save-place-mode 1) ; Remember and restore cursor information + +(setq auto-save-no-message t) ; Do not print a message when auto-saving + +(pixel-scroll-precision-mode 1) ; Precision scrolling + + +;; Source: https://protesilaos.com/codelog/2024-12-11-emacs-diff-save-some-buffers/ +(add-to-list 'save-some-buffers-action-alist +             (list "d" +                   (lambda (buffer) (diff-buffer-with-file (buffer-file-name buffer))) +                   "show diff between the buffer and its file")) +#+end_src +** Emacs server +I used to run Emacs as a systemd daemon, but it was not too deterministic as sometimes it would break. + +  https://rbenencia.name/blog/emacs-daemon-as-a-systemd-service/ + +Now, I simply start it from Emacs itself. This approach works well for me. + +#+begin_src emacs-lisp :tangle "init.el" +;; Server +(require 'server) +(setq server-client-instructions nil) ; Keep it quiet when opening an ec + +(unless (server-running-p) +  (server-start)) +#+end_src +** Modules machinery +#+begin_src emacs-lisp :tangle "init.el" +(dolist (path '("~/.emacs.d/rul-lisp/packages")) +  (add-to-list 'load-path path)) + +(when-let* ((file (locate-user-emacs-file "rul-pre-init.el")) +            ((file-exists-p file))) +  (load-file file)) + +(require 'rul-themes) +(require 'rul-bindings) +(require 'rul-completion) +(require 'rul-dashboard) +(require 'rul-fm) +(require 'rul-fonts) +(require 'rul-io) +(require 'rul-mail) +(require 'rul-modeline) +(require 'rul-org) +(require 'rul-prog) +(require 'rul-terminals) +(require 'rul-vc) +(require 'rul-wm) +(require 'rul-write) + +(when-let* ((file (locate-user-emacs-file "rul-post-init.el")) +            ((file-exists-p file))) +  (load-file file)) + +;; init.el ends here +#+end_src + +* Modules +I group my configuration in logical modules. In general, a module +contains configuration for more than one package. + +** The =themes= module +The =themes= module contains code pertaining to Emacs themes.  + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-themes.el" +(use-package ef-themes :ensure t) +(use-package modus-themes +  :ensure t +  :config +  (setq +   modus-themes-mode-line '(accented borderless padded) +   modus-themes-region '(bg-only) +   modus-themes-bold-constructs t +   modus-themes-italic-constructs t +   modus-themes-paren-match '(bold intense) +   modus-themes-headings (quote ((1 . (rainbow variable-pitch 1.3)) +                                 (2 . (rainbow 1.1)) +                                 (t . (rainbow)))) +   modus-themes-org-blocks 'tinted)) +#+end_src + + +Additionally, this module subscribes to =org.freedesktop.appearance color-theme= +to detect what color theme is preferred, and set our Emacs theme accordingly. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-themes.el" +(use-package dbus) +(defun mf/set-theme-from-dbus-value (value) +  "Set the appropiate theme according to the color-scheme setting value." +  (message "value is %s" value) +  (if (equal value '1) +      (progn (message "Switch to dark theme") +             (modus-themes-select 'modus-vivendi)) +    (progn (message "Switch to light theme") +           (modus-themes-select 'modus-operandi)))) + +(defun mf/color-scheme-changed (path var value) +  "DBus handler to detect when the color-scheme has changed." +  (when (and (string-equal path "org.freedesktop.appearance") +             (string-equal var "color-scheme")) +    (mf/set-theme-from-dbus-value (car value)) +    )) + +;; Register for future changes +(dbus-register-signal + :session "org.freedesktop.portal.Desktop" + "/org/freedesktop/portal/desktop" "org.freedesktop.portal.Settings" + "SettingChanged" + #'mf/color-scheme-changed) + +;; Request the current color-scheme +(dbus-call-method-asynchronously + :session "org.freedesktop.portal.Desktop" + "/org/freedesktop/portal/desktop" "org.freedesktop.portal.Settings" + "Read" + (lambda (value) (mf/set-theme-from-dbus-value (caar value))) + "org.freedesktop.appearance" + "color-scheme" + ) + + +(provide 'rul-themes) +#+end_src + +** The =bindings= module +This module contains code pertaining to keybindings. It starts by +defining a set global keys. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-bindings.el" +;; Global keybindings +(global-set-key (kbd "C-c R") 'revert-buffer) +(global-set-key (kbd "C-c w") 'whitespace-cleanup) + +(defun help/insert-em-dash () +  "Inserts an EM-DASH (not a HYPEN, not an N-DASH)" +  (interactive) +  (insert "—")) + +(global-set-key (kbd "C--") #'help/insert-em-dash) +#+end_src + +Next, we define a few /hydras/. /Hydras/ are a way of grouping keybindings +together, offering a menu on the way. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-bindings.el" +(use-package hydra +  :ensure t +  :defer 1) + +;; tab-bar +(defhydra hydra-tab-bar (:color amaranth) +  "Tab Bar Operations" +  ("t" tab-new "Create a new tab" :column "Creation" :exit t) +  ("d" dired-other-tab "Open Dired in another tab") +  ("f" find-file-other-tab "Find file in another tab") +  ("x" tab-close "Close current tab") +  ("m" tab-move "Move current tab" :column "Management") +  ("r" tab-rename "Rename Tab") +  ("<return>" tab-bar-select-tab-by-name "Select tab by name" :column "Navigation") +  ("l" tab-next "Next Tab") +  ("j" tab-previous "Previous Tab") +  ("q" nil "Exit" :exit t)) + +(global-set-key (kbd "C-x t") 'hydra-tab-bar/body) + +;; Zoom +(defhydra hydra-zoom () +  "zoom" +  ("g" text-scale-increase "in") +  ("l" text-scale-decrease "out")) + +(global-set-key (kbd "C-c z") 'hydra-zoom/body) + +;; Go +(defhydra hydra-go () +  "zoom" +  ("=" gofmt :exit t) +  ("c" go-coverage :exit t)) + +;; vterm +(defhydra hydra-vterm () +  "zoom" +  ("t" multi-vterm "Open a terminal" :exit t) +  ("d" multi-vterm-dedicated-open "Dedicated" :exit t) +  ("p" multi-vterm-prev "Previous terminal") +  ("n" multi-vterm-next "Next terminal") +  ("r" multi-vterm-rename-buffer "Rename buffer" :exit t) +  ) + +(global-set-key (kbd "C-c t") 'hydra-vterm/body) +(global-set-key (kbd "C-c m") 'hydra-go/body) +#+end_src + +Finally, we make use of =which-key=, which will show a menu with all +keybinding options after a prefix is pressed. I think this package has +the potential to obsolete =hydra=, so I'll have to revisit that code. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-bindings.el" +(use-package which-key +  :ensure t +  :config +  (which-key-mode)) + +(provide 'rul-bindings) +#+end_src + +** The =completions= module +This module contains code pertaining to completion and the minibuffer. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-completion.el" +(use-package orderless :ensure t) + +(setq completion-styles '(basic substring initials orderless)) +(setq completion-category-overrides +      '( +        (file (styles . (basic partial-completion orderless))) +        (project-file (styles . (flex basic substring partial-completion orderless))) +        )) + +(setq completion-ignore-case t) +#+end_src + +The =vertico= package provides a vertical completion UI based on the default completion +system. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-completion.el" +;; Enable vertico +(use-package vertico +  :ensure t +  :init +  (vertico-mode) + +  :config +  (add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)) +#+end_src + +The =marginalia= package annotates the completion candidates with useful contextual +information. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-completion.el" +;; Enable rich annotations using the Marginalia package +(use-package marginalia +  :ensure t +  :bind (:map minibuffer-local-map +         ("M-A" . marginalia-cycle)) +  :init +  (marginalia-mode)) +#+end_src + +The =consult= package replaces most of Emacs core functions with +completion-friendly alternatives that integrates well with =vertico= and +=marginalia=. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-completion.el" +(use-package consult +  :ensure t +  :bind (;; C-c bindings in `mode-specific-map' +         ("C-c M-x" . consult-mode-command) +         ("C-c h" . consult-history) +         ("C-c k" . consult-kmacro) +         ("C-c m" . consult-man) +         ("C-c i" . consult-info) +         ([remap Info-search] . consult-info) + +         ;; C-x bindings in `ctl-x-map' +         ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command +         ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer +         ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window +         ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame +         ("C-x r b" . consult-bookmark)            ;; orig. bookmark-jump +         ("C-x p b" . consult-project-buffer)      ;; orig. project-switch-to-buffer + +         ;; Custom M-# bindings for fast register access +         ("M-#" . consult-register-load) +         ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated) +         ("C-M-#" . consult-register) + +         ;; Other custom bindings +         ("M-y" . consult-yank-pop)                ;; orig. yank-pop + +         ;; M-g bindings in `goto-map' +         ("M-g e" . consult-compile-error) +         ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck +         ("M-g g" . consult-goto-line)             ;; orig. goto-line +         ("M-g M-g" . consult-goto-line)           ;; orig. goto-line +         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading +         ("M-g m" . consult-mark) +         ("M-g k" . consult-global-mark) +         ("M-g i" . consult-imenu) +         ("M-g I" . consult-imenu-multi) + +         ;; M-s bindings in `search-map' +         ("M-s d" . consult-find) +         ("M-s D" . consult-locate) +         ("M-s g" . consult-grep) +         ("M-s G" . consult-git-grep) +         ("M-s r" . consult-ripgrep) +         ("M-s l" . consult-line) +         ("M-s L" . consult-line-multi) +         ("M-s k" . consult-keep-lines) +         ("M-s u" . consult-focus-lines) + +         ;; Isearch integration +         ("M-s e" . consult-isearch-history) + +         :map isearch-mode-map +         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string +         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string +         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch +         ("M-s L" . consult-line-multi)            ;; needed by consult-line to detect isearch + +         ;; Minibuffer history +         :map minibuffer-local-map +         ("M-s" . consult-history)                 ;; orig. next-matching-history-element +         ("M-r" . consult-history))                ;; orig. previous-matching-history-element + +  :init +  (setq xref-show-xrefs-function #'consult-xref) +  (setq xref-show-definitions-function #'consult-xref) +  (add-hook 'completion-list-mode-hook #'consult-preview-at-point-mode) + +  :config +  (setq consult-preview-key 'any) +  (setq consult-narrow-key "<") +) +#+end_src + +The next piece of code corresponds to =embark=, a package that enables +context-specific actions in the minibuffer, or common buffers. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-completion.el" +(use-package embark +  :ensure t + +  :bind +  (("C-." . embark-act)         ;; pick some comfortable binding +   ("M-." . embark-dwim)        ;; good alternative: M-. +   ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' + +  :init +  (setq prefix-help-command #'embark-prefix-help-command) + +  :config +  ;; Hide the mode line of the Embark live/completions buffers +  (add-to-list 'display-buffer-alist +               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" +                 nil +                 (window-parameters (mode-line-format . none))))) + +(use-package embark-consult +  :ensure t +  :hook +  (embark-collect-mode . consult-preview-at-point-mode)) + +(provide 'rul-completion) +#+end_src + +** The =dashboard= module +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-dashboard.el" +(use-package page-break-lines :ensure t) + +(use-package dashboard +  :ensure t + +  :config +  (dashboard-setup-startup-hook) + +  :custom +  (dashboard-center-content t) +  (dashboard-startup-banner 3) +  (dashboard-items '((recents   . 5) +                     (bookmarks . 5) +                     (projects  . 5) +                     (agenda    . 5) +                     )) +  (dashboard-icon-type 'nerd-icons) +  (dashboard-set-heading-icons t) +  (dashboard-set-file-icons t) +) + +(provide 'rul-dashboard) +#+end_src +** The =fm= module +The =fm= module contains code pertaining to file management. In +particular, it's the module that configures =dired= and adds a few extra +packages. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-fm.el" +;;; rul-fm.el --- File management + +;; dired +(add-hook 'dired-mode-hook #'dired-hide-details-mode) +(setq dired-guess-shell-alist-user +      '(("\\.\\(png\\|jpe?g\\|tiff\\)" "feh" "xdg-open") +        ("\\.\\(mp[34]\\|m4a\\|ogg\\|flac\\|webm\\|mkv\\)" "mpv" "xdg-open") +        (".*" "xdg-open"))) + +(setq dired-kill-when-opening-new-dired-buffer t) +(put 'dired-find-alternate-file 'disabled nil) + +;;; Icons +(use-package nerd-icons :ensure t ) +(use-package nerd-icons-dired :ensure t +  :config +  (add-hook 'dired-mode-hook #'nerd-icons-dired-mode)) + +(provide 'rul-fm) +#+end_src + +** The =fonts= module +The =fonts= module contains code pertaining to fonts. In particular, it +installs =fontaine=, a software that allows defining font presets. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-fonts.el" +;;; rul-fonts.el --- Fonts configuration + +(use-package fontaine +  :ensure t +  :config +  (setq fontaine-presets +      '((tiny +         :default-height 100) +        (small +         :default-height 120) +        (medium +         :default-height 140) +        (large +         :default-weight semilight +         :default-height 180 +         :bold-weight extrabold) +        (presentation +         :default-weight semilight +         :default-height 200 +         :bold-weight extrabold) +        (jumbo +         :default-weight semilight +         :default-height 230 +         :bold-weight extrabold) +        (writing +         :default-height 140 +         :default-family "Lato" +         :variable-pitch-family "Regular" +         ) +        (t +         :default-family "Iosevka" +         :default-weight regular +         :default-height 140 +         :variable-pitch-family "Iosevka Aile"))) + +  ;; Set desired style from `fontaine-presets' +  (fontaine-set-preset 'medium)) + +(provide 'rul-fonts) +#+end_src + +** The =io= module +The =io= module contains configurations for packages related to Internet +services and media. I don't have excessive costumizations in these +packages, so they're somewhat unrelated fragments of code grouped in +the same file. + +We install =elfeed= to browse RSS and Atom feeds. +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-io.el" +;;; rul-io.el --- Configuration for Internet and media packages + +(use-package elfeed :ensure t) +(provide 'rul-feeds) +#+end_src + +The =empv= package allow us to use the =mpv= player from within +Emacs. Here we're simply installing it and configuring it with some +Internet radio channels. It requires =mpv= to be installed. +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-io.el" +(use-package empv +:ensure t +:config +  (bind-key "C-x m" empv-map) +  (setq empv-radio-channels +      '( +       ("SomaFM - Groove Salad" . "http://www.somafm.com/groovesalad.pls") +       ("SomaFM - DEFCON" . "https://somafm.com/defcon256.pls") +       ("SomaFM - Metal" . "https://somafm.com/metal.pls") +       ("SomaFM - Lush" . "https://somafm.com/lush130.pls") +       ("KCSM Jazz 91" . "http://ice5.securenetsystems.net/KCSM") +       ))) + +(provide 'rul-io) +#+end_src +** The =mail= module +Emacs can act as Mail User Agent. My preferred package for this is +=notmuch=. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-mail.el" +;;; rul-mail.el --- Email configuration + +;; mml-sec.el +;; Use sender to find GPG key. +(setq mml-secure-openpgp-sign-with-sender t) + +(use-package notmuch +  :ensure t +  :config +  ;; UI +  (setq notmuch-show-logo nil +        notmuch-column-control 1.0 +        notmuch-hello-auto-refresh t +        notmuch-hello-recent-searches-max 20 +        notmuch-hello-thousands-separator "" +        notmuch-show-all-tags-list t +        notmuch-show-text/html-blocked-images nil +        ) + +  ;; Keymaps +  (defun rul/capture-mail() +    "Capture mail to org mode." +    (interactive) +    (org-store-link nil) +    (org-capture nil "m") +    ) + +  (bind-key "c" 'rul/capture-mail notmuch-show-mode-map) + +  (define-key notmuch-show-mode-map "R" 'notmuch-show-reply) +  (define-key notmuch-search-mode-map "R" 'notmuch-search-reply-to-thread) + +  ;; Spam +  (define-key notmuch-show-mode-map "S" +              (lambda () +                "mark message as spam" +                (interactive) +                (notmuch-show-tag (list "+spam" "-inbox" "-unread")))) + +  (define-key notmuch-search-mode-map "S" +              (lambda (&optional beg end) +                "mark thread as spam" +                (interactive (notmuch-search-interactive-region)) +                (notmuch-search-tag (list "+spam" "-inbox" "-unread") beg end))) + +  ;; Archive +  (setq notmuch-archive-tags (list "-inbox" "+archive")) +  (define-key notmuch-show-mode-map "A" +              (lambda () +                "archive" +                (interactive) +                (notmuch-show-tag (list "+archive" "-inbox" "-unread")) +                (notmuch-refresh-this-buffer))) + +  (define-key notmuch-search-mode-map "A" +              (lambda (&optional beg end) +                "archive thread" +                (interactive (notmuch-search-interactive-region)) +                (notmuch-search-tag (list "+archive" "-inbox" "-unread") beg end) +                (notmuch-refresh-this-buffer))) + +  ;; Mark as read +  (define-key notmuch-search-mode-map "r" +              (lambda (&optional beg end) +                "mark thread as read" +                (interactive (notmuch-search-interactive-region)) +                (notmuch-search-tag (list "-unread") beg end) +                (notmuch-search-next-thread))) + +  (define-key notmuch-search-mode-map (kbd "RET") +              (lambda () +                "Show the selected thread with notmuch-tree if it has more +than one email. Use notmuch-show otherwise." +                (interactive) +                (if (= (plist-get (notmuch-search-get-result) :total) 1) +                    (notmuch-search-show-thread) +                  (notmuch-tree (notmuch-search-find-thread-id) +                                notmuch-search-query-string +                                nil +                                (notmuch-prettify-subject (notmuch-search-find-subject)))))) + +  (defun color-inbox-if-unread () (interactive) +         (save-excursion +           (goto-char (point-min)) +           (let ((cnt (car (process-lines "notmuch" "count" "tag:inbox and tag:unread")))) +             (when (> (string-to-number cnt) 0) +               (save-excursion +                 (when (search-forward "inbox" (point-max) t) +                   (let* ((overlays (overlays-in (match-beginning 0) (match-end 0))) +                          (overlay (car overlays))) +                     (when overlay +                       (overlay-put overlay 'face '((:inherit bold) (:foreground "green"))))))))))) + +  (defvar notmuch-hello-refresh-count 0) +  (defun notmuch-hello-refresh-status-message () +    (let* ((new-count +            (string-to-number +             (car (process-lines notmuch-command "count")))) +           (diff-count (- new-count notmuch-hello-refresh-count))) +      (cond +       ((= notmuch-hello-refresh-count 0) +        (message "You have %s messages." +                 (notmuch-hello-nice-number new-count))) +       ((> diff-count 0) +        (message "You have %s more messages since last refresh." +                 (notmuch-hello-nice-number diff-count))) +       ((< diff-count 0) +        (message "You have %s fewer messages since last refresh." +                 (notmuch-hello-nice-number (- diff-count))))) +      (setq notmuch-hello-refresh-count new-count))) + +  (add-hook 'notmuch-hello-refresh-hook 'color-inbox-if-unread) +  (add-hook 'notmuch-hello-refresh-hook 'notmuch-hello-refresh-status-message) + +  (setq notmuch-hello-sections '(notmuch-hello-insert-saved-searches +                                 notmuch-hello-insert-search +                                 notmuch-hello-insert-recent-searches +                                 notmuch-hello-insert-alltags +                                 )) + +  ;; https://git.sr.ht/~tslil/dotfiles/tree/4e51afbb/emacs/notmuch-config.el#L76-82 +  (defmacro make-binds (mode-map binds argfunc &rest body) +    "Create keybindings in `mode-map' using a list of (keystr . arg) +pairs in `binds' of the form ( ... (argfunc arg) body)." +    `(progn ,@(mapcar (lambda (pair) +                        `(define-key ,mode-map (kbd ,(car pair)) +                                     (lambda () (interactive) (,argfunc ,(cdr pair)) ,@body))) +                      (eval binds)))) + +  (defvar notmuch-hello-tree-searches '(("u" . "tag:unread") +                                        ("i" . "tag:inbox") +                                        ("*" . "*")) +    "List of (key . query) pairs to bind in notmuch-hello.") + +  (make-binds notmuch-hello-mode-map +              notmuch-hello-tree-searches +              notmuch-search) +) ;; ends use-package notmuch + +(use-package notmuch-indicator :ensure t) + +(provide 'rul-mail) +#+end_src +** The =modeline= module +The =modeline= module contains code pertaining to Emacs modeline. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-modeline.el" +;;; rul-modeline.el --- Modeline configuration + +;; Most of the code in this file is based on: +;;   https://git.sr.ht/~protesilaos/dotfiles/tree/cf26bc34/item/emacs/.emacs.d/prot-lisp/prot-modeline.el +;; +;; All Kudos to Prot. + +;;;; Faces +(defface rul-modeline-indicator-red +  '((default :inherit bold) +    (((class color) (min-colors 88) (background light)) +     :foreground "#880000") +    (((class color) (min-colors 88) (background dark)) +     :foreground "#ff9f9f") +    (t :foreground "red")) +  "Face for modeline indicators.") + +;;;; Common helper functions +(defcustom rul-modeline-string-truncate-length 9 +  "String length after which truncation should be done in small windows." +  :type 'natnum) + +(defun rul-modeline--string-truncate-p (str) +  "Return non-nil if STR should be truncated." +  (and (< (window-total-width) split-width-threshold) +       (> (length str) rul-modeline-string-truncate-length) +       (not (one-window-p :no-minibuffer)))) + +(defun rul-modeline-string-truncate (str) +  "Return truncated STR, if appropriate, else return STR. +Truncation is done up to `rul-modeline-string-truncate-length'." +  (if (rul-modeline--string-truncate-p str) +      (concat (substring str 0 rul-modeline-string-truncate-length) "...") +    str)) + +;;;; Major mode +(defun rul-modeline-major-mode-indicator () +  "Return appropriate propertized mode line indicator for the major mode." +  (let ((indicator (cond +                    ((derived-mode-p 'text-mode) "§") +                    ((derived-mode-p 'prog-mode) "λ") +                    ((derived-mode-p 'comint-mode) ">_") +                    (t "◦")))) +    (propertize indicator 'face 'shadow))) + +(defun rul-modeline-major-mode-name () +  "Return capitalized `major-mode' without the -mode suffix." +  (capitalize (string-replace "-mode" "" (symbol-name major-mode)))) + +(defun rul-modeline-major-mode-help-echo () +  "Return `help-echo' value for `rul-modeline-major-mode'." +  (if-let ((parent (get major-mode 'derived-mode-parent))) +      (format "Symbol: `%s'.  Derived from: `%s'" major-mode parent) +    (format "Symbol: `%s'." major-mode))) + +(defvar-local rul-modeline-major-mode +    (list +     (propertize "%[" 'face 'rul-modeline-indicator-red) +     '(:eval +       (concat +        (rul-modeline-major-mode-indicator) +        " " +        (propertize +         (rul-modeline-string-truncate +          (rul-modeline-major-mode-name)) +         'mouse-face 'mode-line-highlight +         'help-echo (rul-modeline-major-mode-help-echo)))) +     (propertize "%]" 'face 'rul-modeline-indicator-red)) +  "Mode line construct for displaying major modes.") + +(with-eval-after-load 'eglot +  (setq mode-line-misc-info +        (delete '(eglot--managed-mode (" [" eglot--mode-line-format "] ")) mode-line-misc-info))) + +(defvar-local prot-modeline-eglot +    `(:eval +      (when (and (featurep 'eglot) (mode-line-window-selected-p)) +        '(eglot--managed-mode eglot--mode-line-format))) +  "Mode line construct displaying Eglot information. +Specific to the current window's mode line.") + +;;;; Miscellaneous +(defvar-local rul-modeline-misc-info +    '(:eval +      (when (mode-line-window-selected-p) +        mode-line-misc-info)) +  "Mode line construct displaying `mode-line-misc-info'. +Specific to the current window's mode line.") + +;;;; Display current time +(setq display-time-format " %a %e %b, %H:%M ") +(setq display-time-default-load-average nil) +(setq display-time-mail-string "") + +;;;; Variables used in the modeline need to be in `risky-local-variable'. +(dolist (construct '( +                     rul-modeline-major-mode +                     rul-modeline-misc-info +                     )) +  (put construct 'risky-local-variable t)) + +;;;; Finally, define the modeline format +(setq-default mode-line-format +              '("%e" +                mode-line-front-space +                mode-line-buffer-identification +                mode-line-front-space +                rul-modeline-major-mode +                prot-modeline-eglot +                mode-line-format-right-align +                rul-modeline-misc-info +                )) + +(provide 'rul-modeline) +#+end_src +** The =org= module + +My org mode configuration is quite big, so I split it across multiple files. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-org.el" +;;; rul-org.el --- Org configuration +(require 'org) +(require 'org-capture) +(require 'org-protocol) +(require 'org-habit) + +(require 'rul-org-agenda) + +(setq org-attach-use-inheritance t) +(setq org-cycle-separator-lines 0) +(setq org-hide-leading-stars nil) +(setq org-startup-indented t) +(setq org-edit-src-content-indentation 0) + +(use-package org-modern :ensure t) +(use-package org-pomodoro +  :ensure t +  :config +  (defun rul/disable-notifications () +    "Disable GNOME notifications." +    (shell-command "gsettings set org.gnome.desktop.notifications show-banners false")) + +  (defun rul/enable-notifications () +    "Enable GNOME notifications." +    (shell-command "gsettings set org.gnome.desktop.notifications show-banners true")) + +  ;; Add hooks for Pomodoro start and finish +  (add-hook 'org-pomodoro-started-hook #'rul/disable-notifications) +  (add-hook 'org-pomodoro-finished-hook #'rul/enable-notifications) +  (add-hook 'org-pomodoro-killed-hook #'rul/enable-notifications)) + +;; (add-hook 'org-mode-hook 'turn-off-auto-fill) +;; (add-hook 'auto-save-hook 'org-save-all-org-buffers) +(add-hook 'org-mode-hook 'visual-line-mode) + +(use-package org-download +  :ensure t +  :config +  (add-hook 'dired-mode-hook 'org-download-enable)) + +(setq org-startup-indented t +      org-pretty-entities nil +      org-hide-emphasis-markers t +      ;; show actually italicized text instead of /italicized text/ +      org-fontify-whole-heading-line t +      org-fontify-done-headline t +      org-fontify-quote-and-verse-blocks t) + +;; ORG BINDINGS ;; +(global-set-key (kbd "C-c l") #'org-store-link) +(global-set-key (kbd "C-c c") #'org-capture) +(global-set-key (kbd "C-c s") #'org-schedule) + +(global-set-key (kbd "<f9>") 'bh/punch-in) +(global-set-key (kbd "<f10>") 'bh/punch-out) +(global-set-key (kbd "<f12>") 'org-agenda) + +;; ORG STATES ;; +(setq org-todo-keywords +      (quote ((sequence "TODO(t)" "MAYBE(m)" "NEXT(n)" "|" "DONE(d)") +              (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "MEETING")))) + +(setq org-use-fast-todo-selection t) + +(setq org-todo-state-tags-triggers +      (quote (("CANCELLED" ("CANCELLED" . t)) +              ("WAITING" ("WAITING" . t)) +              ("HOLD" ("WAITING") ("HOLD" . t)) +              (done ("WAITING") ("HOLD")) +              ("TODO" ("WAITING") ("CANCELLED") ("HOLD")) +              ("NEXT" ("WAITING") ("CANCELLED") ("HOLD")) +              ("DONE" ("WAITING") ("CANCELLED") ("HOLD"))))) + +(setq org-enforce-todo-dependencies t) +(setq org-log-done (quote time)) +(setq org-log-redeadline (quote time)) +(setq org-log-reschedule (quote time)) +(setq org-log-into-drawer t) + +;; CAPTURE ;; +(setq org-capture-templates +      (quote +       ( + +        ("w" "Todo" entry +         (file+headline org-refile-path "Tasks") +         "* TODO %?" +         :empty-lines 1) + +        ("m" +         "Capture incoming email" +         entry +         (file+headline org-refile-path "Incoming") +         "* TODO Re: %:description\n\n  Source: %u, %a\n" +         :empty-lines 1) + +        ("e" "Elfeed entry" entry +         (file+headline org-refile-path "Read later") +         "* %? [[%:link][%:description]]\n  %U\n  %:description\n") + +        ("L" "Web Link" entry +         (file+headline org-refile-path "Read later") +         "* %?[[%:link][%:description]]\n %:initial\n \nCaptured On: %U" +         ) + +        ("l" "Web Link with Selection" entry +         (file+headline org-refile-path "Read later") +         "* [[%:link][%:description]]\n %:initial\n \nCaptured On: %U") +        ))) + +;; REFILE ;; + +; Targets include this file and any file contributing to the agenda - up to 3 levels deep +(setq org-refile-targets +      '((nil :maxlevel . 3) +        (org-agenda-files :maxlevel . 3))) + +; Targets complete directly with IDO +(setq org-outline-path-complete-in-steps nil) + +; Allow refile to create parent tasks with confirmation +(setq org-refile-allow-creating-parent-nodes (quote confirm)) + + + +;; ORG REPORTS ;; +; Set default column view headings: Task Effort Clock_Summary +(setq org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM") + +(defun my-org-clocktable-indent-string (level) +  (if (= level 1) +      "" +    (let ((str "^")) +      (while (> level 2) +        (setq level (1- level) +              str (concat str "--"))) +      (concat str "-> ")))) + +(advice-add 'org-clocktable-indent-string :override #'my-org-clocktable-indent-string) + +(setq org-clock-clocktable-default-properties '(:maxlevel 4 :scope file :formula %)) + +; global Effort estimate values +; global STYLE property values for completion +(setq org-global-properties (quote (("Effort_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00") +                                    ("STYLE_ALL" . "habit")))) + +;; TAGS ;; +; Tags with fast selection keys +(setq org-tag-alist (quote ((:startgroup) +                            ("@errand" . ?e) +                            ("@office" . ?o) +                            ("@home" . ?H) +                            (:endgroup) +                            ("WAITING" . ?w) +                            ("HOLD" . ?h) +                            ("CANCELLED" . ?c) +                            ("FLAGGED" . ??)))) + +(setq org-stuck-projects +      '("+LEVEL=2+PROJECT/-MAYBE-DONE" ("NEXT") ("@shop") +        "\\<IGNORE\\>")) + +; Allow setting single tags without the menu +(setq org-fast-tag-selection-single-key (quote expert)) + +;; org-modern +(add-hook 'org-mode-hook 'org-modern-mode) +(add-hook 'org-agenda-finalize-hook #'org-modern-agenda) + +;; Honor ATTR_ORG attribute. Defaults to image's width if not set. +(setq org-image-actual-width nil) + +(provide 'rul-org) +#+end_src + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-org-agenda.el" +;;; rul-org-agenda.el --- Org agenda configuration +(require 'org) + +(global-set-key (kbd "<f12>") #'org-agenda) +(global-set-key (kbd "C-c a") #'org-agenda) + +(defun bh/is-project-p () +  "Any task with a todo keyword subtask" +  (save-restriction +    (widen) +    (let ((has-subtask) +          (subtree-end (save-excursion (org-end-of-subtree t))) +          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) +      (save-excursion +        (forward-line 1) +        (while (and (not has-subtask) +                    (< (point) subtree-end) +                    (re-search-forward "^\*+ " subtree-end t)) +          (when (member (org-get-todo-state) org-todo-keywords-1) +            (setq has-subtask t)))) +      (and is-a-task has-subtask)))) + +(defun bh/is-project-subtree-p () +  "Any task with a todo keyword that is in a project subtree. +Callers of this function already widen the buffer view." +  (let ((task (save-excursion (org-back-to-heading 'invisible-ok) +                              (point)))) +    (save-excursion +      (bh/find-project-task) +      (if (equal (point) task) +          nil +        t)))) + +(defun bh/is-task-p () +  "Any task with a todo keyword and no subtask" +  (save-restriction +    (widen) +    (let ((has-subtask) +          (subtree-end (save-excursion (org-end-of-subtree t))) +          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) +      (save-excursion +        (forward-line 1) +        (while (and (not has-subtask) +                    (< (point) subtree-end) +                    (re-search-forward "^\*+ " subtree-end t)) +          (when (member (org-get-todo-state) org-todo-keywords-1) +            (setq has-subtask t)))) +      (and is-a-task (not has-subtask))))) + +(defun bh/is-subproject-p () +  "Any task which is a subtask of another project" +  (let ((is-subproject) +        (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) +    (save-excursion +      (while (and (not is-subproject) (org-up-heading-safe)) +        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) +          (setq is-subproject t)))) +    (and is-a-task is-subproject))) + +(defun bh/list-sublevels-for-projects-indented () +  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks. +  This is normally used by skipping functions where this variable is already local to the agenda." +  (if (marker-buffer org-agenda-restrict-begin) +      (setq org-tags-match-list-sublevels 'indented) +    (setq org-tags-match-list-sublevels nil)) +  nil) + +(defun bh/list-sublevels-for-projects () +  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks. +  This is normally used by skipping functions where this variable is already local to the agenda." +  (if (marker-buffer org-agenda-restrict-begin) +      (setq org-tags-match-list-sublevels t) +    (setq org-tags-match-list-sublevels nil)) +  nil) + +(defvar bh/hide-scheduled-and-waiting-next-tasks t) + +(defun bh/toggle-next-task-display () +  (interactive) +  (setq bh/hide-scheduled-and-waiting-next-tasks (not bh/hide-scheduled-and-waiting-next-tasks)) +  (when  (equal major-mode 'org-agenda-mode) +    (org-agenda-redo)) +  (message "%s WAITING and SCHEDULED NEXT Tasks" (if bh/hide-scheduled-and-waiting-next-tasks "Hide" "Show"))) + +(defun bh/skip-stuck-projects () +  "Skip trees that are not stuck projects" +  (save-restriction +    (widen) +    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) +      (if (bh/is-project-p) +          (let* ((subtree-end (save-excursion (org-end-of-subtree t))) +                 (has-next )) +            (save-excursion +              (forward-line 1) +              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t)) +                (unless (member "WAITING" (org-get-tags-at)) +                  (setq has-next t)))) +            (if has-next +                nil +              next-headline)) ; a stuck project, has subtasks but no next task +        nil)))) + +(defun bh/skip-non-stuck-projects () +  "Skip trees that are not stuck projects" +  ;; (bh/list-sublevels-for-projects-indented) +  (save-restriction +    (widen) +    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) +      (if (bh/is-project-p) +          (let* ((subtree-end (save-excursion (org-end-of-subtree t))) +                 (has-next )) +            (save-excursion +              (forward-line 1) +              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t)) +                (unless (member "WAITING" (org-get-tags-at)) +                  (setq has-next t)))) +            (if has-next +                next-headline +              nil)) ; a stuck project, has subtasks but no next task +        next-headline)))) + +(defun bh/skip-non-projects () +  "Skip trees that are not projects" +  ;; (bh/list-sublevels-for-projects-indented) +  (if (save-excursion (bh/skip-non-stuck-projects)) +      (save-restriction +        (widen) +        (let ((subtree-end (save-excursion (org-end-of-subtree t)))) +          (cond +           ((bh/is-project-p) +            nil) +           ((and (bh/is-project-subtree-p) (not (bh/is-task-p))) +            nil) +           (t +            subtree-end)))) +    (save-excursion (org-end-of-subtree t)))) + +(defun bh/skip-non-tasks () +  "Show non-project tasks. +Skip project and sub-project tasks, habits, and project related tasks." +  (save-restriction +    (widen) +    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) +      (cond +       ((bh/is-task-p) +        nil) +       (t +        next-headline))))) + +(defun bh/skip-project-trees-and-habits () +  "Skip trees that are projects" +  (save-restriction +    (widen) +    (let ((subtree-end (save-excursion (org-end-of-subtree t)))) +      (cond +       ((bh/is-project-p) +        subtree-end) +       ((org-is-habit-p) +        subtree-end) +       (t +        nil))))) + +(defun bh/skip-projects-and-habits-and-single-tasks () +  "Skip trees that are projects, tasks that are habits, single non-project tasks" +  (save-restriction +    (widen) +    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) +      (cond +       ((org-is-habit-p) +        next-headline) +       ((and bh/hide-scheduled-and-waiting-next-tasks +             (member "WAITING" (org-get-tags-at))) +        next-headline) +       ((bh/is-project-p) +        next-headline) +       ((and (bh/is-task-p) (not (bh/is-project-subtree-p))) +        next-headline) +       (t +        nil))))) + +(defun bh/skip-project-tasks-maybe () +  "Show tasks related to the current restriction. +When restricted to a project, skip project and sub project tasks, habits, NEXT tasks, and loose tasks. +When not restricted, skip project and sub-project tasks, habits, and project related tasks." +  (save-restriction +    (widen) +    (let* ((subtree-end (save-excursion (org-end-of-subtree t))) +           (next-headline (save-excursion (or (outline-next-heading) (point-max)))) +           (limit-to-project (marker-buffer org-agenda-restrict-begin))) +      (cond +       ((bh/is-project-p) +        next-headline) +       ((org-is-habit-p) +        subtree-end) +       ((and (not limit-to-project) +             (bh/is-project-subtree-p)) +        subtree-end) +       ((and limit-to-project +             (bh/is-project-subtree-p) +             (member (org-get-todo-state) (list "NEXT"))) +        subtree-end) +       (t +        nil))))) + +(defun bh/skip-project-tasks () +  "Show non-project tasks. +Skip project and sub-project tasks, habits, and project related tasks." +  (save-restriction +    (widen) +    (let* ((subtree-end (save-excursion (org-end-of-subtree t)))) +      (cond +       ((bh/is-project-p) +        subtree-end) +       ((org-is-habit-p) +        subtree-end) +       ((bh/is-project-subtree-p) +        subtree-end) +       ((not (org-entry-is-todo-p)) +        subtree-end) +       (t +        nil))))) + +(defun bh/skip-non-project-tasks () +  "Show project tasks. +Skip project and sub-project tasks, habits, and loose non-project tasks." +  (save-restriction +    (widen) +    (let* ((subtree-end (save-excursion (org-end-of-subtree t))) +           (next-headline (save-excursion (or (outline-next-heading) (point-max))))) +      (cond +       ((bh/is-project-p) +        next-headline) +       ((org-is-habit-p) +        subtree-end) +       ((and (bh/is-project-subtree-p) +             (member (org-get-todo-state) (list "NEXT"))) +        subtree-end) +       ((not (bh/is-project-subtree-p)) +        subtree-end) +       (t +        nil))))) + +(defun bh/skip-projects-and-habits () +  "Skip trees that are projects and tasks that are habits" +  (save-restriction +    (widen) +    (let ((subtree-end (save-excursion (org-end-of-subtree t)))) +      (cond +       ((bh/is-project-p) +        subtree-end) +       ((org-is-habit-p) +        subtree-end) +       (t +        nil))))) + +(defun bh/skip-non-subprojects () +  "Skip trees that are not projects" +  (let ((next-headline (save-excursion (outline-next-heading)))) +    (if (bh/is-subproject-p) +        nil +      next-headline))) + +;; CLOCKING ;; +;; Resume clocking task when emacs is restarted +(org-clock-persistence-insinuate) +;; +;; Show lot of clocking history so it's easy to pick items off the C-F11 list +(setq org-clock-history-length 23) +;; Resume clocking task on clock-in if the clock is open +(setq org-clock-in-resume t) +;; Change tasks to NEXT when clocking in +(setq org-clock-in-switch-to-state 'bh/clock-in-to-next) +;; Separate drawers for clocking and logs +(setq org-drawers (quote ("PROPERTIES" "LOGBOOK"))) +;; Save clock data and state changes and notes in the LOGBOOK drawer +(setq org-clock-into-drawer t) +;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration +(setq org-clock-out-remove-zero-time-clocks t) +;; Clock out when moving task to a done state +(setq org-clock-out-when-done t) +;; Save the running clock and all clock history when exiting Emacs, load it on startup +(setq org-clock-persist t) +;; Do not prompt to resume an active clock +(setq org-clock-persist-query-resume nil) +;; Enable auto clock resolution for finding open clocks +(setq org-clock-auto-clock-resolution (quote when-no-clock-is-running)) +;; Include current clocking task in clock reports +(setq org-clock-report-include-clocking-task t) + + +(setq bh/keep-clock-running nil) + +(defun bh/clock-in-to-next (kw) +  "Switch a task from TODO to NEXT when clocking in. +Skips capture tasks, projects, and subprojects. +Switch projects and subprojects from NEXT back to TODO" +  (when (not (and (boundp 'org-capture-mode) org-capture-mode)) +    (cond +     ((and (member (org-get-todo-state) (list "TODO")) +           (bh/is-task-p)) +      "NEXT") +     ((and (member (org-get-todo-state) (list "NEXT")) +           (bh/is-project-p)) +      "TODO")))) + +(defun bh/find-project-task () +  "Move point to the parent (project) task if any" +  (save-restriction +    (widen) +    (let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point)))) +      (while (org-up-heading-safe) +        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) +          (setq parent-task (point)))) +      (goto-char parent-task) +      parent-task))) + +(defun bh/punch-in (arg) +  "Start continuous clocking and set the default task to the +selected task.  If no task is selected set the Organization task +as the default task." +  (interactive "p") +  (setq bh/keep-clock-running t) +  (if (equal major-mode 'org-agenda-mode) +      ;; +      ;; We're in the agenda +      ;; +      (let* ((marker (org-get-at-bol 'org-hd-marker)) +             (tags (org-with-point-at marker (org-get-tags-at)))) +        (if (and (eq arg 4) tags) +            (org-agenda-clock-in '(16)) +          (bh/clock-in-organization-task-as-default))) +    ;; +    ;; We are not in the agenda +    ;; +    (save-restriction +      (widen) +      ; Find the tags on the current task +      (if (and (equal major-mode 'org-mode) (not (org-before-first-heading-p)) (eq arg 4)) +          (org-clock-in '(16)) +        (bh/clock-in-organization-task-as-default))))) + +(defun bh/punch-out () +  (interactive) +  (setq bh/keep-clock-running nil) +  (when (org-clock-is-active) +    (org-clock-out)) +  (org-agenda-remove-restriction-lock)) + +(defun bh/clock-in-default-task () +  (save-excursion +    (org-with-point-at org-clock-default-task +      (org-clock-in)))) + +(defun bh/clock-in-parent-task () +  "Move point to the parent (project) task if any and clock in" +  (let ((parent-task)) +    (save-excursion +      (save-restriction +        (widen) +        (while (and (not parent-task) (org-up-heading-safe)) +          (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) +            (setq parent-task (point)))) +        (if parent-task +            (org-with-point-at parent-task +              (org-clock-in)) +          (when bh/keep-clock-running +            (bh/clock-in-default-task))))))) + +(defvar bh/organization-task-id "redefine") ;; org-id-get-create + +;; https://stackoverflow.com/a/10091330 +(defun zin/org-agenda-skip-tag (tag &optional others) +  "Skip all entries that correspond to TAG. + +If OTHERS is true, skip all entries that do not correspond to TAG." +  (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))) +        (current-headline (or (and (org-at-heading-p) +                                   (point)) +                              (save-excursion (org-back-to-heading))))) +    (if others +        (if (not (member tag (org-get-tags-at current-headline))) +            next-headline +          nil) +      (if (member tag (org-get-tags-at current-headline)) +          next-headline +        nil)))) + +(defun bh/clock-in-organization-task-as-default () +  (interactive) +  (org-with-point-at (org-id-find bh/organization-task-id 'marker) +    (org-clock-in '(16)))) + +(defun bh/clock-out-maybe () +  (when (and bh/keep-clock-running +             (not org-clock-clocking-in) +             (marker-buffer org-clock-default-task) +             (not org-clock-resolving-clocks-due-to-idleness)) +    (bh/clock-in-parent-task))) + +(add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append) + +;;; Focusing on current work + +(global-set-key (kbd "<f5>") 'bh/org-todo) +(defun bh/org-todo (arg) +  (interactive "p") +  (if (equal arg 4) +      (save-restriction +        (bh/narrow-to-org-subtree) +        (org-show-todo-tree nil)) +    (bh/narrow-to-org-subtree) +    (org-show-todo-tree nil))) + +(global-set-key (kbd "<S-f5>") 'bh/widen) +(defun bh/widen () +  (interactive) +  (if (equal major-mode 'org-agenda-mode) +      (progn +        (org-agenda-remove-restriction-lock) +        (when org-agenda-sticky +          (org-agenda-redo))) +    (widen))) + +(defun bh/narrow-to-org-subtree () +  (widen) +  (org-narrow-to-subtree) +  (save-restriction +    (org-agenda-set-restriction-lock))) + +;; AGENDA VIEW ;; + +;; Do not dim blocked tasks +(setq org-agenda-compact-blocks nil) +(setq org-agenda-dim-blocked-tasks nil) +(setq org-agenda-block-separator 61) + +;; Agenda log mode items to display (closed and state changes by default) +(setq org-agenda-log-mode-items (quote (closed state))) + +; For tag searches ignore tasks with scheduled and deadline dates +(setq org-agenda-tags-todo-honor-ignore-options t) + +(setq org-icalendar-include-body nil) +(setq org-icalendar-include-bbdb-anniversaries t) +(setq org-icalendar-include-todo t) +(setq org-icalendar-use-scheduled '(todo-start event-if-not-todo event-if-todo-not-done)) + +(provide 'rul-org-agenda) +#+end_src +** The =prog= module +This package contains code related to programming or markup languages +modes. As my configurations are generally small, I prefer to have them +on a single file. + +#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-prog.el" +;;; rul-prog.el --- Configuration related to programming and markup +;;; languages +(use-package eglot :ensure t) + +;; Go +(use-package go-mode +  :ensure t +  :init +  (progn +    (bind-key [remap find-tag] #'godef-jump)) +  :config +  (add-hook 'go-mode-hook #'yas-minor-mode) +  (add-hook 'go-mode-hook 'electric-pair-mode) +  (add-hook 'go-mode-hook 'my-go-mode-hook) +  (add-hook 'before-save-hook 'gofmt-before-save)) + +(use-package go-eldoc +  :ensure t +  :init +  (add-hook 'go-mode-hook 'go-eldoc-setup)) + +;; Latex +(add-hook 'latex-mode-hook 'flyspell-mode) +(setq TeX-PDF-mode t) + +(defun pdfevince () +  (add-to-list 'TeX-output-view-style +		'("^pdf$" "." "evince %o %(outpage)"))) + +(add-hook  'LaTeX-mode-hook  'pdfevince  t) ; AUCTeX LaTeX mode + +;; Markdown +(use-package markdown-mode +  :ensure t +  :config +  (setq auto-mode-alist +        (cons '("\\.mdwn" . markdown-mode) auto-mode-alist))) + +;; Python +(use-package blacken :ensure t :defer t) +(with-eval-after-load 'lsp-mode +  (lsp-register-client +   (make-lsp-client +    :new-connection (lsp-stdio-connection '("ruff" "server")) +    :activation-fn (lsp-activate-on "python") +    :server-id 'ruff-lsp))) +(add-hook 'python-mode-hook #'lsp) + +;; Terraform +(use-package terraform-mode :ensure t :defer t) + +;; YAML +(use-package yaml-mode :ensure t :defer t) + +;; Rust +(use-package rust-mode +  :defer t +  :init +  (setq rust-mode-treesitter-derive t) +  :config +  (add-hook 'rust-mode-hook 'eglot-ensure)) + +(provide 'rul-prog)  #+end_src diff --git a/.emacs.d/rul-init.d/auto-fill.el b/.emacs.d/rul-init.d/auto-fill.el deleted file mode 100644 index dad2831..0000000 --- a/.emacs.d/rul-init.d/auto-fill.el +++ /dev/null @@ -1,4 +0,0 @@ -;; auto-fill mode -(add-hook 'text-mode-hook 'turn-on-auto-fill) -(global-set-key (kbd "C-c q") 'auto-fill-mode) - diff --git a/.emacs.d/rul-init.d/flycheck.el b/.emacs.d/rul-init.d/flycheck.el deleted file mode 100644 index 006081e..0000000 --- a/.emacs.d/rul-init.d/flycheck.el +++ /dev/null @@ -1,22 +0,0 @@ -(use-package flycheck -  :ensure t -  :config - -(flycheck-define-checker proselint -  "A linter for prose." -  :command ("proselint" source-inplace) -  :error-patterns -  ((warning line-start (file-name) ":" line ":" column ": " -	    (id (one-or-more (not (any " ")))) -	    (message) line-end)) -  :modes (text-mode markdown-mode gfm-mode org-mode)) - -(add-to-list 'flycheck-checkers 'proselint) - -;; TODO: docker run --rm -p 8010:8010 erikvl87/languagetool -(use-package flycheck-languagetool -  :ensure t -  :hook (message-mode . flycheck-languagetool-setup) -  :init -  (setq flycheck-languagetool-url "http://localhost:8010") -)) diff --git a/.emacs.d/rul-init.d/flyspell.el b/.emacs.d/rul-init.d/flyspell.el deleted file mode 100644 index 8cf27b8..0000000 --- a/.emacs.d/rul-init.d/flyspell.el +++ /dev/null @@ -1,12 +0,0 @@ -(defcustom flyspell-delayed-commands nil -  "List of commands that are \"delayed\" for Flyspell mode. -After these commands, Flyspell checking is delayed for a short time, -whose length is specified by `flyspell-delay'." -  :group 'flyspell -  :type '(repeat (symbol))) - -(setq ispell-dictionary "en") -(setq flyspell-default-dictionary "en") - -(setq flyspell-issue-welcome-flag nil) -(setq-default ispell-list-command "list") diff --git a/.emacs.d/rul-init.d/go-lang.el b/.emacs.d/rul-init.d/go-lang.el deleted file mode 100644 index 8ec678b..0000000 --- a/.emacs.d/rul-init.d/go-lang.el +++ /dev/null @@ -1,23 +0,0 @@ -;; Debian packages: elpa-go-mode -;; Elpa packages: go-eldoc - -(use-package go-mode -  :ensure t -  :init -  (progn -    (bind-key [remap find-tag] #'godef-jump)) -  :config -  (add-hook 'go-mode-hook #'yas-minor-mode) -  (add-hook 'go-mode-hook 'electric-pair-mode) -  (add-hook 'go-mode-hook 'my-go-mode-hook) -  (add-hook 'before-save-hook 'gofmt-before-save) -) - -(use-package go-eldoc -  :ensure t -  :init -  (add-hook 'go-mode-hook 'go-eldoc-setup)) - -;; Define function to call when go-mode loads -(defun my-go-mode-hook () -  (set 'compile-command "go build -v && go test -v && go vet")) diff --git a/.emacs.d/rul-init.d/ibuffer.el b/.emacs.d/rul-init.d/ibuffer.el deleted file mode 100644 index d5198d8..0000000 --- a/.emacs.d/rul-init.d/ibuffer.el +++ /dev/null @@ -1,35 +0,0 @@ -;; Debian packages: elpa-ibuffer-vc - -(use-package ibuffer                    ; Better buffer list -  :bind (([remap list-buffers] . ibuffer)) -  ;; Show VC Status in ibuffer -  :config (setq ibuffer-formats -                '((mark modified read-only vc-status-mini " " -                        (name 18 18 :left :elide) -                        " " -                        (size 9 -1 :right) -                        " " -                        (mode 16 16 :left :elide) -                        " " -                        (vc-status 16 16 :left) -                        " " -                        filename-and-process) -                  (mark modified read-only " " -                        (name 18 18 :left :elide) -                        " " -                        (size 9 -1 :right) -                        " " -                        (mode 16 16 :left :elide) -                        " " filename-and-process) -                  (mark " " -                        (name 16 -1) -                        " " filename)))) - -(use-package ibuffer-vc                 ; Group buffers by VC project and status -  :ensure t -  :defer t -  :init (add-hook 'ibuffer-hook -                  (lambda () -                    (ibuffer-vc-set-filter-groups-by-vc-root) -                    (unless (eq ibuffer-sorting-mode 'alphabetic) -                      (ibuffer-do-sort-by-alphabetic))))) diff --git a/.emacs.d/rul-init.d/imenu.el b/.emacs.d/rul-init.d/imenu.el deleted file mode 100644 index 1a2b29b..0000000 --- a/.emacs.d/rul-init.d/imenu.el +++ /dev/null @@ -1,12 +0,0 @@ -;; Debian packages: elpa-imenu-list -(use-package imenu-list -  :ensure t -  :bind ("C-." . imenu-list-minor-mode) -  :config -  (setq imenu-list-focus-after-activation t) -  (setq imenu-list-size 0.2) -  (setq imenu-list-position 'left) -  (add-hook 'go-mode-hook #'imenu-list-minor-mode)) - - - diff --git a/.emacs.d/rul-init.d/latex.el b/.emacs.d/rul-init.d/latex.el deleted file mode 100644 index de4de1f..0000000 --- a/.emacs.d/rul-init.d/latex.el +++ /dev/null @@ -1,9 +0,0 @@ -(add-hook 'latex-mode-hook 'flyspell-mode) -(setq TeX-PDF-mode t) - -(defun pdfevince () -  (add-to-list 'TeX-output-view-style -		'("^pdf$" "." "evince %o %(outpage)"))) - -(add-hook  'LaTeX-mode-hook  'pdfevince  t) ; AUCTeX LaTeX mode - diff --git a/.emacs.d/rul-init.d/logos.el b/.emacs.d/rul-init.d/logos.el deleted file mode 100644 index 0ea1244..0000000 --- a/.emacs.d/rul-init.d/logos.el +++ /dev/null @@ -1,31 +0,0 @@ -(use-package logos -:ensure t -:config - -;; If you want to use outlines instead of page breaks (the ^L) -(setq logos-outlines-are-pages t) -(setq logos-outline-regexp-alist -      `((emacs-lisp-mode . "^;;;+ ") -        (org-mode . "^\\*+ +") -        (markdown-mode . "^\\#+ +") -        )) - -;; These apply when `logos-focus-mode' is enabled.  Their value is -;; buffer-local. -(setq-default logos-hide-mode-line t -              logos-hide-buffer-boundaries t -              logos-hide-fringe t -              logos-variable-pitch nil -              logos-buffer-read-only nil -              logos-scroll-lock nil -              logos-olivetti t -              olivetti-body-width 100 -              ) - - -(let ((map global-map)) -  (define-key map [remap narrow-to-region] #'logos-narrow-dwim) -  (define-key map [remap forward-page] #'logos-forward-page-dwim) -  (define-key map [remap backward-page] #'logos-backward-page-dwim) -  (define-key map (kbd "<f9>") #'logos-focus-mode)) -) diff --git a/.emacs.d/rul-init.d/mail-mode.el b/.emacs.d/rul-init.d/mail-mode.el deleted file mode 100644 index 09b04f9..0000000 --- a/.emacs.d/rul-init.d/mail-mode.el +++ /dev/null @@ -1,15 +0,0 @@ -(setq auto-mode-alist (append '((".*tmp/mutt.*" . message-mode)) auto-mode-alist)) -(setq auto-mode-alist (append '((".*tmp/neomutt.*" . message-mode)) auto-mode-alist)) -(add-to-list 'auto-mode-alist '("/mutt" . mail-mode)) - -(setq mml-secure-openpgp-sign-with-sender t) - -(add-hook 'mail-mode-hook -          (lambda () -            (font-lock-add-keywords nil -                                    '(("^[ \t]*>[ \t]*>[ \t]*>.*$" -                                       (0 'compilation-error)) -                                      ("^[ \t]*>[ \t]*>.*$" -                                       (0 'compilation-column-number)) -                                      ("^[ \t]*>.*$" -                                       (0 'comint-highlight-prompt)))))) diff --git a/.emacs.d/rul-init.d/markdown.el b/.emacs.d/rul-init.d/markdown.el deleted file mode 100644 index f035509..0000000 --- a/.emacs.d/rul-init.d/markdown.el +++ /dev/null @@ -1,5 +0,0 @@ -(autoload 'markdown-mode "markdown-mode.el" -  "Major mode for editing Markdown files" t) - -(setq auto-mode-alist -      (cons '("\\.mdwn" . markdown-mode) auto-mode-alist)) diff --git a/.emacs.d/rul-init.d/notmuch.el b/.emacs.d/rul-init.d/notmuch.el deleted file mode 100644 index e8e4d9d..0000000 --- a/.emacs.d/rul-init.d/notmuch.el +++ /dev/null @@ -1,136 +0,0 @@ -;; -------- -;; notmuch mode -;; -------- -(require 'rul-config-mail) -(use-package notmuch -:ensure t -:config -;;;; General UI -(setq notmuch-show-logo nil -      notmuch-column-control 1.0 -      notmuch-hello-auto-refresh t -      notmuch-hello-recent-searches-max 20 -      notmuch-hello-thousands-separator "" -      notmuch-show-all-tags-list t) - -;; Keymaps -(defun rul/capture-mail() -  "Capture mail to org mode." -  (interactive) -  (org-store-link nil) -  (org-capture nil "m") -  ) - -(bind-key "c" 'rul/capture-mail notmuch-show-mode-map) - -(define-key notmuch-show-mode-map "R" 'notmuch-show-reply) -(define-key notmuch-search-mode-map "R" 'notmuch-search-reply-to-thread) - -; Spam -(define-key notmuch-show-mode-map "S" -  (lambda () -    "mark message as spam" -    (interactive) -    (notmuch-show-tag (list "+spam" "-inbox" "-unread")))) - -(define-key notmuch-search-mode-map "S" -  (lambda (&optional beg end) -    "mark thread as spam" -    (interactive (notmuch-search-interactive-region)) -    (notmuch-search-tag (list "+spam" "-inbox" "-unread") beg end))) - -; Archive -(setq notmuch-archive-tags (list "-inbox" "+archive")) -(define-key notmuch-show-mode-map "A" -  (lambda () -    "archive" -    (interactive) -    (notmuch-show-tag (list "+archive" "-inbox" "-unread")) -    (notmuch-refresh-this-buffer))) - -(define-key notmuch-search-mode-map "A" -  (lambda (&optional beg end) -    "archive thread" -    (interactive (notmuch-search-interactive-region)) -    (notmuch-search-tag (list "+archive" "-inbox" "-unread") beg end) -    (notmuch-refresh-this-buffer))) - -; Mark as read -(define-key notmuch-search-mode-map "r" -  (lambda (&optional beg end) -    "mark thread as read" -    (interactive (notmuch-search-interactive-region)) -    (notmuch-search-tag (list "-unread") beg end) -    (notmuch-search-next-thread))) - -(define-key notmuch-search-mode-map (kbd "RET") -  (lambda () -    "Show the selected thread with notmuch-tree if it has more -than one email. Use notmuch-show otherwise." -    (interactive) -    (if (= (plist-get (notmuch-search-get-result) :total) 1) -        (notmuch-search-show-thread) -      (notmuch-tree (notmuch-search-find-thread-id) -                    notmuch-search-query-string -                    nil -                    (notmuch-prettify-subject (notmuch-search-find-subject)))))) - -(defun color-inbox-if-unread () (interactive) -       (save-excursion -         (goto-char (point-min)) -         (let ((cnt (car (process-lines "notmuch" "count" "tag:inbox and tag:unread")))) -           (when (> (string-to-number cnt) 0) -             (save-excursion -               (when (search-forward "inbox" (point-max) t) -                 (let* ((overlays (overlays-in (match-beginning 0) (match-end 0))) -                        (overlay (car overlays))) -                   (when overlay -                     (overlay-put overlay 'face '((:inherit bold) (:foreground "green"))))))))))) - -(defvar notmuch-hello-refresh-count 0) -(defun notmuch-hello-refresh-status-message () -  (let* ((new-count -          (string-to-number -           (car (process-lines notmuch-command "count")))) -         (diff-count (- new-count notmuch-hello-refresh-count))) -    (cond -     ((= notmuch-hello-refresh-count 0) -      (message "You have %s messages." -               (notmuch-hello-nice-number new-count))) -     ((> diff-count 0) -      (message "You have %s more messages since last refresh." -               (notmuch-hello-nice-number diff-count))) -     ((< diff-count 0) -      (message "You have %s fewer messages since last refresh." -               (notmuch-hello-nice-number (- diff-count))))) -    (setq notmuch-hello-refresh-count new-count))) - -(add-hook 'notmuch-hello-refresh-hook 'color-inbox-if-unread) -(add-hook 'notmuch-hello-refresh-hook 'notmuch-hello-refresh-status-message) - -(setq notmuch-hello-sections '(notmuch-hello-insert-saved-searches -                               notmuch-hello-insert-search -                               notmuch-hello-insert-recent-searches -                               notmuch-hello-insert-alltags -                               )) - -;; https://git.sr.ht/~tslil/dotfiles/tree/4e51afbb/emacs/notmuch-config.el#L76-82 -(defmacro make-binds (mode-map binds argfunc &rest body) -  "Create keybindings in `mode-map' using a list of (keystr . arg) -pairs in `binds' of the form ( ... (argfunc arg) body)." -  `(progn ,@(mapcar (lambda (pair) -                      `(define-key ,mode-map (kbd ,(car pair)) -                         (lambda () (interactive) (,argfunc ,(cdr pair)) ,@body))) -                    (eval binds)))) - -(defvar notmuch-hello-tree-searches '(("u" . "tag:unread") -                                      ("i" . "tag:inbox") -                                      ("*" . "*")) -  "List of (key . query) pairs to bind in notmuch-hello.") - -(make-binds notmuch-hello-mode-map -            notmuch-hello-tree-searches -            notmuch-search) -) - -(use-package notmuch-indicator :ensure t) diff --git a/.emacs.d/rul-init.d/python.el b/.emacs.d/rul-init.d/python.el deleted file mode 100644 index 3186c72..0000000 --- a/.emacs.d/rul-init.d/python.el +++ /dev/null @@ -1 +0,0 @@ -(add-hook 'python-mode-hook 'py-autopep8-enable-on-save) diff --git a/.emacs.d/rul-init.d/which-key.el b/.emacs.d/rul-init.d/which-key.el deleted file mode 100644 index 1d8fd8d..0000000 --- a/.emacs.d/rul-init.d/which-key.el +++ /dev/null @@ -1,5 +0,0 @@ -(use-package which-key -  :ensure t -  :config -  (which-key-mode) -) diff --git a/.emacs.d/rul-lisp/config/rul-config-elfeed.el b/.emacs.d/rul-lisp/config/rul-config-elfeed.el deleted file mode 100644 index 026c325..0000000 --- a/.emacs.d/rul-lisp/config/rul-config-elfeed.el +++ /dev/null @@ -1,2 +0,0 @@ -(setq elfeed-feeds '("https://planet.debian.org/rss10.xml")) -(provide 'rul-config-elfeed) diff --git a/.emacs.d/rul-lisp/config/rul-config-mail.el b/.emacs.d/rul-lisp/config/rul-config-mail.el deleted file mode 100644 index 240f8be..0000000 --- a/.emacs.d/rul-lisp/config/rul-config-mail.el +++ /dev/null @@ -1 +0,0 @@ -(provide 'rul-config-mail) diff --git a/.emacs.d/rul-lisp/config/rul-config-org.el b/.emacs.d/rul-lisp/config/rul-config-org.el deleted file mode 100644 index bf538dc..0000000 --- a/.emacs.d/rul-lisp/config/rul-config-org.el +++ /dev/null @@ -1,22 +0,0 @@ -(setq - org-agenda-files '("~/org/") - org-agenda-custom-commands - '(("x" agenda) -   ("y" agenda*) -   ("w" todo "WAITING") -   ("W" todo-tree "WAITING") -   ) - org-journal-file-type 'yearly - org-journal-dir "~/org/journal/" - org-journal-file-format "%Y.org" - org-journal-time-prefix "* " - org-journal-time-format "" - org-refile-path "~/refile.org" - org-roam-directory "~/org/roam/" - - org-agenda-private-local-path "/tmp/example.ics" - org-agenda-private-remote-path "/sshx:user@host:example.ics" - ) - -(provide 'rul-config-org) - diff --git a/.emacs.d/rul-init.d/hydra.el b/.emacs.d/rul-lisp/packages/rul-bindings.el index 525162e..96d14b0 100644 --- a/.emacs.d/rul-init.d/hydra.el +++ b/.emacs.d/rul-lisp/packages/rul-bindings.el @@ -1,3 +1,14 @@ +;; Global keybindings +(global-set-key (kbd "C-c R") 'revert-buffer) +(global-set-key (kbd "C-c w") 'whitespace-cleanup) + +(defun help/insert-em-dash () +  "Inserts an EM-DASH (not a HYPEN, not an N-DASH)" +  (interactive) +  (insert "—")) + +(global-set-key (kbd "C--") #'help/insert-em-dash) +  (use-package hydra    :ensure t    :defer 1) @@ -43,6 +54,11 @@    )  (global-set-key (kbd "C-c t") 'hydra-vterm/body) +(global-set-key (kbd "C-c m") 'hydra-go/body) +(use-package which-key +  :ensure t +  :config +  (which-key-mode)) -(global-set-key (kbd "C-c m") 'hydra-go/body) +(provide 'rul-bindings) diff --git a/.emacs.d/rul-lisp/packages/rul-completion.el b/.emacs.d/rul-lisp/packages/rul-completion.el index 2b3afa1..3412354 100644 --- a/.emacs.d/rul-lisp/packages/rul-completion.el +++ b/.emacs.d/rul-lisp/packages/rul-completion.el @@ -1,5 +1,14 @@  (use-package orderless :ensure t) +(setq completion-styles '(basic substring initials orderless)) +(setq completion-category-overrides +      '( +        (file (styles . (basic partial-completion orderless))) +        (project-file (styles . (flex basic substring partial-completion orderless))) +        )) + +(setq completion-ignore-case t) +  ;; Enable vertico  (use-package vertico    :ensure t @@ -7,50 +16,18 @@    (vertico-mode)    :config -  (add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy) - -  ;; Different scroll margin -  ;; (setq vertico-scroll-margin 0) - -  ;; Show more candidates -  ;; (setq vertico-count 20) - -  ;; Grow and shrink the Vertico minibuffer -  ;; (setq vertico-resize t) - -  ;; Optionally enable cycling for `vertico-next' and `vertico-previous'. -  ;; (setq vertico-cycle t) -  ) +  (add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy))  ;; Enable rich annotations using the Marginalia package  (use-package marginalia    :ensure t -  ;; Bind `marginalia-cycle' locally in the minibuffer.  To make the binding -  ;; available in the *Completions* buffer, add it to the -  ;; `completion-list-mode-map'.    :bind (:map minibuffer-local-map           ("M-A" . marginalia-cycle)) - -  ;; The :init section is always executed.    :init - -  ;; Marginalia must be actived in the :init section of use-package such that -  ;; the mode gets enabled right away. Note that this forces loading the -  ;; package.    (marginalia-mode)) -(setq completion-styles '(basic substring initials orderless)) -(setq completion-category-overrides -      '( -        (file (styles . (basic partial-completion orderless))) -        (project-file (styles . (flex basic substring partial-completion orderless))) -        )) - -(setq completion-ignore-case t) -  (use-package consult    :ensure t -  ;; Replace bindings. Lazily loaded due by `use-package'.    :bind (;; C-c bindings in `mode-specific-map'           ("C-c M-x" . consult-mode-command)           ("C-c h" . consult-history) @@ -126,7 +103,7 @@    :bind    (("C-." . embark-act)         ;; pick some comfortable binding -   ("C-;" . embark-dwim)        ;; good alternative: M-. +   ("M-." . embark-dwim)        ;; good alternative: M-.     ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'    :init @@ -139,9 +116,8 @@                   nil                   (window-parameters (mode-line-format . none))))) -;; Consult users will also want the embark-consult package.  (use-package embark-consult -  :ensure t ; only need to install it, embark loads it after consult if found +  :ensure t    :hook    (embark-collect-mode . consult-preview-at-point-mode)) diff --git a/.emacs.d/rul-lisp/packages/rul-dashboard.el b/.emacs.d/rul-lisp/packages/rul-dashboard.el new file mode 100644 index 0000000..67bd188 --- /dev/null +++ b/.emacs.d/rul-lisp/packages/rul-dashboard.el @@ -0,0 +1,22 @@ +(use-package page-break-lines :ensure t) + +(use-package dashboard +  :ensure t + +  :config +  (dashboard-setup-startup-hook) + +  :custom +  (dashboard-center-content t) +  (dashboard-startup-banner 3) +  (dashboard-items '((recents   . 5) +                     (bookmarks . 5) +                     (projects  . 5) +                     (agenda    . 5) +                     )) +  (dashboard-icon-type 'nerd-icons) +  (dashboard-set-heading-icons t) +  (dashboard-set-file-icons t) +) + +(provide 'rul-dashboard) diff --git a/.emacs.d/rul-lisp/packages/rul-elfeed.el b/.emacs.d/rul-lisp/packages/rul-elfeed.el deleted file mode 100644 index 22aacdd..0000000 --- a/.emacs.d/rul-lisp/packages/rul-elfeed.el +++ /dev/null @@ -1,6 +0,0 @@ -(use-package elfeed -:ensure t -:config -(require 'rul-config-elfeed)) - -(provide 'rul-elfeed) diff --git a/.emacs.d/rul-lisp/packages/rul-fm.el b/.emacs.d/rul-lisp/packages/rul-fm.el new file mode 100644 index 0000000..83aaf37 --- /dev/null +++ b/.emacs.d/rul-lisp/packages/rul-fm.el @@ -0,0 +1,19 @@ +;;; rul-fm.el --- File management + +;; dired +(add-hook 'dired-mode-hook #'dired-hide-details-mode) +(setq dired-guess-shell-alist-user +      '(("\\.\\(png\\|jpe?g\\|tiff\\)" "feh" "xdg-open") +        ("\\.\\(mp[34]\\|m4a\\|ogg\\|flac\\|webm\\|mkv\\)" "mpv" "xdg-open") +        (".*" "xdg-open"))) + +(setq dired-kill-when-opening-new-dired-buffer t) +(put 'dired-find-alternate-file 'disabled nil) + +;;; Icons +(use-package nerd-icons :ensure t ) +(use-package nerd-icons-dired :ensure t +  :config +  (add-hook 'dired-mode-hook #'nerd-icons-dired-mode)) + +(provide 'rul-fm) diff --git a/.emacs.d/rul-init.d/fonts.el b/.emacs.d/rul-lisp/packages/rul-fonts.el index a7cb255..34cc54a 100644 --- a/.emacs.d/rul-init.d/fonts.el +++ b/.emacs.d/rul-lisp/packages/rul-fonts.el @@ -1,3 +1,5 @@ +;;; rul-fonts.el --- Fonts configuration +  (use-package fontaine    :ensure t    :config @@ -7,7 +9,7 @@          (small           :default-height 120)          (medium -         :default-height 140) +         :default-height 150)          (large           :default-weight semilight           :default-height 180 @@ -20,6 +22,11 @@           :default-weight semilight           :default-height 230           :bold-weight extrabold) +        (writing +         :default-height 140 +         :default-family "Lato" +         :variable-pitch-family "Regular" +         )          (t           :default-family "Iosevka"           :default-weight regular @@ -28,3 +35,5 @@    ;; Set desired style from `fontaine-presets'    (fontaine-set-preset 'medium)) + +(provide 'rul-fonts) diff --git a/.emacs.d/rul-lisp/packages/rul-media.el b/.emacs.d/rul-lisp/packages/rul-io.el index b2f8db1..eb2c1c7 100644 --- a/.emacs.d/rul-lisp/packages/rul-media.el +++ b/.emacs.d/rul-lisp/packages/rul-io.el @@ -1,3 +1,8 @@ +;;; rul-io.el --- Configuration for Internet and media packages + +(use-package elfeed :ensure t) +(provide 'rul-feeds) +  (use-package empv  :ensure t  :config @@ -9,7 +14,6 @@         ("SomaFM - Metal" . "https://somafm.com/metal.pls")         ("SomaFM - Lush" . "https://somafm.com/lush130.pls")         ("KCSM Jazz 91" . "http://ice5.securenetsystems.net/KCSM") -       )) -  ) +       ))) -(provide 'rul-media) +(provide 'rul-io) diff --git a/.emacs.d/rul-lisp/packages/rul-mail.el b/.emacs.d/rul-lisp/packages/rul-mail.el new file mode 100644 index 0000000..6206118 --- /dev/null +++ b/.emacs.d/rul-lisp/packages/rul-mail.el @@ -0,0 +1,144 @@ +;;; rul-mail.el --- Email configuration + +;; mml-sec.el +;; Use sender to find GPG key. +(setq mml-secure-openpgp-sign-with-sender t) + +(use-package notmuch +  :ensure t +  :config +  ;; UI +  (setq notmuch-show-logo nil +        notmuch-column-control 1.0 +        notmuch-hello-auto-refresh t +        notmuch-hello-recent-searches-max 20 +        notmuch-hello-thousands-separator "" +        notmuch-show-all-tags-list t +        notmuch-show-text/html-blocked-images nil +        ) + +  (setq notmuch-draft-folder "current/Drafts") + +  ;; Keymaps +  (defun rul/capture-mail() +    "Capture mail to org mode." +    (interactive) +    (org-store-link nil) +    (org-capture nil "m") +    ) + +  (bind-key "c" 'rul/capture-mail notmuch-show-mode-map) + +  (define-key notmuch-show-mode-map "R" 'notmuch-show-reply) +  (define-key notmuch-search-mode-map "R" 'notmuch-search-reply-to-thread) + +  ;; Spam +  (define-key notmuch-show-mode-map "S" +              (lambda () +                "mark message as spam" +                (interactive) +                (notmuch-show-tag (list "+spam" "-inbox" "-unread")))) + +  (define-key notmuch-search-mode-map "S" +              (lambda (&optional beg end) +                "mark thread as spam" +                (interactive (notmuch-search-interactive-region)) +                (notmuch-search-tag (list "+spam" "-inbox" "-unread") beg end))) + +  ;; Archive +  (setq notmuch-archive-tags (list "-inbox" "+archive")) +  (define-key notmuch-show-mode-map "A" +              (lambda () +                "archive" +                (interactive) +                (notmuch-show-tag (list "+archive" "-inbox" "-unread")) +                (notmuch-refresh-this-buffer))) + +  (define-key notmuch-search-mode-map "A" +              (lambda (&optional beg end) +                "archive thread" +                (interactive (notmuch-search-interactive-region)) +                (notmuch-search-tag (list "+archive" "-inbox" "-unread") beg end) +                (notmuch-refresh-this-buffer))) + +  ;; Mark as read +  (define-key notmuch-search-mode-map "r" +              (lambda (&optional beg end) +                "mark thread as read" +                (interactive (notmuch-search-interactive-region)) +                (notmuch-search-tag (list "-unread") beg end) +                (notmuch-search-next-thread))) + +  (define-key notmuch-search-mode-map (kbd "RET") +              (lambda () +                "Show the selected thread with notmuch-tree if it has more +than one email. Use notmuch-show otherwise." +                (interactive) +                (if (= (plist-get (notmuch-search-get-result) :total) 1) +                    (notmuch-search-show-thread) +                  (notmuch-tree (notmuch-search-find-thread-id) +                                notmuch-search-query-string +                                nil +                                (notmuch-prettify-subject (notmuch-search-find-subject)))))) + +  (defun color-inbox-if-unread () (interactive) +         (save-excursion +           (goto-char (point-min)) +           (let ((cnt (car (process-lines "notmuch" "count" "tag:inbox and tag:unread")))) +             (when (> (string-to-number cnt) 0) +               (save-excursion +                 (when (search-forward "inbox" (point-max) t) +                   (let* ((overlays (overlays-in (match-beginning 0) (match-end 0))) +                          (overlay (car overlays))) +                     (when overlay +                       (overlay-put overlay 'face '((:inherit bold) (:foreground "green"))))))))))) + +  (defvar notmuch-hello-refresh-count 0) +  (defun notmuch-hello-refresh-status-message () +    (let* ((new-count +            (string-to-number +             (car (process-lines notmuch-command "count")))) +           (diff-count (- new-count notmuch-hello-refresh-count))) +      (cond +       ((= notmuch-hello-refresh-count 0) +        (message "You have %s messages." +                 (notmuch-hello-nice-number new-count))) +       ((> diff-count 0) +        (message "You have %s more messages since last refresh." +                 (notmuch-hello-nice-number diff-count))) +       ((< diff-count 0) +        (message "You have %s fewer messages since last refresh." +                 (notmuch-hello-nice-number (- diff-count))))) +      (setq notmuch-hello-refresh-count new-count))) + +  (add-hook 'notmuch-hello-refresh-hook 'color-inbox-if-unread) +  (add-hook 'notmuch-hello-refresh-hook 'notmuch-hello-refresh-status-message) + +  (setq notmuch-hello-sections '(notmuch-hello-insert-saved-searches +                                 notmuch-hello-insert-search +                                 notmuch-hello-insert-recent-searches +                                 notmuch-hello-insert-alltags +                                 )) + +  ;; https://git.sr.ht/~tslil/dotfiles/tree/4e51afbb/emacs/notmuch-config.el#L76-82 +  (defmacro make-binds (mode-map binds argfunc &rest body) +    "Create keybindings in `mode-map' using a list of (keystr . arg) +pairs in `binds' of the form ( ... (argfunc arg) body)." +    `(progn ,@(mapcar (lambda (pair) +                        `(define-key ,mode-map (kbd ,(car pair)) +                                     (lambda () (interactive) (,argfunc ,(cdr pair)) ,@body))) +                      (eval binds)))) + +  (defvar notmuch-hello-tree-searches '(("u" . "tag:unread") +                                        ("i" . "tag:inbox") +                                        ("*" . "*")) +    "List of (key . query) pairs to bind in notmuch-hello.") + +  (make-binds notmuch-hello-mode-map +              notmuch-hello-tree-searches +              notmuch-search) +) ;; ends use-package notmuch + +(use-package notmuch-indicator :ensure t) + +(provide 'rul-mail) diff --git a/.emacs.d/rul-lisp/packages/rul-modeline.el b/.emacs.d/rul-lisp/packages/rul-modeline.el index ae250c4..32c6048 100644 --- a/.emacs.d/rul-lisp/packages/rul-modeline.el +++ b/.emacs.d/rul-lisp/packages/rul-modeline.el @@ -1,3 +1,5 @@ +;;; rul-modeline.el --- Modeline configuration +  ;; Most of the code in this file is based on:  ;;   https://git.sr.ht/~protesilaos/dotfiles/tree/cf26bc34/item/emacs/.emacs.d/prot-lisp/prot-modeline.el  ;; @@ -103,10 +105,14 @@ Specific to the current window's mode line.")                  mode-line-front-space                  mode-line-buffer-identification                  mode-line-front-space +                mode-line-percent-position +                mode-line-front-space                  rul-modeline-major-mode                  prot-modeline-eglot                  mode-line-format-right-align                  rul-modeline-misc-info +                mode-line-front-space +                mode-line-front-space                  ))  (provide 'rul-modeline) diff --git a/.emacs.d/rul-lisp/packages/rul-org-agenda.el b/.emacs.d/rul-lisp/packages/rul-org-agenda.el index bfdc8d3..ddfbd7e 100644 --- a/.emacs.d/rul-lisp/packages/rul-org-agenda.el +++ b/.emacs.d/rul-lisp/packages/rul-org-agenda.el @@ -1,3 +1,4 @@ +;;; rul-org-agenda.el --- Org agenda configuration  (require 'org)  (global-set-key (kbd "<f12>") #'org-agenda) @@ -365,7 +366,7 @@ as the default task."            (when bh/keep-clock-running              (bh/clock-in-default-task))))))) -(defvar bh/organization-task-id "eb155a82-92b2-4f25-a3c6-0304591af2f9") +(defvar bh/organization-task-id "redefine") ;; org-id-get-create  ;; https://stackoverflow.com/a/10091330  (defun zin/org-agenda-skip-tag (tag &optional others) @@ -398,6 +399,34 @@ If OTHERS is true, skip all entries that do not correspond to TAG."  (add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append) +;;; Focusing on current work + +(global-set-key (kbd "<f5>") 'bh/org-todo) +(defun bh/org-todo (arg) +  (interactive "p") +  (if (equal arg 4) +      (save-restriction +        (bh/narrow-to-org-subtree) +        (org-show-todo-tree nil)) +    (bh/narrow-to-org-subtree) +    (org-show-todo-tree nil))) + +(global-set-key (kbd "<S-f5>") 'bh/widen) +(defun bh/widen () +  (interactive) +  (if (equal major-mode 'org-agenda-mode) +      (progn +        (org-agenda-remove-restriction-lock) +        (when org-agenda-sticky +          (org-agenda-redo))) +    (widen))) + +(defun bh/narrow-to-org-subtree () +  (widen) +  (org-narrow-to-subtree) +  (save-restriction +    (org-agenda-set-restriction-lock))) +  ;; AGENDA VIEW ;;  ;; Do not dim blocked tasks diff --git a/.emacs.d/rul-lisp/packages/rul-org-journal.el b/.emacs.d/rul-lisp/packages/rul-org-journal.el deleted file mode 100644 index 46fcebf..0000000 --- a/.emacs.d/rul-lisp/packages/rul-org-journal.el +++ /dev/null @@ -1,19 +0,0 @@ -(use-package org-journal -  :ensure t -  :init -  ;; Change default prefix key; needs to be set before loading org-journal -  (setq org-journal-prefix-key "C-c j ") -  :config -  (require 'rul-config-org) -  (setq org-journal-date-format "%A, %d %B %Y") - -  (global-set-key (kbd "C-c j o") 'org-journal-open-current-journal-file) -  (global-set-key (kbd "C-c j j") 'org-journal-new-entry) -  (global-set-key (kbd "C-c j J") 'org-journal-new-scheduled-entry) - -  (define-key org-journal-mode-map (kbd "C-c j n") 'org-journal-next-entry) -  (define-key org-journal-mode-map (kbd "C-c j p") 'org-journal-previous-entry) -  (define-key org-journal-mode-map (kbd "C-c j r") 'org-journal-reschedule-scheduled-entry) -  ) - -(provide 'rul-org-journal) diff --git a/.emacs.d/rul-lisp/packages/rul-org-notify.el b/.emacs.d/rul-lisp/packages/rul-org-notify.el deleted file mode 100644 index 50c35a0..0000000 --- a/.emacs.d/rul-lisp/packages/rul-org-notify.el +++ /dev/null @@ -1,9 +0,0 @@ -(use-package org-notify -  :ensure t -  :config -  (org-notify-start) -  (org-notify-add 'default -                  '(:time "-1s" :period "20s" :duration 10 -                          :actions (-message -ding)) -                  '(:time "1d" :actions -notify/window -                          :duration 60))) diff --git a/.emacs.d/rul-lisp/packages/rul-org.el b/.emacs.d/rul-lisp/packages/rul-org.el index ed95a3a..7b2670b 100644 --- a/.emacs.d/rul-lisp/packages/rul-org.el +++ b/.emacs.d/rul-lisp/packages/rul-org.el @@ -1,14 +1,10 @@ -;; Debian packages: elpa-org -;; Elpa packages: org-modern +;;; rul-org.el --- Org configuration  (require 'org)  (require 'org-capture)  (require 'org-protocol)  (require 'org-habit) -(require 'rul-config-org) -  (require 'rul-org-agenda) -(require 'rul-org-journal)  (setq org-attach-use-inheritance t)  (setq org-cycle-separator-lines 0) @@ -17,10 +13,24 @@  (setq org-edit-src-content-indentation 0)  (use-package org-modern :ensure t) -(use-package org-pomodoro :ensure t) +(use-package org-pomodoro +  :ensure t +  :config +  (defun rul/disable-notifications () +    "Disable GNOME notifications." +    (shell-command "gsettings set org.gnome.desktop.notifications show-banners false")) + +  (defun rul/enable-notifications () +    "Enable GNOME notifications." +    (shell-command "gsettings set org.gnome.desktop.notifications show-banners true")) -(add-hook 'org-mode-hook 'turn-off-auto-fill) -(add-hook 'auto-save-hook 'org-save-all-org-buffers) +  ;; Add hooks for Pomodoro start and finish +  (add-hook 'org-pomodoro-started-hook #'rul/disable-notifications) +  (add-hook 'org-pomodoro-finished-hook #'rul/enable-notifications) +  (add-hook 'org-pomodoro-killed-hook #'rul/enable-notifications)) + +;; (add-hook 'org-mode-hook 'turn-off-auto-fill) +;; (add-hook 'auto-save-hook 'org-save-all-org-buffers)  (add-hook 'org-mode-hook 'visual-line-mode)  (use-package org-download @@ -41,6 +51,10 @@  (global-set-key (kbd "C-c c") #'org-capture)  (global-set-key (kbd "C-c s") #'org-schedule) +(global-set-key (kbd "<f9>") 'bh/punch-in) +(global-set-key (kbd "<f10>") 'bh/punch-out) +(global-set-key (kbd "<f12>") 'org-agenda) +  ;; ORG STATES ;;  (setq org-todo-keywords        (quote ((sequence "TODO(t)" "MAYBE(m)" "NEXT(n)" "|" "DONE(d)") @@ -61,9 +75,9 @@  (setq org-log-done (quote time))  (setq org-log-redeadline (quote time))  (setq org-log-reschedule (quote time)) +(setq org-log-into-drawer t)  ;; CAPTURE ;; -(setq org-default-notes-file org-refile-path)  (setq org-capture-templates        (quote         ( @@ -86,13 +100,12 @@          ("L" "Web Link" entry           (file+headline org-refile-path "Read later") -         "* %?[[%:link][%:description]] \"\")\n %:initial\n \nCaptured On: %U" +         "* %?[[%:link][%:description]]\n %:initial\n \nCaptured On: %U"           )          ("l" "Web Link with Selection" entry           (file+headline org-refile-path "Read later") -         "* [[%:link][%:description]] \n %:initial\n \nCaptured On: %U") - +         "* [[%:link][%:description]]\n %:initial\n \nCaptured On: %U")          )))  ;; REFILE ;; @@ -158,4 +171,14 @@  ;; Honor ATTR_ORG attribute. Defaults to image's width if not set.  (setq org-image-actual-width nil) +(use-package org-clock-agenda-daytime-mode +    :ensure t +    :config +    (setq +     org-clock-agenda-daytime-target-work-time-minutes 300 +     org-clock-agenda-daytime-maximum-work-time-minutes 480 +     ) +    (org-clock-agenda-daytime-mode) +    ) +  (provide 'rul-org) diff --git a/.emacs.d/rul-lisp/packages/rul-prog.el b/.emacs.d/rul-lisp/packages/rul-prog.el index e7753a2..316736b 100644 --- a/.emacs.d/rul-lisp/packages/rul-prog.el +++ b/.emacs.d/rul-lisp/packages/rul-prog.el @@ -1,14 +1,50 @@ +;;; rul-prog.el --- Configuration related to programming and markup +;;; languages  (use-package eglot :ensure t) -;; Dart -(setq dart-server-format-on-save t) -(add-hook 'dart-mode-hook 'lsp) +;; Go +(use-package go-mode +  :ensure t +  :init +  (progn +    (bind-key [remap find-tag] #'godef-jump)) +  :config +  (add-hook 'go-mode-hook #'yas-minor-mode) +  (add-hook 'go-mode-hook 'electric-pair-mode) +  (add-hook 'go-mode-hook 'my-go-mode-hook) +  (add-hook 'before-save-hook 'gofmt-before-save)) + +(use-package go-eldoc +  :ensure t +  :init +  (add-hook 'go-mode-hook 'go-eldoc-setup)) -(setq gc-cons-threshold (* 100 1024 1024) -      read-process-output-max (* 1024 1024)) +;; Latex +(add-hook 'latex-mode-hook 'flyspell-mode) +(setq TeX-PDF-mode t) + +(defun pdfevince () +  (add-to-list 'TeX-output-view-style +		'("^pdf$" "." "evince %o %(outpage)"))) + +(add-hook  'LaTeX-mode-hook  'pdfevince  t) ; AUCTeX LaTeX mode + +;; Markdown +(use-package markdown-mode +  :ensure t +  :config +  (setq auto-mode-alist +        (cons '("\\.mdwn" . markdown-mode) auto-mode-alist)))  ;; Python  (use-package blacken :ensure t :defer t) +(with-eval-after-load 'lsp-mode +  (lsp-register-client +   (make-lsp-client +    :new-connection (lsp-stdio-connection '("ruff" "server")) +    :activation-fn (lsp-activate-on "python") +    :server-id 'ruff-lsp))) +(add-hook 'python-mode-hook #'lsp)  ;; Terraform  (use-package terraform-mode :ensure t :defer t) @@ -22,7 +58,6 @@    :init    (setq rust-mode-treesitter-derive t)    :config -  (add-hook 'rust-mode-hook 'eglot-ensure) -  ) +  (add-hook 'rust-mode-hook 'eglot-ensure))  (provide 'rul-prog) diff --git a/.emacs.d/rul-init.d/vterm.el b/.emacs.d/rul-lisp/packages/rul-terminals.el index 5116bf0..9678b55 100644 --- a/.emacs.d/rul-init.d/vterm.el +++ b/.emacs.d/rul-lisp/packages/rul-terminals.el @@ -1,5 +1,9 @@  (use-package multi-vterm    :ensure t +  :init +  (setq vterm-always-compile-module t)    :config    (setq vterm-max-scrollback 100000)    (add-hook 'vterm-mode-hook 'goto-address-mode)) + +(provide 'rul-terminals) diff --git a/.emacs.d/rul-init.d/themes.el b/.emacs.d/rul-lisp/packages/rul-themes.el index 468cd28..2c696ec 100644 --- a/.emacs.d/rul-init.d/themes.el +++ b/.emacs.d/rul-lisp/packages/rul-themes.el @@ -1,17 +1,17 @@ -(use-package modus-themes :ensure t)  (use-package ef-themes :ensure t) - -(setq - modus-themes-mode-line '(accented borderless padded) - modus-themes-region '(bg-only) - modus-themes-bold-constructs t - modus-themes-italic-constructs t - modus-themes-paren-match '(bold intense) - modus-themes-headings (quote ((1 . (rainbow variable-pitch 1.3)) -                               (2 . (rainbow 1.1)) -                               (t . (rainbow)))) - modus-themes-org-blocks 'tinted - ) +(use-package modus-themes +  :ensure t +  :config +  (setq +   modus-themes-mode-line '(accented borderless padded) +   modus-themes-region '(bg-only) +   modus-themes-bold-constructs t +   modus-themes-italic-constructs t +   modus-themes-paren-match '(bold intense) +   modus-themes-headings (quote ((1 . (rainbow variable-pitch 1.3)) +                                 (2 . (rainbow 1.1)) +                                 (t . (rainbow)))) +   modus-themes-org-blocks 'tinted))  (use-package dbus)  (defun mf/set-theme-from-dbus-value (value) @@ -46,3 +46,6 @@   "org.freedesktop.appearance"   "color-scheme"   ) + + +(provide 'rul-themes) diff --git a/.emacs.d/rul-init.d/magit.el b/.emacs.d/rul-lisp/packages/rul-vc.el index 11370e5..a2ab563 100644 --- a/.emacs.d/rul-init.d/magit.el +++ b/.emacs.d/rul-lisp/packages/rul-vc.el @@ -1,9 +1,8 @@ -;; Debian packages: elpa-magit -  (use-package magit    :ensure t    :bind    (("C-c g s" . magit-status) +   ("C-c g F" . magit-pull-from-upstream)     ("C-c g b" . magit-blame))    :config    (progn @@ -16,3 +15,5 @@        (delete-other-windows))))  (add-to-list 'project-switch-commands '(magit-project-status "Magit" "m")) + +(provide 'rul-vc) diff --git a/.emacs.d/rul-lisp/packages/rul-wm.el b/.emacs.d/rul-lisp/packages/rul-wm.el index 0af3eef..d33bcdb 100644 --- a/.emacs.d/rul-lisp/packages/rul-wm.el +++ b/.emacs.d/rul-lisp/packages/rul-wm.el @@ -6,6 +6,14 @@      (or (derived-mode-p 'org-mode 'org-agenda-mode)           (member (buffer-file-name) (org-agenda-files))))) +;; Side window for dictionary +(setq switch-to-buffer-obey-display-actions t) +(add-to-list 'display-buffer-alist +   '("^\\*Dictionary\\*" display-buffer-in-side-window +     (side . bottom) +     (window-height . 12) +     )) +  ;;;; tab-bar.el  (let ((map global-map))  (define-key map (kbd "C-<next>") 'tab-bar-switch-to-next-tab) @@ -21,7 +29,9 @@  (setq tab-bar-new-tab-to 'rightmost)  (setq tab-bar-close-button-show nil)  (set-face-attribute 'tab-bar nil :height 0.8) -(tab-bar-mode 1) + +;; I've moved to a frame oriented workflow, so I no longer use tabs. +;; (tab-bar-mode 1)  ;; Pop-up buffers  ;; https://protesilaos.com/codelog/2024-09-19-emacs-command-popup-frame-emacsclient/ @@ -61,10 +71,44 @@ Also see `prot-window-delete-popup-frame'." command)    :config    (setq olivetti-body-width 100)) +(use-package logos +:ensure t +:config + +;; If you want to use outlines instead of page breaks (the ^L) +(setq logos-outlines-are-pages t) +(setq logos-outline-regexp-alist +      `((emacs-lisp-mode . "^;;;+ ") +        (org-mode . "^\\*+ +") +        (markdown-mode . "^\\#+ +") +        )) + +;; These apply when `logos-focus-mode' is enabled.  Their value is +;; buffer-local. +(setq-default logos-hide-mode-line t +              logos-hide-buffer-boundaries t +              logos-hide-fringe t +              logos-variable-pitch nil +              logos-buffer-read-only nil +              logos-scroll-lock nil +              logos-olivetti t +              olivetti-body-width 100 +              ) + + +(let ((map global-map)) +  (define-key map [remap narrow-to-region] #'logos-narrow-dwim) +  (define-key map [remap forward-page] #'logos-forward-page-dwim) +  (define-key map [remap backward-page] #'logos-backward-page-dwim) +  (define-key map (kbd "<f7>") #'logos-focus-mode)) +) +  (use-package beframe    :ensure t    :hook (after-init . beframe-mode)    :config +  (setq beframe-functions-in-frames '(project-prompt-project-dir)) +  (setq beframe-global-buffers nil)    (define-key global-map (kbd "C-c b") beframe-prefix-map)    ;;Integration with Consult @@ -93,4 +137,11 @@ With optional argument FRAME, return the list of buffers of FRAME."      (add-to-list 'consult-buffer-sources 'beframe-consult-source))) +(defun kill-project-buffers-and-close-frame () +  (interactive) +  (project-kill-buffers) +  (delete-frame (selected-frame))) + +(define-key global-map (kbd "C-x p K") 'kill-project-buffers-and-close-frame) +  (provide 'rul-wm) diff --git a/.emacs.d/rul-lisp/packages/rul-write.el b/.emacs.d/rul-lisp/packages/rul-write.el index b997ed9..4160d2f 100644 --- a/.emacs.d/rul-lisp/packages/rul-write.el +++ b/.emacs.d/rul-lisp/packages/rul-write.el @@ -1,5 +1,5 @@  ;;;; `dictionary' -(setq dictionary-server "dict.org" +(setq dictionary-server "localhost"        dictionary-default-popup-strategy "lev"        dictionary-create-buttons nil        dictionary-use-single-buffer t) @@ -51,4 +51,60 @@ Else create a new file."         today         '("journal")))))) +;; auto-fill mode +(add-hook 'text-mode-hook 'turn-on-auto-fill) + +(use-package electric +  :init +  (setq electric-quote-replace-double t) +  :hook +  (message-mode . electric-quote-local-mode)) + +(use-package message +  :hook +  (message-mode . my/message-mode-setup)) + +(defun my/message-mode-setup () +  (setq fill-column 72 +        sentence-end-double-space nil) +  (auto-fill-mode 1)) + +;; Flycheck +(use-package flycheck +  :ensure t +  :config + +(flycheck-define-checker proselint +  "A linter for prose." +  :command ("proselint" source-inplace) +  :error-patterns +  ((warning line-start (file-name) ":" line ":" column ": " +	    (id (one-or-more (not (any " ")))) +	    (message) line-end)) +  :modes (text-mode markdown-mode gfm-mode org-mode)) + +(add-to-list 'flycheck-checkers 'proselint) + +;; TODO: docker run --rm -p 8010:8010 erikvl87/languagetool +(use-package flycheck-languagetool +  :ensure t +  :hook (message-mode . flycheck-languagetool-setup) +  :init +  (setq flycheck-languagetool-url "http://localhost:8010") +)) + +;; Flyspell +(defcustom flyspell-delayed-commands nil +  "List of commands that are \"delayed\" for Flyspell mode. +After these commands, Flyspell checking is delayed for a short time, +whose length is specified by `flyspell-delay'." +  :group 'flyspell +  :type '(repeat (symbol))) + +(setq ispell-dictionary "en") +(setq flyspell-default-dictionary "en") + +(setq flyspell-issue-welcome-flag nil) +(setq-default ispell-list-command "list") +  (provide 'rul-write) diff --git a/.inputrc b/.inputrc new file mode 100644 index 0000000..a8e424b --- /dev/null +++ b/.inputrc @@ -0,0 +1,2 @@ +"\M-\C-f": shell-forward-word +"\M-\C-b": shell-backward-word
\ No newline at end of file diff --git a/.xprofile b/.xprofile new file mode 100644 index 0000000..d1606ec --- /dev/null +++ b/.xprofile @@ -0,0 +1 @@ +export PATH="$HOME/bin:$PATH"
\ No newline at end of file @@ -8,3 +8,6 @@ bin_file_name := 10-$(cur_dir)  all:  	$(bin_dir)/pycombine -e '(Makefile|README.md|debian)' "$(HOME)" "$(repo_dir)"  	xdg-settings set default-url-scheme-handler org-protocol org-protocol.desktop + +fonts: +	$(bin_dir)/setup-install-fonts diff --git a/bin/gnome-move-windows b/bin/gnome-move-windows index d6cd934..f4fcd4e 100755 --- a/bin/gnome-move-windows +++ b/bin/gnome-move-windows @@ -10,10 +10,11 @@ done  # Assign windows to predetermined workplaces  misc=$(wmctrl -l |  awk '/isco|eepa/ {print $1}') -main="$(wmctrl -l  | awk '/ main$/ {print $1}')" -communications="$(wmctrl -l |  awk '/Webex|Slack|communications/ {print $1}')" -terminals="$(wmctrl -l  | awk '/Alacritty|terminals$/ {print $1}')" -browsers="$(wmctrl -l  | awk '/Firefox|Chrom/ {print $1}')" +main="$(wmctrl -xl  | awk '/ emacs/ {print $1}')" +communications="$(wmctrl -l |  awk '/ebex|lack|communications|notmuch|Outlook|elfeed/ {print $1}')" +media="$(wmctrl -l |  awk '/YouTube|Spotify/ {print $1}')" +terminals="$(wmctrl -l  | awk '/Alacritty|kitty|terminal/ {print $1}')" +browsers="$(wmctrl -xl  | awk '/irefox|hrom/ {print $1}')"  for window_id in $misc; do      wmctrl -i -r $window_id -t 4 @@ -34,3 +35,7 @@ done  for window_id in $terminals; do      wmctrl -i -r $window_id -t 3  done + +for window_id in $media; do +    wmctrl -i -r $window_id -t 8 +done diff --git a/bin/gnome-set-config b/bin/gnome-set-config index 84c3319..69a2b44 100755 --- a/bin/gnome-set-config +++ b/bin/gnome-set-config @@ -8,6 +8,9 @@ NUM_WORKSPACES=9  gsettings set org.gnome.mutter dynamic-workspaces false  gsettings set org.gnome.desktop.wm.preferences num-workspaces $NUM_WORKSPACES +# Disable the default <Super>p. I don't use it, and it's disruptive when I accidentally trigger it. +gsettings set org.gnome.mutter.keybindings switch-monitor '[]' +  for i in $(seq 1 $NUM_WORKSPACES); do      gsettings set org.gnome.shell.keybindings switch-to-application-$i '[]'      gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-$i "['<Super>$i']" @@ -15,7 +18,7 @@ for i in $(seq 1 $NUM_WORKSPACES); do  done  # This configuration is not present in gsettings; we need to fall back to dconf -bindings="emacs org-mode move-windows" +bindings="emacs org-mode move-windows rofi rofi-run"  keybindings_key="/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings"  keybindings=$(echo $bindings | awk -v key="$keybindings_key" '{for(i=1;i<=NF;i++) printf("'\''" key "/" $i "/'\''%s", (i==NF ? "" : ","))}')  keybindings="[$keybindings]" @@ -33,3 +36,15 @@ dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/org  dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/move-windows/binding "'<Shift><Super>m'"  dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/move-windows/command "'gnome-move-windows'"  dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/move-windows/name "'move-windows'" + +# Disable default for <Super>space. +gsettings set org.gnome.desktop.wm.keybindings switch-input-source "[]" +gsettings set org.gnome.desktop.wm.keybindings switch-input-source-backward '[]' + +dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/rofi/binding "'<Super>space'" +dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/rofi/command "'rofi -show window'" +dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/rofi/name "'rofi'" + +dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/rofi-run/binding "'<Super>f2'" +dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/rofi-run/command "'rofi -show run'" +dconf write /org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/rofi-run/name "'rofi-run'" diff --git a/bin/setup-install-fonts b/bin/setup-install-fonts new file mode 100755 index 0000000..ea96873 --- /dev/null +++ b/bin/setup-install-fonts @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +FONT_DIR="$HOME/.local/share/fonts" +TEMP_DIR=$(mktemp -d) + +mkdir -p "$FONT_DIR" + +pushd $TEMP_DIR +curl -s 'https://api.github.com/repos/be5invis/Iosevka/releases/latest' | \ +  jq -r ".assets[] | .browser_download_url" | \ +  grep PkgTTC-Iosevka | \ +  xargs -n 1 curl -L -O --fail --silent --show-error + +for f in *.zip; do +    unzip "$f" +done + +mv *.ttc "$FONT_DIR/" +fc-cache -f -v "$FONT_DIR" + +popd +rm -rf "$TEMP_DIR" + +echo "Iosevka fonts have been installed." diff --git a/debian/control b/debian/control index 9ff4f63..33513e5 100644 --- a/debian/control +++ b/debian/control @@ -6,8 +6,13 @@ Build-Depends:   fzf,   make,   cmake, + jq, + libtool-bin,   mpv,   python3-proselint, + ripgrep, + rofi, + vim,  Standards-Version: 4.5.1  Rules-Requires-Root: no  | 
