;;; common.el --- Common settings for text files. -*- lexical-binding: t; -*- ;;; Commentary: ;;; Code: (require 'basics/package-management) (require 'basics/global-variables) (use-package emacs :straight (:type built-in) :demand t :custom ((require-final-newline t) ; Always add newline at end of file. (fill-column 80) ; Documents are 80 chars wide by default. (word-wrap t)) ; Wrap at word for continuation lines. :bind (("C-r" . jump-to-register) ; Move point to location in register. ("C-S-r" . point-to-register); Store location of point in register. ("M-W" . copy-to-register) ; Store text in register. ("C-S-y" . insert-register) ; Insert text from register. ("M-" . list-registers) ; List all registers. ("C-c C-S-t" . toggle-truncate-lines)) :hook (text-mode . auto-fill-mode)) ; Enable word-wrapping at fill-column. ;; Quickly jump to next/previous register. (use-package register-quicknav :straight (register-quicknav :type git :repo "https://schlomp.space/tastytea/register-quicknav.git" :branch "main") ;; ^^^^^^^ See . ;; Fix is in develop: . :custom (register-quicknav-buffer-only t) :bind (("C-" . register-quicknav-prev-register) ("C-" . register-quicknav-next-register) ("C-" . register-quicknav-point-to-unused-register) ("C-S-" . register-quicknav-clear-current-register))) ;; Save cursor position. (use-package saveplace :demand t :config (save-place-mode t)) ;; Ruler with fill-column marker. (use-package ruler-mode :straight (:type built-in) :after (doom-themes display-line-numbers) :demand t :config (progn (defun my/ruler-set-colors () (set-face-background 'ruler-mode-default (face-foreground 'line-number)) (set-face-foreground 'ruler-mode-default (face-background 'default)) (set-face-foreground 'ruler-mode-column-number (face-background 'default)) (if (and (window-system) (>= emacs-major-version 27)) (set-face-foreground 'ruler-mode-fill-column (face-foreground 'fill-column-indicator nil t)) (set-face-foreground 'ruler-mode-fill-column (face-foreground 'shadow))) (set-face-foreground 'ruler-mode-comment-column (face-foreground 'ruler-mode-fill-column)) (set-face-foreground 'ruler-mode-goal-column (face-foreground 'ruler-mode-fill-column)) (set-face-foreground 'ruler-mode-current-column (face-foreground 'line-number-current-line))) (my/ruler-set-colors) (defun my/ruler-on () "Turn `ruler-mode' on." (unless (bound-and-true-p lsp-mode) ;; lsp-mode has this breadcrumb thingie instead. (ruler-mode 1)))) :custom-face (ruler-mode-default ((t (:inherit·default :box·nil)))) :hook ((find-file . my/ruler-on) (text-mode . my/ruler-on) ; For the scratch buffer. (server-after-make-frame . my/ruler-set-colors))) ;; Show a fill-column indicator vertically across the buffer. (when (>= emacs-major-version 27) (use-package display-fill-column-indicator :hook ((find-file . display-fill-column-indicator-mode) (text-mode . display-fill-column-indicator-mode)))) ;; spell checking. (use-package ispell :straight (:type built-in) ;; Use hunspell if possible and configure multiple dictionaries. ;; :config (when (executable-find "hunspell") (customize-set-variable 'ispell-program-name (executable-find "hunspell")) ;; (customize-set-variable 'ispell-dictionary "en_US,de_DE") (ispell-set-spellchecker-params) (ispell-hunspell-add-multi-dic "en_US,de_DE") (ispell-hunspell-add-multi-dic "en_GB,de_DE") (ispell-hunspell-add-multi-dic "de_DE,de_AT,de_CH"))) ;; Interactive spell checking. (use-package flyspell :if (and (not slow-computer) (or (executable-find "aspell") (executable-find "hunspell") (executable-find "ispell"))) :diminish flyspell-mode :custom ((flyspell-default-dictionary "en_US")) :config (progn (defun my/toggle-flyspell () "Toggle flyspell-mode and run flyspell-buffer after activating." (interactive) (if (bound-and-true-p flyspell-mode) (flyspell-mode 0) (flyspell-mode) (flyspell-buffer))) (defun my/flyspell-german () "Set dictionary to german." (interactive) (ispell-change-dictionary "de_DE"))) :bind (("" . my/toggle-flyspell) (:map flyspell-mode-map ("C-;" . nil) ; iedit needs C-;. ("C-M-i" . nil) ; imenu-anywhere needs it. ("C-c ." . flyspell-auto-correct-word))) ; C-. doesn't work in TUI. :hook ((prog-mode . flyspell-prog-mode) ; Spellcheck comments. (text-mode . flyspell-mode) ; Spellcheck text documents ↓. (LaTeX-mode . my/flyspell-german) (LaTeX-mode . flyspell-mode) (adoc-mode . flyspell-mode) (markdown-mode . flyspell-mode) (git-commit-mode . flyspell-mode)) :mode ("COMMIT_EDITMSG\\'" . flyspell-mode)) ;; The string Time-stamp: <> in the first 8 lines of the file will be updated ;; with the current timestamp. (use-package time-stamp :config (progn (if (>= emacs-major-version 27) (setq time-stamp-format "%Y-%02m-%02dT%02H:%02M:%02S%5z") ;; Set to UTC since ISO 8601 is not supported. (setq time-stamp-format "%Y-%02m-%02dT%02H:%02M:%02S+0000") (setq time-stamp-time-zone t))) :hook (before-save . time-stamp)) ;; A template system. (use-package yasnippet :after (company) :defines (company-candidates) :functions (yas-reload-all yas-expand-snippet) :diminish yas-minor-mode :config (progn (defun my/tab-yas-or-company () "Complete with company if possible, jump to next field otherwise." (interactive) (if company-candidates (company-complete-selection) (yas-next-field))) (yas-reload-all) (defun my/string-to-var (string) "Replace characters that usually are illegal in variable names in STRING with _." (interactive) (replace-regexp-in-string "[[:space:]]" "_" (replace-regexp-in-string "[^[:ascii:]]" "_" string)))) :bind (:map yas-keymap ("" . my/tab-yas-or-company) ("TAB" . my/tab-yas-or-company)) :hook ((prog-mode . yas-minor-mode) (org-mode . yas-minor-mode) (nxml-mode . yas-minor-mode))) ;; Install snippet-collection but don't use it. (use-package yasnippet-snippets :demand t :after (yasnippet) ;; Don't add the snippets. :config (delete 'yasnippet-snippets-dir yas-snippet-dirs)) ;; Automatically insert text in new files. (use-package autoinsert :after (yasnippet) :init (progn (defun my/autoinsert-yas-expand () "Replace text in yasnippet template." (yas-minor-mode t) (yas-expand-snippet (buffer-string) (point-min) (point-max)))) :custom ((auto-insert-directory (concat user-emacs-directory "auto-insert")) (auto-insert-query nil)) ; Don't ask before inserting. :config (progn (add-to-list 'auto-insert-alist '(("\\.c\\(pp\\|c\\|xx\\|\\+\\+\\)$" . "C++ program") . ["cpp" my/autoinsert-yas-expand])) (add-to-list 'auto-insert-alist '(("\\.h\\(pp\\|h\\|xx\\|\\+\\+\\)$" . "C++ header") . ["hpp" my/autoinsert-yas-expand])) (add-to-list 'auto-insert-alist '(("\\.[1-9]\\.adoc$" . "AsciiDoc manpage") . ["manpage.adoc" my/autoinsert-yas-expand])) (add-to-list 'auto-insert-alist '(("\\.user.js$" . "Userscript") . ["user.js" my/autoinsert-yas-expand])) (add-to-list 'auto-insert-alist '(("metadata\\.xml$" . "Gentoo pkg metadata") . ["metadata.xml" my/autoinsert-yas-expand]))) :hook (find-file . auto-insert)) ;; Better search. (use-package swiper :after (ivy) :functions (swiper) :bind ("C-s" . swiper)) ;; Visualize and transform whitespace. (use-package whitespace :after (company) :functions (my/on-off-whitespace-before-company) :diminish whitespace-mode :custom (whitespace-line-column nil) ; Set to fill-column. :config (progn (delete 'newline-mark whitespace-style) ; Don't paint $ at eol. (delete 'lines whitespace-style) ; Don't mark whole long lines. (when (< emacs-major-version 27) ; Mark end of too long lines. (add-to-list 'whitespace-style 'lines-tail)) ;; Workaround to not show dots in popup menus. (defvar-local my/ws-enabled nil) (defun my/whitespace-mode-off () (setq-local my/ws-enabled whitespace-mode) (when my/ws-enabled (whitespace-mode -1))) (defun my/whitespace-mode-on () (when my/ws-enabled (whitespace-mode t))) ;; company: (defun my/on-off-whitespace-before-company (command) (when (string= "show" command) (my/whitespace-mode-off)) (when (string= "hide" command) (my/whitespace-mode-on))) (advice-add 'company-call-frontends :before #'my/on-off-whitespace-before-company) ;; popup: (defadvice popup-create (before my/popup-suspend-ws activate) "Suspend whitespace-mode while popups are visible." (my/whitespace-mode-off)) (defadvice popup-delete (after my/popup-restore-ws activate) "Restore whitespace-mode when all popups have closed." (my/whitespace-mode-on)) (if (display-graphic-p) (custom-set-faces '(whitespace-line ((t (:inherit whitespace-line :weight normal :foreground nil :background nil :box (:line-width 1 :color "dark red")))))) (custom-set-faces ; else '(whitespace-line ((t (:inherit whitespace-line :background nil :underline t)))))) ;; Workaround for ;; , fixed ;; in 28.1. (defun my/ws-load-local-vars-first () "Loads fill-column before enabling whitespace-mode." ;; We don't use 'lines-tail in Emacs >= 27. (when (< emacs-major-version 27) (hack-local-variables)) (whitespace-mode)) (defun my/ws-maybe-cleanup () "Run `whitespace-cleanup' if `my/reformat-save' is t." (when my/reformat-save (whitespace-cleanup)))) :bind ("C-c w" . whitespace-mode) :hook ((prog-mode . my/ws-load-local-vars-first) (conf-mode . my/ws-load-local-vars-first) (text-mode . my/ws-load-local-vars-first))) ;; Calls whitespace-cleanup before saving the current buffer, but only if the ;; whitespace in the buffer was initially clean. (use-package whitespace-cleanup-mode :after (whitespace) :config (global-whitespace-cleanup-mode) :hook (change-major-mode-hook . (lambda () (when (not my/reformat-save) (setq-local whitespace-cleanup-mode nil))))) ;; ripgrep. (use-package rg :bind ("C-c s" . rg-menu)) ;; Insert pseudo latin text. (use-package lorem-ipsum) ;; Translate ANSI escape color codes. (use-package ansi-color :config (progn (defun my/apply-ansi-colors-on-buffer () "Apply ANSI colors in the current buffer." (interactive) (let ((inhibit-read-only t)) (ansi-color-apply-on-region (point-min) (point-max)))) (defun my/apply-ansi-colors-compilation () "Apply ANSI colors in the compilation window." (let ((inhibit-read-only t)) (ansi-color-apply-on-region compilation-filter-start (point))))) :mode ("\\.log$" . my/apply-ansi-colors-on-buffer) :hook (compilation-filter . my/apply-ansi-colors-compilation)) ;; Colorize color names. (use-package rainbow-mode :demand t :diminish rainbow-mode) ;; Tries to find points of interest in buffer and jumps to them. (use-package imenu :custom (imenu-auto-rescan t)) ;; Tries to find points of interest in all open buffers and jumps to them. (use-package imenu-anywhere :after (imenu ivy) :bind ("C-M-i" . ivy-imenu-anywhere)) (provide 'text/common) ;;; common.el ends here