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)
Copyright (c) 2016-2018 Henrik Lissner.
Copyright (c) 2016-2019 Henrik Lissner.
Permission is hereby granted, free of charge, to any person obtaining
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"
"\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"
" -e --emacsd DIR\tUse the emacs config at DIR (e.g. ~/.emacs.d)\n"
" -i --insecure\t\tDisable TLS/SSL validation (not recommended)\n"
@ -46,7 +47,7 @@
(while (ignore-errors (string-prefix-p "-" (car args)))
(pcase (pop args)
((or "-h" "--help")
(error "Did you mean 'doom help'?"))
(push "help" args))
((or "-d" "--debug")
(setenv "DEBUG" "1")
(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; }
":"; exec emacs --quick --script "$0"; exit 0
;; Uses a couple simple heuristics to locate issues with your environment that
;; could interfere with running or setting up DOOM Emacs.
;; The Doom doctor is essentially one big, self-contained elisp shell script
;; 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
;; ships with MacOS).
;; In really old versions of Emacs `user-emacs-directory' isn't defined
(defvar user-emacs-directory (expand-file-name "../" (file-name-directory load-file-name)))
(unless (file-directory-p user-emacs-directory)
(error "Couldn't find a Doom config!"))
(unless noninteractive
(error "This script must not be run from an interactive session."))
(when (getenv "DEBUG")
(setq debug-on-error t))
(require 'pp)
@ -117,10 +124,10 @@
;; --- 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"))
(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)
(concat "\nMacOS users should use homebrew (https://brew.sh) to install Emacs\n"
" brew install emacs --with-modules --with-imagemagick --with-cocoa"))))
@ -166,7 +173,7 @@
font font-dest)
(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 "
"case, ignore this warning."))))))
"case feel free to ignore this warning."))))))
;; gnutls-cli & openssl
(section! "Checking gnutls/openssl...")
@ -289,6 +296,9 @@
(or (cdr-safe ex) (car ex)))
(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)
(section! "Checking your enabled modules...")
(let ((indent 4))
@ -296,22 +306,21 @@
(maphash
(lambda (key plist)
(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"))
(packages-file (doom-module-path (car key) (cdr key) "packages.el"))
doom-packages)
(when (or (file-exists-p doctor-file)
(file-exists-p packages-file))
(let ((doom--stage 'packages))
(when (load packages-file t t)
(cl-loop for (name . plist) in doom-packages
unless (or (doom-package-prop name :disable)
(doom-package-prop name :ignore t)
(package-built-in-p name)
(package-installed-p name))
do (error! "%s is not installed" name)))
(let ((doom--stage 'doctor))
(load doctor-file t t)))))
(packages-file (doom-module-path (car key) (cdr key) "packages.el")))
(cl-loop with doom--stage = 'packages
for name in (let (doom-packages
doom-disabled-packages)
(load packages-file 'noerror 'nomessage)
(mapcar #'car doom-packages))
unless (or (doom-package-prop name :disable)
(doom-package-prop name :ignore t)
(package-built-in-p name)
(package-installed-p name))
do (error! "%s is not installed" name))
(let ((doom--stage 'doctor))
(load doctor-file 'noerror 'nomessage)))
(file-missing (error! "%s" (error-message-string ex)))
(error (error! "Syntax error: %s" ex)))))
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
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
@ -54,7 +49,8 @@ BUF should be skipped over by functions like `next-buffer' and `other-buffer'."
(defun doom-fallback-buffer ()
"Returns the fallback buffer, creating it if necessary. By default this is the
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
(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))))
(message "Aborted")
(set-buffer-modified-p nil)
(when (or ;; if there aren't more real buffers than visible buffers,
;; then there are no real, non-visible buffers left.
(not (cl-set-difference (doom-real-buffer-list)
(doom-visible-buffers)))
;; if we end up back where we start (or previous-buffer
;; returns nil), we have nowhere left to go
(memq (previous-buffer) (list buf 'nil)))
(switch-to-buffer (doom-fallback-buffer)))
(kill-buffer buf)))
(let (buffer-list-update-hook)
(when (or ;; if there aren't more real buffers than visible buffers,
;; then there are no real, non-visible buffers left.
(not (cl-set-difference (doom-real-buffer-list)
(doom-visible-buffers)))
;; if we end up back where we start (or previous-buffer
;; returns nil), we have nowhere left to go
(memq (switch-to-prev-buffer nil t) (list buf 'nil)))
(switch-to-buffer (doom-fallback-buffer)))
(unless (delq (selected-window) (get-buffer-window-list buf nil t))
(kill-buffer buf)))))
((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)))
(kill-buffer buffer)
(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)))))
;;;###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
that belong to the current project."
(interactive "P")
(save-some-buffers)
(unless project-p
(delete-other-windows))
(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
(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
project."
(interactive "P")
(let ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list)))
(current-buffer (current-buffer)))
(dolist (buf buffers)
(unless (eq buf current-buffer)
(doom-kill-buffer-and-windows buf)))
(let ((buffers
(delq (current-buffer)
(if project-p (doom-project-buffer-list) (doom-buffer-list)))))
(mapc #'doom-kill-buffer-and-windows buffers)
(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
(defun doom/kill-matching-buffers (pattern &optional project-p)
@ -293,44 +299,23 @@ project."
(interactive
(list (read-regexp "Buffer pattern: ")
current-prefix-arg))
(let* ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list)))
(n (doom-kill-matching-buffers pattern buffers)))
(let* ((buffers (if project-p (doom-project-buffer-list) (doom-buffer-list))))
(doom-kill-matching-buffers pattern buffers)
(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
(defun doom/cleanup-session (arg &optional buffer-list)
"Clean up buried buries and orphaned processes in the current workspace. If
ALL-P (universal argument), clean them up globally."
(defun doom/kill-buried-buffers (&optional project-p)
"Kill buffers that are buried.
If PROJECT-P (universal argument), only kill buried buffers belonging to the
current project."
(interactive "P")
(let ((buffers (doom-buried-buffers buffer-list))
(n 0))
(dolist (buf buffers)
(unless (buffer-modified-p buf)
(kill-buffer buf)
(cl-incf n)))
(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))
(let ((buffers (doom-buried-buffers (if project-p (doom-project-buffer-list)))))
(mapc #'kill-buffer buffers)
(when (called-interactively-p 'interactive)
(message "Killed %d buffer(s)"
(- (length buffers)
(length (cl-remove-if-not #'buffer-live-p buffers)))))))

View file

@ -3,17 +3,38 @@
(require 'core-cli)
(defun doom--run (command &optional yes)
(let ((default-directory doom-emacs-dir)
(doom-auto-accept yes))
(let ((compilation-buffer-name-function (lambda (_) "*bin/doom*")))
(compile (format "bin/doom %s" command) t))
(while compilation-in-progress
(sit-for 1))
(when (y-or-n-p "Reload Doom config?")
(doom/reload))
(message "Done")))
(let* ((default-directory doom-emacs-dir)
(doom-auto-accept yes)
(buf (get-buffer-create " *bin/doom*"))
(wconf (current-window-configuration))
(ignore-window-parameters t)
(noninteractive t)
(standard-output
(lambda (char)
(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
(defun doom//update (&optional yes)
"TODO"
@ -24,7 +45,9 @@
(defun doom//upgrade (&optional yes)
"TODO"
(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
(defun doom//install (&optional yes)
@ -43,24 +66,3 @@
"TODO"
(interactive "P")
(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")
(or (ignore-errors
(require 'use-package)
(cl-loop for (name . plist) in (doom-get-packages :private t)
if (use-package-plist-delete (copy-sequence plist) :private)
(cl-loop for (name . plist) in (doom-find-packages :private t)
if (use-package-plist-delete (copy-sequence plist) :modules)
collect (format "%s" (cons name it))
else
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."
(interactive)
(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
emacs-version
(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)
(defun doom--run-vanilla-sandbox (&optional load-doom-p)
(defun doom--run-vanilla-sandbox (&optional mode)
(interactive)
(let ((contents (buffer-string))
(file (make-temp-file "doom-sandbox-")))
(require 'package)
(with-temp-file file
(insert
(prin1-to-string
`(cond (,load-doom-p
(setq doom-private-dir "/tmp/does/not/exist"
doom-modules ,doom-modules)
(load ,user-init-file))
((setq package--init-file-ensured t
package-user-dir ,package-user-dir
package-archives ',package-archives
user-emacs-directory ,doom-emacs-dir)
(package-initialize))))
(macroexp-progn
(append `((setq debug-on-error t
package--init-file-ensured t
package-user-dir ,package-user-dir
package-archives ',package-archives
user-emacs-directory ,doom-emacs-dir
doom-modules ,doom-modules))
(pcase mode
(`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"
(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)
(condition-case e
(cond ((display-graphic-p)
@ -174,30 +187,58 @@ pasting into a bug report or discord."
(delete-file file)
(signal (car e) (cdr e)))))))
(defun doom--run-vanilla-doom-sandbox ()
(interactive)
(doom--run-vanilla-sandbox t))
(fset 'doom--run-vanilla-emacs (lambda! (doom--run-vanilla-sandbox 'vanilla)))
(fset 'doom--run-vanilla-doom (lambda! (doom--run-vanilla-sandbox 'vanilla-doom)))
(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
(defun doom/open-vanilla-sandbox ()
"Open an Emacs Lisp buffer destinated to run in a blank Emacs session (and
optionally load only Doom and its modules, without your private config).
"Open the Emacs Lisp sandbox.
This provides a testbed for debugging code without Doom (or your private config)
standing in the way, and without sacrificing access to installed packages."
This is a test bed for running Emacs Lisp in an instance of Emacs with varying
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)
(let* ((buffer-name "*doom:vanilla-sandbox*")
(exists (get-buffer buffer-name))
(buf (get-buffer-create buffer-name)))
(with-current-buffer buf
(emacs-lisp-mode)
(local-set-key (kbd "C-c C-c") #'doom--run-vanilla-sandbox)
(local-set-key (kbd "C-c C-d") #'doom--run-vanilla-doom-sandbox)
(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")
(doom-sandbox-emacs-lisp-mode)
(setq header-line-format
(concat "C-c C-c = vanilla Emacs"
" / "
"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)
(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)))
(pop-to-buffer buf)))
@ -320,3 +361,14 @@ If INIT-FILE is non-nil, profile that instead of USER-INIT-FILE."
;;;###autoload
(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)
(delete-file old-path))
(kill-this-buffer)
(find-file new-path)
(doom--forget-file old-path new-path)
(doom--update-file new-path)
(find-file new-path)
(message "File successfully moved to %s" dest))))
(`overwrite-self (error "Cannot overwrite self"))
(`aborted (message "Aborted"))

View file

@ -1,45 +1,67 @@
;;; core/autoload/help.el -*- lexical-binding: t; -*-
(defvar doom--module-mode-alist
'((c-mode :lang cc)
(c++-mode :lang cc)
(objc++-mode :lang cc)
(java-mode :lang java)
(csharp-mode :lang csharp)
(clojure-mode :lang clojure)
'((dockerfile-mode :tools docker)
(haxor-mode :lang assembly)
(mips-mode :lang assembly)
(nasm-mode :lang assembly)
(c-mode :lang cc)
(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)
(go-mode :lang go)
(haskell-mode :lang haskell)
(js2-mode :lang javascript)
(julia-mode :lang julia)
(latex-mode :lang latex)
(LaTeX-mode :lang latex)
(ledger-mode :lang ledger)
(lua-mode :lang lua)
(markdown-mode :lang markdown)
(gfm-mode :lang markdown)
(ocaml-mode :lang ocaml)
(org-mode :lang org)
(perl-mode :lang perl)
(php-mode :lang php)
(hack-mode :lang php)
(plantuml-mode :lang plantuml)
(ess-r-mode :lang ess)
(ess-julia-mode :lang ess)
(go-mode :lang go)
(haskell-mode :lang haskell)
(hy-mode :lang hy)
(java-mode :lang java)
(js2-mode :lang javascript)
(rjsx-mode :lang javascript)
(typescript-mode :lang javascript)
(coffee-mode :lang javascript)
(julia-mode :lang julia)
(latex-mode :lang latex)
(LaTeX-mode :lang latex)
(ledger-mode :lang ledger)
(lua-mode :lang lua)
(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)
(python-mode :lang python)
(python-mode :lang python)
(restclient-mode :lang rest)
(ruby-mode :lang ruby)
(enh-ruby-mode :lang ruby)
(rust-mode :lang rust)
(scala-mode :lang scala)
(sh-mode :lang sh)
(swift-mode :lang swift)
(typescript-mode :lang typescript)
(web-mode :lang web)
(css-mode :lang web)
(scss-mode :lang web)
(sass-mode :lang web)
(less-css-mode :lang web)
(stylus-mode :lang web))
(ruby-mode :lang ruby)
(enh-ruby-mode :lang ruby)
(rust-mode :lang rust)
(scala-mode :lang scala)
(sh-mode :lang sh)
(swift-mode :lang swift)
(web-mode :lang web)
(css-mode :lang web)
(scss-mode :lang web)
(sass-mode :lang web)
(less-css-mode :lang web)
(stylus-mode :lang web))
"TODO")
@ -54,16 +76,17 @@
collect mode))
;;
;; Commands
;;;###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
(defun doom/describe-setters (setting)
"Open the documentation of Doom functions and configuration macros."
What is an autodef? It's a function or macro that is always defined, even if its
containing module is disabled (in which case it will safely no-op). This
syntactic sugar lets you use them without needing to check if they are
available."
(interactive
(let* ((settings
(cl-loop with case-fold-search = nil
@ -74,42 +97,52 @@
(string-match-p "[a-z]!$" sym-name))
collect sym))
(sym (symbol-at-point))
(setting
(autodef
(completing-read
"Describe setter: "
;; TODO Could be cleaner (refactor me!)
(cl-loop with maxwidth = (apply #'max (mapcar #'length (mapcar #'symbol-name settings)))
for def in (sort settings #'string-lessp)
if (or (get def 'doom-module)
(doom-module-from-path (symbol-file def)))
if (get def 'doom-module)
collect
(format (format "%%-%ds%%s" (+ maxwidth 4))
def (propertize (format "%s %s" (car it) (cdr it))
'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
(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)))
'face 'font-lock-comment-face))
else
collect (symbol-name def))
def (propertize (format "core/%s.el" (file-name-sans-extension (file-relative-name (symbol-file def) doom-core-dir)))
'face 'font-lock-comment-face)))
nil t
(when (and (symbolp sym)
(string-match-p "!$" (symbol-name sym)))
(symbol-name sym)))))
(list (and setting (car (split-string setting " "))))))
(or (stringp setting)
(functionp setting)
(signal 'wrong-type-argument (list '(stringp functionp) setting)))
(let ((fn (if (functionp setting)
setting
(intern-soft setting))))
(list (and autodef (car (split-string autodef " "))))))
(or (stringp autodef)
(functionp autodef)
(signal 'wrong-type-argument (list '(stringp functionp) autodef)))
(let ((fn (if (functionp autodef)
autodef
(intern-soft autodef))))
(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)
(helpful-callable 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
(defun doom/describe-module (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)
(or (doom-module-p category module)
(error "'%s %s' isn't a valid module" category module))
(let ((doc-path (doom-module-path category module "README.org")))
(unless (file-exists-p doc-path)
(error "There is no documentation for this module (%s)" doc-path))
(find-file doc-path)))
(doom-project-browse (doom-module-path category module)))
(defun doom--describe-package-insert-button (label path &optional regexp)
(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
(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."
(global-set-key [remap describe-package] #'doom/describe-package)
(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
(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))))))
(list
(let* ((guess (or (function-called-at-point)
(symbol-at-point))))
(require 'finder-inf nil t)
(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
(defun doom/what-face (arg &optional pos)
"Shows all faces and overlay faces at point.
Interactively prints the list to the echo area. Noninteractively, returns a list
whose car is the list of faces and cadr is the list of overlay faces."
(interactive "P")
(let* ((pos (or pos (point)))
(faces (let ((face (get-text-property pos 'face)))
(if (keywordp (car-safe face))
(list face)
(cl-loop for f in (doom-enlist face) collect f))))
(overlays (cl-loop for ov in (overlays-at pos (1+ pos))
nconc (doom-enlist (overlay-get ov 'face)))))
(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))))))
(defun doom/describe-symbol (symbol)
"Show help for SYMBOL, a variable, function or macro."
(interactive
(list (helpful--read-symbol "Symbol: " #'helpful--bound-p)))
(let* ((sym (intern-soft symbol))
(bound (boundp sym))
(fbound (fboundp sym)))
(cond ((and sym bound (not fbound))
(helpful-variable sym))
((and sym fbound (not bound))
(helpful-callable sym))
((apropos (format "^%s\$" symbol)))
((apropos (format "%s" symbol))))))
;;;###autoload
(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 ()
"TODO"
(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; -*-
;;;###if (not EMACS26+)
;;;###if (version< emacs-version "26.1")
;; 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

View file

@ -32,7 +32,7 @@
"TODO")
;;;###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
`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)))))
((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
(defmacro format! (message &rest args)
"An alternative to `format' that understands (color ...) and converts them
into faces or ANSI codes depending on the type of sesssion we're in."
`(cl-flet
(,@(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)))
`(format ,@(doom--short-color-replace `(,message ,@args))))
;;;###autoload
(defmacro print! (message &rest args)
@ -79,8 +87,5 @@ Can be colored using (color ...) blocks:
(print! (green \"Great %s!\") \"success\")
Uses faces in interactive sessions and ANSI codes otherwise."
`(if (not noninteractive)
(message (format! ,message ,@args))
;; princ prints to stdout, message to stderr
(princ (format! ,message ,@args))
(terpri)))
`(progn (princ (format! ,message ,@args))
(terpri)))

View file

@ -40,8 +40,9 @@
;;;###autoload
(defun doom-package-backend (name &optional noerror)
"Get which backend the package NAME was installed with. Can either be elpa or
quelpa. Throws an error if NOERROR is nil and the package isn't installed."
"Get which backend the package NAME was installed with. Can either be elpa,
quelpa or emacs (built-in). Throws an error if NOERROR is nil and the package
isn't installed."
(cl-check-type name symbol)
(cond ((assq name quelpa-cache) 'quelpa)
((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
was installed with. Returns nil otherwise, or if package isn't installed."
(cl-check-type name symbol)
(doom-initialize-packages)
(and (package-installed-p name)
(let* ((plist (cdr (assq name doom-packages)))
(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
was installed with."
(cl-check-type name symbol)
(doom-initialize-packages)
(and (package-installed-p name)
(when-let* ((quelpa-recipe (assq name quelpa-cache))
(doom-recipe (assq name doom-packages)))
@ -116,15 +115,16 @@ was installed with."
(cdr (plist-get (cdr doom-recipe) :recipe)))))))
;;;###autoload
(cl-defun doom-get-packages (&key (installed 'any)
(private 'any)
(disabled 'any)
(pinned 'any)
(ignored 'any)
(sort t)
changed
backend
deps)
(cl-defun doom-find-packages (&key (installed 'any)
(private 'any)
(disabled 'any)
(pinned 'any)
(ignored 'any)
(core 'any)
sort
changed
backend
deps)
"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
(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
properties:
:backend BACKEND
Can be 'quelpa, 'elpa or 'emacs
:installed BOOL
Only return installed packages (t) or uninstalled packages (nil)
:private BOOL
Only return private packages (t) or non-private packages (nil)
:disabled BOOL
Only return packages that are disabled (t) or otherwise (nil)
:ignored BOOL
Only return packages that are ignored (t) or otherwise (nil)
:backend 'quelpa|'elpa|'emacs|'any
Include packages installed through 'quelpa, 'elpa or 'emacs. 'any is the
wildcard.
:installed BOOL|'any
t = only include installed packages
nil = exclude installed packages
:private BOOL|'any
t = only include user-installed packages
nil = exclude user-installed packages
: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
Only return packages that are pinned (t), not pinned (nil) or pinned to a
specific archive (stringp)
: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.
Warning: this function is expensive, as it re-evaluates your all packages.el
files."
(doom-initialize-packages)
(cl-remove-duplicates
(cl-loop with packages = (append (mapcar #'list doom-core-packages)
doom-packages)
for (sym . plist)
in (if sort
(cl-sort (copy-sequence packages) #'string-lessp :key #'car)
packages)
if (and (or (not backend)
(eq (doom-package-backend sym t) backend))
(or (eq ignored 'any)
(let* ((form (plist-get plist :ignore))
(value (eval form)))
(if ignored value (not value))))
(or (eq disabled 'any)
(if disabled
(plist-get plist :disable)
(not (plist-get plist :disable))))
(or (eq installed 'any)
(if installed
(doom-package-installed-p sym)
(not (doom-package-installed-p sym))))
(or (eq private 'any)
(if private
(plist-get plist :private)
(not (plist-get plist :private))))
(or (eq pinned 'any)
(cond ((eq pinned 't)
(plist-get plist :pin))
((null pinned)
(not (plist-get plist :pin)))
((equal (plist-get plist :pin) pinned)))))
collect (cons sym plist)
and if (and deps (not (package-built-in-p sym)))
nconc
(cl-loop for pkg in (doom-get-dependencies-for sym 'recursive 'noerror)
if (or (eq installed 'any)
(if installed
(doom-package-installed-p pkg)
(not (doom-package-installed-p pkg))))
collect (cons pkg (cdr (assq pkg doom-packages)))))
:key #'car))
(cl-loop with packages = doom-packages
for (sym . plist)
in (if sort
(cl-sort (copy-sequence doom-packages) #'string-lessp :key #'car)
packages)
if (and (or (not backend)
(eq (doom-package-backend sym t) backend))
(or (eq ignored 'any)
(let* ((form (plist-get plist :ignore))
(value (eval form)))
(if ignored value (not value))))
(or (eq disabled 'any)
(if disabled
(plist-get plist :disable)
(not (plist-get plist :disable))))
(or (eq installed 'any)
(if installed
(doom-package-installed-p sym)
(not (doom-package-installed-p sym))))
(or (eq private 'any)
(let ((modules (plist-get plist :modules)))
(if private
(assq :private modules)
(not (assq :private modules)))))
(or (eq core 'any)
(let ((modules (plist-get plist :modules)))
(if core
(assq :core modules)
(not (assq :core modules)))))
(or (eq pinned 'any)
(cond ((eq pinned 't)
(plist-get plist :pin))
((null pinned)
(not (plist-get plist :pin)))
((equal (plist-get plist :pin) pinned)))))
collect (cons sym plist)
and if (and deps (not (package-built-in-p sym)))
nconc
(cl-loop for pkg in (doom-get-dependencies-for sym 'recursive 'noerror)
if (or (eq installed 'any)
(if installed
(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
(defun doom-get-package-alist ()
"Returns a list of all desired packages, their dependencies and their desc
objects, in the order of their `package! blocks.'"
(doom-initialize-packages)
(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)
nconc (cl-loop for dep in (package--get-deps name)
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.
Used by `doom-packages-update'."
(doom-initialize-packages t)
(doom-refresh-packages-maybe doom-debug-mode)
(require 'async)
(let (quelpa-pkgs elpa-pkgs)
;; Separate quelpa from elpa packages
(dolist (pkg (mapcar #'car package-alist))
(when (and (or (not (doom-package-prop pkg :freeze 'eval))
include-frozen-p)
(not (doom-package-prop pkg :ignore 'eval))
(not (doom-package-different-backend-p pkg)))
(push pkg
(if (eq (doom-package-backend pkg) 'quelpa)
quelpa-pkgs
elpa-pkgs))))
(let-alist
(seq-group-by
#'doom-package-backend
(cl-loop for package in (mapcar #'car package-alist)
when (and (or (not (doom-package-prop package :freeze 'eval))
include-frozen-p)
(not (doom-package-prop package :ignore 'eval))
(not (doom-package-different-backend-p package)))
collect package))
;; The bottleneck in this process is quelpa's version checks, so check them
;; asynchronously.
(let (futures)
(dolist (pkg quelpa-pkgs)
(when doom-debug-mode
(message "New thread for: %s" pkg))
(push (async-start
`(lambda ()
(let ((gc-cons-threshold ,doom-gc-cons-upper-limit)
(doom-init-p t)
(noninteractive t)
(load-path ',load-path)
(package-alist ',package-alist)
(package-archive-contents ',package-archive-contents)
(package-selected-packages ',package-selected-packages)
(doom-packages ',doom-packages)
(doom-modules ',doom-modules)
(quelpa-cache ',quelpa-cache)
(user-emacs-directory ,user-emacs-directory)
doom-private-dir)
(load ,(expand-file-name "core.el" doom-core-dir))
(load ,(expand-file-name "autoload/packages.el" doom-core-dir))
(require 'package)
(require 'quelpa)
(doom-package-outdated-p ',pkg))))
futures))
(delq nil
(append (mapcar #'doom-package-outdated-p elpa-pkgs)
(mapcar #'async-get (reverse futures)))))))
(cl-loop with partitions = (min 2 (/ (length .quelpa) 4))
for package-list in (seq-partition .quelpa partitions)
do (doom-log "New thread for: %s" package-list)
collect
(async-start
`(lambda ()
(let ((gc-cons-threshold ,doom-gc-cons-upper-limit)
(doom-init-p t)
(noninteractive t)
(load-path ',load-path)
(package-alist ',package-alist)
(package-archive-contents ',package-archive-contents)
(package-selected-packages ',package-selected-packages)
(doom-packages ',doom-packages)
(doom-modules ',doom-modules)
(quelpa-cache ',quelpa-cache)
(user-emacs-directory ,user-emacs-directory)
doom-private-dir)
(load ,(expand-file-name "core.el" doom-core-dir))
(load ,(expand-file-name "autoload/packages.el" doom-core-dir))
(require 'package)
(require 'quelpa)
(delq nil (mapcar #'doom-package-outdated-p ',package-list)))))
into futures
finally return
(append (delq nil (mapcar #'doom-package-outdated-p .elpa))
(mapcan #'async-get futures)
nil))))
;;;###autoload
(defun doom-get-orphaned-packages ()
@ -295,7 +362,7 @@ depended on.
Used by `doom-packages-autoremove'."
(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)
(cl-loop for pkg in package-selected-packages
if (and (doom-package-different-backend-p pkg)
@ -303,22 +370,17 @@ Used by `doom-packages-autoremove'."
collect pkg))))
;;;###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
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
`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'."
(doom-initialize-packages)
(cl-loop for (name . plist)
in (doom-get-packages :ignored (if include-ignored-p 'any)
:disabled nil
:deps t
:sort nil)
in (doom-find-packages :ignored nil
:disabled nil
:deps t)
if (and (or (plist-get plist :pin)
(not (package-built-in-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
example; the package name can be omitted)."
(cl-check-type name symbol)
(doom-initialize-packages)
(when (and (package-installed-p name)
(not (package-built-in-p name)))
(if (or (doom-package-different-backend-p name)
@ -362,6 +423,7 @@ example; the package name can be omitted)."
(package-install name))
(if (not (package-installed-p name))
(doom--delete-package-files name)
(add-to-list 'package-selected-packages name nil 'eq)
(setf (alist-get name doom-packages) plist)
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
package.el as appropriate."
(cl-check-type name symbol)
(doom-initialize-packages)
(unless (package-installed-p name)
(error "%s isn't installed" name))
(when (doom-package-different-backend-p name)
@ -401,7 +462,6 @@ package.el as appropriate."
(defun doom-delete-package (name &optional force-p)
"Uninstalls package NAME if it exists, and clears it from `quelpa-cache'."
(cl-check-type name symbol)
(doom-initialize-packages)
(unless (package-installed-p name)
(user-error "%s isn't installed" name))
(let ((inhibit-message (not doom-debug-mode))
@ -419,6 +479,14 @@ package.el as appropriate."
;;
;; 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
(defun doom/update-package (pkg)
"Prompts the user with a list of outdated packages and updates the selected
@ -436,7 +504,6 @@ calls."
(unless name
(user-error "'%s' is already up-to-date" selection))
(list (assq name packages))))
(doom-initialize-packages)
(cl-destructuring-bind (package old-version new-version) pkg
(if-let* ((desc (doom-package-outdated-p package)))
(let ((old-v-str (package-version-join old-version))
@ -456,7 +523,6 @@ calls."
;;;###autoload
(defun doom*package-delete (desc &rest _)
"Update `quelpa-cache' upon a successful `package-delete'."
(doom-initialize-packages)
(let ((name (package-desc-name desc)))
(unless (package-installed-p name)
(when-let* ((spec (assq name quelpa-cache)))
@ -474,8 +540,7 @@ calls."
;; Replace with Doom variants
;;;###autoload
(advice-add #'package-autoremove :override (λ! (doom-packages-autoremove current-prefix-arg)))
(advice-add #'package-autoremove :override #'doom//autoremove)
;;;###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; -*-
;;;###autoload
(autoload 'projectile-relevant-known-projects "projectile")
;;
;; Macros
@ -33,6 +37,28 @@ they are absolute."
(dolist (fn projectile-project-root-files-functions)
(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

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
(defun doom-surrounded-p (pair &optional inline balanced)
@ -108,7 +108,7 @@ afterwards, kill line to beginning of line."
(interactive)
(let ((empty-line-p (save-excursion (beginning-of-line)
(looking-at-p "[ \t]*$"))))
(funcall (if (featurep 'evil)
(funcall (if (fboundp 'evil-delete)
#'evil-delete
#'delete-region)
(point-at-bol) (point))
@ -132,30 +132,6 @@ opposite indentation style."
(tabify 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
(defun doom/delete-trailing-newlines ()
"Trim trailing newlines.

View file

@ -163,6 +163,30 @@ OPACITY is an integer between 0 to 100, inclusive."
100))))
(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

View file

@ -37,9 +37,8 @@ it exists."
(print! (bold (green "\nFinished!")))
(message "If you have a running Emacs Session, you will need to restart it or")
(message "reload Doom for changes to take effect:\n")
(when (fboundp '+workspace/restart-emacs-then-restore)
(message " M-x +workspace/restart-emacs-then-restore"))
(message " M-x restart-emacs")
(message " M-x doom/restart-and-restore")
(message " M-x doom/restart")
(message " M-x doom/reload"))
(defun doom--do-load (&rest files)
@ -156,7 +155,7 @@ even if it doesn't need reloading!"
forms)
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
(let* ((sexp (sexp-at-point))
(pred (match-string 1))
(alt-sexp (match-string 1))
(type (car sexp))
(name (doom-unquote (cadr sexp)))
(origin (cond ((doom-module-from-path path))
@ -166,37 +165,39 @@ even if it doesn't need reloading!"
`(:core . ,(intern (file-name-base path))))))
(doom-file-form
`(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
(let ((docstring (if (stringp (car body))
(pop body)
"No documentation.")))
(push (cond ((not (and member-p
(or (null pred)
(let ((load-file-name path))
(eval (read pred) t)))))
(push doom-file-form forms)
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
origin docstring))
(condition-case-unless-debug e
(append (list (pcase type
(`defun 'defmacro)
(`cl-defun `cl-defmacro)
(_ type))
name arglist docstring)
(cl-loop for arg in arglist
if (and (symbolp arg)
(not (keywordp arg))
(not (memq arg cl--lambda-list-keywords)))
collect arg into syms
else if (listp arg)
collect (car arg) into syms
finally return (if syms `((ignore ,@syms)))))
('error
(message "Ignoring autodef %s (%s)"
name e)
nil)))
((make-autoload sexp (abbreviate-file-name (file-name-sans-extension path)))))
(push (if member-p
(make-autoload sexp (abbreviate-file-name (file-name-sans-extension path)))
(push doom-file-form forms)
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
origin docstring))
(condition-case-unless-debug e
(if alt-sexp
(read alt-sexp)
(append (list (pcase type
(`defun 'defmacro)
(`cl-defun `cl-defmacro)
(_ type))
name arglist docstring)
(cl-loop for arg in arglist
if (and (symbolp arg)
(not (keywordp arg))
(not (memq arg cl--lambda-list-keywords)))
collect arg into syms
else if (listp arg)
collect (car arg) into syms
finally return (if syms `((ignore ,@syms))))))
('error
(message "Ignoring autodef %s (%s)"
name e)
nil)))
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
(let ((name (doom-unquote name))
(target (doom-unquote target)))
(unless (and member-p
(or (null pred)
(let ((load-file-name path))
(eval (read pred) t))))
(unless member-p
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
origin docstring))
(setq target #'ignore))
(push doom-file-form forms)
(push `(put ',name 'doom-module ',origin) forms)
(push `(defalias ',name #',target ,docstring)
forms))))
((and member-p
(or (null pred)
(eval (read pred) t)))
(member-p
(push sexp forms)))))
(if forms
(concat (string-join (mapcar #'prin1-to-string (reverse forms)) "\n")
@ -320,7 +318,7 @@ modified."
(prin1 `(setq load-path ',load-path
auto-mode-alist ',auto-mode-alist
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)
(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
(doom--generate-header 'doom-reload-package-autoloads)
(save-excursion
;; Cache the important and expensive-to-initialize state here.
;; Cache important and expensive-to-initialize state here.
(doom--generate-var-cache)
(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)
(print! (green "✓ Package autoloads included")))
;; 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)
(print! "Regenerating autoloads files")
(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")))
(with-temp-buffer
(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
;; reload it with `noninteractive' set to nil to force them to.
(quiet! (doom-reload-autoloads))
(doom-initialize 'force t)
(doom-initialize-modules 'force)
(let ((target-paths
;; Convert targets into a list of string paths, pointing to the root
;; directory of modules
(cond ((stringp (car modules)) ; command line
(save-match-data
(cl-loop for arg in modules
if (string= arg ":core") collect doom-core-dir
else if (string-match-p "/" arg)
nconc (mapcar (apply-partially #'expand-file-name arg)
doom-modules-dirs)
else
nconc (cl-loop for dir in doom-modules-dirs
for path = (expand-file-name arg dir)
if (file-directory-p path)
nconc (doom-files-in path :type 'dirs :depth 1 :full t))
finally do (setq argv nil))))
(let ((doom-modules (doom-modules))
noninteractive)
(let ((target-paths
;; Convert targets into a list of string paths, pointing to the root
;; directory of modules
(cond ((stringp (car modules)) ; command line
(save-match-data
(cl-loop for arg in modules
if (string= arg ":core") collect doom-core-dir
else if (string-match-p "/" arg)
nconc (mapcar (apply-partially #'expand-file-name arg)
doom-modules-dirs)
else
nconc (cl-loop for dir in doom-modules-dirs
for path = (expand-file-name arg dir)
if (file-directory-p path)
nconc (doom-files-in path :type 'dirs :depth 1 :full t))
finally do (setq argv nil))))
(modules ; cons-cells given to MODULES
(cl-loop for (module . submodule) in modules
if (doom-module-locate-path module submodule)
collect it))
(modules ; cons-cells given to MODULES
(cl-loop for (module . submodule) in modules
if (doom-module-locate-path module submodule)
collect it))
((append (list doom-core-dir)
(doom-module-load-path))))))
;; Load all the unit test files...
(require 'buttercup)
(mapc (lambda (file) (load file :noerror (not doom-debug-mode)))
(doom-files-in (mapcar (apply-partially #'expand-file-name "test/")
target-paths)
:match "\\.el$" :full t))
;; ... then run them
(when doom-debug-mode
(setq buttercup-stack-frame-style 'pretty))
(let ((split-width-threshold 0)
(split-height-threshold 0)
(window-min-width 0)
(window-min-height 0))
(buttercup-run))))
((append (list doom-core-dir)
(doom-module-load-path))))))
;; Load all the unit test files...
(require 'buttercup)
(mapc (lambda (file) (load file :noerror (not doom-debug-mode)))
(doom-files-in (mapcar (apply-partially #'expand-file-name "test/")
target-paths)
:match "\\.el$" :full t))
;; ... then run them
(when doom-debug-mode
(setq buttercup-stack-frame-style 'pretty))
(let ((split-width-threshold 0)
(split-height-threshold 0)
(window-min-width 0)
(window-min-height 0))
(buttercup-run)))))
;;

View file

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

View file

@ -2,26 +2,54 @@
;; A centralized keybinds system, integrated with `which-key' to preview
;; 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"
"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"
"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"
"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"
"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)
"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
"A hook run after C-g is pressed (or ESC in normal mode, for evil users). Both
trigger `doom/escape'.
@ -29,13 +57,13 @@ trigger `doom/escape'.
If any hook returns non-nil, all hooks after it are ignored.")
(defun doom/escape ()
"Run the `doom-escape-hook'."
"Run `doom-escape-hook'."
(interactive)
(cond ((minibuffer-window-active-p (minibuffer-window))
;; quit the minibuffer if open.
(abort-recursive-edit))
;; 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
((or defining-kbd-macro executing-kbd-macro) nil)
;; 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)
;; Convenience aliases
(defalias 'define-key! #'general-def)
(defalias 'unmap! #'general-unbind)
;; leader/localleader keys
(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
;; We avoid `general-create-definer' to ensure that :states, :wk-full-keys and
;; :keymaps cannot be overwritten.
(defmacro define-leader-key! (&rest args)
`(general-define-key
:states nil
:wk-full-keys nil
:keymaps 'doom-leader-map
:prefix doom-leader-alt-key
,@args))
(general-create-definer define-localleader-key!
:major-modes t
:wk-full-keys nil
:prefix doom-localleader-alt-key)
;; Because :non-normal-prefix doesn't work for non-evil sessions (only evil's
;; emacs state), we must redefine `define-localleader-key!' once evil is loaded
;; :non-normal-prefix doesn't apply to non-evil sessions (only evil's emacs
;; state), so we must redefine `define-localleader-key!' to behave differently
;; where evil is present.
(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!
:states '(normal visual motion emacs)
:major-modes t
:wk-full-keys nil
:prefix doom-localleader-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
:defer 1
@ -111,11 +208,13 @@ If any hook returns non-nil, all hooks after it are ignored.")
(which-key-mode +1))
;; `hydra'
;;;###package hydra
(setq lv-use-seperator t)
;;
;;; `map!' macro
(defvar doom-evil-state-alist
'((?n . normal)
(?v . visual)

View file

@ -1,20 +1,7 @@
;;; 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)
"Converts a simple nested series of or/and forms into a series of
@ -23,23 +10,27 @@
For example
(doom--resolve-path-forms
'(or \"some-file\" (and path-var \"/an/absolute/path\"))
'(or A (and B C))
\"~\")
Returns
Returns (approximately):
'(let ((_directory \"~\"))
(or (file-exists-p (expand-file-name \"some-file\" _directory))
(and (file-exists-p (expand-file-name path-var _directory))
(file-exists-p \"/an/absolute/path\"))))
'(let* ((_directory \"~\")
(A (expand-file-name A _directory))
(B (expand-file-name B _directory))
(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!'."
(declare (pure t) (side-effect-free t))
(cond ((stringp spec)
`(file-exists-p
,(if (file-name-absolute-p spec)
spec
`(expand-file-name ,spec ,directory))))
`(let ((--file-- ,(if (file-name-absolute-p spec)
spec
`(expand-file-name ,spec ,directory))))
(and (file-exists-p --file--)
--file--)))
((and (listp spec)
(memq (car spec) '(or and)))
`(,(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))))
((or (symbolp spec)
(listp spec))
`(file-exists-p ,(if (and directory
(or (not (stringp directory))
(file-name-absolute-p directory)))
`(expand-file-name ,spec ,directory)
spec)))
(t spec)))
`(let ((--file-- ,(if (and directory
(or (not (stringp directory))
(file-name-absolute-p directory)))
`(expand-file-name ,spec ,directory)
spec)))
(and (file-exists-p --file--)
--file--)))
(spec)))
(defun doom--resolve-hook-forms (hooks)
(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)
"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)
(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! ()
"Return the emacs lisp file this macro is called from."
(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)))))
(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)))
(mode (or mode feature)))
`(progn
(delq ',feature features)
(setq features (delq ',feature features))
(advice-add #',mode :before #',advice-fn)
(defun ,advice-fn (&rest _)
;; Some plugins (like yasnippet) run `lisp-mode' early, to parse some
;; elisp. This would prematurely trigger this function. In these cases,
;; `lisp-mode-hook' is let-bound to nil or its hooks are delayed, so if
;; we see either, keep pretending elisp-mode isn't loaded.
;; Some plugins (like yasnippet) will invoke a mode early, e.g. to
;; parse some code. This would prematurely trigger this function. This
;; checks for that:
(when (and ,(intern (format "%s-hook" mode))
(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
;; expected.
(provide ',feature)
@ -279,7 +294,9 @@ Examples:
(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
`args'."
`args'.
\(fn [:append :local] HOOKS FUNCTIONS)"
(declare (indent defun) (debug t))
(let ((hook-fn 'add-hook)
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)
"Convenience macro for `remove-hook'. Takes the same arguments as
`add-hook!'."
`add-hook!'.
\(fn [:append :local] HOOKS FUNCTIONS)"
(declare (indent defun) (debug t))
`(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)))
(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)
"Enables a minor mode if certain conditions are met.
@ -377,16 +423,15 @@ The available conditions are:
mode modes match files when)))))
(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
...) and (or ...), as well.
Returns the last file found to meet the rules set by SPEC. SPEC can be a single
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
doesn't apply to variables, however.
DIRECTORY is where to look for the files in SPEC if they aren't absolute.
For example:
(file-exists-p! (or doom-core-dir \"~/.config\" \"some-file\") \"~\")"
(if directory
`(let ((--directory-- ,directory))

View file

@ -17,7 +17,8 @@
(syntax-checker (:tools flycheck)))
(:tools (rotate-text (:editor rotate-text)))
(: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
location (which will create an alias). Each CAR and CDR is a (CATEGORY .
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)
"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)))
(load! "init" (plist-get plist :path) t)))
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
(maphash (lambda (key plist)
(let ((doom--current-module key)
(doom--current-flags (plist-get plist :flags)))
(load! "config" (plist-get plist :path) t)))
doom-modules)
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
(load! "config" doom-private-dir t)
(unless custom-file
(setq custom-file (concat doom-local-dir "custom.el")))
(when (stringp custom-file)
(load custom-file t t t))
(run-hook-wrapped 'doom-post-init-hook #'doom-try-run-hook))))
(load custom-file t t t)))))
;;
;; Module API
;;; Module API
(defun doom-module-p (category module)
"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)
doom-modules
doom-init-modules-p)
(message "Initializing modules")
(load! "init" doom-private-dir t)
(or doom-modules
(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)
@ -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-expand-minimally (not noninteractive))
;; Adds two new keywords to `use-package' (and consequently, `def-package!'),
;; they are:
;; Adds two new keywords to `use-package' (and consequently, `def-package!') to
;; expand its lazy-loading capabilities. They are:
;;
;; :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, 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
;; ;; 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
;; ...)
;; Check out `def-package!'s documentation for more about these two.
(defvar doom--deferred-packages-alist '(t))
(after! use-package-core
(add-to-list 'use-package-deferring-keywords :defer-incrementally nil #'eq)
(add-to-list 'use-package-deferring-keywords :after-call nil #'eq)
;; :ensure and :pin don't work well with Doom, so we forcibly remove them.
(dolist (keyword '(:ensure :pin))
(setq use-package-keywords (delq keyword use-package-keywords)))
(setq use-package-keywords
(use-package-list-insert :defer-incrementally use-package-keywords :after))
(setq use-package-keywords
(use-package-list-insert :after-call use-package-keywords :after))
;; Insert new deferring keywords
(dolist (keyword '(:defer-incrementally :after-call))
(add-to-list 'use-package-deferring-keywords keyword nil #'eq)
(setq use-package-keywords
(use-package-list-insert keyword use-package-keywords :after)))
(defalias 'use-package-normalize/:defer-incrementally 'use-package-normalize-symlist)
(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
`((fset ',fn
(lambda (&rest _)
(when doom-debug-mode
(message "Loading deferred package %s from %s" ',name ',fn))
(condition-case e (require ',name)
(doom-log "Loading deferred package %s from %s" ',name ',fn)
(condition-case e
(require ',name)
((debug error)
(message "Failed to load deferred package %s: %s" ',name e)))
(dolist (hook (cdr (assq ',name doom--deferred-packages-alist)))
(if (functionp hook)
(advice-remove hook #',fn)
(remove-hook hook #',fn)))
(delq (assq ',name doom--deferred-packages-alist)
doom--deferred-packages-alist)
(fmakunbound ',fn))))
(when-let* ((deferral-list (assq ',name doom--deferred-packages-alist)))
(dolist (hook (cdr deferral-list))
(if (functionp hook)
(advice-remove hook #',fn)
(remove-hook hook #',fn)))
(setq doom--deferred-packages-alist
(delq deferral-list doom--deferred-packages-alist))))))
(let (forms)
(dolist (hook hooks forms)
(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)
"Bootstraps DOOM Emacs and its modules.
@ -294,12 +292,14 @@ The overall load order of Doom is as follows:
~/.emacs.d/core/core.el
$DOOMDIR/init.el
{$DOOMDIR,~/.emacs.d}/modules/*/*/init.el
`doom-init-hook'
`doom-before-init-modules-hook'
{$DOOMDIR,~/.emacs.d}/modules/*/*/config.el
`doom-init-modules-hook'
$DOOMDIR/config.el
`doom-after-init-modules-hook'
`after-init-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'
for a list of all recognized module trees. Order defines precedence (from most
@ -335,10 +335,43 @@ to least)."
(defvar doom-disabled-packages)
(defmacro def-package! (name &rest plist)
"This is a thin wrapper around `use-package'."
`(use-package ,name
,@(if (memq name doom-disabled-packages) `(:disabled t))
,@plist))
"This is a thin wrapper around `use-package'.
It is ignored if the NAME package is disabled.
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)
"Reconfigures a package's `def-package!' block.

View file

@ -1,10 +1,18 @@
;;; core-os.el -*- lexical-binding: t; -*-
;; clipboard
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)
;; Use a shared clipboard
select-enable-clipboard t
select-enable-primary t)
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
;; fewer opts to process for systems that don't need them
(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:
;; https://bitbucket.org/lyro/evil/issue/336/osx-visual-state-copies-the-region-on
@ -29,14 +37,11 @@
;; than a new one
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))
;; Syncs ns frame parameters with theme (and fixes mismatching text
;; 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
;; 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
ensure all the necessary package metadata is initialized and available for
them."
(with-temp-buffer ; prevent buffer-local settings from propagating
(let ((load-prefer-newer t)) ; reduce stale code issues
;; package.el and quelpa handle themselves if their state changes during
;; the current session, but if you change an packages.el file in a module,
;; there's no non-trivial way to detect that, so we give you a way to
;; reload only doom-packages (by passing 'internal as FORCE-P).
(unless (eq force-p 'internal)
;; `package-alist'
(when (or force-p (not (bound-and-true-p package-alist)))
(doom-ensure-packages-initialized 'force)
(setq load-path (cl-remove-if-not #'file-directory-p load-path)))
;; `quelpa-cache'
(when (or force-p (not (bound-and-true-p quelpa-cache)))
;; ensure un-byte-compiled version of quelpa is loaded
(unless (featurep 'quelpa)
(load (locate-library "quelpa.el") nil t t))
(setq quelpa-initialized-p nil)
(or (quelpa-setup-p)
(error "Could not initialize quelpa"))))
;; `doom-packages'
(when (or force-p (not doom-packages))
(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)))))))))
(let ((load-prefer-newer t)) ; reduce stale code issues
;; package.el and quelpa handle themselves if their state changes during 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
;; doom-packages pass 'internal as FORCE-P or use `doom/reload-packages'.
(unless (eq force-p 'internal)
;; `package-alist'
(when (or force-p (not (bound-and-true-p package-alist)))
(doom-ensure-packages-initialized 'force)
(setq load-path (cl-delete-if-not #'file-directory-p load-path)))
;; `quelpa-cache'
(when (or force-p (not (bound-and-true-p quelpa-cache)))
;; ensure un-byte-compiled version of quelpa is loaded
(unless (featurep 'quelpa)
(load (locate-library "quelpa.el") nil t t))
(setq quelpa-initialized-p nil)
(or (quelpa-setup-p)
(error "Could not initialize quelpa"))))
;; `doom-packages'
(when (or force-p (not doom-packages))
(setq doom-packages (doom-package-list)))))
;;
@ -169,7 +144,7 @@ them."
;;
;; 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).
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.
:freeze FORM
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
elsewhere."
(declare (indent defun))
(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 (cl-evenp (length recipe))
(setq plist (plist-put plist :recipe (cons name recipe))))
(setq pin nil
plist (plist-put plist :pin nil)))
(when (file-in-directory-p (FILE!) doom-private-dir)
(setq plist (plist-put plist :private t)))
(let (newplist)
(while plist
(unless (null (cadr plist))
(push (cadr plist) newplist)
(push (car plist) newplist))
(pop plist)
(pop plist))
(setq plist newplist))
(let ((module-list (plist-get old-plist :modules))
(module (or doom--current-module
(let ((file (FILE!)))
(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-log "Registered package '%s'%s"
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
(append (if disable `((add-to-list 'doom-disabled-packages ',name nil #'eq)))
(if pin `((setf (alist-get ',name package-pinned-packages) ,pin)))
(append (when disable
(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)
(not (memq ',name doom-disabled-packages)))))))

View file

@ -1,7 +1,7 @@
;;; core-projects.el -*- lexical-binding: t; -*-
(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)
:init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
@ -15,9 +15,11 @@
:config
(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)
(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
(push ".project" projectile-project-root-files-bottom-up)
@ -66,23 +68,10 @@
;;
;; 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
"Hook run when a project is enabled. The name of the project's mode and its
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
modes
files
@ -94,9 +83,9 @@ state are passed in.")
on-exit)
"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
major-modes that are specific to a specific folder, certain project structure,
framework or arbitrary context you define. These project modes can have their
own settings, keymaps, hooks, snippets, etc.
major-modes that are specific to a folder, project structure, framework or
whatever arbitrary context you define. These project modes can have their own
settings, keymaps, hooks, snippets, etc.
This creates NAME-hook and NAME-map as well.

View file

@ -1,9 +1,12 @@
;;; core-ui.el -*- lexical-binding: t; -*-
;;
;;; Variables
(defvar doom-theme nil
"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
"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
size.")
;;
(defvar doom-init-ui-hook nil
"List of hooks to run when the UI has been initialized.")
(defvar doom--prefer-theme-elc nil
"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'.")
;;
;;; 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
ansi-color-for-comint-mode t
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
enable-recursive-minibuffers nil
frame-inhibit-implied-resize t
frame-title-format '("%b Doom Emacs") ; simple name in frame title
;; remove continuation arrow on right fringe
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
show-help-function nil ; hide :help-echo text
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
visible-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
window-resize-pixelwise t
frame-resize-pixelwise t)
;; y/n instead of yes/no
(fset #'yes-or-no-p #'y-or-n-p)
;; Truly silence startup message
(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'
(setq avy-all-windows nil
avy-background t)
;; Disable these because whitespace should be customized programmatically
;; (through `whitespace-style'), and not through these commands.
(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
: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-window-setup-function #'ediff-setup-windows-plain)
:config
(defvar doom--ediff-saved-wconf nil)
;; Restore window config after quitting ediff
(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)
(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-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
global-hl-line-sticky-flag nil)
;; On Emacs 26+, when point is on the last line, hl-line highlights bleed into
;; the rest of the window after eob. This is the fix.
(when EMACS26+
(defun doom--line-range ()
(cons (line-beginning-position)
(cond ((let ((eol (line-end-position)))
(and (= eol (point-max))
(/= eol (line-beginning-position))))
(1- (line-end-position)))
((or (eobp)
(= (line-end-position 2) (point-max)))
(line-end-position))
((line-beginning-position 2)))))
(setq hl-line-range-function #'doom--line-range))
;; Disable `hl-line' in evil-visual mode (temporarily). `hl-line' can make the
;; selection region harder to see while in evil visual mode.
(after! evil
@ -220,14 +275,14 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
(def-package! winner
;; undo/redo changes to Emacs' window layout
:after-call doom-exit-window-hook
:preface (defvar winner-dont-bind-my-keys t) ; I'll bind keys myself
:config (winner-mode +1))
:after-call (after-find-file doom-switch-window-hook)
:preface (defvar winner-dont-bind-my-keys t)
:config (winner-mode +1)) ; I'll bind keys myself
(def-package! paren
;; highlight matching delimiters
:after-call (after-find-file doom-exit-buffer-hook)
:after-call (after-find-file doom-switch-buffer-hook)
:init
(defun doom|disable-show-paren-mode ()
"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
(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|disable-line-numbers () (display-line-numbers-mode -1))
;; Emacs 26+ has native line number support, and will ignore nlinum. This is for
;; Emacs 25 users:
;; `nlinum' is used for Emacs 25 users, as Emacs 26+ has native line numbers.
(def-package! nlinum
;; Line number column. A faster (or equivalent, in the worst case) line number
;; 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)
;; Changing fonts can leave nlinum line numbers in their original size; this
;; forces them to resize.
(advice-add #'set-frame-font :after #'nlinum-hl-flush-all-windows))
(add-hook 'after-setting-font-hook #'nlinum-hl-flush-all-windows))
(def-package! nlinum-relative
:unless EMACS26+
:defer t
:config
(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
(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.")
(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
(progn
(cond (doom-font
;; We avoid `set-frame-font' for performance reasons.
;; Manipulating `default-frame-alist' is effective enough.
(add-to-list
'default-frame-alist
(cons 'font
@ -380,20 +484,27 @@ frame's window-system, the theme will be reloaded.")
(signal 'doom-error e)))))
(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)))
(let ((doom--prefer-theme-elc t))
(load-theme doom-theme t))))
;; Getting themes to remain consistent across GUI Emacs, terminal Emacs and
;; daemon Emacs is hairy. `doom|init-theme' sorts out the initial GUI frame.
;; Attaching `doom|init-theme-in-frame' to `after-make-frame-functions' sorts
;; out daemon and emacsclient frames.
;;
;; There will still be issues with simultaneous gui and terminal (emacsclient)
;; frames, however. There's always `doom/reload-theme' if you need it!
(defun doom|reload-theme-maybe (_frame)
"Reloads the theme if the display device has changed."
(unless (cl-find doom-last-window-system (frame-list) :key #'framep-on-display)
(setq doom-last-window-system nil)
(doom|reload-theme-in-frame-maybe (selected-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
(framep 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))
(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
;; 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)))
;;; Bootstrap
(defun doom|init-ui ()
"Initialize Doom's user interface by applying all its advice and hooks."
(add-to-list 'kill-buffer-query-functions #'doom|protect-fallback-buffer nil #'eq)
(add-to-list 'kill-buffer-query-functions #'doom|protect-visible-buffer nil #'eq)
(add-hook 'after-change-major-mode-hook #'doom|highlight-non-default-indentation)
(run-hook-wrapped 'doom-init-ui-hook #'doom-try-run-hook))
(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
(unless (fboundp 'define-fringe-bitmap)
(defun define-fringe-bitmap (&rest _)))
(defun doom*disable-old-themes-first (orig-fn &rest args)
(mapc #'disable-theme custom-enabled-themes)
(apply orig-fn args)
(when (fboundp 'powerline-reset)
(powerline-reset)))
(advice-add #'load-theme :around #'doom*disable-old-themes-first)
(defun doom*prefer-compiled-theme (orig-fn &rest args)
"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."
@ -517,27 +566,37 @@ startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
(apply orig-fn args)))
(advice-add #'load-theme :around #'doom*prefer-compiled-theme)
(defun doom|disable-whitespace-mode-in-childframes (frame)
"`whitespace-mode' inundates child frames with whitspace markers, so disable
(after! whitespace
(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."
(when (frame-parameter frame 'parent-frame)
(with-selected-frame frame
(setq-local whitespace-style nil)
frame)))
(add-hook 'after-make-frame-functions #'doom|disable-whitespace-mode-in-childframes)
(unless (frame-parameter nil 'parent-frame)
(funcall orig-fn)))
(add-function :around whitespace-enable-predicate #'doom*disable-whitespace-mode-in-childframes)
(defun doom*silence-motion-errors (orig-fn &rest args)
"Prevent disruptive motion errors taking over the minibuffer while we're in
it."
(if (not (minibufferp))
(apply orig-fn args)
(ignore-errors (apply orig-fn args))
(when (<= (point) (minibuffer-prompt-end))
(goto-char (minibuffer-prompt-end)))))
(advice-add #'left-char :around #'doom*silence-motion-errors)
(advice-add #'right-char :around #'doom*silence-motion-errors)
(advice-add #'delete-backward-char :around #'doom*silence-motion-errors)
(advice-add #'backward-kill-sentence :around #'doom*silence-motion-errors)
(defun doom|disable-whitespace-mode-in-childframes (frame)
"`whitespace-mode' inundates child frames with whitspace markers, so disable
it to fix all that visual noise."
(when (frame-parameter frame 'parent-frame)
(with-selected-frame frame
(setq-local whitespace-style nil)
frame)))
(add-hook 'after-make-frame-functions #'doom|disable-whitespace-mode-in-childframes))
;; Don't allow cursor to enter the prompt
(setq minibuffer-prompt-properties '(read-only t intangible t cursor-intangible t face minibuffer-prompt))
(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
(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
(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
"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
@ -208,12 +123,10 @@ and `doom-exit-window-hook'."
;; UTF-8 as the default coding system
(when (fboundp 'set-charset-priority)
(set-charset-priority 'unicode)) ; pretty
(prefer-coding-system 'utf-8) ; pretty
(set-terminal-coding-system 'utf-8) ; pretty
(set-keyboard-coding-system 'utf-8) ; pretty
(set-selection-coding-system 'utf-8) ; perdy
(setq locale-coding-system 'utf-8) ; please
(setq-default buffer-file-coding-system 'utf-8) ; with sugar on top
(prefer-coding-system 'utf-8) ; pretty
(setq selection-coding-system 'utf-8) ; pretty
(setq locale-coding-system 'utf-8) ; please
(if IS-WINDOWS (set-w32-system-coding-system 'utf-8)) ; with sugar on top
(setq-default
ad-redefinition-action 'accept ; silence advised function warnings
@ -230,8 +143,6 @@ and `doom-exit-window-hook'."
inhibit-default-init t
initial-major-mode 'fundamental-mode
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)
auto-save-default 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")
auto-save-list-file-name (concat doom-cache-dir "autosave")
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/")
request-storage-directory (concat doom-cache-dir "request")
server-auth-dir (concat doom-cache-dir "server/")
@ -315,6 +229,13 @@ original value of `symbol-file'."
#'doom-try-run-hook))
(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
@ -357,17 +278,17 @@ intervals."
(let* ((reqs (cl-delete-if #'featurep packages))
(req (ignore-errors (pop reqs))))
(when req
(when doom-debug-mode
(message "Incrementally loading %s" req))
(doom-log "Incrementally loading %s" req)
(condition-case e
(require req nil t)
(error
((error debug)
(message "Failed to load '%s' package incrementally, because: %s"
req e)))
(when reqs
(run-with-idle-timer doom-incremental-idle-timer
nil #'doom-load-packages-incrementally
reqs t))))))))
(if reqs
(run-with-idle-timer doom-incremental-idle-timer
nil #'doom-load-packages-incrementally
reqs t)
(doom-log "Finished incremental loading"))))))))
(defun doom|load-packages-incrementally ()
"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
(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.
Meant to be used with `run-hook-wrapped'."
(when doom-debug-mode
(message "Running doom hook: %s" hook))
(doom-log "Running doom hook: %s" hook)
(condition-case e
(funcall hook)
((debug error)
@ -457,11 +377,18 @@ If RETURN-P, return the message as a string instead of displaying it."
;;
;; Bootstrap functions
(defun doom-initialize (&optional force-p force-load-core-p)
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
(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))))))
Loads Doom core files if in an interactive session or FORCE-LOAD-CORE-P is
non-nil.
(defun doom-initialize (&optional force-p)
"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,
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
~/.doom.d/init.el
Module init.el files
`doom-init-hook'
`doom-before-init-modules-hook'
Module config.el files
~/.doom.d/config.el
`doom-post-init-hook'
`doom-init-modules-hook'
`after-init-hook'
`emacs-startup-hook'
`doom-init-ui-hook'
`window-setup-hook'
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
@ -508,47 +437,45 @@ to least)."
;; autoloads file and caches `load-path', `auto-mode-alist',
;; `Info-directory-list', `doom-disabled-packages' and
;; `package-activated-list'. A big reduction in startup time.
(unless (or force-p
(doom-initialize-autoloads doom-package-autoload-file)
noninteractive)
(user-error "Your package autoloads are missing! Run `bin/doom refresh' to regenerate them")))
(let (command-switch-alist)
(unless (or force-p
(doom-initialize-autoloads doom-package-autoload-file)
noninteractive)
(user-error "Your package autoloads are missing! Run `bin/doom refresh' to regenerate them"))))
(require 'core-lib)
(require 'core-modules)
(require 'core-os)
(when (or force-load-core-p (not noninteractive))
(add-hook! 'emacs-startup-hook
#'(doom|init-switch-hooks doom|display-benchmark))
(if noninteractive
(require 'core-cli)
(add-hook 'window-setup-hook #'doom|display-benchmark)
(require 'core-keybinds)
(require 'core-ui)
(require 'core-editor)
(require 'core-projects)
(require 'core-keybinds)))
(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))))))
(require 'core-editor)))
;;
;; 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)
(require 'core-modules)
(when noninteractive
(require 'core-cli))
(after! package
(require 'core-packages))
(add-to-list 'load-path doom-core-dir)
(doom-initialize noninteractive)
(unless noninteractive
(doom-initialize-modules))
(after! package
(require 'core-packages)
(doom-initialize-packages))
(provide 'core)
;;; 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-os.el
(package! xclip)
(when IS-MAC
(package! exec-path-from-shell)
(package! osx-clipboard)
@ -10,7 +11,6 @@
;; core-ui.el
(package! all-the-icons)
(package! hide-mode-line)
(package! highlight-indentation)
(package! highlight-numbers)
(package! highlight-escape-sequences
:recipe (:fetcher github :repo "hlissner/highlight-escape-sequences"))
@ -28,7 +28,6 @@
(package! avy)
(package! command-log-mode)
(package! dtrt-indent)
(package! expand-region)
(package! helpful)
(package! pcre2el)
(package! smartparens)

View file

@ -1,6 +1,12 @@
;; Welcome to the vanilla sandbox!
;;
;; This is a test bed for running Emacs Lisp in either a vanilla Emacs session
;; free of Doom's clutches (C-c C-c), or in a vanilla Doom session free of your
;; private config (C-c C-d).
;; This is a test bed for running Emacs Lisp in an instance of Emacs with varying
;; amounts of Doom loaded:
;;
;; 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; -*-
;;; core/test/test-autoload-help.el
(load! "autoload/help" doom-core-dir)
;; (load! "autoload/help" doom-core-dir)
;;
(describe "core/autoload/help"
:var (a)
(before-each (setq a (switch-to-buffer (get-buffer-create "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))))
;; (describe "core/autoload/help"
;; :var (a)
;; (before-each (setq a (switch-to-buffer (get-buffer-create "a"))))
;; (after-each (kill-buffer a)))

View file

@ -55,8 +55,8 @@
(doom-missing-dummy)
(doom-noquelpa-dummy)
(doom-disabled-dummy :disable t)
(doom-private-dummy :private t)
(doom-disabled-private-dummy :private t :disable t)
(doom-private-dummy :modules ((:private)))
(doom-disabled-private-dummy :modules ((:private)) :disable t)
(doom-quelpa-dummy :recipe (doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist")))
quelpa-cache
'((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))
(it "returns all packages"
(expect (mapcar #'car (doom-get-packages))
(expect (mapcar #'car (doom-find-packages))
:to-have-same-items-as
(mapcar #'car doom-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
'(doom-disabled-dummy doom-disabled-private-dummy)))
(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
'(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-missing-dummy doom-noquelpa-dummy doom-private-dummy)))
(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
'(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-noquelpa-dummy)))
(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
'(doom-missing-dummy doom-private-dummy)))
(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
'(doom-private-dummy doom-disabled-private-dummy)))
(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
'(doom-disabled-private-dummy))))

View file

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

View file

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

View file

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

View file

@ -1,33 +1,9 @@
;; -*- no-byte-compile: t; -*-
;;; ../core/test/test-core-ui.el
(require '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"
:var (kill-buffer-query-functions a b)
(before-all

View file

@ -61,43 +61,39 @@
(before-each
(setq a (switch-to-buffer (get-buffer-create "a"))
b (get-buffer-create "b"))
(spy-on 'before-hook)
(spy-on 'after-hook)
(doom|init-switch-hooks))
(spy-on '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))
(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 b))
(describe "switch-buffer"
:var (doom-exit-buffer-hook
doom-enter-buffer-hook)
:var (doom-switch-buffer-hook)
(before-each
(setq doom-exit-buffer-hook '(before-hook)
doom-enter-buffer-hook '(after-hook)))
(setq doom-switch-buffer-hook '(hook)))
(after-each
(setq doom-exit-buffer-hook nil
doom-enter-buffer-hook nil))
(setq doom-switch-buffer-hook nil))
(it "should trigger when switching buffers"
(switch-to-buffer b)
(switch-to-buffer a)
(switch-to-buffer b)
(expect 'before-hook :to-have-been-called-times 3)
(expect 'after-hook :to-have-been-called-times 3))
(expect 'hook :to-have-been-called-times 3))
(it "should trigger only once on the same buffer"
(switch-to-buffer b)
(switch-to-buffer b)
(switch-to-buffer a)
(expect 'before-hook :to-have-been-called-times 2)
(expect 'after-hook :to-have-been-called-times 2)))
(expect 'hook :to-have-been-called-times 2)))
(describe "switch-window"
:var (doom-exit-window-hook
doom-enter-window-hook
x y)
:var (doom-switch-window-hook x y)
(before-each
(delete-other-windows)
(setq x (get-buffer-window a)
@ -105,21 +101,17 @@
(with-selected-window y
(switch-to-buffer b))
(select-window x)
(spy-calls-reset 'before-hook)
(spy-calls-reset 'after-hook)
(setq doom-exit-window-hook '(before-hook)
doom-enter-window-hook '(after-hook)))
(spy-calls-reset 'hook)
(setq doom-switch-window-hook '(hook)))
(it "should trigger when switching windows"
(select-window y)
(select-window x)
(select-window y)
(expect 'before-hook :to-have-been-called-times 3)
(expect 'after-hook :to-have-been-called-times 3))
(expect 'hook :to-have-been-called-times 3))
(it "should trigger only once on the same window"
(select-window y)
(select-window y)
(select-window x)
(expect 'before-hook :to-have-been-called-times 2)
(expect 'after-hook :to-have-been-called-times 2))))))
(expect '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 '(menu-bar-lines . 0))
(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
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...
;;ivy ; a search engine for love and life
ivy ; a search engine for love and life
:ui
;;deft ; notational velocity for Emacs
doom ; what makes DOOM look the way it does
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
evil-goggles ; display visual hints when editing in evil
;;fci ; a `fill-column' indicator
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
;;neotree ; a project drawer, like NERDTree for vim
treemacs ; a project drawer, like neotree but cooler
@ -69,7 +69,7 @@
;;gist ; interacting with github gists
;;lsp
;;macos ; MacOS-specific commands
;;magit ; a git porcelain for Emacs
magit ; a git porcelain for Emacs
;;make ; run make tasks from Emacs
;;password-store ; password manager for nerds
;;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)
(when (featurep 'solaire-mode)
(add-hook 'cfw:calendar-mode-hook #'solaire-mode))
(add-hook 'cfw:calendar-mode-hook #'doom|mark-buffer-as-real)
(add-hook 'cfw:calendar-mode-hook 'hide-mode-line-mode)
(advice-add #'cfw:render-button :override #'+calendar*cfw:render-button))

View file

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

View file

@ -162,9 +162,10 @@ order.
(string-join (delq nil (cdr command)) " ")
(abbreviate-file-name directory))
helm-source-do-ag)
(cl-letf ((+helm-global-prompt prompt)
((symbol-function 'helm-do-ag--helm)
(helm-attrset '+helm-command command helm-source-do-ag)
(cl-letf (((symbol-function 'helm-do-ag--helm)
(lambda () (helm :sources '(helm-source-do-ag)
:prompt prompt
:buffer "*helm-ag*"
:keymap helm-do-ag-map
:input query
@ -177,7 +178,7 @@ order.
return (intern (format format tool))))
;;;###autoload
(defun +helm/project-search (&optional all-files-p)
(defun +helm/project-search (&optional arg)
"Performs a project search from the project root.
Uses the first available search backend from `+helm-project-search-engines'. If
@ -186,10 +187,10 @@ ones, in the search."
(interactive "P")
(funcall (or (+helm--get-command "+helm/%s")
#'+helm/grep)
(or all-files-p current-prefix-arg)))
arg))
;;;###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.
Uses the first available search backend from `+helm-project-search-engines'. If
@ -198,7 +199,7 @@ ones."
(interactive "P")
(funcall (or (+helm--get-command "+helm/%s-from-cwd")
#'+helm/grep-from-cwd)
(or all-files-p current-prefix-arg)))
arg))
;; Relative to project root
@ -213,21 +214,31 @@ ones."
(dolist (engine `(,@(cl-remove-duplicates +helm-project-search-engines :from-end t) grep))
(defalias (intern (format "+helm/%s" engine))
(lambda (all-files-p &optional query directory)
(lambda (arg &optional query directory)
(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.
QUERY is a regexp. If omitted, the current selection is used. If no selection is
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."
engine))
(defalias (intern (format "+helm/%s-from-cwd" engine))
(lambda (all-files-p &optional query)
(lambda (arg &optional query)
(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.
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; -*-
(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)))
(when (stringp buffer)
(setq buffer (get-buffer buffer)))
@ -28,21 +34,73 @@ temporary/special buffers in `font-lock-comment-face'."
;;
;; 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
(defun +ivy/switch-workspace-buffer (&optional arg)
"Switch to another buffer within the current workspace.
If ARG (universal argument), open selection in other-window."
(interactive "P")
(ivy-read "Switch to workspace buffer: "
'internal-complete-buffer
:predicate #'+ivy--is-workspace-or-other-buffer-p
:action (if arg
#'ivy--switch-buffer-other-window-action
#'ivy--switch-buffer-action)
:matcher #'ivy--switch-buffer-matcher
:keymap ivy-switch-buffer-map
:caller #'+ivy/switch-workspace-buffer))
(+ivy--switch-buffer t arg))
;;;###autoload
(defun +ivy/switch-workspace-buffer-other-window ()
"Switch another window to a buffer within the current workspace."
(interactive)
(+ivy--switch-buffer t t))
;;;###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)
"Generate a list of task tags (specified by `+ivy-task-tags') for
@ -230,7 +288,7 @@ order.
'grep)
(error "No search engine specified (is ag, rg, pt or git installed?)")))
(query
(or query
(or (if query (rxt-quote-pcre query))
(when (use-region-p)
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
(end (or (bound-and-true-p evil-visual-end) (region-end))))

View file

@ -3,6 +3,13 @@
(defvar +ivy-buffer-icons nil
"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
'(("TODO" . warning)
("FIXME" . error))
@ -58,9 +65,11 @@ immediately runs it on the current candidate (ending the ivy session)."
(after! yasnippet
(add-to-list 'yas-prompt-functions #'+ivy-yas-prompt nil #'eq))
(map! [remap switch-to-buffer] #'ivy-switch-buffer
[remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer
[remap imenu-anywhere] #'ivy-imenu-anywhere)
(map! :map ivy-mode-map
[remap switch-to-buffer] #'+ivy/switch-buffer
[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)
@ -68,15 +77,15 @@ immediately runs it on the current candidate (ending the ivy session)."
:commands (ivy-dispatching-done-hydra ivy--matcher-desc)
:init
(define-key! ivy-minibuffer-map
"\C-o" #'+ivy-coo-hydra/body
(kbd "M-o") #'ivy-dispatching-done-hydra)))
"C-o" #'+ivy-coo-hydra/body
"M-o" #'ivy-dispatching-done-hydra)))
(def-package! ivy-rich
:hook (ivy-mode . ivy-rich-mode)
:config
;; 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))
(ivy-set-display-transformer cmd 'ivy-rich--ivy-switch-buffer-transformer))
;; 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-function] #'counsel-describe-function
[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 find-file] #'counsel-find-file
[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
(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
(dolist (fn '(swiper counsel-ag counsel-grep counsel-git-grep))
(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; -*-
;; 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
(setq persp-keymap-prefix (kbd "C-c e"))
(setq persp-keymap-prefix (kbd "C-c w"))
(after! projectile
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map))
(which-key-add-key-based-replacements "C-c !" "checking")
(which-key-add-key-based-replacements "C-c e" "perspective")
(which-key-add-key-based-replacements "C-c p" "projectile")
(after! which-key
(which-key-add-key-based-replacements "C-c !" "checking")
(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
"<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))
;;
;;; Global keybinds
;; 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
(:when (featurep! :ui neotree)
"<f9>" #'+neotree/open)
(:when (featurep! :ui treemacs)
"<f9>" #'+treemacs/toggle)
"C-=" #'er/expand-region
"C--" #'er/contract-region
;; 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-h b" #'counsel-descbinds
"C-M-y" #'counsel-yank-pop
"C-h F" #'counsel-faces
"C-h p" #'counsel-package
"C-h a" #'counsel-apropos
"C-h V" #'counsel-set-variable
"C-'" #'counsel-imenu))
;; repl toggle
"C-c C-z" #'+eval/open-repl
;; 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
[return] #'neotree-enter
"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))
(:after helpful-mode
(:map helpful-mode-map
"o" #'ace-link-help))
(: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)))
(map! :leader
:desc "Find file in project" "C-f" #'projectile-find-file
:desc "Evaluate line/region" "e" #'+eval/line-or-region
:desc "Pop up scratch buffer" "x" #'doom/open-to-scratch-buffer
:desc "Switch to scratch buffer" "X" #'doom/switch-to-scratch-buffer
(:when (featurep! :emacs term)
:desc "Terminal" "`" #'+term/open
:desc "Terminal in popup" "~" #'+term/open-popup-in-project)
(:when (featurep! :tools vterm)
:desc "Terminal" "`" #'+vterm/open
:desc "Terminal in popup" "~" #'+vterm/open-popup-in-project)
(:when (featurep! :emacs eshell)
:desc "Eshell" "`" #'+eshell/open
:desc "Eshell in popup" "~" #'+eshell/open-popup)
;; Add labels to prefixes defined elsewhere
:desc "project" "p" nil
(:prefix ("f" . "file")
:desc "Find other file" "a" #'projectile-find-other-file
:desc "Browse private config" "c" #'doom/open-private-config
:desc "Find file in private config" "C" #'doom/find-file-in-private-config
:desc "Open project editorconfig" "." #'editorconfig-find-current-editorconfig
:desc "Find directory" "d" #'dired
:desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
:desc "Browse emacs.d" "E" #'+default/browse-emacsd
:desc "Find file from here" "f" (if (fboundp 'counsel-file-jump) #'counsel-file-jump #'find-file)
:desc "Find file in other project" "F" #'doom/browse-in-other-project
:desc "Find file in project" "p" #'projectile-find-file
:desc "Find file in other project" "P" #'doom/find-file-in-other-project
:desc "Recent files" "r" #'recentf-open-files
:desc "Recent project files" "R" #'projectile-recentf
:desc "Sudo this file" "s" #'doom/sudo-this-file
: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)
"o" nil ; we need to unbind it first as Org claims this
(:prefix ("o". "org")
(: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 "Switch org buffers" "b" #'org-switchb
:desc "Capture" "c" #'org-capture
:desc "Goto capture" "C" (λ! (require 'org-capture) (call-interactively #'org-capture-goto-target))
:desc "Link store" "l" #'org-store-link
:desc "Sync org caldav" "s" #'org-caldav-sync)
(: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" #'doom/restart-and-restore
:desc "Restart Emacs" "R" #'doom/restart)
(:prefix ("&" . "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)
(:prefix ("v" . "versioning")
:desc "Git revert file" "R" #'vc-revert
(:when (featurep! :ui vc-gutter)
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
:desc "Git time machine" "t" #'git-timemachine-toggle
:desc "Jump to next hunk" "n" #'git-gutter:next-hunk
:desc "Jump to previous hunk" "p" #'git-gutter:previous-hunk)
(:when (featurep! :tools magit)
:desc "Magit dispatch" "/" #'magit-dispatch
:desc "Forge dispatch" "'" #'forge-dispatch
:desc "Magit status" "g" #'magit-status
:desc "Magit file delete" "x" #'magit-file-delete
:desc "Magit blame" "B" #'magit-blame-addition
:desc "Magit clone" "C" #'+magit/clone
:desc "Magit fetch" "F" #'magit-fetch
:desc "Magit buffer log" "L" #'magit-log
:desc "Git stage file" "S" #'magit-stage-file
:desc "Git unstage file" "U" #'magit-unstage-file
(:prefix ("f" . "find")
:desc "Find file" "f" #'magit-find-file
:desc "Find gitconfig file" "g" #'magit-find-git-config-file
:desc "Find commit" "c" #'magit-show-commit
:desc "Find issue" "i" #'forge-visit-issue
:desc "Find pull request" "p" #'forge-visit-pullreq)
(:prefix ("o" . "open in browser")
:desc "Browse region or line" "." #'+vc/git-browse-region-or-line
:desc "Browse remote" "r" #'forge-browse-remote
:desc "Browse commit" "c" #'forge-browse-commit
:desc "Browse an issue" "i" #'forge-browse-issue
:desc "Browse a pull request" "p" #'forge-browse-pullreq
:desc "Browse issues" "I" #'forge-browse-issues
:desc "Browse pull requests" "P" #'forge-browse-pullreqs)
(:prefix ("l" . "list")
(:when (featurep! :tools gist)
:desc "List gists" "g" #'+gist:list)
:desc "List repositories" "r" #'magit-list-repositories
:desc "List submodules" "s" #'magit-list-submodules
:desc "List issues" "i" #'forge-list-issues
:desc "List pull requests" "p" #'forge-list-pullreqs
:desc "List notifications" "n" #'forge-list-notifications)
(:prefix ("c" . "create")
:desc "Initialize repo" "r" #'magit-init
:desc "Clone repo" "R" #'+magit/clone
:desc "Commit" "c" #'magit-commit-create
:desc "Issue" "i" #'forge-create-issue
: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
;; 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
(setq evil-collection-key-blacklist
(list "C-j" "C-k" "gd" "gf" "K" "[" "]" "gz"
@ -21,9 +17,6 @@
"M-;" #'eval-expression
"A-;" #'eval-expression)
[remap evil-jump-to-tag] #'projectile-find-tag
[remap find-tag] #'projectile-find-tag
;; Smart tab
:i [tab] (general-predicate-dispatch nil ; fall back to nearest keymap
(and (featurep! :feature snippets)
@ -34,10 +27,6 @@
(+company-has-completion-p))
'+company/complete)
: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)
(save-excursion (end-of-line) (invisible-p (point))))
'+fold/toggle
@ -59,18 +48,111 @@
:i [remap newline] #'newline-and-indent ; auto-indent on newline
: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
:map vc-annotate-mode-map
[remap quit-window] #'kill-this-buffer)
;; 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
: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)
:nv "K" #'+lookup/documentation
:nv "gd" #'+lookup/definition
@ -216,10 +199,13 @@
[delete] #'+snippets/delete-forward-char-or-field)))
(: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-previous-word-generic
(:map flyspell-mouse-map
"RET" #'flyspell-correct-word-generic
[return] #'flyspell-correct-word-generic
[mouse-1] #'flyspell-correct-word-generic))
(:when (featurep! :tools flycheck)
@ -227,11 +213,12 @@
:m "[e" #'previous-error
(:after flycheck
:map flycheck-error-list-mode-map
:n "C-n" #'flycheck-error-list-next-error
:n "C-p" #'flycheck-error-list-previous-error
:n "j" #'flycheck-error-list-next-error
:n "k" #'flycheck-error-list-previous-error
:n "RET" #'flycheck-error-list-goto-error))
:n "C-n" #'flycheck-error-list-next-error
:n "C-p" #'flycheck-error-list-previous-error
:n "j" #'flycheck-error-list-next-error
:n "k" #'flycheck-error-list-previous-error
:n "RET" #'flycheck-error-list-goto-error
:n [return] #'flycheck-error-list-goto-error))
(:when (featurep! :feature workspaces)
:n "gt" #'+workspace/switch-right
@ -279,6 +266,7 @@
"C-S-s" (cond ((featurep! :completion helm) #'helm-company)
((featurep! :completion ivy) #'counsel-company))
"C-SPC" #'company-complete-common
"TAB" #'company-complete-common-or-cycle
[tab] #'company-complete-common-or-cycle
[backtab] #'company-select-previous)
(:map company-search-map ; applies to `company-filter-map' too
@ -287,9 +275,11 @@
"C-j" #'company-select-next-or-abort
"C-k" #'company-select-previous-or-abort
"C-s" (λ! (company-search-abort) (company-filter-candidates))
[escape] #'company-search-abort)
"ESC" #'company-search-abort)
;; 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)
(:map (help-mode-map helpful-mode-map)
@ -302,6 +292,7 @@
(:after counsel
:map counsel-ag-map
"C-SPC" #'ivy-call-and-recenter ; preview
"C-l" #'ivy-done
[backtab] #'+ivy/wgrep-occur ; search/replace on results
[C-return] (+ivy-do-action! #'+ivy-git-grep-other-window-action))
(:after swiper
@ -327,6 +318,7 @@
"C-s" #'helm-minibuffer-history
"C-b" #'backward-word
;; Swap TAB and C-z
"TAB" #'helm-execute-persistent-action
[tab] #'helm-execute-persistent-action
"C-z" #'helm-select-action)
(:after swiper-helm
@ -363,29 +355,31 @@
(:when (featurep! :ui neotree)
:after neotree
:map neotree-mode-map
:n "g" nil
:n [tab] #'neotree-quick-look
:n [return] #'neotree-enter
:n [backspace] #'evil-window-prev
:n "c" #'neotree-create-node
:n "r" #'neotree-rename-node
:n "d" #'neotree-delete-node
:n "j" #'neotree-next-line
:n "k" #'neotree-previous-line
:n "n" #'neotree-next-line
:n "p" #'neotree-previous-line
:n "h" #'+neotree/collapse-or-up
:n "l" #'+neotree/expand-or-open
:n "J" #'neotree-select-next-sibling-node
:n "K" #'neotree-select-previous-sibling-node
:n "H" #'neotree-select-up-node
:n "L" #'neotree-select-down-node
:n "G" #'evil-goto-line
:n "gg" #'evil-goto-first-line
:n "v" #'neotree-enter-vertical-split
:n "s" #'neotree-enter-horizontal-split
:n "q" #'neotree-hide
:n "R" #'neotree-refresh)
:n "g" nil
:n "TAB" #'neotree-quick-look
:n "RET" #'neotree-enter
:n [tab] #'neotree-quick-look
:n [return] #'neotree-enter
:n "DEL" #'evil-window-prev
:n "c" #'neotree-create-node
:n "r" #'neotree-rename-node
:n "d" #'neotree-delete-node
:n "j" #'neotree-next-line
:n "k" #'neotree-previous-line
:n "n" #'neotree-next-line
:n "p" #'neotree-previous-line
:n "h" #'+neotree/collapse-or-up
:n "l" #'+neotree/expand-or-open
:n "J" #'neotree-select-next-sibling-node
:n "K" #'neotree-select-previous-sibling-node
:n "H" #'neotree-select-up-node
:n "L" #'neotree-select-down-node
:n "G" #'evil-goto-line
:n "gg" #'evil-goto-first-line
:n "v" #'neotree-enter-vertical-split
:n "s" #'neotree-enter-horizontal-split
:n "q" #'neotree-hide
:n "R" #'neotree-refresh)
(:when (featurep! :ui popup)
:n "C-`" #'+popup/toggle
@ -415,8 +409,9 @@
: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-first-cursor
:nv "q" #'evil-mc-undo-all-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)
(:after evil-mc
:map evil-mc-key-map
@ -433,9 +428,10 @@
:nv "C-M-d" #'evil-multiedit-restore
(:after evil-multiedit
(:map evil-multiedit-state-map
"M-d" #'evil-multiedit-match-and-next
"M-D" #'evil-multiedit-match-and-prev
"RET" #'evil-multiedit-toggle-or-restrict-region)
"M-d" #'evil-multiedit-match-and-next
"M-D" #'evil-multiedit-match-and-prev
"RET" #'evil-multiedit-toggle-or-restrict-region
[return] #'evil-multiedit-toggle-or-restrict-region)
(:map (evil-multiedit-state-map evil-multiedit-insert-state-map)
"C-n" #'evil-multiedit-next
"C-p" #'evil-multiedit-prev)))
@ -467,7 +463,8 @@
(:when (featurep! :tools gist)
:after gist
: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 "c" #'gist-add-buffer
:n "d" #'gist-kill-current
@ -497,16 +494,16 @@
;; C-u is used by evil
: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 "Find file" "." #'find-file
:desc "Switch buffer" "," #'switch-to-buffer
(:when (featurep! :feature workspaces)
:desc "Switch workspace buffer" "," #'persp-switch-to-buffer
:desc "Switch buffer" "<" #'switch-to-buffer)
(:unless (featurep! :feature workspaces)
:desc "Switch buffer" "," #'switch-to-buffer)
:desc "Resume last search" "'"
(cond ((featurep! :completion ivy) #'ivy-resume)
@ -520,49 +517,23 @@
(:prefix ("/" . "search")
:desc "Jump to symbol across buffers" "I" #'imenu-anywhere
:desc "Search buffer" "b" #'swiper
:desc "Search current directory" "d"
(cond ((featurep! :completion helm) #'+helm/project-search-from-cwd)
((featurep! :completion ivy) #'+ivy/project-search-from-cwd))
:desc "Search current directory" "d" #'+default/search-from-cwd
:desc "Jump to symbol" "i" #'imenu
:desc "Jump to link" "l" #'ace-link
:desc "Look up online" "o" #'+lookup/online-select
:desc "Search project" "p"
(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)
:desc "Search project" "p" #'+default/search-project)
(:when (featurep! :feature workspaces)
(:prefix ([tab] . "workspace")
(:prefix ("TAB" . "workspace")
:desc "Display tab bar" "TAB" #'+workspace/display
:desc "Switch workspace" "." #'+workspace/switch-to
:desc "New workspace" "n" #'+workspace/new
: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 "Autosave current session" "S" #'+workspace/save-session
:desc "Switch workspace" "." #'+workspace/switch-to
:desc "Delete session" "x" #'+workspace/kill-session
:desc "Delete this workspace" "d" #'+workspace/delete
: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 "Previous workspace" "[" #'+workspace/switch-left
:desc "Switch to 1st workspace" "1" (λ! (+workspace/switch-to 0))
@ -578,8 +549,6 @@
(:prefix ("b" . "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 "Next buffer" "]" #'next-buffer
(:when (featurep! :feature workspaces)
@ -589,40 +558,44 @@
:desc "Switch buffer" "b" #'switch-to-buffer)
:desc "Kill buffer" "k" #'kill-this-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 "Previous buffer" "p" #'previous-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 "Bury buffer" "z" #'bury-buffer)
(:prefix ("c" . "code")
:desc "Jump to references" "D" #'+lookup/references
:desc "Evaluate & replace region" "E" #'+eval:replace-region
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
:desc "Build tasks" "b" #'+eval/build
:desc "Compile project" "c" #'projectile-compile-project
: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 & replace region" "E" #'+eval:replace-region
:desc "Format buffer/region" "f" #'+format/region-or-buffer
:desc "Open REPL" "r" #'+eval/open-repl-other-window
:desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
:desc "List errors" "x" #'flycheck-list-errors)
(: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 "Sudo find file" ">" #'doom/sudo-find-file
: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 file in other project" "?" #'doom/find-file-in-other-project
:desc "Find other file" "a" #'projectile-find-other-file
:desc "Open project editorconfig" "c" #'editorconfig-find-current-editorconfig
:desc "Find directory" "d" #'dired
: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 project files" "R" #'projectile-recentf
: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)
(:prefix ("g" . "git")
@ -673,34 +646,6 @@
:desc "Issue" "i" #'forge-create-issue
: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")
:desc "Insert from clipboard" "y" #'+default/yank-pop
:desc "Insert from evil register" "r" #'evil-ex-registers
@ -710,10 +655,17 @@
:desc "Open deft" "d" #'deft
:desc "Find file in notes" "n" #'+default/find-in-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")
: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 "Debugger" "d" #'+debug/open
:desc "REPL" "r" #'+eval/open-repl-other-window
@ -767,12 +719,15 @@
:desc "List project tasks" "t" #'+default/project-tasks
:desc "Invalidate cache" "x" #'projectile-invalidate-cache)
(:prefix ("q" . "quit/restart")
(:prefix ("q" . "session")
:desc "Quit Emacs" "q" #'evil-quit-all
:desc "Save and quit Emacs" "Q" #'evil-save-and-quit
: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)
:desc "Quick save current session" "s" #'doom/quicksave-session
:desc "Restore last session" "l" #'doom/quickload-session
: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)
(:prefix ("r" . "remote")
@ -790,15 +745,16 @@
:desc "Jump to mode snippet" "/" #'yas-visit-snippet-file
:desc "Jump to snippet" "s" #'+snippets/find-file
: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")
:desc "Flyspell" "s" #'flyspell-mode
:desc "Flycheck" "f" #'flycheck-mode
:desc "Line numbers" "l" #'doom/toggle-line-numbers
:desc "Frame fullscreen" "F" #'toggle-frame-fullscreen
:desc "Indent guides" "i" #'highlight-indentation-mode
:desc "Indent guides (column)" "I" #'highlight-indentation-current-column-mode
:desc "Indent guides" "i" #'highlight-indent-guides-mode
:desc "Impatient mode" "h" #'+impatient-mode/toggle
:desc "Big mode" "b" #'doom-big-font-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 ()
(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
(defun +default/compile (arg)
"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)))))))
;; Otherwise, do simple deletion.
((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
(setq epa-file-encrypt-to
@ -27,113 +27,12 @@
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
;; 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
(after! tabulated-list
(define-key tabulated-list-mode-map "q" #'quit-window))
@ -171,7 +70,7 @@
:n "s-/" #'evil-commentary-line
:v "s-/" #'evil-commentary
: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-left] #'doom/backward-to-bol-or-indent
: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)
;; Make M-x harder to miss
@ -189,6 +129,13 @@
"M-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.
;; 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.
@ -199,8 +146,12 @@
:gni [M-return] #'+default/newline-below
:gni [M-S-return] #'+default/newline-above
: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)
(save-excursion
(cond ((+fold--vimish-fold-p) (vimish-fold-toggle))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-toggle-hiding)))
((+fold--outline-fold-p)
(cl-letf (((symbol-function #'outline-hide-subtree)
(symbol-function #'outline-hide-entry)))
(outline-toggle-children))))))
(outline-toggle-children)))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-toggle-hiding))))))
;;;###autoload
(defun +fold/open ()
@ -59,10 +59,10 @@ Targets `vimmish-fold', `hideshow' and `outline' folds."
(interactive)
(save-excursion
(cond ((+fold--vimish-fold-p) (vimish-fold-unfold))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block)))
((+fold--outline-fold-p)
(outline-show-children)
(outline-show-entry)))))
(outline-show-entry))
((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block))))))
;;;###autoload
(defun +fold/close ()

View file

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

View file

@ -17,6 +17,7 @@
(defvar evil-mc-key-map (make-sparse-keymap))
:config
(global-evil-mc-mode +1)
(setq evil-mc-enable-bar-cursor (not (or IS-MAC IS-WINDOWS)))
(after! smartparens
;; Make evil-mc cooperate with smartparens better
@ -56,7 +57,7 @@
:evil-mc t))
(after! multiple-cursors
(after! multiple-cursors-core
(setq mc/list-file (concat doom-etc-dir "mc-lists.el"))
;; 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-rotate-image-file (concat image-dired-dir "temp-rotate-image"))
:config
(setq dired-listing-switches "-aBhl --group-directories-first")
(when IS-BSD
;; Use GNU ls as `gls' from `coreutils' if available. Add `(setq
;; dired-use-ls-dired nil)' to your config to suppress the Dired warning
;; 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'
(if-let* ((gls (executable-find "gls")))
(setq insert-directory-program gls)
(message "Cannot find `gls` (GNU ls). Install coreutils via your system package manager")))
(let ((args (list "-aBhl" "--group-directories-first")))
(when IS-BSD
;; Use GNU ls as `gls' from `coreutils' if available. Add `(setq
;; dired-use-ls-dired nil)' to your config to suppress the Dired warning
;; 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'
(if-let* ((gls (executable-find "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")))
(setq dired-listing-switches (string-join args " ")))
(defun +dired|sort-directories-first ()
"List directories first in dired buffers."
@ -91,6 +92,7 @@
ranger-excluded-extensions '("mkv" "iso" "mp4")
ranger-deer-show-details nil
ranger-max-preview-size 10
ranger-show-literal nil
dired-omit-verbose nil))

View file

@ -17,8 +17,10 @@ Enables `electric-indent-local-mode' in MODES.
(unintern fn nil))
((fset fn
(lambda ()
(cl-destructuring-bind (&key chars words) plist
(electric-indent-local-mode +1)
(if chars (setq electric-indent-chars chars))
(if words (setq +electric-indent-words words)))))
(when (eq major-mode mode)
(setq-local electric-indent-inhibit nil)
(cl-destructuring-bind (&key chars words) plist
(electric-indent-local-mode +1)
(if chars (setq electric-indent-chars chars))
(if words (setq +electric-indent-words words))))))
(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
;; it delegates these commands to a term buffer.
(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)))
(defun +eshell|init-aliases ()

View file

@ -17,6 +17,14 @@
(funcall runner 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
(defun +eval/buffer-or-region ()
"Evaluate the whole buffer."

View file

@ -1,9 +1,5 @@
;;; 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)
(interactive "<!>")
(doom/open-scratch-buffer bang))
@ -46,14 +42,30 @@ This command understands vim file modifiers (like %:p:h). See
(interactive "<r>")
(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
;;; these are defined in feature/evil
;;(evil-ex-define-cmd "al[ign]" #'+evil:align)
;;(evil-ex-define-cmd "g[lobal]" #'+evil:global)
;;; Custom commands
;; Editing
(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)
;;; 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]all" #'+default:kill-all-buffers)
(evil-ex-define-cmd "k[ill]m" #'+default:kill-matching-buffers)
(evil-ex-define-cmd "k[ill]all" #'+evil:kill-all-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]b" #'doom/kill-buried-buffers)
(evil-ex-define-cmd "l[ast]" #'doom/popup-restore)
(evil-ex-define-cmd "m[sg]" #'view-echo-area-messages)
(evil-ex-define-cmd "pop[up]" #'doom/popup-this-buffer)
;;; Project navigation
(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)
(cond ((featurep! :completion ivy)
@ -135,7 +147,7 @@ This command understands vim file modifiers (like %:p:h). See
;;; Project tools
(evil-ex-define-cmd "compile" #'+evil:compile)
(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)
;;; File operations
@ -145,8 +157,8 @@ This command understands vim file modifiers (like %:p:h). See
;;; Sessions/tabs
(evil-ex-define-cmd "sclear" #'+workspace/kill-session)
(evil-ex-define-cmd "sl[oad]" #'+workspace:load-session)
(evil-ex-define-cmd "ss[ave]" #'+workspace:save-session)
(evil-ex-define-cmd "sl[oad]" #'doom/quickload-session)
(evil-ex-define-cmd "ss[ave]" #'doom/quicksave-session)
(evil-ex-define-cmd "tabc[lose]" #'+workspace:delete)
(evil-ex-define-cmd "tabclear" #'doom/kill-all-buffers)
(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)
(unless (memq (or (car-safe module) module) +evil-collection-disabled-list)
(when doom-debug-mode
(message "Loaded evil-collection-%s" (or (car-safe module) module)))
(doom-log "Initialized evil-collection-%s" (or (car-safe module) module))
(with-demoted-errors "evil-collection error: %s"
(evil-collection-init (list module)))))
@ -195,6 +194,10 @@ variable for an explanation of the defaults (in comments). See
"]l" #'forward-button
"[l" #'backward-button))
(evil-define-key* 'normal process-menu-mode-map
"q" #'kill-this-buffer
"d" #'process-menu-delete-process)
;; Load the rest
(dolist (mode evil-collection-mode-list)
(dolist (req (or (cdr-safe mode) (list mode)))

View file

@ -4,26 +4,25 @@
#+STARTUP: inlineimages
* Table of Contents :TOC_3:noexport:
- [[Description][Description]]
- [[Module Flags][Module Flags]]
- [[Plugins][Plugins]]
- [[Hacks][Hacks]]
- [[Prerequisites][Prerequisites]]
- [[Features][Features]]
- [[Ported vim plugins][Ported vim plugins]]
- [[Custom Text Objects][Custom Text Objects]]
- [[Custom Ex Commands][Custom Ex Commands]]
- [[A hybrid code-folding system][A hybrid code-folding system]]
- [[Differences from vim][Differences from vim]]
- [[Configuration][Configuration]]
- [[Removing evil-mode][Removing evil-mode]]
- [[#description][Description]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#hacks][Hacks]]
- [[#prerequisites][Prerequisites]]
- [[#features][Features]]
- [[#ported-vim-plugins][Ported vim plugins]]
- [[#custom-text-objects][Custom Text Objects]]
- [[#custom-ex-commands][Custom Ex Commands]]
- [[#configuration][Configuration]]
- [[#removing-evil-mode][Removing evil-mode]]
- [[#restoring-old-substitution-behavior-on-ss][Restoring old substitution behavior on s/S]]
* Description
This holy module brings the vim experience to Emacs.
** Module Flags
+ =+everywhere= Enables evilified keybinds everywhere possible, utilizing the
~evil-collection~ plugin.
+ =+everywhere= Enables evilified keybinds everywhere possible. Uses the
[[https://github.com/emacs-evil/evil-collection][evil-collection]] plugin as a foundation.
** Plugins
+ [[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.
+ The o/O keys will respect and continue commented lines (can be disabled by
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 ~:g[lobal]~ ex command has been modified to highlight matches
incrementally.
+ The ~:g[lobal]~ ex command has been modified to highlight matches.
+ More of vim's filename modifiers are supported in ex commands (like ~:p~,
~:p:h~ or ~:t~) than vanilla evil-mode offers.
+ 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
The following vim plugins have been ported to evil:
| Vim Plugin | Emacs Plugin | Keybind(s) |
|-----------------------+--------------------------------+---------------------|
| vim-commentary | evil-commentary | omap =gc= |
| vim-easymotion | evil-easymotion | omap =gs= |
| vim-seek or vim-sneak | evil-snipe | mmap =s=/=S= |
| vim-surround | evil-embrace and evil-surround | vmap =S=, omap =ys= |
| Vim Plugin | Emacs Plugin | Keybind(s) |
|-----------------------+--------------------------------+--------------------------------------|
| vim-commentary | evil-commentary | omap =gc= |
| vim-easymotion | evil-easymotion | omap =gs= |
| 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= |
In other modules:
+ The tools/neotree & tools/treemacs modules contain a =NERDTree= equivalent.
+ The editor/multiple-cursors module contains:
+ ~vim-multiedit~ => evil-multiedit
+ ~vim-multiple-cursors~ => evil-mc
+ The tools/neotree & tools/treemacs modules provide a =NERDTree= equivalent.
+ The editor/multiple-cursors module contains functionality equal to the
following vim plugins:
+ evil-multiedit => vim-multiedit
+ evil-mc => vim-multiple-cursors
** Custom Text Objects
+ A list of new text objects:
+ Blocks: ~B~ (from ~evil-textobj-anyblock~)
+ Args: ~a~ (from ~evil-args~)
+ Indentation: ~i~ / ~I~ / ~J~ (from ~evil-indent-plus~)
This module provides a couple extra text objects, along with the built-in ones.
For posterity, here are the built-in ones:
+ =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
| Ex Command | Description |
|----------------------+----------------------------------------------------------------------------------|
| ~:al[ign][!] REGEXP~ | Align text to the first match of REGEXP. If BANG, align all matches on each line |
| ~:mv[!] NEWPATH~ | Move the current file to NEWPATH |
| ~:cp[!] NEWPATH~ | Copy the current file to NEWPATH |
| ~:rm[!] [PATH]~ | Delete the current buffer's file and buffer |
** A hybrid code-folding system
This module combines ~vimish-fold~ and ~hideshow~. The former allows arbitrary
folds and the latter allows folds on markers and indentation. Together, they
create a more consistent (and feature-complete) code-folding system.
Most vim folding keys should work, e.g. =zr=, =zm=, =za=, =zo=, etc.
** Differences from vim
+ Column-wise ranges in ex commands are enabled by default. i.e. the range in
=:'<,'>s/a/b= will only affects the visual selection, not full lines (see
~evil-ex-visual-char-range~).
+ =:g= will incrementally highlight buffer matches.
| Ex Command | Description |
|----------------------+--------------------------------------------------------------------------------------|
| ~:@~ | Apply macro on selected lines |
| ~:ag[!] REGEXP~ | Perform a project search with ag |
| ~:agcwd[!] REGEXP~ | Perform a project search with ag |
| ~: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 |
| ~:cp[!] NEWPATH~ | Copy the current file to NEWPATH |
| ~:dash QUERY~ | Look up QUERY (or the symbol at point) in dash docsets |
| ~:dehtml [INPUT]~ | HTML decode selected text / inserts result if INPUT is given |
| ~:enhtml [INPUT]~ | HTML encode selected text / inserts result if INPUT is given |
| ~:grep[!]~ | Perform a project search with git-grep |
| ~:grepcwd[!]~ | Perform a project search with git-grep |
| ~:iedit REGEXP~ | Invoke iedit on all matches for REGEXP |
| ~:k[ill]all[!]~ | Kill all buffers (if BANG, affect buffer across workspaces) |
| ~:k[ill]b~ | Kill all buried buffers |
| ~:k[ill]m[!] REGEXP~ | Kill buffers whose name matches REGEXP (if BANG, affect buffers across workspaces) |
| ~:k[ill]o~ | Kill all other buffers besides the selected one |
| ~: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
** Removing evil-mode
You must do two things to remove Evil:
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.
3. [OPTIONAL] You may want a new ~doom-leader-alt-key~ and
~doom-localleader-alt-key~. By default, these are bound to =M-SPC= and =M-SPC
m=.
3. [OPTIONAL] You may want to assign new values to ~doom-leader-alt-key~ and
~doom-localleader-alt-key~. These are bound to =C-c= and =C-c l= by default.
#+begin_quote
Ignore ~doom-leader-key~ and ~doom-localleader-key~, they don't apply to
non-evil sessions.
#+end_quote
Note that evil-specific configuration and keybinds (defined with ~map!~) will be
ignored without evil present (and stripped out when byte-compiling).
Evil-specific configuration and keybindings (defined with ~map!~) will be
ignored without =:feature evil= present (and omitted when byte-compiling).
Unfortunately, since Doom was designed by a vimmer, for vimmers, little
consideration into a keybinding scheme for vanilla Emacs users.
Keep in mind that, at the time of this writing, Doom was designed by a vimmer,
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."
(when (called-interactively-p 'any)
(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
(defun +evil/visual-indent ()
@ -50,10 +50,10 @@
(call-interactively #'evil-paste-after)))
(defun +evil--window-swap (direction)
"Move current window to the next window in DIRECTION. If there are no windows
there and there is only one window, split in that direction and place this
window there. If there are no windows and this isn't the only window, use
evil-window-move-* (e.g. `evil-window-move-far-left')"
"Move current window to the next window in DIRECTION.
If there are no windows there and there is only one window, split in that
direction and place this window there. If there are no windows and this isn't
the only window, use evil-window-move-* (e.g. `evil-window-move-far-left')."
(when (window-dedicated-p)
(user-error "Cannot swap a dedicated 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)
(evil-define-operator +evil:apply-macro (beg end)
@ -154,7 +154,8 @@ integration."
(doom/clone-and-narrow-buffer beg end bang))
;; --- custom arg handlers ----------------
;;
;;; Custom arg handlers
(defvar +evil--flag nil)
@ -241,7 +242,8 @@ the first match on each line)."
-1 1 bang))
;; --- wgrep ------------------------------
;;
;;; wgrep
;;;###autoload (autoload '+evil-delete "feature/evil/autoload/evil" nil t)
(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)
(def-package! evil
:init
:hook (doom-init-modules . evil-mode)
:demand t
:preface
(setq evil-want-visual-char-semi-exclusive t
evil-magic t
evil-echo-state t
@ -27,8 +29,6 @@ line with a linewise comment.")
evil-respect-visual-line-mode t
;; more vim-like behavior
evil-symbol-word-search t
;; don't activate mark on shift-click
shift-select-mode nil
;; cursor appearance
evil-default-cursor '+evil-default-cursor
evil-normal-state-cursor 'box
@ -39,18 +39,16 @@ line with a linewise comment.")
evil-want-keybinding (not (featurep! +everywhere)))
:config
(load! "+commands")
(add-hook 'doom-post-init-hook #'evil-mode)
(evil-select-search-module 'evil-search-module 'evil-search)
(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 ()
(set-popup-rules!
'(("^\\*evil-registers" :size 0.3)
("^\\*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
(defvar +evil--default-cursor-color
@ -104,12 +102,7 @@ line with a linewise comment.")
;; and one custom one: %:P (expand to the project root).
(advice-add #'evil-ex-replace-special-filenames :override #'+evil*resolve-vim-path)
;; make `try-expand-dabbrev' from `hippie-expand' work in minibuffer. See
;; `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)))
;; make `try-expand-dabbrev' (from `hippie-expand') work in minibuffer
(add-hook 'minibuffer-inactive-mode-hook #'+evil*fix-dabbrev-in-minibuffer)
;; Focus and recenter new splits
@ -117,25 +110,26 @@ line with a linewise comment.")
(advice-add #'evil-window-vsplit :override #'+evil*window-vsplit)
;; 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 #'helm-ag--find-file-action :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...
(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)
;; 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-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 -----------
;; These arg types will highlight matches in the current buffer
(evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match)
@ -159,7 +153,10 @@ line with a linewise comment.")
;; `evil-collection'
(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
:after evil-surround
:commands (embrace-add-pair embrace-add-pair-regexp)
:hook (LaTeX-mode . embrace-LaTeX-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
;; Add extra pairs
(add-hook! emacs-lisp-mode
(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))
(after! evil-surround
(evil-embrace-enable-evil-surround-integration))
:config
(setq evil-embrace-show-help-p nil)
(evil-embrace-enable-evil-surround-integration)
(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))))
(defun +evil|embrace-latex-mode-hook ()
(embrace-add-pair-regexp ?l "\\[a-z]+{" "}" #'+evil--embrace-latex))
(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)))))))
(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 "(") "")) ")"))
(defun +evil|embrace-lisp-mode-hook ()
(embrace-add-pair-regexp ?f "([^ ]+ " ")" #'+evil--embrace-elisp-fn))
;; Add escaped-sequence support to embrace
(setf (alist-get ?\\ (default-value 'embrace--pairs-list))
@ -240,13 +212,13 @@ line with a linewise comment.")
(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
(setq evil-escape-excluded-states '(normal visual multiedit emacs motion)
evil-escape-excluded-major-modes '(neotree-mode treemacs-mode term-mode)
evil-escape-key-sequence "jk"
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)
:config
;; 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))
;; Without `evil-visualstar', * and # grab the word at point and search, no
;; matter what mode you're in. I want to be able to visually select a region and
;; search for other occurrences of it.
;; Allows you to use the selection for * and #
(def-package! evil-visualstar
:commands (evil-visualstar/begin-search
evil-visualstar/begin-search-forward

View file

@ -84,7 +84,7 @@ Otherwise, these properties are available to be set:
;;
;; Library
;; Helpers
;; Helpers
(defun +lookup--online-provider (&optional force-p namespace)
@ -100,59 +100,64 @@ Otherwise, these properties are available to be set:
provider))))
(defun +lookup--symbol-or-region (&optional initial)
(cond (initial)
(cond ((stringp initial)
initial)
((use-region-p)
(buffer-substring-no-properties (region-beginning)
(region-end)))
((require 'xref nil t)
(xref-backend-identifier-at-point (xref-find-backend)))))
(defun +lookup--jump-to (prop identifier &optional other-window)
;; TODO Refactor me
(let ((origin (point-marker)))
(cl-loop for fn
in (plist-get (list :definition +lookup-definition-functions
:references +lookup-references-functions
:documentation +lookup-documentation-functions
:file +lookup-file-functions)
prop)
for cmd = (or (command-remapping fn) fn)
if (get fn '+lookup-async)
return
(progn
(when other-window
;; If async, we can't catch the window change or destination buffer
;; reliably, so we set up the new window ahead of time.
(switch-to-buffer-other-window (current-buffer))
(goto-char (marker-position origin)))
(call-interactively fn)
t)
if (condition-case e
(save-window-excursion
(when (or (if (commandp cmd)
(call-interactively cmd)
(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--run-hooks (hook identifier origin &optional other-window)
(doom-log "Looking up '%s' with '%s'" identifier hook)
(condition-case-unless-debug e
(if (get hook '+lookup-async)
(progn
(when other-window
;; If async, we can't catch the window change or destination buffer
;; reliably, so we set up the new window ahead of time.
(switch-to-buffer-other-window (current-buffer))
(goto-char (marker-position origin)))
(if (commandp hook)
(call-interactively hook)
(funcall hook identifier))
t)
(save-window-excursion
(when (or (if (commandp hook)
(call-interactively hook)
(funcall hook identifier))
(null origin)
(/= (point-marker) origin))
(point-marker))))
((error user-error)
(message "%s" e)
nil)))
(defun +lookup--file-search (identifier)
(unless identifier
(let ((query (rxt-quote-pcre identifier)))
(ignore-errors
(cond ((featurep! :completion ivy)
(+ivy-file-search nil :query query)
t)
((featurep! :completion helm)
(+helm-file-search nil :query query)
t))))))
(defun +lookup--jump-to (prop identifier &optional other-window)
(let ((ret
(condition-case e
(run-hook-wrapped
(plist-get (list :definition '+lookup-definition-functions
:references '+lookup-references-functions
:documentation '+lookup-documentation-functions
:file '+lookup-file-functions)
prop)
'+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)
"Uses `evil-goto-definition' to conduct a text search for IDENTIFIER in the
current buffer."
(and (featurep 'evil)
evil-mode
(and (fboundp 'evil-goto-definition)
(ignore-errors
(cl-destructuring-bind (beg . end)
(bounds-of-thing-at-point 'symbol)
@ -268,7 +272,7 @@ search otherwise."
((error "Couldn't find references of '%s'" identifier))))
;;;###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.
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
(list (+lookup--symbol-or-region)
current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point"))
((+lookup--jump-to :documentation identifier other-window))
(cond ((+lookup--jump-to :documentation identifier t))
((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
;; declare helm before dumb-jump.
(when (featurep! :completion helm)
(depends-on! :completion helm))
(package! helm))
;;
(package! dumb-jump)

View file

@ -21,13 +21,15 @@
:config
(setq yas-verbosity (if doom-debug-mode 3 0)
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
(add-to-list 'yas-snippet-dirs '+snippets-dir nil #'eq)
;; 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
;; are multiple choices.
(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/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-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-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-left~ | =SPC TAB [= / =[ w= / =gT= | Switch to previous 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; -*-
;;;###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)
(evil-define-command +workspace:save (&optional name)
"Ex wrapper around `+workspace/save-session'."

View file

@ -112,14 +112,6 @@ Returns t if successful, nil otherwise."
*persp-hash* (list 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
(defun +workspace-save (name)
"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))
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
(defun +workspace-new (name)
"Create a new workspace named NAME. If one already exists, return nil.
@ -206,6 +186,9 @@ throws an error."
;;
;; Commands
;;;###autoload
(defalias '+workspace/restore-last-session #'doom/quickload-session)
;;;###autoload
(defun +workspace/load (name)
"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-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
(defun +workspace/rename (new-name)
"Rename the current workspace."
@ -437,12 +380,6 @@ the next."
(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
@ -570,7 +507,7 @@ This be hooked to `projectile-after-switch-project-hook'."
(+workspace-message
(format "Switched to '%s' in new workspace" new-name)
'success))
(with-current-buffer (switch-to-buffer (doom-fallback-buffer))
(with-current-buffer (doom-fallback-buffer)
(setq default-directory +workspaces--project-dir)
(message "Switched to '%s'" (doom-project-name +workspaces--project-dir)))
(unless current-prefix-arg

View file

@ -5,11 +5,6 @@
;; it because it was unstable and slow; `persp-mode' is neither (and still
;; 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.
(defvar +workspaces-main "main"
@ -20,26 +15,20 @@
`counsel-projectile-switch-project'. This function must take one argument: the
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
"Controls the behavior of workspaces when switching to a new project.
Can be one of the following:
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.
nil Never create a new workspace on project switch.")
;; If emacs is passed --restore, restore the last session on startup. This is
;; used by the `+workspace/restart-emacs-then-restore' command.
(defun +workspaces-restore-last-session (&rest _)
(add-hook 'emacs-startup-hook #'+workspace/load-session :append))
(add-to-list 'command-switch-alist (cons "--restore" #'+workspaces-restore-last-session))
;; 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'.")
;;
@ -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."
(unless persp-mode
(persp-mode +1))
(unless noninteractive
(let (persp-before-switch-functions persp-activated-functions)
(with-selected-frame frame
;; The default perspective persp-mode creates (`persp-nil-name') is
;; 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*
;; main workspace to fill this role.
(unless (persp-get-by-name +workspaces-main)
(persp-add-new +workspaces-main))
;; Switch to it if we aren't auto-loading the last session
(when (and (string= (safe-persp-name (get-current-persp)) persp-nil-name)
(= persp-auto-resume-time -1))
(persp-frame-switch +workspaces-main frame)
;; We want to know where we are in every new daemon frame
(when (daemonp)
(run-at-time 0.1 nil #'+workspace/display))
;; Fix #319: the warnings buffer gets swallowed by creating
;; `+workspaces-main', so we display it manually, if it exists.
(when-let* ((warnings (get-buffer "*Warnings*")))
(save-excursion
(display-buffer-in-side-window
warnings '((window-height . shrink-window-if-larger-than-buffer))))))))))
(persp-mode +1)
(unless noninteractive
(let (persp-before-switch-functions persp-activated-functions)
(with-selected-frame frame
;; The default perspective persp-mode creates (`persp-nil-name') is
;; 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*
;; main workspace to fill this role.
(unless (persp-get-by-name +workspaces-main)
(persp-add-new +workspaces-main))
;; Switch to it if we aren't auto-loading the last session
(when (and (string= (safe-persp-name (get-current-persp)) persp-nil-name)
(= persp-auto-resume-time -1))
(persp-frame-switch +workspaces-main frame)
;; We want to know where we are in every new daemon frame
(when (daemonp)
(run-at-time 0.1 nil #'+workspace/display))
;; Fix #319: the warnings buffer gets swallowed by creating
;; `+workspaces-main', so we display it manually, if it exists.
(when-let* ((warnings (get-buffer "*Warnings*")))
(save-excursion
(display-buffer-in-side-window
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
(setq persp-autokill-buffer-on-remove 'kill-weak
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)
(add-hook 'doom-cleanup-hook #'+workspaces|cleanup-unassociated-buffers)
;; Ensure buffers we've opened/switched to are auto-added to the current
;; perspective
(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
(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)))))
(cond ((file-exists-p! (or (concat base ".cpp")
(concat base ".cc")))
@ -70,13 +79,11 @@ preceded by the opening brace or a comma (disregarding whitespace in between)."
"\\|[-+] ([a-zA-Z0-9_]+)"
"\\)")))
(objc-mode))
((fboundp 'c-or-c++-mode) ; introduced in Emacs 26.1
(c-or-c++-mode))
((+cc--re-search-for ; TODO Remove this along with Emacs 25 support
((+cc--re-search-for
(let ((id "[a-zA-Z0-9_]+") (ws "[ \t\r]+") (ws-maybe "[ \t\r]*"))
(concat "^" ws-maybe "\\(?:"
"using" ws "\\(?:namespace" ws "std;\\|std::\\)"
"\\|" "namespace" "\\(:?" ws id "\\)?" ws-maybe "{"
"using" ws "\\(?:namespace" ws "std;\\|std::\\)"
"\\|" "namespace" "\\(?:" ws id "\\)?" ws-maybe "{"
"\\|" "class" ws id ws-maybe "[:{\n]"
"\\|" "template" ws-maybe "<.*>"
"\\|" "#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))
((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
@ -99,7 +114,7 @@ preceded by the opening brace or a comma (disregarding whitespace in between)."
;; first rtag
(when (and (featurep 'rtags)
rtags-enabled
(executable-find "rc"))
(executable-find rtags-rc-binary-name))
(with-temp-buffer
(message "Reloaded compile commands for rtags daemon")
(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"
(when (memq major-mode '(c-mode c++-mode))
(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))
t)))
(defvar +cc--project-includes-alist nil)
;;;###autoload
(defun +cc|irony-init-compile-options ()
(defun +cc|init-irony-compile-options ()
"Initialize compiler options for irony-mode. It searches for the nearest
compilation database and initailizes it, otherwise falling back on
`+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))
(require 'irony-cdb)
(unless (irony-cdb-autosetup-compile-options)
(irony-cdb--update-compile-options
(delq nil
(append (cdr-safe (assq major-mode +cc-default-compiler-options))
(cl-loop with path = (or buffer-file-name default-directory)
for dir in '("include" "includes")
if (projectile-locate-dominating-file path dir)
collect it)
(cl-loop for path in +cc-default-include-paths
if (stringp path)
nconc (list "-I" path))))
(doom-project-root)))
;; Make ffap aware of include paths
(when irony--working-directory
(require 'ffap)
(make-local-variable 'ffap-c-path)
(make-local-variable 'ffap-c++-path)
(cl-loop for opt in irony--compile-options
if (and (stringp opt)
(string-match "^-I\\(.+\\)" opt))
do (add-to-list (pcase major-mode
(`c-mode 'ffap-c-path)
(`c++-mode 'ffap-c++-path))
(expand-file-name (match-string 1 opt)
irony--working-directory))))))
(let ((project-root (doom-project-root))
(include-paths (+cc-resolve-include-paths)))
(setf (alist-get project-root +cc--project-includes-alist)
include-paths)
(irony-cdb--update-compile-options
(append (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))
(cl-loop for path in include-paths
collect (format "-I%s" path)))
project-root)))))
;; ;;;###autoload
;; (defun +cc|init-ccls-compile-options ()
;; "TODO"
;; (when (memq major-mode '(c-mode c++-mode objc-mode))
;; (when-let* ((include-paths (+cc-resolve-include-paths)))
;; (let ((args (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))))
;; (setf (alist-get (or (lsp-workspace-root)
;; (lsp--suggest-project-root)
;; (doom-project-root))
;; +cc--project-includes-alist)
;; include-paths)
;; (setq ccls-initialization-options
;; `(:clang (:extraArgs
;; [,@(cl-loop for path in include-paths
;; collect (format "-I%s" path))])))))))
;;;###autoload
(defun +cc|cleanup-rtags ()
"Kill rtags server(s) if there are no C/C++ buffers open."
(unless (doom-buffers-in-mode '(c-mode c++-mode) (buffer-list))
(rtags-cancel-process)))
(defun +cc|init-ffap-integration ()
"Takes the local project include paths and registers them with ffap.
This way, `find-file-at-point' (and `+lookup/file') will know where to find most
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; -*-
(defvar +cc-default-include-paths (list "include/")
"A list of default paths, relative to a project root, to search for headers in
C/C++. Paths can be absolute. This is ignored if your project has a compilation
database.")
(defvar +cc-default-include-paths
(list "include"
"includes")
"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
"Fallback major mode for .h files if all other heuristics fail (in
@ -20,7 +24,9 @@ database.")
"-stdlib=libc++")))
(objc-mode . nil))
"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
(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
(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++" "Boost")
@ -69,12 +80,11 @@ compilation database is present in the project.")
;;; Better fontification (also see `modern-cpp-font-lock')
(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
(unless (assoc "doom" c-style-alist)
(push '("doom"
(c-basic-offset . tab-width)
(c-add-style
"doom" '((c-basic-offset . tab-width)
(c-comment-only-line-offset . 0)
(c-hanging-braces-alist (brace-list-open)
(brace-entry-open)
@ -102,8 +112,7 @@ compilation database is present in the project.")
;; another level
(access-label . -)
(inclass +cc-c++-lineup-inclass +)
(label . 0)))
c-style-alist))
(label . 0))))
;;; Keybindings
;; 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/"))
:init
(defun +cc|init-irony-mode ()
(when (and (memq major-mode '(c-mode c++-mode objc-mode))
(file-directory-p irony-server-install-prefix))
(irony-mode +1)))
(add-hook 'c-mode-common-hook #'+cc|init-irony-mode)
(if (file-directory-p irony-server-install-prefix)
(irony-mode +1)
(message "Irony server isn't installed")))
(add-hook! (c-mode-local-vars c++-mode-local-vars objc-mode-local-vars)
#'+cc|init-irony-mode)
:config
(setq irony-cdb-search-directory-list '("." "build" "build-conda"))
;; Initialize compilation database, if present. Otherwise, fall back on
;; `+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
:hook (irony-mode . irony-eldoc))
@ -188,10 +198,11 @@ compilation database is present in the project.")
:init
(defun +cc|init-rtags ()
"Start an rtags server in c-mode and c++-mode buffers."
(when (and (memq major-mode '(c-mode c++-mode))
(rtags-executable-find "rdm"))
(when (and (require 'rtags nil t)
(rtags-executable-find rtags-rdm-binary-name))
(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
(setq rtags-autostart-diagnostics t
rtags-use-bookmarks nil
@ -210,7 +221,6 @@ compilation database is present in the project.")
:definition #'rtags-find-symbol-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)))
;; Use rtags-imenu instead of imenu/counsel-imenu
@ -224,17 +234,16 @@ compilation database is present in the project.")
;;
;; LSP
(def-package! cquery
(def-package! ccls
: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
(defun +lsp|init-cquery ()
(defun +cc|init-ccls ()
(setq-local company-transformers nil)
(setq-local company-lsp-async t)
(setq-local company-lsp-cache-candidates nil)
(condition-case nil
(lsp)
(user-error nil)))
(setq cquery-extra-init-params
'(:index (:comments 2)
:cacheFormat "msgpack"
:completion (:detailedLabel t))))
(lsp))
(after! projectile
(add-to-list 'projectile-globally-ignored-directories ".ccls-cache")
(add-to-list 'projectile-project-root-files-bottom-up ".ccls-root")
(add-to-list 'projectile-project-root-files-top-down-recurring "compile_commands.json")))

View file

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

View file

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

View file

@ -1,110 +1,112 @@
;;; lang/clojure/config.el -*- lexical-binding: t; -*-
;; `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!
'(("^\\*cider-error*" :ignore t)
("^\\*cider-repl" :quit 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
(:map clojure-mode-map
"'" #'cider-jack-in
"\"" #'cider-jack-in-clojurescript
(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))
(:prefix ("e" . "eval")
"d" #'cider-eval-defun-at-point
"D" #'cider-insert-defun-in-repl
"e" #'cider-eval-last-sexp
"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)))
(map! (:localleader
(:map clojure-mode-map
"'" #'cider-jack-in
"\"" #'cider-jack-in-clojurescript
(:when (featurep! :feature evil +everywhere)
:map cider-repl-mode-map
:i [S-return] #'cider-repl-newline-and-indent
:map cider-repl-history-mode-map
:i [return] #'cider-repl-history-insert-and-quit
:i "q" #'cider-repl-history-quit
:i "l" #'cider-repl-history-occur
:i "s" #'cider-repl-history-search-forward
:i "r" #'cider-repl-history-search-backward
:i "U" #'cider-repl-history-undo-other-window)))
(:prefix ("e" . "eval")
"d" #'cider-eval-defun-at-point
"D" #'cider-insert-defun-in-repl
"e" #'cider-eval-last-sexp
"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)))
(def-package! clj-refactor
: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))
(:when (featurep! :feature evil +everywhere)
:map cider-repl-mode-map
:i [S-return] #'cider-repl-newline-and-indent
:map cider-repl-history-mode-map
:i [return] #'cider-repl-history-insert-and-quit
:i "q" #'cider-repl-history-quit
:i "l" #'cider-repl-history-occur
:i "s" #'cider-repl-history-search-forward
:i "r" #'cider-repl-history-search-backward
:i "U" #'cider-repl-history-undo-other-window)))
(def-package! flycheck-joker
:when (featurep! :tools flycheck)
:after flycheck))
(def-package! clj-refactor
: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'
(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 '())
(after! company-coq
(set-popup-rule! "^\\*\\(?:response\\|goals\\)\\*" :ignore t)
(set-lookup-handlers! 'company-coq-mode

View file

@ -3,20 +3,10 @@
(def-package! elixir-mode
:defer t
:init
;; Disable default smartparens config; there are too many, they're intrusive
;; and we only want a subset of them (defined below).
;; Disable default smartparens config. There are too many pairs; we only want
;; a subset of them (defined below).
(provide 'smartparens-elixir)
: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
;; Functional
:def "def"
@ -30,6 +20,16 @@
:for "for"
: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
:when (featurep! :completion company)
:commands alchemist-company

View file

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

View file

@ -9,7 +9,8 @@
to a pop up buffer."
(require 'pp)
(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
(concat "(progn "
(buffer-substring-no-properties beg end)
@ -97,16 +98,17 @@ library/userland functions"
(defun +emacs-lisp|extend-imenu ()
"Improve imenu support with better expression regexps and Doom-specific forms."
(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)
("Package" "^\\s-*(\\(?:def-\\)?package! +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Package" "^\\s-*;;;###package\\s-+\\(\\_<[^ ()\n]+\\_>\\)$" 1)
("Major modes" "^\\s-*(define-derived-mode +\\([^ ()\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\\))")
("Modes" "^\\s-*(define-\\(?:global\\(?:ized\\)?-minor\\|generic\\|minor\\)-mode +\\([^ ()\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)
("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))))
@ -121,3 +123,11 @@ library/userland functions"
if (file-in-directory-p buffer-file-name dir)
return t)))
(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
"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
;; to pretend it isn't loaded
(defer-feature! elisp-mode emacs-lisp-mode)
@ -11,14 +16,14 @@
;;
;; Config
(add-to-list 'auto-mode-alist '("\\.Cask\\'" . emacs-lisp-mode))
(after! elisp-mode
(def-package! elisp-mode
:mode ("\\.Cask\\'" . emacs-lisp-mode)
:config
(set-repl-handler! 'emacs-lisp-mode #'+emacs-lisp/open-repl)
(set-eval-handler! 'emacs-lisp-mode #'+emacs-lisp-eval)
(set-lookup-handlers! 'emacs-lisp-mode
:definition #'elisp-def
:documentation #'info-lookup-symbol)
:documentation #'+emacs-lisp-lookup-documentation)
(set-docsets! 'emacs-lisp-mode "Emacs Lisp")
(set-pretty-symbols! 'emacs-lisp-mode :lambda "lambda")
(set-rotate-patterns! 'emacs-lisp-mode
@ -35,14 +40,15 @@
mode-name "Elisp"
;; Don't treat autoloads or sexp openers as outline headers, we have
;; hideshow for that.
outline-regexp ";;;;* [^ \t\n]")
outline-regexp +emacs-lisp-outline-regexp)
;; variable-width indentation is superior in elisp
(add-to-list 'doom-detect-indentation-excluded-modes 'emacs-lisp-mode nil #'eq)
(add-hook! 'emacs-lisp-mode-hook
#'(;; 3rd-party functionality
auto-compile-on-save-mode outline-minor-mode
auto-compile-on-save-mode
outline-minor-mode
;; initialization
+emacs-lisp|extend-imenu))
@ -54,7 +60,7 @@
(font-lock-add-keywords
'emacs-lisp-mode
(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
(when +emacs-lisp-enable-extra-fontification
`((+emacs-lisp-highlight-vars-and-faces . +emacs-lisp--face)))))
@ -104,6 +110,7 @@
;; `overseer'
(autoload 'overseer-test "overseer" nil t)
(remove-hook 'emacs-lisp-mode-hook 'overseer-enable-mode)
(def-package! flycheck-cask
@ -114,12 +121,20 @@
(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
(def-project-mode! +emacs-lisp-ert-mode
:modes (emacs-lisp-mode)
:match "/test[/-].+\\.el$")
:match "/test[/-].+\\.el$"
:add-hooks (overseer-enable-mode))
(associate! buttercup-minor-mode
:modes (emacs-lisp-mode)

View file

@ -1,11 +1,14 @@
;; -*- no-byte-compile: t; -*-
;;; lang/emacs-lisp/packages.el
(package! elisp-mode :built-in t)
(package! auto-compile)
(package! highlight-quoted)
(package! macrostep)
(package! overseer)
(package! elisp-def)
(package! elisp-demos)
(when (featurep! :tools flycheck)
(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$"
;; rebar files
"/rebar\\.config\\(?:\\.script\\)?$"
;; erlang configs
"/\\(?:app\\|sys\\)\\.config$"))
(add-to-list 'auto-mode-alist (cons regexp 'erlang-mode)))
(def-package! erlang
:mode ("\\.erlang$" . erlang-mode)
:mode ("/rebar\\.config\\(?:\\.script\\)?$" . erlang-mode)
:mode ("/\\(?:app\\|sys\\)\\.config$" . erlang-mode))
(def-package! flycheck-rebar3

View file

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

View file

@ -21,7 +21,7 @@
"goimports"))))
(if (featurep! +lsp)
(add-hook 'go-mode-hook #'+lsp|init)
(add-hook 'go-mode-hook #'lsp!)
(add-hook 'go-mode-hook #'go-eldoc-setup))
(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; -*-
(cond ((featurep! +intero) (load! "+intero"))
((featurep! +dante) (load! "+dante")))
((featurep! +dante) (load! "+dante"))
((featurep! +lsp) (load! "+lsp")))
;;
;; Common packages
(after! haskell-mode
(setq haskell-process-suggest-remove-import-lines t ; warnings for redundant imports etc
haskell-process-auto-import-loaded-modules t)
(when (featurep! :tools 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))
haskell-process-auto-import-loaded-modules t
haskell-process-show-overlays (not (featurep! :tools flycheck))) ; redundant with flycheck
(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-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")
(map! :localleader

View file

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

View file

@ -3,7 +3,7 @@
(def-package! lsp-java
:after-call java-mode
:init (add-hook 'java-mode-hook #'+lsp|init)
:init (add-hook 'java-mode-hook #'lsp!)
:config
;; TODO keybinds
;; 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)
(cond ((featurep! +lsp) (load! "+lsp"))
((featurep! +meghanada) (load! "+meghanada"))
;; TODO lang/java +lsp (lsp-java?)
;; ((featurep! +lsp) (load! "+lsp"))
)
(cond ((featurep! +lsp) (load! "+lsp"))
((featurep! +meghanada) (load! "+meghanada")))
;;

View file

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

View file

@ -1,5 +1,10 @@
;;; 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
:hook (LaTeX-mode . reftex-mode)
:config

View file

@ -1,6 +1,6 @@
;;; lang/latex/+viewers.el -*- lexical-binding: t; -*-
(cl-block 'viewer
(catch 'found-viewer
(dolist (viewer +latex-viewers)
(if (pcase viewer
(`skim
@ -33,7 +33,7 @@
;; Update PDF buffers after successful LaTeX runs
(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
(add-to-list 'TeX-view-program-list '("preview-pane" latex-preview-pane-mode))
@ -44,7 +44,6 @@
(setq latex-preview-pane-multifile-mode 'auctex)
(define-key! doc-view-mode-map
(kbd "ESC") #'delete-window
"q" #'delete-window
"k" (λ! (quit-window) (delete-window))))
"ESC" #'delete-window
"q" #'delete-window
"k" (λ! (quit-window) (delete-window))))

View file

@ -14,7 +14,7 @@
(let* ((offset LaTeX-indent-level)
(contin (or (and (boundp '+latex-indent-level-item-continuation)
+latex-indent-level-item-continuation)
(* 4 LaTeX-indent-level)))
(* 4 offset)))
(re-beg "\\\\begin{")
(re-end "\\\\end{")
(re-env "\\(itemize\\|\\enumerate\\|description\\)")
@ -37,8 +37,7 @@
indent)
((looking-at "\\\\item")
(+ offset indent))
(t
(+ contin indent))))))
((+ contin indent))))))
;;;###autoload
(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)
;; Fold TeX macros
(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
(set-popup-rule! " output\\*$" :size 15)
;; 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
(cl-find-if #'byte-code-function-p find-file-hook)
'local))
;; Enable rainbow mode after applying styles to the buffer
(add-hook 'TeX-update-style-hook #'rainbow-delimiters-mode)
(when (featurep! :tools flyspell)
(add-hook 'latex-mode-local-vars-hook #'flyspell-mode))
(add-hook 'latex-mode-local-vars-hook #'flyspell-mode!)
;; All these excess pairs dramatically slow down typing in latex buffers, so
;; we remove them. Let snippets do their job.
(after! smartparens-latex

View file

@ -11,7 +11,7 @@
(let ((delim "~~"))
(if (markdown-use-region-p)
;; Active region
(cl-destructuring-bind (beg end)
(cl-destructuring-bind (beg . end)
(markdown-unwrap-things-in-region
(region-beginning) (region-end)
+markdown--regex-del 2 4)
@ -20,3 +20,23 @@
(if (thing-at-point-looking-at +markdown--regex-del)
(markdown-unwrap-thing-at-point nil 2 4)
(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