doomemacs/core/core-ui.el
Henrik Lissner a0250e60e3
Add rainbow-delimiters in lang/common-lisp instead
Gives users one place to look to determine what cosmetic hooks are
applied in lisp-mode.
2018-09-09 09:58:19 -04:00

502 lines
20 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; core-ui.el -*- lexical-binding: t; -*-
(defvar doom-theme nil
"A symbol representing the color theme to load.")
(defvar doom-font nil
"The default font to use. Expects a `font-spec'.")
(defvar doom-big-font nil
"The default large font to use when `doom-big-font-mode' is enabled. Expects a
`font-spec'.")
(defvar doom-variable-pitch-font nil
"The default font to use for variable-pitch text. Expects a `font-spec'.")
(defvar doom-unicode-font nil
"Fallback font for unicode glyphs. Is ignored if :feature unicode is active.
Expects a `font-spec'.")
(defvar doom-major-mode-names
'((sh-mode . "sh")
(emacs-lisp-mode . "Elisp"))
"An alist mapping major modes symbols to strings (or functions that will
return a string). This changes the 'long' name of a major-mode, allowing for
shorter major mode name in the mode-line. See `doom|set-mode-name'.")
;;
(defvar doom-init-ui-hook nil
"List of hooks to run when the UI has been initialized.")
(setq-default
ansi-color-for-comint-mode t
bidi-display-reordering nil ; disable bidirectional text for tiny performance boost
blink-matching-paren nil ; don't blink--too distracting
compilation-always-kill t ; kill compilation process before starting another
compilation-ask-about-save nil ; save all buffers on `compile'
compilation-scroll-output 'first-error
confirm-nonexistent-file-or-buffer t
confirm-kill-emacs #'doom-quit-p ; custom confirmation when killing Emacs
cursor-in-non-selected-windows nil ; hide cursors in other windows
custom-theme-directory (expand-file-name "themes/" doom-private-dir)
display-line-numbers-width 3
enable-recursive-minibuffers nil
frame-inhibit-implied-resize t
;; remove continuation arrow on right fringe
fringe-indicator-alist
(delq (assq 'continuation fringe-indicator-alist)
fringe-indicator-alist)
highlight-nonselected-windows nil
image-animate-loop t
indicate-buffer-boundaries nil
indicate-empty-lines nil
inhibit-compacting-font-caches t
max-mini-window-height 0.3
mode-line-default-help-echo nil ; disable mode-line mouseovers
mouse-yank-at-point t ; middle-click paste at point, not at click
resize-mini-windows 'grow-only ; Minibuffer resizing
show-help-function nil ; hide :help-echo text
split-width-threshold 160 ; favor horizontal splits
uniquify-buffer-name-style 'forward
use-dialog-box nil ; always avoid GUI
visible-cursor nil
x-stretch-cursor nil
;; `pos-tip' defaults
pos-tip-internal-border-width 6
pos-tip-border-width 1
;; no beeping or blinking please
ring-bell-function #'ignore
visible-bell nil
;; don't resize emacs in steps, it looks weird
window-resize-pixelwise t
frame-resize-pixelwise t)
(fset #'yes-or-no-p #'y-or-n-p) ; y/n instead of yes/no
;;
;; Plugins
;;
;; `avy'
(setq avy-all-windows nil
avy-background t)
;; `all-the-icons'
(def-package! all-the-icons
:commands (all-the-icons-octicon all-the-icons-faicon all-the-icons-fileicon
all-the-icons-wicon all-the-icons-material all-the-icons-alltheicon)
:init
(defun doom*disable-all-the-icons-in-tty (orig-fn &rest args)
(when (display-graphic-p)
(apply orig-fn args)))
:config
;; all-the-icons doesn't work in the terminal, so we "disable" it.
(dolist (fn '(all-the-icons-octicon all-the-icons-material
all-the-icons-faicon all-the-icons-fileicon
all-the-icons-wicon all-the-icons-alltheicon))
(advice-add fn :around #'doom*disable-all-the-icons-in-tty)))
;; `hide-mode-line-mode'
(add-hook 'completion-list-mode-hook #'hide-mode-line-mode)
(add-hook 'Man-mode-hook #'hide-mode-line-mode)
;; `highlight-numbers' -- better number literal fontification in code
(def-package! highlight-numbers
:hook (prog-mode . highlight-numbers-mode)
:config (setq highlight-numbers-generic-regexp "\\_<[[:digit:]]+\\(?:\\.[0-9]*\\)?\\_>"))
;; `highlight-escape-sequences'
(def-package! highlight-escape-sequences
:hook ((prog-mode conf-mode) . highlight-escape-sequences-mode))
;; `rainbow-delimiters' --- helps us distinguish stacked delimiter pairs.
;; Especially in parentheses-drunk languages like Lisp.
(setq rainbow-delimiters-max-face-count 3)
;; `restart-emacs'
(setq restart-emacs--args (list "--restore"))
;; `visual-fill-column' For a distractions-free-like UI, that dynamically
;; resizes margins and can center a buffer.
(setq visual-fill-column-center-text t
visual-fill-column-width
;; take Emacs 26 line numbers into account
(+ (if (boundp 'display-line-numbers) 6 0)
fill-column))
(defun doom*hide-undefined-which-key-binds (bindings)
(cl-loop for bind in bindings
if (or (member (cdr bind) '("Prefix Command" "??"))
(fboundp (intern (cdr bind))))
collect bind))
(advice-add #'which-key--get-current-bindings :filter-return #'doom*hide-undefined-which-key-binds)
(advice-add #'which-key--get-keymap-bindings :filter-return #'doom*hide-undefined-which-key-binds)
;;
;; Built-in packages
;;
;; show typed keystrokes in minibuffer
(defun doom|enable-ui-keystrokes () (setq echo-keystrokes 0.02))
(defun doom|disable-ui-keystrokes () (setq echo-keystrokes 0))
(doom|enable-ui-keystrokes)
;; ...but hide them while isearch is active
(add-hook 'isearch-mode-hook #'doom|disable-ui-keystrokes)
(add-hook 'isearch-mode-end-hook #'doom|enable-ui-keystrokes)
;; Highlights the current line
(def-package! hl-line ; built-in
:hook ((prog-mode text-mode conf-mode) . hl-line-mode)
:config
;; I don't need hl-line showing in other windows. This also offers a small
;; speed boost when buffer is displayed in multiple windows.
(setq hl-line-sticky-flag nil
global-hl-line-sticky-flag nil)
;; On Emacs 26+, when point is on the last line, hl-line highlights bleed into
;; the rest of the window after eob. This is the fix.
(when EMACS26+
(defun doom--line-range ()
(cons (line-beginning-position)
(cond ((let ((eol (line-end-position)))
(and (= eol (point-max))
(/= eol (line-beginning-position))))
(1- (line-end-position)))
((or (eobp)
(= (line-end-position 2) (point-max)))
(line-end-position))
((line-beginning-position 2)))))
(setq hl-line-range-function #'doom--line-range))
;; Disable `hl-line' in evil-visual mode (temporarily). `hl-line' can make the
;; selection region harder to see while in evil visual mode.
(after! evil
(defvar-local doom-buffer-hl-line-mode nil)
(defun doom|disable-hl-line ()
(when hl-line-mode
(setq doom-buffer-hl-line-mode t)
(hl-line-mode -1)))
(defun doom|enable-hl-line-maybe ()
(if doom-buffer-hl-line-mode (hl-line-mode +1)))
(add-hook 'evil-visual-state-entry-hook #'doom|disable-hl-line)
(add-hook 'evil-visual-state-exit-hook #'doom|enable-hl-line-maybe)))
;; undo/redo changes to Emacs' window layout
(def-package! winner
:after-call doom-exit-window-hook
:preface (defvar winner-dont-bind-my-keys t) ; I'll bind keys myself
:config (winner-mode +1))
;; highlight matching delimiters
(def-package! paren
:after-call (after-find-file doom-exit-buffer-hook)
:init
(defun doom|disable-show-paren-mode ()
"Turn off `show-paren-mode' buffer-locally."
(set (make-local-variable 'show-paren-mode) nil))
:config
(setq show-paren-delay 0.1
show-paren-highlight-openparen t
show-paren-when-point-inside-paren t)
(show-paren-mode +1))
;; The native border "consumes" a pixel of the fringe on righter-most splits,
;; `window-divider' does not. Available since Emacs 25.1.
(setq-default window-divider-default-places t
window-divider-default-bottom-width 1
window-divider-default-right-width 1)
(add-hook 'doom-init-ui-hook #'window-divider-mode)
;; remove prompt if the file is opened in other clients
(defun server-remove-kill-buffer-hook ()
(remove-hook 'kill-buffer-query-functions #'server-kill-buffer-query-function))
(add-hook 'server-visit-hook #'server-remove-kill-buffer-hook)
;; `whitespace-mode' (built-in)
(setq whitespace-line-column nil
whitespace-style
'(face indentation tabs tab-mark spaces space-mark newline newline-mark
trailing lines-tail)
whitespace-display-mappings
'((tab-mark ?\t [? ?\t])
(newline-mark ?\n [ ?\n])
(space-mark ?\ [] [?.])))
(defun doom|highlight-non-default-indentation ()
"Highlight whitespace that doesn't match your `indent-tabs-mode' setting."
(unless (or (bound-and-true-p global-whitespace-mode)
(bound-and-true-p whitespace-mode)
(eq indent-tabs-mode (default-value 'indent-tabs-mode))
(eq major-mode 'fundamental-mode)
(derived-mode-p 'special-mode))
(require 'whitespace)
(set (make-local-variable 'whitespace-style)
(if (or (bound-and-true-p whitespace-mode)
(bound-and-true-p whitespace-newline-mode))
(cl-union (if indent-tabs-mode '(tabs tab-mark) '(spaces space-mark))
whitespace-style)
`(face ,@(if indent-tabs-mode '(tabs tab-mark) '(spaces space-mark))
trailing-lines tail)))
(whitespace-mode +1)))
;;
;; Line numbers
;;
;; Emacs 26+ has native line number support, and will ignore nlinum. This is for
;; Emacs 25 users:
(defun doom|enable-line-numbers () (display-line-numbers-mode +1))
(defun doom|disable-line-numbers () (display-line-numbers-mode -1))
;; Line number column. A faster (or equivalent, in the worst case) line number
;; plugin than `linum-mode'.
(def-package! nlinum
:when (get 'display-line-numbers 'nlinum)
:commands nlinum-mode
:init
(defvar doom-line-number-lpad 4
"How much padding to place before line numbers.")
(defvar doom-line-number-rpad 1
"How much padding to place after line numbers.")
(defvar doom-line-number-pad-char 32
"Character to use for padding line numbers.
By default, this is a space character. If you use `whitespace-mode' with
`space-mark', the whitespace in line numbers will be affected (this can look
ugly). In this case, you can change this to ?\u2002, which is a unicode
character that looks like a space that `whitespace-mode' won't affect.")
:config
(setq nlinum-highlight-current-line t)
;; Fix lingering hl-line overlays (caused by nlinum)
(add-hook! 'hl-line-mode-hook
(remove-overlays (point-min) (point-max) 'face 'hl-line))
(defun doom-nlinum-format-fn (line _width)
"A more customizable `nlinum-format-function'. See `doom-line-number-lpad',
`doom-line-number-rpad' and `doom-line-number-pad-char'. Allows a fix for
`whitespace-mode' space-marks appearing inside the line number."
(let ((str (number-to-string line)))
(setq str (concat (make-string (max 0 (- doom-line-number-lpad (length str)))
doom-line-number-pad-char)
str
(make-string doom-line-number-rpad doom-line-number-pad-char)))
(put-text-property 0 (length str) 'face
(if (and nlinum-highlight-current-line
(= line nlinum--current-line))
'nlinum-current-line
'linum)
str)
str))
(setq nlinum-format-function #'doom-nlinum-format-fn)
(defun doom|init-nlinum-width ()
"Calculate line number column width beforehand (optimization)."
(setq nlinum--width
(length (save-excursion (goto-char (point-max))
(format-mode-line "%l")))))
(add-hook 'nlinum-mode-hook #'doom|init-nlinum-width))
;; Fixes disappearing line numbers in nlinum and other quirks
(def-package! nlinum-hl
:when (get 'display-line-numbers 'nlinum)
:after nlinum
:config
;; With `markdown-fontify-code-blocks-natively' enabled in `markdown-mode',
;; line numbers tend to vanish next to code blocks.
(advice-add #'markdown-fontify-code-block-natively
:after #'nlinum-hl-do-markdown-fontify-region)
;; When using `web-mode's code-folding an entire range of line numbers will
;; vanish in the affected area.
(advice-add #'web-mode-fold-or-unfold :after #'nlinum-hl-do-generic-flush)
;; Changing fonts can leave nlinum line numbers in their original size; this
;; forces them to resize.
(advice-add #'set-frame-font :after #'nlinum-hl-flush-all-windows))
(def-package! nlinum-relative
:when (get 'display-line-numbers 'nlinum)
:commands (nlinum-relative-mode nlinum-relative-on nlinum-relative-off)
:config
(setq nlinum-format " %d ")
(add-hook 'evil-mode #'nlinum-relative-setup-evil))
;;
;; Theme & font
;;
(defvar doom-last-window-system
(if (daemonp) 'daemon initial-window-system)
"The `window-system' of the last frame. If this doesn't match the current
frame's window-system, the theme will be reloaded.")
(defun doom|init-fonts ()
"Initialize fonts."
(condition-case e
(custom-set-faces
(when (fontp doom-font)
(let ((xlfd (font-xlfd-name doom-font)))
(add-to-list 'default-frame-alist (cons 'font xlfd))
`(fixed-pitch ((t (:font ,xlfd))))))
(when (fontp doom-variable-pitch-font)
`(variable-pitch ((t (:font ,(font-xlfd-name doom-variable-pitch-font))))))
;; Fallback to `doom-unicode-font' for Unicode characters
(when (fontp doom-unicode-font)
(set-fontset-font t nil doom-unicode-font nil 'append)
nil))
((debug error)
(if (string-prefix-p "Font not available: " (error-message-string e))
(lwarn 'doom-ui :warning
"Could not find the '%s' font on your system, falling back to system font"
(font-get (caddr e) :family))
(lwarn 'doom-ui :error
"Unexpected error while initializing fonts: %s"
(error-message-string e))))))
(defun doom|init-theme ()
"Set the theme and load the font, in that order."
(when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
(load-theme doom-theme t)))
;; Getting themes to remain consistent across GUI Emacs, terminal Emacs and
;; daemon Emacs is hairy. `doom|init-theme' sorts out the initial GUI frame.
;; Attaching `doom|init-theme-in-frame' to `after-make-frame-functions' sorts
;; out daemon and emacsclient frames.
;;
;; There will still be issues with simultaneous gui and terminal (emacsclient)
;; frames, however. There's always `doom/reload-theme' if you need it!
(defun doom|reload-theme-in-frame-maybe (frame)
"Reloads the theme in new daemon or tty frames."
(when (and doom-theme
(framep frame)
(not (eq doom-last-window-system (framep-on-display frame))))
(with-selected-frame frame
(load-theme doom-theme t))
(setq doom-last-window-system (framep-on-display frame))))
(defun doom|reload-theme-maybe (_frame)
"Reloads the theme after closing the last frame of a type."
(unless (cl-find doom-last-window-system (frame-list) :key #'framep-on-display)
(setq doom-last-window-system nil)
(doom|reload-theme-in-frame (selected-frame))))
;; fonts
(add-hook 'doom-init-ui-hook #'doom|init-fonts)
;; themes
(add-hook 'doom-init-ui-hook #'doom|init-theme)
(add-hook 'after-make-frame-functions #'doom|reload-theme-in-frame-maybe)
(add-hook 'after-delete-frame-functions #'doom|reload-theme-maybe)
;;
;; Bootstrap
;;
;; simple name in frame title
(setq frame-title-format '("%b Doom Emacs"))
;; draw me like one of your French editors
(tooltip-mode -1) ; relegate tooltips to echo area only
;; a good indicator that Emacs isn't frozen
(add-hook 'doom-init-ui-hook #'blink-cursor-mode)
;; line numbers in most modes
(add-hook! (prog-mode text-mode conf-mode) #'display-line-numbers-mode)
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
(add-to-list 'default-frame-alist (cons 'buffer-predicate #'doom-buffer-frame-predicate))
;; Prevent the glimpse of un-styled Emacs by setting these early.
(add-to-list 'default-frame-alist '(tool-bar-lines 0))
(add-to-list 'default-frame-alist '(menu-bar-lines 0))
(add-to-list 'default-frame-alist '(vertical-scroll-bars))
;; prompts the user for confirmation when deleting a non-empty frame
(global-set-key [remap delete-frame] #'doom/delete-frame)
(defun doom|no-fringes-in-minibuffer (&rest _)
"Disable fringes in the minibuffer window."
(set-window-fringes (minibuffer-window) 0 0 nil))
(add-hook! '(doom-init-ui-hook minibuffer-setup-hook window-configuration-change-hook)
#'doom|no-fringes-in-minibuffer)
(defun doom|set-mode-name ()
"Set the major mode's `mode-name', as dictated by `doom-major-mode-names'."
(when-let* ((name (cdr (assq major-mode doom-major-mode-names))))
(setq mode-name
(cond ((functionp name) (funcall name))
((stringp name) name)
((error "'%s' isn't a valid name for %s" name major-mode))))))
(defun doom|protect-visible-buffer ()
"Don't kill the current buffer if it is visible in another window (bury it
instead). Meant for `kill-buffer-query-functions'."
(not (and (delq (selected-window) (get-buffer-window-list nil nil t))
(not (member (substring (buffer-name) 0 1) '(" " "*"))))))
(defun doom|protect-fallback-buffer ()
"Don't kill the scratch buffer. Meant for `kill-buffer-query-functions'."
(not (eq (current-buffer) (doom-fallback-buffer))))
(defun doom|init-ui ()
"Initialize Doom's user interface by applying all its advice and hooks."
(add-to-list 'kill-buffer-query-functions #'doom|protect-fallback-buffer nil #'eq)
(add-to-list 'kill-buffer-query-functions #'doom|protect-visible-buffer nil #'eq)
(add-hook 'after-change-major-mode-hook #'doom|set-mode-name)
(add-hook 'after-change-major-mode-hook #'doom|highlight-non-default-indentation)
(add-hook 'compilation-filter-hook #'doom|apply-ansi-color-to-compilation-buffer)
;;
(run-hook-wrapped 'doom-init-ui-hook #'doom-try-run-hook))
(add-hook 'emacs-startup-hook #'doom|init-ui)
;;
;; Fixes/hacks
;;
;; doesn't exist in terminal Emacs; we define it to prevent errors
(unless (fboundp 'define-fringe-bitmap)
(defun define-fringe-bitmap (&rest _)))
(defun doom*disable-old-themes-first (orig-fn &rest args)
(mapc #'disable-theme custom-enabled-themes)
(apply orig-fn args)
(when (fboundp 'powerline-reset)
(powerline-reset)))
(advice-add #'load-theme :around #'doom*disable-old-themes-first)
(defun doom|disable-whitespace-mode-in-childframes (frame)
(when (frame-parameter frame 'parent-frame)
(with-selected-frame frame
(setq-local whitespace-style nil)
frame)))
(add-hook 'after-make-frame-functions #'doom|disable-whitespace-mode-in-childframes)
;; Disruptive motion errors take over the minibuffer while we're typing there;
;; prevent this from happening.
(defun doom*silence-motion-errors (orig-fn &rest args)
(if (not (minibufferp))
(apply orig-fn args)
(ignore-errors (apply orig-fn args))
(when (<= (point) (minibuffer-prompt-end))
(goto-char (minibuffer-prompt-end)))))
(advice-add #'left-char :around #'doom*silence-motion-errors)
(advice-add #'right-char :around #'doom*silence-motion-errors)
(advice-add #'delete-backward-char :around #'doom*silence-motion-errors)
(advice-add #'backward-kill-sentence :around #'doom*silence-motion-errors)
(defun doom*no-fringes-in-which-key-buffer (&rest _)
(doom|no-fringes-in-minibuffer)
(set-window-fringes (get-buffer-window which-key--buffer) 0 0 nil))
(advice-add 'which-key--show-buffer-side-window :after #'doom*no-fringes-in-which-key-buffer)
;; Switch to `doom-fallback-buffer' if on last real buffer
(advice-add #'kill-this-buffer :around #'doom*switch-to-fallback-buffer-maybe)
(provide 'core-ui)
;;; core-ui.el ends here