.emacs.d/init/text/common.el

268 lines
7.4 KiB
EmacsLisp

;;; common.el --- Common settings for text files. -*- lexical-binding: t; -*-
;; Time-stamp: <2019-12-18T23:44:03+00:00>
;;; Commentary:
;;; Code:
(require 'basics/global-variables)
(use-package emacs
:ensure nil
:custom
(require-final-newline t) ; Always add newline at end of file.
(fill-column 80) ; Documents are 80 chars wide by default.
:hook
(text-mode . auto-fill-mode) ; Enable word-wrapping at fill-column.
)
;; Save cursor position.
(use-package saveplace
:ensure nil ; Builtin.
:config
(save-place-mode t)
)
;; Ruler with fill-column marker.
(use-package ruler-mode
:ensure nil ; Builtin.
:config
(defun my/ruler-on ()
"Turn ruler on."
(ruler-mode 1)
)
:custom-face
(ruler-mode-default ((t
(:inherit default
:background "gray18"
:foreground "dim gray"
:box nil))))
(ruler-mode-column-number ((t
(:inherit ruler-mode-default
:foreground "dark gray"))))
:hook
(find-file . my/ruler-on)
(text-mode . my/ruler-on) ; For the scratch buffer.
)
;; Spell checking.
(unless slow-computer
(use-package flyspell
:if (or (executable-find "aspell")
(executable-find "hunspell")
(executable-find "ispell"))
:custom
(ispell-dictionary "english")
:config
(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 "german"))
;; Allow setting the language in file/dir local variables.
(put 'ispell-dictionary 'safe-local-variable #'stringp)
:bind
("<f9>" . my/toggle-flyspell)
(:map flyspell-mode-map
("C-;" . nil)) ; iedit needs C-;.
:hook
;; Spellcheck comments.
(prog-mode . flyspell-prog-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)
)
) ; unless slow-computer.
;; The string Time-stamp: <> in the first 8 lines of the file will be updated
;; with the current timestamp.
(use-package time-stamp
:custom
(time-stamp-format "%:y-%02m-%02dT%02H:%02M:%02S+00:00")
(time-stamp-time-zone t) ; Set to UTC until ISO 8601 is supported.
:hook
(before-save . time-stamp)
)
;; A template system.
(use-package yasnippet
:functions (yas-reload-all yas-expand-snippet)
:config
(yas-reload-all)
:hook
(prog-mode . yas-minor-mode)
)
;; Install snippet-collection but don't use it.
(use-package yasnippet-snippets
:defer t
:config
(setq yasnippet-snippets-dir "")
)
;; Automatically insert text in new files.
(use-package autoinsert
:after (yasnippet)
:init
(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
(add-to-list 'auto-insert-alist
'(("\\.\\(cpp\\|cc\\|cxx\\|c\\+\\+\\)\\'" . "C++ program") .
["cpp" my/autoinsert-yas-expand]))
(add-to-list 'auto-insert-alist
'(("\\.\\(hpp\\|hh\\|hxx\\|h\\+\\+\\)\\'" . "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]))
: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/whitespace-mode-enabled-p my/on-off-whitespace-before-company)
:custom
(whitespace-line-column nil) ; Set to fill-column.
:config
(delete 'newline-mark whitespace-style) ; Don't paint $ at eol.
(delete 'lines whitespace-style) ; Don't mark whole overly long lines.
(add-to-list 'whitespace-style 'lines-tail) ; Mark end of overly long lines.
;; Workaround to not show dots in popup menus.
(defun my/whitespace-mode-enabled-p ()
(symbol-value 'whitespace-mode))
(defvar-local my/ws-enabled nil)
;; company:
(defun my/on-off-whitespace-before-company(command)
(when (string= "show" command)
(setq-local my/ws-enabled (my/whitespace-mode-enabled-p))
(if my/ws-enabled
(whitespace-mode -1)))
(when (string= "hide" command)
(if my/ws-enabled
(whitespace-mode t))))
(advice-add 'company-call-frontends
:before #'my/on-off-whitespace-before-company)
(defun my/whitespace-mode-off ()
(setq-local my/ws-enabled (my/whitespace-mode-enabled-p))
(if my/ws-enabled
(whitespace-mode -1)))
(defun my/whitespace-mode-on ()
(if my/ws-enabled
(whitespace-mode t)))
;; popup:
(defadvice popup-create (before my/popup-suppress-whitespace-mode activate)
"Suspend whitespace-mode while popups are visible."
(my/whitespace-mode-off))
(defadvice popup-delete (after my/popup-restore-whitespace-mode 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")
;; :underline (:color "dark red")
)))))
(custom-set-faces ; else
'(whitespace-line ((t (:inherit whitespace-line
:background nil
:underline t
)))))
)
(defun my/ws-load-local-vars-first ()
"Loads local variables (fill-column) before enabling whitespace-mode."
(hack-local-variables)
(whitespace-mode)
)
(defvar no-ws-cleanup nil
"Do not cleanup whitespace if t.")
(make-variable-buffer-local 'no-ws-cleanup)
(put 'no-ws-cleanup 'safe-local-variable #'booleanp) ; Mark as safe.
(defun my/ws-maybe-cleanup ()
"Run `whitespace-cleanup' if `no-ws-cleanup' is not t."
(unless no-ws-cleanup
(whitespace-cleanup))
)
:bind
("C-x 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)
(before-save . my/ws-maybe-cleanup)
:custom-face
(whitespace-space ((nil :foreground "gray18")))
)
(provide 'text/common)
;;; common.el ends here