diff options
Diffstat (limited to '')
-rw-r--r-- | .emacs.d/init.el | 407 | ||||
-rw-r--r-- | .emacs.d/lisp/bandali-essentials.el | 402 | ||||
-rw-r--r-- | .emacs.d/lisp/bandali-utils.el | 94 |
3 files changed, 505 insertions, 398 deletions
diff --git a/.emacs.d/init.el b/.emacs.d/init.el index f9518c2..7ab00be 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -113,7 +113,7 @@ plain variables. This means that `setopt' will execute any (load custom-file 'noerror)) ;; Start Emacs server -;; (https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html) +;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html (run-with-idle-timer 0.5 nil #'require 'server) (with-eval-after-load 'server (declare-function server-edit "server") @@ -122,361 +122,12 @@ plain variables. This means that `setopt' will execute any (or (server-running-p) (server-mode))) -;;; Defaults - -;;;; C source code - -(setq-default - ;; Case-sensitive search (and `dabbrev-expand'). - ;; case-fold-search nil - indent-tabs-mode nil ; always use space for indentation - ;; tab-width 4 - indicate-buffer-boundaries 'left) - -(setq - ;; line-spacing 3 - completion-ignore-case t - read-buffer-completion-ignore-case t - enable-recursive-minibuffers t - resize-mini-windows t - message-log-max 20000 - mode-line-compact t - ;; mouse-autoselect-window t - scroll-conservatively 15 - scroll-preserve-screen-position 1 - ;; I don't feel like randomly jumping out of my chair. - ring-bell-function 'ignore) - -;;;; elisp source code - -(with-eval-after-load 'minibuffer - (setopt read-file-name-completion-ignore-case t)) - -(with-eval-after-load 'files - (setopt - make-backup-files nil - ;; Insert newline at the end of files. - ;; require-final-newline t - ;; Open read-only file buffers in view-mode, to get `q' for quit. - view-read-only t) - (add-to-list 'auto-mode-alist '("\\README.*" . text-mode)) - (add-to-list 'auto-mode-alist '("\\.*rc$" . conf-mode)) - (add-to-list 'auto-mode-alist '("\\.bashrc$" . sh-mode)) - (add-to-list 'auto-mode-alist '("\\COMMIT_EDITMSG$" . text-mode))) - -(setq disabled-command-function nil) - -(run-with-idle-timer 0.1 nil #'require 'autorevert) -(with-eval-after-load 'autorevert - (setopt - ;; auto-revert-verbose nil - global-auto-revert-non-file-buffers nil) - (global-auto-revert-mode 1)) - -(run-with-idle-timer 0.1 nil #'require 'time) -(with-eval-after-load 'time - (setopt - display-time-default-load-average nil - display-time-format " %a %Y-%m-%d %-l:%M%P" - display-time-mail-icon - '(image :type xpm :file "gnus/gnus-pointer.xpm" :ascent center) - display-time-use-mail-icon t - zoneinfo-style-world-list - `(,@zoneinfo-style-world-list - ("Etc/UTC" "UTC") - ("Asia/Tehran" "Tehran") - ("Australia/Melbourne" "Melbourne"))) - (unless (display-graphic-p) - (display-time-mode))) - -(defvar b/battery-format "%p%b %t") -(run-with-idle-timer 0.1 nil #'require 'battery) -(with-eval-after-load 'battery - (setopt battery-mode-line-format (format " [%s]" b/battery-format)) - ;; (display-battery-mode -1) - ) - -(run-with-idle-timer 0.5 nil #'require 'winner) -(with-eval-after-load 'winner - (winner-mode 1) - (when (featurep 'exwm) - ;; prevent a bad interaction between EXWM and winner-mode, where - ;; sometimes closing a window (like closing a terminal after - ;; entering a GPG password via pinentry-gnome3's floating window) - ;; results in a dead frame somewhere and effectively freezes EXWM. - (advice-add - 'winner-insert-if-new - :around - (lambda (orig-fun &rest args) - ;; only add the frame if it's live - (when (frame-live-p (car args)) - (apply orig-fun args)))))) - -(run-with-idle-timer 0.5 nil #'require 'windmove) -(with-eval-after-load 'windmove - (setopt windmove-wrap-around t) - (b/keymap-global-set "M-H" #'windmove-left) - (b/keymap-global-set "M-L" #'windmove-right) - (b/keymap-global-set "M-K" #'windmove-up) - (b/keymap-global-set "M-J" #'windmove-down)) - -(with-eval-after-load 'isearch - (setopt - isearch-allow-scroll t - isearch-lazy-count t - ;; Match non-ASCII variants during search - search-default-mode #'char-fold-to-regexp)) - -(b/keymap-global-set "C-x v C-=" #'vc-ediff) - -(with-eval-after-load 'vc-git - (setopt - ;; vc-git-show-stash 0 - vc-git-print-log-follow t)) - -(with-eval-after-load 'ediff - (setopt - ediff-window-setup-function #'ediff-setup-windows-plain - ediff-split-window-function #'split-window-horizontally)) - -;; (with-eval-after-load 'face-remap -;; (setopt -;; ;; Gentler font resizing. -;; text-scale-mode-step 1.05)) - -(run-with-idle-timer 0.4 nil #'require 'mwheel) -(with-eval-after-load 'mwheel - (setopt - mouse-wheel-scroll-amount '(1 ((shift) . 1)) ; one line at a time - mouse-wheel-progressive-speed nil ; don't accelerate scrolling - mouse-wheel-follow-mouse t)) ; scroll window under mouse - -(run-with-idle-timer 0.4 nil #'require 'pixel-scroll) -(with-eval-after-load 'pixel-scroll - (pixel-scroll-mode 1)) - -(with-eval-after-load 'epg-config - (setopt - epg-gpg-program (executable-find "gpg") - ;; Ask for GPG passphrase in minibuffer. - ;; Will fail if gpg >= 2.1 is not available. - epg-pinentry-mode 'loopback)) - -;; (with-eval-after-load 'auth-source -;; (setopt -;; auth-sources '("~/.authinfo.gpg") -;; authinfo-hidden -;; (regexp-opt '("password" "client-secret" "token")))) - -(with-eval-after-load 'info - (setq - Info-directory-list - `(,@Info-directory-list - ,(expand-file-name - (convert-standard-filename "info/") source-directory) - "/usr/share/info/"))) - -(when (display-graphic-p) - (set-fontset-font t 'arabic "Sahel WOL") - (let ((emoji-font "Apple Color Emoji")) - (when (member emoji-font (font-family-list)) - (set-fontset-font - t 'emoji `(,emoji-font . "iso10646-1") nil 'prepend))) - (with-eval-after-load 'faces - (let ((grey "#e7e7e7")) - ;; (set-face-attribute 'default nil - ;; :font "Source Code Pro" - ;; :height 113 ; 130 ; 105 - ;; :weight 'medium) - ;; (set-face-attribute 'fixed-pitch nil - ;; :font "Source Code Pro" - ;; :weight 'medium) - ;; (set-face-attribute 'default nil - ;; :font "Inconsolata Medium-12:hinting=true:autohint=true") - ;; (set-face-attribute 'fixed-pitch nil - ;; :font "Inconsolata Medium-12:hinting=true:autohint=true") - (set-face-attribute 'default nil - :font "Source Code Pro Medium-10.5") - (set-face-attribute 'fixed-pitch nil - :font "Source Code Pro Medium-10.5") - (set-face-attribute 'mode-line nil - :box '(:line-width 2 :style released-button) - :background grey - :inherit 'fixed-pitch)))) - -(when (and (version< emacs-version "28") mode-line-compact) - ;; Manually make some `mode-line' spaces smaller. - ;; Emacs 28 and above do a terrific job at this out of the box - ;; when `mode-line-compact' is set to t (see above)." - (setq-default - mode-line-format - (mapcar - (lambda (x) - (if (and (stringp x) - (or (string= x " ") - (string= x " "))) - " " - x)) - mode-line-format) - mode-line-buffer-identification - (propertized-buffer-identification "%10b"))) - - -;;; Useful utilities - -(defun b/insert-asterism () - "Insert a centred asterism." - (interactive) - (let ((asterism "* * *")) - (insert - (concat - "\n" - (make-string - (floor (/ (- fill-column (length asterism)) 2)) - ?\s) - asterism - "\n")))) - -(defun b/join-line-top () - "Like `join-line', but join next line to the current line." - (interactive) - (join-line 1)) - -(defun b/*scratch* () - "Switch to `*scratch*' buffer, creating it if it does not exist." - (interactive) - (let ((fun (if (functionp #'get-scratch-buffer-create) - #'get-scratch-buffer-create ; (version<= "29" emacs-version) - #'startup--get-buffer-create-scratch))) ; (version< emacs-version "29") - (switch-to-buffer (funcall fun)))) - -(defun b/duplicate-line-or-region (&optional n) - "Duplicate the current line, or region (if active). -Make N (default: 1) copies of the current line or region." - (interactive "*p") - (let ((u-r-p (use-region-p)) ; if region is active - (n1 (or n 1))) - (save-excursion - (let ((text - (if u-r-p - (buffer-substring (region-beginning) (region-end)) - (prog1 (thing-at-point 'line) - (end-of-line) - (if (eobp) - (newline) - (forward-line 1)))))) - (dotimes (_ (abs n1)) - (insert text)))))) - -(defun b/invert-default-face (arg) - "Invert the `default' and `mode-line' faces for the current frame. -Swap the background and foreground for the two `default' and -`mode-line' faces, effectively acting like a simple light/dark -theme toggle. If prefix argument ARG is given, invert the faces -for all frames." - (interactive "P") - (let ((frame (unless arg - (selected-frame)))) - (invert-face 'default frame) - (invert-face 'mode-line frame) - (when (fboundp #'exwm-systemtray--refresh-background-color) - (exwm-systemtray--refresh-background-color 'remap)))) - -(defun b/unfill-paragraph-or-region (&optional beg end) - "Unfill paragraph, or region (if active)." - (interactive "r") - (let ((fill-column most-positive-fixnum)) - (if (use-region-p) - (fill-region beg end) - (fill-paragraph)))) - - -;;; General key bindings - -(let ((kfs - '(("C-c i" . ielm) - ("C-c d" . b/duplicate-line-or-region) - ("C-c j" . b/join-line-top) - ("C-S-j" . b/join-line-top) - ("C-c s c" . b/*scratch*) - ("C-c v" . b/invert-default-face) - ("C-c q" . b/unfill-paragraph-or-region) - ;; evaling and macro-expanding - ("C-c e b" . eval-buffer) - ("C-c e e" . eval-last-sexp) - ("C-c e m" . pp-macroexpand-last-sexp) - ("C-c e r" . eval-region) - ;; emacs things - ("C-c e i" . emacs-init-time) - ("C-c e u" . emacs-uptime) - ("C-c e v" . emacs-version) - ;; finding - ("C-c f ." . find-file) - ("C-c f l" . find-library) - ("C-c f p" . find-file-at-point) - ;; frames - ("C-c F m" . make-frame-command) - ("C-c F d" . delete-frame) - ;; help/describe - ("C-c h F" . describe-face)))) - (dolist (kf kfs) - (let ((key (car kf)) - (fun (cdr kf))) - (b/keymap-global-set key fun)))) - -(when (display-graphic-p) - ;; Too easy to accidentally suspend (freeze) Emacs GUI. - (b/keymap-global-unset "C-z")) - - ;;; Essential packages (add-to-list 'load-path (b/emacs.d "lisp")) +(require 'bandali-essentials) ;; (require 'bandali-exwm) - -;; recently opened files -(run-with-idle-timer 0.2 nil #'require 'recentf) -(with-eval-after-load 'recentf - (setopt recentf-max-saved-items 2000) - (recentf-mode) - - (defun b/recentf-open () - "Use `completing-read' to \\[find-file] a recent file." - (interactive) - (find-file - (completing-read "Find recent file: " recentf-list))) - (b/keymap-global-set "C-c f r" #'b/recentf-open)) - -(with-eval-after-load 'help - (temp-buffer-resize-mode) - (setopt help-window-select t)) - -(with-eval-after-load 'help-mode - (let ((m help-mode-map)) - (b/keymap-set m "p" #'backward-button) - (b/keymap-set m "n" #'forward-button) - (b/keymap-set m "b" #'help-go-back) - (b/keymap-set m "f" #'help-go-forward))) - -(with-eval-after-load 'doc-view - (b/keymap-set doc-view-mode-map "M-RET" #'image-previous-line)) - -(with-eval-after-load 'shr - (setopt shr-max-width 80)) - -(with-eval-after-load 'mule-cmds - (setopt default-input-method "farsi-isiri-9147")) - -(with-eval-after-load 'tramp - (tramp-set-completion-function - "ssh" - (append (tramp-get-completion-function "ssh") - (mapcar (lambda (file) `(tramp-parse-sconfig ,file)) - (directory-files - "~/.ssh/config.d/" - 'full directory-files-no-dot-files-regexp))))) - (require 'bandali-eshell) (require 'bandali-ibuffer) (require 'bandali-dired) @@ -492,52 +143,15 @@ for all frames." (require 'bandali-erc) -;;; Editing - -;; Display Lisp objects at point in the echo area. -(with-eval-after-load 'eldoc - (setopt eldoc-minor-mode-string " eldoc") - (global-eldoc-mode 1)) - -;; highlight matching parens -(run-with-idle-timer 0.2 nil #'require 'paren) -(with-eval-after-load 'paren - (show-paren-mode 1)) +;;; Programming modes -(with-eval-after-load 'simple - (setopt - ;; Save what I copy into clipboard from other applications into - ;; Emacs' kill-ring, which would allow me to still be able to - ;; easily access it in case I kill (cut or copy) something else - ;; inside Emacs before yanking (pasting) what I'd originally - ;; intended to. - save-interprogram-paste-before-kill t) - (column-number-mode 1) - (line-number-mode 1)) - -(run-with-idle-timer 0.2 nil #'require 'savehist) -(with-eval-after-load 'savehist - ;; Save minibuffer history. - (savehist-mode 1) - (add-to-list 'savehist-additional-variables 'kill-ring)) - -;; Automatically save place in files. -(run-with-idle-timer 0.2 nil #'require 'saveplace nil 'noerror) -(with-eval-after-load 'saveplace - (save-place-mode 1)) - -(with-eval-after-load 'flyspell - (setopt flyspell-mode-line-string " fly")) - -(with-eval-after-load 'text-mode - (add-hook 'text-mode-hook #'flyspell-mode) - (b/keymap-set text-mode-map "M-RET" #'b/insert-asterism)) - -(with-eval-after-load 'abbrev - (add-hook 'text-mode-hook #'abbrev-mode)) +(use-package elisp-mode + :bind + ("C-c e e" . eval-last-sexp)) - -;;; Programming modes +(use-package pp + :bind + ("C-c e m" . pp-macroexpand-last-sexp)) (with-eval-after-load 'lisp-mode (add-hook @@ -594,9 +208,6 @@ for all frames." ;;; Emacs enhancements & auxiliary packages -(with-eval-after-load 'man - (setopt Man-width 80)) - ;; `debbugs' (b/keymap-global-set "C-c D d" #'debbugs-gnu) (b/keymap-global-set "C-c D b" #'debbugs-gnu-bugs) diff --git a/.emacs.d/lisp/bandali-essentials.el b/.emacs.d/lisp/bandali-essentials.el new file mode 100644 index 0000000..a0ea5f1 --- /dev/null +++ b/.emacs.d/lisp/bandali-essentials.el @@ -0,0 +1,402 @@ +;;; bandali-essentials.el --- bandali's essentials -*- lexical-binding: t; -*- + +;; Copyright (c) 2018-2025 Amin Bandali <bandali@gnu.org> + +;; Author: Amin Bandali <bandali@gnu.org> +;; Keywords: files, internal + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; The core essentials of my GNU Emacs setup. + +;;; Code: + +(use-package emacs + :demand t + :bind + ("C-c e b" . eval-buffer) + ("C-c e r" . eval-region) + :config + (when (display-graphic-p) + ;; Too easy to accidentally suspend (freeze) Emacs GUI. + (b/keymap-global-unset "C-z")) + + (setq-default + ;; Case-sensitive search (and `dabbrev-expand'). + ;; case-fold-search nil + indent-tabs-mode nil ; always use space for indentation + ;; tab-width 4 + indicate-buffer-boundaries 'left) + + (setq + ;; line-spacing 3 + completion-ignore-case t + read-buffer-completion-ignore-case t + enable-recursive-minibuffers t + resize-mini-windows t + message-log-max 20000 + mode-line-compact t + ;; mouse-autoselect-window t + scroll-conservatively 15 + scroll-preserve-screen-position 1 + ;; I don't feel like randomly jumping out of my chair. + ring-bell-function 'ignore) + + ;; Mode-line compacting for older Emacsen. + (when (and (version< emacs-version "28") mode-line-compact) + ;; Manually make some `mode-line' spaces smaller. + ;; Emacs 28 and above do a terrific job at this out of the box + ;; when `mode-line-compact' is set to t (see above)." + (setq-default + mode-line-format + (mapcar + (lambda (x) + (if (and (stringp x) + (or (string= x " ") + (string= x " "))) + " " + x)) + mode-line-format) + mode-line-buffer-identification + (propertized-buffer-identification "%10b"))) + + ;; Fonts and types. + (when (display-graphic-p) + (set-fontset-font t 'arabic "Sahel WOL") + (let ((emoji-font "Apple Color Emoji")) + (when (member emoji-font (font-family-list)) + (set-fontset-font + t 'emoji `(,emoji-font . "iso10646-1") nil 'prepend))) + (with-eval-after-load 'faces + (let ((grey "#e7e7e7")) + ;; (set-face-attribute 'default nil + ;; :font "Source Code Pro" + ;; :height 113 ; 130 ; 105 + ;; :weight 'medium) + ;; (set-face-attribute 'fixed-pitch nil + ;; :font "Source Code Pro" + ;; :weight 'medium) + ;; (set-face-attribute 'default nil + ;; :font "Inconsolata Medium-12:hinting=true:autohint=true") + ;; (set-face-attribute 'fixed-pitch nil + ;; :font "Inconsolata Medium-12:hinting=true:autohint=true") + (set-face-attribute 'default nil + :font "Source Code Pro Medium-10.5") + (set-face-attribute 'fixed-pitch nil + :font "Source Code Pro Medium-10.5") + (set-face-attribute 'mode-line nil + :box '(:line-width 2 :style released-button) + :background grey + :inherit 'fixed-pitch))))) + +(use-package minibuffer + :custom + (read-file-name-completion-ignore-case t)) + +(use-package files + :bind + ("C-c f ." . find-file) + :custom + (make-backup-files nil) + ;; Insert newline at the end of files. + ;; (require-final-newline t) + ;; Open read-only file buffers in view-mode, to get `q' for quit. + (view-read-only t)) + +(use-package ffap + :bind + ("C-c f p" . find-file-at-point)) + +(use-package find-func + :bind + ("C-c f l" . find-library)) + +(use-package frame + :bind + ("C-c F m" . make-frame-command) + ("C-c F d" . delete-frame)) + +(use-package text-mode + :mode "\\(README.*\\|COMMIT_EDITMSG$\\)") + +(use-package conf-mode + :mode "\\.*rc$") + +(use-package sh-script + :mode ("\\.bashrc$" . sh-mode)) + +(use-package novice + :config + (setq disabled-command-function nil)) + +(use-package autorevert + :defer 0.1 + :custom + ;; (auto-revert-verbose nil) + (global-auto-revert-non-file-buffers nil) + :config + (global-auto-revert-mode 1)) + +(use-package time + :defer 0.1 + :bind + ("C-c e i" . emacs-init-time) + ("C-c e u" . emacs-uptime) + :custom + (display-time-default-load-average nil) + (display-time-format " %a %Y-%m-%d %-l:%M%P") + (display-time-mail-icon + '(image :type xpm :file "gnus/gnus-pointer.xpm" :ascent center)) + (display-time-use-mail-icon t) + :config + (setopt + zoneinfo-style-world-list + `(,@zoneinfo-style-world-list + ("Etc/UTC" "UTC") + ("Asia/Tehran" "Tehran") + ("Australia/Melbourne" "Melbourne"))) + (unless (display-graphic-p) + (display-time-mode 1))) + +(defvar b/battery-format "%p%b %t") +(use-package battery + ;; :if (not (display-graphic-p)) + :custom + (battery-mode-line-format (format " [%s]" b/battery-format))) + +(use-package winner + :defer 0.5 + :config + (winner-mode 1) + (when (featurep 'exwm) + ;; Prevent a bad interaction between EXWM and winner-mode, where + ;; sometimes closing a window (like closing a terminal after + ;; entering a GPG password via pinentry-gnome3's floating window) + ;; results in a dead frame somewhere and effectively freezes EXWM. + (advice-add + 'winner-insert-if-new + :around + (lambda (orig-fun &rest args) + ;; only add the frame if it's live + (when (frame-live-p (car args)) + (apply orig-fun args)))))) + +(use-package windmove + :defer 0.5 + :custom + (windmove-wrap-around t) + :bind + ("M-H" . windmove-left) + ("M-L" . windmove-right) + ("M-K" . windmove-up) + ("M-J" . windmove-down)) + +(use-package isearch + :custom + (isearch-allow-scroll t) + (isearch-lazy-count t) + ;; Match non-ASCII variants during search + (search-default-mode #'char-fold-to-regexp)) + +(use-package vc + :bind + ("C-x v C-=" . vc-ediff)) + +(use-package vc-git + :custom + ;; (vc-git-show-stash 0) + (vc-git-print-log-follow t)) + +(use-package ediff + :custom + (ediff-window-setup-function #'ediff-setup-windows-plain) + (ediff-split-window-function #'split-window-horizontally)) + +(use-package face-remap + :disabled + :custom + ;; Gentler font scaling. + (text-scale-mode-step 1.05)) + +(use-package mwheel + :defer 0.4 + :custom + (mouse-wheel-scroll-amount '(1 ((shift) . 1))) ; one line at a time + (mouse-wheel-progressive-speed nil) ; don't accelerate scrolling + (mouse-wheel-follow-mouse t)) ; scroll window under mouse + +(use-package pixel-scroll + :defer 0.4 + :config + (pixel-scroll-mode 1)) + +(use-package epg-config + :custom + (epg-gpg-program (executable-find "gpg")) + ;; Ask for GPG passphrase in minibuffer. + ;; Will fail if gpg >= 2.1 is not available. + (epg-pinentry-mode 'loopback)) + +(use-package auth-source + :disabled + :custom + (auth-sources '("~/.authinfo.gpg")) + (authinfo-hidden + (regexp-opt '("password" "client-secret" "token")))) + +(use-package info + :config + (setq + Info-directory-list + `(,@Info-directory-list + ,(expand-file-name + (convert-standard-filename "info/") source-directory) + "/usr/share/info/"))) + +(use-package ielm + :bind + ("C-c i" . ielm)) + +(use-package recentf + ;; recently opened files + :defer 0.2 + :init + (defun b/recentf-open () + "Use `completing-read' to \\[find-file] a recent file." + (interactive) + (find-file + (completing-read "Find recent file: " recentf-list))) + :bind + ("C-c f r" . b/recentf-open) + :custom + (recentf-max-saved-items 2000) + :config + (recentf-mode 1)) + +(use-package help + :custom + (help-window-select t) + :config + (temp-buffer-resize-mode 1)) + +(use-package help-mode + :bind + (:map + help-mode-map + ("p" . backward-button) + ("n" . forward-button) + ("b" . help-go-back) + ("f" . help-go-forward))) + +(use-package help-fns + :bind + ("C-c h F" . describe-face)) + +(use-package doc-view + :bind + (:map + doc-view-mode-map + ("M-RET" . image-previous-line))) + +(use-package man + :custom + (Man-width 80)) + +(use-package shr + :custom + (shr-max-width 80)) + +(use-package mule-cmds + :preface (provide 'mule-cmds) + :custom + (default-input-method "farsi-isiri-9147")) + +(use-package tramp + :config + (tramp-set-completion-function + "ssh" + (append (tramp-get-completion-function "ssh") + (mapcar (lambda (file) `(tramp-parse-sconfig ,file)) + (directory-files + "~/.ssh/config.d/" + 'full directory-files-no-dot-files-regexp))))) + +(use-package eldoc + ;; Display Lisp objects at point in the echo area. + :custom + (eldoc-minor-mode-string " eldoc") + :config + (global-eldoc-mode 1)) + +(use-package paren + ;; Highlight matching parens. + :defer 0.2 + :config + (show-paren-mode 1)) + +(use-package simple + :custom + ;; Save what I copy into clipboard from other applications into + ;; Emacs' kill-ring, which would allow me to still be able to + ;; easily access it in case I kill (cut or copy) something else + ;; inside Emacs before yanking (pasting) what I'd originally + ;; intended to. + (save-interprogram-paste-before-kill t) + :config + (column-number-mode 1) + (line-number-mode 1)) + +(use-package savehist + ;; Save minibuffer history. + :defer 0.2 + :config + (savehist-mode 1) + (add-to-list 'savehist-additional-variables 'kill-ring)) + +(use-package saveplace + ;; Automatically save place in files. + :defer 0.2 + :config + (save-place-mode 1)) + +(use-package flyspell + :custom + (flyspell-mode-line-string " fly") + :hook + (text-mode . flyspell-mode)) + +(use-package abbrev + :hook + (text-mode . abbrev-mode)) + +(use-package version + :bind + ("C-c e v" . emacs-version)) + +(use-package bandali-utils + :bind + ("C-c d" . b/duplicate-line-or-region) + ("C-c j" . b/join-line-top) + ("C-S-j" . b/join-line-top) + ("C-c s c" . b/*scratch*) + ("C-c v" . b/invert-default-face) + ("C-c q" . b/unfill-paragraph-or-region) + (:map + text-mode-map + ("M-RET" . b/insert-asterism))) + +(provide 'bandali-essentials) +;;; bandali-essentials.el ends here diff --git a/.emacs.d/lisp/bandali-utils.el b/.emacs.d/lisp/bandali-utils.el new file mode 100644 index 0000000..9edc91e --- /dev/null +++ b/.emacs.d/lisp/bandali-utils.el @@ -0,0 +1,94 @@ +;;; bandali-utils.el --- useful utilities -*- lexical-binding: t; -*- + +;; Copyright (c) 2018-2025 Amin Bandali <bandali@gnu.org> + +;; Author: Amin Bandali <bandali@gnu.org> +;; Keywords: convenience + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Some useful utilities. + +;;; Code: + +(defun b/insert-asterism () + "Insert a centred asterism." + (interactive) + (let ((asterism "* * *")) + (insert + (concat + "\n" + (make-string + (floor (/ (- fill-column (length asterism)) 2)) + ?\s) + asterism + "\n")))) + +(defun b/join-line-top () + "Like `join-line', but join next line to the current line." + (interactive) + (join-line 1)) + +(defun b/*scratch* () + "Switch to `*scratch*' buffer, creating it if it does not exist." + (interactive) + (let ((fun (if (functionp #'get-scratch-buffer-create) + #'get-scratch-buffer-create ; (version<= "29" emacs-version) + #'startup--get-buffer-create-scratch))) ; (version< emacs-version "29") + (switch-to-buffer (funcall fun)))) + +(defun b/duplicate-line-or-region (&optional n) + "Duplicate the current line, or region (if active). +Make N (default: 1) copies of the current line or region." + (interactive "*p") + (let ((u-r-p (use-region-p)) ; if region is active + (n1 (or n 1))) + (save-excursion + (let ((text + (if u-r-p + (buffer-substring (region-beginning) (region-end)) + (prog1 (thing-at-point 'line) + (end-of-line) + (if (eobp) + (newline) + (forward-line 1)))))) + (dotimes (_ (abs n1)) + (insert text)))))) + +(defun b/invert-default-face (arg) + "Invert the `default' and `mode-line' faces for the current frame. +Swap the background and foreground for the two `default' and +`mode-line' faces, effectively acting like a simple light/dark +theme toggle. If prefix argument ARG is given, invert the faces +for all frames." + (interactive "P") + (let ((frame (unless arg + (selected-frame)))) + (invert-face 'default frame) + (invert-face 'mode-line frame) + (when (fboundp #'exwm-systemtray--refresh-background-color) + (exwm-systemtray--refresh-background-color 'remap)))) + +(defun b/unfill-paragraph-or-region (&optional beg end) + "Unfill paragraph, or region (if active)." + (interactive "r") + (let ((fill-column most-positive-fixnum)) + (if (use-region-p) + (fill-region beg end) + (fill-paragraph)))) + +(provide 'bandali-utils) +;;; bandali-utils.el ends here |