592 lines
24 KiB
EmacsLisp
592 lines
24 KiB
EmacsLisp
;;; core-editor.el -*- lexical-binding: t; -*-
|
|
|
|
(defvar doom-detect-indentation-excluded-modes '(fundamental-mode so-long-mode)
|
|
"A list of major modes in which indentation should be automatically
|
|
detected.")
|
|
|
|
(defvar-local doom-inhibit-indent-detection nil
|
|
"A buffer-local flag that indicates whether `dtrt-indent' should try to detect
|
|
indentation settings or not. This should be set by editorconfig if it
|
|
successfully sets indent_style/indent_size.")
|
|
|
|
(defvar doom-inhibit-large-file-detection nil
|
|
"If non-nil, inhibit large/long file detection when opening files.")
|
|
|
|
(defvar doom-large-file-p nil)
|
|
(put 'doom-large-file-p 'permanent-local t)
|
|
|
|
(defvar doom-large-file-size-alist '(("." . 1.0))
|
|
"An alist mapping regexps (like `auto-mode-alist') to filesize thresholds.
|
|
|
|
If a file is opened and discovered to be larger than the threshold, Doom
|
|
performs emergency optimizations to prevent Emacs from hanging, crashing or
|
|
becoming unusably slow.
|
|
|
|
These thresholds are in MB, and is used by `doom--optimize-for-large-files-a'.")
|
|
|
|
(defvar doom-large-file-excluded-modes
|
|
'(so-long-mode special-mode archive-mode tar-mode jka-compr
|
|
git-commit-mode image-mode doc-view-mode doc-view-mode-maybe
|
|
ebrowse-tree-mode pdf-view-mode tags-table-mode)
|
|
"Major modes that `doom-check-large-file-h' will ignore.")
|
|
|
|
|
|
;;
|
|
;;; File handling
|
|
|
|
(defadvice! doom--prepare-for-large-files-a (size _ filename &rest _)
|
|
"Sets `doom-large-file-p' if the file is considered large.
|
|
|
|
Uses `doom-large-file-size-alist' to determine when a file is too large. When
|
|
`doom-large-file-p' is set, other plugins can detect this and reduce their
|
|
runtime costs (or disable themselves) to ensure the buffer is as fast as
|
|
possible."
|
|
:before #'abort-if-file-too-large
|
|
(and (numberp size)
|
|
(null doom-inhibit-large-file-detection)
|
|
(ignore-errors
|
|
(> size
|
|
(* 1024 1024
|
|
(assoc-default filename doom-large-file-size-alist
|
|
#'string-match-p))))
|
|
(setq-local doom-large-file-p size)))
|
|
|
|
(add-hook! 'find-file-hook
|
|
(defun doom-optimize-for-large-files-h ()
|
|
"Trigger `so-long-minor-mode' if the file is large."
|
|
(when (and doom-large-file-p buffer-file-name)
|
|
(if (or doom-inhibit-large-file-detection
|
|
(memq major-mode doom-large-file-excluded-modes))
|
|
(kill-local-variable 'doom-large-file-p)
|
|
(when (fboundp 'so-long-minor-mode) ; in case the user disabled it
|
|
(so-long-minor-mode +1))
|
|
(message "Large file detected! Cutting a few corners to improve performance...")))))
|
|
|
|
|
|
;; Resolve symlinks when opening files, so that any operations are conducted
|
|
;; from the file's true directory (like `find-file').
|
|
(setq find-file-visit-truename t
|
|
vc-follow-symlinks t)
|
|
|
|
;; Disable the warning "X and Y are the same file". It's fine to ignore this
|
|
;; warning as it will redirect you to the existing buffer anyway.
|
|
(setq find-file-suppress-same-file-warnings t)
|
|
|
|
;; Don't generate backups or lockfiles. While auto-save maintains a copy so long
|
|
;; as a buffer is unsaved, backups create copies once, when the file is first
|
|
;; written, and never again until it is killed and reopened. This is better
|
|
;; suited to version control, and I don't want world-readable copies of
|
|
;; potentially sensitive material floating around our filesystem.
|
|
(setq create-lockfiles nil
|
|
make-backup-files nil
|
|
;; But in case the user does enable it, some sensible defaults:
|
|
version-control t ; number each backup file
|
|
backup-by-copying t ; instead of renaming current file (clobbers links)
|
|
delete-old-versions t ; clean up after itself
|
|
kept-old-versions 5
|
|
kept-new-versions 5
|
|
backup-directory-alist (list (cons "." (concat doom-cache-dir "backup/")))
|
|
tramp-backup-directory-alist backup-directory-alist)
|
|
|
|
;; But turn on auto-save, so we have a fallback in case of crashes or lost data.
|
|
;; Use `recover-file' or `recover-session' to recover them.
|
|
(setq auto-save-default t
|
|
;; Don't auto-disable auto-save after deleting big chunks. This defeats
|
|
;; the purpose of a failsafe. This adds the risk of losing the data we
|
|
;; just deleted, but I believe that's VCS's jurisdiction, not ours.
|
|
auto-save-include-big-deletions t
|
|
;; Keep it out of `doom-emacs-dir' or the local directory.
|
|
auto-save-list-file-prefix (concat doom-cache-dir "autosave/")
|
|
tramp-auto-save-directory (concat doom-cache-dir "tramp-autosave/")
|
|
auto-save-file-name-transforms
|
|
(list (list "\\`/[^/]*:\\([^/]*/\\)*\\([^/]*\\)\\'"
|
|
;; Prefix tramp autosaves to prevent conflicts with local ones
|
|
(concat auto-save-list-file-prefix "tramp-\\2") t)
|
|
(list ".*" auto-save-list-file-prefix t)))
|
|
|
|
(add-hook! 'after-save-hook
|
|
(defun doom-guess-mode-h ()
|
|
"Guess major mode when saving a file in `fundamental-mode'.
|
|
|
|
Likely, something has changed since the buffer was opened. e.g. A shebang line
|
|
or file path may exist now."
|
|
(when (eq major-mode 'fundamental-mode)
|
|
(let ((buffer (or (buffer-base-buffer) (current-buffer))))
|
|
(and (buffer-file-name buffer)
|
|
(eq buffer (window-buffer (selected-window))) ; only visible buffers
|
|
(set-auto-mode))))))
|
|
|
|
|
|
;;
|
|
;;; Formatting
|
|
|
|
;; Favor spaces over tabs. Pls dun h8, but I think spaces (and 4 of them) is a
|
|
;; more consistent default than 8-space tabs. It can be changed on a per-mode
|
|
;; basis anyway (and is, where tabs are the canonical style, like go-mode).
|
|
(setq-default indent-tabs-mode nil
|
|
tab-width 4)
|
|
|
|
;; Only indent the line when at BOL or in a line's indentation. Anywhere else,
|
|
;; insert literal indentation.
|
|
(setq-default tab-always-indent nil)
|
|
|
|
;; Make `tabify' and `untabify' only affect indentation. Not tabs/spaces in the
|
|
;; middle of a line.
|
|
(setq tabify-regexp "^\t* [ \t]+")
|
|
|
|
;; An archaic default in the age of widescreen 4k displays? I disagree. We still
|
|
;; frequently split our terminals and editor frames, or have them side-by-side,
|
|
;; using up more of that newly available horizontal real-estate.
|
|
(setq-default fill-column 80)
|
|
|
|
;; Continue wrapped words at whitespace, rather than in the middle of a word.
|
|
(setq-default word-wrap t)
|
|
;; ...but don't do any wrapping by default. It's expensive. Enable
|
|
;; `visual-line-mode' if you want soft line-wrapping. `auto-fill-mode' for hard
|
|
;; line-wrapping.
|
|
(setq-default truncate-lines t)
|
|
;; If enabled (and `truncate-lines' was disabled), soft wrapping no longer
|
|
;; occurs when that window is less than `truncate-partial-width-windows'
|
|
;; characters wide. We don't need this, and it's extra work for Emacs otherwise,
|
|
;; so off it goes.
|
|
(setq truncate-partial-width-windows nil)
|
|
|
|
;; This was a widespread practice in the days of typewriters. I actually prefer
|
|
;; it when writing prose with monospace fonts, but it is obsolete otherwise.
|
|
(setq sentence-end-double-space nil)
|
|
|
|
;; The POSIX standard defines a line is "a sequence of zero or more non-newline
|
|
;; characters followed by a terminating newline", so files should end in a
|
|
;; newline. Windows doesn't respect this (because it's Windows), but we should,
|
|
;; since programmers' tools tend to be POSIX compliant (and no big deal if not).
|
|
(setq require-final-newline t)
|
|
|
|
;; Default to soft line-wrapping in text modes. It is more sensibile for text
|
|
;; modes, even if hard wrapping is more performant.
|
|
(add-hook 'text-mode-hook #'visual-line-mode)
|
|
|
|
|
|
;;
|
|
;;; Clipboard / kill-ring
|
|
|
|
;; Cull duplicates in the kill ring to reduce bloat and make the kill ring
|
|
;; easier to peruse (with `counsel-yank-pop' or `helm-show-kill-ring'.
|
|
(setq kill-do-not-save-duplicates t)
|
|
|
|
;; Allow UTF or composed text from the clipboard, even in the terminal or on
|
|
;; non-X systems (like Windows or macOS), where only `STRING' is used.
|
|
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
|
|
|
|
|
|
;;
|
|
;;; Extra file extensions to support
|
|
|
|
(nconc
|
|
auto-mode-alist
|
|
'(("/LICENSE\\'" . text-mode)
|
|
("\\.log\\'" . text-mode)
|
|
("rc\\'" . conf-mode)
|
|
("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode)))
|
|
|
|
|
|
;;
|
|
;;; Built-in plugins
|
|
|
|
(use-package! autorevert
|
|
;; revert buffers when their files/state have changed
|
|
:hook (focus-in . doom-auto-revert-buffers-h)
|
|
:hook (after-save . doom-auto-revert-buffers-h)
|
|
:hook (doom-switch-buffer . doom-auto-revert-buffer-h)
|
|
:hook (doom-switch-window . doom-auto-revert-buffer-h)
|
|
:config
|
|
(setq auto-revert-verbose t ; let us know when it happens
|
|
auto-revert-use-notify nil
|
|
auto-revert-stop-on-user-input nil
|
|
;; Only prompts for confirmation when buffer is unsaved.
|
|
revert-without-query (list "."))
|
|
|
|
;; `auto-revert-mode' and `global-auto-revert-mode' would, normally, abuse the
|
|
;; heck out of inotify handles _or_ aggresively poll your buffer list every X
|
|
;; seconds. Too many inotify handles can grind Emacs to a halt if you preform
|
|
;; expensive or batch processes on files outside of Emacs (e.g. their mtime
|
|
;; changes), and polling your buffer list is terribly inefficient as your
|
|
;; buffer list grows into the tens or hundreds.
|
|
;;
|
|
;; So Doom uses a different strategy: we lazily auto revert buffers when the
|
|
;; user a) saves a file, b) switches to a buffer (or its window), or c) you
|
|
;; focus Emacs (after using another program). This way, Emacs only ever has to
|
|
;; operate on, at minimum, a single buffer and, at maximum, X buffers, where X
|
|
;; is the number of open windows (which is rarely, if ever, over 10).
|
|
(defun doom-auto-revert-buffer-h ()
|
|
"Auto revert current buffer, if necessary."
|
|
(unless (or auto-revert-mode (active-minibuffer-window))
|
|
(let ((auto-revert-mode t))
|
|
(auto-revert-handler))))
|
|
|
|
(defun doom-auto-revert-buffers-h ()
|
|
"Auto revert stale buffers in visible windows, if necessary."
|
|
(dolist (buf (doom-visible-buffers))
|
|
(with-current-buffer buf
|
|
(doom-auto-revert-buffer-h)))))
|
|
|
|
|
|
(use-package! recentf
|
|
;; Keep track of recently opened files
|
|
:defer-incrementally easymenu tree-widget timer
|
|
:hook (doom-first-file . recentf-mode)
|
|
:commands recentf-open-files
|
|
:config
|
|
(defun doom--recent-file-truename (file)
|
|
(if (or (file-remote-p file nil t)
|
|
(not (file-remote-p file)))
|
|
(file-truename file)
|
|
file))
|
|
(setq recentf-filename-handlers
|
|
'(;; Text properties inflate the size of recentf's files, and there is
|
|
;; no purpose in persisting them, so we strip them out.
|
|
substring-no-properties
|
|
;; Resolve symlinks of local files. Otherwise we get duplicate
|
|
;; entries opening symlinks.
|
|
doom--recent-file-truename
|
|
;; Replace $HOME with ~, which is more portable, and reduces how much
|
|
;; horizontal space the recentf listing uses to list recent files.
|
|
abbreviate-file-name)
|
|
recentf-save-file (concat doom-cache-dir "recentf")
|
|
recentf-auto-cleanup 'never
|
|
recentf-max-menu-items 0
|
|
recentf-max-saved-items 200)
|
|
|
|
(add-hook! '(doom-switch-window-hook write-file-functions)
|
|
(defun doom--recentf-touch-buffer-h ()
|
|
"Bump file in recent file list when it is switched or written to."
|
|
(when buffer-file-name
|
|
(recentf-add-file buffer-file-name))
|
|
;; Return nil for `write-file-functions'
|
|
nil))
|
|
|
|
(add-hook! 'dired-mode-hook
|
|
(defun doom--recentf-add-dired-directory-h ()
|
|
"Add dired directory to recentf file list."
|
|
(recentf-add-file default-directory)))
|
|
|
|
(add-hook 'kill-emacs-hook #'recentf-cleanup)
|
|
(advice-add #'recentf-load-list :around #'doom-shut-up-a))
|
|
|
|
|
|
(use-package! savehist
|
|
;; persist variables across sessions
|
|
:defer-incrementally custom
|
|
:hook (doom-first-input . savehist-mode)
|
|
:init
|
|
(setq savehist-file (concat doom-cache-dir "savehist"))
|
|
:config
|
|
(setq savehist-save-minibuffer-history t
|
|
savehist-autosave-interval nil ; save on kill only
|
|
savehist-additional-variables
|
|
'(kill-ring ; persist clipboard
|
|
mark-ring global-mark-ring ; persist marks
|
|
search-ring regexp-search-ring)) ; persist searches
|
|
(add-hook! 'savehist-save-hook
|
|
(defun doom-unpropertize-kill-ring-h ()
|
|
"Remove text properties from `kill-ring' for a smaller savehist file."
|
|
(setq kill-ring (cl-loop for item in kill-ring
|
|
if (stringp item)
|
|
collect (substring-no-properties item)
|
|
else if item collect it)))))
|
|
|
|
|
|
(use-package! saveplace
|
|
;; persistent point location in buffers
|
|
:hook (doom-first-file . save-place-mode)
|
|
:init
|
|
(setq save-place-file (concat doom-cache-dir "saveplace")
|
|
save-place-limit 100)
|
|
:config
|
|
(defadvice! doom--recenter-on-load-saveplace-a (&rest _)
|
|
"Recenter on cursor when loading a saved place."
|
|
:after-while #'save-place-find-file-hook
|
|
(if buffer-file-name (ignore-errors (recenter))))
|
|
|
|
(defadvice! doom--inhibit-saveplace-in-long-files-a (orig-fn &rest args)
|
|
:around #'save-place-to-alist
|
|
(unless doom-large-file-p
|
|
(apply orig-fn args)))
|
|
|
|
(defadvice! doom--dont-prettify-saveplace-cache-a (orig-fn)
|
|
"`save-place-alist-to-file' uses `pp' to prettify the contents of its cache.
|
|
`pp' can be expensive for longer lists, and there's no reason to prettify cache
|
|
files, so we replace calls to `pp' with the much faster `prin1'."
|
|
:around #'save-place-alist-to-file
|
|
(letf! ((#'pp #'prin1)) (funcall orig-fn))))
|
|
|
|
|
|
(use-package! server
|
|
:when (display-graphic-p)
|
|
:after-call pre-command-hook after-find-file focus-out-hook
|
|
:defer 1
|
|
:init
|
|
(when-let (name (getenv "EMACS_SERVER_NAME"))
|
|
(setq server-name name))
|
|
:config
|
|
(setq server-auth-dir (concat doom-emacs-dir "server/"))
|
|
(unless (server-running-p)
|
|
(server-start)))
|
|
|
|
|
|
;;
|
|
;;; Packages
|
|
|
|
(use-package! better-jumper
|
|
:hook (doom-first-input . better-jumper-mode)
|
|
:commands doom-set-jump-a doom-set-jump-maybe-a doom-set-jump-h
|
|
:preface
|
|
;; REVIEW Suppress byte-compiler warning spawning a *Compile-Log* buffer at
|
|
;; startup. This can be removed once gilbertw1/better-jumper#2 is merged.
|
|
(defvar better-jumper-local-mode nil)
|
|
:init
|
|
(global-set-key [remap evil-jump-forward] #'better-jumper-jump-forward)
|
|
(global-set-key [remap evil-jump-backward] #'better-jumper-jump-backward)
|
|
(global-set-key [remap xref-pop-marker-stack] #'better-jumper-jump-backward)
|
|
:config
|
|
(defun doom-set-jump-a (orig-fn &rest args)
|
|
"Set a jump point and ensure ORIG-FN doesn't set any new jump points."
|
|
(better-jumper-set-jump (if (markerp (car args)) (car args)))
|
|
(let ((evil--jumps-jumping t)
|
|
(better-jumper--jumping t))
|
|
(apply orig-fn args)))
|
|
|
|
(defun doom-set-jump-maybe-a (orig-fn &rest args)
|
|
"Set a jump point if ORIG-FN returns non-nil."
|
|
(let ((origin (point-marker))
|
|
(result
|
|
(let* ((evil--jumps-jumping t)
|
|
(better-jumper--jumping t))
|
|
(apply orig-fn args))))
|
|
(unless result
|
|
(with-current-buffer (marker-buffer origin)
|
|
(better-jumper-set-jump
|
|
(if (markerp (car args))
|
|
(car args)
|
|
origin))))
|
|
result))
|
|
|
|
(defun doom-set-jump-h ()
|
|
"Run `better-jumper-set-jump' but return nil, for short-circuiting hooks."
|
|
(better-jumper-set-jump)
|
|
nil)
|
|
|
|
;; Creates a jump point before killing a buffer. This allows you to undo
|
|
;; killing a buffer easily (only works with file buffers though; it's not
|
|
;; possible to resurrect special buffers).
|
|
(advice-add #'kill-current-buffer :around #'doom-set-jump-a)
|
|
|
|
;; Create a jump point before jumping with imenu.
|
|
(advice-add #'imenu :around #'doom-set-jump-a))
|
|
|
|
|
|
(use-package! dtrt-indent
|
|
;; Automatic detection of indent settings
|
|
:when doom-interactive-p
|
|
:hook ((change-major-mode-after-body read-only-mode) . doom-detect-indentation-h)
|
|
:config
|
|
(defun doom-detect-indentation-h ()
|
|
(unless (or (not after-init-time)
|
|
doom-inhibit-indent-detection
|
|
doom-large-file-p
|
|
(memq major-mode doom-detect-indentation-excluded-modes)
|
|
(member (substring (buffer-name) 0 1) '(" " "*")))
|
|
;; Don't display messages in the echo area, but still log them
|
|
(let ((inhibit-message (not doom-debug-p)))
|
|
(dtrt-indent-mode +1))))
|
|
|
|
;; Enable dtrt-indent even in smie modes so that it can update `tab-width',
|
|
;; `standard-indent' and `evil-shift-width' there as well.
|
|
(setq dtrt-indent-run-after-smie t)
|
|
;; Reduced from the default of 5000 for slightly faster analysis
|
|
(setq dtrt-indent-max-lines 2000)
|
|
|
|
;; always keep tab-width up-to-date
|
|
(push '(t tab-width) dtrt-indent-hook-generic-mapping-list)
|
|
|
|
(defvar dtrt-indent-run-after-smie)
|
|
(defadvice! doom--fix-broken-smie-modes-a (orig-fn arg)
|
|
"Some smie modes throw errors when trying to guess their indentation, like
|
|
`nim-mode'. This prevents them from leaving Emacs in a broken state."
|
|
:around #'dtrt-indent-mode
|
|
(let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie))
|
|
(letf! ((defun symbol-config--guess (beg end)
|
|
(funcall symbol-config--guess beg (min end 10000)))
|
|
(defun smie-config-guess ()
|
|
(condition-case e (funcall smie-config-guess)
|
|
(error (setq dtrt-indent-run-after-smie t)
|
|
(message "[WARNING] Indent detection: %s"
|
|
(error-message-string e))
|
|
(message ""))))) ; warn silently
|
|
(funcall orig-fn arg)))))
|
|
|
|
|
|
(use-package! helpful
|
|
;; a better *help* buffer
|
|
:commands helpful--read-symbol
|
|
:init
|
|
;; Make `apropos' et co search more extensively. They're more useful this way.
|
|
(setq apropos-do-all t)
|
|
|
|
(global-set-key [remap describe-function] #'helpful-callable)
|
|
(global-set-key [remap describe-command] #'helpful-command)
|
|
(global-set-key [remap describe-variable] #'helpful-variable)
|
|
(global-set-key [remap describe-key] #'helpful-key)
|
|
(global-set-key [remap describe-symbol] #'helpful-symbol)
|
|
|
|
(defun doom-use-helpful-a (orig-fn &rest args)
|
|
"Force ORIG-FN to use helpful instead of the old describe-* commands."
|
|
(letf! ((#'describe-function #'helpful-function)
|
|
(#'describe-variable #'helpful-variable))
|
|
(apply orig-fn args)))
|
|
|
|
(after! apropos
|
|
;; patch apropos buttons to call helpful instead of help
|
|
(dolist (fun-bt '(apropos-function apropos-macro apropos-command))
|
|
(button-type-put
|
|
fun-bt 'action
|
|
(lambda (button)
|
|
(helpful-callable (button-get button 'apropos-symbol)))))
|
|
(dolist (var-bt '(apropos-variable apropos-user-option))
|
|
(button-type-put
|
|
var-bt 'action
|
|
(lambda (button)
|
|
(helpful-variable (button-get button 'apropos-symbol)))))))
|
|
|
|
|
|
;;;###package imenu
|
|
(add-hook 'imenu-after-jump-hook #'recenter)
|
|
|
|
|
|
(use-package! smartparens
|
|
;; Auto-close delimiters and blocks as you type. It's more powerful than that,
|
|
;; but that is all Doom uses it for.
|
|
:hook (doom-first-buffer . smartparens-global-mode)
|
|
:commands sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string
|
|
:config
|
|
;; smartparens recognizes `slime-mrepl-mode', but not `sly-mrepl-mode', so...
|
|
(add-to-list 'sp-lisp-modes 'sly-mrepl-mode)
|
|
;; Load default smartparens rules for various languages
|
|
(require 'smartparens-config)
|
|
;; Overlays are too distracting and not terribly helpful. show-parens does
|
|
;; this for us already (and is faster), so...
|
|
(setq sp-highlight-pair-overlay nil
|
|
sp-highlight-wrap-overlay nil
|
|
sp-highlight-wrap-tag-overlay nil)
|
|
(with-eval-after-load 'evil
|
|
;; But if someone does want overlays enabled, evil users will be stricken
|
|
;; with an off-by-one issue where smartparens assumes you're outside the
|
|
;; pair when you're really at the last character in insert mode. We must
|
|
;; correct this vile injustice.
|
|
(setq sp-show-pair-from-inside t)
|
|
;; ...and stay highlighted until we've truly escaped the pair!
|
|
(setq sp-cancel-autoskip-on-backward-movement nil)
|
|
;; Smartparens conditional binds a key to C-g when sp overlays are active
|
|
;; (even if they're invisible). This disruptively changes the behavior of
|
|
;; C-g in insert mode, requiring two presses of the key to exit insert mode.
|
|
;; I don't see the point of this keybind, so...
|
|
(setq sp-pair-overlay-keymap (make-sparse-keymap)))
|
|
|
|
;; The default is 100, because smartparen's scans are relatively expensive
|
|
;; (especially with large pair lists for some modes), we reduce it, as a
|
|
;; better compromise between performance and accuracy.
|
|
(setq sp-max-prefix-length 25)
|
|
;; No pair has any business being longer than 4 characters; if they must, set
|
|
;; it buffer-locally. It's less work for smartparens.
|
|
(setq sp-max-pair-length 4)
|
|
|
|
;; Silence some harmless but annoying echo-area spam
|
|
(dolist (key '(:unmatched-expression :no-matching-tag))
|
|
(setf (alist-get key sp-message-alist) nil))
|
|
|
|
(add-hook! 'eval-expression-minibuffer-setup-hook
|
|
(defun doom-init-smartparens-in-eval-expression-h ()
|
|
"Enable `smartparens-mode' in the minibuffer for `eval-expression'.
|
|
This includes everything that calls `read--expression', e.g.
|
|
`edebug-eval-expression' Only enable it if
|
|
`smartparens-global-mode' is on."
|
|
(when smartparens-global-mode (smartparens-mode +1))))
|
|
(add-hook! 'minibuffer-setup-hook
|
|
(defun doom-init-smartparens-in-minibuffer-maybe-h ()
|
|
"Enable `smartparens' for non-`eval-expression' commands.
|
|
Only enable `smartparens-mode' if `smartparens-global-mode' is
|
|
on."
|
|
(when (and smartparens-global-mode (memq this-command '(evil-ex)))
|
|
(smartparens-mode +1))))
|
|
|
|
;; You're likely writing lisp in the minibuffer, therefore, disable these
|
|
;; quote pairs, which lisps doesn't use for strings:
|
|
(sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil)
|
|
(sp-local-pair 'minibuffer-inactive-mode "`" nil :actions nil)
|
|
|
|
;; Smartparens breaks evil-mode's replace state
|
|
(defvar doom-buffer-smartparens-mode nil)
|
|
(add-hook! 'evil-replace-state-exit-hook
|
|
(defun doom-enable-smartparens-mode-maybe-h ()
|
|
(when doom-buffer-smartparens-mode
|
|
(turn-on-smartparens-mode)
|
|
(kill-local-variable 'doom-buffer-smartparens-mode))))
|
|
(add-hook! 'evil-replace-state-entry-hook
|
|
(defun doom-disable-smartparens-mode-maybe-h ()
|
|
(when smartparens-mode
|
|
(setq-local doom-buffer-smartparens-mode t)
|
|
(turn-off-smartparens-mode)))))
|
|
|
|
|
|
(use-package! so-long
|
|
:hook (doom-first-file . global-so-long-mode)
|
|
:config
|
|
(setq so-long-threshold 400) ; reduce false positives w/ larger threshold
|
|
;; Don't disable syntax highlighting and line numbers, or make the buffer
|
|
;; read-only, in `so-long-minor-mode', so we can have a basic editing
|
|
;; experience in them, at least. It will remain off in `so-long-mode',
|
|
;; however, because long files have a far bigger impact on Emacs performance.
|
|
(delq! 'font-lock-mode so-long-minor-modes)
|
|
(delq! 'display-line-numbers-mode so-long-minor-modes)
|
|
(delq! 'buffer-read-only so-long-variable-overrides 'assq)
|
|
;; ...but at least reduce the level of syntax highlighting
|
|
(add-to-list 'so-long-variable-overrides '(font-lock-maximum-decoration . 1))
|
|
;; ...and insist that save-place not operate in large/long files
|
|
(add-to-list 'so-long-variable-overrides '(save-place-alist . nil))
|
|
;; But disable everything else that may be unnecessary/expensive for large or
|
|
;; wide buffers.
|
|
(appendq! so-long-minor-modes
|
|
'(flycheck-mode
|
|
flyspell-mode
|
|
spell-fu-mode
|
|
eldoc-mode
|
|
smartparens-mode
|
|
highlight-numbers-mode
|
|
better-jumper-local-mode
|
|
ws-butler-mode
|
|
auto-composition-mode
|
|
undo-tree-mode
|
|
highlight-indent-guides-mode
|
|
hl-fill-column-mode))
|
|
(defun doom-buffer-has-long-lines-p ()
|
|
(unless (bound-and-true-p visual-line-mode)
|
|
(let ((so-long-skip-leading-comments
|
|
;; HACK Fix #2183: `so-long-detected-long-line-p' tries to parse
|
|
;; comment syntax, but comment state may not be initialized,
|
|
;; leading to a wrong-type-argument: stringp error.
|
|
(bound-and-true-p comment-use-syntax)))
|
|
(so-long-detected-long-line-p))))
|
|
(setq so-long-predicate #'doom-buffer-has-long-lines-p))
|
|
|
|
|
|
(use-package! ws-butler
|
|
;; a less intrusive `delete-trailing-whitespaces' on save
|
|
:hook (doom-first-buffer . ws-butler-global-mode)
|
|
:config
|
|
;; ws-butler normally preserves whitespace in the buffer (but strips it from
|
|
;; the written file). While sometimes convenient, this behavior is not
|
|
;; intuitive. To the average user it looks like whitespace cleanup is failing,
|
|
;; which causes folks to redundantly install their own.
|
|
(setq ws-butler-keep-whitespace-before-point nil))
|
|
|
|
(provide 'core-editor)
|
|
;;; core-editor.el ends here
|