Merge pull request #1 from hlissner/develop

merge
This commit is contained in:
xhcoding 2019-03-25 09:58:18 +08:00 committed by GitHub
commit 4c6b9d25c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
162 changed files with 4333 additions and 5028 deletions

View file

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016-2018 Henrik Lissner. Copyright (c) 2016-2019 Henrik Lissner.
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the

View file

@ -30,6 +30,7 @@
" doom run -p ~/.other.doom.d -e ~/.other.emacs.d -nw file.txt\n" " doom run -p ~/.other.doom.d -e ~/.other.emacs.d -nw file.txt\n"
"\n" "\n"
(format! (bold "Options:\n")) (format! (bold "Options:\n"))
" -h --help\t\tSame as help command\n"
" -d --debug\t\tTurns on doom-debug-mode (and debug-on-error)\n" " -d --debug\t\tTurns on doom-debug-mode (and debug-on-error)\n"
" -e --emacsd DIR\tUse the emacs config at DIR (e.g. ~/.emacs.d)\n" " -e --emacsd DIR\tUse the emacs config at DIR (e.g. ~/.emacs.d)\n"
" -i --insecure\t\tDisable TLS/SSL validation (not recommended)\n" " -i --insecure\t\tDisable TLS/SSL validation (not recommended)\n"
@ -46,7 +47,7 @@
(while (ignore-errors (string-prefix-p "-" (car args))) (while (ignore-errors (string-prefix-p "-" (car args)))
(pcase (pop args) (pcase (pop args)
((or "-h" "--help") ((or "-h" "--help")
(error "Did you mean 'doom help'?")) (push "help" args))
((or "-d" "--debug") ((or "-d" "--debug")
(setenv "DEBUG" "1") (setenv "DEBUG" "1")
(message "Debug mode on")) (message "Debug mode on"))

View file

@ -4,17 +4,24 @@
":"; [[ $VERSION == *\ 2[0-2].[0-1].[0-9] ]] && { echo "You're running $VERSION"; echo "That version is too old to run the doctor. Check your PATH"; echo; exit 2; } ":"; [[ $VERSION == *\ 2[0-2].[0-1].[0-9] ]] && { echo "You're running $VERSION"; echo "That version is too old to run the doctor. Check your PATH"; echo; exit 2; }
":"; exec emacs --quick --script "$0"; exit 0 ":"; exec emacs --quick --script "$0"; exit 0
;; Uses a couple simple heuristics to locate issues with your environment that ;; The Doom doctor is essentially one big, self-contained elisp shell script
;; could interfere with running or setting up DOOM Emacs. ;; that uses a series of simple heuristics to diagnose common issues on your
;; system. Issues that could intefere with Doom Emacs.
;;
;; Doom module may optionally have a doctor.el file to run their own heuristics
;; in. Doctor scripts may run in versions of Emacs as old as Emacs 23, so you
;; are limited to very basic standard library calls (e.g. avoid cl, subr-x, and
;; any Doom dependencies).
;; In case it isn't defined (in really old versions of Emacs, like the one that ;; In really old versions of Emacs `user-emacs-directory' isn't defined
;; ships with MacOS).
(defvar user-emacs-directory (expand-file-name "../" (file-name-directory load-file-name))) (defvar user-emacs-directory (expand-file-name "../" (file-name-directory load-file-name)))
(unless (file-directory-p user-emacs-directory) (unless (file-directory-p user-emacs-directory)
(error "Couldn't find a Doom config!")) (error "Couldn't find a Doom config!"))
(unless noninteractive (unless noninteractive
(error "This script must not be run from an interactive session.")) (error "This script must not be run from an interactive session."))
(when (getenv "DEBUG")
(setq debug-on-error t))
(require 'pp) (require 'pp)
@ -117,10 +124,10 @@
;; --- is emacs set up properly? ------------------------------ ;; --- is emacs set up properly? ------------------------------
(when (version< emacs-version "25.1") (when (version< emacs-version "25.3")
(error! "Important: Emacs %s detected [%s]" emacs-version (executable-find "emacs")) (error! "Important: Emacs %s detected [%s]" emacs-version (executable-find "emacs"))
(explain! (explain!
"DOOM only supports >= 25.1. Perhaps your PATH wasn't set up properly." "DOOM only supports >= 25.3. Perhaps your PATH wasn't set up properly."
(when (eq system-type 'darwin) (when (eq system-type 'darwin)
(concat "\nMacOS users should use homebrew (https://brew.sh) to install Emacs\n" (concat "\nMacOS users should use homebrew (https://brew.sh) to install Emacs\n"
" brew install emacs --with-modules --with-imagemagick --with-cocoa")))) " brew install emacs --with-modules --with-imagemagick --with-cocoa"))))
@ -166,7 +173,7 @@
font font-dest) font font-dest)
(explain! "You can install it by running `M-x all-the-icons-install-fonts' within Emacs.\n\n" (explain! "You can install it by running `M-x all-the-icons-install-fonts' within Emacs.\n\n"
"This could also mean you've installed them in non-standard locations, in which " "This could also mean you've installed them in non-standard locations, in which "
"case, ignore this warning.")))))) "case feel free to ignore this warning."))))))
;; gnutls-cli & openssl ;; gnutls-cli & openssl
(section! "Checking gnutls/openssl...") (section! "Checking gnutls/openssl...")
@ -289,6 +296,9 @@
(or (cdr-safe ex) (car ex))) (or (cdr-safe ex) (car ex)))
(setq doom-modules nil))) (setq doom-modules nil)))
(section! "Checking Doom core for irregularities...")
(load (expand-file-name "doctor.el" doom-core-dir) nil 'nomessage)
(when (bound-and-true-p doom-modules) (when (bound-and-true-p doom-modules)
(section! "Checking your enabled modules...") (section! "Checking your enabled modules...")
(let ((indent 4)) (let ((indent 4))
@ -296,22 +306,21 @@
(maphash (maphash
(lambda (key plist) (lambda (key plist)
(let ((prefix (format "%s" (color 1 "(%s %s) " (car key) (cdr key))))) (let ((prefix (format "%s" (color 1 "(%s %s) " (car key) (cdr key)))))
(condition-case ex (condition-case-unless-debug ex
(let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el")) (let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el"))
(packages-file (doom-module-path (car key) (cdr key) "packages.el")) (packages-file (doom-module-path (car key) (cdr key) "packages.el")))
doom-packages) (cl-loop with doom--stage = 'packages
(when (or (file-exists-p doctor-file) for name in (let (doom-packages
(file-exists-p packages-file)) doom-disabled-packages)
(let ((doom--stage 'packages)) (load packages-file 'noerror 'nomessage)
(when (load packages-file t t) (mapcar #'car doom-packages))
(cl-loop for (name . plist) in doom-packages unless (or (doom-package-prop name :disable)
unless (or (doom-package-prop name :disable) (doom-package-prop name :ignore t)
(doom-package-prop name :ignore t) (package-built-in-p name)
(package-built-in-p name) (package-installed-p name))
(package-installed-p name)) do (error! "%s is not installed" name))
do (error! "%s is not installed" name))) (let ((doom--stage 'doctor))
(let ((doom--stage 'doctor)) (load doctor-file 'noerror 'nomessage)))
(load doctor-file t t)))))
(file-missing (error! "%s" (error-message-string ex))) (file-missing (error! "%s" (error-message-string ex)))
(error (error! "Syntax error: %s" ex))))) (error (error! "Syntax error: %s" ex)))))
doom-modules))) doom-modules)))

View file

@ -34,11 +34,6 @@ See `doom-real-buffer-p' for more information.")
"The name of the buffer to fall back to if no other buffers exist (will create "The name of the buffer to fall back to if no other buffers exist (will create
it if it doesn't exist).") it if it doesn't exist).")
;;;###autoload
(defvar doom-cleanup-hook ()
"A list of hooks run when `doom/cleanup-session' is run, meant to clean up
leftover buffers and processes.")
;; ;;
;; Functions ;; Functions
@ -54,7 +49,8 @@ BUF should be skipped over by functions like `next-buffer' and `other-buffer'."
(defun doom-fallback-buffer () (defun doom-fallback-buffer ()
"Returns the fallback buffer, creating it if necessary. By default this is the "Returns the fallback buffer, creating it if necessary. By default this is the
scratch buffer. See `doom-fallback-buffer-name' to change this." scratch buffer. See `doom-fallback-buffer-name' to change this."
(get-buffer-create doom-fallback-buffer-name)) (let (buffer-list-update-hook)
(get-buffer-create doom-fallback-buffer-name)))
;;;###autoload ;;;###autoload
(defalias 'doom-buffer-list #'buffer-list) (defalias 'doom-buffer-list #'buffer-list)
@ -224,15 +220,17 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
(format "Buffer %s is modified; kill anyway?" buf)))) (format "Buffer %s is modified; kill anyway?" buf))))
(message "Aborted") (message "Aborted")
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
(when (or ;; if there aren't more real buffers than visible buffers, (let (buffer-list-update-hook)
;; then there are no real, non-visible buffers left. (when (or ;; if there aren't more real buffers than visible buffers,
(not (cl-set-difference (doom-real-buffer-list) ;; then there are no real, non-visible buffers left.
(doom-visible-buffers))) (not (cl-set-difference (doom-real-buffer-list)
;; if we end up back where we start (or previous-buffer (doom-visible-buffers)))
;; returns nil), we have nowhere left to go ;; if we end up back where we start (or previous-buffer
(memq (previous-buffer) (list buf 'nil))) ;; returns nil), we have nowhere left to go
(switch-to-buffer (doom-fallback-buffer))) (memq (switch-to-prev-buffer nil t) (list buf 'nil)))
(kill-buffer buf))) (switch-to-buffer (doom-fallback-buffer)))
(unless (delq (selected-window) (get-buffer-window-list buf nil t))
(kill-buffer buf)))))
((funcall orig-fn))))) ((funcall orig-fn)))))
@ -254,7 +252,8 @@ If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
(set-buffer-modified-p nil))) (set-buffer-modified-p nil)))
(kill-buffer buffer) (kill-buffer buffer)
(cl-loop for win in windows (cl-loop for win in windows
if (doom-real-buffer-p (window-buffer win)) if (and (window-live-p win)
(doom-unreal-buffer-p (window-buffer win)))
do (with-selected-window win (previous-buffer))))) do (with-selected-window win (previous-buffer)))))
;;;###autoload ;;;###autoload
@ -264,10 +263,16 @@ If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
If PROJECT-P (universal argument), don't close windows and only kill buffers If PROJECT-P (universal argument), don't close windows and only kill buffers
that belong to the current project." that belong to the current project."
(interactive "P") (interactive "P")
(save-some-buffers)
(unless project-p (unless project-p
(delete-other-windows)) (delete-other-windows))
(switch-to-buffer (doom-fallback-buffer)) (switch-to-buffer (doom-fallback-buffer))
(doom/cleanup-session nil (if project-p (doom-project-buffer-list)))) (let ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list))))
(mapc #'kill-buffer buffers)
(when (called-interactively-p 'interactive)
(message "Killed %s buffers"
(- (length buffers)
(length (cl-remove-if-not #'buffer-live-p buffers)))))))
;;;###autoload ;;;###autoload
(defun doom/kill-other-buffers (&optional project-p) (defun doom/kill-other-buffers (&optional project-p)
@ -276,13 +281,14 @@ that belong to the current project."
If PROJECT-P (universal argument), kill only buffers that belong to the current If PROJECT-P (universal argument), kill only buffers that belong to the current
project." project."
(interactive "P") (interactive "P")
(let ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list))) (let ((buffers
(current-buffer (current-buffer))) (delq (current-buffer)
(dolist (buf buffers) (if project-p (doom-project-buffer-list) (doom-buffer-list)))))
(unless (eq buf current-buffer) (mapc #'doom-kill-buffer-and-windows buffers)
(doom-kill-buffer-and-windows buf)))
(when (called-interactively-p 'interactive) (when (called-interactively-p 'interactive)
(message "Killed %s buffers" (length buffers))))) (message "Killed %s buffers"
(- (length buffers)
(length (cl-remove-if-not #'buffer-live-p buffers)))))))
;;;###autoload ;;;###autoload
(defun doom/kill-matching-buffers (pattern &optional project-p) (defun doom/kill-matching-buffers (pattern &optional project-p)
@ -293,44 +299,23 @@ project."
(interactive (interactive
(list (read-regexp "Buffer pattern: ") (list (read-regexp "Buffer pattern: ")
current-prefix-arg)) current-prefix-arg))
(let* ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list))) (let* ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list))))
(n (doom-kill-matching-buffers pattern buffers))) (doom-kill-matching-buffers pattern buffers)
(when (called-interactively-p 'interactive) (when (called-interactively-p 'interactive)
(message "Killed %s buffers" n)))) (message "Killed %d buffer(s)"
(- (length buffers)
(length (cl-remove-if-not #'buffer-live-p buffers)))))))
;;;###autoload ;;;###autoload
(defun doom/cleanup-session (arg &optional buffer-list) (defun doom/kill-buried-buffers (&optional project-p)
"Clean up buried buries and orphaned processes in the current workspace. If "Kill buffers that are buried.
ALL-P (universal argument), clean them up globally."
If PROJECT-P (universal argument), only kill buried buffers belonging to the
current project."
(interactive "P") (interactive "P")
(let ((buffers (doom-buried-buffers buffer-list)) (let ((buffers (doom-buried-buffers (if project-p (doom-project-buffer-list)))))
(n 0)) (mapc #'kill-buffer buffers)
(dolist (buf buffers) (when (called-interactively-p 'interactive)
(unless (buffer-modified-p buf) (message "Killed %d buffer(s)"
(kill-buffer buf) (- (length buffers)
(cl-incf n))) (length (cl-remove-if-not #'buffer-live-p buffers)))))))
(when arg
(setq n (+ n (doom/cleanup-buffer-processes))))
(dolist (hook doom-cleanup-hook)
(let ((m (funcall hook)))
(when (integerp m)
(setq n (+ n m)))))
(message "Cleaned up %s buffers" n)
n))
;;;###autoload
(defun doom/cleanup-buffer-processes ()
"Kill all processes that have no visible associated buffers. Return number of
processes killed."
(interactive)
(let ((n 0))
(dolist (p (process-list))
(let ((process-buffer (process-buffer p)))
(when (and (process-live-p p)
(not (string= (process-name p) "server"))
(or (not process-buffer)
(and (bufferp process-buffer)
(not (buffer-live-p process-buffer)))))
(delete-process p)
(cl-incf n))))
n))

View file

@ -3,17 +3,38 @@
(require 'core-cli) (require 'core-cli)
(defun doom--run (command &optional yes) (defun doom--run (command &optional yes)
(let ((default-directory doom-emacs-dir) (let* ((default-directory doom-emacs-dir)
(doom-auto-accept yes)) (doom-auto-accept yes)
(let ((compilation-buffer-name-function (lambda (_) "*bin/doom*"))) (buf (get-buffer-create " *bin/doom*"))
(compile (format "bin/doom %s" command) t)) (wconf (current-window-configuration))
(while compilation-in-progress (ignore-window-parameters t)
(sit-for 1)) (noninteractive t)
(when (y-or-n-p "Reload Doom config?") (standard-output
(doom/reload)) (lambda (char)
(message "Done"))) (with-current-buffer buf
(insert char)
(when (memq char '(?\n ?\r))
(ansi-color-apply-on-region (line-beginning-position -1) (line-end-position))
(redisplay))))))
(doom-initialize t)
(setq doom-modules (doom-modules))
(doom-initialize-modules t)
(doom-initialize-packages t)
(with-current-buffer (switch-to-buffer buf)
(erase-buffer)
(require 'package)
(redisplay)
(doom-dispatch command nil)
(print! (green "\nDone!"))))
(message (format! (green "Done!"))))
;;;###autoload
(defun doom//autoloads (&optional yes)
"TODO"
(interactive "P")
(doom--run "autoloads" yes))
;;;###autoload ;;;###autoload
(defun doom//update (&optional yes) (defun doom//update (&optional yes)
"TODO" "TODO"
@ -24,7 +45,9 @@
(defun doom//upgrade (&optional yes) (defun doom//upgrade (&optional yes)
"TODO" "TODO"
(interactive "P") (interactive "P")
(doom--run "upgrade" yes)) (doom--run "upgrade" yes)
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect. Restart?")
(doom/restart-and-restore)))
;;;###autoload ;;;###autoload
(defun doom//install (&optional yes) (defun doom//install (&optional yes)
@ -43,24 +66,3 @@
"TODO" "TODO"
(interactive "P") (interactive "P")
(doom--run "refresh" yes)) (doom--run "refresh" yes))
;;;###autoload
(defun doom/reload (&optional force-p)
"Reloads your config. This is experimental!
If called from a noninteractive session, this will try to communicate with a
live server (if one is found) to tell it to run this function.
If called from an interactive session, tries to reload autoloads files (if
necessary), reinistalize doom (via `doom-initialize') and reloads your private
init.el and config.el. Then runs `doom-reload-hook'."
(interactive "P")
(require 'core-cli)
(doom-reload-autoloads force-p)
(setq load-path doom-site-load-path)
(let (doom-init-p)
(doom-initialize))
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
(doom-initialize-modules 'force))
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)
(message "Finished!"))

38
core/autoload/config.el Normal file
View file

@ -0,0 +1,38 @@
;;; core/autoload/config.el -*- lexical-binding: t; -*-
;;;###autoload
(defun doom/open-private-config ()
"TODO"
(interactive)
(unless (file-directory-p doom-private-dir)
(make-directory doom-private-dir t))
(doom-project-browse doom-private-dir))
;;;###autoload
(defun doom/find-file-in-private-config ()
"TODO"
(interactive)
(doom-project-find-file doom-private-dir))
;;;###autoload
(defun doom/reload (&optional force-p)
"Reloads your config. This is experimental!
If called from a noninteractive session, this will try to communicate with a
live server (if one is found) to tell it to run this function.
If called from an interactive session, tries to reload autoloads files (if
necessary), reinistalize doom (via `doom-initialize') and reloads your private
init.el and config.el. Then runs `doom-reload-hook'."
(interactive "P")
(require 'core-cli)
(doom-reload-autoloads force-p)
(setq load-path doom-site-load-path)
(let (doom-init-p)
(doom-initialize))
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
(doom-initialize-modules 'force))
(when (bound-and-true-p doom-packages)
(doom/reload-packages))
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)
(message "Finished!"))

View file

@ -61,8 +61,8 @@ ready to be pasted in a bug report on github."
"n/a") "n/a")
(or (ignore-errors (or (ignore-errors
(require 'use-package) (require 'use-package)
(cl-loop for (name . plist) in (doom-get-packages :private t) (cl-loop for (name . plist) in (doom-find-packages :private t)
if (use-package-plist-delete (copy-sequence plist) :private) if (use-package-plist-delete (copy-sequence plist) :modules)
collect (format "%s" (cons name it)) collect (format "%s" (cons name it))
else else
collect (symbol-name name))) collect (symbol-name name)))
@ -115,7 +115,7 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
branch and commit." branch and commit."
(interactive) (interactive)
(require 'vc-git) (require 'vc-git)
(print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s." (print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s"
doom-version doom-version
emacs-version emacs-version
(or (vc-git--symbolic-ref doom-core-dir) (or (vc-git--symbolic-ref doom-core-dir)
@ -139,25 +139,38 @@ pasting into a bug report or discord."
(defvar doom--sandbox-init-doom-p nil) (defvar doom--sandbox-init-doom-p nil)
(defun doom--run-vanilla-sandbox (&optional load-doom-p) (defun doom--run-vanilla-sandbox (&optional mode)
(interactive) (interactive)
(let ((contents (buffer-string)) (let ((contents (buffer-string))
(file (make-temp-file "doom-sandbox-"))) (file (make-temp-file "doom-sandbox-")))
(require 'package)
(with-temp-file file (with-temp-file file
(insert (insert
(prin1-to-string (prin1-to-string
`(cond (,load-doom-p (macroexp-progn
(setq doom-private-dir "/tmp/does/not/exist" (append `((setq debug-on-error t
doom-modules ,doom-modules) package--init-file-ensured t
(load ,user-init-file)) package-user-dir ,package-user-dir
((setq package--init-file-ensured t package-archives ',package-archives
package-user-dir ,package-user-dir user-emacs-directory ,doom-emacs-dir
package-archives ',package-archives doom-modules ,doom-modules))
user-emacs-directory ,doom-emacs-dir) (pcase mode
(package-initialize)))) (`vanilla-doom+ ; Doom core + modules - private config
`((setq doom-private-dir "/tmp/does/not/exist")
(load-file ,user-init-file)
(doom|run-all-startup-hooks)))
(`vanilla-doom ; only Doom core
`((setq doom-private-dir "/tmp/does/not/exist"
doom-init-modules-p t)
(load-file ,user-init-file)
(doom|run-all-startup-hooks)))
(`vanilla ; nothing loaded
`((package-initialize)))))))
"\n(unwind-protect (progn\n" contents "\n)\n" "\n(unwind-protect (progn\n" contents "\n)\n"
(format "(delete-file %S))" file))) (format "(delete-file %S))" file)))
(let ((args (list "-Q" "-l" file))) (let ((args (if (eq mode 'doom)
(list "-l" file)
(list "-Q" "-l" file))))
(require 'restart-emacs) (require 'restart-emacs)
(condition-case e (condition-case e
(cond ((display-graphic-p) (cond ((display-graphic-p)
@ -174,30 +187,58 @@ pasting into a bug report or discord."
(delete-file file) (delete-file file)
(signal (car e) (cdr e))))))) (signal (car e) (cdr e)))))))
(defun doom--run-vanilla-doom-sandbox () (fset 'doom--run-vanilla-emacs (lambda! (doom--run-vanilla-sandbox 'vanilla)))
(interactive) (fset 'doom--run-vanilla-doom (lambda! (doom--run-vanilla-sandbox 'vanilla-doom)))
(doom--run-vanilla-sandbox t)) (fset 'doom--run-vanilla-doom+ (lambda! (doom--run-vanilla-sandbox 'vanilla-doom+)))
(fset 'doom--run-full-doom (lambda! (doom--run-vanilla-sandbox 'doom)))
(defvar doom-sandbox-emacs-lisp-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-c") #'doom--run-vanilla-emacs)
(define-key map (kbd "C-c C-d") #'doom--run-vanilla-doom)
(define-key map (kbd "C-c C-p") #'doom--run-vanilla-doom+)
(define-key map (kbd "C-c C-f") #'doom--run-full-doom)
(define-key map (kbd "C-c C-k") #'kill-this-buffer)
map))
(define-derived-mode doom-sandbox-emacs-lisp-mode emacs-lisp-mode "Sandbox Elisp"
"TODO")
;;;###autoload ;;;###autoload
(defun doom/open-vanilla-sandbox () (defun doom/open-vanilla-sandbox ()
"Open an Emacs Lisp buffer destinated to run in a blank Emacs session (and "Open the Emacs Lisp sandbox.
optionally load only Doom and its modules, without your private config).
This provides a testbed for debugging code without Doom (or your private config) This is a test bed for running Emacs Lisp in an instance of Emacs with varying
standing in the way, and without sacrificing access to installed packages." amounts of Doom loaded, including:
a) vanilla Emacs (nothing loaded),
b) vanilla Doom (only Doom core) and
c) Doom + modules - your private config.
This is done without sacrificing access to installed packages. Use the sandbox
to reproduce bugs and determine if Doom is to blame."
(interactive) (interactive)
(let* ((buffer-name "*doom:vanilla-sandbox*") (let* ((buffer-name "*doom:vanilla-sandbox*")
(exists (get-buffer buffer-name)) (exists (get-buffer buffer-name))
(buf (get-buffer-create buffer-name))) (buf (get-buffer-create buffer-name)))
(with-current-buffer buf (with-current-buffer buf
(emacs-lisp-mode) (doom-sandbox-emacs-lisp-mode)
(local-set-key (kbd "C-c C-c") #'doom--run-vanilla-sandbox) (setq header-line-format
(local-set-key (kbd "C-c C-d") #'doom--run-vanilla-doom-sandbox) (concat "C-c C-c = vanilla Emacs"
(local-set-key (kbd "C-c C-k") #'kill-this-buffer) " / "
(setq header-line-format "C-c C-c to run the session / C-c C-d to run it with vanilla Doom loaded / C-c C-k to abort it") "C-c C-d = Doom core"
" / "
"C-c C-p = Doom core + modules - private config"
" / "
"C-c C-f = Full Doom"
" / "
"C-c C-k to abort"))
(setq-local default-directory doom-emacs-dir) (setq-local default-directory doom-emacs-dir)
(unless (buffer-live-p exists) (unless (buffer-live-p exists)
(doom-template-insert "VANILLA_SANDBOX")) (doom-template-insert "VANILLA_SANDBOX")
(let ((contents (substitute-command-keys (buffer-string))))
(erase-buffer)
(insert contents "\n")))
(goto-char (point-max))) (goto-char (point-max)))
(pop-to-buffer buf))) (pop-to-buffer buf)))
@ -320,3 +361,14 @@ If INIT-FILE is non-nil, profile that instead of USER-INIT-FILE."
;;;###autoload ;;;###autoload
(advice-add #'esup :override #'doom/profile-emacs) (advice-add #'esup :override #'doom/profile-emacs)
;;;###autoload
(defun doom/toggle-debug-mode (&optional arg)
"Toggle `debug-on-error' and `doom-debug-mode' for verbose logging."
(interactive (list (or current-prefix-arg 'toggle)))
(let ((value
(cond ((eq arg 'toggle) (not doom-debug-mode))
((> (prefix-numeric-value arg) 0)))))
(setq doom-debug-mode value
debug-on-error value)
(message "Debug mode %s" (if value "on" "off"))))

View file

@ -184,9 +184,9 @@ file if it exists, without confirmation."
(when (file-exists-p old-path) (when (file-exists-p old-path)
(delete-file old-path)) (delete-file old-path))
(kill-this-buffer) (kill-this-buffer)
(find-file new-path)
(doom--forget-file old-path new-path) (doom--forget-file old-path new-path)
(doom--update-file new-path) (doom--update-file new-path)
(find-file new-path)
(message "File successfully moved to %s" dest)))) (message "File successfully moved to %s" dest))))
(`overwrite-self (error "Cannot overwrite self")) (`overwrite-self (error "Cannot overwrite self"))
(`aborted (message "Aborted")) (`aborted (message "Aborted"))

View file

@ -1,45 +1,67 @@
;;; core/autoload/help.el -*- lexical-binding: t; -*- ;;; core/autoload/help.el -*- lexical-binding: t; -*-
(defvar doom--module-mode-alist (defvar doom--module-mode-alist
'((c-mode :lang cc) '((dockerfile-mode :tools docker)
(c++-mode :lang cc) (haxor-mode :lang assembly)
(objc++-mode :lang cc) (mips-mode :lang assembly)
(java-mode :lang java) (nasm-mode :lang assembly)
(csharp-mode :lang csharp) (c-mode :lang cc)
(clojure-mode :lang clojure) (c++-mode :lang cc)
(objc++-mode :lang cc)
(crystal-mode :lang crystal)
(lisp-mode :lang common-lisp)
(csharp-mode :lang csharp)
(clojure-mode :lang clojure)
(graphql-mode :lang data)
(toml-mode :lang data)
(json-mode :lang data)
(yaml-mode :lang data)
(csv-mode :lang data)
(dhall-mode :lang data)
(erlang-mode :lang erlang)
(elixir-mode :lang elixir)
(elm-mode :lang elm)
(emacs-lisp-mode :lang emacs-lisp) (emacs-lisp-mode :lang emacs-lisp)
(go-mode :lang go) (ess-r-mode :lang ess)
(haskell-mode :lang haskell) (ess-julia-mode :lang ess)
(js2-mode :lang javascript) (go-mode :lang go)
(julia-mode :lang julia) (haskell-mode :lang haskell)
(latex-mode :lang latex) (hy-mode :lang hy)
(LaTeX-mode :lang latex) (java-mode :lang java)
(ledger-mode :lang ledger) (js2-mode :lang javascript)
(lua-mode :lang lua) (rjsx-mode :lang javascript)
(markdown-mode :lang markdown) (typescript-mode :lang javascript)
(gfm-mode :lang markdown) (coffee-mode :lang javascript)
(ocaml-mode :lang ocaml) (julia-mode :lang julia)
(org-mode :lang org) (latex-mode :lang latex)
(perl-mode :lang perl) (LaTeX-mode :lang latex)
(php-mode :lang php) (ledger-mode :lang ledger)
(hack-mode :lang php) (lua-mode :lang lua)
(plantuml-mode :lang plantuml) (markdown-mode :lang markdown)
(gfm-mode :lang markdown)
(nim-mode :lang nim)
(nix-mode :lang nix)
(taureg-mode :lang ocaml)
(org-mode :lang org)
(perl-mode :lang perl)
(php-mode :lang php)
(hack-mode :lang php)
(plantuml-mode :lang plantuml)
(purescript-mode :lang purescript) (purescript-mode :lang purescript)
(python-mode :lang python) (python-mode :lang python)
(restclient-mode :lang rest) (restclient-mode :lang rest)
(ruby-mode :lang ruby) (ruby-mode :lang ruby)
(enh-ruby-mode :lang ruby) (enh-ruby-mode :lang ruby)
(rust-mode :lang rust) (rust-mode :lang rust)
(scala-mode :lang scala) (scala-mode :lang scala)
(sh-mode :lang sh) (sh-mode :lang sh)
(swift-mode :lang swift) (swift-mode :lang swift)
(typescript-mode :lang typescript) (web-mode :lang web)
(web-mode :lang web) (css-mode :lang web)
(css-mode :lang web) (scss-mode :lang web)
(scss-mode :lang web) (sass-mode :lang web)
(sass-mode :lang web) (less-css-mode :lang web)
(less-css-mode :lang web) (stylus-mode :lang web))
(stylus-mode :lang web))
"TODO") "TODO")
@ -54,16 +76,17 @@
collect mode)) collect mode))
;; ;;
;; Commands ;; Commands
;;;###autoload ;;;###autoload
(define-obsolete-function-alias 'doom/describe-setting 'doom/describe-setters "2.1.0") (defun doom/describe-autodefs (autodef)
"Open the documentation of Doom autodefs.
;;;###autoload What is an autodef? It's a function or macro that is always defined, even if its
(defun doom/describe-setters (setting) containing module is disabled (in which case it will safely no-op). This
"Open the documentation of Doom functions and configuration macros." syntactic sugar lets you use them without needing to check if they are
available."
(interactive (interactive
(let* ((settings (let* ((settings
(cl-loop with case-fold-search = nil (cl-loop with case-fold-search = nil
@ -74,42 +97,52 @@
(string-match-p "[a-z]!$" sym-name)) (string-match-p "[a-z]!$" sym-name))
collect sym)) collect sym))
(sym (symbol-at-point)) (sym (symbol-at-point))
(setting (autodef
(completing-read (completing-read
"Describe setter: " "Describe setter: "
;; TODO Could be cleaner (refactor me!) ;; TODO Could be cleaner (refactor me!)
(cl-loop with maxwidth = (apply #'max (mapcar #'length (mapcar #'symbol-name settings))) (cl-loop with maxwidth = (apply #'max (mapcar #'length (mapcar #'symbol-name settings)))
for def in (sort settings #'string-lessp) for def in (sort settings #'string-lessp)
if (or (get def 'doom-module) if (get def 'doom-module)
(doom-module-from-path (symbol-file def)))
collect collect
(format (format "%%-%ds%%s" (+ maxwidth 4)) (format (format "%%-%ds%%s" (+ maxwidth 4))
def (propertize (format "%s %s" (car it) (cdr it)) def (propertize (format "%s %s" (car it) (cdr it))
'face 'font-lock-comment-face)) 'face 'font-lock-comment-face))
else if (file-in-directory-p (symbol-file def) doom-core-dir) else if (and (string-match-p "^set-.+!$" (symbol-name def))
(symbol-file def)
(file-in-directory-p (symbol-file def) doom-core-dir))
collect collect
(format (format "%%-%ds%%s" (+ maxwidth 4)) (format (format "%%-%ds%%s" (+ maxwidth 4))
def (propertize (format "%s %s" :core (file-name-sans-extension (file-relative-name (symbol-file def) doom-core-dir))) def (propertize (format "core/%s.el" (file-name-sans-extension (file-relative-name (symbol-file def) doom-core-dir)))
'face 'font-lock-comment-face)) 'face 'font-lock-comment-face)))
else
collect (symbol-name def))
nil t nil t
(when (and (symbolp sym) (when (and (symbolp sym)
(string-match-p "!$" (symbol-name sym))) (string-match-p "!$" (symbol-name sym)))
(symbol-name sym))))) (symbol-name sym)))))
(list (and setting (car (split-string setting " ")))))) (list (and autodef (car (split-string autodef " "))))))
(or (stringp setting) (or (stringp autodef)
(functionp setting) (functionp autodef)
(signal 'wrong-type-argument (list '(stringp functionp) setting))) (signal 'wrong-type-argument (list '(stringp functionp) autodef)))
(let ((fn (if (functionp setting) (let ((fn (if (functionp autodef)
setting autodef
(intern-soft setting)))) (intern-soft autodef))))
(or (fboundp fn) (or (fboundp fn)
(error "'%s' is not a valid DOOM setting" setting)) (error "'%s' is not a valid DOOM autodef" autodef))
(if (fboundp 'helpful-callable) (if (fboundp 'helpful-callable)
(helpful-callable fn) (helpful-callable fn)
(describe-function fn)))) (describe-function fn))))
;;;###autoload
(defun doom/describe-active-minor-mode (mode)
"Get information on an active minor mode. Use `describe-minor-mode' for a
selection of all minor-modes, active or not."
(interactive
(list (completing-read "Minor mode: " (doom-active-minor-modes))))
(describe-minor-mode-from-symbol
(cond ((stringp mode) (intern mode))
((symbolp mode) mode)
((error "Expected a symbol/string, got a %s" (type-of mode))))))
;;;###autoload ;;;###autoload
(defun doom/describe-module (category module) (defun doom/describe-module (category module)
"Open the documentation of CATEGORY MODULE. "Open the documentation of CATEGORY MODULE.
@ -162,55 +195,121 @@ current file is in, or d) the module associated with the current major mode (see
(cl-check-type module symbol) (cl-check-type module symbol)
(or (doom-module-p category module) (or (doom-module-p category module)
(error "'%s %s' isn't a valid module" category module)) (error "'%s %s' isn't a valid module" category module))
(let ((doc-path (doom-module-path category module "README.org"))) (doom-project-browse (doom-module-path category module)))
(unless (file-exists-p doc-path)
(error "There is no documentation for this module (%s)" doc-path)) (defun doom--describe-package-insert-button (label path &optional regexp)
(find-file doc-path))) (declare (indent defun))
(insert-text-button
(string-trim label)
'face 'link
'follow-link t
'action
`(lambda (_)
(unless (file-exists-p ,path)
(user-error "Module doesn't exist"))
(when (window-dedicated-p)
(other-window 1))
(let ((buffer (find-file ,path)))
(when ,(stringp regexp)
(with-current-buffer buffer
(goto-char (point-min))
(if (re-search-forward ,regexp nil t)
(recenter)
(message "Couldn't find the config block"))))))))
;;;###autoload ;;;###autoload
(defun doom/describe-active-minor-mode (mode) (global-set-key [remap describe-package] #'doom/describe-package)
"Get information on an active minor mode. Use `describe-minor-mode' for a
selection of all minor-modes, active or not." (defvar doom--describe-package-list-cache nil)
;;;###autoload
(defun doom/describe-package (package)
"Like `describe-packages', but is Doom aware.
Only shows installed packages. Includes information about where packages are
defined and configured.
If prefix arg is prsent, refresh the cache."
(interactive (interactive
(list (completing-read "Minor mode: " (doom-active-minor-modes)))) (list
(describe-minor-mode-from-symbol (let* ((guess (or (function-called-at-point)
(cond ((stringp mode) (intern mode)) (symbol-at-point))))
((symbolp mode) mode) (require 'finder-inf nil t)
((error "Expected a symbol/string, got a %s" (type-of mode)))))) (require 'core-packages)
(doom-initialize-packages)
(let ((packages
(or (unless current-prefix-arg doom--describe-package-list-cache)
(cl-loop for pkg
in (cl-delete-duplicates
(sort (append (mapcar #'car package-alist)
(mapcar #'car package-archive-contents)
(mapcar #'car package--builtins))
#'string-greaterp))
if (assq pkg package-alist)
collect (symbol-name pkg)
else
collect (propertize (symbol-name pkg) 'face 'font-lock-comment-face)))))
(unless (memq guess packages)
(setq guess nil))
(setq doom--describe-package-list-cache packages)
(intern
(completing-read
(if guess
(format "Describe package (default %s): "
guess)
"Describe package: ")
packages nil t nil nil
(if guess (symbol-name guess))))))))
(describe-package package)
(save-excursion
(with-current-buffer (help-buffer)
(let ((inhibit-read-only t))
(goto-char (point-min))
(when (and (doom-package-installed-p package)
(re-search-forward "^ *Status: " nil t))
(end-of-line)
(let ((indent (make-string (length (match-string 0)) ? )))
(insert "\n" indent "Installed by the following Doom modules:\n")
(dolist (m (get package 'doom-module))
(insert indent)
(doom--describe-package-insert-button
(format " %s %s" (car m) (or (cdr m) ""))
(pcase (car m)
(:core doom-core-dir)
(:private doom-private-dir)
(category (doom-module-path category (cdr m)))))
(insert "\n"))
(package--print-help-section "Source")
(pcase (doom-package-backend package)
(`elpa (insert "[M]ELPA"))
(`quelpa (insert (format "QUELPA %s" (prin1-to-string (doom-package-prop package :recipe)))))
(`emacs (insert "Built-in")))
(insert "\n")
(package--print-help-section "Configs")
(dolist (file (get package 'doom-files))
(doom--describe-package-insert-button
(abbreviate-file-name file)
file
(format "\\((\\(:?after!\\|def-package!\\)[ \t\n]*%s\\|^[ \t]*;; `%s'$\\)"
package package))
(insert "\n" indent))
(delete-char -1)))))))
;;;###autoload ;;;###autoload
(defun doom/what-face (arg &optional pos) (defun doom/describe-symbol (symbol)
"Shows all faces and overlay faces at point. "Show help for SYMBOL, a variable, function or macro."
(interactive
Interactively prints the list to the echo area. Noninteractively, returns a list (list (helpful--read-symbol "Symbol: " #'helpful--bound-p)))
whose car is the list of faces and cadr is the list of overlay faces." (let* ((sym (intern-soft symbol))
(interactive "P") (bound (boundp sym))
(let* ((pos (or pos (point))) (fbound (fboundp sym)))
(faces (let ((face (get-text-property pos 'face))) (cond ((and sym bound (not fbound))
(if (keywordp (car-safe face)) (helpful-variable sym))
(list face) ((and sym fbound (not bound))
(cl-loop for f in (doom-enlist face) collect f)))) (helpful-callable sym))
(overlays (cl-loop for ov in (overlays-at pos (1+ pos)) ((apropos (format "^%s\$" symbol)))
nconc (doom-enlist (overlay-get ov 'face))))) ((apropos (format "%s" symbol))))))
(cond ((called-interactively-p 'any)
(message "%s %s\n%s %s"
(propertize "Faces:" 'face 'font-lock-comment-face)
(if faces
(cl-loop for face in faces
if (or (listp face) arg)
concat (format "'%s " face)
else
concat (concat (propertize (symbol-name face) 'face face) " "))
"n/a ")
(propertize "Overlays:" 'face 'font-lock-comment-face)
(if overlays
(cl-loop for ov in overlays
if arg concat (concat (symbol-name ov) " ")
else concat (concat (propertize (symbol-name ov) 'face ov) " "))
"n/a")))
(t
(and (or faces overlays)
(list faces overlays))))))
;;;###autoload ;;;###autoload
(defalias 'doom/help 'doom/open-manual) (defalias 'doom/help 'doom/open-manual)
@ -219,4 +318,14 @@ whose car is the list of faces and cadr is the list of overlay faces."
(defun doom/open-manual () (defun doom/open-manual ()
"TODO" "TODO"
(interactive) (interactive)
(find-file (expand-file-name "index.org" doom-docs-dir))) (user-error "This command isn't implemented yet")
;; (find-file (expand-file-name "index.org" doom-docs-dir))
)
;;;###autoload
(defun doom/open-news ()
"TODO"
(interactive)
(user-error "This command isn't implemented yet")
;; (find-file (expand-file-name (concat "news/" doom-version) doom-docs-dir))
)

View file

@ -1,5 +1,5 @@
;;; core/autoload/line-numbers.el -*- lexical-binding: t; -*- ;;; core/autoload/line-numbers.el -*- lexical-binding: t; -*-
;;;###if (not EMACS26+) ;;;###if (version< emacs-version "26.1")
;; This was lifted out of the display-line-numbers library in Emacs 26.1 and ;; This was lifted out of the display-line-numbers library in Emacs 26.1 and
;; modified to use nlinum for Emacs 25.x users. It should be removed should ;; modified to use nlinum for Emacs 25.x users. It should be removed should

View file

@ -32,7 +32,7 @@
"TODO") "TODO")
;;;###autoload ;;;###autoload
(defun doom-ansi-apply (style text) (defun doom-color-apply (style text)
"Apply CODE to formatted MESSAGE with ARGS. CODE is derived from any of "Apply CODE to formatted MESSAGE with ARGS. CODE is derived from any of
`doom-message-fg', `doom-message-bg' or `doom-message-fx'. `doom-message-fg', `doom-message-bg' or `doom-message-fx'.
@ -53,19 +53,27 @@ Otherwise, it maps colors to a term-color-* face."
`(:foreground ,(face-foreground (caddr (assq style doom-ansi-alist))))) `(:foreground ,(face-foreground (caddr (assq style doom-ansi-alist)))))
((cddr (assq style doom-ansi-alist))))))))) ((cddr (assq style doom-ansi-alist)))))))))
(defun doom--short-color-replace (forms)
"Replace color-name functions with calls to `doom-color-apply'."
(cond ((null forms) nil)
((listp forms)
(append (cond ((not (symbolp (car forms)))
(list (doom--short-color-replace (car forms))))
((assq (car forms) doom-ansi-alist)
`(doom-color-apply ',(car forms)))
((eq (car forms) 'color)
(pop forms)
`(doom-color-apply ,(car forms)))
((list (car forms))))
(doom--short-color-replace (cdr forms))
nil))
(forms)))
;;;###autoload ;;;###autoload
(defmacro format! (message &rest args) (defmacro format! (message &rest args)
"An alternative to `format' that understands (color ...) and converts them "An alternative to `format' that understands (color ...) and converts them
into faces or ANSI codes depending on the type of sesssion we're in." into faces or ANSI codes depending on the type of sesssion we're in."
`(cl-flet `(format ,@(doom--short-color-replace `(,message ,@args))))
(,@(mapcar (lambda (rule) `(,(car rule)
(lambda (message)
(doom-ansi-apply ',(car rule) message))))
doom-ansi-alist)
(color
(lambda (code format)
(doom-ansi-apply code format))))
(format ,message ,@args)))
;;;###autoload ;;;###autoload
(defmacro print! (message &rest args) (defmacro print! (message &rest args)
@ -79,8 +87,5 @@ Can be colored using (color ...) blocks:
(print! (green \"Great %s!\") \"success\") (print! (green \"Great %s!\") \"success\")
Uses faces in interactive sessions and ANSI codes otherwise." Uses faces in interactive sessions and ANSI codes otherwise."
`(if (not noninteractive) `(progn (princ (format! ,message ,@args))
(message (format! ,message ,@args)) (terpri)))
;; princ prints to stdout, message to stderr
(princ (format! ,message ,@args))
(terpri)))

View file

@ -40,8 +40,9 @@
;;;###autoload ;;;###autoload
(defun doom-package-backend (name &optional noerror) (defun doom-package-backend (name &optional noerror)
"Get which backend the package NAME was installed with. Can either be elpa or "Get which backend the package NAME was installed with. Can either be elpa,
quelpa. Throws an error if NOERROR is nil and the package isn't installed." quelpa or emacs (built-in). Throws an error if NOERROR is nil and the package
isn't installed."
(cl-check-type name symbol) (cl-check-type name symbol)
(cond ((assq name quelpa-cache) 'quelpa) (cond ((assq name quelpa-cache) 'quelpa)
((assq name package-alist) 'elpa) ((assq name package-alist) 'elpa)
@ -96,7 +97,6 @@ list of the package."
"Return t if a package named NAME (a symbol) has a new backend than what it "Return t if a package named NAME (a symbol) has a new backend than what it
was installed with. Returns nil otherwise, or if package isn't installed." was installed with. Returns nil otherwise, or if package isn't installed."
(cl-check-type name symbol) (cl-check-type name symbol)
(doom-initialize-packages)
(and (package-installed-p name) (and (package-installed-p name)
(let* ((plist (cdr (assq name doom-packages))) (let* ((plist (cdr (assq name doom-packages)))
(old-backend (doom-package-backend name 'noerror)) (old-backend (doom-package-backend name 'noerror))
@ -108,7 +108,6 @@ was installed with. Returns nil otherwise, or if package isn't installed."
"Return t if a package named NAME (a symbol) has a different recipe than it "Return t if a package named NAME (a symbol) has a different recipe than it
was installed with." was installed with."
(cl-check-type name symbol) (cl-check-type name symbol)
(doom-initialize-packages)
(and (package-installed-p name) (and (package-installed-p name)
(when-let* ((quelpa-recipe (assq name quelpa-cache)) (when-let* ((quelpa-recipe (assq name quelpa-cache))
(doom-recipe (assq name doom-packages))) (doom-recipe (assq name doom-packages)))
@ -116,15 +115,16 @@ was installed with."
(cdr (plist-get (cdr doom-recipe) :recipe))))))) (cdr (plist-get (cdr doom-recipe) :recipe)))))))
;;;###autoload ;;;###autoload
(cl-defun doom-get-packages (&key (installed 'any) (cl-defun doom-find-packages (&key (installed 'any)
(private 'any) (private 'any)
(disabled 'any) (disabled 'any)
(pinned 'any) (pinned 'any)
(ignored 'any) (ignored 'any)
(sort t) (core 'any)
changed sort
backend changed
deps) backend
deps)
"Retrieves a list of primary packages (i.e. non-dependencies). Each element is "Retrieves a list of primary packages (i.e. non-dependencies). Each element is
a cons cell, whose car is the package symbol and whose cdr is the quelpa recipe a cons cell, whose car is the package symbol and whose cdr is the quelpa recipe
(if any). (if any).
@ -132,76 +132,146 @@ a cons cell, whose car is the package symbol and whose cdr is the quelpa recipe
You can build a filtering criteria using one or more of the following You can build a filtering criteria using one or more of the following
properties: properties:
:backend BACKEND :backend 'quelpa|'elpa|'emacs|'any
Can be 'quelpa, 'elpa or 'emacs Include packages installed through 'quelpa, 'elpa or 'emacs. 'any is the
:installed BOOL wildcard.
Only return installed packages (t) or uninstalled packages (nil) :installed BOOL|'any
:private BOOL t = only include installed packages
Only return private packages (t) or non-private packages (nil) nil = exclude installed packages
:disabled BOOL :private BOOL|'any
Only return packages that are disabled (t) or otherwise (nil) t = only include user-installed packages
:ignored BOOL nil = exclude user-installed packages
Only return packages that are ignored (t) or otherwise (nil) :core BOOL|'any
t = only include Doom core packages
nil = exclude Doom core packages
:disabled BOOL|'any
t = only include disabled packages
nil = exclude disabled packages
:ignored BOOL|'any
t = only include ignored packages
nil = exclude ignored packages
:pinned BOOL|ARCHIVE :pinned BOOL|ARCHIVE
Only return packages that are pinned (t), not pinned (nil) or pinned to a Only return packages that are pinned (t), not pinned (nil) or pinned to a
specific archive (stringp) specific archive (stringp)
:deps BOOL :deps BOOL
Includes the package's dependencies (t). Includes the package's dependencies (t) or not (nil).
The resulting list is sorted unless :sort nil is passed to this function. The resulting list is sorted unless :sort nil is passed to this function.
Warning: this function is expensive, as it re-evaluates your all packages.el Warning: this function is expensive, as it re-evaluates your all packages.el
files." files."
(doom-initialize-packages) (cl-loop with packages = doom-packages
(cl-remove-duplicates for (sym . plist)
(cl-loop with packages = (append (mapcar #'list doom-core-packages) in (if sort
doom-packages) (cl-sort (copy-sequence doom-packages) #'string-lessp :key #'car)
for (sym . plist) packages)
in (if sort if (and (or (not backend)
(cl-sort (copy-sequence packages) #'string-lessp :key #'car) (eq (doom-package-backend sym t) backend))
packages) (or (eq ignored 'any)
if (and (or (not backend) (let* ((form (plist-get plist :ignore))
(eq (doom-package-backend sym t) backend)) (value (eval form)))
(or (eq ignored 'any) (if ignored value (not value))))
(let* ((form (plist-get plist :ignore)) (or (eq disabled 'any)
(value (eval form))) (if disabled
(if ignored value (not value)))) (plist-get plist :disable)
(or (eq disabled 'any) (not (plist-get plist :disable))))
(if disabled (or (eq installed 'any)
(plist-get plist :disable) (if installed
(not (plist-get plist :disable)))) (doom-package-installed-p sym)
(or (eq installed 'any) (not (doom-package-installed-p sym))))
(if installed (or (eq private 'any)
(doom-package-installed-p sym) (let ((modules (plist-get plist :modules)))
(not (doom-package-installed-p sym)))) (if private
(or (eq private 'any) (assq :private modules)
(if private (not (assq :private modules)))))
(plist-get plist :private) (or (eq core 'any)
(not (plist-get plist :private)))) (let ((modules (plist-get plist :modules)))
(or (eq pinned 'any) (if core
(cond ((eq pinned 't) (assq :core modules)
(plist-get plist :pin)) (not (assq :core modules)))))
((null pinned) (or (eq pinned 'any)
(not (plist-get plist :pin))) (cond ((eq pinned 't)
((equal (plist-get plist :pin) pinned))))) (plist-get plist :pin))
collect (cons sym plist) ((null pinned)
and if (and deps (not (package-built-in-p sym))) (not (plist-get plist :pin)))
nconc ((equal (plist-get plist :pin) pinned)))))
(cl-loop for pkg in (doom-get-dependencies-for sym 'recursive 'noerror) collect (cons sym plist)
if (or (eq installed 'any) and if (and deps (not (package-built-in-p sym)))
(if installed nconc
(doom-package-installed-p pkg) (cl-loop for pkg in (doom-get-dependencies-for sym 'recursive 'noerror)
(not (doom-package-installed-p pkg)))) if (or (eq installed 'any)
collect (cons pkg (cdr (assq pkg doom-packages))))) (if installed
:key #'car)) (doom-package-installed-p pkg)
(not (doom-package-installed-p pkg))))
collect (cons pkg (cdr (assq pkg doom-packages))))))
(defun doom--read-module-packages-file (file &optional raw noerror)
(with-temp-buffer ; prevent buffer-local settings from propagating
(condition-case e
(if (not raw)
(load file noerror t t)
(when (file-readable-p file)
(insert-file-contents file)
(while (re-search-forward "(package! " nil t)
(save-excursion
(goto-char (match-beginning 0))
(cl-destructuring-bind (name . plist) (cdr (sexp-at-point))
(push (cons name
(plist-put plist :modules
(cond ((file-in-directory-p file doom-private-dir)
(list :private))
((file-in-directory-p file doom-core-dir)
(list :core))
((doom-module-from-path file)))))
doom-packages))))))
((debug error)
(signal 'doom-package-error
(list (or (doom-module-from-path file)
'(:private . packages))
e))))))
;;;###autoload
(defun doom-package-list (&optional all-p)
"Retrieve a list of explicitly declared packages from enabled modules.
This excludes core packages listed in `doom-core-packages'.
If ALL-P, gather packages unconditionally across all modules, including disabled
ones."
(let ((noninteractive t)
(doom--stage 'packages)
(doom-modules (doom-modules))
doom-packages
doom-disabled-packages
package-pinned-packages)
(doom--read-module-packages-file (expand-file-name "packages.el" doom-core-dir) all-p)
(let ((private-packages (expand-file-name "packages.el" doom-private-dir)))
(unless all-p
;; We load the private packages file twice to ensure disabled packages
;; are seen ASAP, and a second time to ensure privately overridden
;; packages are properly overwritten.
(doom--read-module-packages-file private-packages nil t))
(if all-p
(mapc #'doom--read-module-packages-file
(doom-files-in doom-modules-dir
:depth 2
:full t
:match "/packages\\.el$"))
(cl-loop for key being the hash-keys of doom-modules
for path = (doom-module-path (car key) (cdr key) "packages.el")
for doom--current-module = key
do (doom--read-module-packages-file path nil t)))
(doom--read-module-packages-file private-packages all-p t))
(append (cl-loop for package in doom-core-packages
collect (list package :modules '((:core internal))))
(nreverse doom-packages))))
;;;###autoload ;;;###autoload
(defun doom-get-package-alist () (defun doom-get-package-alist ()
"Returns a list of all desired packages, their dependencies and their desc "Returns a list of all desired packages, their dependencies and their desc
objects, in the order of their `package! blocks.'" objects, in the order of their `package! blocks.'"
(doom-initialize-packages)
(cl-remove-duplicates (cl-remove-duplicates
(cl-loop for name in (append doom-core-packages (mapcar #'car doom-packages)) (cl-loop for name in (mapcar #'car doom-packages)
if (assq name package-alist) if (assq name package-alist)
nconc (cl-loop for dep in (package--get-deps name) nconc (cl-loop for dep in (package--get-deps name)
if (assq dep package-alist) if (assq dep package-alist)
@ -244,49 +314,46 @@ containing (PACKAGE-SYMBOL OLD-VERSION-LIST NEW-VERSION-LIST).
If INCLUDE-FROZEN-P is non-nil, check frozen packages as well. If INCLUDE-FROZEN-P is non-nil, check frozen packages as well.
Used by `doom-packages-update'." Used by `doom-packages-update'."
(doom-initialize-packages t)
(doom-refresh-packages-maybe doom-debug-mode) (doom-refresh-packages-maybe doom-debug-mode)
(require 'async) (let-alist
(let (quelpa-pkgs elpa-pkgs) (seq-group-by
;; Separate quelpa from elpa packages #'doom-package-backend
(dolist (pkg (mapcar #'car package-alist)) (cl-loop for package in (mapcar #'car package-alist)
(when (and (or (not (doom-package-prop pkg :freeze 'eval)) when (and (or (not (doom-package-prop package :freeze 'eval))
include-frozen-p) include-frozen-p)
(not (doom-package-prop pkg :ignore 'eval)) (not (doom-package-prop package :ignore 'eval))
(not (doom-package-different-backend-p pkg))) (not (doom-package-different-backend-p package)))
(push pkg collect package))
(if (eq (doom-package-backend pkg) 'quelpa)
quelpa-pkgs
elpa-pkgs))))
;; The bottleneck in this process is quelpa's version checks, so check them ;; The bottleneck in this process is quelpa's version checks, so check them
;; asynchronously. ;; asynchronously.
(let (futures) (cl-loop with partitions = (min 2 (/ (length .quelpa) 4))
(dolist (pkg quelpa-pkgs) for package-list in (seq-partition .quelpa partitions)
(when doom-debug-mode do (doom-log "New thread for: %s" package-list)
(message "New thread for: %s" pkg)) collect
(push (async-start (async-start
`(lambda () `(lambda ()
(let ((gc-cons-threshold ,doom-gc-cons-upper-limit) (let ((gc-cons-threshold ,doom-gc-cons-upper-limit)
(doom-init-p t) (doom-init-p t)
(noninteractive t) (noninteractive t)
(load-path ',load-path) (load-path ',load-path)
(package-alist ',package-alist) (package-alist ',package-alist)
(package-archive-contents ',package-archive-contents) (package-archive-contents ',package-archive-contents)
(package-selected-packages ',package-selected-packages) (package-selected-packages ',package-selected-packages)
(doom-packages ',doom-packages) (doom-packages ',doom-packages)
(doom-modules ',doom-modules) (doom-modules ',doom-modules)
(quelpa-cache ',quelpa-cache) (quelpa-cache ',quelpa-cache)
(user-emacs-directory ,user-emacs-directory) (user-emacs-directory ,user-emacs-directory)
doom-private-dir) doom-private-dir)
(load ,(expand-file-name "core.el" doom-core-dir)) (load ,(expand-file-name "core.el" doom-core-dir))
(load ,(expand-file-name "autoload/packages.el" doom-core-dir)) (load ,(expand-file-name "autoload/packages.el" doom-core-dir))
(require 'package) (require 'package)
(require 'quelpa) (require 'quelpa)
(doom-package-outdated-p ',pkg)))) (delq nil (mapcar #'doom-package-outdated-p ',package-list)))))
futures)) into futures
(delq nil finally return
(append (mapcar #'doom-package-outdated-p elpa-pkgs) (append (delq nil (mapcar #'doom-package-outdated-p .elpa))
(mapcar #'async-get (reverse futures))))))) (mapcan #'async-get futures)
nil))))
;;;###autoload ;;;###autoload
(defun doom-get-orphaned-packages () (defun doom-get-orphaned-packages ()
@ -295,7 +362,7 @@ depended on.
Used by `doom-packages-autoremove'." Used by `doom-packages-autoremove'."
(let ((package-selected-packages (let ((package-selected-packages
(mapcar #'car (doom-get-packages :ignored nil :disabled nil)))) (mapcar #'car (doom-find-packages :ignored nil :disabled nil))))
(append (package--removable-packages) (append (package--removable-packages)
(cl-loop for pkg in package-selected-packages (cl-loop for pkg in package-selected-packages
if (and (doom-package-different-backend-p pkg) if (and (doom-package-different-backend-p pkg)
@ -303,22 +370,17 @@ Used by `doom-packages-autoremove'."
collect pkg)))) collect pkg))))
;;;###autoload ;;;###autoload
(defun doom-get-missing-packages (&optional include-ignored-p) (defun doom-get-missing-packages ()
"Return a list of requested packages that aren't installed or built-in, but "Return a list of requested packages that aren't installed or built-in, but
are enabled (with a `package!' directive). Each element is a list whose CAR is are enabled (with a `package!' directive). Each element is a list whose CAR is
the package symbol, and whose CDR is a plist taken from that package's the package symbol, and whose CDR is a plist taken from that package's
`package!' declaration. `package!' declaration.
If INCLUDE-IGNORED-P is non-nil, includes missing packages that are ignored,
i.e. they have an :ignore property.
Used by `doom-packages-install'." Used by `doom-packages-install'."
(doom-initialize-packages)
(cl-loop for (name . plist) (cl-loop for (name . plist)
in (doom-get-packages :ignored (if include-ignored-p 'any) in (doom-find-packages :ignored nil
:disabled nil :disabled nil
:deps t :deps t)
:sort nil)
if (and (or (plist-get plist :pin) if (and (or (plist-get plist :pin)
(not (package-built-in-p name))) (not (package-built-in-p name)))
(or (not (doom-package-installed-p name)) (or (not (doom-package-installed-p name))
@ -343,7 +405,6 @@ Used by `doom-packages-install'."
"Installs package NAME with optional quelpa RECIPE (see `quelpa-recipe' for an "Installs package NAME with optional quelpa RECIPE (see `quelpa-recipe' for an
example; the package name can be omitted)." example; the package name can be omitted)."
(cl-check-type name symbol) (cl-check-type name symbol)
(doom-initialize-packages)
(when (and (package-installed-p name) (when (and (package-installed-p name)
(not (package-built-in-p name))) (not (package-built-in-p name)))
(if (or (doom-package-different-backend-p name) (if (or (doom-package-different-backend-p name)
@ -362,6 +423,7 @@ example; the package name can be omitted)."
(package-install name)) (package-install name))
(if (not (package-installed-p name)) (if (not (package-installed-p name))
(doom--delete-package-files name) (doom--delete-package-files name)
(add-to-list 'package-selected-packages name nil 'eq)
(setf (alist-get name doom-packages) plist) (setf (alist-get name doom-packages) plist)
name))) name)))
@ -370,7 +432,6 @@ example; the package name can be omitted)."
"Updates package NAME (a symbol) if it is out of date, using quelpa or "Updates package NAME (a symbol) if it is out of date, using quelpa or
package.el as appropriate." package.el as appropriate."
(cl-check-type name symbol) (cl-check-type name symbol)
(doom-initialize-packages)
(unless (package-installed-p name) (unless (package-installed-p name)
(error "%s isn't installed" name)) (error "%s isn't installed" name))
(when (doom-package-different-backend-p name) (when (doom-package-different-backend-p name)
@ -401,7 +462,6 @@ package.el as appropriate."
(defun doom-delete-package (name &optional force-p) (defun doom-delete-package (name &optional force-p)
"Uninstalls package NAME if it exists, and clears it from `quelpa-cache'." "Uninstalls package NAME if it exists, and clears it from `quelpa-cache'."
(cl-check-type name symbol) (cl-check-type name symbol)
(doom-initialize-packages)
(unless (package-installed-p name) (unless (package-installed-p name)
(user-error "%s isn't installed" name)) (user-error "%s isn't installed" name))
(let ((inhibit-message (not doom-debug-mode)) (let ((inhibit-message (not doom-debug-mode))
@ -419,6 +479,14 @@ package.el as appropriate."
;; ;;
;; Interactive commands ;; Interactive commands
;;;###autoload
(defun doom/reload-packages ()
"Reload `doom-packages', `package' and `quelpa'."
(interactive)
(message "Reloading packages")
(doom-initialize-packages t)
(message "Reloading packages...DONE"))
;;;###autoload ;;;###autoload
(defun doom/update-package (pkg) (defun doom/update-package (pkg)
"Prompts the user with a list of outdated packages and updates the selected "Prompts the user with a list of outdated packages and updates the selected
@ -436,7 +504,6 @@ calls."
(unless name (unless name
(user-error "'%s' is already up-to-date" selection)) (user-error "'%s' is already up-to-date" selection))
(list (assq name packages)))) (list (assq name packages))))
(doom-initialize-packages)
(cl-destructuring-bind (package old-version new-version) pkg (cl-destructuring-bind (package old-version new-version) pkg
(if-let* ((desc (doom-package-outdated-p package))) (if-let* ((desc (doom-package-outdated-p package)))
(let ((old-v-str (package-version-join old-version)) (let ((old-v-str (package-version-join old-version))
@ -456,7 +523,6 @@ calls."
;;;###autoload ;;;###autoload
(defun doom*package-delete (desc &rest _) (defun doom*package-delete (desc &rest _)
"Update `quelpa-cache' upon a successful `package-delete'." "Update `quelpa-cache' upon a successful `package-delete'."
(doom-initialize-packages)
(let ((name (package-desc-name desc))) (let ((name (package-desc-name desc)))
(unless (package-installed-p name) (unless (package-installed-p name)
(when-let* ((spec (assq name quelpa-cache))) (when-let* ((spec (assq name quelpa-cache)))
@ -474,8 +540,7 @@ calls."
;; Replace with Doom variants ;; Replace with Doom variants
;;;###autoload ;;;###autoload
(advice-add #'package-autoremove :override (λ! (doom-packages-autoremove current-prefix-arg))) (advice-add #'package-autoremove :override #'doom//autoremove)
;;;###autoload ;;;###autoload
(advice-add #'package-install-selected-packages :override (λ! (doom-packages-install current-prefix-arg))) (advice-add #'package-install-selected-packages :override #'doom//install)

View file

@ -1,5 +1,9 @@
;;; core/autoload/projects.el -*- lexical-binding: t; -*- ;;; core/autoload/projects.el -*- lexical-binding: t; -*-
;;;###autoload
(autoload 'projectile-relevant-known-projects "projectile")
;; ;;
;; Macros ;; Macros
@ -33,6 +37,28 @@ they are absolute."
(dolist (fn projectile-project-root-files-functions) (dolist (fn projectile-project-root-files-functions)
(remhash (format "%s-%s" fn default-directory) projectile-project-root-cache))) (remhash (format "%s-%s" fn default-directory) projectile-project-root-cache)))
;;;###autoload
(defun doom/find-file-in-other-project (project-root)
"Preforms `projectile-find-file' in a known project of your choosing."
(interactive
(list
(completing-read "Find file in project: " (projectile-relevant-known-projects)
nil nil nil nil (doom-project-root))))
(unless (file-directory-p project-root)
(error "Project directory '%s' doesn't exist" project-root))
(doom-project-find-file project-root))
;;;###autoload
(defun doom/browse-in-other-project (project-root)
"Preforms `find-file' in a known project of your choosing."
(interactive
(list
(completing-read "Browse in project: " (projectile-relevant-known-projects)
nil nil nil nil (doom-project-root))))
(unless (file-directory-p project-root)
(error "Project directory '%s' doesn't exist" project-root))
(doom-project-browse project-root))
;; ;;
;; Library ;; Library

119
core/autoload/sessions.el Normal file
View file

@ -0,0 +1,119 @@
;;; core/autoload/sessions.el -*- lexical-binding: t; -*-
;;
;;; Helpers
;;;###autoload
(defun doom-save-session (&optional file)
"TODO"
(setq file (expand-file-name (or file (doom-session-file))))
(cond ((require 'persp-mode nil t)
(unless persp-mode (persp-mode +1))
(setq persp-auto-save-opt 0)
(persp-save-state-to-file file))
((and (require 'frameset nil t)
(require 'restart-emacs nil t))
(let ((frameset-filter-alist (append '((client . restart-emacs--record-tty-file))
frameset-filter-alist))
(desktop-base-file-name (file-name-nondirectory file))
(desktop-dirname (file-name-directory file))
(desktop-restore-eager t)
desktop-file-modtime)
(make-directory desktop-dirname t)
(desktop-save desktop-dirname t)))
((error "No session backend to save session with"))))
;;;###autoload
(defun doom-load-session (&optional file)
"TODO"
(setq file (expand-file-name (or file (doom-session-file))))
(message "Attempting to load %s" file)
(cond ((require 'persp-mode nil t)
(unless persp-mode (persp-mode +1))
(persp-load-state-from-file file))
((and (require 'frameset nil t)
(require 'restart-emacs nil t))
(restart-emacs--restore-frames-using-desktop file))
((error "No session backend to load session with"))))
;;;###autoload
(defun doom-session-file ()
"TODO"
(cond ((require 'persp-mode nil t)
(expand-file-name persp-auto-save-fname persp-save-dir))
((require 'desktop nil t)
(desktop-full-file-name))
((error "No session backend available"))))
;;
;;; Command line switch
;;;###autoload
(defun doom-restore-session-handler (&rest _)
"TODO"
(add-hook 'window-setup-hook #'doom-load-session 'append))
;;;###autoload
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler))
;;
;;; Commands
;;;###autoload
(defun doom/quickload-session ()
"TODO"
(interactive)
(message "Restoring session...")
(doom-load-session)
(message "Session restored. Welcome back."))
;;;###autoload
(defun doom/quicksave-session ()
"TODO"
(interactive)
(message "Saving session")
(doom-save-session)
(message "Saving session...DONE"))
;;;###autoload
(defun doom/load-session (file)
"TODO"
(interactive
(let ((session-file (doom-session-file)))
(list (or (read-file-name "Session to restore: "
(file-name-directory session-file)
nil t
(file-name-nondirectory session-file))
(user-error "No session selected. Aborting")))))
(unless file
(error "No session file selected"))
(message "Loading '%s' session" file)
(doom-load-session file))
;;;###autoload
(defun doom/save-session (file)
"TODO"
(interactive
(let ((session-file (doom-session-file)))
(list (or (read-file-name "Save session to: "
(file-name-directory session-file)
nil nil
(file-name-nondirectory session-file))
(user-error "No session selected. Aborting")))))
(unless file
(error "No session file selected"))
(message "Saving '%s' session" file)
(doom-save-session file))
;;;###autoload
(defalias 'doom/restart #'restart-emacs)
;;;###autoload
(defun doom/restart-and-restore (&optional debug)
"TODO"
(interactive "P")
(doom/quicksave-session)
(restart-emacs
(delq nil (list (if debug "--debug-init") "--restore"))))

View file

@ -1,4 +1,4 @@
;;; core/autoload/editor.el -*- lexical-binding: t; -*- ;;; core/autoload/text.el -*- lexical-binding: t; -*-
;;;###autoload ;;;###autoload
(defun doom-surrounded-p (pair &optional inline balanced) (defun doom-surrounded-p (pair &optional inline balanced)
@ -108,7 +108,7 @@ afterwards, kill line to beginning of line."
(interactive) (interactive)
(let ((empty-line-p (save-excursion (beginning-of-line) (let ((empty-line-p (save-excursion (beginning-of-line)
(looking-at-p "[ \t]*$")))) (looking-at-p "[ \t]*$"))))
(funcall (if (featurep 'evil) (funcall (if (fboundp 'evil-delete)
#'evil-delete #'evil-delete
#'delete-region) #'delete-region)
(point-at-bol) (point)) (point-at-bol) (point))
@ -132,30 +132,6 @@ opposite indentation style."
(tabify beg end) (tabify beg end)
(untabify beg end)))) (untabify beg end))))
(defvar-local doom--buffer-narrowed-origin nil)
;;;###autoload
(defun doom/clone-and-narrow-buffer (beg end &optional clone-p)
"Restrict editing in this buffer to the current region, indirectly. With CLONE-P,
clone the buffer and hard-narrow the selection. If mark isn't active, then widen
the buffer (if narrowed).
Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(interactive "rP")
(cond ((or (region-active-p)
(and beg end))
(deactivate-mark)
(when clone-p
(let ((old-buf (current-buffer)))
(switch-to-buffer (clone-indirect-buffer nil nil))
(setq doom--buffer-narrowed-origin old-buf)))
(narrow-to-region beg end))
(doom--buffer-narrowed-origin
(kill-this-buffer)
(switch-to-buffer doom--buffer-narrowed-origin)
(setq doom--buffer-narrowed-origin nil))
(t
(widen))))
;;;###autoload ;;;###autoload
(defun doom/delete-trailing-newlines () (defun doom/delete-trailing-newlines ()
"Trim trailing newlines. "Trim trailing newlines.

View file

@ -163,6 +163,30 @@ OPACITY is an integer between 0 to 100, inclusive."
100)))) 100))))
(set-frame-parameter nil 'alpha opacity)) (set-frame-parameter nil 'alpha opacity))
(defvar-local doom--buffer-narrowed-origin nil)
;;;###autoload
(defun doom/clone-and-narrow-buffer (beg end &optional clone-p)
"Restrict editing in this buffer to the current region, indirectly. With CLONE-P,
clone the buffer and hard-narrow the selection. If mark isn't active, then widen
the buffer (if narrowed).
Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(interactive "rP")
(cond ((or (region-active-p)
(and beg end))
(deactivate-mark)
(when clone-p
(let ((old-buf (current-buffer)))
(switch-to-buffer (clone-indirect-buffer nil nil))
(setq doom--buffer-narrowed-origin old-buf)))
(narrow-to-region beg end))
(doom--buffer-narrowed-origin
(kill-this-buffer)
(switch-to-buffer doom--buffer-narrowed-origin)
(setq doom--buffer-narrowed-origin nil))
(t
(widen))))
;; ;;
;; Modes ;; Modes

View file

@ -37,9 +37,8 @@ it exists."
(print! (bold (green "\nFinished!"))) (print! (bold (green "\nFinished!")))
(message "If you have a running Emacs Session, you will need to restart it or") (message "If you have a running Emacs Session, you will need to restart it or")
(message "reload Doom for changes to take effect:\n") (message "reload Doom for changes to take effect:\n")
(when (fboundp '+workspace/restart-emacs-then-restore) (message " M-x doom/restart-and-restore")
(message " M-x +workspace/restart-emacs-then-restore")) (message " M-x doom/restart")
(message " M-x restart-emacs")
(message " M-x doom/reload")) (message " M-x doom/reload"))
(defun doom--do-load (&rest files) (defun doom--do-load (&rest files)
@ -156,7 +155,7 @@ even if it doesn't need reloading!"
forms) forms)
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t) (while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
(let* ((sexp (sexp-at-point)) (let* ((sexp (sexp-at-point))
(pred (match-string 1)) (alt-sexp (match-string 1))
(type (car sexp)) (type (car sexp))
(name (doom-unquote (cadr sexp))) (name (doom-unquote (cadr sexp)))
(origin (cond ((doom-module-from-path path)) (origin (cond ((doom-module-from-path path))
@ -166,37 +165,39 @@ even if it doesn't need reloading!"
`(:core . ,(intern (file-name-base path)))))) `(:core . ,(intern (file-name-base path))))))
(doom-file-form (doom-file-form
`(put ',name 'doom-file ,(abbreviate-file-name path)))) `(put ',name 'doom-file ,(abbreviate-file-name path))))
(cond ((memq type '(defun defmacro cl-defun cl-defmacro)) (cond ((and (not member-p) alt-sexp)
(push (read alt-sexp) forms))
((memq type '(defun defmacro cl-defun cl-defmacro))
(cl-destructuring-bind (_ name arglist &rest body) sexp (cl-destructuring-bind (_ name arglist &rest body) sexp
(let ((docstring (if (stringp (car body)) (let ((docstring (if (stringp (car body))
(pop body) (pop body)
"No documentation."))) "No documentation.")))
(push (cond ((not (and member-p (push (if member-p
(or (null pred) (make-autoload sexp (abbreviate-file-name (file-name-sans-extension path)))
(let ((load-file-name path)) (push doom-file-form forms)
(eval (read pred) t))))) (setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
(push doom-file-form forms) origin docstring))
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s" (condition-case-unless-debug e
origin docstring)) (if alt-sexp
(condition-case-unless-debug e (read alt-sexp)
(append (list (pcase type (append (list (pcase type
(`defun 'defmacro) (`defun 'defmacro)
(`cl-defun `cl-defmacro) (`cl-defun `cl-defmacro)
(_ type)) (_ type))
name arglist docstring) name arglist docstring)
(cl-loop for arg in arglist (cl-loop for arg in arglist
if (and (symbolp arg) if (and (symbolp arg)
(not (keywordp arg)) (not (keywordp arg))
(not (memq arg cl--lambda-list-keywords))) (not (memq arg cl--lambda-list-keywords)))
collect arg into syms collect arg into syms
else if (listp arg) else if (listp arg)
collect (car arg) into syms collect (car arg) into syms
finally return (if syms `((ignore ,@syms))))) finally return (if syms `((ignore ,@syms))))))
('error ('error
(message "Ignoring autodef %s (%s)" (message "Ignoring autodef %s (%s)"
name e) name e)
nil))) nil)))
((make-autoload sexp (abbreviate-file-name (file-name-sans-extension path)))))
forms) forms)
(push `(put ',name 'doom-module ',origin) forms)))) (push `(put ',name 'doom-module ',origin) forms))))
@ -204,19 +205,16 @@ even if it doesn't need reloading!"
(cl-destructuring-bind (_type name target &optional docstring) sexp (cl-destructuring-bind (_type name target &optional docstring) sexp
(let ((name (doom-unquote name)) (let ((name (doom-unquote name))
(target (doom-unquote target))) (target (doom-unquote target)))
(unless (and member-p (unless member-p
(or (null pred) (setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
(let ((load-file-name path)) origin docstring))
(eval (read pred) t))))
(setq target #'ignore)) (setq target #'ignore))
(push doom-file-form forms) (push doom-file-form forms)
(push `(put ',name 'doom-module ',origin) forms) (push `(put ',name 'doom-module ',origin) forms)
(push `(defalias ',name #',target ,docstring) (push `(defalias ',name #',target ,docstring)
forms)))) forms))))
((and member-p (member-p
(or (null pred)
(eval (read pred) t)))
(push sexp forms))))) (push sexp forms)))))
(if forms (if forms
(concat (string-join (mapcar #'prin1-to-string (reverse forms)) "\n") (concat (string-join (mapcar #'prin1-to-string (reverse forms)) "\n")
@ -320,7 +318,7 @@ modified."
(prin1 `(setq load-path ',load-path (prin1 `(setq load-path ',load-path
auto-mode-alist ',auto-mode-alist auto-mode-alist ',auto-mode-alist
Info-directory-list ',Info-directory-list Info-directory-list ',Info-directory-list
doom-disabled-packages ',doom-disabled-packages doom-disabled-packages ',(mapcar #'car (doom-find-packages :disabled t))
package-activated-list ',package-activated-list) package-activated-list ',package-activated-list)
(current-buffer))) (current-buffer)))
@ -354,10 +352,10 @@ This should be run whenever your `doom!' block or update your packages."
(with-temp-file doom-package-autoload-file (with-temp-file doom-package-autoload-file
(doom--generate-header 'doom-reload-package-autoloads) (doom--generate-header 'doom-reload-package-autoloads)
(save-excursion (save-excursion
;; Cache the important and expensive-to-initialize state here. ;; Cache important and expensive-to-initialize state here.
(doom--generate-var-cache) (doom--generate-var-cache)
(print! (green "✓ Cached package state")) (print! (green "✓ Cached package state"))
;; Loop through packages and concatenate all their autoloads files. ;; Concatenate the autoloads of all installed packages.
(doom--generate-package-autoloads) (doom--generate-package-autoloads)
(print! (green "✓ Package autoloads included"))) (print! (green "✓ Package autoloads included")))
;; Remove `load-path' and `auto-mode-alist' modifications (most of them, ;; Remove `load-path' and `auto-mode-alist' modifications (most of them,

View file

@ -60,6 +60,9 @@ packages and regenerates the autoloads file."
(doom-packages-install doom-auto-accept) (doom-packages-install doom-auto-accept)
(print! "Regenerating autoloads files") (print! "Regenerating autoloads files")
(doom-reload-autoloads nil 'force-p) (doom-reload-autoloads nil 'force-p)
(when (y-or-n-p "Download and install all-the-icon's fonts?")
(require 'all-the-icons)
(all-the-icons-install-fonts 'yes))
(print! (bold (green "\nFinished! Doom is ready to go!\n"))) (print! (bold (green "\nFinished! Doom is ready to go!\n")))
(with-temp-buffer (with-temp-buffer
(doom-template-insert "QUICKSTART_INTRO") (doom-template-insert "QUICKSTART_INTRO")

View file

@ -16,46 +16,46 @@ If neither is available, run all tests in all enabled modules."
;; Core libraries aren't fully loaded in a noninteractive session, so we ;; Core libraries aren't fully loaded in a noninteractive session, so we
;; reload it with `noninteractive' set to nil to force them to. ;; reload it with `noninteractive' set to nil to force them to.
(quiet! (doom-reload-autoloads)) (quiet! (doom-reload-autoloads))
(doom-initialize 'force t) (let ((doom-modules (doom-modules))
(doom-initialize-modules 'force) noninteractive)
(let ((target-paths (let ((target-paths
;; Convert targets into a list of string paths, pointing to the root ;; Convert targets into a list of string paths, pointing to the root
;; directory of modules ;; directory of modules
(cond ((stringp (car modules)) ; command line (cond ((stringp (car modules)) ; command line
(save-match-data (save-match-data
(cl-loop for arg in modules (cl-loop for arg in modules
if (string= arg ":core") collect doom-core-dir if (string= arg ":core") collect doom-core-dir
else if (string-match-p "/" arg) else if (string-match-p "/" arg)
nconc (mapcar (apply-partially #'expand-file-name arg) nconc (mapcar (apply-partially #'expand-file-name arg)
doom-modules-dirs) doom-modules-dirs)
else else
nconc (cl-loop for dir in doom-modules-dirs nconc (cl-loop for dir in doom-modules-dirs
for path = (expand-file-name arg dir) for path = (expand-file-name arg dir)
if (file-directory-p path) if (file-directory-p path)
nconc (doom-files-in path :type 'dirs :depth 1 :full t)) nconc (doom-files-in path :type 'dirs :depth 1 :full t))
finally do (setq argv nil)))) finally do (setq argv nil))))
(modules ; cons-cells given to MODULES (modules ; cons-cells given to MODULES
(cl-loop for (module . submodule) in modules (cl-loop for (module . submodule) in modules
if (doom-module-locate-path module submodule) if (doom-module-locate-path module submodule)
collect it)) collect it))
((append (list doom-core-dir) ((append (list doom-core-dir)
(doom-module-load-path)))))) (doom-module-load-path))))))
;; Load all the unit test files... ;; Load all the unit test files...
(require 'buttercup) (require 'buttercup)
(mapc (lambda (file) (load file :noerror (not doom-debug-mode))) (mapc (lambda (file) (load file :noerror (not doom-debug-mode)))
(doom-files-in (mapcar (apply-partially #'expand-file-name "test/") (doom-files-in (mapcar (apply-partially #'expand-file-name "test/")
target-paths) target-paths)
:match "\\.el$" :full t)) :match "\\.el$" :full t))
;; ... then run them ;; ... then run them
(when doom-debug-mode (when doom-debug-mode
(setq buttercup-stack-frame-style 'pretty)) (setq buttercup-stack-frame-style 'pretty))
(let ((split-width-threshold 0) (let ((split-width-threshold 0)
(split-height-threshold 0) (split-height-threshold 0)
(window-min-width 0) (window-min-width 0)
(window-min-height 0)) (window-min-height 0))
(buttercup-run)))) (buttercup-run)))))
;; ;;

View file

@ -21,7 +21,7 @@ successfully sets indent_style/indent_size.")
detected.") detected.")
(setq-default (setq-default
large-file-warning-threshold 30000000 large-file-warning-threshold 15000000
vc-follow-symlinks t vc-follow-symlinks t
;; Save clipboard contents into kill-ring before replacing them ;; Save clipboard contents into kill-ring before replacing them
save-interprogram-paste-before-kill t save-interprogram-paste-before-kill t
@ -37,7 +37,7 @@ detected.")
hscroll-margin 2 hscroll-margin 2
hscroll-step 1 hscroll-step 1
scroll-conservatively 1001 scroll-conservatively 1001
scroll-margin 0 scroll-margin 2
scroll-preserve-screen-position t scroll-preserve-screen-position t
;; Whitespace (see `editorconfig') ;; Whitespace (see `editorconfig')
indent-tabs-mode nil indent-tabs-mode nil
@ -52,23 +52,14 @@ detected.")
;; Remove hscroll-margin in shells, otherwise it causes jumpiness ;; Remove hscroll-margin in shells, otherwise it causes jumpiness
(setq-hook! '(eshell-mode-hook term-mode-hook) hscroll-margin 0) (setq-hook! '(eshell-mode-hook term-mode-hook) hscroll-margin 0)
(defun doom|check-large-file () (defun doom*optimize-literal-mode-for-large-files (buffer)
"Check if the buffer's file is large (see `doom-large-file-size'). If so, ask "TODO"
for confirmation to open it literally (read-only, disabled undo and in (with-current-buffer buffer
fundamental-mode) for performance sake." (when find-file-literally
(when (and (not (memq major-mode doom-large-file-modes-list)) (setq buffer-read-only t)
auto-mode-alist (buffer-disable-undo))
(get-buffer-window)) buffer))
(when-let* ((size (nth 7 (file-attributes buffer-file-name)))) (advice-add #'find-file-noselect-1 :filter-return #'doom*optimize-literal-mode-for-large-files)
(when (and (> size (* 1024 1024 doom-large-file-size))
(y-or-n-p
(format (concat "%s is a large file, open literally to "
"avoid performance issues?")
(file-relative-name buffer-file-name))))
(setq buffer-read-only t)
(buffer-disable-undo)
(fundamental-mode)))))
(add-hook 'find-file-hook #'doom|check-large-file)
;; ;;
@ -156,7 +147,7 @@ savehist file."
(def-package! smartparens (def-package! smartparens
;; Auto-close delimiters and blocks as you type. It's more powerful than that, ;; Auto-close delimiters and blocks as you type. It's more powerful than that,
;; but that is all Doom uses it for. ;; but that is all Doom uses it for.
:after-call (doom-exit-buffer-hook after-find-file) :after-call (doom-switch-buffer-hook after-find-file)
:commands (sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string) :commands (sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string)
:config :config
(require 'smartparens-config) (require 'smartparens-config)
@ -229,9 +220,9 @@ savehist file."
(advice-add #'dtrt-indent-mode :around #'doom*fix-broken-smie-modes)) (advice-add #'dtrt-indent-mode :around #'doom*fix-broken-smie-modes))
(def-package! undo-tree (def-package! undo-tree
;; Branching & persistent undo ;; Branching & persistent undo
:after-call (doom-exit-buffer-hook after-find-file) :after-call (doom-switch-buffer-hook after-find-file)
:config :config
(setq undo-tree-auto-save-history t (setq undo-tree-auto-save-history t
;; undo-in-region is known to cause undo history corruption, which can ;; undo-in-region is known to cause undo history corruption, which can
@ -278,23 +269,29 @@ savehist file."
command-log-mode-is-global t)) command-log-mode-is-global t))
(def-package! expand-region
:commands (er/contract-region er/mark-symbol er/mark-word)
:config
(defun doom*quit-expand-region ()
"Properly abort an expand-region region."
(when (memq last-command '(er/expand-region er/contract-region))
(er/contract-region 0)))
(advice-add #'evil-escape :before #'doom*quit-expand-region)
(advice-add #'doom/escape :before #'doom*quit-expand-region))
;; `helpful' --- a better *help* buffer ;; `helpful' --- a better *help* buffer
(let ((map (current-global-map))) (def-package! helpful
(define-key map [remap describe-function] #'helpful-callable) :commands helpful--read-symbol
(define-key map [remap describe-command] #'helpful-command) :init
(define-key map [remap describe-variable] #'helpful-variable) (define-key!
(define-key map [remap describe-key] #'helpful-key)) [remap describe-function] #'helpful-callable
[remap describe-command] #'helpful-command
[remap describe-variable] #'helpful-variable
[remap describe-key] #'helpful-key
[remap describe-symbol] #'doom/describe-symbol)
(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)))))))
(def-package! ws-butler (def-package! ws-butler

View file

@ -2,26 +2,54 @@
;; A centralized keybinds system, integrated with `which-key' to preview ;; A centralized keybinds system, integrated with `which-key' to preview
;; available keybindings. All built into one powerful macro: `map!'. If evil is ;; available keybindings. All built into one powerful macro: `map!'. If evil is
;; never loaded, then evil bindings set with `map!' will be ignored. ;; never loaded, then evil bindings set with `map!' are ignored (i.e. omitted
;; entirely for performance reasons).
(defvar doom-leader-key "SPC" (defvar doom-leader-key "SPC"
"The leader prefix key for Evil users.") "The leader prefix key for Evil users.
This needs to be changed from $DOOMDIR/init.el.")
(defvar doom-leader-alt-key "M-SPC" (defvar doom-leader-alt-key "M-SPC"
"An alternative leader prefix key, used for Insert and Emacs states, and for "An alternative leader prefix key, used for Insert and Emacs states, and for
non-evil users.") non-evil users.
This needs to be changed from $DOOMDIR/init.el.")
(defvar doom-localleader-key "SPC m" (defvar doom-localleader-key "SPC m"
"The localleader prefix key, for major-mode specific commands.") "The localleader prefix key, for major-mode specific commands.
This needs to be changed from $DOOMDIR/init.el.")
(defvar doom-localleader-alt-key "M-SPC m" (defvar doom-localleader-alt-key "M-SPC m"
"The localleader prefix key, for major-mode specific commands.") "The localleader prefix key, for major-mode specific commands. Used for Insert
and Emacs states, and for non-evil users.
This needs to be changed from $DOOMDIR/init.el.")
(defvar doom-leader-map (make-sparse-keymap) (defvar doom-leader-map (make-sparse-keymap)
"An overriding keymap for <leader> keys.") "An overriding keymap for <leader> keys.")
(defvar doom-which-key-leader-prefix-regexp nil)
;; ;;
;;; Universal, non-nuclear escape
;; `keyboard-quit' is too much of a nuclear option. I wanted an ESC/C-g to
;; do-what-I-mean. It serves four purposes (in order):
;;
;; 1. Quit active states; e.g. highlights, searches, snippets, iedit,
;; multiple-cursors, recording macros, etc.
;; 2. Close popup windows remotely (if it is allowed to)
;; 3. Refresh buffer indicators, like git-gutter and flycheck
;; 4. Or fall back to `keyboard-quit'
;;
;; And it should do these things incrementally, rather than all at once. And it
;; shouldn't interfere with recording macros or the minibuffer. This may require
;; you press ESC/C-g two or three times on some occasions to reach
;; `keyboard-quit', but this is much more intuitive.
(defvar doom-escape-hook nil (defvar doom-escape-hook nil
"A hook run after C-g is pressed (or ESC in normal mode, for evil users). Both "A hook run after C-g is pressed (or ESC in normal mode, for evil users). Both
trigger `doom/escape'. trigger `doom/escape'.
@ -29,13 +57,13 @@ trigger `doom/escape'.
If any hook returns non-nil, all hooks after it are ignored.") If any hook returns non-nil, all hooks after it are ignored.")
(defun doom/escape () (defun doom/escape ()
"Run the `doom-escape-hook'." "Run `doom-escape-hook'."
(interactive) (interactive)
(cond ((minibuffer-window-active-p (minibuffer-window)) (cond ((minibuffer-window-active-p (minibuffer-window))
;; quit the minibuffer if open. ;; quit the minibuffer if open.
(abort-recursive-edit)) (abort-recursive-edit))
;; Run all escape hooks. If any returns non-nil, then stop there. ;; Run all escape hooks. If any returns non-nil, then stop there.
((cl-find-if #'funcall doom-escape-hook)) ((run-hook-with-args-until-success 'doom-escape-hook))
;; don't abort macros ;; don't abort macros
((or defining-kbd-macro executing-kbd-macro) nil) ((or defining-kbd-macro executing-kbd-macro) nil)
;; Back to the default ;; Back to the default
@ -45,53 +73,122 @@ If any hook returns non-nil, all hooks after it are ignored.")
;; ;;
;; General ;;; General + leader/localleader keys
(require 'general) (require 'general)
;; Convenience aliases ;; Convenience aliases
(defalias 'define-key! #'general-def) (defalias 'define-key! #'general-def)
(defalias 'unmap! #'general-unbind) (defalias 'unmap! #'general-unbind)
;; leader/localleader keys ;; We avoid `general-create-definer' to ensure that :states, :wk-full-keys and
(defvar doom-leader-alist `((t . ,doom-leader-map)))
(add-to-list 'emulation-mode-map-alists 'doom-leader-alist)
;; We avoid `general-create-definer' to ensure that :states, :prefix and
;; :keymaps cannot be overwritten. ;; :keymaps cannot be overwritten.
(defmacro define-leader-key! (&rest args) (defmacro define-leader-key! (&rest args)
`(general-define-key `(general-define-key
:states nil :states nil
:wk-full-keys nil
:keymaps 'doom-leader-map :keymaps 'doom-leader-map
:prefix doom-leader-alt-key
,@args)) ,@args))
(general-create-definer define-localleader-key! (general-create-definer define-localleader-key!
:major-modes t :major-modes t
:wk-full-keys nil
:prefix doom-localleader-alt-key) :prefix doom-localleader-alt-key)
;; Because :non-normal-prefix doesn't work for non-evil sessions (only evil's ;; :non-normal-prefix doesn't apply to non-evil sessions (only evil's emacs
;; emacs state), we must redefine `define-localleader-key!' once evil is loaded ;; state), so we must redefine `define-localleader-key!' to behave differently
;; where evil is present.
(after! evil (after! evil
(defmacro define-leader-key! (&rest args)
`(general-define-key
:states '(normal visual motion emacs)
:keymaps 'doom-leader-map
:prefix doom-leader-key
:non-normal-prefix doom-leader-alt-key
,@args))
(general-create-definer define-localleader-key! (general-create-definer define-localleader-key!
:states '(normal visual motion emacs) :states '(normal visual motion emacs)
:major-modes t :major-modes t
:wk-full-keys nil
:prefix doom-localleader-key :prefix doom-localleader-key
:non-normal-prefix doom-localleader-alt-key)) :non-normal-prefix doom-localleader-alt-key))
;; We use a prefix commands instead of general's :prefix/:non-normal-prefix
;; properties because general is incredibly slow binding keys en mass with them
;; in conjunction with :states -- an effective doubling of Doom's startup time!
(define-prefix-command 'doom/leader 'doom-leader-map)
(define-key doom-leader-map [override-state] 'all)
;; Bind `doom-leader-key' and `doom-leader-alt-key' as late as possible to give
;; the user a chance to modify them.
(defun doom|init-leader-keys ()
"Bind `doom-leader-key' and `doom-leader-alt-key'."
(let ((map general-override-mode-map))
(if (not (featurep 'evil))
(define-key map (kbd doom-leader-alt-key) 'doom/leader)
(evil-define-key* '(normal visual motion) map (kbd doom-leader-key) 'doom/leader)
(evil-define-key* '(emacs insert) map (kbd doom-leader-alt-key) 'doom/leader))
(general-override-mode +1))
(unless (stringp doom-which-key-leader-prefix-regexp)
(setq doom-which-key-leader-prefix-regexp
(concat "\\(?:"
(cl-loop for key in (append (list doom-leader-key doom-leader-alt-key)
(where-is-internal 'doom/leader))
if (stringp key) collect key into keys
else collect (key-description key) into keys
finally return (string-join keys "\\|"))
"\\)"))))
(add-hook 'doom-after-init-modules-hook #'doom|init-leader-keys)
;; However, the prefix command approach (along with :wk-full-keys in
;; `define-leader-key!') means that which-key is only informed of the key
;; sequence minus `doom-leader-key'/`doom-leader-alt-key'. e.g. binding to `SPC
;; f s' creates a wildcard label for any key that ends in 'f s'.
;;
;; So we forcibly inject `doom-leader-key' and `doom-leader-alt-key' into the
;; which-key key replacement regexp for keybinds created on `doom-leader-map'.
;; This is a dirty hack, but I'd rather this than general being responsible for
;; 50% of Doom's startup time.
(defun doom*general-extended-def-:which-key (_state keymap key edef kargs)
(with-eval-after-load 'which-key
(let* ((wk (general--getf2 edef :which-key :wk))
(major-modes (general--getf edef kargs :major-modes))
(keymaps (plist-get kargs :keymaps))
;; index of keymap in :keymaps
(keymap-index (cl-dotimes (ind (length keymaps))
(when (eq (nth ind keymaps) keymap)
(cl-return ind))))
(mode (let ((mode (if (and major-modes (listp major-modes))
(nth keymap-index major-modes)
major-modes)))
(if (eq mode t)
(general--remove-map keymap)
mode)))
(key (key-description key))
(key-regexp (concat (if (general--getf edef kargs :wk-full-keys)
"\\`"
;; Modification begin
(if (memq 'doom-leader-map keymaps)
(concat "\\`" doom-which-key-leader-prefix-regexp " ")))
;; Modification end
(regexp-quote key)
"\\'"))
(prefix (plist-get kargs :prefix))
(binding (or (when (and (plist-get edef :def)
(not (plist-get edef :keymp)))
(plist-get edef :def))
(when (and prefix (string= key prefix))
(plist-get kargs :prefix-command))))
(replacement (cond ((stringp wk)
(cons nil wk))
(wk)))
(match/replacement
(cons
(cons (when (general--getf edef kargs :wk-match-keys)
key-regexp)
(when (and (general--getf edef kargs :wk-match-binding)
binding
(symbolp binding))
(symbol-name binding)))
replacement)))
(general--add-which-key-replacement mode match/replacement)
(when (and (consp replacement) (not (functionp replacement)))
(general--add-which-key-title-prefix mode key (cdr replacement))))))
(advice-add #'general-extended-def-:which-key :override #'doom*general-extended-def-:which-key)
;; ;;
;; Packages ;;; Packages
(def-package! which-key (def-package! which-key
:defer 1 :defer 1
@ -111,11 +208,13 @@ If any hook returns non-nil, all hooks after it are ignored.")
(which-key-mode +1)) (which-key-mode +1))
;; `hydra' ;;;###package hydra
(setq lv-use-seperator t) (setq lv-use-seperator t)
;; ;;
;;; `map!' macro
(defvar doom-evil-state-alist (defvar doom-evil-state-alist
'((?n . normal) '((?n . normal)
(?v . visual) (?v . visual)

View file

@ -1,20 +1,7 @@
;;; core-lib.el -*- lexical-binding: t; -*- ;;; core-lib.el -*- lexical-binding: t; -*-
;; Built-in packages we use a lot of
(require 'subr-x)
(require 'cl-lib)
(eval-and-compile
(unless EMACS26+
(with-no-warnings
;; if-let and when-let were moved to (if|when)-let* in Emacs 26+ so we
;; alias them for 25 users.
(defalias 'if-let* #'if-let)
(defalias 'when-let* #'when-let))))
;; ;;
;; Helpers ;;; Helpers
(defun doom--resolve-path-forms (spec &optional directory) (defun doom--resolve-path-forms (spec &optional directory)
"Converts a simple nested series of or/and forms into a series of "Converts a simple nested series of or/and forms into a series of
@ -23,23 +10,27 @@
For example For example
(doom--resolve-path-forms (doom--resolve-path-forms
'(or \"some-file\" (and path-var \"/an/absolute/path\")) '(or A (and B C))
\"~\") \"~\")
Returns Returns (approximately):
'(let ((_directory \"~\")) '(let* ((_directory \"~\")
(or (file-exists-p (expand-file-name \"some-file\" _directory)) (A (expand-file-name A _directory))
(and (file-exists-p (expand-file-name path-var _directory)) (B (expand-file-name B _directory))
(file-exists-p \"/an/absolute/path\")))) (C (expand-file-name C _directory)))
(or (and (file-exists-p A) A)
(and (if (file-exists-p B) B)
(if (file-exists-p C) C))))
This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'." This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
(declare (pure t) (side-effect-free t)) (declare (pure t) (side-effect-free t))
(cond ((stringp spec) (cond ((stringp spec)
`(file-exists-p `(let ((--file-- ,(if (file-name-absolute-p spec)
,(if (file-name-absolute-p spec) spec
spec `(expand-file-name ,spec ,directory))))
`(expand-file-name ,spec ,directory)))) (and (file-exists-p --file--)
--file--)))
((and (listp spec) ((and (listp spec)
(memq (car spec) '(or and))) (memq (car spec) '(or and)))
`(,(car spec) `(,(car spec)
@ -47,12 +38,14 @@ This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
collect (doom--resolve-path-forms i directory)))) collect (doom--resolve-path-forms i directory))))
((or (symbolp spec) ((or (symbolp spec)
(listp spec)) (listp spec))
`(file-exists-p ,(if (and directory `(let ((--file-- ,(if (and directory
(or (not (stringp directory)) (or (not (stringp directory))
(file-name-absolute-p directory))) (file-name-absolute-p directory)))
`(expand-file-name ,spec ,directory) `(expand-file-name ,spec ,directory)
spec))) spec)))
(t spec))) (and (file-exists-p --file--)
--file--)))
(spec)))
(defun doom--resolve-hook-forms (hooks) (defun doom--resolve-hook-forms (hooks)
(declare (pure t) (side-effect-free t)) (declare (pure t) (side-effect-free t))
@ -76,7 +69,7 @@ This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
;; ;;
;; Public library ;;; Public library
(defun doom-unquote (exp) (defun doom-unquote (exp)
"Return EXP unquoted." "Return EXP unquoted."
@ -102,6 +95,23 @@ This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
(cl-check-type :test keyword) (cl-check-type :test keyword)
(substring (symbol-name keyword) 1)) (substring (symbol-name keyword) 1))
(defmacro doom-log (format-string &rest args)
"Log to *Messages* if `doom-debug-mode' is on.
Does not interrupt the minibuffer if it is in use, but still logs to *Messages*.
Accepts the same arguments as `message'."
`(when doom-debug-mode
(let ((inhibit-message (active-minibuffer-window)))
(message
,(concat (propertize "DOOM " 'face 'font-lock-comment-face)
format-string
(when doom--current-module
(propertize
(format " [%s/%s]"
(doom-keyword-name (car doom--current-module))
(cdr doom--current-module))
'face 'warning)))
,@args))))
(defun FILE! () (defun FILE! ()
"Return the emacs lisp file this macro is called from." "Return the emacs lisp file this macro is called from."
(cond ((bound-and-true-p byte-compile-current-file)) (cond ((bound-and-true-p byte-compile-current-file))
@ -143,20 +153,25 @@ serve as a predicated alternative to `after!'."
(add-hook 'after-load-functions #',fun))))) (add-hook 'after-load-functions #',fun)))))
(defmacro defer-feature! (feature &optional mode) (defmacro defer-feature! (feature &optional mode)
"TODO" "Pretend FEATURE hasn't been loaded yet, until FEATURE-hook is triggered.
Some packages (like `elisp-mode' and `lisp-mode') are loaded immediately at
startup, which will prematurely trigger `after!' (and `with-eval-after-load')
blocks. To get around this we make Emacs believe FEATURE hasn't been loaded yet,
then wait until FEATURE-hook (or MODE-hook, if MODE is provided) is triggered to
reverse this and trigger `after!' blocks at a more reasonable time."
(let ((advice-fn (intern (format "doom|defer-feature-%s" feature))) (let ((advice-fn (intern (format "doom|defer-feature-%s" feature)))
(mode (or mode feature))) (mode (or mode feature)))
`(progn `(progn
(delq ',feature features) (setq features (delq ',feature features))
(advice-add #',mode :before #',advice-fn) (advice-add #',mode :before #',advice-fn)
(defun ,advice-fn (&rest _) (defun ,advice-fn (&rest _)
;; Some plugins (like yasnippet) run `lisp-mode' early, to parse some ;; Some plugins (like yasnippet) will invoke a mode early, e.g. to
;; elisp. This would prematurely trigger this function. In these cases, ;; parse some code. This would prematurely trigger this function. This
;; `lisp-mode-hook' is let-bound to nil or its hooks are delayed, so if ;; checks for that:
;; we see either, keep pretending elisp-mode isn't loaded.
(when (and ,(intern (format "%s-hook" mode)) (when (and ,(intern (format "%s-hook" mode))
(not delay-mode-hooks)) (not delay-mode-hooks))
;; Otherwise, announce to the world elisp-mode has been loaded, so ;; Otherwise, announce to the world this package has been loaded, so
;; `after!' handlers can respond and configure elisp-mode as ;; `after!' handlers can respond and configure elisp-mode as
;; expected. ;; expected.
(provide ',feature) (provide ',feature)
@ -279,7 +294,9 @@ Examples:
(add-hook! :append :local (one-mode second-mode) (setq v 5) (setq a 2)) (add-hook! :append :local (one-mode second-mode) (setq v 5) (setq a 2))
Body forms can access the hook's arguments through the let-bound variable Body forms can access the hook's arguments through the let-bound variable
`args'." `args'.
\(fn [:append :local] HOOKS FUNCTIONS)"
(declare (indent defun) (debug t)) (declare (indent defun) (debug t))
(let ((hook-fn 'add-hook) (let ((hook-fn 'add-hook)
append-p local-p) append-p local-p)
@ -310,7 +327,9 @@ Body forms can access the hook's arguments through the let-bound variable
(defmacro remove-hook! (&rest args) (defmacro remove-hook! (&rest args)
"Convenience macro for `remove-hook'. Takes the same arguments as "Convenience macro for `remove-hook'. Takes the same arguments as
`add-hook!'." `add-hook!'.
\(fn [:append :local] HOOKS FUNCTIONS)"
(declare (indent defun) (debug t)) (declare (indent defun) (debug t))
`(add-hook! :remove ,@args)) `(add-hook! :remove ,@args))
@ -331,6 +350,33 @@ Body forms can access the hook's arguments through the let-bound variable
(push `(setq-local ,var ,val) forms))) (push `(setq-local ,var ,val) forms)))
(nreverse forms)))) (nreverse forms))))
(defun advice-add! (symbols where functions)
"Variadic version of `advice-add'.
SYMBOLS and FUNCTIONS can be lists of functions."
(let ((functions (if (functionp functions)
(list functions)
functions)))
(dolist (s (doom-enlist symbols))
(dolist (f (doom-enlist functions))
(advice-add s where f)))))
(defun advice-remove! (symbols where-or-fns &optional functions)
"Variadic version of `advice-remove'.
WHERE-OR-FNS is ignored if FUNCTIONS is provided. This lets you substitute
advice-add with advice-remove and evaluate them without having to modify every
statement."
(unless functions
(setq functions where-or-fns
where-or-fns nil))
(let ((functions (if (functionp functions)
(list functions)
functions)))
(dolist (s (doom-enlist symbols))
(dolist (f (doom-enlist functions))
(advice-remove s f)))))
(cl-defmacro associate! (mode &key modes match files when) (cl-defmacro associate! (mode &key modes match files when)
"Enables a minor mode if certain conditions are met. "Enables a minor mode if certain conditions are met.
@ -377,16 +423,15 @@ The available conditions are:
mode modes match files when))))) mode modes match files when)))))
(defmacro file-exists-p! (spec &optional directory) (defmacro file-exists-p! (spec &optional directory)
"Returns t if the files in SPEC all exist. "Returns non-nil if the files in SPEC all exist.
SPEC can be a single file or a list of forms/files. It understands nested (and Returns the last file found to meet the rules set by SPEC. SPEC can be a single
...) and (or ...), as well. file or a list of forms/files. It understands nested (and ...) and (or ...), as
well.
DIRECTORY is where to look for the files in SPEC if they aren't absolute. This DIRECTORY is where to look for the files in SPEC if they aren't absolute.
doesn't apply to variables, however.
For example: For example:
(file-exists-p! (or doom-core-dir \"~/.config\" \"some-file\") \"~\")" (file-exists-p! (or doom-core-dir \"~/.config\" \"some-file\") \"~\")"
(if directory (if directory
`(let ((--directory-- ,directory)) `(let ((--directory-- ,directory))

View file

@ -17,7 +17,8 @@
(syntax-checker (:tools flycheck))) (syntax-checker (:tools flycheck)))
(:tools (rotate-text (:editor rotate-text))) (:tools (rotate-text (:editor rotate-text)))
(:emacs (electric-indent (:emacs electric)) (:emacs (electric-indent (:emacs electric))
(hideshow (:editor fold)))) (hideshow (:editor fold)))
(:ui (doom-modeline (:ui modeline))))
"An alist of deprecated modules, mapping deprecated modules to an optional new "An alist of deprecated modules, mapping deprecated modules to an optional new
location (which will create an alias). Each CAR and CDR is a (CATEGORY . location (which will create an alias). Each CAR and CDR is a (CATEGORY .
MODULES). E.g. MODULES). E.g.
@ -32,7 +33,24 @@ A warning will be put out if these deprecated modules are used.")
;; ;;
;; Bootstrap API ;;; Custom hooks
(defvar doom-before-init-modules-hook nil
"A list of hooks to run before Doom's modules' config.el files are loaded, but
after their init.el files are loaded.")
(defvar doom-init-modules-hook nil
"A list of hooks to run after Doom's modules' config.el files have loaded, but
before the user's private module.")
(defvaralias 'doom-after-init-modules-hook 'after-init-hook)
(define-obsolete-variable-alias 'doom-post-init-hook 'doom-init-modules-hook "2.1.0")
(define-obsolete-variable-alias 'doom-init-hook 'doom-before-init-modules-hook "2.1.0")
;;
;;; Bootstrap API
(defun doom-initialize-modules (&optional force-p) (defun doom-initialize-modules (&optional force-p)
"Loads the init.el in `doom-private-dir' and sets up hooks for a healthy "Loads the init.el in `doom-private-dir' and sets up hooks for a healthy
@ -50,23 +68,23 @@ non-nil."
(doom--current-flags (plist-get plist :flags))) (doom--current-flags (plist-get plist :flags)))
(load! "init" (plist-get plist :path) t))) (load! "init" (plist-get plist :path) t)))
doom-modules) doom-modules)
(run-hook-wrapped 'doom-init-hook #'doom-try-run-hook) (run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook)
(unless noninteractive (unless noninteractive
(maphash (lambda (key plist) (maphash (lambda (key plist)
(let ((doom--current-module key) (let ((doom--current-module key)
(doom--current-flags (plist-get plist :flags))) (doom--current-flags (plist-get plist :flags)))
(load! "config" (plist-get plist :path) t))) (load! "config" (plist-get plist :path) t)))
doom-modules) doom-modules)
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
(load! "config" doom-private-dir t) (load! "config" doom-private-dir t)
(unless custom-file (unless custom-file
(setq custom-file (concat doom-local-dir "custom.el"))) (setq custom-file (concat doom-local-dir "custom.el")))
(when (stringp custom-file) (when (stringp custom-file)
(load custom-file t t t)) (load custom-file t t t)))))
(run-hook-wrapped 'doom-post-init-hook #'doom-try-run-hook))))
;; ;;
;; Module API ;;; Module API
(defun doom-module-p (category module) (defun doom-module-p (category module)
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')." "Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
@ -176,7 +194,6 @@ non-nil, return paths of possible modules, activated or otherwise."
(let ((noninteractive t) (let ((noninteractive t)
doom-modules doom-modules
doom-init-modules-p) doom-init-modules-p)
(message "Initializing modules")
(load! "init" doom-private-dir t) (load! "init" doom-private-dir t)
(or doom-modules (or doom-modules
(make-hash-table :test 'equal (make-hash-table :test 'equal
@ -185,7 +202,7 @@ non-nil, return paths of possible modules, activated or otherwise."
;; ;;
;; Use-package modifications ;;; Use-package modifications
(autoload 'use-package "use-package-core" nil nil t) (autoload 'use-package "use-package-core" nil nil t)
@ -194,43 +211,24 @@ non-nil, return paths of possible modules, activated or otherwise."
use-package-minimum-reported-time (if doom-debug-mode 0 0.1) use-package-minimum-reported-time (if doom-debug-mode 0 0.1)
use-package-expand-minimally (not noninteractive)) use-package-expand-minimally (not noninteractive))
;; Adds two new keywords to `use-package' (and consequently, `def-package!'), ;; Adds two new keywords to `use-package' (and consequently, `def-package!') to
;; they are: ;; expand its lazy-loading capabilities. They are:
;; ;;
;; :after-call SYMBOL|LIST ;; :after-call SYMBOL|LIST
;; Takes a symbol or list of symbols representing functions or hook variables.
;; The first time any of these functions or hooks are executed, the package is
;; loaded. e.g.
;;
;; (def-package! projectile
;; :after-call (pre-command-hook after-find-file dired-before-readin-hook)
;; ...)
;;
;; :defer-incrementally SYMBOL|LIST|t ;; :defer-incrementally SYMBOL|LIST|t
;; Takes a symbol or list of symbols representing packages that will be loaded
;; incrementally at startup before this one. This is helpful for large
;; packages like magit or org, which load a lot of dependencies on first load.
;; This lets you load them piece-meal, one at a time, during idle periods, so
;; that when you finally do need the package, it'll loads much quicker. e.g.
;; ;;
;; (def-package! magit ;; Check out `def-package!'s documentation for more about these two.
;; ;; You do not need to include magit in this list!
;; :defer-incrementally (dash f s with-editor git-commit package)
;; ...)
;;
;; (def-package! x
;; ;; This is equivalent to :defer-incrementally (x)
;; :defer-incrementally t
;; ...)
(defvar doom--deferred-packages-alist '(t)) (defvar doom--deferred-packages-alist '(t))
(after! use-package-core (after! use-package-core
(add-to-list 'use-package-deferring-keywords :defer-incrementally nil #'eq) ;; :ensure and :pin don't work well with Doom, so we forcibly remove them.
(add-to-list 'use-package-deferring-keywords :after-call nil #'eq) (dolist (keyword '(:ensure :pin))
(setq use-package-keywords (delq keyword use-package-keywords)))
(setq use-package-keywords ;; Insert new deferring keywords
(use-package-list-insert :defer-incrementally use-package-keywords :after)) (dolist (keyword '(:defer-incrementally :after-call))
(setq use-package-keywords (add-to-list 'use-package-deferring-keywords keyword nil #'eq)
(use-package-list-insert :after-call use-package-keywords :after)) (setq use-package-keywords
(use-package-list-insert keyword use-package-keywords :after)))
(defalias 'use-package-normalize/:defer-incrementally 'use-package-normalize-symlist) (defalias 'use-package-normalize/:defer-incrementally 'use-package-normalize-symlist)
(defun use-package-handler/:defer-incrementally (name _keyword targets rest state) (defun use-package-handler/:defer-incrementally (name _keyword targets rest state)
@ -249,18 +247,18 @@ non-nil, return paths of possible modules, activated or otherwise."
(use-package-concat (use-package-concat
`((fset ',fn `((fset ',fn
(lambda (&rest _) (lambda (&rest _)
(when doom-debug-mode (doom-log "Loading deferred package %s from %s" ',name ',fn)
(message "Loading deferred package %s from %s" ',name ',fn)) (condition-case e
(condition-case e (require ',name) (require ',name)
((debug error) ((debug error)
(message "Failed to load deferred package %s: %s" ',name e))) (message "Failed to load deferred package %s: %s" ',name e)))
(dolist (hook (cdr (assq ',name doom--deferred-packages-alist))) (when-let* ((deferral-list (assq ',name doom--deferred-packages-alist)))
(if (functionp hook) (dolist (hook (cdr deferral-list))
(advice-remove hook #',fn) (if (functionp hook)
(remove-hook hook #',fn))) (advice-remove hook #',fn)
(delq (assq ',name doom--deferred-packages-alist) (remove-hook hook #',fn)))
doom--deferred-packages-alist) (setq doom--deferred-packages-alist
(fmakunbound ',fn)))) (delq deferral-list doom--deferred-packages-alist))))))
(let (forms) (let (forms)
(dolist (hook hooks forms) (dolist (hook hooks forms)
(push (if (functionp hook) (push (if (functionp hook)
@ -275,7 +273,7 @@ non-nil, return paths of possible modules, activated or otherwise."
;; ;;
;; Module config macros ;;; Module config macros
(defmacro doom! (&rest modules) (defmacro doom! (&rest modules)
"Bootstraps DOOM Emacs and its modules. "Bootstraps DOOM Emacs and its modules.
@ -294,12 +292,14 @@ The overall load order of Doom is as follows:
~/.emacs.d/core/core.el ~/.emacs.d/core/core.el
$DOOMDIR/init.el $DOOMDIR/init.el
{$DOOMDIR,~/.emacs.d}/modules/*/*/init.el {$DOOMDIR,~/.emacs.d}/modules/*/*/init.el
`doom-init-hook' `doom-before-init-modules-hook'
{$DOOMDIR,~/.emacs.d}/modules/*/*/config.el {$DOOMDIR,~/.emacs.d}/modules/*/*/config.el
`doom-init-modules-hook'
$DOOMDIR/config.el $DOOMDIR/config.el
`doom-after-init-modules-hook'
`after-init-hook' `after-init-hook'
`emacs-startup-hook' `emacs-startup-hook'
`doom-post-init-hook' (at end of `emacs-startup-hook') `window-setup-hook'
Module load order is determined by your `doom!' block. See `doom-modules-dirs' Module load order is determined by your `doom!' block. See `doom-modules-dirs'
for a list of all recognized module trees. Order defines precedence (from most for a list of all recognized module trees. Order defines precedence (from most
@ -335,10 +335,43 @@ to least)."
(defvar doom-disabled-packages) (defvar doom-disabled-packages)
(defmacro def-package! (name &rest plist) (defmacro def-package! (name &rest plist)
"This is a thin wrapper around `use-package'." "This is a thin wrapper around `use-package'.
`(use-package ,name
,@(if (memq name doom-disabled-packages) `(:disabled t)) It is ignored if the NAME package is disabled.
,@plist))
Supports two special properties over `use-package':
:after-call SYMBOL|LIST
Takes a symbol or list of symbols representing functions or hook variables.
The first time any of these functions or hooks are executed, the package is
loaded. e.g.
(def-package! projectile
:after-call (pre-command-hook after-find-file dired-before-readin-hook)
...)
:defer-incrementally SYMBOL|LIST|t
Takes a symbol or list of symbols representing packages that will be loaded
incrementally at startup before this one. This is helpful for large packages
like magit or org, which load a lot of dependencies on first load. This lets
you load them piece-meal during idle periods, so that when you finally do need
the package, it'll load quicker. e.g.
NAME is implicitly added if this property is present and non-nil. No need to
specify it. A value of `t' implies NAME, e.g.
(def-package! x
;; This is equivalent to :defer-incrementally (x)
:defer-incrementally t
...)"
(unless (or (memq name doom-disabled-packages)
;; At compile-time, use-package will forcibly load its package to
;; prevent compile-time errors. However, Doom users can
;; intentionally disable packages, resulting if file-missing
;; package errors, so we preform this check at compile time:
(and (bound-and-true-p byte-compile-current-file)
(not (locate-library (symbol-name name)))))
`(use-package ,name ,@plist)))
(defmacro def-package-hook! (package when &rest body) (defmacro def-package-hook! (package when &rest body)
"Reconfigures a package's `def-package!' block. "Reconfigures a package's `def-package!' block.

View file

@ -1,10 +1,18 @@
;;; core-os.el -*- lexical-binding: t; -*- ;;; core-os.el -*- lexical-binding: t; -*-
;; clipboard ;; clipboard
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING) (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
;; Use a shared clipboard
select-enable-clipboard t ;; fewer opts to process for systems that don't need them
select-enable-primary t) (unless IS-MAC (setq command-line-ns-option-alist nil))
(unless IS-LINUX (setq command-line-x-option-alist nil))
;; Fix the clipboard in terminal or daemon Emacs (non-GUI)
(defun doom|init-clipboard-in-tty-emacs ()
(if IS-MAC
(if (require 'osx-clipboard nil t) (osx-clipboard-mode))
(if (require 'xclip nil t) (xclip-mode))))
(add-hook 'tty-setup-hook #'doom|init-clipboard-in-tty-emacs)
;; stop copying each visual state move to the clipboard: ;; stop copying each visual state move to the clipboard:
;; https://bitbucket.org/lyro/evil/issue/336/osx-visual-state-copies-the-region-on ;; https://bitbucket.org/lyro/evil/issue/336/osx-visual-state-copies-the-region-on
@ -29,14 +37,11 @@
;; than a new one ;; than a new one
ns-pop-up-frames nil) ns-pop-up-frames nil)
;; Fix the clipboard in terminal or daemon Emacs (non-GUI)
(when (or (daemonp) (not (display-graphic-p)))
(add-hook 'doom-post-init-hook #'osx-clipboard-mode))
(when (or (daemonp) (display-graphic-p)) (when (or (daemonp) (display-graphic-p))
;; Syncs ns frame parameters with theme (and fixes mismatching text ;; Syncs ns frame parameters with theme (and fixes mismatching text
;; colr in the frame title) ;; colr in the frame title)
(require 'ns-auto-titlebar nil t) (when (require 'ns-auto-titlebar nil t)
(add-hook 'doom-load-theme-hook #'ns-auto-titlebar-mode))
;; A known problem with GUI Emacs on MacOS (or daemons started via ;; A known problem with GUI Emacs on MacOS (or daemons started via
;; launchctl or brew services): it runs in an isolated ;; launchctl or brew services): it runs in an isolated

View file

@ -87,52 +87,27 @@ If FORCE-P is 'internal, only (re)populate `doom-packages'.
Use this before any of package.el, quelpa or Doom's package management's API to Use this before any of package.el, quelpa or Doom's package management's API to
ensure all the necessary package metadata is initialized and available for ensure all the necessary package metadata is initialized and available for
them." them."
(with-temp-buffer ; prevent buffer-local settings from propagating (let ((load-prefer-newer t)) ; reduce stale code issues
(let ((load-prefer-newer t)) ; reduce stale code issues ;; package.el and quelpa handle themselves if their state changes during the
;; package.el and quelpa handle themselves if their state changes during ;; current session, but if you change an packages.el file in a module,
;; the current session, but if you change an packages.el file in a module, ;; there's no non-trivial way to detect that, so to reload only
;; there's no non-trivial way to detect that, so we give you a way to ;; doom-packages pass 'internal as FORCE-P or use `doom/reload-packages'.
;; reload only doom-packages (by passing 'internal as FORCE-P). (unless (eq force-p 'internal)
(unless (eq force-p 'internal) ;; `package-alist'
;; `package-alist' (when (or force-p (not (bound-and-true-p package-alist)))
(when (or force-p (not (bound-and-true-p package-alist))) (doom-ensure-packages-initialized 'force)
(doom-ensure-packages-initialized 'force) (setq load-path (cl-delete-if-not #'file-directory-p load-path)))
(setq load-path (cl-remove-if-not #'file-directory-p load-path))) ;; `quelpa-cache'
;; `quelpa-cache' (when (or force-p (not (bound-and-true-p quelpa-cache)))
(when (or force-p (not (bound-and-true-p quelpa-cache))) ;; ensure un-byte-compiled version of quelpa is loaded
;; ensure un-byte-compiled version of quelpa is loaded (unless (featurep 'quelpa)
(unless (featurep 'quelpa) (load (locate-library "quelpa.el") nil t t))
(load (locate-library "quelpa.el") nil t t)) (setq quelpa-initialized-p nil)
(setq quelpa-initialized-p nil) (or (quelpa-setup-p)
(or (quelpa-setup-p) (error "Could not initialize quelpa"))))
(error "Could not initialize quelpa")))) ;; `doom-packages'
;; `doom-packages' (when (or force-p (not doom-packages))
(when (or force-p (not doom-packages)) (setq doom-packages (doom-package-list)))))
(cl-flet
((_load
(lambda (file &optional noerror)
(condition-case e
(load file noerror t t)
((debug error)
(signal 'doom-package-error
(list (or (doom-module-from-path file)
'(:private . packages))
e)))))))
(let ((doom-modules (doom-modules))
(doom--stage 'packages)
(noninteractive t))
(setq doom-packages nil)
(_load (expand-file-name "packages.el" doom-core-dir))
;; We load the private packages file twice to ensure disabled
;; packages are seen ASAP, and a second time to ensure privately
;; overridden packages are properly overwritten.
(let ((private-packages (expand-file-name "packages.el" doom-private-dir)))
(_load private-packages t)
(cl-loop for key being the hash-keys of doom-modules
for path = (doom-module-path (car key) (cdr key) "packages.el")
do (let ((doom--current-module key)) (_load path t)))
(_load private-packages t)
(setq doom-packages (reverse doom-packages)))))))))
;; ;;
@ -169,7 +144,7 @@ them."
;; ;;
;; Module package macros ;; Module package macros
(cl-defmacro package! (name &rest plist &key recipe pin disable _ignore _freeze) (cl-defmacro package! (name &rest plist &key built-in recipe pin disable _ignore _freeze)
"Declares a package and how to install it (if applicable). "Declares a package and how to install it (if applicable).
This macro is declarative and does not load nor install packages. It is used to This macro is declarative and does not load nor install packages. It is used to
@ -193,30 +168,48 @@ Accepts the following properties:
Do not install this package. Do not install this package.
:freeze FORM :freeze FORM
Do not update this package if FORM is non-nil. Do not update this package if FORM is non-nil.
:built-in BOOL
Same as :ignore if the package is a built-in Emacs package.
Returns t if package is successfully registered, and nil if it was disabled Returns t if package is successfully registered, and nil if it was disabled
elsewhere." elsewhere."
(declare (indent defun)) (declare (indent defun))
(doom--assert-stage-p 'packages #'package!) (doom--assert-stage-p 'packages #'package!)
(let ((plist (append plist (cdr (assq name doom-packages))))) (let ((old-plist (cdr (assq name doom-packages))))
(when recipe (when recipe
(when (cl-evenp (length recipe)) (when (cl-evenp (length recipe))
(setq plist (plist-put plist :recipe (cons name recipe)))) (setq plist (plist-put plist :recipe (cons name recipe))))
(setq pin nil (setq pin nil
plist (plist-put plist :pin nil))) plist (plist-put plist :pin nil)))
(when (file-in-directory-p (FILE!) doom-private-dir) (let ((module-list (plist-get old-plist :modules))
(setq plist (plist-put plist :private t))) (module (or doom--current-module
(let (newplist) (let ((file (FILE!)))
(while plist (cond ((file-in-directory-p file doom-private-dir)
(unless (null (cadr plist)) (list :private))
(push (cadr plist) newplist) ((file-in-directory-p file doom-core-dir)
(push (car plist) newplist)) (list :core))
(pop plist) ((doom-module-from-path file)))))))
(pop plist)) (doom-log "Registered package '%s'%s"
(setq plist newplist)) name (if recipe (format " with recipe %s" recipe) ""))
(unless (member module module-list)
(setq module-list (append module-list (list module) nil)
plist (plist-put plist :modules module-list))))
(when (and built-in (locate-library (symbol-name name) nil doom-site-load-path))
(doom-log "Ignoring built-in package '%s'" name)
(setq plist (plist-put plist :ignore t)))
(while plist
(unless (null (cadr plist))
(setq old-plist (plist-put old-plist (car plist) (cadr plist))))
(pop plist)
(pop plist))
(setq plist old-plist)
(macroexp-progn (macroexp-progn
(append (if disable `((add-to-list 'doom-disabled-packages ',name nil #'eq))) (append (when disable
(if pin `((setf (alist-get ',name package-pinned-packages) ,pin))) (doom-log "Disabling package '%s'" name)
`((add-to-list 'doom-disabled-packages ',name nil 'eq)))
(when pin
(doom-log "Pinning package '%s' to '%s'" name pin)
`((setf (alist-get ',name package-pinned-packages) ,pin)))
`((setf (alist-get ',name doom-packages) ',plist) `((setf (alist-get ',name doom-packages) ',plist)
(not (memq ',name doom-disabled-packages))))))) (not (memq ',name doom-disabled-packages)))))))

View file

@ -1,7 +1,7 @@
;;; core-projects.el -*- lexical-binding: t; -*- ;;; core-projects.el -*- lexical-binding: t; -*-
(def-package! projectile (def-package! projectile
:after-call (pre-command-hook after-find-file dired-before-readin-hook) :after-call (after-find-file dired-before-readin-hook minibuffer-setup-hook)
:commands (projectile-project-root projectile-project-name projectile-project-p) :commands (projectile-project-root projectile-project-name projectile-project-p)
:init :init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache") (setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
@ -15,9 +15,11 @@
:config :config
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook) (add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
(add-hook 'find-file-hook #'doom|init-project-mode)
(projectile-mode +1) (projectile-mode +1)
(global-set-key [remap evil-jump-to-tag] #'projectile-find-tag)
(global-set-key [remap find-tag] #'projectile-find-tag)
;; a more generic project root file ;; a more generic project root file
(push ".project" projectile-project-root-files-bottom-up) (push ".project" projectile-project-root-files-bottom-up)
@ -66,23 +68,10 @@
;; ;;
;; Project-based minor modes ;; Project-based minor modes
(defvar-local doom-project nil
"Either the symbol or a list of project modes you want to enable. Available
for .dir-locals.el.")
(defvar doom-project-hook nil (defvar doom-project-hook nil
"Hook run when a project is enabled. The name of the project's mode and its "Hook run when a project is enabled. The name of the project's mode and its
state are passed in.") state are passed in.")
(defun doom|init-project-mode ()
"Auto-enable the project(s) listed in `doom-project'."
(when doom-project
(if (symbolp doom-project)
(funcall doom-project)
(cl-loop for mode in doom-project
unless (symbol-value mode)
do (funcall mode)))))
(cl-defmacro def-project-mode! (name &key (cl-defmacro def-project-mode! (name &key
modes modes
files files
@ -94,9 +83,9 @@ state are passed in.")
on-exit) on-exit)
"Define a project minor-mode named NAME (a symbol) and declare where and how "Define a project minor-mode named NAME (a symbol) and declare where and how
it is activated. Project modes allow you to configure 'sub-modes' for it is activated. Project modes allow you to configure 'sub-modes' for
major-modes that are specific to a specific folder, certain project structure, major-modes that are specific to a folder, project structure, framework or
framework or arbitrary context you define. These project modes can have their whatever arbitrary context you define. These project modes can have their own
own settings, keymaps, hooks, snippets, etc. settings, keymaps, hooks, snippets, etc.
This creates NAME-hook and NAME-map as well. This creates NAME-hook and NAME-map as well.

View file

@ -1,9 +1,12 @@
;;; core-ui.el -*- lexical-binding: t; -*- ;;; core-ui.el -*- lexical-binding: t; -*-
;;
;;; Variables
(defvar doom-theme nil (defvar doom-theme nil
"A symbol representing the Emacs theme to load at startup. "A symbol representing the Emacs theme to load at startup.
This is changed when `load-theme' is used as well.") This is changed by `load-theme'.")
(defvar doom-font nil (defvar doom-font nil
"The default font to use. "The default font to use.
@ -48,15 +51,106 @@ Expects either a `font-spec', font object, a XFT font string or XLFD string. See
It is recommended you don't set specify a font-size, as to inherit `doom-font's It is recommended you don't set specify a font-size, as to inherit `doom-font's
size.") size.")
;;
(defvar doom-init-ui-hook nil
"List of hooks to run when the UI has been initialized.")
(defvar doom--prefer-theme-elc nil (defvar doom--prefer-theme-elc nil
"If non-nil, `load-theme' will prefer the compiled theme (unlike its default "If non-nil, `load-theme' will prefer the compiled theme (unlike its default
behavior). Do not set this directly, this is let-bound in `doom|init-theme'.") behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
;;
;;; Custom hooks
(defvar doom-init-ui-hook nil
"List of hooks to run when the UI has been initialized.")
(defvar doom-load-theme-hook nil
"Hook run after the theme is loaded with `load-theme' or reloaded with
`doom/reload-theme'.")
(defvar doom-switch-buffer-hook nil
"TODO")
(defvar doom-switch-window-hook nil
"TODO")
(defvar doom-switch-frame-hook nil
"TODO")
(defvar doom-inhibit-switch-buffer-hooks nil
"Letvar for inhibiting `doom-switch-buffer-hook'. Do not set this directly.")
(defvar doom-inhibit-switch-window-hooks nil
"Letvar for inhibiting `doom-switch-window-hook'. Do not set this directly.")
(defvar doom-inhibit-switch-frame-hooks nil
"Letvar for inhibiting `doom-switch-frame-hook'. Do not set this directly.")
(defvar doom--last-window nil)
(defvar doom--last-frame nil)
(defun doom|run-switch-window-hooks ()
(unless (or doom-inhibit-switch-window-hooks
(eq doom--last-window (selected-window))
(minibufferp))
(let ((doom-inhibit-switch-window-hooks t))
(run-hooks 'doom-switch-window-hook)
(doom-log "Window switched to %s" (selected-window))
(setq doom--last-window (selected-window)))))
(defun doom|run-switch-frame-hooks (&rest _)
(let ((selected-frame (selected-frame)))
(unless (or doom-inhibit-switch-frame-hooks
(eq doom--last-frame (selected-frame))
(frame-parameter nil 'parent-frame))
(let ((doom-inhibit-switch-frame-hooks t))
(run-hooks 'doom-switch-frame-hook)
(doom-log "Frame switched to %s" (selected-frame))
(setq doom--last-frame (selected-frame))))))
(defun doom*run-switch-buffer-hooks (orig-fn buffer-or-name &rest args)
(if (or doom-inhibit-switch-buffer-hooks
(if (eq orig-fn 'switch-to-buffer)
(car args) ; norecord
(eq (get-buffer buffer-or-name) (current-buffer))))
(apply orig-fn buffer-or-name args)
(let ((doom-inhibit-switch-buffer-hooks t))
(doom-log "Buffer switched in %s" (selected-window))
(prog1 (apply orig-fn buffer-or-name args)
(run-hooks 'doom-switch-buffer-hook)))))
(defun doom*run-load-theme-hooks (theme &optional _no-confirm no-enable)
"Set up `doom-load-theme-hook' to run after `load-theme' is called."
(unless no-enable
(setq doom-theme theme)
(run-hooks 'doom-load-theme-hook)))
(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|highlight-non-default-indentation ()
"Highlight whitespace that doesn't match your `indent-tabs-mode' setting.
e.g. If you indent with spaces by default, tabs will be highlighted. If you
indent with tabs, spaces at BOL are highlighted.
Does nothing if `whitespace-mode' is already active or the current buffer is
read-only or not file-visiting."
(unless (or (bound-and-true-p global-whitespace-mode)
(bound-and-true-p whitespace-mode)
(eq major-mode 'fundamental-mode)
buffer-read-only
(null buffer-file-name))
(require 'whitespace)
(set (make-local-variable 'whitespace-style)
(if (bound-and-true-p whitespace-newline-mode)
(cl-union (if indent-tabs-mode '(indentation) '(tabs tab-mark))
whitespace-style)
`(face ,@(if indent-tabs-mode '(indentation) '(tabs tab-mark))
trailing-lines tail)))
(whitespace-mode +1)))
;;
;;; General configuration
(setq-default (setq-default
ansi-color-for-comint-mode t ansi-color-for-comint-mode t
bidi-display-reordering nil ; disable bidirectional text for tiny performance boost bidi-display-reordering nil ; disable bidirectional text for tiny performance boost
@ -71,6 +165,7 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
display-line-numbers-width 3 display-line-numbers-width 3
enable-recursive-minibuffers nil enable-recursive-minibuffers nil
frame-inhibit-implied-resize t frame-inhibit-implied-resize t
frame-title-format '("%b Doom Emacs") ; simple name in frame title
;; remove continuation arrow on right fringe ;; remove continuation arrow on right fringe
fringe-indicator-alist fringe-indicator-alist
(delq (assq 'continuation fringe-indicator-alist) (delq (assq 'continuation fringe-indicator-alist)
@ -86,7 +181,7 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
resize-mini-windows 'grow-only ; Minibuffer resizing resize-mini-windows 'grow-only ; Minibuffer resizing
show-help-function nil ; hide :help-echo text show-help-function nil ; hide :help-echo text
split-width-threshold 160 ; favor horizontal splits split-width-threshold 160 ; favor horizontal splits
uniquify-buffer-name-style 'forward uniquify-buffer-name-style nil ; custom modeline will show file paths anyway
use-dialog-box nil ; always avoid GUI use-dialog-box nil ; always avoid GUI
visible-cursor nil visible-cursor nil
x-stretch-cursor nil x-stretch-cursor nil
@ -99,68 +194,41 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
;; don't resize emacs in steps, it looks weird ;; don't resize emacs in steps, it looks weird
window-resize-pixelwise t window-resize-pixelwise t
frame-resize-pixelwise t) frame-resize-pixelwise t)
;; y/n instead of yes/no ;; y/n instead of yes/no
(fset #'yes-or-no-p #'y-or-n-p) (fset #'yes-or-no-p #'y-or-n-p)
;; Truly silence startup message ;; Truly silence startup message
(fset #'display-startup-echo-area-message #'ignore) (fset #'display-startup-echo-area-message #'ignore)
;; relegate tooltips to echo area only
(if (bound-and-true-p tooltip-mode) (tooltip-mode -1))
;; enabled by default; no thanks, too distracting
(blink-cursor-mode -1)
;; Handle ansi codes in compilation buffer
(add-hook 'compilation-filter-hook #'doom|apply-ansi-color-to-compilation-buffer)
;; 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)
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
(add-to-list 'default-frame-alist '(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)
;; ;;
;; Third party packages ;;; Built-in packages
;; `avy' ;; Disable these because whitespace should be customized programmatically
(setq avy-all-windows nil ;; (through `whitespace-style'), and not through these commands.
avy-background t) (put 'whitespace-toggle-options 'disabled t)
(put 'global-whitespace-toggle-options 'disabled 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)
(if (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 conf-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' --- provides a simple mechanism for restarting Emacs and
;; daemons interactively.
(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 EMACS26+ 6 0) fill-column))
;;
;; Built-in packages
(def-package! ediff (def-package! ediff
:defer t :defer t
@ -169,13 +237,15 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
ediff-split-window-function #'split-window-horizontally ediff-split-window-function #'split-window-horizontally
ediff-window-setup-function #'ediff-setup-windows-plain) ediff-window-setup-function #'ediff-setup-windows-plain)
:config :config
(defvar doom--ediff-saved-wconf nil)
;; Restore window config after quitting ediff ;; Restore window config after quitting ediff
(defun doom|ediff-save-wconf () (defun doom|ediff-save-wconf ()
(setq +ediff--saved-wconf (current-window-configuration))) (setq doom--ediff-saved-wconf (current-window-configuration)))
(add-hook 'ediff-before-setup-hook #'doom|ediff-save-wconf) (add-hook 'ediff-before-setup-hook #'doom|ediff-save-wconf)
(defun doom|ediff-restore-wconf () (defun doom|ediff-restore-wconf ()
(set-window-configuration +ediff--saved-wconf)) (when (window-configuration-p doom--ediff-saved-wconf)
(set-window-configuration doom--ediff-saved-wconf)))
(add-hook 'ediff-quit-hook #'doom|ediff-restore-wconf 'append) (add-hook 'ediff-quit-hook #'doom|ediff-restore-wconf 'append)
(add-hook 'ediff-suspend-hook #'doom|ediff-restore-wconf 'append)) (add-hook 'ediff-suspend-hook #'doom|ediff-restore-wconf 'append))
@ -189,21 +259,6 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
(setq hl-line-sticky-flag nil (setq hl-line-sticky-flag nil
global-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 ;; Disable `hl-line' in evil-visual mode (temporarily). `hl-line' can make the
;; selection region harder to see while in evil visual mode. ;; selection region harder to see while in evil visual mode.
(after! evil (after! evil
@ -220,14 +275,14 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
(def-package! winner (def-package! winner
;; undo/redo changes to Emacs' window layout ;; undo/redo changes to Emacs' window layout
:after-call doom-exit-window-hook :after-call (after-find-file doom-switch-window-hook)
:preface (defvar winner-dont-bind-my-keys t) ; I'll bind keys myself :preface (defvar winner-dont-bind-my-keys t)
:config (winner-mode +1)) :config (winner-mode +1)) ; I'll bind keys myself
(def-package! paren (def-package! paren
;; highlight matching delimiters ;; highlight matching delimiters
:after-call (after-find-file doom-exit-buffer-hook) :after-call (after-find-file doom-switch-buffer-hook)
:init :init
(defun doom|disable-show-paren-mode () (defun doom|disable-show-paren-mode ()
"Turn off `show-paren-mode' buffer-locally." "Turn off `show-paren-mode' buffer-locally."
@ -259,7 +314,56 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
;; ;;
;; Line numbers ;;; Third party packages
;;;###package avy
(setq avy-all-windows nil
avy-background t)
(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)
(if (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)))
;;;###package hide-mode-line-mode
(add-hook 'completion-list-mode-hook #'hide-mode-line-mode)
(add-hook 'Man-mode-hook #'hide-mode-line-mode)
;; Better fontification of number literals in code
(def-package! highlight-numbers
:hook ((prog-mode conf-mode) . highlight-numbers-mode)
:config (setq highlight-numbers-generic-regexp "\\_<[[:digit:]]+\\(?:\\.[0-9]*\\)?\\_>"))
;;;###package highlight-escape-sequences
(def-package! highlight-escape-sequences
:hook ((prog-mode conf-mode) . highlight-escape-sequences-mode))
;;;###package rainbow-delimiters
;; Helps us distinguish stacked delimiter pairs, especially in parentheses-drunk
;; languages like Lisp.
(setq rainbow-delimiters-max-face-count 3)
;;;###package 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 EMACS26+ 6 0) fill-column))
;;
;;; Line numbers
;; line numbers in most modes ;; line numbers in most modes
(add-hook! (prog-mode text-mode conf-mode) #'display-line-numbers-mode) (add-hook! (prog-mode text-mode conf-mode) #'display-line-numbers-mode)
@ -267,8 +371,7 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
(defun doom|enable-line-numbers () (display-line-numbers-mode +1)) (defun doom|enable-line-numbers () (display-line-numbers-mode +1))
(defun doom|disable-line-numbers () (display-line-numbers-mode -1)) (defun doom|disable-line-numbers () (display-line-numbers-mode -1))
;; Emacs 26+ has native line number support, and will ignore nlinum. This is for ;; `nlinum' is used for Emacs 25 users, as Emacs 26+ has native line numbers.
;; Emacs 25 users:
(def-package! nlinum (def-package! nlinum
;; Line number column. A faster (or equivalent, in the worst case) line number ;; Line number column. A faster (or equivalent, in the worst case) line number
;; plugin than `linum-mode'. ;; plugin than `linum-mode'.
@ -332,18 +435,18 @@ character that looks like a space that `whitespace-mode' won't affect.")
(advice-add #'web-mode-fold-or-unfold :after #'nlinum-hl-do-generic-flush) (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 ;; Changing fonts can leave nlinum line numbers in their original size; this
;; forces them to resize. ;; forces them to resize.
(advice-add #'set-frame-font :after #'nlinum-hl-flush-all-windows)) (add-hook 'after-setting-font-hook #'nlinum-hl-flush-all-windows))
(def-package! nlinum-relative (def-package! nlinum-relative
:unless EMACS26+ :unless EMACS26+
:defer t :defer t
:config :config
(setq nlinum-format " %d ") (setq nlinum-format " %d ")
(add-hook 'evil-mode #'nlinum-relative-setup-evil)) (add-hook 'evil-mode-hook #'nlinum-relative-setup-evil))
;; ;;
;; Theme & font ;;; Theme & font
(defvar doom-last-window-system (defvar doom-last-window-system
(if (daemonp) 'daemon initial-window-system) (if (daemonp) 'daemon initial-window-system)
@ -351,12 +454,13 @@ character that looks like a space that `whitespace-mode' won't affect.")
frame's window-system, the theme will be reloaded.") frame's window-system, the theme will be reloaded.")
(defun doom|init-fonts () (defun doom|init-fonts ()
"Initialize fonts." "Loads fonts.
Fonts are specified by `doom-font', `doom-variable-pitch-font',
`doom-serif-font' and `doom-unicode-font'."
(condition-case e (condition-case e
(progn (progn
(cond (doom-font (cond (doom-font
;; We avoid `set-frame-font' for performance reasons.
;; Manipulating `default-frame-alist' is effective enough.
(add-to-list (add-to-list
'default-frame-alist 'default-frame-alist
(cons 'font (cons 'font
@ -380,20 +484,27 @@ frame's window-system, the theme will be reloaded.")
(signal 'doom-error e))))) (signal 'doom-error e)))))
(defun doom|init-theme () (defun doom|init-theme ()
"Set the theme and load the font, in that order." "Load the theme specified by `doom-theme'."
(when (and doom-theme (not (memq doom-theme custom-enabled-themes))) (when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
(let ((doom--prefer-theme-elc t)) (let ((doom--prefer-theme-elc t))
(load-theme doom-theme t)))) (load-theme doom-theme t))))
;; Getting themes to remain consistent across GUI Emacs, terminal Emacs and (defun doom|reload-theme-maybe (_frame)
;; daemon Emacs is hairy. `doom|init-theme' sorts out the initial GUI frame. "Reloads the theme if the display device has changed."
;; Attaching `doom|init-theme-in-frame' to `after-make-frame-functions' sorts (unless (cl-find doom-last-window-system (frame-list) :key #'framep-on-display)
;; out daemon and emacsclient frames. (setq doom-last-window-system nil)
;; (doom|reload-theme-in-frame-maybe (selected-frame))))
;; 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) (defun doom|reload-theme-in-frame-maybe (frame)
"Reloads the theme in new daemon or tty frames." "Reloads the theme if the display device has changed.
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|reload-theme-in-frame-maybe' 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!"
(when (and doom-theme (when (and doom-theme
(framep frame) (framep frame)
(not (eq doom-last-window-system (framep-on-display frame)))) (not (eq doom-last-window-system (framep-on-display frame))))
@ -401,109 +512,47 @@ frame's window-system, the theme will be reloaded.")
(load-theme doom-theme t)) (load-theme doom-theme t))
(setq doom-last-window-system (framep-on-display frame)))) (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
(unless (daemonp)
(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 ;;; Bootstrap
;; simple name in frame title
(setq frame-title-format '("%b Doom Emacs"))
;; relegate tooltips to echo area only
(if (boundp 'tooltip-mode) (tooltip-mode -1))
;; enabled by default; no thanks, too distracting
(blink-cursor-mode -1)
;; Handle ansi codes in compilation buffer
(add-hook 'compilation-filter-hook #'doom|apply-ansi-color-to-compilation-buffer)
;; 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)
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
(add-to-list 'default-frame-alist '(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|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|highlight-non-default-indentation ()
"Highlight whitespace that doesn't match your `indent-tabs-mode' setting.
e.g. If you indent with spaces by default, tabs will be highlighted. If you
indent with tabs, spaces at BOL are highlighted.
Does nothing if `whitespace-mode' is already active or the current buffer is
read-only or not file-visiting."
(unless (or (bound-and-true-p global-whitespace-mode)
(bound-and-true-p whitespace-mode)
(eq major-mode 'fundamental-mode)
buffer-read-only
(null buffer-file-name))
(require 'whitespace)
(set (make-local-variable 'whitespace-style)
(if (bound-and-true-p whitespace-newline-mode)
(cl-union (if indent-tabs-mode '(indentation) '(tabs tab-mark))
whitespace-style)
`(face ,@(if indent-tabs-mode '(indentation) '(tabs tab-mark))
trailing-lines tail)))
(whitespace-mode +1)))
(defun doom|init-ui () (defun doom|init-ui ()
"Initialize Doom's user interface by applying all its advice and hooks." "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) (run-hook-wrapped 'doom-init-ui-hook #'doom-try-run-hook)
(add-to-list 'kill-buffer-query-functions #'doom|protect-visible-buffer nil #'eq)
(add-hook 'after-change-major-mode-hook #'doom|highlight-non-default-indentation)
(run-hook-wrapped 'doom-init-ui-hook #'doom-try-run-hook))
(add-hook 'emacs-startup-hook #'doom|init-ui) (add-to-list 'kill-buffer-query-functions #'doom|protect-fallback-buffer nil 'eq)
(add-hook 'after-change-major-mode-hook #'doom|highlight-non-default-indentation)
;; Reload theme if the display device has changed
(add-hook 'after-make-frame-functions #'doom|reload-theme-in-frame-maybe)
(add-hook 'after-delete-frame-functions #'doom|reload-theme-maybe)
;; Initialize custom switch-{buffer,window,frame} hooks:
;; + `doom-switch-buffer-hook'
;; + `doom-switch-window-hook'
;; + `doom-switch-frame-hook'
(add-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
(add-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
(advice-add! '(switch-to-buffer display-buffer) :around #'doom*run-switch-buffer-hooks))
;; Apply `doom-theme'
(unless (daemonp)
(add-hook 'doom-init-ui-hook #'doom|init-theme))
;; Apply `doom-font' et co
(add-hook 'doom-after-init-modules-hook #'doom|init-fonts)
;; Setup `doom-load-theme-hook'
(advice-add #'load-theme :after #'doom*run-load-theme-hooks)
(add-hook 'window-setup-hook #'doom|init-ui)
;; ;;
;; Fixes/hacks ;;; Fixes/hacks
;; doesn't exist in terminal Emacs; we define it to prevent errors ;; doesn't exist in terminal Emacs; we define it to prevent errors
(unless (fboundp 'define-fringe-bitmap) (unless (fboundp 'define-fringe-bitmap)
(defun define-fringe-bitmap (&rest _))) (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*prefer-compiled-theme (orig-fn &rest args) (defun doom*prefer-compiled-theme (orig-fn &rest args)
"Make `load-theme' prioritize the byte-compiled theme for a moderate boost in "Make `load-theme' prioritize the byte-compiled theme for a moderate boost in
startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil." startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
@ -517,27 +566,37 @@ startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
(apply orig-fn args))) (apply orig-fn args)))
(advice-add #'load-theme :around #'doom*prefer-compiled-theme) (advice-add #'load-theme :around #'doom*prefer-compiled-theme)
(defun doom|disable-whitespace-mode-in-childframes (frame) (after! whitespace
"`whitespace-mode' inundates child frames with whitspace markers, so disable (defun doom*disable-whitespace-mode-in-childframes (orig-fn)
"`whitespace-mode' inundates child frames with whitspace markers, so disable
it to fix all that visual noise." it to fix all that visual noise."
(when (frame-parameter frame 'parent-frame) (unless (frame-parameter nil 'parent-frame)
(with-selected-frame frame (funcall orig-fn)))
(setq-local whitespace-style nil) (add-function :around whitespace-enable-predicate #'doom*disable-whitespace-mode-in-childframes)
frame)))
(add-hook 'after-make-frame-functions #'doom|disable-whitespace-mode-in-childframes)
(defun doom*silence-motion-errors (orig-fn &rest args) (defun doom|disable-whitespace-mode-in-childframes (frame)
"Prevent disruptive motion errors taking over the minibuffer while we're in "`whitespace-mode' inundates child frames with whitspace markers, so disable
it." it to fix all that visual noise."
(if (not (minibufferp)) (when (frame-parameter frame 'parent-frame)
(apply orig-fn args) (with-selected-frame frame
(ignore-errors (apply orig-fn args)) (setq-local whitespace-style nil)
(when (<= (point) (minibuffer-prompt-end)) frame)))
(goto-char (minibuffer-prompt-end))))) (add-hook 'after-make-frame-functions #'doom|disable-whitespace-mode-in-childframes))
(advice-add #'left-char :around #'doom*silence-motion-errors)
(advice-add #'right-char :around #'doom*silence-motion-errors) ;; Don't allow cursor to enter the prompt
(advice-add #'delete-backward-char :around #'doom*silence-motion-errors) (setq minibuffer-prompt-properties '(read-only t intangible t cursor-intangible t face minibuffer-prompt))
(advice-add #'backward-kill-sentence :around #'doom*silence-motion-errors) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Don't display messages in the minibuffer when using the minibuffer
(defmacro doom-silence-motion-key (command key)
(let ((key-command (intern (format "doom/silent-%s" command))))
`(progn
(defun ,key-command ()
(interactive)
(ignore-errors (call-interactively ',command)))
(define-key minibuffer-local-map (kbd ,key) #',key-command))))
(doom-silence-motion-key backward-delete-char "<backspace>")
(doom-silence-motion-key delete-char "<delete>")
;; Switch to `doom-fallback-buffer' if on last real buffer ;; Switch to `doom-fallback-buffer' if on last real buffer
(advice-add #'kill-this-buffer :around #'doom*switch-to-fallback-buffer-maybe) (advice-add #'kill-this-buffer :around #'doom*switch-to-fallback-buffer-maybe)

View file

@ -113,94 +113,9 @@ Doom was setup, which can cause problems.")
;; ;;
;; Custom hooks ;; Custom hooks
(defvar doom-init-hook nil
"Hooks run after all init.el files are loaded, including your private and all
module init.el files, but before their config.el files are loaded.")
(defvar doom-post-init-hook nil
"A list of hooks run when Doom is fully initialized. Fires near the end of
`emacs-startup-hook', as late as possible. Guaranteed to run after everything
else (except for `window-setup-hook').")
(defvar doom-reload-hook nil (defvar doom-reload-hook nil
"A list of hooks to run when `doom/reload' is called.") "A list of hooks to run when `doom/reload' is called.")
(defvar doom-load-theme-hook nil
"Hook run after the theme is loaded with `load-theme' or reloaded with
`doom/reload-theme'.")
(defvar doom-exit-window-hook nil
"Hook run before `switch-window' or `switch-frame' are called.
Also see `doom-enter-window-hook'.")
(defvar doom-enter-window-hook nil
"Hook run after `switch-window' or `switch-frame' are called.
Also see `doom-exit-window-hook'.")
(defvar doom-exit-buffer-hook nil
"Hook run after `switch-to-buffer', `pop-to-buffer' or `display-buffer' are
called. The buffer to be switched to is current when these hooks run.
Also see `doom-enter-buffer-hook'.")
(defvar doom-enter-buffer-hook nil
"Hook run before `switch-to-buffer', `pop-to-buffer' or `display-buffer' are
called. The buffer to be switched to is current when these hooks run.
Also see `doom-exit-buffer-hook'.")
(defvar doom-inhibit-switch-buffer-hooks nil
"Letvar for inhibiting `doom-enter-buffer-hook' and `doom-exit-buffer-hook'.
Do not set this directly.")
(defvar doom-inhibit-switch-window-hooks nil
"Letvar for inhibiting `doom-enter-window-hook' and `doom-exit-window-hook'.
Do not set this directly.")
(defun doom*switch-window-hooks (orig-fn window &optional norecord)
(if (or doom-inhibit-switch-window-hooks
(null window)
(eq window (selected-window))
(window-minibuffer-p)
(window-minibuffer-p window))
(funcall orig-fn window norecord)
(let ((doom-inhibit-switch-window-hooks t))
(run-hooks 'doom-exit-window-hook)
(prog1 (funcall orig-fn window norecord)
(with-selected-window window
(run-hooks 'doom-enter-window-hook))))))
(defun doom*switch-buffer-hooks (orig-fn buffer-or-name &rest args)
(if (or doom-inhibit-switch-buffer-hooks
(eq (get-buffer buffer-or-name) (current-buffer)))
(apply orig-fn buffer-or-name args)
(let ((doom-inhibit-switch-buffer-hooks t))
(run-hooks 'doom-exit-buffer-hook)
(prog1 (apply orig-fn buffer-or-name args)
(when (buffer-live-p (get-buffer buffer-or-name))
(with-current-buffer buffer-or-name
(run-hooks 'doom-enter-buffer-hook)))))))
(defun doom|init-switch-hooks (&optional disable)
"Set up enter/exit hooks for windows and buffers.
See `doom-enter-buffer-hook', `doom-enter-window-hook', `doom-exit-buffer-hook'
and `doom-exit-window-hook'."
(dolist (spec '((select-window . doom*switch-window-hooks)
(switch-to-buffer . doom*switch-buffer-hooks)
(display-buffer . doom*switch-buffer-hooks)
(pop-to-buffer . doom*switch-buffer-hooks)))
(if disable
(advice-remove (car spec) (cdr spec))
(advice-add (car spec) :around (cdr spec)))))
(defun doom*load-theme-hooks (theme &rest _)
"Set up `doom-load-theme-hook' to run after `load-theme' is called."
(setq doom-theme theme)
(run-hooks 'doom-load-theme-hook))
(advice-add #'load-theme :after #'doom*load-theme-hooks)
;; ;;
;; Emacs core configuration ;; Emacs core configuration
@ -208,12 +123,10 @@ and `doom-exit-window-hook'."
;; UTF-8 as the default coding system ;; UTF-8 as the default coding system
(when (fboundp 'set-charset-priority) (when (fboundp 'set-charset-priority)
(set-charset-priority 'unicode)) ; pretty (set-charset-priority 'unicode)) ; pretty
(prefer-coding-system 'utf-8) ; pretty (prefer-coding-system 'utf-8) ; pretty
(set-terminal-coding-system 'utf-8) ; pretty (setq selection-coding-system 'utf-8) ; pretty
(set-keyboard-coding-system 'utf-8) ; pretty (setq locale-coding-system 'utf-8) ; please
(set-selection-coding-system 'utf-8) ; perdy (if IS-WINDOWS (set-w32-system-coding-system 'utf-8)) ; with sugar on top
(setq locale-coding-system 'utf-8) ; please
(setq-default buffer-file-coding-system 'utf-8) ; with sugar on top
(setq-default (setq-default
ad-redefinition-action 'accept ; silence advised function warnings ad-redefinition-action 'accept ; silence advised function warnings
@ -230,8 +143,6 @@ and `doom-exit-window-hook'."
inhibit-default-init t inhibit-default-init t
initial-major-mode 'fundamental-mode initial-major-mode 'fundamental-mode
initial-scratch-message nil initial-scratch-message nil
;; keep the point out of the minibuffer
minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt)
;; History & backup settings (save nothing, that's what git is for) ;; History & backup settings (save nothing, that's what git is for)
auto-save-default nil auto-save-default nil
create-lockfiles nil create-lockfiles nil
@ -255,6 +166,9 @@ and `doom-exit-window-hook'."
async-byte-compile-log-file (concat doom-etc-dir "async-bytecomp.log") async-byte-compile-log-file (concat doom-etc-dir "async-bytecomp.log")
auto-save-list-file-name (concat doom-cache-dir "autosave") auto-save-list-file-name (concat doom-cache-dir "autosave")
backup-directory-alist (list (cons "." (concat doom-cache-dir "backup/"))) backup-directory-alist (list (cons "." (concat doom-cache-dir "backup/")))
desktop-dirname (concat doom-etc-dir "desktop")
desktop-base-file-name "autosave"
desktop-base-lock-name "autosave-lock"
pcache-directory (concat doom-cache-dir "pcache/") pcache-directory (concat doom-cache-dir "pcache/")
request-storage-directory (concat doom-cache-dir "request") request-storage-directory (concat doom-cache-dir "request")
server-auth-dir (concat doom-cache-dir "server/") server-auth-dir (concat doom-cache-dir "server/")
@ -315,6 +229,13 @@ original value of `symbol-file'."
#'doom-try-run-hook)) #'doom-try-run-hook))
(add-hook 'hack-local-variables-hook #'doom|run-local-var-hooks) (add-hook 'hack-local-variables-hook #'doom|run-local-var-hooks)
(defun doom|run-local-var-hooks-if-necessary ()
"If `enable-local-variables' is disabled, then `hack-local-variables-hook' is
never triggered."
(unless enable-local-variables
(doom|run-local-var-hooks)))
(add-hook 'after-change-major-mode-hook #'doom|run-local-var-hooks-if-necessary)
;; ;;
;; Incremental lazy-loading ;; Incremental lazy-loading
@ -357,17 +278,17 @@ intervals."
(let* ((reqs (cl-delete-if #'featurep packages)) (let* ((reqs (cl-delete-if #'featurep packages))
(req (ignore-errors (pop reqs)))) (req (ignore-errors (pop reqs))))
(when req (when req
(when doom-debug-mode (doom-log "Incrementally loading %s" req)
(message "Incrementally loading %s" req))
(condition-case e (condition-case e
(require req nil t) (require req nil t)
(error ((error debug)
(message "Failed to load '%s' package incrementally, because: %s" (message "Failed to load '%s' package incrementally, because: %s"
req e))) req e)))
(when reqs (if reqs
(run-with-idle-timer doom-incremental-idle-timer (run-with-idle-timer doom-incremental-idle-timer
nil #'doom-load-packages-incrementally nil #'doom-load-packages-incrementally
reqs t)))))))) reqs t)
(doom-log "Finished incremental loading"))))))))
(defun doom|load-packages-incrementally () (defun doom|load-packages-incrementally ()
"Begin incrementally loading packages in `doom-incremental-packages'. "Begin incrementally loading packages in `doom-incremental-packages'.
@ -380,7 +301,7 @@ If this is a daemon session, load them all immediately instead."
nil #'doom-load-packages-incrementally nil #'doom-load-packages-incrementally
(cdr doom-incremental-packages) t)))) (cdr doom-incremental-packages) t))))
(add-hook 'emacs-startup-hook #'doom|load-packages-incrementally) (add-hook 'window-setup-hook #'doom|load-packages-incrementally)
;; ;;
@ -391,8 +312,7 @@ If this is a daemon session, load them all immediately instead."
issues easier. issues easier.
Meant to be used with `run-hook-wrapped'." Meant to be used with `run-hook-wrapped'."
(when doom-debug-mode (doom-log "Running doom hook: %s" hook)
(message "Running doom hook: %s" hook))
(condition-case e (condition-case e
(funcall hook) (funcall hook)
((debug error) ((debug error)
@ -457,11 +377,18 @@ If RETURN-P, return the message as a string instead of displaying it."
;; ;;
;; Bootstrap functions ;; Bootstrap functions
(defun doom-initialize (&optional force-p force-load-core-p) (defun doom-initialize-autoloads (file)
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil). "Tries to load FILE (an autoloads file). Return t on success, throws an error
in interactive sessions, nil otherwise (but logs a warning)."
(condition-case e
(load (file-name-sans-extension file) 'noerror 'nomessage)
((debug error)
(if noninteractive
(message "Autoload file warning: %s -> %s" (car e) (error-message-string e))
(signal 'doom-autoload-error (list (file-name-nondirectory file) e))))))
Loads Doom core files if in an interactive session or FORCE-LOAD-CORE-P is (defun doom-initialize (&optional force-p)
non-nil. "Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
The bootstrap process involves making sure 1) the essential directories exist, The bootstrap process involves making sure 1) the essential directories exist,
2) the core packages are installed, 3) `doom-autoload-file' and 2) the core packages are installed, 3) `doom-autoload-file' and
@ -477,12 +404,14 @@ The overall load order of Doom is as follows:
~/.emacs.d/core/core.el ~/.emacs.d/core/core.el
~/.doom.d/init.el ~/.doom.d/init.el
Module init.el files Module init.el files
`doom-init-hook' `doom-before-init-modules-hook'
Module config.el files Module config.el files
~/.doom.d/config.el ~/.doom.d/config.el
`doom-post-init-hook' `doom-init-modules-hook'
`after-init-hook' `after-init-hook'
`emacs-startup-hook' `emacs-startup-hook'
`doom-init-ui-hook'
`window-setup-hook'
Module load order is determined by your `doom!' block. See `doom-modules-dirs' Module load order is determined by your `doom!' block. See `doom-modules-dirs'
for a list of all recognized module trees. Order defines precedence (from most for a list of all recognized module trees. Order defines precedence (from most
@ -508,47 +437,45 @@ to least)."
;; autoloads file and caches `load-path', `auto-mode-alist', ;; autoloads file and caches `load-path', `auto-mode-alist',
;; `Info-directory-list', `doom-disabled-packages' and ;; `Info-directory-list', `doom-disabled-packages' and
;; `package-activated-list'. A big reduction in startup time. ;; `package-activated-list'. A big reduction in startup time.
(unless (or force-p (let (command-switch-alist)
(doom-initialize-autoloads doom-package-autoload-file) (unless (or force-p
noninteractive) (doom-initialize-autoloads doom-package-autoload-file)
(user-error "Your package autoloads are missing! Run `bin/doom refresh' to regenerate them"))) noninteractive)
(user-error "Your package autoloads are missing! Run `bin/doom refresh' to regenerate them"))))
(require 'core-lib)
(require 'core-modules)
(require 'core-os) (require 'core-os)
(when (or force-load-core-p (not noninteractive)) (if noninteractive
(add-hook! 'emacs-startup-hook (require 'core-cli)
#'(doom|init-switch-hooks doom|display-benchmark)) (add-hook 'window-setup-hook #'doom|display-benchmark)
(require 'core-keybinds)
(require 'core-ui) (require 'core-ui)
(require 'core-editor)
(require 'core-projects) (require 'core-projects)
(require 'core-keybinds))) (require 'core-editor)))
(defun doom-initialize-autoloads (file)
"Tries to load FILE (an autoloads file). Return t on success, throws an error
in interactive sessions, nil otherwise (but logs a warning)."
(condition-case e
(load (file-name-sans-extension file) 'noerror 'nomessage)
((debug error)
(if noninteractive
(message "Autoload file warning: %s -> %s" (car e) (error-message-string e))
(signal 'doom-autoload-error (list (file-name-nondirectory file) e))))))
;; ;;
;; Bootstrap Doom ;; Bootstrap Doom
(add-to-list 'load-path doom-core-dir) (eval-and-compile
(require 'subr-x)
(require 'cl-lib)
(unless EMACS26+
(with-no-warnings
;; if-let and when-let were moved to (if|when)-let* in Emacs 26+ so we
;; alias them for 25 users.
(defalias 'if-let* #'if-let)
(defalias 'when-let* #'when-let))))
(require 'core-lib) (add-to-list 'load-path doom-core-dir)
(require 'core-modules)
(when noninteractive
(require 'core-cli))
(after! package
(require 'core-packages))
(doom-initialize noninteractive) (doom-initialize noninteractive)
(unless noninteractive (unless noninteractive
(doom-initialize-modules)) (doom-initialize-modules))
(after! package
(require 'core-packages)
(doom-initialize-packages))
(provide 'core) (provide 'core)
;;; core.el ends here ;;; core.el ends here

29
core/doctor.el Normal file
View file

@ -0,0 +1,29 @@
;;; core/doctor.el -*- lexical-binding: t; -*-
(defun file-size (file &optional dir)
(setq file (expand-file-name file dir))
(when (file-exists-p file)
(/ (nth 7 (file-attributes file))
1024.0)))
;; Check for oversized problem files in cache that may cause unusual/tremendous
;; delays or freezing. This shouldn't happen often.
(dolist (file (list "savehist"
"projectile.cache"))
(let* ((path (expand-file-name file doom-core-dir))
(size (file-size path)))
(when (and (numberp size) (> size 2000))
(warn! "%s is too large (%.02fmb). This may cause freezes or odd startup delays"
(file-relative-name path doom-core-dir)
(/ size 1024))
(explain! "Consider deleting it from your system (manually)"))))
(when! (not (executable-find "fd"))
(warn! "Couldn't find the `fd' binary; project file searches will be slightly slower"))
(let ((default-directory "~"))
(require 'projectile)
(when! (cl-find-if #'projectile-file-exists-p projectile-project-root-files-bottom-up)
(warn! "Your $HOME is recognized as a project root")
(explain! "Doom will disable bottom-up root search, which may reduce the accuracy of project\n"
"detection.")))

View file

@ -2,6 +2,7 @@
;;; core/packages.el ;;; core/packages.el
;; core-os.el ;; core-os.el
(package! xclip)
(when IS-MAC (when IS-MAC
(package! exec-path-from-shell) (package! exec-path-from-shell)
(package! osx-clipboard) (package! osx-clipboard)
@ -10,7 +11,6 @@
;; core-ui.el ;; core-ui.el
(package! all-the-icons) (package! all-the-icons)
(package! hide-mode-line) (package! hide-mode-line)
(package! highlight-indentation)
(package! highlight-numbers) (package! highlight-numbers)
(package! highlight-escape-sequences (package! highlight-escape-sequences
:recipe (:fetcher github :repo "hlissner/highlight-escape-sequences")) :recipe (:fetcher github :repo "hlissner/highlight-escape-sequences"))
@ -28,7 +28,6 @@
(package! avy) (package! avy)
(package! command-log-mode) (package! command-log-mode)
(package! dtrt-indent) (package! dtrt-indent)
(package! expand-region)
(package! helpful) (package! helpful)
(package! pcre2el) (package! pcre2el)
(package! smartparens) (package! smartparens)

View file

@ -1,6 +1,12 @@
;; Welcome to the vanilla sandbox! ;; Welcome to the vanilla sandbox!
;; ;;
;; This is a test bed for running Emacs Lisp in either a vanilla Emacs session ;; This is a test bed for running Emacs Lisp in an instance of Emacs with varying
;; free of Doom's clutches (C-c C-c), or in a vanilla Doom session free of your ;; amounts of Doom loaded:
;; private config (C-c C-d). ;;
;; a) vanilla Emacs (nothing loaded) \\[doom--run-vanilla-emacs]
;; b) vanilla Doom (only Doom core) \\[doom--run-vanilla-doom]
;; c) Doom + modules - your private config \\[doom--run-vanilla-doom+]
;; d) Doom (normal) \\[doom--run-full-doom]
;;
;; This is done without sacrificing access to installed packages. Use the sandbox
;; to reproduce bugs and determine if Doom is to blame.

View file

@ -1,31 +1,10 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-help.el ;;; core/test/test-autoload-help.el
(load! "autoload/help" doom-core-dir) ;; (load! "autoload/help" doom-core-dir)
;; ;;
(describe "core/autoload/help" ;; (describe "core/autoload/help"
:var (a) ;; :var (a)
(before-each (setq a (switch-to-buffer (get-buffer-create "a")))) ;; (before-each (setq a (switch-to-buffer (get-buffer-create "a"))))
(after-each (kill-buffer a)) ;; (after-each (kill-buffer a)))
(describe "what-face"
(before-each
(insert (propertize "Hello " 'face 'font-lock-keyword-face))
(insert "world"))
(it "returns list of faces at point"
(expect (doom/what-face nil (point-min)) :to-equal '((font-lock-keyword-face) ())))
(it "returns nil if no faces at point"
(expect (doom/what-face nil (point-max)) :to-be nil)))
(describe "what-face overlays"
(before-each
(insert "Hello world")
(let ((ov (make-overlay 1 6)))
(overlay-put ov 'face 'font-lock-keyword-face)))
(it "returns list of overlays at point"
(expect (doom/what-face nil (point-min)) :to-equal '(() (font-lock-keyword-face))))
(it "returns nil if no overlays at point"
(expect (doom/what-face nil (point-max)) :to-be nil))))

View file

@ -55,8 +55,8 @@
(doom-missing-dummy) (doom-missing-dummy)
(doom-noquelpa-dummy) (doom-noquelpa-dummy)
(doom-disabled-dummy :disable t) (doom-disabled-dummy :disable t)
(doom-private-dummy :private t) (doom-private-dummy :modules ((:private)))
(doom-disabled-private-dummy :private t :disable t) (doom-disabled-private-dummy :modules ((:private)) :disable t)
(doom-quelpa-dummy :recipe (doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist"))) (doom-quelpa-dummy :recipe (doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist")))
quelpa-cache quelpa-cache
'((doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist") '((doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist")
@ -95,31 +95,31 @@
(spy-on #'doom-package-installed-p :and-call-fake #'package-installed-p)) (spy-on #'doom-package-installed-p :and-call-fake #'package-installed-p))
(it "returns all packages" (it "returns all packages"
(expect (mapcar #'car (doom-get-packages)) (expect (mapcar #'car (doom-find-packages))
:to-have-same-items-as :to-have-same-items-as
(mapcar #'car doom-packages))) (mapcar #'car doom-packages)))
(it "returns only disabled packages" (it "returns only disabled packages"
(expect (mapcar #'car (doom-get-packages :disabled t)) (expect (mapcar #'car (doom-find-packages :disabled t))
:to-have-same-items-as :to-have-same-items-as
'(doom-disabled-dummy doom-disabled-private-dummy))) '(doom-disabled-dummy doom-disabled-private-dummy)))
(it "returns only non-disabled packages" (it "returns only non-disabled packages"
(expect (mapcar #'car (doom-get-packages :disabled nil)) (expect (mapcar #'car (doom-find-packages :disabled nil))
:to-have-same-items-as :to-have-same-items-as
'(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-missing-dummy doom-noquelpa-dummy doom-private-dummy))) '(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-missing-dummy doom-noquelpa-dummy doom-private-dummy)))
(it "returns only installed packages" (it "returns only installed packages"
(expect (mapcar #'car (doom-get-packages :disabled nil :installed t)) (expect (mapcar #'car (doom-find-packages :disabled nil :installed t))
:to-have-same-items-as :to-have-same-items-as
'(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-noquelpa-dummy))) '(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-noquelpa-dummy)))
(it "returns only non-installed packages" (it "returns only non-installed packages"
(expect (mapcar #'car (doom-get-packages :disabled nil :installed nil)) (expect (mapcar #'car (doom-find-packages :disabled nil :installed nil))
:to-have-same-items-as :to-have-same-items-as
'(doom-missing-dummy doom-private-dummy))) '(doom-missing-dummy doom-private-dummy)))
(it "returns only private packages" (it "returns only private packages"
(expect (mapcar #'car (doom-get-packages :private t)) (expect (mapcar #'car (doom-find-packages :private t))
:to-have-same-items-as :to-have-same-items-as
'(doom-private-dummy doom-disabled-private-dummy))) '(doom-private-dummy doom-disabled-private-dummy)))
(it "returns only disabled and private packages" (it "returns only disabled and private packages"
(expect (mapcar #'car (doom-get-packages :disabled t :private t)) (expect (mapcar #'car (doom-find-packages :disabled t :private t))
:to-have-same-items-as :to-have-same-items-as
'(doom-disabled-private-dummy)))) '(doom-disabled-private-dummy))))

View file

@ -1,6 +1,8 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-keybinds.el ;;; core/test/test-core-keybinds.el
(require 'core-keybinds)
(buttercup-define-matcher :to-expand-into (src result) (buttercup-define-matcher :to-expand-into (src result)
(let ((src (funcall src)) (let ((src (funcall src))
(result (funcall result))) (result (funcall result)))

View file

@ -1,6 +1,8 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-lib.el ;;; core/test/test-core-lib.el
(require 'core-lib)
(describe "core/lib" (describe "core/lib"
;; --- Helpers ---------------------------- ;; --- Helpers ----------------------------
(describe "doom-unquote" (describe "doom-unquote"

View file

@ -1,4 +1,6 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-modules.el ;;; core/test/test-core-modules.el
;; (require 'core-modules)
(describe "core-modules") (describe "core-modules")

View file

@ -1,33 +1,9 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; ../core/test/test-core-ui.el ;;; ../core/test/test-core-ui.el
(require 'core-ui)
(describe "core/ui" (describe "core/ui"
(describe "doom|protect-visible-buffer"
:var (kill-buffer-query-functions wconf a b)
(before-each
(setq a (switch-to-buffer (get-buffer-create "a"))
b (get-buffer-create "b")
kill-buffer-query-functions '(doom|protect-visible-buffer)
wconf (current-window-configuration))
(delete-other-windows))
(after-each
(let (kill-buffer-query-functions kill-buffer-hook)
(kill-buffer a)
(kill-buffer b))
(set-window-configuration wconf))
(it "shouldn't kill buffers that are visible in more than one window"
(with-temp-buffer-window
(switch-to-buffer a) (split-window)
(switch-to-buffer b) (split-window)
(switch-to-buffer a)
(expect (kill-buffer) :to-be nil)
(select-window (get-buffer-window b))
(expect (kill-buffer)))))
(describe "doom|protect-fallback-buffer" (describe "doom|protect-fallback-buffer"
:var (kill-buffer-query-functions a b) :var (kill-buffer-query-functions a b)
(before-all (before-all

View file

@ -61,43 +61,39 @@
(before-each (before-each
(setq a (switch-to-buffer (get-buffer-create "a")) (setq a (switch-to-buffer (get-buffer-create "a"))
b (get-buffer-create "b")) b (get-buffer-create "b"))
(spy-on 'before-hook) (spy-on 'hook)
(spy-on 'after-hook) (add-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
(doom|init-switch-hooks)) (add-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
(advice-add! '(switch-to-buffer display-buffer) :around #'doom*run-switch-buffer-hooks))
(after-each (after-each
(doom|init-switch-hooks 'disable) (remove-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
(remove-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
(advice-remove! '(switch-to-buffer display-buffer) #'doom*run-switch-buffer-hooks)
(kill-buffer a) (kill-buffer a)
(kill-buffer b)) (kill-buffer b))
(describe "switch-buffer" (describe "switch-buffer"
:var (doom-exit-buffer-hook :var (doom-switch-buffer-hook)
doom-enter-buffer-hook)
(before-each (before-each
(setq doom-exit-buffer-hook '(before-hook) (setq doom-switch-buffer-hook '(hook)))
doom-enter-buffer-hook '(after-hook)))
(after-each (after-each
(setq doom-exit-buffer-hook nil (setq doom-switch-buffer-hook nil))
doom-enter-buffer-hook nil))
(it "should trigger when switching buffers" (it "should trigger when switching buffers"
(switch-to-buffer b) (switch-to-buffer b)
(switch-to-buffer a) (switch-to-buffer a)
(switch-to-buffer b) (switch-to-buffer b)
(expect 'before-hook :to-have-been-called-times 3) (expect 'hook :to-have-been-called-times 3))
(expect 'after-hook :to-have-been-called-times 3))
(it "should trigger only once on the same buffer" (it "should trigger only once on the same buffer"
(switch-to-buffer b) (switch-to-buffer b)
(switch-to-buffer b) (switch-to-buffer b)
(switch-to-buffer a) (switch-to-buffer a)
(expect 'before-hook :to-have-been-called-times 2) (expect 'hook :to-have-been-called-times 2)))
(expect 'after-hook :to-have-been-called-times 2)))
(describe "switch-window" (describe "switch-window"
:var (doom-exit-window-hook :var (doom-switch-window-hook x y)
doom-enter-window-hook
x y)
(before-each (before-each
(delete-other-windows) (delete-other-windows)
(setq x (get-buffer-window a) (setq x (get-buffer-window a)
@ -105,21 +101,17 @@
(with-selected-window y (with-selected-window y
(switch-to-buffer b)) (switch-to-buffer b))
(select-window x) (select-window x)
(spy-calls-reset 'before-hook) (spy-calls-reset 'hook)
(spy-calls-reset 'after-hook) (setq doom-switch-window-hook '(hook)))
(setq doom-exit-window-hook '(before-hook)
doom-enter-window-hook '(after-hook)))
(it "should trigger when switching windows" (it "should trigger when switching windows"
(select-window y) (select-window y)
(select-window x) (select-window x)
(select-window y) (select-window y)
(expect 'before-hook :to-have-been-called-times 3) (expect 'hook :to-have-been-called-times 3))
(expect 'after-hook :to-have-been-called-times 3))
(it "should trigger only once on the same window" (it "should trigger only once on the same window"
(select-window y) (select-window y)
(select-window y) (select-window y)
(select-window x) (select-window x)
(expect 'before-hook :to-have-been-called-times 2) (expect 'hook :to-have-been-called-times 2))))))
(expect 'after-hook :to-have-been-called-times 2))))))

View file

@ -15,3 +15,6 @@
(add-to-list 'default-frame-alist '(tool-bar-lines . 0)) (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 '(menu-bar-lines . 0))
(add-to-list 'default-frame-alist '(vertical-scroll-bars)) (add-to-list 'default-frame-alist '(vertical-scroll-bars))
;; One less file to load at startup
(setq site-run-file nil)

View file

@ -13,20 +13,20 @@
:completion :completion
company ; the ultimate code completion backend company ; the ultimate code completion backend
helm ; the *other* search engine for love and life ;;helm ; the *other* search engine for love and life
;;ido ; the other *other* search engine... ;;ido ; the other *other* search engine...
;;ivy ; a search engine for love and life ivy ; a search engine for love and life
:ui :ui
;;deft ; notational velocity for Emacs ;;deft ; notational velocity for Emacs
doom ; what makes DOOM look the way it does doom ; what makes DOOM look the way it does
doom-dashboard ; a nifty splash screen for Emacs doom-dashboard ; a nifty splash screen for Emacs
doom-modeline ; a snazzy Atom-inspired mode-line
doom-quit ; DOOM quit-message prompts when you quit Emacs doom-quit ; DOOM quit-message prompts when you quit Emacs
evil-goggles ; display visual hints when editing in evil evil-goggles ; display visual hints when editing in evil
;;fci ; a `fill-column' indicator ;;fci ; a `fill-column' indicator
hl-todo ; highlight TODO/FIXME/NOTE tags hl-todo ; highlight TODO/FIXME/NOTE tags
;;modeline ; snazzy, Atom-inspired modeline, plus API ;;indent-guides ; highlighted indent columns
modeline ; snazzy, Atom-inspired modeline, plus API
nav-flash ; blink the current line after jumping nav-flash ; blink the current line after jumping
;;neotree ; a project drawer, like NERDTree for vim ;;neotree ; a project drawer, like NERDTree for vim
treemacs ; a project drawer, like neotree but cooler treemacs ; a project drawer, like neotree but cooler
@ -69,7 +69,7 @@
;;gist ; interacting with github gists ;;gist ; interacting with github gists
;;lsp ;;lsp
;;macos ; MacOS-specific commands ;;macos ; MacOS-specific commands
;;magit ; a git porcelain for Emacs magit ; a git porcelain for Emacs
;;make ; run make tasks from Emacs ;;make ; run make tasks from Emacs
;;password-store ; password manager for nerds ;;password-store ; password manager for nerds
;;pdf ; pdf enhancements ;;pdf ; pdf enhancements

171
modules/README.org Normal file
View file

@ -0,0 +1,171 @@
#+TITLE: Doom Modules
* Table of Contents :TOC:noexport:
- [[#feature][:feature]]
- [[#completion][:completion]]
- [[#ui][:ui]]
- [[#editor][:editor]]
- [[#emacs][:emacs]]
- [[#tools][:tools]]
- [[#lang][:lang]]
- [[#app][:app]]
- [[#collab][:collab]]
- [[#config][:config]]
* :feature
Broad modules that bring essential IDE functionality to Emacs.
+ debugger: A (nigh-)universal debugger in Emacs
+ [[file:feature/eval/README.org][eval]]: REPL & code evaluation support for a variety of languages
+ [[file:feature/evil/README.org][evil]] =+everywhere=: Vim in Emacs
+ [[file:feature/file-templates/README.org][file-templates]]: Auto-inserted templates in blank new files
+ [[file:feature/lookup/README.org][lookup]] =+docsets=: Universal jump-to & documentation lookup backend
+ [[file:feature/snippets/README.org][snippets]]: A templating system for Emacs for lazy typers (aka programmers)
+ [[file:feature/workspaces/README.org][workspaces]]: Isolated workspaces
* :completion
Swappable completion modules for quickly narrowing down lists of candidates.
+ [[file:completion/company/README.org][company]] =+auto +childframe=: The ultimate code completion backend
+ helm =+fuzzy +childframe=: *Another* search engine for love and life
+ ido: The /other/ *other* search engine for love and life
+ [[file:completion/ivy/README.org][ivy]] =+fuzzy +childframe=: /The/ search engine for love and life
* :ui
Aesthetic modules that affect the Emacs interface or user experience.
+ [[file:ui/deft/README.org][deft]]:
+ [[file:ui/doom/README.org][doom]]:
+ [[file:ui/doom-dashboard/README.org][doom-dashboard]]:
+ [[file:ui/doom-quit/README.org][doom-quit]]:
+ [[file:ui/evil-goggles/README.org][evil-goggles]]:
+ fci:
+ [[file:ui/hl-todo/README.org][hl-todo]]:
+ [[file:ui/modeline/README.org][modeline]]:
+ [[file:ui/nav-flash/README.org][nav-flash]]:
+ [[file:ui/neotree/README.org][neotree]]:
+ treemacs:
+ [[file:ui/popup/README.org][popup]] =+all +defaults=: Makes temporary/disposable windows less intrusive
+ pretty-code:
+ [[file:ui/tabbar/README.org][tabbar]]:
+ [[file:ui/unicode/README.org][unicode]]:
+ vc-gutter:
+ vi-tilde-fringe:
+ [[file:ui/window-select/README.org][window-select]]:
* :editor
Modules that affect and augment your ability to write and edit text.
+ [[file:editor/fold/README.org][fold]]: universal code folding
+ [[file:editor/format/README.org][format]] =+onsave=:
+ [[file:editor/lispy/README.org][lispy]]:
+ multiple-cursors:
+ [[file:editor/parinfer/README.org][parinfer]]:
+ rotate-text:
* :emacs
Modules that reconfigure packages or features built into Emacs
+ dired =+ranger +icons=:
+ electric:
+ eshell:
+ imenu:
+ term:
+ vc:
* :tools
Small modules that give Emacs access to external tools & services.
+ ansible:
+ docker:
+ [[file:tools/editorconfig/README.org][editorconfig]]:
+ [[file:tools/ein/README.org][ein]]:
+ flyspell: Spell checking
+ flycheck: Live error/warning highlights
+ gist:
+ [[file:tools/lsp/README.org][lsp]]:
+ macos:
+ make:
+ magit:
+ password-store:
+ pdf:
+ prodigy:
+ rgb:
+ terraform:
+ tmux:
+ upload:
+ [[file:tools/wakatime/README.org][wakatime]]:
+ vterm:
* :lang
Modules that bring support for a language or group of languages to Emacs.
+ assembly:
+ [[file:lang/cc/README.org][cc]] =+lsp=:
+ clojure:
+ common-lisp:
+ [[file:lang/coq/README.org][coq]]:
+ crystal:
+ [[file:lang/csharp/README.org][csharp]]:
+ data:
+ erlang:
+ elixir:
+ elm:
+ emacs-lisp:
+ [[file:lang/ess/README.org][ess]]:
+ [[file:lang/go/README.org][go]] =+lsp=:
+ [[file:lang/haskell/README.org][haskell]] =+intero +dante=:
+ hy:
+ [[file:lang/idris/README.org][idris]]:
+ java =+meghanada=:
+ [[file:lang/javascript/README.org][javascript]] =+lsp=:
+ julia:
+ [[file:lang/latex/README.org][latex]]:
+ ledger:
+ lua:
+ markdown:
+ [[file:lang/nim/README.org][nim]]:
+ nix:
+ [[file:lang/ocaml/README.org][ocaml]] =+lsp=:
+ [[file:lang/org/README.org][org]] =+attach +babel +capture +export +present +ipython=:
+ [[file:lang/perl/README.org][perl]]:
+ [[file:lang/php/README.org][php]] =+lsp=:
+ plantuml:
+ purescript:
+ python =+lsp=:
+ qt:
+ racket:
+ [[file:lang/rest/README.org][rest]]:
+ ruby =+lsp=:
+ [[file:lang/rust/README.org][rust]] =+lsp=:
+ scala:
+ [[file:lang/sh/README.org][sh]] =+fish +lsp=:
+ [[file:lang/solidity/README.org][solidity]]:
+ swift:
+ web =+lsp=:
+ vala:
* :app
Large, opinionated modules that transform and take over Emacs, i.e.
Doom-specific porcelains.
+ calendar:
+ [[file:app/email/README.org][email]] =+gmail=:
+ [[file:app/irc/README.org][irc]]:
+ regex:
+ rss =+org=:
+ twitter:
+ [[file:app/write/README.org][write]] =+wordnut +langtool=:
* :collab
Modules that enable collaborative programming over the internet.
+ floobits:
+ impatient-mode:
* :config
Modules that configure Emacs one way or another, or focus on making it easier
for you to customize it yourself.
+ literate:
+ [[file:config/default/README.org][default]] =+bindings +smartparens=:

View file

@ -28,8 +28,7 @@
(define-key cfw:calendar-mode-map "q" #'+calendar/quit) (define-key cfw:calendar-mode-map "q" #'+calendar/quit)
(when (featurep 'solaire-mode) (add-hook 'cfw:calendar-mode-hook #'doom|mark-buffer-as-real)
(add-hook 'cfw:calendar-mode-hook #'solaire-mode))
(add-hook 'cfw:calendar-mode-hook 'hide-mode-line-mode) (add-hook 'cfw:calendar-mode-hook 'hide-mode-line-mode)
(advice-add #'cfw:render-button :override #'+calendar*cfw:render-button)) (advice-add #'cfw:render-button :override #'+calendar*cfw:render-button))

View file

@ -18,6 +18,8 @@
company-echo-metadata-frontend)) company-echo-metadata-frontend))
:config :config
(add-hook 'company-mode-hook #'+company|init-backends) (add-hook 'company-mode-hook #'+company|init-backends)
(when (featurep! :feature evil)
(add-hook 'company-mode-hook #'evil-normalize-keymaps))
(global-company-mode +1)) (global-company-mode +1))
@ -36,10 +38,7 @@
(add-to-list 'company-frontends 'company-tng-frontend) (add-to-list 'company-frontends 'company-tng-frontend)
(define-key! company-active-map (define-key! company-active-map
"RET" nil "RET" nil
[return] nil
"TAB" #'company-select-next "TAB" #'company-select-next
[tab] #'company-select-next
"<backtab>" #'company-select-previous
[backtab] #'company-select-previous)) [backtab] #'company-select-previous))
@ -60,44 +59,60 @@
(setq company-box-show-single-candidate t (setq company-box-show-single-candidate t
company-box-backends-colors nil company-box-backends-colors nil
company-box-max-candidates 50 company-box-max-candidates 50
company-box-icons-yasnippet (all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-green) company-box-icons-alist 'company-box-icons-all-the-icons
company-box-icons-unknown (all-the-icons-material "find_in_page" :height 0.8 :face 'all-the-icons-purple) company-box-icons-functions
company-box-icons-elisp '(+company-box-icons--yasnippet company-box-icons--lsp +company-box-icons--elisp company-box-icons--acphp)
(list (all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red) company-box-icons-all-the-icons
(all-the-icons-material "check_circle" :height 0.8 :face 'all-the-icons-blue) `((Unknown . ,(all-the-icons-material "find_in_page" :height 0.8 :face 'all-the-icons-purple))
(all-the-icons-material "stars" :height 0.8 :face 'all-the-icons-orange) (Text . ,(all-the-icons-material "text_fields" :height 0.8 :face 'all-the-icons-green))
(all-the-icons-material "format_paint" :height 0.8 :face 'all-the-icons-pink)) (Method . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
company-box-icons-lsp (Function . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
`((1 . ,(all-the-icons-material "text_fields" :height 0.8 :face 'all-the-icons-green)) ; text (Constructor . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(2 . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) ; method (Field . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(3 . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) ; function (Variable . ,(all-the-icons-material "adjust" :height 0.8 :face 'all-the-icons-blue))
(4 . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) ; constructor (Class . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red))
(5 . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) ; field (Interface . ,(all-the-icons-material "settings_input_component" :height 0.8 :face 'all-the-icons-red))
(6 . ,(all-the-icons-material "adjust" :height 0.8 :face 'all-the-icons-blue)) ; variable (Module . ,(all-the-icons-material "view_module" :height 0.8 :face 'all-the-icons-red))
(7 . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red)) ; class (Property . ,(all-the-icons-material "settings" :height 0.8 :face 'all-the-icons-red))
(8 . ,(all-the-icons-material "settings_input_component" :height 0.8 :face 'all-the-icons-red)) ; interface (Unit . ,(all-the-icons-material "straighten" :height 0.8 :face 'all-the-icons-red))
(9 . ,(all-the-icons-material "view_module" :height 0.8 :face 'all-the-icons-red)) ; module (Value . ,(all-the-icons-material "filter_1" :height 0.8 :face 'all-the-icons-red))
(10 . ,(all-the-icons-material "settings" :height 0.8 :face 'all-the-icons-red)) ; property (Enum . ,(all-the-icons-material "plus_one" :height 0.8 :face 'all-the-icons-red))
(11 . ,(all-the-icons-material "straighten" :height 0.8 :face 'all-the-icons-red)) ; unit (Keyword . ,(all-the-icons-material "filter_center_focus" :height 0.8 :face 'all-the-icons-red))
(12 . ,(all-the-icons-material "filter_1" :height 0.8 :face 'all-the-icons-red)) ; value (Snippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-red))
(13 . ,(all-the-icons-material "plus_one" :height 0.8 :face 'all-the-icons-red)) ; enum (Color . ,(all-the-icons-material "color_lens" :height 0.8 :face 'all-the-icons-red))
(14 . ,(all-the-icons-material "filter_center_focus" :height 0.8 :face 'all-the-icons-red)) ; keyword (File . ,(all-the-icons-material "insert_drive_file" :height 0.8 :face 'all-the-icons-red))
(15 . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-red)) ; snippet (Reference . ,(all-the-icons-material "collections_bookmark" :height 0.8 :face 'all-the-icons-red))
(16 . ,(all-the-icons-material "color_lens" :height 0.8 :face 'all-the-icons-red)) ; color (Folder . ,(all-the-icons-material "folder" :height 0.8 :face 'all-the-icons-red))
(17 . ,(all-the-icons-material "insert_drive_file" :height 0.8 :face 'all-the-icons-red)) ; file (EnumMember . ,(all-the-icons-material "people" :height 0.8 :face 'all-the-icons-red))
(18 . ,(all-the-icons-material "collections_bookmark" :height 0.8 :face 'all-the-icons-red)) ; reference (Constant . ,(all-the-icons-material "pause_circle_filled" :height 0.8 :face 'all-the-icons-red))
(19 . ,(all-the-icons-material "folder" :height 0.8 :face 'all-the-icons-red)) ; folder (Struct . ,(all-the-icons-material "streetview" :height 0.8 :face 'all-the-icons-red))
(20 . ,(all-the-icons-material "people" :height 0.8 :face 'all-the-icons-red)) ; enumMember (Event . ,(all-the-icons-material "event" :height 0.8 :face 'all-the-icons-red))
(21 . ,(all-the-icons-material "pause_circle_filled" :height 0.8 :face 'all-the-icons-red)) ; constant (Operator . ,(all-the-icons-material "control_point" :height 0.8 :face 'all-the-icons-red))
(22 . ,(all-the-icons-material "streetview" :height 0.8 :face 'all-the-icons-red)) ; struct (TypeParameter . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red))
(23 . ,(all-the-icons-material "event" :height 0.8 :face 'all-the-icons-red)) ; event ;; (Template . ,(company-box-icons-image "Template.png"))))
(24 . ,(all-the-icons-material "control_point" :height 0.8 :face 'all-the-icons-red)) ; operator (Yasnippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-green))
(25 . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red))))) (ElispFunction . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(ElispVariable . ,(all-the-icons-material "check_circle" :height 0.8 :face 'all-the-icons-blue))
(ElispFeature . ,(all-the-icons-material "stars" :height 0.8 :face 'all-the-icons-orange))
(ElispFace . ,(all-the-icons-material "format_paint" :height 0.8 :face 'all-the-icons-pink))))
(defun +company-box-icons--yasnippet (candidate)
(when (get-text-property 0 'yas-annotation candidate)
'Yasnippet))
(defun +company-box-icons--elisp (candidate)
(when (derived-mode-p 'emacs-lisp-mode)
(let ((sym (intern candidate)))
(cond ((fboundp sym) 'ElispFunction)
((boundp sym) 'ElispVariable)
((featurep sym) 'ElispFeature)
((facep sym) 'ElispFace))))))
(def-package! company-dict (def-package! company-dict
:defer t :defer t
:config :config
(setq company-dict-dir (expand-file-name "dicts" doom-private-dir))
(defun +company|enable-project-dicts (mode &rest _) (defun +company|enable-project-dicts (mode &rest _)
"Enable per-project dictionaries." "Enable per-project dictionaries."
(if (symbol-value mode) (if (symbol-value mode)

View file

@ -162,9 +162,10 @@ order.
(string-join (delq nil (cdr command)) " ") (string-join (delq nil (cdr command)) " ")
(abbreviate-file-name directory)) (abbreviate-file-name directory))
helm-source-do-ag) helm-source-do-ag)
(cl-letf ((+helm-global-prompt prompt) (helm-attrset '+helm-command command helm-source-do-ag)
((symbol-function 'helm-do-ag--helm) (cl-letf (((symbol-function 'helm-do-ag--helm)
(lambda () (helm :sources '(helm-source-do-ag) (lambda () (helm :sources '(helm-source-do-ag)
:prompt prompt
:buffer "*helm-ag*" :buffer "*helm-ag*"
:keymap helm-do-ag-map :keymap helm-do-ag-map
:input query :input query
@ -177,7 +178,7 @@ order.
return (intern (format format tool)))) return (intern (format format tool))))
;;;###autoload ;;;###autoload
(defun +helm/project-search (&optional all-files-p) (defun +helm/project-search (&optional arg)
"Performs a project search from the project root. "Performs a project search from the project root.
Uses the first available search backend from `+helm-project-search-engines'. If Uses the first available search backend from `+helm-project-search-engines'. If
@ -186,10 +187,10 @@ ones, in the search."
(interactive "P") (interactive "P")
(funcall (or (+helm--get-command "+helm/%s") (funcall (or (+helm--get-command "+helm/%s")
#'+helm/grep) #'+helm/grep)
(or all-files-p current-prefix-arg))) arg))
;;;###autoload ;;;###autoload
(defun +helm/project-search-from-cwd (&optional all-files-p) (defun +helm/project-search-from-cwd (&optional arg)
"Performs a project search recursively from the current directory. "Performs a project search recursively from the current directory.
Uses the first available search backend from `+helm-project-search-engines'. If Uses the first available search backend from `+helm-project-search-engines'. If
@ -198,7 +199,7 @@ ones."
(interactive "P") (interactive "P")
(funcall (or (+helm--get-command "+helm/%s-from-cwd") (funcall (or (+helm--get-command "+helm/%s-from-cwd")
#'+helm/grep-from-cwd) #'+helm/grep-from-cwd)
(or all-files-p current-prefix-arg))) arg))
;; Relative to project root ;; Relative to project root
@ -213,21 +214,31 @@ ones."
(dolist (engine `(,@(cl-remove-duplicates +helm-project-search-engines :from-end t) grep)) (dolist (engine `(,@(cl-remove-duplicates +helm-project-search-engines :from-end t) grep))
(defalias (intern (format "+helm/%s" engine)) (defalias (intern (format "+helm/%s" engine))
(lambda (all-files-p &optional query directory) (lambda (arg &optional query directory)
(interactive "P") (interactive "P")
(+helm-file-search engine :query query :in directory :all-files all-files-p)) (+helm-file-search engine
:query query
:in directory
:all-files (and (not (null arg))
(listp arg))))
(format "Perform a project file search using %s. (format "Perform a project file search using %s.
QUERY is a regexp. If omitted, the current selection is used. If no selection is QUERY is a regexp. If omitted, the current selection is used. If no selection is
active, the last known search is used. active, the last known search is used.
ARG is the universal argument. If a number is passed through it, e.g. C-u 3, then
If ALL-FILES-P, search compressed and hidden files as well." If ALL-FILES-P, search compressed and hidden files as well."
engine)) engine))
(defalias (intern (format "+helm/%s-from-cwd" engine)) (defalias (intern (format "+helm/%s-from-cwd" engine))
(lambda (all-files-p &optional query) (lambda (arg &optional query)
(interactive "P") (interactive "P")
(+helm-file-search engine :query query :in default-directory :all-files all-files-p)) (+helm-file-search engine
:query query
:in default-directory
:all-files (and (not (null arg))
(listp arg))))
(format "Perform a project file search from the current directory using %s. (format "Perform a project file search from the current directory using %s.
QUERY is a regexp. If omitted, the current selection is used. If no selection is QUERY is a regexp. If omitted, the current selection is used. If no selection is

View file

@ -1,6 +1,12 @@
;;; completion/ivy/autoload/ivy.el -*- lexical-binding: t; -*- ;;; completion/ivy/autoload/ivy.el -*- lexical-binding: t; -*-
(defun +ivy--is-workspace-or-other-buffer-p (buffer) (defun +ivy--is-workspace-buffer-p (buffer)
(let ((buffer (car buffer)))
(when (stringp buffer)
(setq buffer (get-buffer buffer)))
(+workspace-contains-buffer-p buffer)))
(defun +ivy--is-workspace-other-buffer-p (buffer)
(let ((buffer (car buffer))) (let ((buffer (car buffer)))
(when (stringp buffer) (when (stringp buffer)
(setq buffer (get-buffer buffer))) (setq buffer (get-buffer buffer)))
@ -28,21 +34,73 @@ temporary/special buffers in `font-lock-comment-face'."
;; ;;
;; Library ;; Library
(defun +ivy--switch-buffer-preview ()
(let (ivy-use-virtual-buffers ivy--virtual-buffers)
(counsel--switch-buffer-update-fn)))
(defalias '+ivy--switch-buffer-preview-all #'counsel--switch-buffer-update-fn)
(defalias '+ivy--switch-buffer-unwind #'counsel--switch-buffer-unwind)
(defun +ivy--switch-buffer (workspace other)
(let ((current (not other))
prompt action filter update unwind)
(cond ((and workspace current)
(setq prompt "Switch to workspace buffer: "
action #'ivy--switch-buffer-action
filter #'+ivy--is-workspace-other-buffer-p))
(workspace
(setq prompt "Switch to workspace buffer in other window: "
action #'ivy--switch-buffer-other-window-action
filter #'+ivy--is-workspace-buffer-p))
(current
(setq prompt "Switch to buffer: "
action #'ivy--switch-buffer-action))
(t
(setq prompt "Switch to buffer in other window: "
action #'ivy--switch-buffer-other-window-action)))
(when +ivy-buffer-preview
(cond ((not (and ivy-use-virtual-buffers
(eq +ivy-buffer-preview 'everything)))
(setq update #'+ivy--switch-buffer-preview
unwind #'+ivy--switch-buffer-unwind))
(t
(setq update #'+ivy--switch-buffer-preview-all
unwind #'+ivy--switch-buffer-unwind))))
(ivy-read prompt 'internal-complete-buffer
:action action
:predicate filter
:update-fn update
:unwind unwind
:preselect (buffer-name (other-buffer (current-buffer)))
:matcher #'ivy--switch-buffer-matcher
:keymap ivy-switch-buffer-map
:caller #'+ivy--switch-buffer)))
;;;###autoload ;;;###autoload
(defun +ivy/switch-workspace-buffer (&optional arg) (defun +ivy/switch-workspace-buffer (&optional arg)
"Switch to another buffer within the current workspace. "Switch to another buffer within the current workspace.
If ARG (universal argument), open selection in other-window." If ARG (universal argument), open selection in other-window."
(interactive "P") (interactive "P")
(ivy-read "Switch to workspace buffer: " (+ivy--switch-buffer t arg))
'internal-complete-buffer
:predicate #'+ivy--is-workspace-or-other-buffer-p ;;;###autoload
:action (if arg (defun +ivy/switch-workspace-buffer-other-window ()
#'ivy--switch-buffer-other-window-action "Switch another window to a buffer within the current workspace."
#'ivy--switch-buffer-action) (interactive)
:matcher #'ivy--switch-buffer-matcher (+ivy--switch-buffer t t))
:keymap ivy-switch-buffer-map
:caller #'+ivy/switch-workspace-buffer)) ;;;###autoload
(defun +ivy/switch-buffer ()
"Switch to another buffer."
(interactive)
(+ivy--switch-buffer nil nil))
;;;###autoload
(defun +ivy/switch-buffer-other-window ()
"Switch to another buffer in another window."
(interactive)
(+ivy--switch-buffer nil t))
(defun +ivy--tasks-candidates (tasks) (defun +ivy--tasks-candidates (tasks)
"Generate a list of task tags (specified by `+ivy-task-tags') for "Generate a list of task tags (specified by `+ivy-task-tags') for
@ -230,7 +288,7 @@ order.
'grep) 'grep)
(error "No search engine specified (is ag, rg, pt or git installed?)"))) (error "No search engine specified (is ag, rg, pt or git installed?)")))
(query (query
(or query (or (if query (rxt-quote-pcre query))
(when (use-region-p) (when (use-region-p)
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning))) (let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
(end (or (bound-and-true-p evil-visual-end) (region-end)))) (end (or (bound-and-true-p evil-visual-end) (region-end))))

View file

@ -3,6 +3,13 @@
(defvar +ivy-buffer-icons nil (defvar +ivy-buffer-icons nil
"If non-nil, show buffer mode icons in `ivy-switch-buffer' and the like.") "If non-nil, show buffer mode icons in `ivy-switch-buffer' and the like.")
(defvar +ivy-buffer-preview nil
"If non-nil, preview buffers while switching, à la `counsel-switch-buffer'.
When nil, don't preview anything.
When non-nil, preview non-virtual buffers.
When 'everything, also preview virtual buffers")
(defvar +ivy-task-tags (defvar +ivy-task-tags
'(("TODO" . warning) '(("TODO" . warning)
("FIXME" . error)) ("FIXME" . error))
@ -58,9 +65,11 @@ immediately runs it on the current candidate (ending the ivy session)."
(after! yasnippet (after! yasnippet
(add-to-list 'yas-prompt-functions #'+ivy-yas-prompt nil #'eq)) (add-to-list 'yas-prompt-functions #'+ivy-yas-prompt nil #'eq))
(map! [remap switch-to-buffer] #'ivy-switch-buffer (map! :map ivy-mode-map
[remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer [remap switch-to-buffer] #'+ivy/switch-buffer
[remap imenu-anywhere] #'ivy-imenu-anywhere) [remap switch-to-buffer-other-window] #'+ivy/switch-buffer-other-window
[remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer
[remap imenu-anywhere] #'ivy-imenu-anywhere)
(ivy-mode +1) (ivy-mode +1)
@ -68,15 +77,15 @@ immediately runs it on the current candidate (ending the ivy session)."
:commands (ivy-dispatching-done-hydra ivy--matcher-desc) :commands (ivy-dispatching-done-hydra ivy--matcher-desc)
:init :init
(define-key! ivy-minibuffer-map (define-key! ivy-minibuffer-map
"\C-o" #'+ivy-coo-hydra/body "C-o" #'+ivy-coo-hydra/body
(kbd "M-o") #'ivy-dispatching-done-hydra))) "M-o" #'ivy-dispatching-done-hydra)))
(def-package! ivy-rich (def-package! ivy-rich
:hook (ivy-mode . ivy-rich-mode) :hook (ivy-mode . ivy-rich-mode)
:config :config
;; Show more buffer information in other switch-buffer commands too ;; Show more buffer information in other switch-buffer commands too
(dolist (cmd '(+ivy/switch-workspace-buffer (dolist (cmd '(+ivy--switch-buffer
counsel-projectile-switch-to-buffer)) counsel-projectile-switch-to-buffer))
(ivy-set-display-transformer cmd 'ivy-rich--ivy-switch-buffer-transformer)) (ivy-set-display-transformer cmd 'ivy-rich--ivy-switch-buffer-transformer))
;; Use `+ivy-rich-buffer-name' to display buffer names ;; Use `+ivy-rich-buffer-name' to display buffer names
@ -95,6 +104,8 @@ immediately runs it on the current candidate (ending the ivy session)."
[remap describe-face] #'counsel-faces [remap describe-face] #'counsel-faces
[remap describe-function] #'counsel-describe-function [remap describe-function] #'counsel-describe-function
[remap describe-variable] #'counsel-describe-variable [remap describe-variable] #'counsel-describe-variable
[remap describe-bindings] #'counsel-descbinds
[remap set-variable] #'counsel-set-variable
[remap execute-extended-command] #'counsel-M-x [remap execute-extended-command] #'counsel-M-x
[remap find-file] #'counsel-find-file [remap find-file] #'counsel-find-file
[remap find-library] #'counsel-find-library [remap find-library] #'counsel-find-library
@ -203,6 +214,10 @@ immediately runs it on the current candidate (ending the ivy session)."
;; default to posframe display function ;; default to posframe display function
(setf (alist-get t ivy-display-functions-alist) #'+ivy-display-at-frame-center-near-bottom) (setf (alist-get t ivy-display-functions-alist) #'+ivy-display-at-frame-center-near-bottom)
;; Fix #1017: stop session persistence from restoring a broken posframe
(defun +workspace|delete-all-posframes (&rest _) (posframe-delete-all))
(add-hook 'persp-after-load-state-functions #'+workspace|delete-all-posframes)
;; posframe doesn't work well with async sources ;; posframe doesn't work well with async sources
(dolist (fn '(swiper counsel-ag counsel-grep counsel-git-grep)) (dolist (fn '(swiper counsel-ag counsel-grep counsel-git-grep))
(setf (alist-get fn ivy-display-functions-alist) #'ivy-display-function-fallback))) (setf (alist-get fn ivy-display-functions-alist) #'ivy-display-function-fallback)))

View file

@ -1,304 +1,352 @@
;;; config/default/+emacs-bindings.el -*- lexical-binding: t; -*- ;;; config/default/+emacs-bindings.el -*- lexical-binding: t; -*-
;; Sensible deafult key bindings for non-evil users ;; Sensible deafult key bindings for non-evil users
(setq doom-leader-alt-key "C-c"
doom-localleader-alt-key "C-c l")
;; persp-mode and projectile in different prefixes ;; persp-mode and projectile in different prefixes
(setq persp-keymap-prefix (kbd "C-c e")) (setq persp-keymap-prefix (kbd "C-c w"))
(after! projectile (after! projectile
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)) (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map))
(which-key-add-key-based-replacements "C-c !" "checking") (after! which-key
(which-key-add-key-based-replacements "C-c e" "perspective") (which-key-add-key-based-replacements "C-c !" "checking")
(which-key-add-key-based-replacements "C-c p" "projectile") (which-key-add-key-based-replacements "C-c l" "<localleader>"))
;; Prefix key to invoke doom related commands
(setq doom-leader-alt-key "C-c")
(setq doom-localleader-alt-key "C-c l")
(map! ;;
;; Text scaling ;;; Global keybinds
"<C-mouse-4>" #'text-scale-increase
"<C-mouse-5>" #'text-scale-decrease
"<C-down-mouse-2>" (λ! (text-scale-set 0))
"M-+" (λ! (text-scale-set 0))
"M-=" #'text-scale-increase
"M--" #'text-scale-decrease
;; Editor related bindings
[remap newline] #'newline-and-indent
"C-j" #'+default/newline
(:when (featurep! :completion ivy)
"C-S-s" #'swiper
"C-S-r" #'ivy-resume)
(:when (featurep! :completion helm)
"C-S-s" #'swiper-helm
"C-S-r" #'helm-resume)
;; Buffer related bindings
"C-x b" #'persp-switch-to-buffer
"C-x C-b" #'ibuffer-list-buffers
"C-x B" #'switch-to-buffer
"C-x k" #'doom/kill-this-buffer-in-all-windows
;; Popup bindigns
"C-x p" #'+popup/other
"C-`" #'+popup/toggle
"C-~" #'+popup/raise
;; Doom emacs bindings
(:leader
(:prefix ("d" . "doom")
:desc "Dashboard" "d" #'+doom-dashboard/open
:desc "Recent files" "f" #'recentf-open-files
(:when (featurep! :ui neotree)
:desc "Open neotree" "n" #'+neotree/open
:desc "File in neotree" "N" #'neotree/find-this-file)
(:when (featurep! :ui treemacs)
:desc "Toggle treemacs" "n" #'+treemacs/toggle
:desc "File in treemacs" "N" #'+treemacs/find-file)
:desc "Popup other" "o" #'+popup/other
:desc "Popup toggle" "t" #'+popup/toggle
:desc "Popup close" "c" #'+popup/close
:desc "Popup close all" "C" #'+popup/close-all
:desc "Popup raise" "r" #'+popup/raise
:desc "Popup restore" "R" #'+popup/restore
:desc "Scratch buffer" "s" #'doom/open-scratch-buffer
:desc "Switch to scratch buffer" "S" #'doom/switch-to-scratch-buffer
:desc "Sudo this file" "u" #'doom/sudo-this-file
:desc "Sudo find file" "U" #'doom/sudo-find-file
:desc "Eshell popup" "e" #'+eshell/open-popup
:desc "Eshell open" "E" #'+eshell/open
:desc "Reload Private Config" "R" #'doom/reload)
;; Org related bindings
"o" nil ; we need to unbind it first as Org claims this
(:prefix ("o". "org")
:desc "Do what I mean" "o" #'+org/dwim-at-point
:desc "Sync org caldav" "s" #'org-caldav-sync
(:prefix ("a" . "org agenda")
:desc "Agenda" "a" #'org-agenda
:desc "Todo list" "t" #'org-todo-list
:desc "Tags view" "m" #'org-tags-view
:desc "View search" "v" #'org-search-view)
:desc "Capture" "c" #'org-capture
:desc "Goto capture" "C" (λ! (require 'org-capture) (call-interactively #'org-capture-goto-target))
:desc "Switch org buffers" "b" #'org-switchb
(:prefix ("e" . "org export")
:desc "Export beamer to latex" "l b" #'org-beamer-export-to-latex
:desc "Export beamer as latex" "l B" #'org-beamer-export-as-latex
:desc "Export beamer as pdf" "l P" #'org-beamer-export-to-pdf)
:desc "Link store" "l" #'org-store-link)
;; Quit/Restart
(:prefix ("q" . "quit/restart")
:desc "Quit Emacs" "q" #'kill-emacs
:desc "Save and quit Emacs" "Q" #'save-buffers-kill-terminal
(:when (featurep! :feature workspaces)
:desc "Quit Emacs & forget session" "X" #'+workspace/kill-session-and-quit
:desc "Restart & restore Emacs" "r" #'+workspace/restart-emacs-then-restore)
:desc "Restart Emacs" "R" #'restart-emacs)
;; Snippets
"&" nil ; yasnippet creates this prefix, we use a different one
(:prefix ("s" . "snippets")
:desc "New snippet" "n" #'yas-new-snippet
:desc "Insert snippet" "i" #'yas-insert-snippet
:desc "Find global snippet" "/" #'yas-visit-snippet-file
:desc "Reload snippets" "r" #'yas-reload-all
:desc "Create Temp Template" "c" #'aya-create
:desc "Use Temp Template" "e" #'aya-expand)
;; Version control bindings
(:prefix ("v" . "versioning")
:desc "Browse issues tracker" "i" #'forge-browse-issues
:desc "Browse remote" "o" #'forge-browse-remote
:desc "Diff current file" "d" #'magit-diff-buffer-file
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk
:desc "Git stage file" "S" #'magit-stage-file
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
:desc "Git time machine" "t" #'git-timemachine-toggle
:desc "Git unstage file" "U" #'magit-unstage-file
:desc "Initialize repo" "I" #'magit-init
:desc "List repositories" "L" #'magit-list-repositories
:desc "Magit blame" "b" #'magit-blame-addition
:desc "Magit buffer log" "l" #'magit-log-buffer-file
:desc "Magit commit" "c" #'magit-commit-create
:desc "Magit status" "g" #'magit-status
:desc "Next hunk" "]" #'git-gutter:next-hunk
:desc "Previous hunk" "[" #'git-gutter:previous-hunk)
;; Worspace and window management bindings
(:prefix ("w". "workspaces")
:desc "Autosave session" "a" #'+workspace/save-session
:desc "Display workspaces" "d" #'+workspace/display
:desc "Rename workspace" "r" #'+workspace/rename
:desc "Create workspace" "c" #'+workspace/new
:desc "Delete workspace" "k" #'+workspace/delete
:desc "Save session" "s" (λ! (let ((current-prefix-arg '(4))) (call-interactively #'+workspace/save-session)))
:desc "Save workspace" "S" #'+workspace/save
:desc "Load session" "l" #'+workspace/load-session
:desc "Load last autosaved session" "L" #'+workspace/load-last-session
:desc "Kill other buffers" "o" #'doom/kill-other-buffers
:desc "Undo window config" "u" #'winner-undo
:desc "Redo window config" "U" #'winner-redo
:desc "Switch to left workspace" "p" #'+workspace/switch-left
:desc "Switch to right workspace" "n" #'+workspace/switch-right
:desc "Switch to" "w" #'+workspace/switch-to
:desc "Switch to workspace 1" "1" (λ! (+workspace/switch-to 0))
:desc "Switch to workspace 2" "2" (λ! (+workspace/switch-to 1))
:desc "Switch to workspace 3" "3" (λ! (+workspace/switch-to 2))
:desc "Switch to workspace 4" "4" (λ! (+workspace/switch-to 3))
:desc "Switch to workspace 5" "5" (λ! (+workspace/switch-to 4))
:desc "Switch to workspace 6" "6" (λ! (+workspace/switch-to 5))
:desc "Switch to workspace 7" "7" (λ! (+workspace/switch-to 6))
:desc "Switch to workspace 8" "8" (λ! (+workspace/switch-to 7))
:desc "Switch to workspace 9" "9" (λ! (+workspace/switch-to 8))
:desc "Switch to last workspace" "0" #'+workspace/switch-to-last)
;; Multiple Cursors
(:when (featurep! :editor multiple-cursors)
(:prefix ("m" . "multiple cursors")
:desc "Edit lines" "l" #'mc/edit-lines
:desc "Mark next" "n" #'mc/mark-next-like-this
:desc "Unmark next" "N" #'mc/unmark-next-like-this
:desc "Mark previous" "p" #'mc/mark-previous-like-this
:desc "Unmark previous" "P" #'mc/unmark-previous-like-this
:desc "Mark all" "t" #'mc/mark-all-like-this
:desc "Mark all DWIM" "m" #'mc/mark-all-like-this-dwim
:desc "Edit line endings" "e" #'mc/edit-ends-of-lines
:desc "Edit line starts" "a" #'mc/edit-beginnings-of-lines
:desc "Mark tag" "s" #'mc/mark-sgml-tag-pair
:desc "Mark in defun" "d" #'mc/mark-all-like-this-in-defun
:desc "Add cursor w/mouse" "<mouse-1>" #'mc/add-cursor-on-click))
;; APPs (map! "C-'" #'imenu
;; Text scaling
"<C-mouse-4>" #'text-scale-increase
"<C-mouse-5>" #'text-scale-decrease
"<C-down-mouse-2>" (λ! (text-scale-set 0))
"M-+" (λ! (text-scale-set 0))
"M-=" #'text-scale-increase
"M--" #'text-scale-decrease
;; Editor related bindings
[remap newline] #'newline-and-indent
"C-j" #'+default/newline
(:when (featurep! :completion ivy)
"C-S-s" #'swiper
"C-S-r" #'ivy-resume)
(:when (featurep! :completion helm)
"C-S-s" #'swiper-helm
"C-S-r" #'helm-resume)
;; Buffer related bindings
"C-x b" #'persp-switch-to-buffer
(:when (featurep! :completion ivy)
"C-x 4 b" #'+ivy/switch-workspace-buffer-other-window)
"C-x C-b" #'ibuffer-list-buffers
"C-x B" #'switch-to-buffer
"C-x 4 B" #'switch-to-buffer-other-window
"C-x k" #'doom/kill-this-buffer-in-all-windows
;; Popup bindigns
"C-x p" #'+popup/other
"C-`" #'+popup/toggle
"C-~" #'+popup/raise)
;; Email
(:when (featurep! :app email)
(:prefix ("M" . "email")
:desc "Open email app" "m" #'=email
:desc "Compose email" "c" #'+email/compose))
;; IRC
(:when (featurep! :app irc)
(:prefix ("I" . "irc")
:desc "Open irc app" "i" #'=irc
:desc "Next unread buffer" "a" #'tracking-next-buffer
:desc "Quit irc" "q" #'+irc/quit
:desc "Reconnect all" "r" #'circe-reconnect-all
:desc "Send message" "s" #'+irc/send-message
(:when (featurep! :completion ivy)
:desc "Jump to channel" "j" #'irc/ivy-jump-to-channel)))
;; Twitter
(:when (featurep! :app twitter)
(:prefix ("T" . "twitter")
:desc "Open twitter app" "t" #'=twitter
:desc "Quit twitter" "q" #'+twitter/quit
:desc "Rerender twits" "r" #'+twitter/rerender-all
:desc "Ace link" "l" #'+twitter/ace-link)))
;; Plugins ;;
;;; Leader keys
;; misc plugins (map! :leader
(:when (featurep! :ui neotree) :desc "Find file in project" "C-f" #'projectile-find-file
"<f9>" #'+neotree/open) :desc "Evaluate line/region" "e" #'+eval/line-or-region
(:when (featurep! :ui treemacs) :desc "Pop up scratch buffer" "x" #'doom/open-to-scratch-buffer
"<f9>" #'+treemacs/toggle) :desc "Switch to scratch buffer" "X" #'doom/switch-to-scratch-buffer
"C-=" #'er/expand-region
"C--" #'er/contract-region (:when (featurep! :emacs term)
;; smartparens :desc "Terminal" "`" #'+term/open
(:after smartparens :desc "Terminal in popup" "~" #'+term/open-popup-in-project)
(:map smartparens-mode-map (:when (featurep! :tools vterm)
"C-M-a" #'sp-beginning-of-sexp :desc "Terminal" "`" #'+vterm/open
"C-M-e" #'sp-end-of-sexp :desc "Terminal in popup" "~" #'+vterm/open-popup-in-project)
"C-M-f" #'sp-forward-sexp (:when (featurep! :emacs eshell)
"C-M-b" #'sp-backward-sexp :desc "Eshell" "`" #'+eshell/open
"C-M-d" #'sp-splice-sexp :desc "Eshell in popup" "~" #'+eshell/open-popup)
"C-M-k" #'sp-kill-sexp
"C-M-t" #'sp-transpose-sexp ;; Add labels to prefixes defined elsewhere
"C-<right>" #'sp-forward-slurp-sexp :desc "project" "p" nil
"M-<right>" #'sp-forward-barf-sexp
"C-<left>" #'sp-backward-slurp-sexp (:prefix ("f" . "file")
"M-<left>" #'sp-backward-barf-sexp)) :desc "Find other file" "a" #'projectile-find-other-file
;; company mode :desc "Browse private config" "c" #'doom/open-private-config
"C-;" #'+company/complete :desc "Find file in private config" "C" #'doom/find-file-in-private-config
;; Counsel :desc "Open project editorconfig" "." #'editorconfig-find-current-editorconfig
(:when (featurep! :completion ivy) :desc "Find directory" "d" #'dired
(:after counsel :desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
(:map counsel-ag-map :desc "Browse emacs.d" "E" #'+default/browse-emacsd
[backtab] #'+ivy/wgrep-occur ; search/replace on results :desc "Find file from here" "f" (if (fboundp 'counsel-file-jump) #'counsel-file-jump #'find-file)
"C-SPC" #'ivy-call-and-recenter ; preview :desc "Find file in other project" "F" #'doom/browse-in-other-project
"M-RET" (+ivy-do-action! #'+ivy-git-grep-other-window-action)) :desc "Find file in project" "p" #'projectile-find-file
"C-h b" #'counsel-descbinds :desc "Find file in other project" "P" #'doom/find-file-in-other-project
"C-M-y" #'counsel-yank-pop :desc "Recent files" "r" #'recentf-open-files
"C-h F" #'counsel-faces :desc "Recent project files" "R" #'projectile-recentf
"C-h p" #'counsel-package :desc "Sudo this file" "s" #'doom/sudo-this-file
"C-h a" #'counsel-apropos :desc "Sudo find file" "S" #'doom/sudo-find-file
"C-h V" #'counsel-set-variable :desc "Delete this file" "X" #'doom/delete-this-file
"C-'" #'counsel-imenu)) :desc "Yank filename" "y" #'+default/yank-buffer-filename)
;; repl toggle
"C-c C-z" #'+eval/open-repl "o" nil ; we need to unbind it first as Org claims this
;; company mode (:prefix ("o". "org")
(:after company (:prefix ("a" . "org agenda")
(:map company-active-map :desc "Agenda" "a" #'org-agenda
"C-o" #'company-search-kill-others :desc "Todo list" "t" #'org-todo-list
"C-n" #'company-select-next :desc "Tags view" "m" #'org-tags-view
"C-p" #'company-select-previous :desc "View search" "v" #'org-search-view)
"C-h" #'company-quickhelp-manual-begin :desc "Switch org buffers" "b" #'org-switchb
"C-S-h" #'company-show-doc-buffer :desc "Capture" "c" #'org-capture
"C-s" #'company-search-candidates :desc "Goto capture" "C" (λ! (require 'org-capture) (call-interactively #'org-capture-goto-target))
"M-s" #'company-filter-candidates :desc "Link store" "l" #'org-store-link
"<C-tab>" #'company-complete-common-or-cycle :desc "Sync org caldav" "s" #'org-caldav-sync)
[tab] #'company-complete-common-or-cycle
[backtab] #'company-select-previous (:prefix ("q" . "quit/restart")
"C-RET" #'counsel-company) :desc "Quit Emacs" "q" #'kill-emacs
(:map company-search-map :desc "Save and quit Emacs" "Q" #'save-buffers-kill-terminal
"C-n" #'company-search-repeat-forward (:when (featurep! :feature workspaces)
"C-p" #'company-search-repeat-backward :desc "Quit Emacs & forget session" "X" #'+workspace/kill-session-and-quit)
"C-s" (λ! (company-search-abort) (company-filter-candidates)))) :desc "Restart & restore Emacs" "r" #'doom/restart-and-restore
;; neotree bindings :desc "Restart Emacs" "R" #'doom/restart)
(:after neotree
:map neotree-mode-map (:prefix ("&" . "snippets")
"q" #'neotree-hide :desc "New snippet" "n" #'yas-new-snippet
[return] #'neotree-enter :desc "Insert snippet" "i" #'yas-insert-snippet
"RET" #'neotree-enter :desc "Find global snippet" "/" #'yas-visit-snippet-file
"SPC" #'neotree-quick-look :desc "Reload snippets" "r" #'yas-reload-all
"v" #'neotree-enter-vertical-split :desc "Create Temp Template" "c" #'aya-create
"s" #'neotree-enter-horizontal-split :desc "Use Temp Template" "e" #'aya-expand)
"c" #'neotree-create-node
"D" #'neotree-delete-node (:prefix ("v" . "versioning")
"g" #'neotree-refresh :desc "Git revert file" "R" #'vc-revert
"r" #'neotree-rename-node (:when (featurep! :ui vc-gutter)
"R" #'neotree-refresh :desc "Git revert hunk" "r" #'git-gutter:revert-hunk
"h" #'+neotree/collapse-or-up :desc "Git stage hunk" "s" #'git-gutter:stage-hunk
"l" #'+neotree/expand-or-open :desc "Git time machine" "t" #'git-timemachine-toggle
"n" #'neotree-next-line :desc "Jump to next hunk" "n" #'git-gutter:next-hunk
"p" #'neotree-previous-line :desc "Jump to previous hunk" "p" #'git-gutter:previous-hunk)
"N" #'neotree-select-next-sibling-node (:when (featurep! :tools magit)
"P" #'neotree-select-previous-sibling-node) :desc "Magit dispatch" "/" #'magit-dispatch
;; help and info :desc "Forge dispatch" "'" #'forge-dispatch
(:after help-mode :desc "Magit status" "g" #'magit-status
(:map help-mode-map :desc "Magit file delete" "x" #'magit-file-delete
"o" #'ace-link-help :desc "Magit blame" "B" #'magit-blame-addition
">" #'help-go-forward :desc "Magit clone" "C" #'+magit/clone
"<" #'help-go-back)) :desc "Magit fetch" "F" #'magit-fetch
(:after helpful-mode :desc "Magit buffer log" "L" #'magit-log
(:map helpful-mode-map :desc "Git stage file" "S" #'magit-stage-file
"o" #'ace-link-help)) :desc "Git unstage file" "U" #'magit-unstage-file
(:after info (:prefix ("f" . "find")
(:map Info-mode-map :desc "Find file" "f" #'magit-find-file
"o" #'ace-link-info)) :desc "Find gitconfig file" "g" #'magit-find-git-config-file
;; yasnippet :desc "Find commit" "c" #'magit-show-commit
(:after yasnippet :desc "Find issue" "i" #'forge-visit-issue
;; keymap while editing an inserted snippet :desc "Find pull request" "p" #'forge-visit-pullreq)
(:map yas-keymap (:prefix ("o" . "open in browser")
"C-e" #'+snippets/goto-end-of-field :desc "Browse region or line" "." #'+vc/git-browse-region-or-line
"C-a" #'+snippets/goto-start-of-field :desc "Browse remote" "r" #'forge-browse-remote
"<S-tab>" #'yas-prev-field :desc "Browse commit" "c" #'forge-browse-commit
"<M-backspace>" #'+snippets/delete-to-start-of-field :desc "Browse an issue" "i" #'forge-browse-issue
[backspace] #'+snippets/delete-backward-char :desc "Browse a pull request" "p" #'forge-browse-pullreq
[delete] #'+snippets/delete-forward-char-or-field)) :desc "Browse issues" "I" #'forge-browse-issues
;; flycheck :desc "Browse pull requests" "P" #'forge-browse-pullreqs)
(:after flycheck (:prefix ("l" . "list")
(:map flycheck-error-list-mode-map (:when (featurep! :tools gist)
"C-n" #'flycheck-error-list-next-error :desc "List gists" "g" #'+gist:list)
"C-p" #'flycheck-error-list-previous-error :desc "List repositories" "r" #'magit-list-repositories
"RET" #'flycheck-error-list-goto-error)) :desc "List submodules" "s" #'magit-list-submodules
;; ivy :desc "List issues" "i" #'forge-list-issues
(:after ivy :desc "List pull requests" "p" #'forge-list-pullreqs
(:map ivy-minibuffer-map :desc "List notifications" "n" #'forge-list-notifications)
"TAB" #'ivy-alt-done (:prefix ("c" . "create")
"C-g" #'keyboard-escape-quit)) :desc "Initialize repo" "r" #'magit-init
;; ein notebokks :desc "Clone repo" "R" #'+magit/clone
(:after ein:notebook-multilang :desc "Commit" "c" #'magit-commit-create
(:map ein:notebook-multilang-mode-map :desc "Issue" "i" #'forge-create-issue
"C-c h" #'+ein/hydra/body))) :desc "Pull request" "p" #'forge-create-pullreq)))
(:prefix ("w" . "workspaces/windows")
:desc "Autosave session" "a" #'doom/quicksave-session
:desc "Display workspaces" "d" #'+workspace/display
:desc "Rename workspace" "r" #'+workspace/rename
:desc "Create workspace" "c" #'+workspace/new
:desc "Delete workspace" "k" #'+workspace/delete
:desc "Save session" "s" #'doom/save-session
:desc "Save workspace" "S" #'+workspace/save
:desc "Load session" "l" #'doom/load-session
:desc "Load last autosaved session" "L" #'doom/quickload-session
:desc "Kill other buffers" "o" #'doom/kill-other-buffers
:desc "Undo window config" "u" #'winner-undo
:desc "Redo window config" "U" #'winner-redo
:desc "Switch to left workspace" "p" #'+workspace/switch-left
:desc "Switch to right workspace" "n" #'+workspace/switch-right
:desc "Switch to" "w" #'+workspace/switch-to
:desc "Switch to workspace 1" "1" (λ! (+workspace/switch-to 0))
:desc "Switch to workspace 2" "2" (λ! (+workspace/switch-to 1))
:desc "Switch to workspace 3" "3" (λ! (+workspace/switch-to 2))
:desc "Switch to workspace 4" "4" (λ! (+workspace/switch-to 3))
:desc "Switch to workspace 5" "5" (λ! (+workspace/switch-to 4))
:desc "Switch to workspace 6" "6" (λ! (+workspace/switch-to 5))
:desc "Switch to workspace 7" "7" (λ! (+workspace/switch-to 6))
:desc "Switch to workspace 8" "8" (λ! (+workspace/switch-to 7))
:desc "Switch to workspace 9" "9" (λ! (+workspace/switch-to 8))
:desc "Switch to last workspace" "0" #'+workspace/switch-to-last)
(:when (featurep! :editor multiple-cursors)
(:prefix ("m" . "multiple cursors")
:desc "Edit lines" "l" #'mc/edit-lines
:desc "Mark next" "n" #'mc/mark-next-like-this
:desc "Unmark next" "N" #'mc/unmark-next-like-this
:desc "Mark previous" "p" #'mc/mark-previous-like-this
:desc "Unmark previous" "P" #'mc/unmark-previous-like-this
:desc "Mark all" "t" #'mc/mark-all-like-this
:desc "Mark all DWIM" "m" #'mc/mark-all-like-this-dwim
:desc "Edit line endings" "e" #'mc/edit-ends-of-lines
:desc "Edit line starts" "a" #'mc/edit-beginnings-of-lines
:desc "Mark tag" "s" #'mc/mark-sgml-tag-pair
:desc "Mark in defun" "d" #'mc/mark-all-like-this-in-defun
:desc "Add cursor w/mouse" "<mouse-1>" #'mc/add-cursor-on-click))
;; APPs
(:when (featurep! :app email)
(:prefix ("M" . "email")
:desc "Open email app" "M" #'=email
:desc "Compose email" "c" #'+email/compose))
(:when (featurep! :app irc)
(:prefix ("I" . "irc")
:desc "Open irc app" "I" #'=irc
:desc "Next unread buffer" "a" #'tracking-next-buffer
:desc "Quit irc" "q" #'+irc/quit
:desc "Reconnect all" "r" #'circe-reconnect-all
:desc "Send message" "s" #'+irc/send-message
(:when (featurep! :completion ivy)
:desc "Jump to channel" "j" #'irc/ivy-jump-to-channel)))
(:when (featurep! :app twitter)
(:prefix ("T" . "twitter")
:desc "Open twitter app" "T" #'=twitter
:desc "Quit twitter" "q" #'+twitter/quit
:desc "Rerender twits" "r" #'+twitter/rerender-all
:desc "Ace link" "l" #'+twitter/ace-link)))
;;
;;; Plugins
(map! "C-=" #'er/expand-region
"C--" #'er/contract-region
(:when (featurep! :ui neotree)
"<f9>" #'+neotree/open
"<F-f9>" #'+neotree/find-this-file)
(:when (featurep! :ui treemacs)
"<f9>" #'+treemacs/open
"<F-f9>" #'+treemacs/find-file)
;; smartparens
(:after smartparens
:map smartparens-mode-map
"C-M-a" #'sp-beginning-of-sexp
"C-M-e" #'sp-end-of-sexp
"C-M-f" #'sp-forward-sexp
"C-M-b" #'sp-backward-sexp
"C-M-d" #'sp-splice-sexp
"C-M-k" #'sp-kill-sexp
"C-M-t" #'sp-transpose-sexp
"C-<right>" #'sp-forward-slurp-sexp
"M-<right>" #'sp-forward-barf-sexp
"C-<left>" #'sp-backward-slurp-sexp
"M-<left>" #'sp-backward-barf-sexp)
;; company mode
"C-;" #'+company/complete
;; Counsel
(:when (featurep! :completion ivy)
(:after counsel
:map counsel-ag-map
[backtab] #'+ivy/wgrep-occur ; search/replace on results
"C-SPC" #'ivy-call-and-recenter ; preview
"M-RET" (+ivy-do-action! #'+ivy-git-grep-other-window-action))
"C-M-y" #'counsel-yank-pop)
;; repl toggle
"C-c C-z" #'+eval/open-repl-other-window
;; company mode
(:after company
:map company-active-map
"C-o" #'company-search-kill-others
"C-n" #'company-select-next
"C-p" #'company-select-previous
"C-h" #'company-quickhelp-manual-begin
"C-S-h" #'company-show-doc-buffer
"C-s" #'company-search-candidates
"M-s" #'company-filter-candidates
"<C-tab>" #'company-complete-common-or-cycle
[tab] #'company-complete-common-or-cycle
[backtab] #'company-select-previous
"C-RET" #'counsel-company
:map company-search-map
"C-n" #'company-search-repeat-forward
"C-p" #'company-search-repeat-backward
"C-s" (λ! (company-search-abort) (company-filter-candidates)))
;; neotree bindings
(:after neotree
:map neotree-mode-map
"q" #'neotree-hide
"RET" #'neotree-enter
"SPC" #'neotree-quick-look
"v" #'neotree-enter-vertical-split
"s" #'neotree-enter-horizontal-split
"c" #'neotree-create-node
"D" #'neotree-delete-node
"g" #'neotree-refresh
"r" #'neotree-rename-node
"R" #'neotree-refresh
"h" #'+neotree/collapse-or-up
"l" #'+neotree/expand-or-open
"n" #'neotree-next-line
"p" #'neotree-previous-line
"N" #'neotree-select-next-sibling-node
"P" #'neotree-select-previous-sibling-node)
;; help and info
(:after help-mode
:map help-mode-map
"o" #'ace-link-help
">" #'help-go-forward
"<" #'help-go-back
"n" #'forward-button
"p" #'backward-button)
(:after helpful
:map helpful-mode-map
"o" #'ace-link-help)
(:after apropos
:map apropos-mode-map
"o" #'ace-link-help
"n" #'forward-button
"p" #'backward-button)
(:after info
:map Info-mode-map
"o" #'ace-link-info)
;; yasnippet
(:after yasnippet
;; keymap while editing an inserted snippet
:map yas-keymap
"C-e" #'+snippets/goto-end-of-field
"C-a" #'+snippets/goto-start-of-field
"<S-tab>" #'yas-prev-field
"<M-backspace>" #'+snippets/delete-to-start-of-field
[backspace] #'+snippets/delete-backward-char
[delete] #'+snippets/delete-forward-char-or-field)
;; flycheck
(:after flycheck
:map flycheck-error-list-mode-map
"C-n" #'flycheck-error-list-next-error
"C-p" #'flycheck-error-list-previous-error
"RET" #'flycheck-error-list-goto-error)
;; ivy
(:after ivy
:map ivy-minibuffer-map
"TAB" #'ivy-alt-done
"C-g" #'keyboard-escape-quit)
;; ein notebokks
(:after ein:notebook-multilang
:map ein:notebook-multilang-mode-map
"C-c h" #'+ein/hydra/body))

View file

@ -0,0 +1,32 @@
;;; config/default/+emacs.el -*- lexical-binding: t; -*-
(require 'projectile) ; we need its keybinds immediately
;;
;;; Reasonable defaults
(setq shift-select-mode t)
(delete-selection-mode +1)
(def-package! expand-region
:commands (er/contract-region er/mark-symbol er/mark-word)
:config
(defun doom*quit-expand-region ()
"Properly abort an expand-region region."
(when (memq last-command '(er/expand-region er/contract-region))
(er/contract-region 0)))
(advice-add #'evil-escape :before #'doom*quit-expand-region)
(advice-add #'doom/escape :before #'doom*quit-expand-region))
(def-package! winum
:after-call (doom-switch-window-hook)
:config (winum-mode +1))
;;
;;; Keybinds
(when (featurep! +bindings)
(load! "+emacs-bindings"))

View file

@ -2,10 +2,6 @@
;; This file defines a Spacemacs-esque keybinding scheme ;; This file defines a Spacemacs-esque keybinding scheme
;; expand-region's prompt can't tell what key contract-region is bound to, so we
;; tell it explicitly.
(setq expand-region-contract-fast-key "C-v")
;; Don't let evil-collection interfere with certain keys ;; Don't let evil-collection interfere with certain keys
(setq evil-collection-key-blacklist (setq evil-collection-key-blacklist
(list "C-j" "C-k" "gd" "gf" "K" "[" "]" "gz" (list "C-j" "C-k" "gd" "gf" "K" "[" "]" "gz"
@ -21,9 +17,6 @@
"M-;" #'eval-expression "M-;" #'eval-expression
"A-;" #'eval-expression) "A-;" #'eval-expression)
[remap evil-jump-to-tag] #'projectile-find-tag
[remap find-tag] #'projectile-find-tag
;; Smart tab ;; Smart tab
:i [tab] (general-predicate-dispatch nil ; fall back to nearest keymap :i [tab] (general-predicate-dispatch nil ; fall back to nearest keymap
(and (featurep! :feature snippets) (and (featurep! :feature snippets)
@ -34,10 +27,6 @@
(+company-has-completion-p)) (+company-has-completion-p))
'+company/complete) '+company/complete)
:n [tab] (general-predicate-dispatch nil :n [tab] (general-predicate-dispatch nil
(derived-mode-p 'magit-mode)
'magit-section-toggle
(derived-mode-p 'deadgrep-mode)
'deadgrep-toggle-file-results
(and (featurep! :editor fold) (and (featurep! :editor fold)
(save-excursion (end-of-line) (invisible-p (point)))) (save-excursion (end-of-line) (invisible-p (point))))
'+fold/toggle '+fold/toggle
@ -59,18 +48,111 @@
:i [remap newline] #'newline-and-indent ; auto-indent on newline :i [remap newline] #'newline-and-indent ; auto-indent on newline
:i "C-j" #'+default/newline ; default behavior :i "C-j" #'+default/newline ; default behavior
;; expand-region
:v "v" (general-predicate-dispatch 'er/expand-region
(eq (evil-visual-type) 'line)
'evil-visual-char)
:v "C-v" #'er/contract-region
(:after vc-annotate (:after vc-annotate
:map vc-annotate-mode-map :map vc-annotate-mode-map
[remap quit-window] #'kill-this-buffer) [remap quit-window] #'kill-this-buffer)
;; misc ;; misc
:n "C-S-f" #'toggle-frame-fullscreen) :n "C-S-f" #'toggle-frame-fullscreen
;; Global evil keybinds
:m "]a" #'evil-forward-arg
:m "[a" #'evil-backward-arg
:m "]o" #'outline-next-visible-heading
:m "[o" #'outline-previous-visible-heading
:n "]b" #'next-buffer
:n "[b" #'previous-buffer
:n "zx" #'kill-this-buffer
:n "ZX" #'bury-buffer
:n "gp" #'+evil/reselect-paste
:n "g=" #'widen
:v "g=" #'+evil:narrow-buffer
:nv "g@" #'+evil:apply-macro
:nv "gc" #'evil-commentary
:nv "gx" #'evil-exchange
:nv "C-a" #'evil-numbers/inc-at-pt
:nv "C-S-a" #'evil-numbers/dec-at-pt
:v "gp" #'+evil/paste-preserve-register
:v "@" #'+evil:apply-macro
;; repeat in visual mode (FIXME buggy)
:v "." #'+evil:apply-macro
;; don't leave visual mode after shifting
:v "<" #'+evil/visual-dedent ; vnoremap < <gv
:v ">" #'+evil/visual-indent ; vnoremap > >gv
;; window management (prefix "C-w")
(:map evil-window-map
;; Navigation
"C-h" #'evil-window-left
"C-j" #'evil-window-down
"C-k" #'evil-window-up
"C-l" #'evil-window-right
"C-w" #'other-window
;; Swapping windows
"H" #'+evil/window-move-left
"J" #'+evil/window-move-down
"K" #'+evil/window-move-up
"L" #'+evil/window-move-right
"C-S-w" #'ace-swap-window
;; Window undo/redo
"u" #'winner-undo
"C-u" #'winner-undo
"C-r" #'winner-redo
"o" #'doom/window-enlargen
"O" #'doom/window-zoom
;; Delete window
"c" #'+workspace/close-window-or-workspace
"C-C" #'ace-delete-window)
;; Plugins
;; evil-easymotion
:m "gs" #'+evil/easymotion ; lazy-load `evil-easymotion'
(:after evil-easymotion
:map evilem-map
"a" (evilem-create #'evil-forward-arg)
"A" (evilem-create #'evil-backward-arg)
"s" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-forward
:pre-hook (save-excursion (call-interactively #'evil-snipe-s))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"S" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-backward
:pre-hook (save-excursion (call-interactively #'evil-snipe-S))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"SPC" #'avy-goto-char-timer
"/" (evilem-create #'evil-ex-search-next
:pre-hook (save-excursion (call-interactively #'evil-ex-search-forward))
:bind ((evil-search-wrap)))
"?" (evilem-create #'evil-ex-search-previous
:pre-hook (save-excursion (call-interactively #'evil-ex-search-backward))
:bind ((evil-search-wrap))))
;; text object plugins
:textobj "x" #'evil-inner-xml-attr #'evil-outer-xml-attr
:textobj "a" #'evil-inner-arg #'evil-outer-arg
:textobj "B" #'evil-textobj-anyblock-inner-block #'evil-textobj-anyblock-a-block
:textobj "i" #'evil-indent-plus-i-indent #'evil-indent-plus-a-indent
:textobj "k" #'evil-indent-plus-i-indent-up #'evil-indent-plus-a-indent-up
:textobj "j" #'evil-indent-plus-i-indent-up-down #'evil-indent-plus-a-indent-up-down
;; evil-snipe
(:after evil-snipe
:map evil-snipe-parent-transient-map
"C-;" (λ! (require 'evil-easymotion)
(call-interactively
(evilem-create #'evil-snipe-repeat
:bind ((evil-snipe-scope 'whole-buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight))))))
;; evil-surround
:v "S" #'evil-surround-region
:o "s" #'evil-surround-edit
:o "S" #'evil-Surround-edit)
;; ;;
@ -95,105 +177,6 @@
:n "gR" #'+eval/buffer :n "gR" #'+eval/buffer
:v "gR" #'+eval:replace-region) :v "gR" #'+eval:replace-region)
(:when (featurep! :feature evil)
:m "]a" #'evil-forward-arg
:m "[a" #'evil-backward-arg
:m "]o" #'outline-next-visible-heading
:m "[o" #'outline-previous-visible-heading
:n "]b" #'next-buffer
:n "[b" #'previous-buffer
:n "zx" #'kill-this-buffer
:n "ZX" #'bury-buffer
:n "gp" #'+evil/reselect-paste
:n "g=" #'widen
:v "g=" #'+evil:narrow-buffer
:nv "g@" #'+evil:apply-macro
:nv "gc" #'evil-commentary
:nv "gx" #'evil-exchange
:nv "C-a" #'evil-numbers/inc-at-pt
:nv "C-S-a" #'evil-numbers/dec-at-pt
:v "gp" #'+evil/paste-preserve-register
:v "@" #'+evil:apply-macro
;; repeat in visual mode (FIXME buggy)
:v "." #'+evil:apply-macro
;; don't leave visual mode after shifting
:v "<" #'+evil/visual-dedent ; vnoremap < <gv
:v ">" #'+evil/visual-indent ; vnoremap > >gv
;; window management (prefix "C-w")
(:map evil-window-map
;; Navigation
"C-h" #'evil-window-left
"C-j" #'evil-window-down
"C-k" #'evil-window-up
"C-l" #'evil-window-right
"C-w" #'other-window
;; Swapping windows
"H" #'+evil/window-move-left
"J" #'+evil/window-move-down
"K" #'+evil/window-move-up
"L" #'+evil/window-move-right
"C-S-w" #'ace-swap-window
;; Window undo/redo
"u" #'winner-undo
"C-u" #'winner-undo
"C-r" #'winner-redo
"o" #'doom/window-enlargen
"O" #'doom/window-zoom
;; Delete window
"c" #'+workspace/close-window-or-workspace
"C-C" #'ace-delete-window)
;; Plugins
;; evil-easymotion
:m "gs" #'+evil/easymotion ; lazy-load `evil-easymotion'
(:after evil-easymotion
:map evilem-map
"a" (evilem-create #'evil-forward-arg)
"A" (evilem-create #'evil-backward-arg)
"s" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-forward
:pre-hook (save-excursion (call-interactively #'evil-snipe-s))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"S" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-backward
:pre-hook (save-excursion (call-interactively #'evil-snipe-S))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"SPC" #'avy-goto-char-timer
"/" (evilem-create #'evil-ex-search-next
:pre-hook (save-excursion (call-interactively #'evil-ex-search-forward))
:bind ((evil-search-wrap)))
"?" (evilem-create #'evil-ex-search-previous
:pre-hook (save-excursion (call-interactively #'evil-ex-search-backward))
:bind ((evil-search-wrap))))
;; text object plugins
:textobj "x" #'evil-inner-xml-attr #'evil-outer-xml-attr
:textobj "a" #'evil-inner-arg #'evil-outer-arg
:textobj "B" #'evil-textobj-anyblock-inner-block #'evil-textobj-anyblock-a-block
:textobj "i" #'evil-indent-plus-i-indent #'evil-indent-plus-a-indent
:textobj "k" #'evil-indent-plus-i-indent-up #'evil-indent-plus-a-indent-up
:textobj "j" #'evil-indent-plus-i-indent-up-down #'evil-indent-plus-a-indent-up-down
;; evil-snipe
(:after evil-snipe
:map evil-snipe-parent-transient-map
"C-;" (λ! (require 'evil-easymotion)
(call-interactively
(evilem-create #'evil-snipe-repeat
:bind ((evil-snipe-scope 'whole-buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight))))))
;; evil-surround
:v "S" #'evil-surround-region
:o "s" #'evil-surround-edit
:o "S" #'evil-Surround-edit)
(:when (featurep! :feature lookup) (:when (featurep! :feature lookup)
:nv "K" #'+lookup/documentation :nv "K" #'+lookup/documentation
:nv "gd" #'+lookup/definition :nv "gd" #'+lookup/definition
@ -216,10 +199,13 @@
[delete] #'+snippets/delete-forward-char-or-field))) [delete] #'+snippets/delete-forward-char-or-field)))
(:when (featurep! :tools flyspell) (:when (featurep! :tools flyspell)
:m "]s" #'evil-next-flyspell-error
:m "[s" #'evil-prev-flyspell-error
:m "]S" #'flyspell-correct-word-generic :m "]S" #'flyspell-correct-word-generic
:m "[S" #'flyspell-correct-previous-word-generic :m "[S" #'flyspell-correct-previous-word-generic
(:map flyspell-mouse-map (:map flyspell-mouse-map
"RET" #'flyspell-correct-word-generic "RET" #'flyspell-correct-word-generic
[return] #'flyspell-correct-word-generic
[mouse-1] #'flyspell-correct-word-generic)) [mouse-1] #'flyspell-correct-word-generic))
(:when (featurep! :tools flycheck) (:when (featurep! :tools flycheck)
@ -227,11 +213,12 @@
:m "[e" #'previous-error :m "[e" #'previous-error
(:after flycheck (:after flycheck
:map flycheck-error-list-mode-map :map flycheck-error-list-mode-map
:n "C-n" #'flycheck-error-list-next-error :n "C-n" #'flycheck-error-list-next-error
:n "C-p" #'flycheck-error-list-previous-error :n "C-p" #'flycheck-error-list-previous-error
:n "j" #'flycheck-error-list-next-error :n "j" #'flycheck-error-list-next-error
:n "k" #'flycheck-error-list-previous-error :n "k" #'flycheck-error-list-previous-error
:n "RET" #'flycheck-error-list-goto-error)) :n "RET" #'flycheck-error-list-goto-error
:n [return] #'flycheck-error-list-goto-error))
(:when (featurep! :feature workspaces) (:when (featurep! :feature workspaces)
:n "gt" #'+workspace/switch-right :n "gt" #'+workspace/switch-right
@ -279,6 +266,7 @@
"C-S-s" (cond ((featurep! :completion helm) #'helm-company) "C-S-s" (cond ((featurep! :completion helm) #'helm-company)
((featurep! :completion ivy) #'counsel-company)) ((featurep! :completion ivy) #'counsel-company))
"C-SPC" #'company-complete-common "C-SPC" #'company-complete-common
"TAB" #'company-complete-common-or-cycle
[tab] #'company-complete-common-or-cycle [tab] #'company-complete-common-or-cycle
[backtab] #'company-select-previous) [backtab] #'company-select-previous)
(:map company-search-map ; applies to `company-filter-map' too (:map company-search-map ; applies to `company-filter-map' too
@ -287,9 +275,11 @@
"C-j" #'company-select-next-or-abort "C-j" #'company-select-next-or-abort
"C-k" #'company-select-previous-or-abort "C-k" #'company-select-previous-or-abort
"C-s" (λ! (company-search-abort) (company-filter-candidates)) "C-s" (λ! (company-search-abort) (company-filter-candidates))
[escape] #'company-search-abort) "ESC" #'company-search-abort)
;; TAB auto-completion in term buffers ;; TAB auto-completion in term buffers
:map comint-mode-map [tab] #'company-complete)) (:map comint-mode-map
"TAB" #'company-complete
[tab] #'company-complete)))
(:when (featurep! :completion ivy) (:when (featurep! :completion ivy)
(:map (help-mode-map helpful-mode-map) (:map (help-mode-map helpful-mode-map)
@ -302,6 +292,7 @@
(:after counsel (:after counsel
:map counsel-ag-map :map counsel-ag-map
"C-SPC" #'ivy-call-and-recenter ; preview "C-SPC" #'ivy-call-and-recenter ; preview
"C-l" #'ivy-done
[backtab] #'+ivy/wgrep-occur ; search/replace on results [backtab] #'+ivy/wgrep-occur ; search/replace on results
[C-return] (+ivy-do-action! #'+ivy-git-grep-other-window-action)) [C-return] (+ivy-do-action! #'+ivy-git-grep-other-window-action))
(:after swiper (:after swiper
@ -327,6 +318,7 @@
"C-s" #'helm-minibuffer-history "C-s" #'helm-minibuffer-history
"C-b" #'backward-word "C-b" #'backward-word
;; Swap TAB and C-z ;; Swap TAB and C-z
"TAB" #'helm-execute-persistent-action
[tab] #'helm-execute-persistent-action [tab] #'helm-execute-persistent-action
"C-z" #'helm-select-action) "C-z" #'helm-select-action)
(:after swiper-helm (:after swiper-helm
@ -363,29 +355,31 @@
(:when (featurep! :ui neotree) (:when (featurep! :ui neotree)
:after neotree :after neotree
:map neotree-mode-map :map neotree-mode-map
:n "g" nil :n "g" nil
:n [tab] #'neotree-quick-look :n "TAB" #'neotree-quick-look
:n [return] #'neotree-enter :n "RET" #'neotree-enter
:n [backspace] #'evil-window-prev :n [tab] #'neotree-quick-look
:n "c" #'neotree-create-node :n [return] #'neotree-enter
:n "r" #'neotree-rename-node :n "DEL" #'evil-window-prev
:n "d" #'neotree-delete-node :n "c" #'neotree-create-node
:n "j" #'neotree-next-line :n "r" #'neotree-rename-node
:n "k" #'neotree-previous-line :n "d" #'neotree-delete-node
:n "n" #'neotree-next-line :n "j" #'neotree-next-line
:n "p" #'neotree-previous-line :n "k" #'neotree-previous-line
:n "h" #'+neotree/collapse-or-up :n "n" #'neotree-next-line
:n "l" #'+neotree/expand-or-open :n "p" #'neotree-previous-line
:n "J" #'neotree-select-next-sibling-node :n "h" #'+neotree/collapse-or-up
:n "K" #'neotree-select-previous-sibling-node :n "l" #'+neotree/expand-or-open
:n "H" #'neotree-select-up-node :n "J" #'neotree-select-next-sibling-node
:n "L" #'neotree-select-down-node :n "K" #'neotree-select-previous-sibling-node
:n "G" #'evil-goto-line :n "H" #'neotree-select-up-node
:n "gg" #'evil-goto-first-line :n "L" #'neotree-select-down-node
:n "v" #'neotree-enter-vertical-split :n "G" #'evil-goto-line
:n "s" #'neotree-enter-horizontal-split :n "gg" #'evil-goto-first-line
:n "q" #'neotree-hide :n "v" #'neotree-enter-vertical-split
:n "R" #'neotree-refresh) :n "s" #'neotree-enter-horizontal-split
:n "q" #'neotree-hide
:n "R" #'neotree-refresh)
(:when (featurep! :ui popup) (:when (featurep! :ui popup)
:n "C-`" #'+popup/toggle :n "C-`" #'+popup/toggle
@ -415,8 +409,9 @@
:nv "N" #'evil-mc-make-and-goto-last-cursor :nv "N" #'evil-mc-make-and-goto-last-cursor
:nv "p" #'evil-mc-make-and-goto-prev-cursor :nv "p" #'evil-mc-make-and-goto-prev-cursor
:nv "P" #'evil-mc-make-and-goto-first-cursor :nv "P" #'evil-mc-make-and-goto-first-cursor
:nv "q" #'evil-mc-undo-all-cursors
:nv "t" #'+multiple-cursors/evil-mc-toggle-cursors :nv "t" #'+multiple-cursors/evil-mc-toggle-cursors
:nv "u" #'evil-mc-undo-all-cursors :nv "u" #'evil-mc-undo-last-added-cursor
:nv "z" #'+multiple-cursors/evil-mc-make-cursor-here) :nv "z" #'+multiple-cursors/evil-mc-make-cursor-here)
(:after evil-mc (:after evil-mc
:map evil-mc-key-map :map evil-mc-key-map
@ -433,9 +428,10 @@
:nv "C-M-d" #'evil-multiedit-restore :nv "C-M-d" #'evil-multiedit-restore
(:after evil-multiedit (:after evil-multiedit
(:map evil-multiedit-state-map (:map evil-multiedit-state-map
"M-d" #'evil-multiedit-match-and-next "M-d" #'evil-multiedit-match-and-next
"M-D" #'evil-multiedit-match-and-prev "M-D" #'evil-multiedit-match-and-prev
"RET" #'evil-multiedit-toggle-or-restrict-region) "RET" #'evil-multiedit-toggle-or-restrict-region
[return] #'evil-multiedit-toggle-or-restrict-region)
(:map (evil-multiedit-state-map evil-multiedit-insert-state-map) (:map (evil-multiedit-state-map evil-multiedit-insert-state-map)
"C-n" #'evil-multiedit-next "C-n" #'evil-multiedit-next
"C-p" #'evil-multiedit-prev))) "C-p" #'evil-multiedit-prev)))
@ -467,7 +463,8 @@
(:when (featurep! :tools gist) (:when (featurep! :tools gist)
:after gist :after gist
:map gist-list-menu-mode-map :map gist-list-menu-mode-map
:n "RET" #'+gist/open-current :n "RET" #'+gist/open-current
:n [return] #'+gist/open-current
:n "b" #'gist-browse-current-url :n "b" #'gist-browse-current-url
:n "c" #'gist-add-buffer :n "c" #'gist-add-buffer
:n "d" #'gist-kill-current :n "d" #'gist-kill-current
@ -497,16 +494,16 @@
;; C-u is used by evil ;; C-u is used by evil
:desc "Universal argument" "u" #'universal-argument :desc "Universal argument" "u" #'universal-argument
:desc "Window management" "w" #'evil-window-map :desc "window" "w" evil-window-map
:desc "help" "h" help-map
:desc "Toggle last popup" "~" #'+popup/toggle :desc "Toggle last popup" "~" #'+popup/toggle
:desc "Find file" "." #'find-file :desc "Find file" "." #'find-file
:desc "Switch buffer" "," #'switch-to-buffer
(:when (featurep! :feature workspaces) (:when (featurep! :feature workspaces)
:desc "Switch workspace buffer" "," #'persp-switch-to-buffer :desc "Switch workspace buffer" "," #'persp-switch-to-buffer
:desc "Switch buffer" "<" #'switch-to-buffer) :desc "Switch buffer" "<" #'switch-to-buffer)
(:unless (featurep! :feature workspaces)
:desc "Switch buffer" "," #'switch-to-buffer)
:desc "Resume last search" "'" :desc "Resume last search" "'"
(cond ((featurep! :completion ivy) #'ivy-resume) (cond ((featurep! :completion ivy) #'ivy-resume)
@ -520,49 +517,23 @@
(:prefix ("/" . "search") (:prefix ("/" . "search")
:desc "Jump to symbol across buffers" "I" #'imenu-anywhere :desc "Jump to symbol across buffers" "I" #'imenu-anywhere
:desc "Search buffer" "b" #'swiper :desc "Search buffer" "b" #'swiper
:desc "Search current directory" "d" :desc "Search current directory" "d" #'+default/search-from-cwd
(cond ((featurep! :completion helm) #'+helm/project-search-from-cwd)
((featurep! :completion ivy) #'+ivy/project-search-from-cwd))
:desc "Jump to symbol" "i" #'imenu :desc "Jump to symbol" "i" #'imenu
:desc "Jump to link" "l" #'ace-link :desc "Jump to link" "l" #'ace-link
:desc "Look up online" "o" #'+lookup/online-select :desc "Look up online" "o" #'+lookup/online-select
:desc "Search project" "p" :desc "Search project" "p" #'+default/search-project)
(cond ((featurep! :completion ivy) #'+ivy/project-search)
((featurep! :completion helm) #'+helm/project-search)))
(:prefix ("]" . "next")
:desc "Increase text size" "]" #'text-scale-increase
:desc "Next buffer" "b" #'next-buffer
:desc "Next diff Hunk" "d" #'git-gutter:next-hunk
:desc "Next todo" "t" #'hl-todo-next
:desc "Next error" "e" #'next-error
:desc "Next workspace" "w" #'+workspace/switch-right
:desc "Next spelling error" "s" #'evil-next-flyspell-error
:desc "Next spelling correction" "S" #'flyspell-correct-next-word-generic)
(:prefix ("[" . "previous")
:desc "Decrease text size" "[" #'text-scale-decrease
:desc "Previous buffer" "b" #'previous-buffer
:desc "Previous diff Hunk" "d" #'git-gutter:previous-hunk
:desc "Previous todo" "t" #'hl-todo-previous
:desc "Previous error" "e" #'previous-error
:desc "Previous workspace" "w" #'+workspace/switch-left
:desc "Previous spelling error" "s" #'evil-prev-flyspell-error
:desc "Previous spelling correction" "S" #'flyspell-correct-word-generic)
(:when (featurep! :feature workspaces) (:when (featurep! :feature workspaces)
(:prefix ([tab] . "workspace") (:prefix ("TAB" . "workspace")
:desc "Display tab bar" "TAB" #'+workspace/display :desc "Display tab bar" "TAB" #'+workspace/display
:desc "Switch workspace" "." #'+workspace/switch-to
:desc "New workspace" "n" #'+workspace/new :desc "New workspace" "n" #'+workspace/new
:desc "Load workspace from file" "l" #'+workspace/load :desc "Load workspace from file" "l" #'+workspace/load
:desc "Load a past session" "L" #'+workspace/load-session
:desc "Save workspace to file" "s" #'+workspace/save :desc "Save workspace to file" "s" #'+workspace/save
:desc "Autosave current session" "S" #'+workspace/save-session
:desc "Switch workspace" "." #'+workspace/switch-to
:desc "Delete session" "x" #'+workspace/kill-session :desc "Delete session" "x" #'+workspace/kill-session
:desc "Delete this workspace" "d" #'+workspace/delete :desc "Delete this workspace" "d" #'+workspace/delete
:desc "Rename workspace" "r" #'+workspace/rename :desc "Rename workspace" "r" #'+workspace/rename
:desc "Restore last session" "R" #'+workspace/load-last-session :desc "Restore last session" "R" #'+workspace/restore-last-session
:desc "Next workspace" "]" #'+workspace/switch-right :desc "Next workspace" "]" #'+workspace/switch-right
:desc "Previous workspace" "[" #'+workspace/switch-left :desc "Previous workspace" "[" #'+workspace/switch-left
:desc "Switch to 1st workspace" "1" (λ! (+workspace/switch-to 0)) :desc "Switch to 1st workspace" "1" (λ! (+workspace/switch-to 0))
@ -578,8 +549,6 @@
(:prefix ("b" . "buffer") (:prefix ("b" . "buffer")
:desc "Toggle narrowing" "-" #'doom/clone-and-narrow-buffer :desc "Toggle narrowing" "-" #'doom/clone-and-narrow-buffer
:desc "New empty buffer" "N" #'evil-buffer-new
:desc "Sudo edit this file" "S" #'doom/sudo-this-file
:desc "Previous buffer" "[" #'previous-buffer :desc "Previous buffer" "[" #'previous-buffer
:desc "Next buffer" "]" #'next-buffer :desc "Next buffer" "]" #'next-buffer
(:when (featurep! :feature workspaces) (:when (featurep! :feature workspaces)
@ -589,40 +558,44 @@
:desc "Switch buffer" "b" #'switch-to-buffer) :desc "Switch buffer" "b" #'switch-to-buffer)
:desc "Kill buffer" "k" #'kill-this-buffer :desc "Kill buffer" "k" #'kill-this-buffer
:desc "Next buffer" "n" #'next-buffer :desc "Next buffer" "n" #'next-buffer
:desc "New empty buffer" "N" #'evil-buffer-new
:desc "Kill other buffers" "o" #'doom/kill-other-buffers :desc "Kill other buffers" "o" #'doom/kill-other-buffers
:desc "Previous buffer" "p" #'previous-buffer :desc "Previous buffer" "p" #'previous-buffer
:desc "Save buffer" "s" #'save-buffer :desc "Save buffer" "s" #'save-buffer
:desc "Sudo edit this file" "S" #'doom/sudo-this-file
:desc "Pop scratch buffer" "x" #'doom/open-scratch-buffer :desc "Pop scratch buffer" "x" #'doom/open-scratch-buffer
:desc "Bury buffer" "z" #'bury-buffer) :desc "Bury buffer" "z" #'bury-buffer)
(:prefix ("c" . "code") (:prefix ("c" . "code")
:desc "Jump to references" "D" #'+lookup/references :desc "Compile project" "c" #'projectile-compile-project
:desc "Evaluate & replace region" "E" #'+eval:replace-region
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
:desc "Build tasks" "b" #'+eval/build
:desc "Jump to definition" "d" #'+lookup/definition :desc "Jump to definition" "d" #'+lookup/definition
:desc "Jump to references" "D" #'+lookup/references
:desc "Evaluate buffer/region" "e" #'+eval/buffer-or-region :desc "Evaluate buffer/region" "e" #'+eval/buffer-or-region
:desc "Evaluate & replace region" "E" #'+eval:replace-region
:desc "Format buffer/region" "f" #'+format/region-or-buffer :desc "Format buffer/region" "f" #'+format/region-or-buffer
:desc "Open REPL" "r" #'+eval/open-repl-other-window :desc "Open REPL" "r" #'+eval/open-repl-other-window
:desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace :desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
:desc "List errors" "x" #'flycheck-list-errors) :desc "List errors" "x" #'flycheck-list-errors)
(:prefix ("f" . "file") (:prefix ("f" . "file")
:desc "Find file" "." #'find-file :desc "Find file" "." (if (fboundp 'counsel-file-jump) #'counsel-file-jump #'find-file)
:desc "Find file in other project" ">" #'doom/browse-in-other-project
:desc "Find file in project" "/" #'projectile-find-file :desc "Find file in project" "/" #'projectile-find-file
:desc "Sudo find file" ">" #'doom/sudo-find-file :desc "Find file in other project" "?" #'doom/find-file-in-other-project
:desc "Find file from here" "?" #'counsel-file-jump
:desc "Browse emacs.d" "E" #'+default/browse-emacsd
:desc "Browse private config" "P" #'+default/browse-config
:desc "Recent project files" "R" #'projectile-recentf
:desc "Delete this file" "X" #'doom/delete-this-file
:desc "Find other file" "a" #'projectile-find-other-file :desc "Find other file" "a" #'projectile-find-other-file
:desc "Open project editorconfig" "c" #'editorconfig-find-current-editorconfig :desc "Open project editorconfig" "c" #'editorconfig-find-current-editorconfig
:desc "Find directory" "d" #'dired :desc "Find directory" "d" #'dired
:desc "Find file in emacs.d" "e" #'+default/find-in-emacsd :desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
:desc "Find file in private config" "p" #'+default/find-in-config :desc "Browse emacs.d" "E" #'+default/browse-emacsd
:desc "Find file from here" "f" #'find-file
:desc "Find file in private config" "p" #'doom/find-file-in-private-config
:desc "Browse private config" "P" #'doom/open-private-config
:desc "Recent files" "r" #'recentf-open-files :desc "Recent files" "r" #'recentf-open-files
:desc "Recent project files" "R" #'projectile-recentf
:desc "Save file" "s" #'save-buffer :desc "Save file" "s" #'save-buffer
:desc "Sudo find file" "S" #'doom/sudo-find-file
:desc "Delete this file" "X" #'doom/delete-this-file
:desc "Yank filename" "y" #'+default/yank-buffer-filename) :desc "Yank filename" "y" #'+default/yank-buffer-filename)
(:prefix ("g" . "git") (:prefix ("g" . "git")
@ -673,34 +646,6 @@
:desc "Issue" "i" #'forge-create-issue :desc "Issue" "i" #'forge-create-issue
:desc "Pull request" "p" #'forge-create-pullreq))) :desc "Pull request" "p" #'forge-create-pullreq)))
(:prefix ("h" . "help")
:desc "What face" "'" #'doom/what-face
:desc "Describe at point" "." #'helpful-at-point
:desc "Describe active minor modes" ";" #'doom/describe-active-minor-mode
:desc "Open Doom manual" "D" #'doom/open-manual
:desc "Open vanilla sandbox" "E" #'doom/open-vanilla-sandbox
:desc "Describe face" "F" #'describe-face
:desc "Find documentation" "K" #'+lookup/documentation
:desc "Command log" "L" #'global-command-log-mode
:desc "Describe mode" "M" #'describe-mode
:desc "Reload private config" "R" #'doom/reload
:desc "Print Doom version" "V" #'doom/version
:desc "Apropos" "a" #'apropos
:desc "Open Bug Report" "b" #'doom/open-bug-report
:desc "Describe char" "c" #'describe-char
:desc "Describe DOOM module" "d" #'doom/describe-module
:desc "Describe function" "f" #'describe-function
:desc "Emacs help map" "h" help-map
:desc "Info" "i" #'info-lookup-symbol
:desc "Describe key" "k" #'describe-key
:desc "Find library" "l" #'find-library
:desc "View *Messages*" "m" #'view-echo-area-messages
:desc "Toggle profiler" "p" #'doom/toggle-profiler
:desc "Reload theme" "r" #'doom/reload-theme
:desc "Describe DOOM setting" "s" #'doom/describe-setters
:desc "Describe variable" "v" #'describe-variable
:desc "Man pages" "w" #'+default/man-or-woman)
(:prefix ("i" . "insert") (:prefix ("i" . "insert")
:desc "Insert from clipboard" "y" #'+default/yank-pop :desc "Insert from clipboard" "y" #'+default/yank-pop
:desc "Insert from evil register" "r" #'evil-ex-registers :desc "Insert from evil register" "r" #'evil-ex-registers
@ -710,10 +655,17 @@
:desc "Open deft" "d" #'deft :desc "Open deft" "d" #'deft
:desc "Find file in notes" "n" #'+default/find-in-notes :desc "Find file in notes" "n" #'+default/find-in-notes
:desc "Browse notes" "N" #'+default/browse-notes :desc "Browse notes" "N" #'+default/browse-notes
:desc "Org capture" "x" #'org-capture) :desc "Pop scratch buffer" "s" #'doom/open-scratch-buffer
:desc "Org capture" "x" #'org-capture
:desc "Org store link" "l" #'org-store-link)
(:prefix ("o" . "open") (:prefix ("o" . "open")
:desc "Org agenda" "a" #'org-agenda :desc "Org agenda" "A" #'org-agenda
(:prefix ("a" . "org agenda")
:desc "Agenda" "a" #'org-agenda
:desc "Todo list" "t" #'org-todo-list
:desc "Tags search" "m" #'org-tags-view
:desc "View search" "v" #'org-search-view)
:desc "Default browser" "b" #'browse-url-of-file :desc "Default browser" "b" #'browse-url-of-file
:desc "Debugger" "d" #'+debug/open :desc "Debugger" "d" #'+debug/open
:desc "REPL" "r" #'+eval/open-repl-other-window :desc "REPL" "r" #'+eval/open-repl-other-window
@ -767,12 +719,15 @@
:desc "List project tasks" "t" #'+default/project-tasks :desc "List project tasks" "t" #'+default/project-tasks
:desc "Invalidate cache" "x" #'projectile-invalidate-cache) :desc "Invalidate cache" "x" #'projectile-invalidate-cache)
(:prefix ("q" . "quit/restart") (:prefix ("q" . "session")
:desc "Quit Emacs" "q" #'evil-quit-all :desc "Quit Emacs" "q" #'evil-quit-all
:desc "Save and quit Emacs" "Q" #'evil-save-and-quit :desc "Save and quit Emacs" "Q" #'evil-save-and-quit
:desc "Quit Emacs & forget session" "X" #'+workspace/kill-session-and-quit :desc "Quick save current session" "s" #'doom/quicksave-session
:desc "Restart & restore Emacs" "r" #'+workspace/restart-emacs-then-restore :desc "Restore last session" "l" #'doom/quickload-session
:desc "Restart Emacs" "R" #'restart-emacs) :desc "Save session to file" "S" #'doom/save-session
:desc "Restore session from file" "L" #'doom/load-session
:desc "Restart & restore Emacs" "r" #'doom/restart-and-restore
:desc "Restart Emacs" "R" #'doom/restart)
(:when (featurep! :tools upload) (:when (featurep! :tools upload)
(:prefix ("r" . "remote") (:prefix ("r" . "remote")
@ -790,15 +745,16 @@
:desc "Jump to mode snippet" "/" #'yas-visit-snippet-file :desc "Jump to mode snippet" "/" #'yas-visit-snippet-file
:desc "Jump to snippet" "s" #'+snippets/find-file :desc "Jump to snippet" "s" #'+snippets/find-file
:desc "Browse snippets" "S" #'+snippets/browse :desc "Browse snippets" "S" #'+snippets/browse
:desc "Reload snippets" "r" #'yas-reload-all)) :desc "Reload snippets" "r" #'yas-reload-all
:desc "Create temporary snippet" "c" #'aya-create
:desc "Use temporary snippet" "e" #'aya-expand))
(:prefix ("t" . "toggle") (:prefix ("t" . "toggle")
:desc "Flyspell" "s" #'flyspell-mode :desc "Flyspell" "s" #'flyspell-mode
:desc "Flycheck" "f" #'flycheck-mode :desc "Flycheck" "f" #'flycheck-mode
:desc "Line numbers" "l" #'doom/toggle-line-numbers :desc "Line numbers" "l" #'doom/toggle-line-numbers
:desc "Frame fullscreen" "F" #'toggle-frame-fullscreen :desc "Frame fullscreen" "F" #'toggle-frame-fullscreen
:desc "Indent guides" "i" #'highlight-indentation-mode :desc "Indent guides" "i" #'highlight-indent-guides-mode
:desc "Indent guides (column)" "I" #'highlight-indentation-current-column-mode
:desc "Impatient mode" "h" #'+impatient-mode/toggle :desc "Impatient mode" "h" #'+impatient-mode/toggle
:desc "Big mode" "b" #'doom-big-font-mode :desc "Big mode" "b" #'doom-big-font-mode
:desc "Evil goggles" "g" #'evil-goggles-mode :desc "Evil goggles" "g" #'evil-goggles-mode

View file

@ -0,0 +1,109 @@
;;; config/default/+evil.el -*- lexical-binding: t; -*-
(defun +default|disable-delete-selection-mode ()
(delete-selection-mode -1))
(add-hook 'evil-insert-state-entry-hook #'delete-selection-mode)
(add-hook 'evil-insert-state-exit-hook #'+default|disable-delete-selection-mode)
;;
;;; Smartparens config
(when (featurep! +smartparens)
;; You can disable :unless predicates with (sp-pair "'" nil :unless nil)
;; And disable :post-handlers with (sp-pair "{" nil :post-handlers nil)
;; or specific :post-handlers with:
;; (sp-pair "{" nil :post-handlers '(:rem ("| " "SPC")))
(after! smartparens
;; Autopair quotes more conservatively; if I'm next to a word/before another
;; quote, I likely don't want to open a new pair.
(let ((unless-list '(sp-point-before-word-p
sp-point-after-word-p
sp-point-before-same-p)))
(sp-pair "'" nil :unless unless-list)
(sp-pair "\"" nil :unless unless-list))
;; Expand {|} => { | }
;; Expand {|} => {
;; |
;; }
(dolist (brace '("(" "{" "["))
(sp-pair brace nil
:post-handlers '(("||\n[i]" "RET") ("| " "SPC"))
;; I likely don't want a new pair if adjacent to a word or opening brace
:unless '(sp-point-before-word-p sp-point-before-same-p)))
;; Major-mode specific fixes
(sp-local-pair '(ruby-mode enh-ruby-mode) "{" "}"
:pre-handlers '(:rem sp-ruby-pre-handler)
:post-handlers '(:rem sp-ruby-post-handler))
;; Don't do square-bracket space-expansion where it doesn't make sense to
(sp-local-pair '(emacs-lisp-mode org-mode markdown-mode gfm-mode)
"[" nil :post-handlers '(:rem ("| " "SPC")))
;; Reasonable default pairs for HTML-style comments
(sp-local-pair (append sp--html-modes '(markdown-mode gfm-mode))
"<!--" "-->"
:unless '(sp-point-before-word-p sp-point-before-same-p)
:actions '(insert) :post-handlers '(("| " "SPC")))
;; Disable electric keys in C modes because it interferes with smartparens
;; and custom bindings. We'll do it ourselves (mostly).
(after! cc-mode
(c-toggle-electric-state -1)
(c-toggle-auto-newline -1)
(setq c-electric-flag nil)
(dolist (key '("#" "{" "}" "/" "*" ";" "," ":" "(" ")" "\177"))
(define-key c-mode-base-map key nil)))
;; Expand C-style doc comment blocks. Must be done manually because some of
;; these languages use specialized (and deferred) parsers, whose state we
;; can't access while smartparens is doing its thing.
(defun +default-expand-doc-comment-block (&rest _ignored)
(let ((indent (current-indentation)))
(newline-and-indent)
(save-excursion
(newline)
(insert (make-string indent 32) " */")
(delete-char 2))))
(sp-local-pair
'(js2-mode typescript-mode rjsx-mode rust-mode c-mode c++-mode objc-mode
csharp-mode java-mode php-mode css-mode scss-mode less-css-mode
stylus-mode)
"/*" "*/"
:actions '(insert)
:post-handlers '(("| " "SPC") ("|\n*/[i][d-2]" "RET") (+default-expand-doc-comment-block "*")))
;; Highjacks backspace to:
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
;; b) delete space-indented `tab-width' steps at a time
;; c) close empty multiline brace blocks in one step:
;; {
;; |
;; }
;; becomes {|}
;; d) refresh smartparens' :post-handlers, so SPC and RET expansions work
;; even after a backspace.
;; e) properly delete smartparen pairs when they are encountered, without
;; the need for strict mode.
;; f) do none of this when inside a string
(advice-add #'delete-backward-char :override #'+default*delete-backward-char)
;; Makes `newline-and-indent' continue comments (and more reliably)
(advice-add #'newline-and-indent :around #'+default*newline-indent-and-continue-comments)))
;;
;;; Keybindings
;; This section is dedicated to "fixing" certain keys so that they behave
;; sensibly (and consistently with similar contexts).
;; Make SPC u SPC u [...] possible (#747)
(map! :map universal-argument-map
:prefix doom-leader-key "u" #'universal-argument-more
:prefix doom-leader-alt-key "u" #'universal-argument-more)
(when (featurep! +bindings)
(load! "+evil-bindings"))

View file

@ -34,18 +34,6 @@
(defun +default/find-in-notes () (defun +default/find-in-notes ()
(interactive) (doom-project-find-file org-directory)) (interactive) (doom-project-find-file org-directory))
;;;###autoload
(defun +default/find-in-config ()
"Open a file somewhere in `doom-private-dir' via a fuzzy filename search."
(interactive)
(doom-project-find-file doom-private-dir))
;;;###autoload
(defun +default/browse-config ()
"Browse the files in `doom-private-dir'."
(interactive)
(doom-project-browse doom-private-dir))
;;;###autoload ;;;###autoload
(defun +default/compile (arg) (defun +default/compile (arg)
"Runs `compile' from the root of the current project. "Runs `compile' from the root of the current project.
@ -230,3 +218,34 @@ possible, or just one char if that's not possible."
((doom--backward-delete-whitespace-to-column))))))) ((doom--backward-delete-whitespace-to-column)))))))
;; Otherwise, do simple deletion. ;; Otherwise, do simple deletion.
((delete-char (- n) killflag)))) ((delete-char (- n) killflag))))
;;;###autoload
(defun +default/search-from-cwd (&optional arg)
"Conduct a text search in files under the current folder.
If prefix ARG is set, prompt for a directory to search from."
(interactive "P")
(let ((default-directory
(if arg
(read-directory-name "Switch to project: " default-directory)
default-directory)))
(call-interactively
(cond ((featurep! :completion ivy) #'+ivy/project-search-from-cwd)
((featurep! :completion helm) #'+helm/project-search-from-cwd)
(#'projectile-grep)))))
;;;###autoload
(defun +default/search-project (&optional arg)
"Conduct a text search in files under the project root.
If prefix ARG is set, prompt for a project to search from."
(interactive "P")
(let ((default-directory
(if arg
(if-let* ((projects (projectile-relevant-known-projects)))
(completing-read "Switch to project: " projects
nil t nil nil (doom-project-root))
(user-error "There are no known projects"))
default-directory)))
(call-interactively
(cond ((featurep! :completion ivy) #'+ivy/project-search)
((featurep! :completion helm) #'+helm/project-search)
(#'rgrep)))))

View file

@ -1,37 +0,0 @@
;; config/default/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :feature evil)
;;;###autoload (autoload '+default:multi-next-line "config/default/autoload/evil" nil t)
(evil-define-motion +default:multi-next-line (count)
"Move down 6 lines."
:type line
(let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode 'magit-mode))))
(evil-line-move (* 6 (or count 1)))))
;;;###autoload (autoload '+default:multi-previous-line "config/default/autoload/evil" nil t)
(evil-define-motion +default:multi-previous-line (count)
"Move up 6 lines."
:type line
(let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode 'magit-mode))))
(evil-line-move (- (* 6 (or count 1))))))
;;;###autoload (autoload '+default:cd "config/default/autoload/evil" nil t)
(evil-define-command +default:cd ()
"Change `default-directory' with `cd'."
(interactive "<f>")
(cd input))
;;;###autoload (autoload '+default:kill-all-buffers "config/default/autoload/evil" nil t)
(evil-define-command +default:kill-all-buffers (&optional bang)
"Kill all buffers. If BANG, kill current session too."
(interactive "<!>")
(if bang
(+workspace/kill-session)
(doom/kill-all-buffers)))
;;;###autoload (autoload '+default:kill-matching-buffers "config/default/autoload/evil" nil t)
(evil-define-command +default:kill-matching-buffers (&optional bang pattern)
"Kill all buffers matching PATTERN regexp. If BANG, only match project
buffers."
(interactive "<a>")
(doom/kill-matching-buffers pattern bang))

View file

@ -12,7 +12,7 @@
;; ;;
;; Reasonable defaults ;;; Reasonable defaults
(after! epa (after! epa
(setq epa-file-encrypt-to (setq epa-file-encrypt-to
@ -27,113 +27,12 @@
epa-pinentry-mode 'loopback)) epa-pinentry-mode 'loopback))
(when (featurep! +smartparens)
;; You can disable :unless predicates with (sp-pair "'" nil :unless nil)
;; And disable :post-handlers with (sp-pair "{" nil :post-handlers nil)
;; or specific :post-handlers with:
;; (sp-pair "{" nil :post-handlers '(:rem ("| " "SPC")))
(after! smartparens
;; Autopair quotes more conservatively; if I'm next to a word/before another
;; quote, I likely don't want to open a new pair.
(let ((unless-list '(sp-point-before-word-p
sp-point-after-word-p
sp-point-before-same-p)))
(sp-pair "'" nil :unless unless-list)
(sp-pair "\"" nil :unless unless-list))
;; Expand {|} => { | }
;; Expand {|} => {
;; |
;; }
(dolist (brace '("(" "{" "["))
(sp-pair brace nil
:post-handlers '(("||\n[i]" "RET") ("| " "SPC"))
;; I likely don't want a new pair if adjacent to a word or opening brace
:unless '(sp-point-before-word-p sp-point-before-same-p)))
;; Major-mode specific fixes
(sp-local-pair '(ruby-mode enh-ruby-mode) "{" "}"
:pre-handlers '(:rem sp-ruby-pre-handler)
:post-handlers '(:rem sp-ruby-post-handler))
;; Don't do square-bracket space-expansion where it doesn't make sense to
(sp-local-pair '(emacs-lisp-mode org-mode markdown-mode gfm-mode)
"[" nil :post-handlers '(:rem ("| " "SPC")))
;; Reasonable default pairs for HTML-style comments
(sp-local-pair (append sp--html-modes '(markdown-mode gfm-mode))
"<!--" "-->" :actions '(insert) :post-handlers '(("| " "SPC")))
;; Disable electric keys in C modes because it interferes with smartparens
;; and custom bindings. We'll do it ourselves (mostly).
(after! cc-mode
(c-toggle-electric-state -1)
(c-toggle-auto-newline -1)
(setq c-tab-always-indent nil
c-electric-flag nil)
(dolist (key '("#" "{" "}" "/" "*" ";" "," ":" "(" ")" "\177"))
(define-key c-mode-base-map key nil)))
;; Expand C-style doc comment blocks. Must be done manually because some of
;; these languages use specialized (and deferred) parsers, whose state we
;; can't access while smartparens is doing its thing.
(defun +default-expand-doc-comment-block (&rest _ignored)
(let ((indent (current-indentation)))
(newline-and-indent)
(save-excursion
(newline)
(insert (make-string indent 32) " */")
(delete-char 2))))
(sp-local-pair
'(js2-mode typescript-mode rjsx-mode rust-mode c-mode c++-mode objc-mode
csharp-mode java-mode php-mode css-mode scss-mode less-css-mode
stylus-mode)
"/*" "*/"
:actions '(insert)
:post-handlers '(("| " "SPC") ("|\n*/[i][d-2]" "RET") (+default-expand-doc-comment-block "*")))
;; Highjacks backspace to:
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
;; b) delete space-indented `tab-width' steps at a time
;; c) close empty multiline brace blocks in one step:
;; {
;; |
;; }
;; becomes {|}
;; d) refresh smartparens' :post-handlers, so SPC and RET expansions work
;; even after a backspace.
;; e) properly delete smartparen pairs when they are encountered, without
;; the need for strict mode.
;; f) do none of this when inside a string
(advice-add #'delete-backward-char :override #'+default*delete-backward-char)
;; Makes `newline-and-indent' continue comments (and more reliably)
(advice-add #'newline-and-indent :around #'+default*newline-indent-and-continue-comments)))
;; ;;
;; Keybinding fixes ;;; Keybinding fixes
;; This section is dedicated to "fixing" certain keys so that they behave ;; This section is dedicated to "fixing" certain keys so that they behave
;; sensibly (and consistently with similar contexts). ;; sensibly (and consistently with similar contexts).
;; Make SPC u SPC u [...] possible (#747)
(map! :map universal-argument-map
:prefix doom-leader-key "u" #'universal-argument-more
:prefix doom-leader-alt-key "u" #'universal-argument-more)
(defun +default|setup-input-decode-map ()
"Ensure TAB and [tab] are treated the same in TTY Emacs."
(define-key input-decode-map (kbd "TAB") [tab]))
(add-hook 'tty-setup-hook #'+default|setup-input-decode-map)
;; A Doom convention where C-s on popups and interactive searches will invoke
;; ivy/helm for their superior filtering.
(define-key! :keymaps +default-minibuffer-maps
"C-s" (if (featurep! :completion ivy)
#'counsel-minibuffer-history
#'helm-minibuffer-history))
;; Consistently use q to quit windows ;; Consistently use q to quit windows
(after! tabulated-list (after! tabulated-list
(define-key tabulated-list-mode-map "q" #'quit-window)) (define-key tabulated-list-mode-map "q" #'quit-window))
@ -171,7 +70,7 @@
:n "s-/" #'evil-commentary-line :n "s-/" #'evil-commentary-line
:v "s-/" #'evil-commentary :v "s-/" #'evil-commentary
:gni [s-return] #'+default/newline-below :gni [s-return] #'+default/newline-below
:gni [s-S-return] #'+default/newline-above :gni [S-s-return] #'+default/newline-above
:gi [s-backspace] #'doom/backward-kill-to-bol-and-indent :gi [s-backspace] #'doom/backward-kill-to-bol-and-indent
:gi [s-left] #'doom/backward-to-bol-or-indent :gi [s-left] #'doom/backward-to-bol-or-indent
:gi [s-right] #'doom/forward-to-last-non-comment-or-eol :gi [s-right] #'doom/forward-to-last-non-comment-or-eol
@ -181,7 +80,48 @@
;; ;;
;; Doom's keybinding scheme ;;; Keybind schemes
;; Custom help keys -- these aren't under `+bindings' because they ought to be
;; universal.
(map! :map help-map
"'" #'describe-char
"a" #'apropos ; replaces `apropos-command'
"A" #'doom/describe-autodefs
"B" #'doom/open-bug-report
"C-c" #'describe-coding-system ; replaces `describe-copying' b/c not useful
"d" #'doom/describe-module ; replaces `apropos-documentation' b/c `apropos' covers this
"D" #'doom/open-manual
"E" #'doom/open-vanilla-sandbox
"F" #'describe-face ; replaces `Info-got-emacs-command-node' b/c redundant w/ `Info-goto-node'
"h" #'doom/describe-symbol ; replaces `view-hello-file' b/c annoying
"C-k" #'describe-key-briefly
"L" #'global-command-log-mode ; replaces `describe-language-environment' b/c remapped to C-l
"C-l" #'describe-language-environment
"M" #'doom/describe-active-minor-mode
"C-m" #'info-emacs-manual
"n" #'doom/open-news ; replaces `view-emacs-news' b/c it's on C-n too
"O" #'+lookup/online
"p" #'doom/describe-package ; replaces `finder-by-keyword'
"P" #'find-library ; replaces `describe-package' b/c redundant w/ `doom/describe-package'
"r" nil ; replaces `info-emacs-manual' b/c it's on C-m now
(:prefix "r"
"r" #'doom/reload
"t" #'doom/reload-theme
"p" #'doom/reload-packages
"f" #'doom/reload-font
"P" #'doom/reload-project)
"T" #'doom/toggle-profiler
"V" #'set-variable
"C-v" #'doom/version
"W" #'+default/man-or-woman)
(after! which-key
(which-key-add-key-based-replacements "C-h r" "reload")
(when (featurep 'evil)
(which-key-add-key-based-replacements (concat doom-leader-key " r") "reload")
(which-key-add-key-based-replacements (concat doom-leader-alt-key " r") "reload")))
(when (featurep! +bindings) (when (featurep! +bindings)
;; Make M-x harder to miss ;; Make M-x harder to miss
@ -189,6 +129,13 @@
"M-x" #'execute-extended-command "M-x" #'execute-extended-command
"A-x" #'execute-extended-command) "A-x" #'execute-extended-command)
;; A Doom convention where C-s on popups and interactive searches will invoke
;; ivy/helm for their superior filtering.
(define-key! :keymaps +default-minibuffer-maps
"C-s" (if (featurep! :completion ivy)
#'counsel-minibuffer-history
#'helm-minibuffer-history))
;; Smarter C-a/C-e for both Emacs and Evil. C-a will jump to indentation. ;; Smarter C-a/C-e for both Emacs and Evil. C-a will jump to indentation.
;; Pressing it again will send you to the true bol. Same goes for C-e, except ;; Pressing it again will send you to the true bol. Same goes for C-e, except
;; it will ignore comments+trailing whitespace before jumping to eol. ;; it will ignore comments+trailing whitespace before jumping to eol.
@ -199,8 +146,12 @@
:gni [M-return] #'+default/newline-below :gni [M-return] #'+default/newline-below
:gni [M-S-return] #'+default/newline-above :gni [M-S-return] #'+default/newline-above
:gni [C-return] #'+default/newline-below :gni [C-return] #'+default/newline-below
:gni [C-S-return] #'+default/newline-above) :gni [C-S-return] #'+default/newline-above))
(if (featurep 'evil)
(load! "+evil-bindings") ;;
(load! "+emacs-bindings"))) ;;; Bootstrap configs
(if (featurep 'evil)
(load! "+evil")
(load! "+emacs"))

View file

@ -0,0 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; config/default/packages.el
(unless (featurep! :feature evil)
(package! winum)
(package! expand-region))

View file

@ -45,11 +45,11 @@ Targets `vimmish-fold', `hideshow' and `outline' folds."
(interactive) (interactive)
(save-excursion (save-excursion
(cond ((+fold--vimish-fold-p) (vimish-fold-toggle)) (cond ((+fold--vimish-fold-p) (vimish-fold-toggle))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-toggle-hiding)))
((+fold--outline-fold-p) ((+fold--outline-fold-p)
(cl-letf (((symbol-function #'outline-hide-subtree) (cl-letf (((symbol-function #'outline-hide-subtree)
(symbol-function #'outline-hide-entry))) (symbol-function #'outline-hide-entry)))
(outline-toggle-children)))))) (outline-toggle-children)))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-toggle-hiding))))))
;;;###autoload ;;;###autoload
(defun +fold/open () (defun +fold/open ()
@ -59,10 +59,10 @@ Targets `vimmish-fold', `hideshow' and `outline' folds."
(interactive) (interactive)
(save-excursion (save-excursion
(cond ((+fold--vimish-fold-p) (vimish-fold-unfold)) (cond ((+fold--vimish-fold-p) (vimish-fold-unfold))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block)))
((+fold--outline-fold-p) ((+fold--outline-fold-p)
(outline-show-children) (outline-show-children)
(outline-show-entry))))) (outline-show-entry))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block))))))
;;;###autoload ;;;###autoload
(defun +fold/close () (defun +fold/close ()

View file

@ -34,16 +34,14 @@
(insert input) (insert input)
(condition-case e (condition-case e
(progn (progn
(when doom-debug-mode (doom-log "formatter (commandp) %s" #',formatter)
(message "formatter (commandp) %s" #',formatter))
(call-interactively #',formatter) (call-interactively #',formatter)
(list nil "")) (list nil ""))
(error (list t (error-message-string e)))))))) (error (list t (error-message-string e))))))))
(defun +format--make-function (formatter &rest _) (defun +format--make-function (formatter &rest _)
`(progn `(progn
(when doom-debug-mode (doom-log "formatter (functionp) %s" #',formatter)
(message "formatter (functionp) %s" #',formatter))
(format-all-buffer-thunk #',formatter))) (format-all-buffer-thunk #',formatter)))
(defun +format--make-shell-command (command ok-statuses error-regexp) (defun +format--make-shell-command (command ok-statuses error-regexp)
@ -66,8 +64,7 @@
((stringp this) ((stringp this)
(push this subargs)))) (push this subargs))))
(setq args (append subargs args))))))) (setq args (append subargs args)))))))
(when doom-debug-mode (doom-log "formatter (arglist) %s" args)
(message "formatter (arglist) %s" args))
(if ,(and (or ok-statuses error-regexp) t) (if ,(and (or ok-statuses error-regexp) t)
(apply #'format-all-buffer-hard (apply #'format-all-buffer-hard
',ok-statuses ,error-regexp ',ok-statuses ,error-regexp

View file

@ -17,6 +17,7 @@
(defvar evil-mc-key-map (make-sparse-keymap)) (defvar evil-mc-key-map (make-sparse-keymap))
:config :config
(global-evil-mc-mode +1) (global-evil-mc-mode +1)
(setq evil-mc-enable-bar-cursor (not (or IS-MAC IS-WINDOWS)))
(after! smartparens (after! smartparens
;; Make evil-mc cooperate with smartparens better ;; Make evil-mc cooperate with smartparens better
@ -56,7 +57,7 @@
:evil-mc t)) :evil-mc t))
(after! multiple-cursors (after! multiple-cursors-core
(setq mc/list-file (concat doom-etc-dir "mc-lists.el")) (setq mc/list-file (concat doom-etc-dir "mc-lists.el"))
;; TODO multiple-cursors config for Emacs users? ;; TODO multiple-cursors config for Emacs users?

View file

@ -17,17 +17,18 @@
image-dired-temp-image-file (concat image-dired-dir "temp-image") image-dired-temp-image-file (concat image-dired-dir "temp-image")
image-dired-temp-rotate-image-file (concat image-dired-dir "temp-rotate-image")) image-dired-temp-rotate-image-file (concat image-dired-dir "temp-rotate-image"))
:config :config
(setq dired-listing-switches "-aBhl --group-directories-first") (let ((args (list "-aBhl" "--group-directories-first")))
(when IS-BSD
(when IS-BSD ;; Use GNU ls as `gls' from `coreutils' if available. Add `(setq
;; Use GNU ls as `gls' from `coreutils' if available. Add `(setq ;; dired-use-ls-dired nil)' to your config to suppress the Dired warning
;; dired-use-ls-dired nil)' to your config to suppress the Dired warning ;; when not using GNU ls. We must look for `gls' after
;; when not using GNU ls. We must look for `gls' after ;; `exec-path-from-shell' was initialized to make sure that `gls' is in
;; `exec-path-from-shell' was initialized to make sure that `gls' is in ;; `exec-path'
;; `exec-path' (if-let* ((gls (executable-find "gls")))
(if-let* ((gls (executable-find "gls"))) (setq insert-directory-program gls)
(setq insert-directory-program gls) (setq args (delete "--group-directories-first" args))
(message "Cannot find `gls` (GNU ls). Install coreutils via your system package manager"))) (message "Cannot find `gls` (GNU ls). Install coreutils via your system package manager")))
(setq dired-listing-switches (string-join args " ")))
(defun +dired|sort-directories-first () (defun +dired|sort-directories-first ()
"List directories first in dired buffers." "List directories first in dired buffers."
@ -91,6 +92,7 @@
ranger-excluded-extensions '("mkv" "iso" "mp4") ranger-excluded-extensions '("mkv" "iso" "mp4")
ranger-deer-show-details nil ranger-deer-show-details nil
ranger-max-preview-size 10 ranger-max-preview-size 10
ranger-show-literal nil
dired-omit-verbose nil)) dired-omit-verbose nil))

View file

@ -17,8 +17,10 @@ Enables `electric-indent-local-mode' in MODES.
(unintern fn nil)) (unintern fn nil))
((fset fn ((fset fn
(lambda () (lambda ()
(cl-destructuring-bind (&key chars words) plist (when (eq major-mode mode)
(electric-indent-local-mode +1) (setq-local electric-indent-inhibit nil)
(if chars (setq electric-indent-chars chars)) (cl-destructuring-bind (&key chars words) plist
(if words (setq +electric-indent-words words))))) (electric-indent-local-mode +1)
(if chars (setq electric-indent-chars chars))
(if words (setq +electric-indent-words words))))))
(add-hook hook fn)))))) (add-hook hook fn))))))

View file

@ -107,7 +107,7 @@ You should use `det-eshell-alias!' to change this.")
;; Visual commands require a proper terminal. Eshell can't handle that, so ;; Visual commands require a proper terminal. Eshell can't handle that, so
;; it delegates these commands to a term buffer. ;; it delegates these commands to a term buffer.
(after! em-term (after! em-term
(dolist (cmd '("tmux" "htop" "bash" "zsh" "fish" "vim" "nvim" "ncmpcpp")) (dolist (cmd '("tmux" "htop" "vim" "nvim" "ncmpcpp"))
(add-to-list 'eshell-visual-commands cmd))) (add-to-list 'eshell-visual-commands cmd)))
(defun +eshell|init-aliases () (defun +eshell|init-aliases ()

View file

@ -17,6 +17,14 @@
(funcall runner beg end) (funcall runner beg end)
(quickrun-region beg end)))) (quickrun-region beg end))))
;;;###autoload
(defun +eval/line-or-region ()
"Evaluate the current line or selected region."
(interactive)
(if (use-region-p)
(call-interactively #'+eval/region)
(+eval/region (line-beginning-position) (line-end-position))))
;;;###autoload ;;;###autoload
(defun +eval/buffer-or-region () (defun +eval/buffer-or-region ()
"Evaluate the whole buffer." "Evaluate the whole buffer."

View file

@ -1,9 +1,5 @@
;;; feature/evil/+commands.el -*- lexical-binding: t; -*- ;;; feature/evil/+commands.el -*- lexical-binding: t; -*-
(evil-define-command +evil:cleanup-session (bang)
(interactive "<!>")
(doom/cleanup-session bang))
(evil-define-operator +evil:open-scratch-buffer (bang) (evil-define-operator +evil:open-scratch-buffer (bang)
(interactive "<!>") (interactive "<!>")
(doom/open-scratch-buffer bang)) (doom/open-scratch-buffer bang))
@ -46,14 +42,30 @@ This command understands vim file modifiers (like %:p:h). See
(interactive "<r>") (interactive "<r>")
(reverse-region beg end)) (reverse-region beg end))
(evil-define-command +evil:cd (&optional path)
"Change `default-directory' with `cd'."
(interactive "<f>")
(let ((path (or path "~")))
(cd path)
(message "Changed directory to '%s'" (abbreviate-file-name (expand-file-name path)))))
(evil-define-command +evil:kill-all-buffers (&optional bang)
"Kill all buffers. If BANG, kill current session too."
(interactive "<!>")
(if (and bang (fboundp '+workspace/kill-session))
(+workspace/kill-session)
(doom/kill-all-buffers)))
(evil-define-command +evil:kill-matching-buffers (&optional bang pattern)
"Kill all buffers matching PATTERN regexp. If BANG, only match project
buffers."
(interactive "<a>")
(doom/kill-matching-buffers pattern bang))
;; ;;
;; Commands ;; Commands
;;; these are defined in feature/evil
;;(evil-ex-define-cmd "al[ign]" #'+evil:align)
;;(evil-ex-define-cmd "g[lobal]" #'+evil:global)
;;; Custom commands ;;; Custom commands
;; Editing ;; Editing
(evil-ex-define-cmd "@" #'+evil:macro-on-all-lines) ; TODO Test me (evil-ex-define-cmd "@" #'+evil:macro-on-all-lines) ; TODO Test me
@ -94,18 +106,18 @@ This command understands vim file modifiers (like %:p:h). See
(evil-ex-define-cmd "grevert" #'git-gutter:revert-hunk) (evil-ex-define-cmd "grevert" #'git-gutter:revert-hunk)
;;; Dealing with buffers ;;; Dealing with buffers
(evil-ex-define-cmd "clean[up]" #'+evil:cleanup-session)
(evil-ex-define-cmd "k[ill]" #'doom/kill-this-buffer) (evil-ex-define-cmd "k[ill]" #'doom/kill-this-buffer)
(evil-ex-define-cmd "k[ill]all" #'+default:kill-all-buffers) (evil-ex-define-cmd "k[ill]all" #'+evil:kill-all-buffers)
(evil-ex-define-cmd "k[ill]m" #'+default:kill-matching-buffers) (evil-ex-define-cmd "k[ill]m" #'+evil:kill-matching-buffers)
(evil-ex-define-cmd "k[ill]o" #'doom/kill-other-buffers) (evil-ex-define-cmd "k[ill]o" #'doom/kill-other-buffers)
(evil-ex-define-cmd "k[ill]b" #'doom/kill-buried-buffers)
(evil-ex-define-cmd "l[ast]" #'doom/popup-restore) (evil-ex-define-cmd "l[ast]" #'doom/popup-restore)
(evil-ex-define-cmd "m[sg]" #'view-echo-area-messages) (evil-ex-define-cmd "m[sg]" #'view-echo-area-messages)
(evil-ex-define-cmd "pop[up]" #'doom/popup-this-buffer) (evil-ex-define-cmd "pop[up]" #'doom/popup-this-buffer)
;;; Project navigation ;;; Project navigation
(evil-ex-define-cmd "a" #'projectile-find-other-file) (evil-ex-define-cmd "a" #'projectile-find-other-file)
(evil-ex-define-cmd "cd" #'+default:cd) (evil-ex-define-cmd "cd" #'+evil:cd)
(evil-ex-define-cmd "pwd" #'+evil:pwd) (evil-ex-define-cmd "pwd" #'+evil:pwd)
(cond ((featurep! :completion ivy) (cond ((featurep! :completion ivy)
@ -135,7 +147,7 @@ This command understands vim file modifiers (like %:p:h). See
;;; Project tools ;;; Project tools
(evil-ex-define-cmd "compile" #'+evil:compile) (evil-ex-define-cmd "compile" #'+evil:compile)
(evil-ex-define-cmd "mak[e]" #'+evil:make) (evil-ex-define-cmd "mak[e]" #'+evil:make)
(evil-ex-define-cmd "debug" #'+debug/run) ;; (evil-ex-define-cmd "debug" #'+debug/run)
(evil-ex-define-cmd "er[rors]" #'flycheck-list-errors) (evil-ex-define-cmd "er[rors]" #'flycheck-list-errors)
;;; File operations ;;; File operations
@ -145,8 +157,8 @@ This command understands vim file modifiers (like %:p:h). See
;;; Sessions/tabs ;;; Sessions/tabs
(evil-ex-define-cmd "sclear" #'+workspace/kill-session) (evil-ex-define-cmd "sclear" #'+workspace/kill-session)
(evil-ex-define-cmd "sl[oad]" #'+workspace:load-session) (evil-ex-define-cmd "sl[oad]" #'doom/quickload-session)
(evil-ex-define-cmd "ss[ave]" #'+workspace:save-session) (evil-ex-define-cmd "ss[ave]" #'doom/quicksave-session)
(evil-ex-define-cmd "tabc[lose]" #'+workspace:delete) (evil-ex-define-cmd "tabc[lose]" #'+workspace:delete)
(evil-ex-define-cmd "tabclear" #'doom/kill-all-buffers) (evil-ex-define-cmd "tabclear" #'doom/kill-all-buffers)
(evil-ex-define-cmd "tabl[ast]" #'+workspace/switch-to-last) (evil-ex-define-cmd "tabl[ast]" #'+workspace/switch-to-last)

View file

@ -163,8 +163,7 @@ variable for an explanation of the defaults (in comments). See
(defun +evil-collection-init (module) (defun +evil-collection-init (module)
(unless (memq (or (car-safe module) module) +evil-collection-disabled-list) (unless (memq (or (car-safe module) module) +evil-collection-disabled-list)
(when doom-debug-mode (doom-log "Initialized evil-collection-%s" (or (car-safe module) module))
(message "Loaded evil-collection-%s" (or (car-safe module) module)))
(with-demoted-errors "evil-collection error: %s" (with-demoted-errors "evil-collection error: %s"
(evil-collection-init (list module))))) (evil-collection-init (list module)))))
@ -195,6 +194,10 @@ variable for an explanation of the defaults (in comments). See
"]l" #'forward-button "]l" #'forward-button
"[l" #'backward-button)) "[l" #'backward-button))
(evil-define-key* 'normal process-menu-mode-map
"q" #'kill-this-buffer
"d" #'process-menu-delete-process)
;; Load the rest ;; Load the rest
(dolist (mode evil-collection-mode-list) (dolist (mode evil-collection-mode-list)
(dolist (req (or (cdr-safe mode) (list mode))) (dolist (req (or (cdr-safe mode) (list mode)))

View file

@ -4,26 +4,25 @@
#+STARTUP: inlineimages #+STARTUP: inlineimages
* Table of Contents :TOC_3:noexport: * Table of Contents :TOC_3:noexport:
- [[Description][Description]] - [[#description][Description]]
- [[Module Flags][Module Flags]] - [[#module-flags][Module Flags]]
- [[Plugins][Plugins]] - [[#plugins][Plugins]]
- [[Hacks][Hacks]] - [[#hacks][Hacks]]
- [[Prerequisites][Prerequisites]] - [[#prerequisites][Prerequisites]]
- [[Features][Features]] - [[#features][Features]]
- [[Ported vim plugins][Ported vim plugins]] - [[#ported-vim-plugins][Ported vim plugins]]
- [[Custom Text Objects][Custom Text Objects]] - [[#custom-text-objects][Custom Text Objects]]
- [[Custom Ex Commands][Custom Ex Commands]] - [[#custom-ex-commands][Custom Ex Commands]]
- [[A hybrid code-folding system][A hybrid code-folding system]] - [[#configuration][Configuration]]
- [[Differences from vim][Differences from vim]] - [[#removing-evil-mode][Removing evil-mode]]
- [[Configuration][Configuration]] - [[#restoring-old-substitution-behavior-on-ss][Restoring old substitution behavior on s/S]]
- [[Removing evil-mode][Removing evil-mode]]
* Description * Description
This holy module brings the vim experience to Emacs. This holy module brings the vim experience to Emacs.
** Module Flags ** Module Flags
+ =+everywhere= Enables evilified keybinds everywhere possible, utilizing the + =+everywhere= Enables evilified keybinds everywhere possible. Uses the
~evil-collection~ plugin. [[https://github.com/emacs-evil/evil-collection][evil-collection]] plugin as a foundation.
** Plugins ** Plugins
+ [[https://github.com/emacs-evil/evil][evil]] + [[https://github.com/emacs-evil/evil][evil]]
@ -48,10 +47,9 @@ This holy module brings the vim experience to Emacs.
+ When a window is split, the new window will be focused. + When a window is split, the new window will be focused.
+ The o/O keys will respect and continue commented lines (can be disabled by + The o/O keys will respect and continue commented lines (can be disabled by
setting ~+evil-want-o/O-to-continue-comments~ to ~nil~). setting ~+evil-want-o/O-to-continue-comments~ to ~nil~).
+ From visual mode, =*= and =#= will search for the current selection instead of + In visual mode, =*= and =#= will search for the current selection instead of
the word-at-point. the word-at-point.
+ The ~:g[lobal]~ ex command has been modified to highlight matches + The ~:g[lobal]~ ex command has been modified to highlight matches.
incrementally.
+ More of vim's filename modifiers are supported in ex commands (like ~:p~, + More of vim's filename modifiers are supported in ex commands (like ~:p~,
~:p:h~ or ~:t~) than vanilla evil-mode offers. ~:p:h~ or ~:t~) than vanilla evil-mode offers.
+ A custom filename modifier is available in Doom: ~:P~, which expands to the + A custom filename modifier is available in Doom: ~:P~, which expands to the
@ -64,64 +62,115 @@ This module has no external prerequisites.
** Ported vim plugins ** Ported vim plugins
The following vim plugins have been ported to evil: The following vim plugins have been ported to evil:
| Vim Plugin | Emacs Plugin | Keybind(s) | | Vim Plugin | Emacs Plugin | Keybind(s) |
|-----------------------+--------------------------------+---------------------| |-----------------------+--------------------------------+--------------------------------------|
| vim-commentary | evil-commentary | omap =gc= | | vim-commentary | evil-commentary | omap =gc= |
| vim-easymotion | evil-easymotion | omap =gs= | | vim-easymotion | evil-easymotion | omap =gs= |
| vim-seek or vim-sneak | evil-snipe | mmap =s=/=S= | | vim-seek or vim-sneak | evil-snipe | mmap =s=/=S=, omap =z=/=Z= & =x=/=x= |
| vim-surround | evil-embrace and evil-surround | vmap =S=, omap =ys= | | vim-surround | evil-embrace and evil-surround | vmap =S=, omap =ys= |
In other modules: In other modules:
+ The tools/neotree & tools/treemacs modules contain a =NERDTree= equivalent. + The tools/neotree & tools/treemacs modules provide a =NERDTree= equivalent.
+ The editor/multiple-cursors module contains: + The editor/multiple-cursors module contains functionality equal to the
+ ~vim-multiedit~ => evil-multiedit following vim plugins:
+ ~vim-multiple-cursors~ => evil-mc + evil-multiedit => vim-multiedit
+ evil-mc => vim-multiple-cursors
** Custom Text Objects ** Custom Text Objects
+ A list of new text objects: This module provides a couple extra text objects, along with the built-in ones.
+ Blocks: ~B~ (from ~evil-textobj-anyblock~) For posterity, here are the built-in ones:
+ Args: ~a~ (from ~evil-args~)
+ Indentation: ~i~ / ~I~ / ~J~ (from ~evil-indent-plus~) + =w W= words
+ =s= sentences
+ =p= paragraphs
+ =b= parenthesized blocks
+ =b ( ) { } [ ] < >= braces, parentheses and brackets
+ =' " `= quotes
+ =t= tags
+ =o= symbols
And these are text objects added by this module:
+ =B= any block delimited by braces, parentheses or backets (provided by
~evil-textobj-anyblock~)
+ =a= C-style fucntion arguments (provided by ~evil-args~)
+ =i I J= By indentation (I includes on line above and J includes one line
below) (provided by ~evil-indent-plus~)
+ =x= XML attributes (provided by ~exato~)
** Custom Ex Commands ** Custom Ex Commands
| Ex Command | Description | | Ex Command | Description |
|----------------------+----------------------------------------------------------------------------------| |----------------------+--------------------------------------------------------------------------------------|
| ~:al[ign][!] REGEXP~ | Align text to the first match of REGEXP. If BANG, align all matches on each line | | ~:@~ | Apply macro on selected lines |
| ~:mv[!] NEWPATH~ | Move the current file to NEWPATH | | ~:ag[!] REGEXP~ | Perform a project search with ag |
| ~:cp[!] NEWPATH~ | Copy the current file to NEWPATH | | ~:agcwd[!] REGEXP~ | Perform a project search with ag |
| ~:rm[!] [PATH]~ | Delete the current buffer's file and buffer | | ~:al[ign] REGEXP~ | Align text that matches REGEXP |
| ~:al[ign][!] REGEXP~ | Align text to the first match of REGEXP. If BANG, align all matches on each line |
** A hybrid code-folding system | ~:cp[!] NEWPATH~ | Copy the current file to NEWPATH |
This module combines ~vimish-fold~ and ~hideshow~. The former allows arbitrary | ~:dash QUERY~ | Look up QUERY (or the symbol at point) in dash docsets |
folds and the latter allows folds on markers and indentation. Together, they | ~:dehtml [INPUT]~ | HTML decode selected text / inserts result if INPUT is given |
create a more consistent (and feature-complete) code-folding system. | ~:enhtml [INPUT]~ | HTML encode selected text / inserts result if INPUT is given |
| ~:grep[!]~ | Perform a project search with git-grep |
Most vim folding keys should work, e.g. =zr=, =zm=, =za=, =zo=, etc. | ~:grepcwd[!]~ | Perform a project search with git-grep |
| ~:iedit REGEXP~ | Invoke iedit on all matches for REGEXP |
** Differences from vim | ~:k[ill]all[!]~ | Kill all buffers (if BANG, affect buffer across workspaces) |
+ Column-wise ranges in ex commands are enabled by default. i.e. the range in | ~:k[ill]b~ | Kill all buried buffers |
=:'<,'>s/a/b= will only affects the visual selection, not full lines (see | ~:k[ill]m[!] REGEXP~ | Kill buffers whose name matches REGEXP (if BANG, affect buffers across workspaces) |
~evil-ex-visual-char-range~). | ~:k[ill]o~ | Kill all other buffers besides the selected one |
+ =:g= will incrementally highlight buffer matches. | ~:k[ill]~ | Kill the current buffer |
| ~:lo[okup] QUERY~ | Look up QUERY on an online search engine |
| ~:mc REGEXP~ | Invoke multiple cursors on all matches for REGEXP |
| ~:mv[!] NEWPATH~ | Move the current file to NEWPATH |
| ~:na[rrow]~ | Narrow the buffer to the selection |
| ~:pad~ | Open a scratch pad for running code quickly |
| ~:pt[!]~ | Perform a project search with pt |
| ~:ptcwd[!]~ | Perform a project search with pt |
| ~:ral[ign] REGEXP~ | Right-align text that matches REGEXP |
| ~:repl~ | Open a REPL and/or copy the current selection to it |
| ~:retab~ | Convert indentation to the default within the selection |
| ~:rev[erse]~ | Reverse the selected lines |
| ~:rg[!]~ | Perform a project search with ripgrep |
| ~:rgcwd[!]~ | Perform a project search with rigprep |
| ~:rm[!] [PATH]~ | Delete the current buffer's file and buffer |
| ~:tcd[!]~ | Send =cd X= to tmux. X = the project root if BANG, X = ~default-directory~ otherwise |
* Configuration * Configuration
** Removing evil-mode ** Removing evil-mode
You must do two things to remove Evil: You must do two things to remove Evil:
1. Remove =:feature evil= from =~/.doom.d/init.el=, 1. Remove =:feature evil= from =~/.doom.d/init.el=,
2. Run ~bin/doom refresh~ to clean up lingering dependencies and refresh yuor 2. Run ~doom refresh~ to clean up lingering dependencies and refresh yuor
autoloads files. autoloads files.
3. [OPTIONAL] You may want a new ~doom-leader-alt-key~ and 3. [OPTIONAL] You may want to assign new values to ~doom-leader-alt-key~ and
~doom-localleader-alt-key~. By default, these are bound to =M-SPC= and =M-SPC ~doom-localleader-alt-key~. These are bound to =C-c= and =C-c l= by default.
m=.
#+begin_quote #+begin_quote
Ignore ~doom-leader-key~ and ~doom-localleader-key~, they don't apply to Ignore ~doom-leader-key~ and ~doom-localleader-key~, they don't apply to
non-evil sessions. non-evil sessions.
#+end_quote #+end_quote
Note that evil-specific configuration and keybinds (defined with ~map!~) will be Evil-specific configuration and keybindings (defined with ~map!~) will be
ignored without evil present (and stripped out when byte-compiling). ignored without =:feature evil= present (and omitted when byte-compiling).
Unfortunately, since Doom was designed by a vimmer, for vimmers, little Keep in mind that, at the time of this writing, Doom was designed by a vimmer,
consideration into a keybinding scheme for vanilla Emacs users. for vimmers. Little consideration has been put into designing a keybind scheme
for vanilla Emacs users (though it's being worked on!).
That means that much of Doom's functionality will be orphaned in an evil-less
setup. You'll have to set your own keybinds.
I suggest studying [[file:../../config/default/+emacs-bindings.el][config/default/+emacs-bindings.el]] to see what keybinds are
available for non-evil users. Otherwise, you may find inspiration [[file:../../../docs/example_configs.org][on the example
Doom configurations page]].
** Restoring old substitution behavior on s/S
Doom replaces the =s= and =S= keys with the =evil-snipe= package (a port of
vim-seek/vim-sneak for 2-character versions of f/F/t/T).
To disable evil-snipe on s/S, you can either:
1. Disable ~evil-snipe-mode~ by adding ~(after! evil-snipe (evil-snipe-mode
-1))~ to =$DOOMDIR/config.el=,
2. Or disable =evil-snipe= completely with ~(package! evil-snipe :disable t)~
added to =$DOOMDIR/packages.el=, but this will also disable incremental
highlighting for the f/F/t/T motions keys.

View file

@ -185,3 +185,23 @@ more information on modifiers."
"Call `doom/escape' if `evil-force-normal-state' is called interactively." "Call `doom/escape' if `evil-force-normal-state' is called interactively."
(when (called-interactively-p 'any) (when (called-interactively-p 'any)
(call-interactively #'doom/escape))) (call-interactively #'doom/escape)))
;;;###autoload
(defun +evil*make-numbered-markers-global (orig-fn char)
(or (and (>= char ?2) (<= char ?9))
(funcall orig-fn char)))
;;;###autoload
(defun +evil*set-jump (orig-fn &rest args)
"Set a jump point and ensure ORIG-FN doesn't set any new jump points."
(evil-set-jump (if (markerp (car args)) (car args)))
(let ((evil--jumps-jumping t))
(apply orig-fn args)))
;;;###autoload
(defun +evil*fix-dabbrev-in-minibuffer ()
"Make `try-expand-dabbrev' from `hippie-expand' work in minibuffer. See
`he-dabbrev-beg', so we need to redefine syntax for '/'."
(set-syntax-table (let* ((table (make-syntax-table)))
(modify-syntax-entry ?/ "." table)
table)))

View file

@ -0,0 +1,33 @@
;;; feature/evil/autoload/embrace.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +evil--embrace-get-pair (char)
(if-let* ((pair (cdr-safe (assoc (string-to-char char) evil-surround-pairs-alist))))
pair
(if-let* ((pair (assoc-default char embrace--pairs-list)))
(if-let* ((real-pair (and (functionp (embrace-pair-struct-read-function pair))
(funcall (embrace-pair-struct-read-function pair)))))
real-pair
(cons (embrace-pair-struct-left pair) (embrace-pair-struct-right pair)))
(cons char char))))
;;;###autoload
(defun +evil--embrace-escaped ()
"Backslash-escaped surround character support for embrace."
(let ((char (read-char "\\")))
(if (eq char 27)
(cons "" "")
(let ((pair (+evil--embrace-get-pair (string char)))
(text (if (sp-point-in-string) "\\\\%s" "\\%s")))
(cons (format text (car pair))
(format text (cdr pair)))))))
;;;###autoload
(defun +evil--embrace-latex ()
"LaTeX command support for embrace."
(cons (format "\\%s{" (read-string "\\")) "}"))
;;;###autoload
(defun +evil--embrace-elisp-fn ()
"Elisp function support for embrace."
(cons (format "(%s " (or (read-string "(") "")) ")"))

View file

@ -13,7 +13,7 @@
;; ;;
;; Commands ;;; Commands
;;;###autoload ;;;###autoload
(defun +evil/visual-indent () (defun +evil/visual-indent ()
@ -50,10 +50,10 @@
(call-interactively #'evil-paste-after))) (call-interactively #'evil-paste-after)))
(defun +evil--window-swap (direction) (defun +evil--window-swap (direction)
"Move current window to the next window in DIRECTION. If there are no windows "Move current window to the next window in DIRECTION.
there and there is only one window, split in that direction and place this If there are no windows there and there is only one window, split in that
window there. If there are no windows and this isn't the only window, use direction and place this window there. If there are no windows and this isn't
evil-window-move-* (e.g. `evil-window-move-far-left')" the only window, use evil-window-move-* (e.g. `evil-window-move-far-left')."
(when (window-dedicated-p) (when (window-dedicated-p)
(user-error "Cannot swap a dedicated window")) (user-error "Cannot swap a dedicated window"))
(let* ((this-window (selected-window)) (let* ((this-window (selected-window))
@ -111,7 +111,7 @@ integration."
;; ;;
;; Evil commands/operators ;;; Evil commands/operators
;;;###autoload (autoload '+evil:apply-macro "feature/evil/autoload/evil" nil t) ;;;###autoload (autoload '+evil:apply-macro "feature/evil/autoload/evil" nil t)
(evil-define-operator +evil:apply-macro (beg end) (evil-define-operator +evil:apply-macro (beg end)
@ -154,7 +154,8 @@ integration."
(doom/clone-and-narrow-buffer beg end bang)) (doom/clone-and-narrow-buffer beg end bang))
;; --- custom arg handlers ---------------- ;;
;;; Custom arg handlers
(defvar +evil--flag nil) (defvar +evil--flag nil)
@ -241,7 +242,8 @@ the first match on each line)."
-1 1 bang)) -1 1 bang))
;; --- wgrep ------------------------------ ;;
;;; wgrep
;;;###autoload (autoload '+evil-delete "feature/evil/autoload/evil" nil t) ;;;###autoload (autoload '+evil-delete "feature/evil/autoload/evil" nil t)
(evil-define-operator +evil-delete (beg end type register yank-handler) (evil-define-operator +evil-delete (beg end type register yank-handler)

View file

@ -14,7 +14,9 @@ line with a linewise comment.")
(defvar evil-want-Y-yank-to-eol t) (defvar evil-want-Y-yank-to-eol t)
(def-package! evil (def-package! evil
:init :hook (doom-init-modules . evil-mode)
:demand t
:preface
(setq evil-want-visual-char-semi-exclusive t (setq evil-want-visual-char-semi-exclusive t
evil-magic t evil-magic t
evil-echo-state t evil-echo-state t
@ -27,8 +29,6 @@ line with a linewise comment.")
evil-respect-visual-line-mode t evil-respect-visual-line-mode t
;; more vim-like behavior ;; more vim-like behavior
evil-symbol-word-search t evil-symbol-word-search t
;; don't activate mark on shift-click
shift-select-mode nil
;; cursor appearance ;; cursor appearance
evil-default-cursor '+evil-default-cursor evil-default-cursor '+evil-default-cursor
evil-normal-state-cursor 'box evil-normal-state-cursor 'box
@ -39,18 +39,16 @@ line with a linewise comment.")
evil-want-keybinding (not (featurep! +everywhere))) evil-want-keybinding (not (featurep! +everywhere)))
:config :config
(load! "+commands")
(add-hook 'doom-post-init-hook #'evil-mode)
(evil-select-search-module 'evil-search-module 'evil-search) (evil-select-search-module 'evil-search-module 'evil-search)
(put 'evil-define-key* 'lisp-indent-function 'defun) (put 'evil-define-key* 'lisp-indent-function 'defun)
;; Done in a hook to ensure the popup rules load as late as possible
(defun +evil|init-popup-rules () (defun +evil|init-popup-rules ()
(set-popup-rules! (set-popup-rules!
'(("^\\*evil-registers" :size 0.3) '(("^\\*evil-registers" :size 0.3)
("^\\*Command Line" :size 8)))) ("^\\*Command Line" :size 8))))
(add-hook 'doom-post-init-hook #'+evil|init-popup-rules) (add-hook 'doom-init-modules-hook #'+evil|init-popup-rules)
;; Change the cursor color in emacs mode ;; Change the cursor color in emacs mode
(defvar +evil--default-cursor-color (defvar +evil--default-cursor-color
@ -104,12 +102,7 @@ line with a linewise comment.")
;; and one custom one: %:P (expand to the project root). ;; and one custom one: %:P (expand to the project root).
(advice-add #'evil-ex-replace-special-filenames :override #'+evil*resolve-vim-path) (advice-add #'evil-ex-replace-special-filenames :override #'+evil*resolve-vim-path)
;; make `try-expand-dabbrev' from `hippie-expand' work in minibuffer. See ;; make `try-expand-dabbrev' (from `hippie-expand') work in minibuffer
;; `he-dabbrev-beg', so we need to redefine syntax for '/'
(defun +evil*fix-dabbrev-in-minibuffer ()
(set-syntax-table (let* ((table (make-syntax-table)))
(modify-syntax-entry ?/ "." table)
table)))
(add-hook 'minibuffer-inactive-mode-hook #'+evil*fix-dabbrev-in-minibuffer) (add-hook 'minibuffer-inactive-mode-hook #'+evil*fix-dabbrev-in-minibuffer)
;; Focus and recenter new splits ;; Focus and recenter new splits
@ -117,25 +110,26 @@ line with a linewise comment.")
(advice-add #'evil-window-vsplit :override #'+evil*window-vsplit) (advice-add #'evil-window-vsplit :override #'+evil*window-vsplit)
;; Integrate evil's jump-list into some navigational commands ;; Integrate evil's jump-list into some navigational commands
(defun +evil*set-jump (orig-fn &rest args)
"Set a jump point and ensure ORIG-FN doesn't set any new jump points."
(evil-set-jump (if (markerp (car args)) (car args)))
(let ((evil--jumps-jumping t))
(apply orig-fn args)))
(advice-add #'counsel-git-grep-action :around #'+evil*set-jump) (advice-add #'counsel-git-grep-action :around #'+evil*set-jump)
(advice-add #'helm-ag--find-file-action :around #'+evil*set-jump) (advice-add #'helm-ag--find-file-action :around #'+evil*set-jump)
(advice-add #'xref-push-marker-stack :around #'+evil*set-jump) (advice-add #'xref-push-marker-stack :around #'+evil*set-jump)
;; In evil, registers 2-9 are buffer-local. In vim, they're global, so... ;; In evil, registers 2-9 are buffer-local. In vim, they're global, so...
(defun +evil*make-numbered-markers-global (orig-fn char)
(or (and (>= char ?2) (<= char ?9))
(funcall orig-fn char)))
(advice-add #'evil-global-marker-p :around #'+evil*make-numbered-markers-global) (advice-add #'evil-global-marker-p :around #'+evil*make-numbered-markers-global)
;; Make o/O continue comments (see `+evil-want-o/O-to-continue-comments') ;; Make o/O continue comments (see `+evil-want-o/O-to-continue-comments')
(advice-add #'evil-open-above :around #'+evil*insert-newline-above-and-respect-comments) (advice-add #'evil-open-above :around #'+evil*insert-newline-above-and-respect-comments)
(advice-add #'evil-open-below :around #'+evil*insert-newline-below-and-respect-comments) (advice-add #'evil-open-below :around #'+evil*insert-newline-below-and-respect-comments)
;; Recenter screen after most searches
(advice-add! '(evil-visualstar/begin-search-forward
evil-visualstar/begin-search-backward
evil-ex-search-word-backward
evil-ex-search-word-backward
evil-ex-search-forward
evil-ex-search-backward)
:after #'doom*recenter)
;; --- custom interactive codes ----------- ;; --- custom interactive codes -----------
;; These arg types will highlight matches in the current buffer ;; These arg types will highlight matches in the current buffer
(evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match) (evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match)
@ -159,7 +153,10 @@ line with a linewise comment.")
;; `evil-collection' ;; `evil-collection'
(when (featurep! +everywhere) (when (featurep! +everywhere)
(load! "+everywhere"))) (load! "+everywhere"))
;; Custom evil ex commands
(load! "+commands"))
;; ;;
@ -186,49 +183,24 @@ line with a linewise comment.")
(def-package! evil-embrace (def-package! evil-embrace
:after evil-surround
:commands (embrace-add-pair embrace-add-pair-regexp) :commands (embrace-add-pair embrace-add-pair-regexp)
:hook (LaTeX-mode . embrace-LaTeX-mode-hook) :hook (LaTeX-mode . embrace-LaTeX-mode-hook)
:hook (org-mode . embrace-org-mode-hook) :hook (org-mode . embrace-org-mode-hook)
:hook ((ruby-mode enh-ruby-mode) . embrace-ruby-mode-hook)
:hook (emacs-lisp-mode . embrace-emacs-lisp-mode-hook)
:hook ((emacs-lisp-mode lisp-mode) . +evil|embrace-lisp-mode-hook)
:hook ((org-mode LaTeX-mode) . +evil|embrace-latex-mode-hook)
:init :init
;; Add extra pairs (after! evil-surround
(add-hook! emacs-lisp-mode (evil-embrace-enable-evil-surround-integration))
(embrace-add-pair ?\` "`" "'"))
(add-hook! (emacs-lisp-mode lisp-mode)
(embrace-add-pair-regexp ?f "([^ ]+ " ")" #'+evil--embrace-elisp-fn))
(add-hook! (org-mode LaTeX-mode)
(embrace-add-pair-regexp ?l "\\[a-z]+{" "}" #'+evil--embrace-latex))
:config :config
(setq evil-embrace-show-help-p nil) (setq evil-embrace-show-help-p nil)
(evil-embrace-enable-evil-surround-integration)
(defun +evil--embrace-get-pair (char) (defun +evil|embrace-latex-mode-hook ()
(if-let* ((pair (cdr-safe (assoc (string-to-char char) evil-surround-pairs-alist)))) (embrace-add-pair-regexp ?l "\\[a-z]+{" "}" #'+evil--embrace-latex))
pair
(if-let* ((pair (assoc-default char embrace--pairs-list)))
(if-let* ((real-pair (and (functionp (embrace-pair-struct-read-function pair))
(funcall (embrace-pair-struct-read-function pair)))))
real-pair
(cons (embrace-pair-struct-left pair) (embrace-pair-struct-right pair)))
(cons char char))))
(defun +evil--embrace-escaped () (defun +evil|embrace-lisp-mode-hook ()
"Backslash-escaped surround character support for embrace." (embrace-add-pair-regexp ?f "([^ ]+ " ")" #'+evil--embrace-elisp-fn))
(let ((char (read-char "\\")))
(if (eq char 27)
(cons "" "")
(let ((pair (+evil--embrace-get-pair (string char)))
(text (if (sp-point-in-string) "\\\\%s" "\\%s")))
(cons (format text (car pair))
(format text (cdr pair)))))))
(defun +evil--embrace-latex ()
"LaTeX command support for embrace."
(cons (format "\\%s{" (read-string "\\")) "}"))
(defun +evil--embrace-elisp-fn ()
"Elisp function support for embrace."
(cons (format "(%s " (or (read-string "(") "")) ")"))
;; Add escaped-sequence support to embrace ;; Add escaped-sequence support to embrace
(setf (alist-get ?\\ (default-value 'embrace--pairs-list)) (setf (alist-get ?\\ (default-value 'embrace--pairs-list))
@ -240,13 +212,13 @@ line with a linewise comment.")
(def-package! evil-escape (def-package! evil-escape
:commands (evil-escape evil-escape-mode evil-escape-pre-command-hook) :commands (evil-escape)
:after-call (evil-normal-state-exit-hook)
:init :init
(setq evil-escape-excluded-states '(normal visual multiedit emacs motion) (setq evil-escape-excluded-states '(normal visual multiedit emacs motion)
evil-escape-excluded-major-modes '(neotree-mode treemacs-mode term-mode) evil-escape-excluded-major-modes '(neotree-mode treemacs-mode term-mode)
evil-escape-key-sequence "jk" evil-escape-key-sequence "jk"
evil-escape-delay 0.25) evil-escape-delay 0.25)
(add-hook 'pre-command-hook #'evil-escape-pre-command-hook)
(evil-define-key* '(insert replace visual operator) 'global "\C-g" #'evil-escape) (evil-define-key* '(insert replace visual operator) 'global "\C-g" #'evil-escape)
:config :config
;; no `evil-escape' in minibuffer ;; no `evil-escape' in minibuffer
@ -311,9 +283,7 @@ the new algorithm is confusing, like in python or ruby."
:config (global-evil-surround-mode 1)) :config (global-evil-surround-mode 1))
;; Without `evil-visualstar', * and # grab the word at point and search, no ;; Allows you to use the selection for * and #
;; matter what mode you're in. I want to be able to visually select a region and
;; search for other occurrences of it.
(def-package! evil-visualstar (def-package! evil-visualstar
:commands (evil-visualstar/begin-search :commands (evil-visualstar/begin-search
evil-visualstar/begin-search-forward evil-visualstar/begin-search-forward

View file

@ -84,7 +84,7 @@ Otherwise, these properties are available to be set:
;; ;;
;; Library ;; Helpers
;; Helpers ;; Helpers
(defun +lookup--online-provider (&optional force-p namespace) (defun +lookup--online-provider (&optional force-p namespace)
@ -100,59 +100,64 @@ Otherwise, these properties are available to be set:
provider)))) provider))))
(defun +lookup--symbol-or-region (&optional initial) (defun +lookup--symbol-or-region (&optional initial)
(cond (initial) (cond ((stringp initial)
initial)
((use-region-p) ((use-region-p)
(buffer-substring-no-properties (region-beginning) (buffer-substring-no-properties (region-beginning)
(region-end))) (region-end)))
((require 'xref nil t) ((require 'xref nil t)
(xref-backend-identifier-at-point (xref-find-backend))))) (xref-backend-identifier-at-point (xref-find-backend)))))
(defun +lookup--jump-to (prop identifier &optional other-window) (defun +lookup--run-hooks (hook identifier origin &optional other-window)
;; TODO Refactor me (doom-log "Looking up '%s' with '%s'" identifier hook)
(let ((origin (point-marker))) (condition-case-unless-debug e
(cl-loop for fn (if (get hook '+lookup-async)
in (plist-get (list :definition +lookup-definition-functions (progn
:references +lookup-references-functions (when other-window
:documentation +lookup-documentation-functions ;; If async, we can't catch the window change or destination buffer
:file +lookup-file-functions) ;; reliably, so we set up the new window ahead of time.
prop) (switch-to-buffer-other-window (current-buffer))
for cmd = (or (command-remapping fn) fn) (goto-char (marker-position origin)))
if (get fn '+lookup-async) (if (commandp hook)
return (call-interactively hook)
(progn (funcall hook identifier))
(when other-window t)
;; If async, we can't catch the window change or destination buffer (save-window-excursion
;; reliably, so we set up the new window ahead of time. (when (or (if (commandp hook)
(switch-to-buffer-other-window (current-buffer)) (call-interactively hook)
(goto-char (marker-position origin))) (funcall hook identifier))
(call-interactively fn) (null origin)
t) (/= (point-marker) origin))
if (condition-case e (point-marker))))
(save-window-excursion ((error user-error)
(when (or (if (commandp cmd) (message "%s" e)
(call-interactively cmd) nil)))
(funcall cmd identifier))
(/= (point-marker) origin))
(point-marker)))
(error (ignore (message "%s" e))))
return
(progn
(funcall (if other-window
#'switch-to-buffer-other-window
#'switch-to-buffer)
(marker-buffer it))
(goto-char it)))))
(defun +lookup--file-search (identifier) (defun +lookup--jump-to (prop identifier &optional other-window)
(unless identifier (let ((ret
(let ((query (rxt-quote-pcre identifier))) (condition-case e
(ignore-errors (run-hook-wrapped
(cond ((featurep! :completion ivy) (plist-get (list :definition '+lookup-definition-functions
(+ivy-file-search nil :query query) :references '+lookup-references-functions
t) :documentation '+lookup-documentation-functions
((featurep! :completion helm) :file '+lookup-file-functions)
(+helm-file-search nil :query query) prop)
t)))))) '+lookup--run-hooks
identifier
(point-marker)
other-window)
(quit (user-error "Aborted %s lookup" prop)))))
(cond ((null ret)
(message "Could not find '%s'" identifier)
nil)
((markerp ret)
(funcall (if other-window
#'switch-to-buffer-other-window
#'switch-to-buffer)
(marker-buffer ret))
(goto-char ret)
(recenter)
t))))
;; ;;
@ -196,8 +201,7 @@ falling back to git-grep)."
(defun +lookup-evil-goto-definition-backend (identifier) (defun +lookup-evil-goto-definition-backend (identifier)
"Uses `evil-goto-definition' to conduct a text search for IDENTIFIER in the "Uses `evil-goto-definition' to conduct a text search for IDENTIFIER in the
current buffer." current buffer."
(and (featurep 'evil) (and (fboundp 'evil-goto-definition)
evil-mode
(ignore-errors (ignore-errors
(cl-destructuring-bind (beg . end) (cl-destructuring-bind (beg . end)
(bounds-of-thing-at-point 'symbol) (bounds-of-thing-at-point 'symbol)
@ -268,7 +272,7 @@ search otherwise."
((error "Couldn't find references of '%s'" identifier)))) ((error "Couldn't find references of '%s'" identifier))))
;;;###autoload ;;;###autoload
(defun +lookup/documentation (identifier &optional other-window) (defun +lookup/documentation (identifier &optional arg)
"Show documentation for IDENTIFIER (defaults to symbol at point or selection. "Show documentation for IDENTIFIER (defaults to symbol at point or selection.
First attempts the :documentation handler specified with `set-lookup-handlers!' First attempts the :documentation handler specified with `set-lookup-handlers!'
@ -277,9 +281,7 @@ for the current mode/buffer (if any), then falls back to the backends in
(interactive (interactive
(list (+lookup--symbol-or-region) (list (+lookup--symbol-or-region)
current-prefix-arg)) current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point")) (cond ((+lookup--jump-to :documentation identifier t))
((+lookup--jump-to :documentation identifier other-window))
((user-error "Couldn't find documentation for '%s'" identifier)))) ((user-error "Couldn't find documentation for '%s'" identifier))))

View file

@ -5,7 +5,7 @@
;; be loaded before it is byte-compiled during installation. To ensure this, we ;; be loaded before it is byte-compiled during installation. To ensure this, we
;; declare helm before dumb-jump. ;; declare helm before dumb-jump.
(when (featurep! :completion helm) (when (featurep! :completion helm)
(depends-on! :completion helm)) (package! helm))
;; ;;
(package! dumb-jump) (package! dumb-jump)

View file

@ -21,13 +21,15 @@
:config :config
(setq yas-verbosity (if doom-debug-mode 3 0) (setq yas-verbosity (if doom-debug-mode 3 0)
yas-also-auto-indent-first-line t yas-also-auto-indent-first-line t
yas-triggers-in-field t) ; Allow nested snippets yas-triggers-in-field t ; Allow nested snippets
;; Remove default ~/.emacs.d/snippets
yas-snippet-dirs (delete yas--default-user-snippets-dir yas-snippet-dirs))
;; Allow private snippets in DOOMDIR/snippets ;; Allow private snippets in DOOMDIR/snippets
(add-to-list 'yas-snippet-dirs '+snippets-dir nil #'eq) (add-to-list 'yas-snippet-dirs '+snippets-dir nil #'eq)
;; Remove GUI dropdown prompt (prefer ivy/helm) ;; Remove GUI dropdown prompt (prefer ivy/helm)
(delq #'yas-dropdown-prompt yas-prompt-functions) (setq yas-prompt-functions (delq 'yas-dropdown-prompt yas-prompt-functions))
;; Prioritize private snippets in `+snippets-dir' over built-in ones if there ;; Prioritize private snippets in `+snippets-dir' over built-in ones if there
;; are multiple choices. ;; are multiple choices.
(add-to-list 'yas-prompt-functions #'+snippets-prompt-private nil #'eq) (add-to-list 'yas-prompt-functions #'+snippets-prompt-private nil #'eq)

View file

@ -61,9 +61,9 @@ in [[../../private/default/+evil-commands.el][private/default/+evil-commands.el]
| ~+workspace/new~ | =SPC TAB n= | Create a new, blank workspace | | ~+workspace/new~ | =SPC TAB n= | Create a new, blank workspace |
| ~+workspace/display~ | =SPC TAB TAB= | Display open workspaces in the mode-line | | ~+workspace/display~ | =SPC TAB TAB= | Display open workspaces in the mode-line |
| ~+workspace/load~ | =SPC TAB l= | Load a saved workspace into the current session | | ~+workspace/load~ | =SPC TAB l= | Load a saved workspace into the current session |
| ~+workspace/load-session~ | =SPC TAB L= / =:sl[oad]= | Replace current session with a saved one | | ~doom/quicksave-load~ | =SPC TAB L= / =:sl[oad]= | Replace current session with a saved one |
| ~+workspace/save~ | =SPC TAB s= | Save the current workspace to a file | | ~+workspace/save~ | =SPC TAB s= | Save the current workspace to a file |
| ~+workspace/save-session~ | =SPC TAB S= / =:ss[ave]= | Save current session | | ~doom/quicksave-save~ | =SPC TAB S= / =:ss[ave]= | Save current session |
| ~+workspace/switch-to~ | =SPC TAB .= | Switch to an open workspace | | ~+workspace/switch-to~ | =SPC TAB .= | Switch to an open workspace |
| ~+workspace/switch-left~ | =SPC TAB [= / =[ w= / =gT= | Switch to previous workspace | | ~+workspace/switch-left~ | =SPC TAB [= / =[ w= / =gT= | Switch to previous workspace |
| ~+workspace/switch-right~ | =SPC TAB [= / =] w= / =gt= | Switch to next workspace | | ~+workspace/switch-right~ | =SPC TAB [= / =] w= / =gt= | Switch to next workspace |

View file

@ -1,20 +1,6 @@
;;; feature/workspaces/autoload/evil.el -*- lexical-binding: t; -*- ;;; feature/workspaces/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :feature evil) ;;;###if (featurep! :feature evil)
;;;###autoload (autoload '+workspace:save-session "feature/workspaces/autoload/evil" nil t)
(evil-define-command +workspace:save-session (&optional bang name)
"Ex wrapper around `+workspace/save-session'. If BANG, then autosave
(pointless if autosaving/loading is off). If NAME is nil, default to 'last'."
(interactive "<!><a>")
(+workspace/save-session (if bang persp-auto-save-fname name)))
;;;###autoload (autoload '+workspace:load-session "feature/workspaces/autoload/evil" nil t)
(evil-define-command +workspace:load-session (&optional bang name)
"Ex wrapper around `+workspace/load-session'. If BANG, then load last autosave
(pointless if autosaving/loading is off). If NAME is nil, defaults to 'last'."
(interactive "<!><a>")
(+workspace/load-session (if bang persp-auto-save-fname name)))
;;;###autoload (autoload '+workspace:save "feature/workspaces/autoload/evil" nil t) ;;;###autoload (autoload '+workspace:save "feature/workspaces/autoload/evil" nil t)
(evil-define-command +workspace:save (&optional name) (evil-define-command +workspace:save (&optional name)
"Ex wrapper around `+workspace/save-session'." "Ex wrapper around `+workspace/save-session'."

View file

@ -112,14 +112,6 @@ Returns t if successful, nil otherwise."
*persp-hash* (list name)) *persp-hash* (list name))
(+workspace-exists-p name)) (+workspace-exists-p name))
;;;###autoload
(defun +workspace-load-session (&optional name)
"Replace current session with the entire session named NAME. If NAME is nil,
use `persp-auto-save-fname'."
(mapc #'+workspace-delete (+workspace-list-names))
(persp-load-state-from-file
(expand-file-name (or name persp-auto-save-fname) persp-save-dir)))
;;;###autoload ;;;###autoload
(defun +workspace-save (name) (defun +workspace-save (name)
"Saves a single workspace (NAME) from the current session. Can be loaded again "Saves a single workspace (NAME) from the current session. Can be loaded again
@ -134,18 +126,6 @@ Returns t on success, nil otherwise."
(and (member name (persp-list-persp-names-in-file fname)) (and (member name (persp-list-persp-names-in-file fname))
t))) t)))
;;;###autoload
(defun +workspace-save-session (&optional name)
"Save a whole session as NAME. If NAME is nil, use `persp-auto-save-fname'.
Return t on success, nil otherwise."
(let ((fname (expand-file-name (or name persp-auto-save-fname)
persp-save-dir)))
;; disable auto-saving on kill-emacs if autosaving (i.e. name is nil)
(when (or (not name)
(string= name persp-auto-save-fname))
(setq persp-auto-save-opt 0))
(and (persp-save-state-to-file fname) t)))
;;;###autoload ;;;###autoload
(defun +workspace-new (name) (defun +workspace-new (name)
"Create a new workspace named NAME. If one already exists, return nil. "Create a new workspace named NAME. If one already exists, return nil.
@ -206,6 +186,9 @@ throws an error."
;; ;;
;; Commands ;; Commands
;;;###autoload
(defalias '+workspace/restore-last-session #'doom/quickload-session)
;;;###autoload ;;;###autoload
(defun +workspace/load (name) (defun +workspace/load (name)
"Load a workspace and switch to it. If called with C-u, try to reload the "Load a workspace and switch to it. If called with C-u, try to reload the
@ -236,46 +219,6 @@ workspace."
(+workspace-message (format "'%s' workspace saved" name) 'success) (+workspace-message (format "'%s' workspace saved" name) 'success)
(+workspace-error (format "Couldn't save workspace %s" name)))) (+workspace-error (format "Couldn't save workspace %s" name))))
;;;###autoload
(defun +workspace/load-session (&optional name)
"Load a session and switch to it. If called with C-u, try to load the last
session."
(interactive
(list
(unless current-prefix-arg
(completing-read
"Session to load: "
(directory-files persp-save-dir nil "^[^_.]")
nil t))))
(condition-case ex
(let ((name (or name persp-auto-save-fname)))
(+workspace-load-session name)
(+workspace-message (format "'%s' workspace loaded" name) 'success))
'(error (+workspace-error (cadr ex) t))))
;;;###autoload
(defun +workspace/load-last-session ()
"Restore last session and switch to it."
(interactive)
(+workspace/load-session))
;;;###autoload
(defun +workspace/save-session (&optional name)
"Save the current session. If called with C-u, prompt you for the name to save
the session as."
(interactive
(list
(when current-prefix-arg
(completing-read
"Save session as: "
(directory-files persp-save-dir nil "^[^_.]")))))
(condition-case-unless-debug ex
(let ((name (or name persp-auto-save-fname)))
(if (+workspace-save-session name)
(+workspace-message (format "Saved session as '%s'" name) 'success)
(error "Couldn't save session as '%s'" name)))
('error (+workspace-error ex t))))
;;;###autoload ;;;###autoload
(defun +workspace/rename (new-name) (defun +workspace/rename (new-name)
"Rename the current workspace." "Rename the current workspace."
@ -437,12 +380,6 @@ the next."
(t (+workspace-error "Can't delete last workspace" t))))))) (t (+workspace-error "Can't delete last workspace" t)))))))
;;;###autoload
(defun +workspace/restart-emacs-then-restore ()
"Restarts Emacs, then restores the session."
(interactive)
(restart-emacs (list "--restore")))
;; ;;
;; Tabs display in minibuffer ;; Tabs display in minibuffer
@ -570,7 +507,7 @@ This be hooked to `projectile-after-switch-project-hook'."
(+workspace-message (+workspace-message
(format "Switched to '%s' in new workspace" new-name) (format "Switched to '%s' in new workspace" new-name)
'success)) 'success))
(with-current-buffer (switch-to-buffer (doom-fallback-buffer)) (with-current-buffer (doom-fallback-buffer)
(setq default-directory +workspaces--project-dir) (setq default-directory +workspaces--project-dir)
(message "Switched to '%s'" (doom-project-name +workspaces--project-dir))) (message "Switched to '%s'" (doom-project-name +workspaces--project-dir)))
(unless current-prefix-arg (unless current-prefix-arg

View file

@ -5,11 +5,6 @@
;; it because it was unstable and slow; `persp-mode' is neither (and still ;; it because it was unstable and slow; `persp-mode' is neither (and still
;; maintained). ;; maintained).
;; ;;
;; By default, sessions are autosaved, but not autoloaded. Use :ss or
;; `+workspace/save-session' to save, and :sl or `+workspace/load-session' to
;; load the last autosaved session. You can give sessions a custom name so they
;; can be loaded later.
;;
;; NOTE persp-mode requires `workgroups' for file persistence in Emacs 24.4. ;; NOTE persp-mode requires `workgroups' for file persistence in Emacs 24.4.
(defvar +workspaces-main "main" (defvar +workspaces-main "main"
@ -20,26 +15,20 @@
`counsel-projectile-switch-project'. This function must take one argument: the `counsel-projectile-switch-project'. This function must take one argument: the
new project directory.") new project directory.")
;; FIXME actually use this for wconf bookmark system
(defvar +workspaces-data-file "_workspaces"
"The basename of the file to store single workspace perspectives. Will be
stored in `persp-save-dir'.")
(defvar +workspaces-on-switch-project-behavior 'non-empty (defvar +workspaces-on-switch-project-behavior 'non-empty
"Controls the behavior of workspaces when switching to a new project. "Controls the behavior of workspaces when switching to a new project.
Can be one of the following: Can be one of the following:
t Always create a new workspace for the project t Always create a new workspace for the project
'non-empty Only create a new workspace if the current one has no buffers 'non-empty Only create a new workspace if the current one already has buffers
associated with it. associated with it.
nil Never create a new workspace on project switch.") nil Never create a new workspace on project switch.")
;; If emacs is passed --restore, restore the last session on startup. This is ;; FIXME actually use this for wconf bookmark system
;; used by the `+workspace/restart-emacs-then-restore' command. (defvar +workspaces-data-file "_workspaces"
(defun +workspaces-restore-last-session (&rest _) "The basename of the file to store single workspace perspectives. Will be
(add-hook 'emacs-startup-hook #'+workspace/load-session :append)) stored in `persp-save-dir'.")
(add-to-list 'command-switch-alist (cons "--restore" #'+workspaces-restore-last-session))
;; ;;
@ -64,31 +53,31 @@ workspace. Also ensures that the *Warnings* buffer will be visible in main.
Uses `+workspaces-main' to determine the name of the main workspace." Uses `+workspaces-main' to determine the name of the main workspace."
(unless persp-mode (unless persp-mode
(persp-mode +1)) (persp-mode +1)
(unless noninteractive (unless noninteractive
(let (persp-before-switch-functions persp-activated-functions) (let (persp-before-switch-functions persp-activated-functions)
(with-selected-frame frame (with-selected-frame frame
;; The default perspective persp-mode creates (`persp-nil-name') is ;; The default perspective persp-mode creates (`persp-nil-name') is
;; special and doesn't represent a real persp object, so buffers can't ;; special and doesn't represent a real persp object, so buffers can't
;; really be assigned to it, among other quirks. We create a *real* ;; really be assigned to it, among other quirks. We create a *real*
;; main workspace to fill this role. ;; main workspace to fill this role.
(unless (persp-get-by-name +workspaces-main) (unless (persp-get-by-name +workspaces-main)
(persp-add-new +workspaces-main)) (persp-add-new +workspaces-main))
;; Switch to it if we aren't auto-loading the last session ;; Switch to it if we aren't auto-loading the last session
(when (and (string= (safe-persp-name (get-current-persp)) persp-nil-name) (when (and (string= (safe-persp-name (get-current-persp)) persp-nil-name)
(= persp-auto-resume-time -1)) (= persp-auto-resume-time -1))
(persp-frame-switch +workspaces-main frame) (persp-frame-switch +workspaces-main frame)
;; We want to know where we are in every new daemon frame ;; We want to know where we are in every new daemon frame
(when (daemonp) (when (daemonp)
(run-at-time 0.1 nil #'+workspace/display)) (run-at-time 0.1 nil #'+workspace/display))
;; Fix #319: the warnings buffer gets swallowed by creating ;; Fix #319: the warnings buffer gets swallowed by creating
;; `+workspaces-main', so we display it manually, if it exists. ;; `+workspaces-main', so we display it manually, if it exists.
(when-let* ((warnings (get-buffer "*Warnings*"))) (when-let* ((warnings (get-buffer "*Warnings*")))
(save-excursion (save-excursion
(display-buffer-in-side-window (display-buffer-in-side-window
warnings '((window-height . shrink-window-if-larger-than-buffer)))))))))) warnings '((window-height . shrink-window-if-larger-than-buffer)))))))))))
(add-hook 'doom-post-init-hook #'+workspaces|init t) (add-hook 'doom-init-modules-hook #'+workspaces|init t)
:config :config
(setq persp-autokill-buffer-on-remove 'kill-weak (setq persp-autokill-buffer-on-remove 'kill-weak
persp-nil-hidden t persp-nil-hidden t
@ -102,8 +91,6 @@ Uses `+workspaces-main' to determine the name of the main workspace."
(advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers) (advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers)
(add-hook 'doom-cleanup-hook #'+workspaces|cleanup-unassociated-buffers)
;; Ensure buffers we've opened/switched to are auto-added to the current ;; Ensure buffers we've opened/switched to are auto-added to the current
;; perspective ;; perspective
(setq persp-add-buffer-on-find-file t (setq persp-add-buffer-on-find-file t

View file

@ -56,7 +56,16 @@ preceded by the opening brace or a comma (disregarding whitespace in between)."
;;;###autoload ;;;###autoload
(defun +cc-c-c++-objc-mode () (defun +cc-c-c++-objc-mode ()
"Sets either `c-mode', `objc-mode' or `c++-mode', whichever is appropriate." "Uses heuristics to detect `c-mode', `objc-mode' or `c++-mode'.
1. Checks if there are nearby cpp/cc/m/mm files with the same name.
2. Checks for ObjC and C++-specific keywords and libraries.
3. Falls back to `+cc-default-header-file-mode', if set.
4. Otherwise, activates `c-mode'.
This is meant to replace `c-or-c++-mode' (introduced in Emacs 26.1), which
doesn't support specification of the fallback mode and whose heuristics are
simpler."
(let ((base (file-name-sans-extension (buffer-file-name (buffer-base-buffer))))) (let ((base (file-name-sans-extension (buffer-file-name (buffer-base-buffer)))))
(cond ((file-exists-p! (or (concat base ".cpp") (cond ((file-exists-p! (or (concat base ".cpp")
(concat base ".cc"))) (concat base ".cc")))
@ -70,13 +79,11 @@ preceded by the opening brace or a comma (disregarding whitespace in between)."
"\\|[-+] ([a-zA-Z0-9_]+)" "\\|[-+] ([a-zA-Z0-9_]+)"
"\\)"))) "\\)")))
(objc-mode)) (objc-mode))
((fboundp 'c-or-c++-mode) ; introduced in Emacs 26.1 ((+cc--re-search-for
(c-or-c++-mode))
((+cc--re-search-for ; TODO Remove this along with Emacs 25 support
(let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*")) (let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*"))
(concat "^" ws-maybe "\\(?:" (concat "^" ws-maybe "\\(?:"
"using" ws "\\(?:namespace" ws "std;\\|std::\\)" "using" ws "\\(?:namespace" ws "std;\\|std::\\)"
"\\|" "namespace" "\\(:?" ws id "\\)?" ws-maybe "{" "\\|" "namespace" "\\(?:" ws id "\\)?" ws-maybe "{"
"\\|" "class" ws id ws-maybe "[:{\n]" "\\|" "class" ws id ws-maybe "[:{\n]"
"\\|" "template" ws-maybe "<.*>" "\\|" "template" ws-maybe "<.*>"
"\\|" "#include" ws-maybe "<\\(?:string\\|iostream\\|map\\)>" "\\|" "#include" ws-maybe "<\\(?:string\\|iostream\\|map\\)>"
@ -86,6 +93,14 @@ preceded by the opening brace or a comma (disregarding whitespace in between)."
(funcall +cc-default-header-file-mode)) (funcall +cc-default-header-file-mode))
((c-mode))))) ((c-mode)))))
(defun +cc-resolve-include-paths ()
(cl-loop with path = (or buffer-file-name default-directory)
for dir in +cc-default-include-paths
if (file-name-absolute-p dir)
collect dir
else if (projectile-locate-dominating-file path dir)
collect (expand-file-name dir it)))
;; ;;
;; Commands ;; Commands
@ -99,7 +114,7 @@ preceded by the opening brace or a comma (disregarding whitespace in between)."
;; first rtag ;; first rtag
(when (and (featurep 'rtags) (when (and (featurep 'rtags)
rtags-enabled rtags-enabled
(executable-find "rc")) (executable-find rtags-rc-binary-name))
(with-temp-buffer (with-temp-buffer
(message "Reloaded compile commands for rtags daemon") (message "Reloaded compile commands for rtags daemon")
(rtags-call-rc :silent t "-J" (or (doom-project-root) default-directory)))) (rtags-call-rc :silent t "-J" (or (doom-project-root) default-directory))))
@ -128,12 +143,13 @@ preceded by the opening brace or a comma (disregarding whitespace in between)."
"Better fontification for preprocessor constants" "Better fontification for preprocessor constants"
(when (memq major-mode '(c-mode c++-mode)) (when (memq major-mode '(c-mode c++-mode))
(font-lock-add-keywords (font-lock-add-keywords
nil '(("\\<[A-Z]*_[A-Z_]+\\>" . font-lock-constant-face) nil '(("\\<[A-Z]*_[0-9A-Z_]+\\>" . font-lock-constant-face)
("\\<[A-Z]\\{3,\\}\\>" . font-lock-constant-face)) ("\\<[A-Z]\\{3,\\}\\>" . font-lock-constant-face))
t))) t)))
(defvar +cc--project-includes-alist nil)
;;;###autoload ;;;###autoload
(defun +cc|irony-init-compile-options () (defun +cc|init-irony-compile-options ()
"Initialize compiler options for irony-mode. It searches for the nearest "Initialize compiler options for irony-mode. It searches for the nearest
compilation database and initailizes it, otherwise falling back on compilation database and initailizes it, otherwise falling back on
`+cc-default-compiler-options' and `+cc-default-include-paths'. `+cc-default-compiler-options' and `+cc-default-include-paths'.
@ -143,33 +159,47 @@ compilation dbs."
(when (memq major-mode '(c-mode c++-mode objc-mode)) (when (memq major-mode '(c-mode c++-mode objc-mode))
(require 'irony-cdb) (require 'irony-cdb)
(unless (irony-cdb-autosetup-compile-options) (unless (irony-cdb-autosetup-compile-options)
(irony-cdb--update-compile-options (let ((project-root (doom-project-root))
(delq nil (include-paths (+cc-resolve-include-paths)))
(append (cdr-safe (assq major-mode +cc-default-compiler-options)) (setf (alist-get project-root +cc--project-includes-alist)
(cl-loop with path = (or buffer-file-name default-directory) include-paths)
for dir in '("include" "includes") (irony-cdb--update-compile-options
if (projectile-locate-dominating-file path dir) (append (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))
collect it) (cl-loop for path in include-paths
(cl-loop for path in +cc-default-include-paths collect (format "-I%s" path)))
if (stringp path) project-root)))))
nconc (list "-I" path))))
(doom-project-root))) ;; ;;;###autoload
;; Make ffap aware of include paths ;; (defun +cc|init-ccls-compile-options ()
(when irony--working-directory ;; "TODO"
(require 'ffap) ;; (when (memq major-mode '(c-mode c++-mode objc-mode))
(make-local-variable 'ffap-c-path) ;; (when-let* ((include-paths (+cc-resolve-include-paths)))
(make-local-variable 'ffap-c++-path) ;; (let ((args (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))))
(cl-loop for opt in irony--compile-options ;; (setf (alist-get (or (lsp-workspace-root)
if (and (stringp opt) ;; (lsp--suggest-project-root)
(string-match "^-I\\(.+\\)" opt)) ;; (doom-project-root))
do (add-to-list (pcase major-mode ;; +cc--project-includes-alist)
(`c-mode 'ffap-c-path) ;; include-paths)
(`c++-mode 'ffap-c++-path)) ;; (setq ccls-initialization-options
(expand-file-name (match-string 1 opt) ;; `(:clang (:extraArgs
irony--working-directory)))))) ;; [,@(cl-loop for path in include-paths
;; collect (format "-I%s" path))])))))))
;;;###autoload ;;;###autoload
(defun +cc|cleanup-rtags () (defun +cc|init-ffap-integration ()
"Kill rtags server(s) if there are no C/C++ buffers open." "Takes the local project include paths and registers them with ffap.
(unless (doom-buffers-in-mode '(c-mode c++-mode) (buffer-list)) This way, `find-file-at-point' (and `+lookup/file') will know where to find most
(rtags-cancel-process))) header files."
(when-let* ((project-root (or (bound-and-true-p irony--working-directory)
(and (featurep 'lsp)
(or (lsp-workspace-root)
(doom-project-root))))))
(require 'ffap)
(make-local-variable 'ffap-c-path)
(make-local-variable 'ffap-c++-path)
(cl-loop for dir in (or (cdr (assoc project-root +cc--project-includes-alist))
(+cc-resolve-include-paths))
do (add-to-list (pcase major-mode
(`c-mode 'ffap-c-path)
(`c++-mode 'ffap-c++-path))
(expand-file-name dir project-root)))))

View file

@ -1,9 +1,13 @@
;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*- ;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*-
(defvar +cc-default-include-paths (list "include/") (defvar +cc-default-include-paths
"A list of default paths, relative to a project root, to search for headers in (list "include"
C/C++. Paths can be absolute. This is ignored if your project has a compilation "includes")
database.") "A list of default relative paths which will be searched for up from the
current file, to be passed to irony as extra header search paths. Paths can be
absolute. This is ignored if your project has a compilation database.
This is ignored by ccls.")
(defvar +cc-default-header-file-mode 'c-mode (defvar +cc-default-header-file-mode 'c-mode
"Fallback major mode for .h files if all other heuristics fail (in "Fallback major mode for .h files if all other heuristics fail (in
@ -20,7 +24,9 @@ database.")
"-stdlib=libc++"))) "-stdlib=libc++")))
(objc-mode . nil)) (objc-mode . nil))
"A list of default compiler options for the C family. These are ignored if a "A list of default compiler options for the C family. These are ignored if a
compilation database is present in the project.") compilation database is present in the project.
This is ignored by ccls.")
;; ;;
@ -42,8 +48,13 @@ compilation database is present in the project.")
;; Activate `c-mode', `c++-mode' or `objc-mode' depending on heuristics ;; Activate `c-mode', `c++-mode' or `objc-mode' depending on heuristics
(add-to-list 'auto-mode-alist '("\\.h\\'" . +cc-c-c++-objc-mode)) (add-to-list 'auto-mode-alist '("\\.h\\'" . +cc-c-c++-objc-mode))
;; Ensure find-file-at-point works in C modes, must be added before irony
;; and/or lsp hooks are run.
(add-hook! (c-mode-local-vars c++-mode-local-vars objc-mode-local-vars)
#'+cc|init-ffap-integration)
:config :config
(set-electric! '(c-mode c++-mode objc-mode java-mode) :chars '(?\n ?\})) (set-electric! '(c-mode c++-mode objc-mode java-mode) :chars '(?\n ?\} ?\{))
(set-docsets! 'c-mode "C") (set-docsets! 'c-mode "C")
(set-docsets! 'c++-mode "C++" "Boost") (set-docsets! 'c++-mode "C++" "Boost")
@ -69,12 +80,11 @@ compilation database is present in the project.")
;;; Better fontification (also see `modern-cpp-font-lock') ;;; Better fontification (also see `modern-cpp-font-lock')
(add-hook 'c-mode-common-hook #'rainbow-delimiters-mode) (add-hook 'c-mode-common-hook #'rainbow-delimiters-mode)
(add-hook! '(c-mode-hook c++-mode-hook) #'+cc|fontify-constants) (add-hook! (c-mode c++-mode) #'+cc|fontify-constants)
;; Custom style, based off of linux ;; Custom style, based off of linux
(unless (assoc "doom" c-style-alist) (c-add-style
(push '("doom" "doom" '((c-basic-offset . tab-width)
(c-basic-offset . tab-width)
(c-comment-only-line-offset . 0) (c-comment-only-line-offset . 0)
(c-hanging-braces-alist (brace-list-open) (c-hanging-braces-alist (brace-list-open)
(brace-entry-open) (brace-entry-open)
@ -102,8 +112,7 @@ compilation database is present in the project.")
;; another level ;; another level
(access-label . -) (access-label . -)
(inclass +cc-c++-lineup-inclass +) (inclass +cc-c++-lineup-inclass +)
(label . 0))) (label . 0))))
c-style-alist))
;;; Keybindings ;;; Keybindings
;; Smartparens and cc-mode both try to autoclose angle-brackets intelligently. ;; Smartparens and cc-mode both try to autoclose angle-brackets intelligently.
@ -131,16 +140,17 @@ compilation database is present in the project.")
(setq irony-server-install-prefix (concat doom-etc-dir "irony-server/")) (setq irony-server-install-prefix (concat doom-etc-dir "irony-server/"))
:init :init
(defun +cc|init-irony-mode () (defun +cc|init-irony-mode ()
(when (and (memq major-mode '(c-mode c++-mode objc-mode)) (if (file-directory-p irony-server-install-prefix)
(file-directory-p irony-server-install-prefix)) (irony-mode +1)
(irony-mode +1))) (message "Irony server isn't installed")))
(add-hook 'c-mode-common-hook #'+cc|init-irony-mode) (add-hook! (c-mode-local-vars c++-mode-local-vars objc-mode-local-vars)
#'+cc|init-irony-mode)
:config :config
(setq irony-cdb-search-directory-list '("." "build" "build-conda")) (setq irony-cdb-search-directory-list '("." "build" "build-conda"))
;; Initialize compilation database, if present. Otherwise, fall back on ;; Initialize compilation database, if present. Otherwise, fall back on
;; `+cc-default-compiler-options'. ;; `+cc-default-compiler-options'.
(add-hook 'irony-mode-hook #'+cc|irony-init-compile-options) (add-hook 'irony-mode-hook #'+cc|init-irony-compile-options)
(def-package! irony-eldoc (def-package! irony-eldoc
:hook (irony-mode . irony-eldoc)) :hook (irony-mode . irony-eldoc))
@ -188,10 +198,11 @@ compilation database is present in the project.")
:init :init
(defun +cc|init-rtags () (defun +cc|init-rtags ()
"Start an rtags server in c-mode and c++-mode buffers." "Start an rtags server in c-mode and c++-mode buffers."
(when (and (memq major-mode '(c-mode c++-mode)) (when (and (require 'rtags nil t)
(rtags-executable-find "rdm")) (rtags-executable-find rtags-rdm-binary-name))
(rtags-start-process-unless-running))) (rtags-start-process-unless-running)))
(add-hook 'c-mode-common-hook #'+cc|init-rtags) (add-hook! (c-mode-local-vars c++-mode-local-vars objc-mode-local-vars)
#'+cc|init-rtags)
:config :config
(setq rtags-autostart-diagnostics t (setq rtags-autostart-diagnostics t
rtags-use-bookmarks nil rtags-use-bookmarks nil
@ -210,7 +221,6 @@ compilation database is present in the project.")
:definition #'rtags-find-symbol-at-point :definition #'rtags-find-symbol-at-point
:references #'rtags-find-references-at-point) :references #'rtags-find-references-at-point)
(add-hook 'doom-cleanup-hook #'+cc|cleanup-rtags)
(add-hook! 'kill-emacs-hook (ignore-errors (rtags-cancel-process))) (add-hook! 'kill-emacs-hook (ignore-errors (rtags-cancel-process)))
;; Use rtags-imenu instead of imenu/counsel-imenu ;; Use rtags-imenu instead of imenu/counsel-imenu
@ -224,17 +234,16 @@ compilation database is present in the project.")
;; ;;
;; LSP ;; LSP
(def-package! cquery (def-package! ccls
:when (featurep! +lsp) :when (featurep! +lsp)
:hook ((c-mode c++-mode objc-mode) . +lsp|init-cquery) :hook ((c-mode-local-vars c++-mode-local-vars objc-mode-local-vars) . +cc|init-ccls)
:config :config
(defun +lsp|init-cquery () (defun +cc|init-ccls ()
(setq-local company-transformers nil) (setq-local company-transformers nil)
(setq-local company-lsp-async t)
(setq-local company-lsp-cache-candidates nil) (setq-local company-lsp-cache-candidates nil)
(condition-case nil (lsp))
(lsp) (after! projectile
(user-error nil))) (add-to-list 'projectile-globally-ignored-directories ".ccls-cache")
(setq cquery-extra-init-params (add-to-list 'projectile-project-root-files-bottom-up ".ccls-root")
'(:index (:comments 2) (add-to-list 'projectile-project-root-files-top-down-recurring "compile_commands.json")))
:cacheFormat "msgpack"
:completion (:detailedLabel t))))

View file

@ -1,10 +1,11 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*- ;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/cc/doctor.el ;;; lang/cc/doctor.el
;; rtags (when (require 'rtags nil t)
(let ((bins (cl-remove-if #'executable-find '("rdm" "rc")))) ;; rtags
(when (/= (length bins) 0) (let ((bins (cl-remove-if #'executable-find `(,rtags-rdm-binary-name ,rtags-rc-binary-name))))
(warn! "Couldn't find the rtag client and/or server programs %s. Disabling rtags support" bins))) (when (/= (length bins) 0)
(warn! "Couldn't find the rtag client and/or server programs %s. Disabling rtags support" bins))))
;; irony server ;; irony server
(when (require 'irony nil t) (when (require 'irony nil t)

View file

@ -13,7 +13,7 @@
(package! company-glsl :recipe (:fetcher github :repo "Kaali/company-glsl")))) (package! company-glsl :recipe (:fetcher github :repo "Kaali/company-glsl"))))
(if (featurep! +lsp) (if (featurep! +lsp)
(package! cquery) (package! ccls)
(when (package! irony) (when (package! irony)
(package! irony-eldoc) (package! irony-eldoc)
(when (featurep! :tools flycheck) (when (featurep! :tools flycheck)

View file

@ -1,110 +1,112 @@
;;; lang/clojure/config.el -*- lexical-binding: t; -*- ;;; lang/clojure/config.el -*- lexical-binding: t; -*-
;; `clojure-mode' ;; `clojure-mode'
(after! clojure-mode (add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
(add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
(def-package! cider
;; NOTE: if you don't have an org directory set (the dir doesn't exist),
;; cider jack in won't work.
:commands (cider-jack-in cider-jack-in-clojurescript)
:hook (clojure-mode-local-vars . cider-mode)
:init
(set-repl-handler! 'clojure-mode #'+clojure/repl)
(set-eval-handler! 'clojure-mode #'cider-eval-region)
(set-lookup-handlers! 'clojure-mode
:definition #'cider-find-dwim
:documentation #'cider-doc)
(add-hook 'cider-mode-hook #'eldoc-mode)
:config
(set-popup-rules! (set-popup-rules!
'(("^\\*cider-error*" :ignore t) '(("^\\*cider-error*" :ignore t)
("^\\*cider-repl" :quit nil) ("^\\*cider-repl" :quit nil)
("^\\*cider-repl-history" :vslot 2 :ttl nil))) ("^\\*cider-repl-history" :vslot 2 :ttl nil)))
(def-package! cider
;; NOTE: if you don't have an org directory set (the dir doesn't exist),
;; cider jack in won't work.
:commands (cider-jack-in cider-jack-in-clojurescript)
:hook (clojure-mode . cider-mode)
:init
(set-repl-handler! 'clojure-mode #'+clojure/repl)
(set-eval-handler! 'clojure-mode #'cider-eval-region)
(set-lookup-handlers! 'clojure-mode
:definition #'cider-find-dwim
:documentation #'cider-doc)
(add-hook 'cider-mode-hook #'eldoc-mode)
:config
(setq nrepl-hide-special-buffers t
nrepl-log-messages nil
cider-font-lock-dynamically '(macro core function var)
cider-overlays-use-font-lock t
cider-prompt-for-symbol nil
cider-repl-display-help-banner nil
cider-repl-history-display-duplicates nil
cider-repl-history-display-style 'one-line
cider-repl-history-file (concat doom-cache-dir "cider-repl-history")
cider-repl-history-highlight-current-entry t
cider-repl-history-quit-action 'delete-and-restore
cider-repl-history-highlight-inserted-item t
cider-repl-history-size 1000
cider-repl-pop-to-buffer-on-connect 'display-only
cider-repl-result-prefix ";; => "
cider-repl-print-length 100
cider-repl-use-clojure-font-lock t
cider-repl-use-pretty-printing t
cider-repl-wrap-history nil
cider-stacktrace-default-filters '(tooling dup))
(map! (:localleader (setq nrepl-hide-special-buffers t
(:map clojure-mode-map nrepl-log-messages nil
"'" #'cider-jack-in cider-font-lock-dynamically '(macro core function var)
"\"" #'cider-jack-in-clojurescript cider-overlays-use-font-lock t
cider-prompt-for-symbol nil
cider-repl-display-help-banner nil
cider-repl-history-display-duplicates nil
cider-repl-history-display-style 'one-line
cider-repl-history-file (concat doom-cache-dir "cider-repl-history")
cider-repl-history-highlight-current-entry t
cider-repl-history-quit-action 'delete-and-restore
cider-repl-history-highlight-inserted-item t
cider-repl-history-size 1000
cider-repl-pop-to-buffer-on-connect 'display-only
cider-repl-result-prefix ";; => "
cider-repl-print-length 100
cider-repl-use-clojure-font-lock t
cider-repl-use-pretty-printing t
cider-repl-wrap-history nil
cider-stacktrace-default-filters '(tooling dup))
(:prefix ("e" . "eval") (map! (:localleader
"d" #'cider-eval-defun-at-point (:map clojure-mode-map
"D" #'cider-insert-defun-in-repl "'" #'cider-jack-in
"e" #'cider-eval-last-sexp "\"" #'cider-jack-in-clojurescript
"E" #'cider-insert-last-sexp-in-repl
"r" #'cider-eval-region
"R" #'cider-insert-region-in-repl
"u" #'cider-undef)
(:prefix ("g" . "go/jump")
"b" #'cider-pop-back
"g" #'cider-find-var
"n" #'cider-find-ns)
(:prefix ("h" . "help")
"n" #'cider-find-ns
"a" #'cider-apropos
"d" #'cider-doc
"g" #'cider-grimoire-web
"j" #'cider-javadoc)
(:prefix ("i" . "inspect")
"i" #'cider-inspect
"r" #'cider-inspect-last-result)
(:prefix ("m" . "macro")
"e" #'cider-macroexpand-1
"E" #'cider-macroexpand-al)
(:prefix ("n" . "namespace")
"n" #'cider-browse-ns
"N" #'cider-browse-ns-all)
(:prefix ("r" . "repl")
"n" #'cider-repl-set-ns
"q" #'cider-quit
"r" #'cider-refresh
"R" #'cider-restart
"b" #'cider-switch-to-repl-buffer
"B" #'+clojure/cider-switch-to-repl-buffer-and-switch-ns
"c" #'cider-repl-clear-buffer)))
(:when (featurep! :feature evil +everywhere) (:prefix ("e" . "eval")
:map cider-repl-mode-map "d" #'cider-eval-defun-at-point
:i [S-return] #'cider-repl-newline-and-indent "D" #'cider-insert-defun-in-repl
:map cider-repl-history-mode-map "e" #'cider-eval-last-sexp
:i [return] #'cider-repl-history-insert-and-quit "E" #'cider-insert-last-sexp-in-repl
:i "q" #'cider-repl-history-quit "r" #'cider-eval-region
:i "l" #'cider-repl-history-occur "R" #'cider-insert-region-in-repl
:i "s" #'cider-repl-history-search-forward "u" #'cider-undef)
:i "r" #'cider-repl-history-search-backward (:prefix ("g" . "go/jump")
:i "U" #'cider-repl-history-undo-other-window))) "b" #'cider-pop-back
"g" #'cider-find-var
"n" #'cider-find-ns)
(:prefix ("h" . "help")
"n" #'cider-find-ns
"a" #'cider-apropos
"d" #'cider-doc
"g" #'cider-grimoire-web
"j" #'cider-javadoc)
(:prefix ("i" . "inspect")
"i" #'cider-inspect
"r" #'cider-inspect-last-result)
(:prefix ("m" . "macro")
"e" #'cider-macroexpand-1
"E" #'cider-macroexpand-al)
(:prefix ("n" . "namespace")
"n" #'cider-browse-ns
"N" #'cider-browse-ns-all)
(:prefix ("r" . "repl")
"n" #'cider-repl-set-ns
"q" #'cider-quit
"r" #'cider-refresh
"R" #'cider-restart
"b" #'cider-switch-to-repl-buffer
"B" #'+clojure/cider-switch-to-repl-buffer-and-switch-ns
"c" #'cider-repl-clear-buffer)))
(def-package! clj-refactor (:when (featurep! :feature evil +everywhere)
:hook (clojure-mode . clj-refactor-mode) :map cider-repl-mode-map
:init :i [S-return] #'cider-repl-newline-and-indent
(set-lookup-handlers! 'clojure-mode :map cider-repl-history-mode-map
:references #'cljr-find-usages) :i [return] #'cider-repl-history-insert-and-quit
:config :i "q" #'cider-repl-history-quit
(map! :map clojure-mode-map :i "l" #'cider-repl-history-occur
:localleader :i "s" #'cider-repl-history-search-forward
:desc "refactor" "R" #'hydra-cljr-help-menu/body)) :i "r" #'cider-repl-history-search-backward
:i "U" #'cider-repl-history-undo-other-window)))
(def-package! flycheck-joker
:when (featurep! :tools flycheck) (def-package! clj-refactor
:after flycheck)) :hook (clojure-mode . clj-refactor-mode)
:init
(set-lookup-handlers! 'clojure-mode
:references #'cljr-find-usages)
:config
(map! :map clojure-mode-map
:localleader
:desc "refactor" "R" #'hydra-cljr-help-menu/body))
(def-package! flycheck-joker
:when (featurep! :tools flycheck)
:after flycheck)

View file

@ -3,8 +3,11 @@
;; `coq' ;; `coq'
(setq proof-electric-terminator-enable t) (setq proof-electric-terminator-enable t)
;; We've replaced coq-mode abbrevs with yasnippet snippets (in the snippets
;; library included with Doom).
(setq coq-mode-abbrev-table '()) (setq coq-mode-abbrev-table '())
(after! company-coq (after! company-coq
(set-popup-rule! "^\\*\\(?:response\\|goals\\)\\*" :ignore t) (set-popup-rule! "^\\*\\(?:response\\|goals\\)\\*" :ignore t)
(set-lookup-handlers! 'company-coq-mode (set-lookup-handlers! 'company-coq-mode

View file

@ -3,20 +3,10 @@
(def-package! elixir-mode (def-package! elixir-mode
:defer t :defer t
:init :init
;; Disable default smartparens config; there are too many, they're intrusive ;; Disable default smartparens config. There are too many pairs; we only want
;; and we only want a subset of them (defined below). ;; a subset of them (defined below).
(provide 'smartparens-elixir) (provide 'smartparens-elixir)
:config :config
;; ...and only complete the basics
(after! smartparens
(sp-with-modes 'elixir-mode
(sp-local-pair "do" "end"
:when '(("RET" "<evil-ret>"))
:unless '(sp-in-comment-p sp-in-string-p)
:post-handlers '("||\n[i]"))
(sp-local-pair "do " " end" :unless '(sp-in-comment-p sp-in-string-p))
(sp-local-pair "fn " " end" :unless '(sp-in-comment-p sp-in-string-p))))
(set-pretty-symbols! 'elixir-mode (set-pretty-symbols! 'elixir-mode
;; Functional ;; Functional
:def "def" :def "def"
@ -30,6 +20,16 @@
:for "for" :for "for"
:return "return" :yield "use") :return "return" :yield "use")
;; ...and only complete the basics
(after! smartparens
(sp-with-modes 'elixir-mode
(sp-local-pair "do" "end"
:when '(("RET" "<evil-ret>"))
:unless '(sp-in-comment-p sp-in-string-p)
:post-handlers '("||\n[i]"))
(sp-local-pair "do " " end" :unless '(sp-in-comment-p sp-in-string-p))
(sp-local-pair "fn " " end" :unless '(sp-in-comment-p sp-in-string-p))))
(def-package! alchemist-company (def-package! alchemist-company
:when (featurep! :completion company) :when (featurep! :completion company)
:commands alchemist-company :commands alchemist-company

View file

@ -5,6 +5,7 @@
(after! elm-mode (after! elm-mode
(add-hook 'elm-mode-hook #'rainbow-delimiters-mode) (add-hook 'elm-mode-hook #'rainbow-delimiters-mode)
(set-company-backend! 'elm-mode 'company-elm) (set-company-backend! 'elm-mode 'company-elm)
(set-repl-handler! 'elm-mode #'run-elm-interactive) (set-repl-handler! 'elm-mode #'run-elm-interactive)
(set-pretty-symbols! 'elm-mode (set-pretty-symbols! 'elm-mode
@ -22,4 +23,3 @@
:when (featurep! :tools flycheck) :when (featurep! :tools flycheck)
:after elm-mode :after elm-mode
:config (add-to-list 'flycheck-checkers 'elm nil #'eq)) :config (add-to-list 'flycheck-checkers 'elm nil #'eq))

View file

@ -9,7 +9,8 @@
to a pop up buffer." to a pop up buffer."
(require 'pp) (require 'pp)
(let ((result (let ((result
(let ((debug-on-error t)) (let ((debug-on-error t)
(doom--current-module (ignore-errors (doom-module-from-path buffer-file-name))))
(eval (read (eval (read
(concat "(progn " (concat "(progn "
(buffer-substring-no-properties beg end) (buffer-substring-no-properties beg end)
@ -97,16 +98,17 @@ library/userland functions"
(defun +emacs-lisp|extend-imenu () (defun +emacs-lisp|extend-imenu ()
"Improve imenu support with better expression regexps and Doom-specific forms." "Improve imenu support with better expression regexps and Doom-specific forms."
(setq imenu-generic-expression (setq imenu-generic-expression
'(("Evil Commands" "^\\s-*(evil-define-\\(?:command\\|operator\\|motion\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1) '(("Evil commands" "^\\s-*(evil-define-\\(?:command\\|operator\\|motion\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Unit tests" "^\\s-*(\\(?:ert-deftest\\|describe\\) +\"\\([^\")]+\\)\"" 1) ("Unit tests" "^\\s-*(\\(?:ert-deftest\\|describe\\) +\"\\([^\")]+\\)\"" 1)
("Package" "^\\s-*(\\(?:def-\\)?package! +\\(\\_<[^ ()\n]+\\_>\\)" 1) ("Package" "^\\s-*(\\(?:def-\\)?package! +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Package" "^\\s-*;;;###package\\s-+\\(\\_<[^ ()\n]+\\_>\\)$" 1)
("Major modes" "^\\s-*(define-derived-mode +\\([^ ()\n]+\\)" 1) ("Major modes" "^\\s-*(define-derived-mode +\\([^ ()\n]+\\)" 1)
("Modelines" "^\\s-*(def-modeline! +\\([^ ()\n]+\\)" 1) ("Modelines" "^\\s-*(def-modeline! +\\([^ ()\n]+\\)" 1)
("Modeline Segments" "^\\s-*(def-modeline-segment! +\\([^ ()\n]+\\)" 1) ("Modeline segments" "^\\s-*(def-modeline-segment! +\\([^ ()\n]+\\)" 1)
("Advice" "^\\s-*(def\\(?:\\(?:ine-\\)?advice\\))") ("Advice" "^\\s-*(def\\(?:\\(?:ine-\\)?advice\\))")
("Modes" "^\\s-*(define-\\(?:global\\(?:ized\\)?-minor\\|generic\\|minor\\)-mode +\\([^ ()\n]+\\)" 1) ("Modes" "^\\s-*(define-\\(?:global\\(?:ized\\)?-minor\\|generic\\|minor\\)-mode +\\([^ ()\n]+\\)" 1)
("Macros" "^\\s-*(\\(?:cl-\\)?def\\(?:ine-compile-macro\\|macro\\) +\\([^ )\n]+\\)" 1) ("Macros" "^\\s-*(\\(?:cl-\\)?def\\(?:ine-compile-macro\\|macro\\) +\\([^ )\n]+\\)" 1)
("Inline Functions" "\\s-*(\\(?:cl-\\)?defsubst +\\([^ )\n]+\\)" 1) ("Inline functions" "\\s-*(\\(?:cl-\\)?defsubst +\\([^ )\n]+\\)" 1)
("Functions" "^\\s-*(\\(?:cl-\\)?def\\(?:un\\|un\\*\\|method\\|generic\\|-memoized!\\) +\\([^ ,)\n]+\\)" 1) ("Functions" "^\\s-*(\\(?:cl-\\)?def\\(?:un\\|un\\*\\|method\\|generic\\|-memoized!\\) +\\([^ ,)\n]+\\)" 1)
("Variables" "^\\s-*(\\(def\\(?:c\\(?:onst\\(?:ant\\)?\\|ustom\\)\\|ine-symbol-macro\\|parameter\\|var\\(?:-local\\)?\\)\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2) ("Variables" "^\\s-*(\\(def\\(?:c\\(?:onst\\(?:ant\\)?\\|ustom\\)\\|ine-symbol-macro\\|parameter\\|var\\(?:-local\\)?\\)\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2)
("Types" "^\\s-*(\\(cl-def\\(?:struct\\|type\\)\\|def\\(?:class\\|face\\|group\\|ine-\\(?:condition\\|error\\|widget\\)\\|package\\|struct\\|t\\(?:\\(?:hem\\|yp\\)e\\)\\)\\)\\s-+'?\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2)))) ("Types" "^\\s-*(\\(cl-def\\(?:struct\\|type\\)\\|def\\(?:class\\|face\\|group\\|ine-\\(?:condition\\|error\\|widget\\)\\|package\\|struct\\|t\\(?:\\(?:hem\\|yp\\)e\\)\\)\\)\\s-+'?\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 2))))
@ -121,3 +123,11 @@ library/userland functions"
if (file-in-directory-p buffer-file-name dir) if (file-in-directory-p buffer-file-name dir)
return t))) return t)))
(flycheck-mode -1))) (flycheck-mode -1)))
;;;###autoload
(defun +emacs-lisp-lookup-documentation (thing)
"Lookup THING with `helpful-variable' if it's a variable, `helpful-callable'
if it's callable, `apropos' otherwise."
(if thing
(doom/describe-symbol thing)
(call-interactively #'doom/describe-symbol)))

View file

@ -3,6 +3,11 @@
(defvar +emacs-lisp-enable-extra-fontification t (defvar +emacs-lisp-enable-extra-fontification t
"If non-nil, highlight special forms, and defined functions and variables.") "If non-nil, highlight special forms, and defined functions and variables.")
(defvar +emacs-lisp-outline-regexp "[ \t]*;;;;* [^ \t\n]"
"Regexp to use for `outline-regexp' in `emacs-lisp-mode'.
This marks a foldable marker for `outline-minor-mode' in elisp buffers.")
;; `elisp-mode' is loaded at startup. In order to lazy load its config we need ;; `elisp-mode' is loaded at startup. In order to lazy load its config we need
;; to pretend it isn't loaded ;; to pretend it isn't loaded
(defer-feature! elisp-mode emacs-lisp-mode) (defer-feature! elisp-mode emacs-lisp-mode)
@ -11,14 +16,14 @@
;; ;;
;; Config ;; Config
(add-to-list 'auto-mode-alist '("\\.Cask\\'" . emacs-lisp-mode)) (def-package! elisp-mode
:mode ("\\.Cask\\'" . emacs-lisp-mode)
(after! elisp-mode :config
(set-repl-handler! 'emacs-lisp-mode #'+emacs-lisp/open-repl) (set-repl-handler! 'emacs-lisp-mode #'+emacs-lisp/open-repl)
(set-eval-handler! 'emacs-lisp-mode #'+emacs-lisp-eval) (set-eval-handler! 'emacs-lisp-mode #'+emacs-lisp-eval)
(set-lookup-handlers! 'emacs-lisp-mode (set-lookup-handlers! 'emacs-lisp-mode
:definition #'elisp-def :definition #'elisp-def
:documentation #'info-lookup-symbol) :documentation #'+emacs-lisp-lookup-documentation)
(set-docsets! 'emacs-lisp-mode "Emacs Lisp") (set-docsets! 'emacs-lisp-mode "Emacs Lisp")
(set-pretty-symbols! 'emacs-lisp-mode :lambda "lambda") (set-pretty-symbols! 'emacs-lisp-mode :lambda "lambda")
(set-rotate-patterns! 'emacs-lisp-mode (set-rotate-patterns! 'emacs-lisp-mode
@ -35,14 +40,15 @@
mode-name "Elisp" mode-name "Elisp"
;; Don't treat autoloads or sexp openers as outline headers, we have ;; Don't treat autoloads or sexp openers as outline headers, we have
;; hideshow for that. ;; hideshow for that.
outline-regexp ";;;;* [^ \t\n]") outline-regexp +emacs-lisp-outline-regexp)
;; variable-width indentation is superior in elisp ;; variable-width indentation is superior in elisp
(add-to-list 'doom-detect-indentation-excluded-modes 'emacs-lisp-mode nil #'eq) (add-to-list 'doom-detect-indentation-excluded-modes 'emacs-lisp-mode nil #'eq)
(add-hook! 'emacs-lisp-mode-hook (add-hook! 'emacs-lisp-mode-hook
#'(;; 3rd-party functionality #'(;; 3rd-party functionality
auto-compile-on-save-mode outline-minor-mode auto-compile-on-save-mode
outline-minor-mode
;; initialization ;; initialization
+emacs-lisp|extend-imenu)) +emacs-lisp|extend-imenu))
@ -54,7 +60,7 @@
(font-lock-add-keywords (font-lock-add-keywords
'emacs-lisp-mode 'emacs-lisp-mode
(append `(;; custom Doom cookies (append `(;; custom Doom cookies
("^;;;###\\(autodef\\|if\\)[ \n]" (1 font-lock-warning-face t))) ("^;;;###\\(autodef\\|if\\|package\\)[ \n]" (1 font-lock-warning-face t)))
;; highlight defined, special variables & functions ;; highlight defined, special variables & functions
(when +emacs-lisp-enable-extra-fontification (when +emacs-lisp-enable-extra-fontification
`((+emacs-lisp-highlight-vars-and-faces . +emacs-lisp--face))))) `((+emacs-lisp-highlight-vars-and-faces . +emacs-lisp--face)))))
@ -104,6 +110,7 @@
;; `overseer' ;; `overseer'
(autoload 'overseer-test "overseer" nil t) (autoload 'overseer-test "overseer" nil t)
(remove-hook 'emacs-lisp-mode-hook 'overseer-enable-mode)
(def-package! flycheck-cask (def-package! flycheck-cask
@ -114,12 +121,20 @@
(add-hook 'flycheck-mode-hook #'flycheck-cask-setup nil t))) (add-hook 'flycheck-mode-hook #'flycheck-cask-setup nil t)))
(def-package! elisp-demos
:defer t
:init
(advice-add 'describe-function-1 :after #'elisp-demos-advice-describe-function-1)
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
;; ;;
;; Project modes ;; Project modes
(def-project-mode! +emacs-lisp-ert-mode (def-project-mode! +emacs-lisp-ert-mode
:modes (emacs-lisp-mode) :modes (emacs-lisp-mode)
:match "/test[/-].+\\.el$") :match "/test[/-].+\\.el$"
:add-hooks (overseer-enable-mode))
(associate! buttercup-minor-mode (associate! buttercup-minor-mode
:modes (emacs-lisp-mode) :modes (emacs-lisp-mode)

View file

@ -1,11 +1,14 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; lang/emacs-lisp/packages.el ;;; lang/emacs-lisp/packages.el
(package! elisp-mode :built-in t)
(package! auto-compile) (package! auto-compile)
(package! highlight-quoted) (package! highlight-quoted)
(package! macrostep) (package! macrostep)
(package! overseer) (package! overseer)
(package! elisp-def) (package! elisp-def)
(package! elisp-demos)
(when (featurep! :tools flycheck) (when (featurep! :tools flycheck)
(package! flycheck-cask)) (package! flycheck-cask))

View file

@ -1,11 +1,9 @@
;;; private/erlang/config.el -*- lexical-binding: t; -*- ;;; lang/erlang/config.el -*- lexical-binding: t; -*-
(dolist (regexp '("\\.erlang$" (def-package! erlang
;; rebar files :mode ("\\.erlang$" . erlang-mode)
"/rebar\\.config\\(?:\\.script\\)?$" :mode ("/rebar\\.config\\(?:\\.script\\)?$" . erlang-mode)
;; erlang configs :mode ("/\\(?:app\\|sys\\)\\.config$" . erlang-mode))
"/\\(?:app\\|sys\\)\\.config$"))
(add-to-list 'auto-mode-alist (cons regexp 'erlang-mode)))
(def-package! flycheck-rebar3 (def-package! flycheck-rebar3

View file

@ -9,6 +9,7 @@
:config :config
(setq ess-offset-continued 'straight (setq ess-offset-continued 'straight
ess-expression-offset 2 ess-expression-offset 2
ess-use-flymake (not (featurep! :tools flycheck))
ess-nuke-trailing-whitespace-p t ess-nuke-trailing-whitespace-p t
ess-default-style 'DEFAULT ess-default-style 'DEFAULT
ess-history-directory (expand-file-name "ess-history/" doom-cache-dir)) ess-history-directory (expand-file-name "ess-history/" doom-cache-dir))

View file

@ -21,7 +21,7 @@
"goimports")))) "goimports"))))
(if (featurep! +lsp) (if (featurep! +lsp)
(add-hook 'go-mode-hook #'+lsp|init) (add-hook 'go-mode-hook #'lsp!)
(add-hook 'go-mode-hook #'go-eldoc-setup)) (add-hook 'go-mode-hook #'go-eldoc-setup))
(map! :map go-mode-map (map! :map go-mode-map

View file

@ -0,0 +1,8 @@
;;; lang/haskell/+lsp.el -*- lexical-binding: t; -*-
(def-package! lsp-haskell
:after haskell-mode
:init (add-hook 'haskell-mode-hook #'lsp!)
:config
;; Does some strange indentation if it pastes in the snippet
(setq-hook! 'haskell-mode-hook yas-indent-line 'fixed))

View file

@ -1,23 +1,26 @@
;;; lang/haskell/config.el -*- lexical-binding: t; -*- ;;; lang/haskell/config.el -*- lexical-binding: t; -*-
(cond ((featurep! +intero) (load! "+intero")) (cond ((featurep! +intero) (load! "+intero"))
((featurep! +dante) (load! "+dante"))) ((featurep! +dante) (load! "+dante"))
((featurep! +lsp) (load! "+lsp")))
;; ;;
;; Common packages ;; Common packages
(after! haskell-mode (after! haskell-mode
(setq haskell-process-suggest-remove-import-lines t ; warnings for redundant imports etc (setq haskell-process-suggest-remove-import-lines t ; warnings for redundant imports etc
haskell-process-auto-import-loaded-modules t) haskell-process-auto-import-loaded-modules t
(when (featurep! :tools flycheck) haskell-process-show-overlays (not (featurep! :tools flycheck))) ; redundant with flycheck
(setq haskell-process-show-overlays nil)) ; flycheck makes this unnecessary
(add-hook! 'haskell-mode-hook
#'(haskell-collapse-mode ; support folding haskell code blocks
interactive-haskell-mode))
(set-lookup-handlers! 'haskell-mode :definition #'haskell-mode-jump-to-def-or-tag) (set-lookup-handlers! 'haskell-mode :definition #'haskell-mode-jump-to-def-or-tag)
(set-file-template! 'haskell-mode :trigger #'haskell-auto-insert-module-template :project t) (set-file-template! 'haskell-mode :trigger #'haskell-auto-insert-module-template :project t)
(set-repl-handler! '(haskell-mode haskell-cabal-mode literate-haskell-mode) #'+haskell/open-repl) (set-repl-handler! '(haskell-mode haskell-cabal-mode literate-haskell-mode) #'+haskell/open-repl)
(add-hook! 'haskell-mode-hook
#'(haskell-collapse-mode ; support folding haskell code blocks
interactive-haskell-mode))
(add-to-list 'completion-ignored-extensions ".hi") (add-to-list 'completion-ignored-extensions ".hi")
(map! :localleader (map! :localleader

View file

@ -7,4 +7,6 @@
(package! dante) (package! dante)
(package! attrap)) (package! attrap))
((featurep! +intero) ((featurep! +intero)
(package! intero))) (package! intero))
((featurep! +lsp)
(package! lsp-haskell)))

View file

@ -3,7 +3,7 @@
(def-package! lsp-java (def-package! lsp-java
:after-call java-mode :after-call java-mode
:init (add-hook 'java-mode-hook #'+lsp|init) :init (add-hook 'java-mode-hook #'lsp!)
:config :config
;; TODO keybinds ;; TODO keybinds
;; TODO treemacs integration (?) ;; TODO treemacs integration (?)

View file

@ -23,11 +23,8 @@ If the depth is 2, the first two directories are removed: net.lissner.game.")
(add-hook 'java-mode-hook #'rainbow-delimiters-mode) (add-hook 'java-mode-hook #'rainbow-delimiters-mode)
(cond ((featurep! +lsp) (load! "+lsp")) (cond ((featurep! +lsp) (load! "+lsp"))
((featurep! +meghanada) (load! "+meghanada")) ((featurep! +meghanada) (load! "+meghanada")))
;; TODO lang/java +lsp (lsp-java?)
;; ((featurep! +lsp) (load! "+lsp"))
)
;; ;;

View file

@ -54,6 +54,9 @@
(set-electric! 'js2-mode :chars '(?\} ?\) ?. ?:)) (set-electric! 'js2-mode :chars '(?\} ?\) ?. ?:))
(set-repl-handler! 'js2-mode #'+javascript/open-repl) (set-repl-handler! 'js2-mode #'+javascript/open-repl)
(after! projectile
(add-to-list 'projectile-globally-ignored-directories "node_modules"))
(map! :map js2-mode-map (map! :map js2-mode-map
:localleader :localleader
"S" #'+javascript/skewer-this-buffer)) "S" #'+javascript/skewer-this-buffer))
@ -123,7 +126,7 @@
;; Tools ;; Tools
(when (featurep! +lsp) (when (featurep! +lsp)
(add-hook! (js2-mode rjsx-mode typescript-mode) #'+lsp|init)) (add-hook! (js2-mode rjsx-mode typescript-mode) #'lsp!))
(def-package! tide (def-package! tide
@ -157,14 +160,15 @@
;; navigation ;; navigation
(set-lookup-handlers! 'tide-mode :async t (set-lookup-handlers! 'tide-mode :async t
:definition #'tide-jump-to-definition :definition #'tide-jump-to-definition
:references #'tide-references :references #'tide-references)
:documentation #'tide-documentation-at-point)
;; resolve to `doom-project-root' if `tide-project-root' fails ;; resolve to `doom-project-root' if `tide-project-root' fails
(advice-add #'tide-project-root :override #'+javascript*tide-project-root) (advice-add #'tide-project-root :override #'+javascript*tide-project-root)
;; cleanup tsserver when no tide buffers are left ;; cleanup tsserver when no tide buffers are left
(add-hook! 'tide-mode-hook (add-hook! 'tide-mode-hook
(add-hook 'kill-buffer-hook #'+javascript|cleanup-tide-processes nil t)) (add-hook 'kill-buffer-hook #'+javascript|cleanup-tide-processes nil t))
(define-key tide-mode-map [remap +lookup/documentation] #'tide-documentation-at-point)
(map! :localleader (map! :localleader
:map tide-mode-map :map tide-mode-map
"R" #'tide-restart-server "R" #'tide-restart-server

View file

@ -1,5 +1,10 @@
;;; lang/latex/+ref.el -*- lexical-binding: t; -*- ;;; lang/latex/+ref.el -*- lexical-binding: t; -*-
(when (stringp +latex-bibtex-file)
(setq bibtex-completion-bibliography (list (expand-file-name +latex-bibtex-file))
reftex-default-bibliography bibtex-completion-bibliography))
(def-package! reftex (def-package! reftex
:hook (LaTeX-mode . reftex-mode) :hook (LaTeX-mode . reftex-mode)
:config :config

View file

@ -1,6 +1,6 @@
;;; lang/latex/+viewers.el -*- lexical-binding: t; -*- ;;; lang/latex/+viewers.el -*- lexical-binding: t; -*-
(cl-block 'viewer (catch 'found-viewer
(dolist (viewer +latex-viewers) (dolist (viewer +latex-viewers)
(if (pcase viewer (if (pcase viewer
(`skim (`skim
@ -33,7 +33,7 @@
;; Update PDF buffers after successful LaTeX runs ;; Update PDF buffers after successful LaTeX runs
(add-hook 'TeX-after-compilation-finished-function #'TeX-revert-document-buffer)))) (add-hook 'TeX-after-compilation-finished-function #'TeX-revert-document-buffer))))
(cl-return-from 'viewer))) (throw 'found-viewer t)))
;; fall back to latex-preview-pane ;; fall back to latex-preview-pane
(add-to-list 'TeX-view-program-list '("preview-pane" latex-preview-pane-mode)) (add-to-list 'TeX-view-program-list '("preview-pane" latex-preview-pane-mode))
@ -44,7 +44,6 @@
(setq latex-preview-pane-multifile-mode 'auctex) (setq latex-preview-pane-multifile-mode 'auctex)
(define-key! doc-view-mode-map (define-key! doc-view-mode-map
(kbd "ESC") #'delete-window "ESC" #'delete-window
"q" #'delete-window "q" #'delete-window
"k" (λ! (quit-window) (delete-window)))) "k" (λ! (quit-window) (delete-window))))

View file

@ -14,7 +14,7 @@
(let* ((offset LaTeX-indent-level) (let* ((offset LaTeX-indent-level)
(contin (or (and (boundp '+latex-indent-level-item-continuation) (contin (or (and (boundp '+latex-indent-level-item-continuation)
+latex-indent-level-item-continuation) +latex-indent-level-item-continuation)
(* 4 LaTeX-indent-level))) (* 4 offset)))
(re-beg "\\\\begin{") (re-beg "\\\\begin{")
(re-end "\\\\end{") (re-end "\\\\end{")
(re-env "\\(itemize\\|\\enumerate\\|description\\)") (re-env "\\(itemize\\|\\enumerate\\|description\\)")
@ -37,8 +37,7 @@
indent) indent)
((looking-at "\\\\item") ((looking-at "\\\\item")
(+ offset indent)) (+ offset indent))
(t ((+ contin indent))))))
(+ contin indent))))))
;;;###autoload ;;;###autoload
(defun +latex-symbols-company-backend (command &optional arg &rest _ignored) (defun +latex-symbols-company-backend (command &optional arg &rest _ignored)

View file

@ -54,6 +54,8 @@ If no viewers are found, `latex-preview-pane' is used.")
(add-hook 'TeX-mode-hook #'visual-line-mode) (add-hook 'TeX-mode-hook #'visual-line-mode)
;; Fold TeX macros ;; Fold TeX macros
(add-hook 'TeX-mode-hook #'TeX-fold-mode) (add-hook 'TeX-mode-hook #'TeX-fold-mode)
;; Enable rainbow mode after applying styles to the buffer
(add-hook 'TeX-mode-hook #'rainbow-delimiters-mode)
;; display output of latex commands in popup ;; display output of latex commands in popup
(set-popup-rule! " output\\*$" :size 15) (set-popup-rule! " output\\*$" :size 15)
;; Do not prompt for Master files, this allows auto-insert to add templates to ;; Do not prompt for Master files, this allows auto-insert to add templates to
@ -63,10 +65,7 @@ If no viewers are found, `latex-preview-pane' is used.")
(remove-hook 'find-file-hook (remove-hook 'find-file-hook
(cl-find-if #'byte-code-function-p find-file-hook) (cl-find-if #'byte-code-function-p find-file-hook)
'local)) 'local))
;; Enable rainbow mode after applying styles to the buffer (add-hook 'latex-mode-local-vars-hook #'flyspell-mode!)
(add-hook 'TeX-update-style-hook #'rainbow-delimiters-mode)
(when (featurep! :tools flyspell)
(add-hook 'latex-mode-local-vars-hook #'flyspell-mode))
;; All these excess pairs dramatically slow down typing in latex buffers, so ;; All these excess pairs dramatically slow down typing in latex buffers, so
;; we remove them. Let snippets do their job. ;; we remove them. Let snippets do their job.
(after! smartparens-latex (after! smartparens-latex

View file

@ -11,7 +11,7 @@
(let ((delim "~~")) (let ((delim "~~"))
(if (markdown-use-region-p) (if (markdown-use-region-p)
;; Active region ;; Active region
(cl-destructuring-bind (beg end) (cl-destructuring-bind (beg . end)
(markdown-unwrap-things-in-region (markdown-unwrap-things-in-region
(region-beginning) (region-end) (region-beginning) (region-end)
+markdown--regex-del 2 4) +markdown--regex-del 2 4)
@ -20,3 +20,23 @@
(if (thing-at-point-looking-at +markdown--regex-del) (if (thing-at-point-looking-at +markdown--regex-del)
(markdown-unwrap-thing-at-point nil 2 4) (markdown-unwrap-thing-at-point nil 2 4)
(markdown-wrap-or-insert delim delim 'word nil nil))))) (markdown-wrap-or-insert delim delim 'word nil nil)))))
;;;###autoload
(defun +markdown-flyspell-word-p ()
"Return t if point is on a word that should be spell checked.
Return nil if on a link url, markup, html, or references."
(let ((faces (doom-enlist (get-text-property (point) 'face))))
(or (and (memq 'font-lock-comment-face faces)
(memq 'markdown-code-face faces))
(not (cl-loop with unsafe-faces = '(markdown-reference-face
markdown-url-face
markdown-markup-face
markdown-comment-face
markdown-html-attr-name-face
markdown-html-attr-value-face
markdown-html-tag-name-face
markdown-code-face)
for face in faces
if (memq face unsafe-faces)
return t)))))

Some files were not shown because too many files have changed in this diff Show more