diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE
new file mode 100644
index 000000000..ff0b5bb67
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE
@@ -0,0 +1,39 @@
+Here are some things you should try before filing a bug report:
+
++ Run `make install` to ensure all plugins are installed.
++ `void-function` or `void-variable` errors could signal an out-of-date autoloads file. Run `make autoloads` or `M-x doom//reload-autoloads` to update it.
++ Scan for common OS/environment issues with `make doctor`.
++ Never debug byte-compiled code. It will interfere in subtle ways. Clean up \*.elc files with `make clean` or `M-x doom//clean-byte-compiled-files`.
++ Check [the FAQ](https://github.com/hlissner/doom-emacs/wiki/FAQ#troubleshooting) to see if your issue is mentioned.
++ Check the relevant module's README.org, if one exists. There may be extra steps to getting certain features to work.
+
+If none of those help, remove this section and fill out the four sections in the template below.
+
+---
+
+### Observed behavior
+
+Describe what happened. Any aids you can include (that you think could be relevant) are a tremendous help; like a screencast gif, video, or link to your customizations for Doom (e.g. a repo or a pastebin).
+
+### Expected behavior
+
+Describe what you _expected_ to happen.
+
+### Steps to reproduce
+
+1. Select these example steps,
+2. Delete them,
+3. And replace them with precise steps to reproduce your issue.
+
+### System information
+
+
+Click to expand
+
+```
+Replace this line with the output of *one* of these commands:
+
++ `M-x doom/info` (from inside Emacs)
++ `DEBUG=1 make doctor` (command line)
+```
+
diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE
new file mode 100644
index 000000000..c7cab1bfb
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE
@@ -0,0 +1,5 @@
+Thank you for contributing to Doom!
+
+Before you submit this PR, please make sure your PR is targeted at develop, not
+master (unless this is a fix for a critical error). Then replace this message
+with a description of your changes.
diff --git a/.gitignore b/.gitignore
index f29afbc1e..47cf11c70 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
.cask/
var/
/init.el
+modules/private/
# emacs tempfiles that shouldn't be there
.mc-lists.el
diff --git a/CHANGELOG.org b/CHANGELOG.org
index 113e95879..ce6b4c018 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -12,6 +12,91 @@
- [[#200-jan-17-2017][2.0.0 (Jan 17, 2017)]]
* Unreleased (develop)
++ *Module changes:*
+ + Add =private/default= to replace =private/hlissner=, which is a more generic
+ "starter" module for new users. My private module is now at
+ [[https://github.com/hlissner/doom-emacs-private][hlissner/doom-emacs-private]].
++ =general=
+ + Fix "peculiar error" messages when running =bin/doom-doctor=, caused by
+ poorly thought out error handling (see [[https://github.com/hlissner/doom-emacs/issues/175][#175]]).
+ + Fix ~doom/am-i-secure~ command.
+ + Add unicode symbols to package management commands. Looks a little nicer <3.
+ + Transform =recentf= entries into their absolute paths with symlinks resolved
+ (using ~file-truename~).
+ + Local data and cache files are no longer host-namespaced. Originally, this
+ was meant to facilitate using the same config files (symlinked) across
+ different computers (e.g. via dropbox). Byte-compiled packages on one
+ computer would cause errors on another, so I abandoned this practice, making
+ ~doom-host-dir~ unnecessary.
+ + Fix an issue during live byte-compilation (with auto-compile-on-save-mode)
+ where ~gc-cons-threshold~ would get set to 304mb in the user's active
+ session, causing freezes and stuttering.
+ + Improve error handling when byte compiling Doom. It now cleans up after
+ itself if something goes wrong, with improved error handling overall.
+ + Fix =stringp= error thrown by ~doom-fetch~ in noninteractive sessions.
+ + =core= Improve GPG integration by setting ~epa-file-encrypt-to~ to
+ ~user-mail-address~, and ~epa-pinentry-mode~ to ~'loopback~ (so that Emacs
+ will prompt you for the passphrase in the minibuffer).
+ + =core-packages= Fix ~doom-module-pairs~ returning pairs in arbitrary order,
+ causing load order errors. This is because the ~hash-table-values~ function
+ in Emacs 25 and under uses ~maphash~, which reverses the hash-table, while
+ newer versions use ~cl-loop~, which doesn't.
+ + =core-packages= Fix ~doom//*~ not running from the correct
+ default-directory, causing errors.
+ + =core-ui= Fix cryptic missing-font errors (also, they are warnings now).
+ + =core-ui= Account for Emacs 26 line numbers when calculating
+ ~visual-fill-column-width~.
+ + =core-editor= the =KILL= argument for ~quit-window &optional KILL WINDOW~
+ has been flipped and now kills the window's buffer by default.
+ + =core-projects= Add ~doom-project-find-file~ and ~doom-project-browse~ for
+ interactively fuzzy-finding and opening files in a directory/project.
+ + Add ~doom/info~ command for collecting information about your system and
+ session and puts it in the clipboard. This is to make it easier for those
+ reporting bugs to easily include it.
+ + Fix ibuffer windows not being handed off to popup system (see [[https://github.com/hlissner/doom-emacs/issues/309][#309]]).
++ =feature=
+ + =file-templates=
+ + Add a file template for fish shell scripts (thanks to [[https://github.com/amosbird][amosbird]]).
+ + Fix some file templates not being inserted, like module README.org files.
+ + =version-control= When evil-mode is available, start git commit message
+ buffers in insert mode (see [[https://github.com/hlissner/doom-emacs/issues/300][#300]]).
+ + =jump= Always prompt for provider when no major-mode specific online jumper
+ is defined (for ~+jump/online~ and ~+jump/documentation~).
++ =ui=
+ + =doom-dashboard=
+ + Fix ~whitespace-mode~ and ~show-trailing-whitespace~ turning the dashboard
+ into a Christmas tree.
+ + Add the ~+doom-dashboard-pwd-policy~ option, giving you control over how
+ ~default-directory~ is set in the dashboard. By default this is set to
+ ~'last-project~, meaning the dashboard's cwd will match the project of the
+ last buffer you killed.
++ =completion=
+ + =ivy= Fix TAB only half-triggering auto-completion (see [[https://github.com/hlissner/doom-emacs/issues/303][#303]]).
++ =lang=
+ + =cc=
+ + Add =rtags= support for better code navigation. This replaces gxtag and
+ etag support. Also includes automatic management of the rdm daemon.
+ + Improved support for JSON compilation databases. Irony-mode (and by
+ extension its flycheck and company plugins will now pick them up with more
+ consistency). This ensures all these tools run with the same compile
+ options as your project.
+ + New ~+cc/reload-compile-db~ commands forcibly refreshes the compilation db
+ of your current project, updating irony and running rtags daemon, if any.
+ + The ~+cc-include-paths~ and ~+cc-compiler-options~ options have been
+ renamed to ~+cc-default-include-paths~ and ~+cc-default-compiler-options~
+ for clarity.
+ + Fix irony-mode complaining when it is enabled in non-C major-modes.
+ + =org=
+ + Change repo source for org-plus-contrib to emacsmirror.
+ + Fix ~+org-dir~ being resolved too soon, robbing the user of the
+ opportunity to change it in their private module.
+ + Fix ~invalid file location~ error when capturing to a TODO template.
+ + Prevent =org-plus-contrib= from being installed on Emacs 26+, as 9.1.4 is
+ included with it.
+ + Fix invalid function errors when drag'n'dropping files into org buffers
+ (see [[https://github.com/hlissner/doom-emacs/issues/307][#307]]).
+ + =java= Fix Doom install meghanada server while byte compiling your Emacs
+ configuration.
* 2.0.8 (Dec 09, 2017)
+ *Module changes:*
diff --git a/bin/doom-doctor b/bin/doom-doctor
index a57693582..eb8b55108 100755
--- a/bin/doom-doctor
+++ b/bin/doom-doctor
@@ -8,6 +8,7 @@
;; In case it isn't defined (in really old versions of Emacs, like the one that
;; ships with MacOS).
(defvar user-emacs-directory (expand-file-name "~/.emacs.d/"))
+(defvar doom-debug-mode (getenv "DEBUG"))
(unless (equal (expand-file-name user-emacs-directory)
(expand-file-name "~/.emacs.d/"))
@@ -15,14 +16,20 @@
(require 'pp)
+(defsubst string-trim-right (string &optional regexp)
+ (if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
+ (replace-match "" t t string)
+ string))
+
;;
(defvar doom-init-p nil)
(defvar doom-errors 0)
(defmacro check! (cond &rest body)
(declare (indent defun))
- `(when ,cond
- ,@body
- (setq doom-errors (1+ doom-errors))))
+ `(let ((it ,cond))
+ (when it
+ ,@body
+ (setq doom-errors (1+ doom-errors)))))
(defun indented (spc msg)
(declare (indent defun))
@@ -57,26 +64,18 @@
"\n")))
(buffer-string)))
-(defmacro wait-for! (var if-body &optional else-body)
- (declare (indent defun))
- `(let ((i 0))
- (while (and (not ,var)
- (< i 5))
- (sleep-for 1)
- (setq i (1+ i)))
- (if ,var
- ,if-body
- ,else-body)))
+(defun sh (cmd)
+ (string-trim-right (shell-command-to-string cmd)))
(defun color (code msg &rest args)
(format "\e[%dm%s\e[%dm" code (apply #'format msg args) 0))
(defalias 'msg! #'message)
-(defmacro error! (&rest args) `(message (color 1 (color 31 ,@args))))
-(defmacro warn! (&rest args) `(message (color 1 (color 33 ,@args))))
-(defmacro success! (&rest args) `(message (color 1 (color 32 ,@args))))
-(defmacro log! (&rest args) `(if doom-debug-mode (message (color 34 ,@args))))
-(defmacro explain! (&rest args) `(message (indented 2 (autofill ,@args))))
+(defmacro error! (&rest args) `(msg! (color 1 (color 31 ,@args))))
+(defmacro warn! (&rest args) `(msg! (color 1 (color 33 ,@args))))
+(defmacro success! (&rest args) `(msg! (color 1 (color 32 ,@args))))
+(defmacro section! (&rest args) `(msg! (color 34 ,@args)))
+(defmacro explain! (&rest args) `(msg! (indented 2 (autofill ,@args))))
;;; Polyfills
;; early versions of emacs won't have this
@@ -88,15 +87,21 @@
;; --- start a'doctorin' --------------------------------------
-(msg! "%s\nRunning Emacs v%s, commit %s"
+(msg! "%s\nRunning Emacs v%s, commit %s\n"
(color 1 "DOOM Doctor")
(color 1 emacs-version)
(if (executable-find "git")
- (shell-command-to-string "git rev-parse HEAD")
+ (sh "git rev-parse HEAD")
"n/a"))
+
+(msg! "shell: %s%s"
+ (getenv "SHELL")
+ (if (equal (getenv "SHELL") (sh "echo $SHELL"))
+ ""
+ (color 31 " (mismatch)")))
(when (boundp 'system-configuration-features)
(msg! "Compiled with:\n%s" (indented 2 (autofill system-configuration-features))))
-(msg! "uname -a:\n%s" (indented 2 (autofill (shell-command-to-string "uname -a"))))
+(msg! "uname -a:\n%s\n" (indented 2 (autofill (sh "uname -a"))))
(let (doom-core-packages doom-debug-mode)
(condition-case ex
@@ -108,11 +113,10 @@
(doom|finalize)
(success! "Attempt to load DOOM: success! Loaded v%s" doom-version)
(when (executable-find "git")
- (msg! "Revision %s"
- (or (ignore-errors
- (let ((default-directory user-emacs-directory))
- (shell-command-to-string "git rev-parse HEAD")))
- "\n"))))
+ (msg! "Revision %s\n"
+ (ignore-errors
+ (let ((default-directory user-emacs-directory))
+ (sh "git rev-parse HEAD"))))))
('error (warn! "Attempt to load DOOM: failed\n %s\n"
(or (cdr-safe ex) (car ex))))))
@@ -120,7 +124,7 @@
;; --- is emacs set up properly? ------------------------------
-(log! "test-emacs")
+(section! "test-emacs")
(check! (version< emacs-version "25.1")
(error! "Important: Emacs %s detected [%s]" emacs-version (executable-find "emacs"))
(explain!
@@ -133,13 +137,13 @@
;; --- is the environment set up properly? --------------------
;; windows? windows
-(log! "test-windows")
+(section! "test-windows")
(check! (memq system-type '(windows-nt ms-dos cygwin))
(warn! "Warning: Windows detected")
(explain! "DOOM was designed for MacOS and Linux. Expect a bumpy ride!"))
;; are all default fonts present
-(log! "test-fonts")
+(section! "test-fonts")
(if (not (fboundp 'find-font))
(progn
(warn! "Warning: unable to detect font")
@@ -162,19 +166,19 @@
"case, ignore this warning."))))))
;; gnutls-cli & openssl
-(log! "test-gnutls")
+(section! "test-gnutls")
(cond ((executable-find "gnutls-cli"))
((executable-find "openssl")
- (let* ((output (shell-command-to-string "openssl ciphers -v"))
+ (let* ((output (sh "openssl ciphers -v"))
(protocols
(let (protos)
(mapcar (lambda (row)
(add-to-list 'protos (cadr (split-string row " " t))))
- (split-string (shell-command-to-string "openssl ciphers -v") "\n"))
+ (split-string (sh "openssl ciphers -v") "\n"))
(delq nil protos))))
(check! (not (or (member "TLSv1.1" protocols)
(member "TLSv1.2" protocols)))
- (let ((version (cadr (split-string (shell-command-to-string "openssl version") " " t))))
+ (let ((version (cadr (split-string (sh "openssl version") " " t))))
(warn! "Warning: couldn't find gnutls-cli, and OpenSSL is out-of-date (v%s)" version)
(explain!
"This may not affect your Emacs experience, but there are security "
@@ -198,7 +202,7 @@
"network, provider, government, neckbearded mother-in-laws, geeky roommates, "
"or just about anyone who knows more about computers than you do!"))))
-(log! "test-tls")
+(section! "test-tls")
(cond ((not (string-match-p "\\_" system-configuration-features))
(warn! "Warning: You didn't install Emacs with gnutls support")
(explain!
@@ -211,53 +215,50 @@
" brew tap d12frosted/emacs-plus"
" brew install emacs-plus"))))
+ ((not (fboundp 'url-retrieve-synchronously))
+ (error! "Can't find url-retrieve-synchronously function. Are you running Emacs 24+?"))
+
((or (executable-find "gnutls-cli")
(executable-find "openssl"))
(let ((tls-checktrust t)
(gnutls-verify-error t))
- (dolist (url '("https://elpa.gnu.org"
- "https://melpa.org"))
- (condition-case-unless-debug ex
- (let (result)
- (let ((inhibit-message t))
- (url-retrieve url (lambda (status &rest _) (setq result status))))
- (wait-for! result
- (when (getenv "DEBUG")
- (success! "Verified %s" (nth 2 (split-string url "/"))))
- (signal 'timed-out url)))
- ('timed-out
- (error! "Timed out trying to contact %s" ex))
- ('error
- (check! t
- (error! "Rejected %s" url)
- (explain! (pp-to-string ex))))))
+ (dolist (url '("https://elpa.gnu.org" "https://melpa.org"))
+ (check! (condition-case-unless-debug e
+ (if (let ((inhibit-message t)) (url-retrieve-synchronously url))
+ (ignore (success! "Validated %s" url))
+ 'empty)
+ ('timed-out 'timeout)
+ ('error e))
+ (pcase it
+ (`empty (error! "Couldn't reach %s" url))
+ (`timeout (error! "Timed out trying to contact %s" ex))
+ (_
+ (error! "Failed to validate %s" url)
+ (when doom-debug-mode
+ (explain! (pp-to-string it)))))))
(dolist (url '("https://self-signed.badssl.com"
"https://wrong.host.badssl.com/"))
- (condition-case-unless-debug ex
- (let (result)
- (let ((inhibit-message t))
- (url-retrieve url (lambda (status &rest _) (setq result status))))
- (wait-for! result
- (check! t
- (warn! "Verified %s (this shouldn't happen!)" (nth 2 (split-string url "/")))
- (explain! (pp-to-string result)))
- (signal 'timed-out url)))
- ('timed-out
- (error! "Timed out trying to contact %s" ex))
- ('error
- (when (getenv "DEBUG")
- (success! "Rejected %s (a good thing!)" url)
- (explain! (pp-to-string ex))))))))
+ (check! (condition-case-unless-debug e
+ (if (let ((inhibit-message t)) (url-retrieve-synchronously url))
+ t
+ 'empty)
+ ('timed-out 'timeout)
+ ('error (ignore (success! "Successfully rejected %s" url))))
+ (pcase it
+ (`empty (error! "Couldn't reach %s" url))
+ (`timeout (error! "Timed out trying to contact %s" ex))
+ (_
+ (error! "Validated %s (this shouldn't happen!)" url)))))))
(t
(error! "Nope!")))
;; bsd vs gnu tar
-(log! "test-tar")
+(section! "test-tar")
(let ((tar-bin (or (executable-find "gtar")
(executable-find "tar"))))
(if tar-bin
- (check! (not (string-match-p "(GNU tar)" (shell-command-to-string (format "%s --version" tar-bin))))
+ (check! (not (string-match-p "(GNU tar)" (sh (format "%s --version" tar-bin))))
(warn! "Warning: BSD tar detected")
(explain!
"QUELPA (through package-build) uses the system tar to build plugins, but it "
@@ -275,50 +276,51 @@
;; --- report! ------------------------------------------------
-(when (getenv "DEBUG")
+(when doom-debug-mode
(msg! "\n====\nHave some debug information:\n")
(when (bound-and-true-p doom-modules)
(msg! " + enabled modules:\n%s"
- (indented 4
- (columns 3 23
- (mapcar (lambda (x) (format "+%s" x))
- (mapcar #'cdr (doom-module-pairs)))))))
+ (indented 4
+ (columns 3 23
+ (mapcar (lambda (x) (format "+%s" x))
+ (mapcar #'cdr (doom-module-pairs)))))))
(when (and (bound-and-true-p doom-packages)
(require 'package nil t))
(msg! " + enabled packages:\n%s"
- (indented 4
- (columns 2 35
- (mapcar (lambda (pkg)
- (let ((desc (cadr (assq pkg package-alist))))
- (when desc
- (package-desc-full-name desc))))
- (sort (mapcar #'car doom-packages) #'string-lessp))))))
+ (indented 4
+ (columns 2 35
+ (delq nil
+ (mapcar (lambda (pkg)
+ (let ((desc (cadr (assq pkg package-alist))))
+ (when desc
+ (package-desc-full-name desc))))
+ (sort (mapcar #'car doom-packages) #'string-lessp)))))))
(msg! " + byte-compiled files:\n%s"
- (indented 4
- (columns 2 39
- (let ((files (append (directory-files-recursively doom-core-dir ".elc$")
- (directory-files-recursively doom-modules-dir ".elc$"))))
- (or (and files (mapcar (lambda (file) (file-relative-name file doom-emacs-dir))
- (nreverse files)))
- (list "n/a"))))))
+ (indented 4
+ (columns 2 39
+ (let ((files (append (directory-files-recursively doom-core-dir ".elc$")
+ (directory-files-recursively doom-modules-dir ".elc$"))))
+ (or (and files (mapcar (lambda (file) (file-relative-name file doom-emacs-dir))
+ (nreverse files)))
+ (list "n/a"))))))
(msg! " + exec-path:\n%s"
- (indented 4
- (columns 1 79 exec-path)))
+ (indented 4
+ (columns 1 79 exec-path)))
(msg! " + PATH:\n%s"
- (indented 4
- (columns 1 79 (split-string (getenv "PATH") ":")))))
+ (indented 4
+ (columns 1 79 (split-string (getenv "PATH") ":")))))
;;
(if (= doom-errors 0)
(success! "Everything seems fine, happy Emacs'ing!")
(message "\n----")
(warn! "There were issues!")
- (unless (getenv "DEBUG")
+ (unless doom-debug-mode
(msg! "\nHopefully these can help you find problems. If not, run this doctor again with DEBUG=1:")
(msg! "\n DEBUG=1 make doctor\n")
(msg! "And file a bug report with its output at https://github.com/hlissner/.emacs.d/issues")))
diff --git a/core/autoload/buffers.el b/core/autoload/buffers.el
index 0b6815021..83369cd4c 100644
--- a/core/autoload/buffers.el
+++ b/core/autoload/buffers.el
@@ -4,8 +4,12 @@
;;;###autoload
(defvar doom-real-buffer-functions '()
- "A list of functions that are run to determine if a buffer is real.")
+ "A list of predicate functions run to determine if a buffer is real. These
+functions are iterated over with one argument, the buffer in question. If any
+function returns non-nil, the procession stops and the buffer is qualified as
+real.")
+;;;###autoload
(defvar-local doom-real-buffer-p nil
"If non-nil, this buffer should be considered real no matter what.")
@@ -14,36 +18,17 @@
"The name of the buffer to fall back to if no other buffers exist (will create
it if it doesn't exist).")
+
+;;
+;; Functions
+;;
+
;;;###autoload
(defun doom-fallback-buffer ()
"Returns the fallback buffer, creating it if necessary. By default this is the
scratch buffer."
(get-buffer-create doom-fallback-buffer))
-;;;###autoload
-(defun doom-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 "r")
- (cond ((region-active-p)
- (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))))
-
-
-;; Buffer Life and Death ;;;;;;;;;;;;;;;
;;;###autoload
(defalias 'doom-buffer-list #'buffer-list)
@@ -66,6 +51,28 @@ If no project is active, return all buffers."
if (doom-real-buffer-p buf)
collect buf))
+;;;###autoload
+(defun doom-real-buffer-p (&optional buffer-or-name)
+ "Returns t if BUFFER-OR-NAME is a 'real' buffer. The complete criteria for a
+real buffer is:
+
+ 1. The buffer-local value of `doom-real-buffer-p' (variable) is non-nil OR
+ 2. Any function in `doom-real-buffer-functions' must return non-nil when
+ passed this buffer OR
+ 3. The current buffer:
+ a) has a `buffer-file-name' defined AND
+ b) is not in a popup window (see `doom-popup-p') AND
+ c) is not a special buffer (its name isn't something like *Help*)
+
+If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
+ (when-let* ((buf (ignore-errors (window-normalize-buffer buffer-or-name))))
+ (or (buffer-local-value 'doom-real-buffer-p buf)
+ (run-hook-with-args-until-success 'doom-real-buffer-functions buf)
+ (not (or (doom-popup-p buf)
+ (minibufferp buf)
+ (string-match-p "^\\s-*\\*" (buffer-name buf))
+ (not (buffer-file-name buf)))))))
+
;;;###autoload
(defun doom-buffers-in-mode (modes &optional buffer-list derived-p)
"Return a list of buffers whose `major-mode' is `eq' to MODE(S).
@@ -112,8 +119,7 @@ If DERIVED-P, test with `derived-mode-p', otherwise use `eq'."
"Switch to the next buffer N times (previous, if N < 0), skipping over unreal
buffers. If there's nothing left, switch to `doom-fallback-buffer'. See
`doom-real-buffer-p' for what 'real' means."
- (let ((buffers (delq (current-buffer) (doom-real-buffer-list)))
- (project-dir (doom-project-root)))
+ (let ((buffers (delq (current-buffer) (doom-real-buffer-list))))
(cond ((or (not buffers)
(zerop (% n (1+ (length buffers)))))
(switch-to-buffer (doom-fallback-buffer) nil t))
@@ -130,96 +136,49 @@ buffers. If there's nothing left, switch to `doom-fallback-buffer'. See
do
(dotimes (_i (abs n))
(funcall move-func)))))
- (when (eq (current-buffer) (doom-fallback-buffer))
- (cd project-dir))
+ (force-mode-line-update)
(current-buffer)))
;;;###autoload
-(defun doom-real-buffer-p (&optional buffer-or-name)
- "Returns t if BUFFER-OR-NAME is a 'real' buffer. The complete criteria for a
-real buffer is:
-
- 1. The buffer-local value of `doom-real-buffer-p' (variable) is non-nil OR
- 2. Any function in `doom-real-buffer-functions' must return non-nil when
- passed this buffer OR
- 3. The current buffer:
- a) has a `buffer-file-name' defined AND
- b) is not in a popup window (see `doom-popup-p') AND
- c) is not a special buffer (its name isn't something like *Help*)
-
-If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
- (when-let* ((buf (ignore-errors (window-normalize-buffer buffer-or-name))))
- (or (buffer-local-value 'doom-real-buffer-p buf)
- (run-hook-with-args-until-success 'doom-real-buffer-functions buf)
- (not (or (doom-popup-p buf)
- (minibufferp buf)
- (string-match-p "^\\s-*\\*" (buffer-name buf))
- (not (buffer-file-name buf)))))))
-
-;;;###autoload
-(defun doom/next-buffer ()
- "Switch to the next real buffer, skipping non-real buffers. See
-`doom-real-buffer-p' for what 'real' means."
- (interactive)
- (doom--cycle-real-buffers +1))
-
-;;;###autoload
-(defun doom/previous-buffer ()
- "Switch to the previous real buffer, skipping non-real buffers. See
-`doom-real-buffer-p' for what 'real' means."
- (interactive)
- (doom--cycle-real-buffers -1))
+(defun doom-set-buffer-real (buffer flag)
+ "Forcibly mark BUFFER as FLAG (non-nil = real)."
+ (with-current-buffer buffer
+ (setq doom-real-buffer-p flag)))
;;;###autoload
(defun doom-kill-buffer (&optional buffer dont-save)
- "Kill BUFFER (falls back to current buffer if omitted) then switch to a real
-buffer. If the buffer is present in another window, only bury it.
+ "Kill BUFFER (defaults to current buffer), but make sure we land on a real
+buffer. Bury the buffer if the buffer is present in another window.
Will prompt to save unsaved buffers when attempting to kill them, unless
DONT-SAVE is non-nil.
See `doom-real-buffer-p' for what 'real' means."
- (setq buffer (or buffer (current-buffer)))
- (when (and (bufferp buffer) (buffer-live-p buffer))
- (let ((buffer-win (get-buffer-window buffer))
- (only-buffer-window-p (= 1 (length (get-buffer-window-list buffer nil t)))))
- ;; deal with unsaved buffers
- (when (and only-buffer-window-p
- (buffer-file-name buffer)
+ (unless buffer
+ (setq buffer (current-buffer)))
+ (when (and (bufferp buffer)
+ (buffer-live-p buffer))
+ (let ((buffer-win (get-buffer-window buffer)))
+ ;; deal with modified buffers
+ (when (and (buffer-file-name buffer)
(buffer-modified-p buffer))
(with-current-buffer buffer
(if (and (not dont-save)
(yes-or-no-p "Buffer is unsaved, save it?"))
(save-buffer)
(set-buffer-modified-p nil))))
- (if buffer-win
- ;; deal with dedicated windows
- (if (window-dedicated-p buffer-win)
- (unless (window--delete buffer-win t t)
- (split-window buffer-win)
- (window--delete buffer-win t t))
- ;; cycle to a real buffer
- (with-selected-window buffer-win
- (doom--cycle-real-buffers -1)
- (when buffer-win
- (unrecord-window-buffer buffer-win buffer))
- (when only-buffer-window-p
- (kill-buffer buffer)))
- (not (eq (current-buffer) buffer)))
- (kill-buffer buffer)))))
-
-;;;###autoload
-(defun doom-force-kill-buffer (&optional buffer dont-save)
- "Kill BUFFER globally and ensure all windows previously showing BUFFER have
-switched to a real buffer."
- (interactive)
- (let* ((buffer (or buffer (current-buffer)))
- (windows (get-buffer-window-list buffer nil t)))
- (doom-kill-buffer buffer dont-save)
- (dolist (win windows)
- (with-selected-window win
- (unless (doom-real-buffer-p)
- (doom/previous-buffer))))))
+ ;; kill the buffer (or close dedicated window)
+ (cond ((not buffer-win)
+ (kill-buffer buffer))
+ ((window-dedicated-p buffer-win)
+ (unless (window--delete buffer-win t t)
+ (split-window buffer-win)
+ (window--delete buffer-win t t)))
+ (t ; cycle to a real buffer
+ (with-selected-window buffer-win
+ (doom--cycle-real-buffers -1)
+ (kill-buffer buffer)))))
+ (not (eq (current-buffer) buffer))))
;;;###autoload
(defun doom-kill-buffer-and-windows (buffer)
@@ -229,23 +188,6 @@ switched to a real buffer."
(delete-window window)))
(kill-buffer buffer))
-;;;###autoload
-(defun doom-kill-process-buffers ()
- "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))
-
;;;###autoload
(defun doom-kill-matching-buffers (pattern &optional buffer-list)
"Kill all buffers (in current workspace OR in BUFFER-LIST) that match the
@@ -254,13 +196,33 @@ regex PATTERN. Returns the number of killed buffers."
(dolist (buf buffers (length buffers))
(doom-kill-buffer buf t))))
+
+;;
+;; Interactive commands
+;;
+
;;;###autoload
-(defun doom/kill-this-buffer ()
+(defun doom/kill-this-buffer (&optional interactive-p)
"Use `doom-kill-buffer' on the current buffer."
- (interactive)
- (when (and (not (doom-kill-buffer)) (called-interactively-p 'interactive))
+ (interactive (list 'interactive))
+ (when (and (not (doom-kill-buffer)) interactive-p)
(message "Nowhere left to go!")))
+;;;###autoload
+(defun doom/kill-this-buffer-in-all-windows (buffer &optional dont-save)
+ "Kill BUFFER globally and ensure all windows previously showing this buffer
+have switched to a real buffer.
+
+If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
+ (interactive
+ (list (current-buffer) current-prefix-arg))
+ (cl-assert (bufferp buffer) t)
+ (let ((windows (get-buffer-window-list buffer nil t)))
+ (doom-kill-buffer buffer dont-save)
+ (cl-loop for win in windows
+ if (doom-real-buffer-p (window-buffer win))
+ do (with-selected-window win (doom/previous-buffer)))))
+
;;;###autoload
(defun doom/kill-all-buffers (&optional project-p)
"Kill all buffers and closes their windows.
@@ -305,18 +267,46 @@ project."
(message "Killed %s buffers" n))))
;;;###autoload
-(defun doom/cleanup-buffers (&optional all-p)
- "Clean up buried and inactive process buffers in the current workspace."
+(defun doom/cleanup-session (&optional all-p)
+ "Clean up buried buries and orphaned processes in the current workspace. If
+ALL-P (universal argument), clean them up globally."
(interactive "P")
+ (run-hooks 'doom-cleanup-hook)
(let ((buffers (doom-buried-buffers (if all-p (buffer-list))))
- (n 0))
+ (n 0)
+ kill-buffer-query-functions)
(mapc #'kill-buffer buffers)
- (setq n (+ n (length buffers) (doom-kill-process-buffers)))
+ (setq n (+ n (length buffers) (doom/cleanup-processes)))
(when (called-interactively-p 'interactive)
(message "Cleaned up %s buffers" n))))
;;;###autoload
-(defun doom-set-buffer-real (buffer flag)
- "Forcibly mark a buffer's real property, no matter what."
- (with-current-buffer buffer
- (setq doom-real-buffer-p flag)))
+(defun doom/cleanup-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))
+
+;;;###autoload
+(defun doom/next-buffer ()
+ "Switch to the next real buffer, skipping non-real buffers. See
+`doom-real-buffer-p' for what 'real' means."
+ (interactive)
+ (doom--cycle-real-buffers +1))
+
+;;;###autoload
+(defun doom/previous-buffer ()
+ "Switch to the previous real buffer, skipping non-real buffers. See
+`doom-real-buffer-p' for what 'real' means."
+ (interactive)
+ (doom--cycle-real-buffers -1))
diff --git a/core/autoload/debug.el b/core/autoload/debug.el
index 77b48b4c5..9cd01271f 100644
--- a/core/autoload/debug.el
+++ b/core/autoload/debug.el
@@ -65,7 +65,7 @@ selection of all minor-modes, active or not."
in '("https://wrong.host.badssl.com/"
"https://self-signed.badssl.com/")
if (condition-case _e
- (url-retrieve bad (lambda (_retrieved) t))
+ (url-retrieve-synchronously bad)
(error nil))
collect bad)))
(error (format "tls seems to be misconfigured (it got %s)."
@@ -86,3 +86,15 @@ selection of all minor-modes, active or not."
(profiler-report)
(profiler-stop))
(setq doom--profiler (not doom--profiler)))
+
+;;;###autoload
+(defun doom/info ()
+ "Collects information about this session of Doom Emacs and copies it to the
+clipboard. Helpful when filing bug reports!"
+ (interactive)
+ (with-temp-buffer
+ (message "Producing information about your system...")
+ (call-process (expand-file-name "bin/doom-doctor" doom-emacs-dir) nil t)
+ (ansi-color-apply-on-region (point-min) (point-max))
+ (kill-new (buffer-string))
+ (message "Done. Copied to clipboard!")))
diff --git a/core/autoload/editor.el b/core/autoload/editor.el
index 3188c27c9..b98d53e75 100644
--- a/core/autoload/editor.el
+++ b/core/autoload/editor.el
@@ -2,7 +2,7 @@
;;;###autoload
(defun doom/sudo-find-file (file)
- "Open a file as root."
+ "Open FILE as root."
(interactive
(list (read-file-name "Open as root: ")))
(find-file (if (file-writable-p file)
@@ -218,8 +218,29 @@ consistent throughout a selected region, depending on `indent-tab-mode'."
(tabify beg end)
(untabify beg end)))
+;;;###autoload
+(defun doom/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 "r")
+ (cond ((region-active-p)
+ (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|enable-delete-trailing-whitespace ()
"Attaches `delete-trailing-whitespace' to a buffer-local `before-save-hook'."
(add-hook 'before-save-hook #'delete-trailing-whitespace nil t))
-
diff --git a/core/autoload/packages.el b/core/autoload/packages.el
index 7fb7356ad..c2049afdd 100644
--- a/core/autoload/packages.el
+++ b/core/autoload/packages.el
@@ -1,11 +1,13 @@
;;; core/autoload/packages.el -*- lexical-binding: t; -*-
+(require 'use-package)
+(require 'quelpa)
+
(defvar doom--last-refresh nil)
;;;###autoload
(defun doom-refresh-packages (&optional force-p)
"Refresh ELPA packages."
- (doom-initialize)
(when force-p
(doom-refresh-clear-cache))
(unless (or (persistent-soft-fetch 'last-pkg-refresh "emacs")
@@ -31,13 +33,14 @@
"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."
(cl-assert (symbolp name) t)
- (doom-initialize)
(cond ((and (or (quelpa-setup-p)
(error "Could not initialize quelpa"))
(assq name quelpa-cache))
'quelpa)
((assq name package-alist)
'elpa)
+ ((package-built-in-p name)
+ 'emacs)
((not noerror)
(error "%s package is not installed" name))))
@@ -84,7 +87,7 @@ installed with. Returns nil otherwise, or if package isn't installed."
(doom-initialize-packages)
(and (package-installed-p name)
(let* ((plist (cdr (assq name doom-packages)))
- (old-backend (doom-package-backend name t))
+ (old-backend (doom-package-backend name 'noerror))
(new-backend (if (plist-get plist :recipe) 'quelpa 'elpa)))
(not (eq old-backend new-backend)))))
@@ -114,14 +117,12 @@ If INSTALLED-ONLY-P, only return packages that are installed."
;;;###autoload
(defun doom-get-depending-on (name)
"Return a list of packages that depend on the package named NAME."
- (doom-initialize)
(when-let* ((desc (cadr (assq name package-alist))))
(mapcar #'package-desc-name (package--used-elsewhere-p desc nil t))))
;;;###autoload
(defun doom-get-dependencies-for (name &optional only)
"Return a list of dependencies for a package."
- (doom-initialize)
(package--get-deps name only))
;;;###autoload
@@ -156,8 +157,9 @@ Used by `doom//packages-update'."
(load ,(expand-file-name "core.el" doom-core-dir)))
(doom-package-outdated-p ',pkg)))
futures))
- (append (delq nil (mapcar #'doom-package-outdated-p elpa-pkgs))
- (delq nil (mapcar #'async-get (reverse futures)))))))
+ (delq nil
+ (append (mapcar #'doom-package-outdated-p elpa-pkgs)
+ (mapcar #'async-get (reverse futures)))))))
;;;###autoload
(defun doom-get-orphaned-packages ()
@@ -170,7 +172,8 @@ Used by `doom//packages-autoremove'."
(append (mapcar #'car doom-packages) doom-core-packages)))
(append (package--removable-packages)
(cl-loop for pkg in package-selected-packages
- if (doom-package-different-backend-p pkg)
+ if (and (doom-package-different-backend-p pkg)
+ (not (package-built-in-p pkg)))
collect pkg))))
;;;###autoload
@@ -213,7 +216,6 @@ Used by `doom//packages-install'."
(symbol-name (car other))))
(defun doom--packages-choose (prompt)
- (doom-initialize)
(let ((table (cl-loop for pkg in package-alist
unless (package-built-in-p (cdr pkg))
collect (cons (package-desc-full-name (cdr pkg))
@@ -269,7 +271,6 @@ example; the package name can be omitted)."
(defun doom-update-package (name &optional force-p)
"Updates package NAME (a symbol) if it is out of date, using quelpa or
package.el as appropriate."
- (doom-initialize)
(unless (package-installed-p name)
(user-error "%s isn't installed" name))
(when (doom-package-different-backend-p name)
@@ -298,7 +299,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'."
- (doom-initialize)
(unless (package-installed-p name)
(user-error "%s isn't installed" name))
(let ((inhibit-message (not doom-debug-mode))
@@ -318,13 +318,14 @@ package.el as appropriate."
;;
-;; Interactive commands
+;; Batch/interactive commands
;;
;;;###autoload
(defun doom//packages-install ()
"Interactive command for installing missing packages."
(interactive)
+ (message! "Looking for packages to install...")
(let ((packages (doom-get-missing-packages)))
(cond ((not packages)
(message! (green "No packages to install!")))
@@ -354,20 +355,20 @@ package.el as appropriate."
(dolist (pkg packages)
(message! "Installing %s" (car pkg))
(doom--condition-case!
- (message! " %s%s"
+ (message! "%s%s"
(cond ((and (package-installed-p (car pkg))
(not (doom-package-different-backend-p (car pkg))))
- (dark (white "ALREADY INSTALLED")))
+ (dark (white "⚠ ALREADY INSTALLED")))
((doom-install-package (car pkg) (cdr pkg))
- (green "DONE"))
+ (green "✓ DONE"))
(t
- (red "FAILED")))
+ (red "✕ FAILED")))
(if (plist-member (cdr pkg) :pin)
(format " [pinned: %s]" (plist-get (cdr pkg) :pin))
- "")))))
+ ""))))
- (message! (bold (green "Finished!")))
- (doom//reload-load-path))))
+ (message! (bold (green "Finished!")))
+ (doom//reload-load-path)))))
;;;###autoload
(defun doom//packages-update ()
@@ -404,8 +405,7 @@ package.el as appropriate."
(message!
(let ((result (doom-update-package (car pkg) t)))
(color (if result 'green 'red)
- " %s"
- (if result "DONE" "FAILED"))))))
+ (if result "✓ DONE" "✕ FAILED"))))))
(message! (bold (green "Finished!")))
(doom//reload-load-path)))))
@@ -414,29 +414,28 @@ package.el as appropriate."
(defun doom//packages-autoremove ()
"Interactive command for auto-removing orphaned packages."
(interactive)
+ (message! "Looking for orphaned packages...")
(let ((packages (doom-get-orphaned-packages)))
(cond ((not packages)
(message! (green "No unused packages to remove")))
- ((not (or (getenv "YES")
- (y-or-n-p
- (format "%s packages will be deleted:\n\n%s\n\nProceed?"
- (length packages)
- (mapconcat
- (lambda (sym)
- (format
- "+ %s (%s)"
- sym
- (let ((backend (doom-package-backend sym)))
- (if (doom-package-different-backend-p sym)
- (if (eq backend 'quelpa)
- "QUELPA->ELPA"
- "ELPA->QUELPA")
- (if (eq backend 'quelpa)
- "QUELPA"
- "ELPA")))))
- (sort (cl-copy-list packages) #'string-lessp)
- "\n")))))
+ ((not
+ (or (getenv "YES")
+ (y-or-n-p
+ (format
+ "%s packages will be deleted:\n\n%s\n\nProceed?"
+ (length packages)
+ (mapconcat
+ (lambda (sym)
+ (format "+ %s (%s)" sym
+ (let ((backend (doom-package-backend sym)))
+ (if (doom-package-different-backend-p sym)
+ (if (eq backend 'quelpa)
+ "QUELPA->ELPA"
+ "ELPA->QUELPA")
+ (upcase (symbol-name backend))))))
+ (sort (cl-copy-list packages) #'string-lessp)
+ "\n")))))
(message! (yellow "Aborted!")))
(t
@@ -446,13 +445,17 @@ package.el as appropriate."
(let ((result (doom-delete-package pkg t)))
(color (if result 'green 'red)
"%s %s"
- (if result "Removed" "Failed to remove")
+ (if result "✓ Removed" "✕ Failed to remove")
pkg)))))
(message! (bold (green "Finished!")))
(doom//reload-load-path)))))
+;;
+;; Interactive commands
+;;
+
;;;###autoload
(defalias 'doom/install-package #'package-install)
@@ -478,7 +481,9 @@ Use this interactively. Use `doom-delete-package' for direct calls."
(if (package-installed-p package)
(if (y-or-n-p (format "%s will be deleted. Confirm?" package))
(message "%s %s"
- (if (doom-delete-package package t) "Deleted" "Failed to delete")
+ (if (doom-delete-package package t)
+ "Deleted"
+ "Failed to delete")
package)
(message "Aborted"))
(message "%s isn't installed" package))))
diff --git a/core/autoload/popups.el b/core/autoload/popups.el
index a182d50c7..c903a964b 100644
--- a/core/autoload/popups.el
+++ b/core/autoload/popups.el
@@ -239,7 +239,7 @@ without leaving any trace behind (muahaha)."
(if (featurep 'evil)
#'evil-force-normal-state
#'keyboard-quit))
- (delete-window)))
+ (quit-restore-window nil 'kill)))
;;;###autoload
(defun doom/popup-this-buffer ()
@@ -413,12 +413,4 @@ properties."
(when (doom-popup-p window)
(setq doom-popup-windows (delq window doom-popup-windows))
(when doom-popup-remember-history
- (setq doom-popup-history (list (doom--popup-data window))))
- (let ((autokill-p (and (not doom-popup-inhibit-autokill)
- (doom-popup-property :autokill window))))
- (with-selected-window window
- (doom-popup-mode -1)
- (when autokill-p
- (when-let* ((process (get-buffer-process (current-buffer))))
- (set-process-query-on-exit-flag process nil))
- (kill-buffer (current-buffer)))))))
+ (setq doom-popup-history (list (doom--popup-data window))))))
diff --git a/core/autoload/system.el b/core/autoload/system.el
index 6fb264fc3..97b44e2da 100644
--- a/core/autoload/system.el
+++ b/core/autoload/system.el
@@ -48,8 +48,8 @@ is given, returns t if it matches the current system, and nil otherwise."
Requires the corresponding client, e.g. git for git repos, hg for mercurial,
etc."
(let* ((command (pcase fetcher
- (:github "git clone --depth 1 --recursive https://github.com/%s.git")
- (:git "git clone --depth 1 --recursive %s")
+ (:github "git clone --recursive https://github.com/%s.git")
+ (:git "git clone --recursive %s")
(:gist "git clone https://gist.github.com/%s.git")
;; TODO Add hg
(_ (error "%s is not a valid fetcher" fetcher))))
@@ -61,8 +61,8 @@ etc."
(error "%s couldn't be found" command))
(unless (file-directory-p dest)
(funcall (if noninteractive
- (lambda (&rest args) (princ (shell-command-to-string args)))
+ (lambda (c) (princ (shell-command-to-string c)))
#'async-shell-command)
(format "%s %s %s" bin args (shell-quote-argument dest)))
- (message! "Cloning %s -> %s" location dest))))
+ (message! "Cloning %s -> %s" location (file-relative-name dest)))))
diff --git a/core/autoload/test.el b/core/autoload/test.el
index 60669a57e..e41cd424c 100644
--- a/core/autoload/test.el
+++ b/core/autoload/test.el
@@ -74,17 +74,32 @@ If neither is available, run all tests in all enabled modules."
(defmacro def-test! (name &rest body)
"Define a namespaced ERT test."
(declare (indent defun) (doc-string 2))
- (unless (plist-get body :disabled)
+ (let (plist)
+ (while (keywordp (car body))
+ (push (pop body) plist))
+ (setq plist (reverse plist))
+ (when (plist-get plist :skip)
+ (setq body `((ert-skip nil) ,@body)))
+ (when-let* ((modes (doom-enlist (plist-get plist :minor-mode))))
+ (dolist (mode modes)
+ (setq body `((with-minor-mode!! ,mode ,@body)))))
+ (when-let* ((before (plist-get plist :before)))
+ (setq body `(,@before ,@body)))
+ (when-let* ((after (plist-get plist :after)))
+ (setq body `(,@body @after)))
`(ert-deftest
,(cl-loop with path = (file-relative-name (file-name-sans-extension load-file-name)
doom-emacs-dir)
for (rep . with) in '(("/test/" . "/") ("/" . ":"))
do (setq path (replace-regexp-in-string rep with path t t))
- finally return (intern (format "%s::%s" path name))) ()
- ()
- ,@body)))
+ finally return (intern (format "%s::%s" path name)))
+ ()
+ (with-temp-buffer
+ (save-mark-and-excursion
+ (save-window-excursion
+ ,@body))))))
-(defmacro should-buffer! (initial expected &rest body)
+(defmacro should-buffer!! (initial expected &rest body)
"Test that a buffer with INITIAL text, run BODY, then test it against EXPECTED.
INITIAL will recognize cursor markers in the form {[0-9]}. A {0} marker marks
@@ -112,7 +127,7 @@ against."
(lambda (m1 m2) (< (marker-position m1)
(marker-position m2))))
(when (equal (caar marker-list) "0")
- (goto-char! 0)))
+ (goto-char!! 0)))
,@body
(let ((result-text (buffer-substring-no-properties (point-min) (point-max)))
(point (point))
@@ -130,15 +145,22 @@ against."
(should (equal expected-text result-text))
(should same-point)))))))
-(defmacro goto-char! (index)
- "Meant to be used with `should-buffer!'. Will move the cursor to one of the
-cursor markers. e.g. Go to marker {2} with (goto-char! 2)."
- `(goto-char (point! ,index)))
+(defmacro goto-char!! (index)
+ "Meant to be used with `should-buffer!!'. Will move the cursor to one of the
+cursor markers. e.g. Go to marker {2} with (goto-char!! 2)."
+ `(goto-char (point!! ,index)))
-(defmacro point! (index)
- "Meant to be used with `should-buffer!'. Returns the position of a cursor
-marker. e.g. {2} can be retrieved with (point! 2)."
+(defmacro point!! (index)
+ "Meant to be used with `should-buffer!!'. Returns the position of a cursor
+marker. e.g. {2} can be retrieved with (point!! 2)."
`(cdr (assoc ,(cond ((numberp index) (number-to-string index))
((symbolp index) (symbol-name index))
((stringp index) index))
marker-list)))
+
+(defmacro with-minor-mode!! (mode &rest body)
+ "TODO"
+ (declare (indent defun))
+ `(progn (,mode +1)
+ ,@body
+ (,mode -1)))
diff --git a/core/core-editor.el b/core/core-editor.el
index 4b178e97c..96de4e8ab 100644
--- a/core/core-editor.el
+++ b/core/core-editor.el
@@ -58,6 +58,12 @@ modes are active and the buffer is read-only.")
(ignore (bury-buffer))))
(add-hook 'kill-buffer-query-functions #'doom|dont-kill-scratch-buffer)
+;; temporary windows often have q bound to `quit-window', which only buries the
+;; contained buffer. I rarely don't want that buffer killed, so...
+(defun doom*quit-window (orig-fn &optional kill window)
+ (funcall orig-fn (not kill) window))
+(advice-add #'quit-window :around #'doom*quit-window)
+
(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
@@ -75,43 +81,6 @@ fundamental-mode) for performance sake."
(fundamental-mode))))
(add-hook 'find-file-hook #'doom|check-large-file)
-;; Automatic minor modes
-(defvar doom-auto-minor-mode-alist '()
- "Alist mapping filename patterns to corresponding minor mode functions, like
-`auto-mode-alist'. All elements of this alist are checked, meaning you can
-enable multiple minor modes for the same regexp.")
-
-(defun doom|enable-minor-mode-maybe ()
- "Check file name against `doom-auto-minor-mode-alist'."
- (when buffer-file-name
- (let ((name buffer-file-name)
- (remote-id (file-remote-p buffer-file-name))
- (alist doom-auto-minor-mode-alist))
- ;; Remove backup-suffixes from file name.
- (setq name (file-name-sans-versions name))
- ;; Remove remote file name identification.
- (when (and (stringp remote-id)
- (string-match-p (regexp-quote remote-id) name))
- (setq name (substring name (match-end 0))))
- (while (and alist (caar alist) (cdar alist))
- (if (string-match-p (caar alist) name)
- (funcall (cdar alist) 1))
- (setq alist (cdr alist))))))
-(add-hook 'find-file-hook #'doom|enable-minor-mode-maybe)
-
-(defun doom*set-indirect-buffer-filename (orig-fn base-buffer name &optional clone)
- "In indirect buffers, `buffer-file-name' is nil, which can cause problems
-with functions that require it (like modeline segments)."
- (let ((file-name (buffer-file-name base-buffer))
- (buffer (funcall orig-fn base-buffer name clone)))
- (when (and file-name buffer)
- (with-current-buffer buffer
- (unless buffer-file-name
- (setq buffer-file-name file-name
- buffer-file-truename (file-truename file-name)))))
- buffer))
-(advice-add #'make-indirect-buffer :around #'doom*set-indirect-buffer-filename)
-
(push '("/LICENSE$" . text-mode) auto-mode-alist)
@@ -138,16 +107,15 @@ with functions that require it (like modeline segments)."
(def-package! recentf
:hook (doom-init . recentf-mode)
:config
- (setq recentf-save-file (concat doom-etc-dir "recentf")
+ (setq recentf-save-file (concat doom-cache-dir "recentf")
recentf-max-menu-items 0
recentf-max-saved-items 300
+ recentf-filename-handlers '(file-truename)
recentf-exclude
(list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$"
"^/var/folders/.+$"
;; ignore private DOOM temp files (but not all of them)
- (concat "^" (replace-regexp-in-string
- (concat "@" (regexp-quote (system-name)))
- "@" (abbreviate-file-name doom-host-dir))))))
+ (concat "^" (file-truename doom-local-dir)))))
;;
@@ -206,8 +174,8 @@ extension, try to guess one."
;; Auto-close delimiters and blocks as you type
(def-package! smartparens
+ :hook (doom-init . smartparens-global-mode)
:config
- (add-hook 'doom-init-hook #'smartparens-global-mode)
(require 'smartparens-config)
(setq sp-autowrap-region nil ; let evil-surround handle this
diff --git a/core/core-lib.el b/core/core-lib.el
index 4bf932203..d812d2b3e 100644
--- a/core/core-lib.el
+++ b/core/core-lib.el
@@ -1,6 +1,5 @@
;;; core-lib.el -*- lexical-binding: t; -*-
-(require 'cl-lib)
(require 'subr-x)
(load "async-autoloads" nil t)
(load "persistent-soft-autoloads" nil t)
diff --git a/core/core-packages.el b/core/core-packages.el
index e7013fbc4..c40ef27b5 100644
--- a/core/core-packages.el
+++ b/core/core-packages.el
@@ -51,11 +51,6 @@
"Non-nil if doom is done initializing (once `doom-post-init-hook' is done). If
this is nil after Emacs has started something is wrong.")
-(defvar doom-package-init-p nil
- "If non-nil, doom's package system has been initialized (by
-`doom-initialize'). This will be nill if you byte-compile your configuration (as
-intended).")
-
(defvar doom-init-time nil
"The time it took, in seconds, for DOOM Emacs to initialize.")
@@ -82,7 +77,7 @@ missing) and shouldn't be deleted.")
"The load path of built in Emacs libraries.")
(defvar doom--package-load-path ()
- "The load path of package libraries installed via ELPA or QUELPA.")
+ "The load path of package libraries installed via ELPA and QUELPA.")
(defvar doom--base-load-path
(append (list doom-core-dir doom-modules-dir)
@@ -135,19 +130,37 @@ are installed.
If you byte-compile core/core.el, this function will be avoided to speed up
startup."
- ;; Called early during initialization; only use native functions!
- (when (or (not doom-package-init-p) force-p)
- (setq load-path doom--base-load-path
- package-activated-list nil)
- ;; Ensure core folders exist
- (dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir package-user-dir))
- (unless (file-directory-p dir)
- (make-directory dir t)))
- (condition-case _ (package-initialize t)
- ('error
- (package-refresh-contents)
- (setq doom--refreshed-p t)
- (package-initialize t)))
+ ;; Called early during initialization; only use native (and cl-lib) functions!
+ (when (or force-p (not doom-init-p))
+ ;; Speed things up with a `load-path' for only the bare essentials
+ (let ((load-path doom--base-load-path))
+ ;; Ensure core folders exist, otherwise we get errors
+ (dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir doom-packages-dir))
+ (unless (file-directory-p dir)
+ (make-directory dir t)))
+ ;; Ensure package.el is initialized; we use its state
+ (setq package-activated-list nil)
+ (condition-case _ (package-initialize t)
+ ('error (package-refresh-contents)
+ (setq doom--refreshed-p t)
+ (package-initialize t)))
+ ;; Ensure core packages are installed
+ (let ((core-packages (cl-remove-if #'package-installed-p doom-core-packages)))
+ (when core-packages
+ (message "Installing core packages")
+ (unless doom--refreshed-p
+ (package-refresh-contents))
+ (dolist (package core-packages)
+ (let ((inhibit-message t))
+ (package-install package))
+ (if (package-installed-p package)
+ (message "✓ Installed %s" package)
+ (error "✕ Couldn't install %s" package)))
+ (message "Installing core packages...done")))
+ (setq doom-init-p t))))
+
+(defun doom-initialize-load-path (&optional force-p)
+ (when (or force-p (not doom--package-load-path))
;; We could let `package-initialize' fill `load-path', but it does more than
;; that alone (like load autoload files). If you want something prematurely
;; optimizated right, ya gotta do it yourself.
@@ -155,23 +168,7 @@ startup."
;; Also, in some edge cases involving package initialization during a
;; non-interactive session, `package-initialize' fails to fill `load-path'.
(setq doom--package-load-path (directory-files package-user-dir t "^[^.]" t)
- load-path (append load-path doom--package-load-path))
- ;; Ensure core packages are installed
- (dolist (pkg doom-core-packages)
- (unless (package-installed-p pkg)
- (unless doom--refreshed-p
- (package-refresh-contents)
- (setq doom--refreshed-p t))
- (let ((inhibit-message t))
- (package-install pkg))
- (if (package-installed-p pkg)
- (message "Installed %s" pkg)
- (error "Couldn't install %s" pkg))))
- (load "quelpa" nil t)
- (load "use-package" nil t)
- (setq doom-package-init-p t)
- (unless noninteractive
- (message "Doom initialized"))))
+ load-path (append doom--base-load-path doom--package-load-path))))
(defun doom-initialize-autoloads ()
"Ensures that `doom-autoload-file' exists and is loaded. Otherwise run
@@ -186,39 +183,35 @@ startup."
If FORCE-P is non-nil, do it even if they are.
This aggressively reloads core autoload files."
- (doom-initialize force-p)
+ (doom-initialize-load-path force-p)
(with-temp-buffer ; prevent buffer-local settings from propagating
- (let ((noninteractive t)
- (load-prefer-newer t)
- (load-fn
- (lambda (file &optional noerror)
- (condition-case-unless-debug ex
- (load file noerror :nomessage :nosuffix)
- ('error
- (error (format "(doom-initialize-packages) %s in %s: %s"
- (car ex)
- (file-relative-name file doom-emacs-dir)
- (error-message-string ex))
- :error))))))
+ (cl-flet
+ ((_load
+ (file &optional noerror interactive)
+ (condition-case-unless-debug ex
+ (let ((load-prefer-newer t)
+ (noninteractive (not interactive)))
+ (load file noerror :nomessage :nosuffix))
+ ('error
+ (lwarn 'doom-initialize-packages :warning
+ "%s in %s: %s"
+ (car ex)
+ (file-relative-name file doom-emacs-dir)
+ (error-message-string ex))))))
(when (or force-p (not doom-modules))
- (setq doom-modules nil)
- (let (noninteractive)
- (load (concat doom-core-dir "core.el") nil t))
- (funcall load-fn (expand-file-name "init.el" doom-emacs-dir))
+ (setq doom-modules nil
+ doom-packages nil)
+ (_load (concat doom-core-dir "core.el") nil 'interactive)
+ (_load (expand-file-name "init.el" doom-emacs-dir))
(when load-p
- (let (noninteractive)
- (funcall load-fn (doom-module-path :private user-login-name "init.el") t))
- (mapc load-fn (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir)))
- (cl-loop for (module . submodule) in (doom-module-pairs)
- for path = (doom-module-path module submodule "config.el")
- do (funcall load-fn path t))))
+ (mapc #'_load (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir)))
+ (_load (expand-file-name "init.el" doom-emacs-dir) nil 'interactive)))
(when (or force-p (not doom-packages))
(setq doom-packages nil)
- (funcall load-fn (expand-file-name "packages.el" doom-core-dir))
+ (_load (expand-file-name "packages.el" doom-core-dir))
(cl-loop for (module . submodule) in (doom-module-pairs)
for path = (doom-module-path module submodule "packages.el")
- do (funcall load-fn path t)))))
- (doom|finalize))
+ do (_load path 'noerror))))))
(defun doom-initialize-modules (modules)
"Adds MODULES to `doom-modules'. MODULES must be in mplist format.
@@ -295,7 +288,7 @@ include all modules, enabled or otherwise."
;; Certainly imprecise, especially where custom additions to
;; load-path are concerned, but I don't mind a [small] margin of
;; error in the plugin count in exchange for faster startup.
- (- (length load-path) (length doom--base-load-path))
+ (length doom--package-load-path)
(hash-table-size doom-modules)
(setq doom-init-time (float-time (time-subtract after-init-time before-init-time)))))
@@ -313,19 +306,17 @@ MODULES is an malformed plist of modules to load."
(doom-initialize-modules modules)
`(let (file-name-handler-alist)
(setq doom-modules ',doom-modules)
-
(unless noninteractive
+ (message "Doom initialized")
,@(cl-loop for (module . submodule) in (doom-module-pairs)
for module-path = (doom-module-path module submodule)
collect `(load! init ,module-path t) into inits
collect `(load! config ,module-path t) into configs
finally return (append inits configs))
-
(when (display-graphic-p)
(require 'server)
(unless (server-running-p)
(server-start)))
-
(add-hook 'doom-init-hook #'doom-packages--display-benchmark t)
(message "Doom modules initialized"))))
@@ -334,7 +325,7 @@ MODULES is an malformed plist of modules to load."
;; Ignore package if NAME is in `doom-disabled-packages'
(when (and (memq name doom-disabled-packages)
(not (memq :disabled plist)))
- (setq plist (append (list :disabled t) plist)))
+ (setq plist `(:disabled t ,@plist)))
;; If byte-compiling, ignore this package if it doesn't meet the condition.
;; This avoids false-positive load errors.
(unless (and (bound-and-true-p byte-compile-current-file)
@@ -377,31 +368,26 @@ to have them return non-nil (or exploit that to overwrite Doom's config)."
"Load a file relative to the current executing file (`load-file-name').
FILESYM is either a symbol or string representing the file to load. PATH is
-where to look for the file (a string representing a directory path), by default
-it is relative to `load-file-name', `byte-compile-current-file' or
+where to look for the file (a string representing a directory path). If omitted,
+the lookup is relative to `load-file-name', `byte-compile-current-file' or
`buffer-file-name' (in that order).
If NOERROR is non-nil, don't throw an error if the file doesn't exist."
- (let ((path (or (and path (or (and (symbolp path) (symbol-value path))
- (and (stringp path) path)
- (and (listp path) (eval path))))
+ (cl-assert (symbolp filesym) t)
+ (let ((path (or path
(and load-file-name (file-name-directory load-file-name))
(and (bound-and-true-p byte-compile-current-file)
(file-name-directory byte-compile-current-file))
(and buffer-file-name
- (file-name-directory buffer-file-name))))
- (filename (cond ((stringp filesym) filesym)
- ((symbolp filesym) (symbol-name filesym))
- (t (error "load! expected a string or symbol, got %s (a %s)"
- filesym (type-of filesym))))))
- (unless path
- (error "Could not find %s" filename))
+ (file-name-directory buffer-file-name))
+ (error "Could not detect path to look for '%s' in" filesym)))
+ (filename (symbol-name filesym)))
(let ((file (expand-file-name (concat filename ".el") path)))
(if (file-exists-p file)
`(load ,(file-name-sans-extension file) ,noerror
,(not doom-debug-mode))
(unless noerror
- (error "Could not load! file %s" file))))))
+ (error "Could not load file '%s' from '%s'" file path))))))
(defmacro require! (module submodule &optional flags reload-p)
"Loads the module specified by MODULE (a property) and SUBMODULE (a symbol).
@@ -507,8 +493,9 @@ loads MODULE SUBMODULE's packages.el file."
t)))
(defun doom-packages--async-run (fn)
- (let ((compilation-filter-hook
- (list (lambda () (ansi-color-apply-on-region compilation-filter-start (point))))))
+ (let* ((default-directory doom-emacs-dir)
+ (compilation-filter-hook
+ (list (lambda () (ansi-color-apply-on-region compilation-filter-start (point))))))
(compile (format "%s --quick --batch -l core/core.el -f %s"
(executable-find "emacs")
(symbol-name fn)))
@@ -527,15 +514,14 @@ call `doom/reload-load-path' remotely (through emacsclient)."
(interactive)
(byte-recompile-file (expand-file-name "core.el" doom-core-dir) t)
(cond (noninteractive
- (message "Reloading...")
(require 'server)
(when (server-running-p)
+ (message "Reloading active Emacs session...")
(server-eval-at server-name '(doom//reload-load-path))))
- (t
- (doom-initialize t)
- (message "Reloaded %d packages" (length doom--package-load-path))
- (run-with-timer 1 nil #'redraw-display)
- (run-hooks 'doom-reload-hook))))
+ ((let ((noninteractive t))
+ (doom-initialize-load-path t)
+ (message "%d packages reloaded" (length doom--package-load-path))
+ (run-hooks 'doom-reload-hook)))))
(defun doom//reload-autoloads ()
"Refreshes the autoloads.el file, specified by `doom-autoload-file'.
@@ -555,7 +541,7 @@ This should be run whenever init.el or an autoload file is modified. Running
;; state. `doom-initialize-packages' will have side effects otherwise.
(and (doom-packages--async-run 'doom//reload-autoloads)
(load doom-autoload-file))
- (doom-initialize-packages)
+ (doom-initialize-packages t)
(let ((targets
(file-expand-wildcards
(expand-file-name "autoload/*.el" doom-core-dir))))
@@ -571,13 +557,15 @@ This should be run whenever init.el or an autoload file is modified. Running
(delete-file doom-autoload-file)
(message "Deleted old autoloads.el"))
(dolist (file (reverse targets))
- (message (cond ((not (doom-packages--read-if-cookies file))
- "Ignoring %s")
- ((update-file-autoloads file nil doom-autoload-file)
- "Nothing in %s")
- (t
- "Scanned %s"))
- (file-relative-name file doom-emacs-dir)))
+ (message
+ (cond ((not (doom-packages--read-if-cookies file))
+ "⚠ Ignoring %s")
+ ((update-file-autoloads file nil doom-autoload-file)
+ "✕ Nothing in %s")
+ (t
+ "✓ Scanned %s"))
+ (file-relative-name file doom-emacs-dir)))
+ (make-directory (file-name-directory doom-autoload-file) t)
(let ((buf (get-file-buffer doom-autoload-file))
current-sexp)
(unwind-protect
@@ -646,33 +634,42 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
(error "No targets to compile"))
(let ((use-package-expand-minimally t))
(push (expand-file-name "init.el" doom-emacs-dir) compile-targets)
- (dolist (target compile-targets)
- (when (or (not recompile-p)
- (let ((elc-file (byte-compile-dest-file target)))
- (and (file-exists-p elc-file)
- (file-newer-than-file-p file elc-file))))
- (let ((result (if (doom-packages--read-if-cookies target)
- (byte-compile-file target)
- 'no-byte-compile))
- (short-name (file-relative-name target doom-emacs-dir)))
- (cl-incf
- (cond ((eq result 'no-byte-compile)
- (message! (dark (white "Ignored %s" short-name)))
- total-noop)
- ((null result)
- (message! (red "Failed to compile %s" short-name))
- total-fail)
- (t
- (message! (green "Compiled %s" short-name))
- (quiet! (load target t t))
- total-ok))))))
- (message!
- (bold
- (color (if (= total-fail 0) 'green 'red)
- "%s %s file(s) %s"
- (if recompile-p "Recompiled" "Compiled")
- (format "%d/%d" total-ok (- (length compile-targets) total-noop))
- (format "(%s ignored)" total-noop)))))))))
+ (condition-case ex
+ (progn
+ (dolist (target compile-targets)
+ (when (or (not recompile-p)
+ (let ((elc-file (byte-compile-dest-file target)))
+ (and (file-exists-p elc-file)
+ (file-newer-than-file-p file elc-file))))
+ (let ((result (if (doom-packages--read-if-cookies target)
+ (byte-compile-file target)
+ 'no-byte-compile))
+ (short-name (file-relative-name target doom-emacs-dir)))
+ (cl-incf
+ (cond ((eq result 'no-byte-compile)
+ (message! (dark (white "⚠ Ignored %s" short-name)))
+ total-noop)
+ ((null result)
+ (message! (red "✕ Failed to compile %s" short-name))
+ total-fail)
+ (t
+ (message! (green "✓ Compiled %s" short-name))
+ (quiet! (load target t t))
+ total-ok))))))
+ (message!
+ (bold
+ (color (if (= total-fail 0) 'green 'red)
+ "%s %s file(s) %s"
+ (if recompile-p "Recompiled" "Compiled")
+ (format "%d/%d" total-ok (- (length compile-targets) total-noop))
+ (format "(%s ignored)" total-noop)))))
+ (error
+ (message! (red "\n%%s\n\n%%s\n\n%%s")
+ "There were breaking errors."
+ (error-message-string ex)
+ "Reverting changes...")
+ (doom//clean-byte-compiled-files)
+ (message! (green "Finished (nothing was byte-compiled)")))))))))
(defun doom//byte-compile-core (&optional recompile-p)
"Byte compile the core Doom files.
@@ -683,7 +680,11 @@ likely change core files directly).
If RECOMPILE-P is non-nil, only recompile out-of-date core files."
(interactive "P")
- (doom//byte-compile (list "core") recompile-p))
+ (if (not noninteractive)
+ ;; This is done in another instance to protect the current session's
+ ;; state. `doom-initialize-packages' will have side effects otherwise.
+ (doom-packages--async-run 'doom//byte-compile-core)
+ (doom//byte-compile (list "core") recompile-p)))
(defun doom//byte-recompile-plugins ()
"Recompile all installed plugins. If you're getting odd errors after upgrading
@@ -692,18 +693,18 @@ If RECOMPILE-P is non-nil, only recompile out-of-date core files."
(byte-recompile-directory package-user-dir 0 t))
(defun doom//clean-byte-compiled-files ()
- "Delete all the compiled elc files in your Emacs configuration.
-
-This excludes compiled packages in `doom-packages-dir'.'"
+ "Delete all the compiled elc files in your Emacs configuration. This excludes
+compiled packages.'"
(interactive)
(let ((targets (append (list (expand-file-name "init.elc" doom-emacs-dir))
(directory-files-recursively doom-core-dir "\\.elc$")
- (directory-files-recursively doom-modules-dir "\\.elc$"))))
+ (directory-files-recursively doom-modules-dir "\\.elc$")))
+ (default-directory doom-emacs-dir))
(unless (cl-loop for path in targets
if (file-exists-p path)
collect path
and do (delete-file path)
- and do (message "Deleted %s" (file-relative-name path)))
+ and do (message "✓ Deleted %s" (file-relative-name path)))
(message "Everything is clean"))))
diff --git a/core/core-popups.el b/core/core-popups.el
index 210e27fea..5ca2fd044 100644
--- a/core/core-popups.el
+++ b/core/core-popups.el
@@ -87,13 +87,13 @@ recognized by DOOM's popup system. They are:
;;
;;
-(defvar doom-popup-parameters
- '(:esc :modeline :transient :fit :align :size)
- "TODO")
+;; (defvar doom-popup-parameters
+;; '(:esc :modeline :transient :fit :align :size)
+;; "TODO")
-(defvar doom-popup-whitelist
- '(("^ ?\\*" :size 15 :noselect t :autokill t :autoclose t))
- "TODO")
+;; (defvar doom-popup-whitelist
+;; '(("^ ?\\*" :size 15 :noselect t :autokill t :autoclose t))
+;; "TODO")
(defvar doom-popup-blacklist
'("^\\*magit")
@@ -122,7 +122,7 @@ recognized by DOOM's popup system. They are:
("*Backtrace*" :size 20 :noselect t)
("*Warnings*" :size 12 :noselect t :autofit t)
("*Messages*" :size 12 :noselect t)
- ("*Help*" :size 0.3)
+ ("*Help*" :size 0.3 :autokill t)
("^\\*.*Shell Command.*\\*$" :regexp t :size 20 :noselect t :autokill t)
(apropos-mode :size 0.3 :autokill t :autoclose t)
(Buffer-menu-mode :size 20 :autokill t)
@@ -144,10 +144,20 @@ recognized by DOOM's popup system. They are:
(defun doom-display-buffer-action (buffer alist)
(shackle-display-buffer buffer alist (shackle-match buffer)))
+ (defun doom|autokill-popups ()
+ (or (not (doom-popup-p))
+ (prog1 (when (and (not doom-popup-inhibit-autokill)
+ (plist-get doom-popup-rules :autokill))
+ (doom-popup-mode -1)
+ (when-let* ((process (get-buffer-process (current-buffer))))
+ (set-process-query-on-exit-flag process nil))
+ t))))
+
(add-hook! doom-post-init
(setq display-buffer-alist
(cons '(doom-display-buffer-condition doom-display-buffer-action)
- display-buffer-alist)))
+ display-buffer-alist))
+ (add-hook 'kill-buffer-query-functions #'doom|autokill-popups))
;; no modeline in popups
(add-hook 'doom-popup-mode-hook #'doom|hide-modeline-in-popup)
@@ -170,7 +180,7 @@ recognized by DOOM's popup system. They are:
(define-key map [escape] #'doom/popup-close-maybe)
(define-key map (kbd "ESC") #'doom/popup-close-maybe)
(define-key map [remap quit-window] #'doom/popup-close-maybe)
- (define-key map [remap doom/kill-this-buffer] #'delete-window)
+ (define-key map [remap doom/kill-this-buffer] #'doom/popup-close-maybe)
(define-key map [remap split-window-right] #'ignore)
(define-key map [remap split-window-below] #'ignore)
(define-key map [remap split-window-horizontally] #'ignore)
diff --git a/core/core-projects.el b/core/core-projects.el
index 01e8e88f4..24db2ee04 100644
--- a/core/core-projects.el
+++ b/core/core-projects.el
@@ -1,10 +1,7 @@
;;; core-projects.el -*- lexical-binding: t; -*-
-(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.")
-
(def-package! projectile
+ :hook (doom-init . projectile-mode)
:init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
projectile-enable-caching (not noninteractive)
@@ -14,17 +11,23 @@ state are passed in.")
projectile-globally-ignored-files '(".DS_Store" "Icon
" "TAGS")
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o"))
- (add-hook 'doom-init-hook #'projectile-mode)
:config
+ (add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
+ (add-hook 'find-file-hook #'doom|autoload-project-mode)
+
;; a more generic project root file
(push ".project" projectile-project-root-files-bottom-up)
- (nconc projectile-globally-ignored-directories (list (abbreviate-file-name doom-local-dir) ".sync"))
- (nconc projectile-other-file-alist '(("css" . ("scss" "sass" "less" "style"))
- ("scss" . ("css"))
- ("sass" . ("css"))
- ("less" . ("css"))
- ("styl" . ("css"))))
+ (setq projectile-globally-ignored-directories
+ (append projectile-globally-ignored-directories
+ (list (abbreviate-file-name doom-local-dir) ".sync"))
+ projectile-other-file-alist
+ (append projectile-other-file-alist
+ '(("css" . ("scss" "sass" "less" "styl"))
+ ("scss" . ("css"))
+ ("sass" . ("css"))
+ ("less" . ("css"))
+ ("styl" . ("css")))))
;; Projectile root-searching functions can cause an infinite loop on TRAMP
;; connections, so disable them.
@@ -76,21 +79,48 @@ which case they're relative to `default-directory'). If they start with a slash,
they are absolute."
(doom--resolve-path-forms files (doom-project-root)))
+(defun doom-project-find-file (dir)
+ "Fuzzy-find a file under DIR."
+ (let ((default-directory dir)
+ ;; Necessary to isolate this search from the current project
+ projectile-project-name
+ projectile-require-project-root
+ projectile-cached-buffer-file-name
+ projectile-cached-project-root)
+ (call-interactively
+ ;; completion modules may remap this command
+ (or (command-remapping #'projectile-find-file)
+ #'projectile-find-file))))
+
+(defun doom-project-browse (dir)
+ "Traverse a file structure starting linearly from DIR."
+ (let ((default-directory dir))
+ (call-interactively
+ ;; completion modules may remap this command
+ (or (command-remapping #'find-file)
+ #'find-file))))
+
;;
;; Projects
;;
(defvar-local doom-project nil
- "A list of project mode to enable. Used for .dir-locals.el.")
+ "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|autoload-project-mode ()
- "Auto-enable projects listed in `doom-project', which is meant to be set from
-.dir-locals.el files."
- (cl-loop for mode in doom-project
- unless (symbol-value mode)
- do (funcall mode)))
-(add-hook 'after-change-major-mode-hook #'doom|autoload-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)))))
(defmacro def-project-mode! (name &rest plist)
"Define a project minor-mode named NAME (a symbol) and declare where and how
@@ -101,8 +131,7 @@ own settings, keymaps, hooks, snippets, etc.
This creates NAME-hook and NAME-map as well.
-A project can be enabled through .dir-locals.el too, if `doom-project' is set to
-the name (symbol) of the project mode(s) to enable.
+A project can be enabled through .dir-locals.el too, by setting `doom-project'.
PLIST may contain any of these properties, which are all checked to see if NAME
should be activated. If they are *all* true, NAME is activated.
@@ -151,7 +180,7 @@ Relevant: `doom-project-hook'."
:keymap (make-sparse-keymap)
(if (not ,name)
,exit-form
- (run-hook-with-args 'doom-project-hook ',name)
+ (run-hook-with-args 'doom-project-hook ',name ,name)
,(when load-form
`(unless ,init-var
,load-form
diff --git a/core/core-ui.el b/core/core-ui.el
index a2f3f011a..ecf053cae 100644
--- a/core/core-ui.el
+++ b/core/core-ui.el
@@ -50,6 +50,7 @@ shorter major mode name in the mode-line. See `doom|set-mode-name'.")
max-mini-window-height 0.3
mode-line-default-help-echo nil ; disable mode-line mouseovers
mouse-yank-at-point t ; middle-click paste at point, not at click
+ ibuffer-use-other-window t
resize-mini-windows 'grow-only ; Minibuffer resizing
show-help-function nil ; hide :help-echo text
split-width-threshold 160 ; favor horizontal splits
@@ -182,9 +183,13 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(when (fontp doom-variable-pitch-font)
(set-face-attribute 'variable-pitch frame :font doom-variable-pitch-font)))
('error
- (lwarn 'doom-ui :error
- "Failed to set fonts because %s"
- (error-message-string ex))))
+ (if (string-prefix-p "Font not available: " (error-message-string ex))
+ (lwarn 'doom-ui :warning
+ "Could not find the '%s' font on your system, falling back to system font"
+ (font-get (caddr ex) :family))
+ (lwarn 'doom-ui :error
+ "Unexpected error while initializing fonts: %s"
+ (error-message-string ex)))))
(run-hooks 'doom-init-ui-hook))
(defun doom|reload-ui-in-daemon (frame)
@@ -224,6 +229,14 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(add-hook! '(doom-post-init-hook minibuffer-setup-hook)
#'doom|no-fringes-in-minibuffer)
+(defun doom|protect-visible-buffers ()
+ "Don't kill the current buffer if it is visible in another window (bury it
+instead)."
+ (not (delq (selected-window)
+ (get-buffer-window-list nil nil t))))
+(add-hook! doom-post-init
+ (add-hook 'kill-buffer-query-functions #'doom|protect-visible-buffers))
+
;;
;; Plugins
@@ -237,14 +250,11 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(defun doom*disable-all-the-icons-in-tty (orig-fn &rest args)
(when (display-graphic-p)
(apply orig-fn args)))
-
;; all-the-icons doesn't work in the terminal, so we "disable" it.
- (advice-add #'all-the-icons-octicon :around #'doom*disable-all-the-icons-in-tty)
- (advice-add #'all-the-icons-material :around #'doom*disable-all-the-icons-in-tty)
- (advice-add #'all-the-icons-faicon :around #'doom*disable-all-the-icons-in-tty)
- (advice-add #'all-the-icons-fileicon :around #'doom*disable-all-the-icons-in-tty)
- (advice-add #'all-the-icons-wicon :around #'doom*disable-all-the-icons-in-tty)
- (advice-add #'all-the-icons-alltheicon :around #'doom*disable-all-the-icons-in-tty))
+ (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)))
(def-package! fringe-helper
:commands (fringe-helper-define fringe-helper-convert)
@@ -255,8 +265,7 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(def-package! hideshow ; built-in
:commands (hs-minor-mode hs-toggle-hiding hs-already-hidden-p)
- :config
- (setq hs-hide-comments-when-hiding-all nil))
+ :config (setq hs-hide-comments-when-hiding-all nil))
(def-package! highlight-indentation
:commands (highlight-indentation-mode highlight-indentation-current-column-mode))
@@ -306,17 +315,20 @@ local value, whether or not it's permanent-local. Therefore, we cycle
;; Helps us distinguish stacked delimiter pairs. Especially in parentheses-drunk
;; languages like Lisp.
(def-package! rainbow-delimiters
- :commands rainbow-delimiters-mode
- :config (setq rainbow-delimiters-max-face-count 3)
- :init (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode))
+ :hook (lisp-mode . rainbow-delimiters-mode)
+ :config (setq rainbow-delimiters-max-face-count 3))
;; For a distractions-free-like UI, that dynamically resizes margets and can
;; center a buffer.
(def-package! visual-fill-column
:commands visual-fill-column-mode
:config
- (setq-default visual-fill-column-center-text nil
- visual-fill-column-width fill-column))
+ (setq-default
+ visual-fill-column-center-text t
+ visual-fill-column-width
+ ;; take Emacs 26 line numbers into account
+ (+ (if (boundp 'display-line-numbers) 6 0)
+ fill-column)))
;;
diff --git a/core/core.el b/core/core.el
index f3eaa03bd..fbcc2348d 100644
--- a/core/core.el
+++ b/core/core.el
@@ -18,14 +18,14 @@
;; Autoloaded functions are in core/autoload/*.el and modules/*/*/autoload.el or
;; modules/*/*/autoload/*.el.
-(defvar doom-version "2.0.8"
+(defvar doom-version "2.0.9"
"Current version of DOOM emacs.")
(defvar doom-debug-mode (or (getenv "DEBUG") init-file-debug)
"If non-nil, all doom functions will be verbose. Set DEBUG=1 in the command
line or use --debug-init to enable this.")
-(defvar doom-emacs-dir (expand-file-name user-emacs-directory)
+(defvar doom-emacs-dir (file-truename user-emacs-directory)
"The path to this emacs.d directory.")
(defvar doom-core-dir (concat doom-emacs-dir "core/")
@@ -34,38 +34,27 @@ line or use --debug-init to enable this.")
(defvar doom-modules-dir (concat doom-emacs-dir "modules/")
"Where configuration modules are stored.")
-
-;; Multi-host directories: I namespace `doom-etc-dir' and `doom-cache-dir' with
-;; host names because I use the same (often symlinked) emacs.d across several
-;; computers -- often simultaneously. Cache or other temporary files would
-;; conflict otherwise.
-
(defvar doom-local-dir (concat doom-emacs-dir ".local/")
"Root directory for local Emacs files. Use this as permanent storage for files
that are safe to share across systems (if this config is symlinked across
several computers).")
-(defvar doom-host-dir (concat doom-local-dir "@" (system-name))
- "Directory for hostname-specific file storage. Used by `doom-etc-dir' and
-`doom-cache-dir'.")
+(defvar doom-etc-dir (concat doom-local-dir "etc/")
+ "Directory for non-volatile storage.
-(defvar doom-etc-dir (concat doom-host-dir "/etc/")
- "Host-namespaced directory for non-volatile storage. These are not deleted or
-tampored with by DOOM functions. Use this for dependencies like servers or
-config files that are stable (i.e. it should be unlikely that you need to delete
-them if something goes wrong).")
+Use this for files that don't change much, like servers binaries, external
+dependencies or long-term shared data.")
-(defvar doom-cache-dir (concat doom-host-dir "/cache/")
- "Host-namespaced directory for volatile storage. Deleted when `doom/reset' is
-called. Use this for transient files that are generated on the fly like caches
-and temporary files. Anything that may need to be cleared if there are
-problems.")
+(defvar doom-cache-dir (concat doom-local-dir "cache/")
+ "Directory for volatile storage.
+
+Use this for files that change often, like cache files.")
(defvar doom-packages-dir (concat doom-local-dir "packages/")
"Where package.el and quelpa plugins (and their caches) are stored.")
(defvar doom-autoload-file (concat doom-local-dir "autoloads.el")
- "Location of the autoloads file generated by `doom/reload-autoloads'.")
+ "Where `doom//reload-autoloads' will generate its autoloads file.")
(defgroup doom nil
"DOOM Emacs, an Emacs configuration for a stubborn, shell-dwelling and
@@ -121,13 +110,14 @@ melodramatic ex-vimmer disappointed with the text-editor status quo."
(load custom-file t t)
;; be quiet at startup; don't load or display anything unnecessary
-(advice-add #'display-startup-echo-area-message :override #'ignore)
-(setq inhibit-startup-message t
- inhibit-startup-echo-area-message user-login-name
- inhibit-default-init t
- initial-major-mode 'fundamental-mode
- initial-scratch-message nil
- mode-line-format nil)
+(unless noninteractive
+ (advice-add #'display-startup-echo-area-message :override #'ignore)
+ (setq inhibit-startup-message t
+ inhibit-startup-echo-area-message user-login-name
+ inhibit-default-init t
+ initial-major-mode 'fundamental-mode
+ initial-scratch-message nil
+ mode-line-format nil))
;; Custom init hooks; clearer than `after-init-hook', `emacs-startup-hook', and
;; `window-setup-hook'.
@@ -152,33 +142,23 @@ ability to invoke the debugger in debug mode."
(car ex) fn (error-message-string ex))))
nil)
-(defun doom|finalize ()
- (unless (or doom-init-p noninteractive)
- (dolist (hook '(doom-init-hook doom-post-init-hook))
- (run-hook-wrapped hook #'doom-try-run-hook hook))
- (setq doom-init-p t))
-
- ;; Don't keep gc-cons-threshold too high. It helps to stave off the GC while
- ;; Emacs starts up, but afterwards it causes stuttering and random freezes. So
- ;; reset it to a reasonable default.
- (setq gc-cons-threshold 16777216
- gc-cons-percentage 0.1
- file-name-handler-alist doom--file-name-handler-alist)
- t)
-
;;;
;; Initialize
(eval-and-compile
(defvar doom--file-name-handler-alist file-name-handler-alist)
- (setq gc-cons-threshold 402653184
- gc-cons-percentage 0.6
- file-name-handler-alist nil)
+ (unless (or after-init-time noninteractive)
+ ;; One of the contributors to long startup times is the garbage collector,
+ ;; so we up its memory threshold, temporarily. It is reset later in
+ ;; `doom|finalize'.
+ (setq gc-cons-threshold 402653184
+ gc-cons-percentage 0.6
+ file-name-handler-alist nil))
- (require 'core-packages (concat doom-core-dir "core-packages"))
- (eval-when-compile
- (doom-initialize))
- (setq load-path (eval-when-compile load-path)
+ (require 'cl-lib)
+ (load (concat doom-core-dir "core-packages") nil t)
+ (setq load-path (eval-when-compile (doom-initialize t)
+ (doom-initialize-load-path t))
doom--package-load-path (eval-when-compile doom--package-load-path))
(load! core-lib)
@@ -195,10 +175,71 @@ ability to invoke the debugger in debug mode."
(load! core-popups) ; taming sudden yet inevitable windows
(load! core-editor) ; baseline configuration for text editing
(load! core-projects) ; making Emacs project-aware
- (load! core-keybinds))) ; centralized keybind system + which-key
+ (load! core-keybinds)) ; centralized keybind system + which-key
-(add-hook! '(emacs-startup-hook doom-reload-hook)
- #'doom|finalize)
+ (defun doom|finalize ()
+ "Run `doom-init-hook', `doom-post-init-hook' and reset `gc-cons-threshold',
+`gc-cons-percentage' and `file-name-handler-alist'."
+ (unless (or (not after-init-time) noninteractive)
+ (dolist (hook '(doom-init-hook doom-post-init-hook))
+ (run-hook-wrapped hook #'doom-try-run-hook hook)))
+
+ ;; If you forget to reset this, you'll get stuttering and random freezes!
+ (setq gc-cons-threshold 16777216
+ gc-cons-percentage 0.1
+ file-name-handler-alist doom--file-name-handler-alist)
+ t)
+
+ (add-hook! '(emacs-startup-hook doom-reload-hook)
+ #'doom|finalize))
+
+
+;;
+;; Emacs fixes/hacks
+;;
+
+;; Automatic minor modes
+(defvar doom-auto-minor-mode-alist '()
+ "Alist mapping filename patterns to corresponding minor mode functions, like
+`auto-mode-alist'. All elements of this alist are checked, meaning you can
+enable multiple minor modes for the same regexp.")
+
+(defun doom|enable-minor-mode-maybe ()
+ "Check file name against `doom-auto-minor-mode-alist'."
+ (when buffer-file-name
+ (let ((name buffer-file-name)
+ (remote-id (file-remote-p buffer-file-name))
+ (alist doom-auto-minor-mode-alist))
+ ;; Remove backup-suffixes from file name.
+ (setq name (file-name-sans-versions name))
+ ;; Remove remote file name identification.
+ (when (and (stringp remote-id)
+ (string-match-p (regexp-quote remote-id) name))
+ (setq name (substring name (match-end 0))))
+ (while (and alist (caar alist) (cdar alist))
+ (if (string-match-p (caar alist) name)
+ (funcall (cdar alist) 1))
+ (setq alist (cdr alist))))))
+(add-hook 'find-file-hook #'doom|enable-minor-mode-maybe)
+
+(defun doom*set-indirect-buffer-filename (orig-fn base-buffer name &optional clone)
+ "In indirect buffers, `buffer-file-name' is nil, which can cause problems
+with functions that require it (like modeline segments)."
+ (let ((file-name (buffer-file-name base-buffer))
+ (buffer (funcall orig-fn base-buffer name clone)))
+ (when (and file-name buffer)
+ (with-current-buffer buffer
+ (unless buffer-file-name
+ (setq buffer-file-name file-name
+ buffer-file-truename (file-truename file-name)))))
+ buffer))
+(advice-add #'make-indirect-buffer :around #'doom*set-indirect-buffer-filename)
+
+(defun doom*no-authinfo-for-tramp (orig-fn &rest args)
+ "Don't look into .authinfo for local sudo TRAMP buffers."
+ (let ((auth-sources (if (equal tramp-current-method "sudo") nil auth-sources)))
+ (apply orig-fn args)))
+(advice-add #'tramp-read-passwd :around #'doom*no-authinfo-for-tramp)
(provide 'core)
;;; core.el ends here
diff --git a/core/test/autoload-buffers.el b/core/test/autoload-buffers.el
index abf5c4245..b39c75b3c 100644
--- a/core/test/autoload-buffers.el
+++ b/core/test/autoload-buffers.el
@@ -1,24 +1,23 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/autoload-buffers.el
-(defmacro -with-temp-buffers! (buffer-args &rest body)
+(defmacro with-temp-buffers!! (buffer-args &rest body)
(declare (indent defun))
(let (buffers)
(dolist (bsym buffer-args)
(push `(,bsym (get-buffer-create ,(symbol-name bsym)))
buffers))
- `(save-window-excursion
- (cl-flet ((buffer-list
- (lambda ()
- (cl-remove-if-not #'buffer-live-p (list ,@(reverse (mapcar #'car buffers)))))))
- (let* (persp-mode
- ,@buffers)
- ,@body
- (mapc #'kill-buffer (buffer-list)))))))
+ `(cl-flet ((buffer-list
+ (lambda ()
+ (cl-remove-if-not #'buffer-live-p (list ,@(reverse (mapcar #'car buffers)))))))
+ (let* (persp-mode
+ ,@buffers)
+ ,@body
+ (mapc #'kill-buffer (buffer-list))))))
;;
(def-test! get-buffers
- (-with-temp-buffers! (a b c)
+ (with-temp-buffers!! (a b c)
(should (cl-every #'buffer-live-p (buffer-list)))
(should (equal (buffer-list) (list a b c)))
(dolist (buf (list (cons a doom-emacs-dir)
@@ -26,6 +25,7 @@
(cons c "/tmp/")))
(with-current-buffer (car buf)
(setq-local default-directory (cdr buf))))
+ (projectile-mode +1)
(with-current-buffer a
;; should produce all buffers
(let ((buffers (doom-buffer-list)))
@@ -37,11 +37,12 @@
;; If no project is available, just get all buffers
(with-current-buffer c
(let ((buffers (doom-project-buffer-list)))
- (should (cl-every (lambda (x) (memq x buffers)) (list a b c)))))))
+ (should (cl-every (lambda (x) (memq x buffers)) (list a b c)))))
+ (projectile-mode -1)))
(def-test! real-buffers
(let (doom-real-buffer-functions)
- (-with-temp-buffers! (a b c d)
+ (with-temp-buffers!! (a b c d)
(dolist (buf (list a b))
(with-current-buffer buf
(setq-local buffer-file-name "x")))
@@ -62,7 +63,7 @@
;; `doom-visible-buffers'
;; `doom-buried-buffers'
(def-test! visible-buffers-and-windows
- (-with-temp-buffers! (a b c d)
+ (with-temp-buffers!! (a b c d)
(switch-to-buffer a)
(should (eq (current-buffer) a))
(should (eq (selected-window) (get-buffer-window a)))
@@ -77,7 +78,7 @@
;; `doom-matching-buffers'
(def-test! matching-buffers
- (-with-temp-buffers! (a b c)
+ (with-temp-buffers!! (a b c)
(let ((buffers (doom-matching-buffers "^[ac]$")))
(should (= 2 (length buffers)))
(should (cl-every #'bufferp buffers))
@@ -86,7 +87,7 @@
;; `doom-buffers-in-mode'
(def-test! buffers-in-mode
- (-with-temp-buffers! (a b c d e)
+ (with-temp-buffers!! (a b c d e)
(dolist (buf (list a b))
(with-current-buffer buf
(emacs-lisp-mode)))
@@ -101,7 +102,7 @@
;; `doom-kill-buffer'
(def-test! kill-buffer
- (-with-temp-buffers! (a b)
+ (with-temp-buffers!! (a b)
(doom-kill-buffer a)
(should-not (buffer-live-p a))
;; modified buffer
@@ -112,7 +113,7 @@
;; `doom--cycle-real-buffers'
(def-test! kill-buffer-then-show-real-buffer
- (-with-temp-buffers! (a b c d)
+ (with-temp-buffers!! (a b c d)
(dolist (buf (list a b d))
(with-current-buffer buf
(setq-local buffer-file-name "x")))
@@ -131,4 +132,4 @@
;; TODO doom/kill-all-buffers
;; TODO doom/kill-other-buffers
;; TODO doom/kill-matching-buffers
-;; TODO doom/cleanup-buffers
+;; TODO doom/cleanup-session
diff --git a/core/test/autoload-debug.el b/core/test/autoload-debug.el
index 32f1090a7..062a16de5 100644
--- a/core/test/autoload-debug.el
+++ b/core/test/autoload-debug.el
@@ -2,18 +2,16 @@
;;; core/test/autoload-debug.el
(def-test! what-face
- (with-temp-buffer
- (insert (propertize "Hello " 'face 'font-lock-keyword-face))
- (insert "world")
+ (insert (propertize "Hello " 'face 'font-lock-keyword-face))
+ (insert "world")
- (should (equal (doom/what-face (point-min)) '((font-lock-keyword-face) ())))
- (should-not (doom/what-face (point-max)))))
+ (should (equal (doom/what-face (point-min)) '((font-lock-keyword-face) ())))
+ (should-not (doom/what-face (point-max))))
(def-test! what-face-overlays
- (with-temp-buffer
- (insert "Hello world")
- (let ((ov (make-overlay 1 6)))
- (overlay-put ov 'face 'font-lock-keyword-face))
+ (insert "Hello world")
+ (let ((ov (make-overlay 1 6)))
+ (overlay-put ov 'face 'font-lock-keyword-face))
- (should (equal (doom/what-face (point-min)) '(() (font-lock-keyword-face))))
- (should-not (doom/what-face (point-max)))))
+ (should (equal (doom/what-face (point-min)) '(() (font-lock-keyword-face))))
+ (should-not (doom/what-face (point-max))))
diff --git a/core/test/autoload-package.el b/core/test/autoload-package.el
index 23db6873e..5d074b0b7 100644
--- a/core/test/autoload-package.el
+++ b/core/test/autoload-package.el
@@ -1,30 +1,21 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/autoload-package.el
-(defun -new-package (name version &optional reqs)
+(defun -pkg (name version &optional reqs)
(package-desc-create :name name :version version :reqs reqs))
-(defmacro -with-temp-packages! (&rest forms)
- "Run FORMS in the context of a temporary package setup (as in, it won't
-affects your Emacs packages)."
- `(let* ((doom-local-dir ,(expand-file-name "test/.local/" doom-emacs-dir))
- (doom-packages-dir (concat doom-local-dir "packages/"))
- (doom-etc-dir (concat doom-local-dir "etc/"))
- (doom-cache-dir (concat doom-local-dir "cache/"))
- (package-user-dir (expand-file-name "elpa" doom-packages-dir))
- package-alist
- package-archive-contents
- package-initialize)
- (package-initialize)
- ,@forms))
-
-(defmacro -with-packages! (packages package-descs &rest body)
- `(let ((doom-packages ,packages)
+(defmacro with-packages!! (packages package-descs &rest body)
+`(let* ((doom-packages-dir ,(expand-file-name "packages/" (file-name-directory load-file-name)))
+ (package-user-dir ,(expand-file-name "elpa" doom-packages-dir))
+ (quelpa-dir ,(expand-file-name "quelpa" doom-packages-dir)))
+ ;; (make-directory doom-packages-dir t)
+ (let ((doom-packages ,packages)
(package-alist ,package-descs)
doom-core-packages)
- (cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _)))
- ((symbol-function 'package-installed-p) (lambda (name &rest _) (assq name package-alist))))
- ,@body)))
+ (cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _))))
+ ,@body))
+ ;; (delete-directory doom-packages-dir t)
+ ))
;;
@@ -32,18 +23,19 @@ affects your Emacs packages)."
;;
(def-test! backend-detection
- (let ((package-alist `((doom-dummy ,(-new-package 'doom-dummy '(20160405 1234)))))
+ (let ((package-alist `((doom-dummy ,(-pkg 'doom-dummy '(20160405 1234)))))
(quelpa-cache '((doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist")))
(quelpa-initialized-p t))
(should (eq (doom-package-backend 'doom-dummy) 'elpa))
- (should (eq (doom-package-backend 'doom-quelpa-dummy) 'quelpa))))
+ (should (eq (doom-package-backend 'doom-quelpa-dummy) 'quelpa))
+ (should (eq (doom-package-backend 'org) 'emacs))))
(def-test! elpa-outdated-detection
(let* ((doom--last-refresh (current-time))
(package-alist
- `((doom-dummy ,(-new-package 'doom-dummy '(20160405 1234)))))
+ `((doom-dummy ,(-pkg 'doom-dummy '(20160405 1234)))))
(package-archive-contents
- `((doom-dummy ,(-new-package 'doom-dummy '(20170405 1234))))))
+ `((doom-dummy ,(-pkg 'doom-dummy '(20170405 1234))))))
(cl-letf (((symbol-function 'package-refresh-contents) (lambda (&rest _))))
(should (equal (doom-package-outdated-p 'doom-dummy)
'(doom-dummy (20160405 1234) (20170405 1234)))))))
@@ -52,7 +44,7 @@ affects your Emacs packages)."
(def-test! get-packages
(let ((quelpa-initialized-p t))
- (-with-packages!
+ (with-packages!!
'((doom-dummy))
'((doom-dummy nil)
(doom-dummy-unwanted nil)
@@ -62,17 +54,17 @@ affects your Emacs packages)."
(def-test! orphaned-packages
"Test `doom-get-orphaned-packages', which gets a list of packages that are
no longer enabled or depended on."
- (-with-packages!
+ (with-packages!!
'((doom-dummy))
- `((doom-dummy ,(-new-package 'doom-dummy '(20160405 1234) '((doom-dummy-dep (1 0)))))
- (doom-dummy-unwanted ,(-new-package 'doom-dummy-unwanted '(20160601 1234)))
- (doom-dummy-dep ,(-new-package 'doom-dummy-dep '(20160301 1234))))
+ `((doom-dummy ,(-pkg 'doom-dummy '(20160405 1234) '((doom-dummy-dep (1 0)))))
+ (doom-dummy-unwanted ,(-pkg 'doom-dummy-unwanted '(20160601 1234)))
+ (doom-dummy-dep ,(-pkg 'doom-dummy-dep '(20160301 1234))))
(should (equal (doom-get-orphaned-packages) '(doom-dummy-unwanted)))))
(def-test! missing-packages
"Test `doom-get-missing-packages, which gets a list of enabled packages that
aren't installed."
- (-with-packages!
+ (with-packages!!
'((doom-dummy) (doom-dummy-installed))
- `((doom-dummy-installed ,(-new-package 'doom-dummy-installed '(20160405 1234))))
+ `((doom-dummy-installed ,(-pkg 'doom-dummy-installed '(20160405 1234))))
(should (equal (doom-get-missing-packages) '((doom-dummy))))))
diff --git a/core/test/core-lib.el b/core/test/core-lib.el
index fba4c22e5..30e59a690 100644
--- a/core/test/core-lib.el
+++ b/core/test/core-lib.el
@@ -147,10 +147,13 @@
;; --- Settings ---------------------------
-(def-setting! :-test-setting (x) x)
-
(def-test! set
- (should (assq :-test-setting doom-settings))
- (should (set! :-test-setting t))
- (let ((inhibit-message t))
- (should-not (set! :non-existant-setting (error "This shouldn't trigger")))))
+ (eval-and-compile
+ (let (doom-settings)
+ (def-setting! :-test-setting (x) `(setq result ,x))
+ (should (assq :-test-setting doom-settings))
+ (let ((inhibit-message t)
+ result)
+ (set! :-test-setting t)
+ (should result)
+ (set! :non-existant-setting (error "This shouldn't trigger"))))))
diff --git a/core/test/core-projects.el b/core/test/core-projects.el
new file mode 100644
index 000000000..3ebf2bc9b
--- /dev/null
+++ b/core/test/core-projects.el
@@ -0,0 +1,43 @@
+;; -*- no-byte-compile: t; -*-
+;;; ../core/test/core-projects.el
+
+(require 'projectile)
+
+;;
+;; `doom-project-p'
+(def-test! project-p
+ :minor-mode projectile-mode
+ (let ((default-directory doom-emacs-dir))
+ (should (doom-project-p)))
+ (let ((default-directory (expand-file-name "~")))
+ (should-not (doom-project-p))))
+
+;; `doom-project-p'
+(def-test! project-root
+ :minor-mode projectile-mode
+ ;; Should resolve to project root
+ (let ((default-directory doom-core-dir))
+ (should (equal (doom-project-root) doom-emacs-dir)))
+ ;; Should resolve to `default-directory' if not a project
+ (let ((default-directory (expand-file-name "~")))
+ (should (equal (doom-project-root) default-directory))))
+
+;; `doom-project-expand'
+(def-test! project-expand
+ :minor-mode projectile-mode
+ (let ((default-directory doom-core-dir))
+ (should (equal (doom-project-expand "init.el")
+ (expand-file-name "init.el" (doom-project-root))))))
+
+;; `doom-project-has!'
+(def-test! project-has!
+ :minor-mode projectile-mode
+ (let ((default-directory doom-core-dir))
+ ;; Resolve from project root
+ (should (doom-project-has! "init.el"))
+ ;; Chained file checks
+ (should (doom-project-has! (and "init.el" "LICENSE")))
+ (should (doom-project-has! (or "init.el" "does-not-exist")))
+ (should (doom-project-has! (and "init.el" (or "LICENSE" "does-not-exist"))))
+ ;; Should resolve relative paths from `default-directory'
+ (should (doom-project-has! (and "./core.el" "../init.el")))))
diff --git a/core/test/core-ui.el b/core/test/core-ui.el
new file mode 100644
index 000000000..c1c82a01d
--- /dev/null
+++ b/core/test/core-ui.el
@@ -0,0 +1,45 @@
+;; -*- no-byte-compile: t; -*-
+;;; ../core/test/core-ui.el
+
+(defmacro with-temp-windows!! (&rest body)
+ (declare (indent defun))
+ `(progn
+ (delete-other-windows)
+ (cl-flet ((split-window (symbol-function #'split-window-horizontally)))
+ (let ((a (get-buffer-create "a"))
+ (b (get-buffer-create "b"))
+ (split-width-threshold 0)
+ (window-min-width 0))
+ ,@body))))
+
+;;
+(def-test! set-mode-name
+ (let ((doom-major-mode-names '((text-mode . "abc")
+ (lisp-mode . (lambda () "xyz"))
+ (js-mode . t))))
+ (text-mode)
+ (should (equal mode-name "abc"))
+ (lisp-mode)
+ (should (equal mode-name "xyz"))
+ (should-error (js-mode))))
+
+(def-test! protect-visible-buffers
+ (with-temp-windows!!
+ (let ((kill-buffer-query-functions '(doom|protect-visible-buffers)))
+ (switch-to-buffer a) (split-window)
+ (switch-to-buffer b) (split-window)
+ (switch-to-buffer a)
+ (should-not (kill-buffer))
+ (select-window (get-buffer-window b))
+ (should (kill-buffer)))))
+
+(def-test! *quit-window
+ (with-temp-windows!!
+ (let (kill-buffer-query-functions)
+ (switch-to-buffer a) (split-window)
+ (switch-to-buffer b)
+ (save-window-excursion
+ (quit-window t)
+ (should (buffer-live-p b)))
+ (quit-window)
+ (should-not (buffer-live-p b)))))
diff --git a/init.example.el b/init.example.el
index 752f734b6..3a7a691a7 100644
--- a/init.example.el
+++ b/init.example.el
@@ -130,7 +130,10 @@
;twitter ; twitter client https://twitter.com/vnought
;write ; emacs as a word processor (latex + org + markdown)
- ;; This is the private module of Doom's maintainer; use it as a reference
+ ;; Private modules are where you place your personal configuration files.
+ ;; By default, they are not tracked. There is one module included here,
+ ;; the defaults module. It contains a Spacemacs-inspired keybinding
+ ;; scheme and additional ex commands for evil-mode. Use it as a reference
;; for your own.
- :private hlissner)
+ :private default)
diff --git a/init.test.el b/init.test.el
index 038114c87..8d529cd2f 100644
--- a/init.test.el
+++ b/init.test.el
@@ -9,6 +9,9 @@
:completion
company
+ :ui
+ doom-dashboard
+
:tools
password-store
diff --git a/modules/app/rss/config.el b/modules/app/rss/config.el
index 343e74bd2..6cdce9a3c 100644
--- a/modules/app/rss/config.el
+++ b/modules/app/rss/config.el
@@ -56,7 +56,7 @@
(def-package! elfeed-org
- :after elfeed
+ :after (:all org elfeed)
:config
(setq rmh-elfeed-org-files
(let ((default-directory +org-dir))
diff --git a/modules/completion/company/README.org b/modules/completion/company/README.org
index 76e9ad4ac..f2a1bc6fc 100644
--- a/modules/completion/company/README.org
+++ b/modules/completion/company/README.org
@@ -14,20 +14,23 @@ This module adds code-completion support, powered by [[https://github.com/compan
- [[#troubleshooting][Troubleshooting]]
* Install
-Certain languages may require additional setup, and some languages may have no completion support at all.
+Some languages require additional setup, and some languages may have no
+completion support at all.
Check the README.org in that language's module for details.
* Configure
** Auto-completion
-By default, I've disabled auto-completion. This is my preference. I prefer to invoke company when I need it by calling ~company-complete~ manually (typically, bound to =C-SPC= in insert mode). However, some may not share my preference.
+By default, I've disabled auto-completion. This is my preference. I prefer to
+invoke company when I need it by calling ~company-complete~ manually (typically,
+bound to =C-SPC= in insert mode). However, some may not share my preference.
To enable auto-completion you must:
1. Load ~company~,
2. and change ~company-idle-delay~ to a non-nil float (the default is 0.5)
-For example, add the following to your ~modules/private//config.el~ module:
+For example:
#+BEGIN_SRC emacs-lisp
(require 'company)
@@ -36,8 +39,10 @@ For example, add the following to your ~modules/private//config.el~ mo
#+END_SRC
* Troubleshooting
-If completion isn't working for you, please consider the following before posting a bug report:
+If completion isn't working for you, please consider the following before
+posting a bug report:
-+ If what you are expecting is popup-as-you-type completion (which is disabled by default), see the "Customize" section above; it includes instructions on how to enable this.
-+ Certain languages may have extra dependencies in order for auto-completion to work. Please look for that module's README.org for details.
-+ Some languages don't have any auto-completion support.
++ If what you are expecting is popup-as-you-type completion (which is disabled
+ by default), see the "Configure > Auto-completion" section above, which will
+ instruct you on how to enable this.
++ Some languages don't have any auto-completion support at all.
diff --git a/modules/completion/company/test/company.el b/modules/completion/company/test/company.el
index d8969d398..4f7244c14 100644
--- a/modules/completion/company/test/company.el
+++ b/modules/completion/company/test/company.el
@@ -4,20 +4,21 @@
(require! :completion company)
(require 'company)
+;;
(def-test! set-company-backend
- (let ((default-backends (default-value 'company-backends)))
+ :minor-mode company-mode
+ (let ((company-backends '(default)))
(set! :company-backend 'emacs-lisp-mode '(backend-1))
(set! :company-backend 'lisp-interaction-mode 'backend-1 'backend-2)
(set! :company-backend 'text-mode 'backend-1)
(with-temp-buffer
(emacs-lisp-mode)
- (should (equal (car company-backends) '(backend-1))))
+ (should (equal company-backends '((backend-1) default))))
(with-temp-buffer
(lisp-interaction-mode)
- (should (equal company-backends
- (append '(backend-1 backend-2) default-backends))))
+ (should (equal company-backends '(backend-1 backend-2 default))))
(with-temp-buffer
(text-mode)
- (should (eq (car company-backends) 'backend-1)))
+ (should (equal company-backends '(backend-1 default))))
;; global backends shouldn't be affected
- (should (equal company-backends default-backends))))
+ (should (equal company-backends '(default)))))
diff --git a/modules/completion/ivy/README.org b/modules/completion/ivy/README.org
index b0732f935..18f399739 100644
--- a/modules/completion/ivy/README.org
+++ b/modules/completion/ivy/README.org
@@ -3,11 +3,13 @@
This module adds Ivy, a completion backend.
#+begin_quote
-I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's lighter.
+I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's
+lighter.
#+end_quote
+ Project-wide search & replace powered by ~rg~ or ~ag~
-+ Project jump-to navigation ala Command-T, Sublime Text's Jump-to-anywhere or Vim's CtrlP plugin.
++ Project jump-to navigation ala Command-T, Sublime Text's Jump-to-anywhere or
+ Vim's CtrlP plugin.
+ Ivy integration for ~M-x~, ~imenu~, ~recentf~ and others.
+ A powerful, interactive in-buffer search using ~swiper~.
+ Ivy-powered TODO/FIXME navigation
@@ -28,7 +30,9 @@ I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's l
* Install
This module optionally depends on [[https://github.com/BurntSushi/ripgrep][ripgrep]] and [[https://github.com/ggreer/the_silver_searcher][the_silver_searcher]].
-~rg~ is faster, but its results aren't deterministic, neither does it support multiline search or full PCRE, that's where ~ag~ is useful.
+~rg~ is faster, but its results aren't deterministic, neither does it support
+multiline search or full PCRE (at the time of writing), that's where ~ag~ is
+useful.
** MacOS
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
@@ -41,37 +45,58 @@ sudo pacman --needed --noconfirm -S ripgrep the_silver_searcher
#+END_SRC
* Usage
-Here is some insight into how I use this module. Keep in mind that the referenced commands and keybindings are defined [[/modules/private/hlissner][in my private module]].
+Here is some insight into how I use this module.
** Project search & replace
-Ex interfaces to Ag (the silver searcher) and Rg (ripgrep) are available: ~:ag[!]~ and ~:rg[!]~, or their current-directory counterparts ~:agcwd[!]~ and ~:rgcwd[!]~.
+There are four Ex interfaces for the silver searcher and ripgrep. They are:
+
++ ~:ag[!]~
++ ~:agcwd[!]~
++ ~:rg[!]~
++ ~:rgcwd[!]~
+
+The optional BANG tells ag/rg to include ignored files in the search. And the
+\*cwd variant of each command will only search in the current directory
+(non-recursively).
[[/../screenshots/modules/completion/ivy/ivy-search.gif]]
-From this session, you can press =S+Tab= to create a writeable occur-buffer in wgrep mode.
+Now, how do we do text replacements? With the ivy popup open you can press
+=S+Tab= to create an wgrep buffer out of the results.
[[/../screenshots/modules/completion/ivy/ivy-search-replace.gif]]
-Make your modifications and press =C-c C-c= to commit them, or =C-c C-k= to abort.
+Make your modifications and press =C-c C-c= to commit them, or =C-c C-k= to
+abort.
** Jump-to-file project navigation
-Inspired by Sublime Text's jump-to-anywhere, Vim's CtrlP or Unite plugins, and Textmate's Command-T, a marriage of ~projectile~ and ~ivy~ makes this available to you in Emacs. Invoke it with =SPC f /=, =SPC SPC= or ~counsel-projectile-find-file~.
+Inspired by Sublime Text's jump-to-anywhere, Vim's CtrlP/Unite plugins, and
+Textmate's Command-T, a marriage of ~projectile~ and ~ivy~ makes this available
+in Emacs.
+
+Invoke it with =SPC f /=, =SPC SPC= or ~M-x counsel-projectile-find-file~.
[[/../screenshots/modules/completion/ivy/ivy-projectile.gif]]
** In-buffer searching
-I use ~evil-search~ (invoked by pressing =/= in normal mode) when jumping small/moderate (or predictable) distances. However, there are occasions where I need more feedback, so I turn to ~swiper~ (available directly with =M-x swiper RET=, or via ~:sw[iper]~).
+I use ~evil-search~ (invoked by pressing =/= in normal mode) when jumping
+small/moderate (or predictable) distances. However, there are occasions where I
+need more feedback, so I turn to ~swiper~ (available directly with =M-x swiper
+RET=, or via ~:sw[iper]~).
[[/../screenshots/modules/completion/ivy/ivy-swiper.gif]]
** Task lookup
-I sprinkle my projects with TODO's & FIXME's. You can navigate to and peruse them via ~M-x +ivy/tasks~ or ~:todo[!]~ (ex command).
+I sprinkle my projects with TODO's & FIXME's. You can navigate to and peruse
+them via ~M-x +ivy/tasks~ or ~:todo[!]~ (ex command).
[[/../screenshots/modules/completion/ivy/ivy-todo.gif]]
* Appendix
** Commands
-Here is a list of my commonly used commands, their default keybinds (defined in [[../../private/hlissner/+bindings.el][private/hlissner/+bindings.el]]), and their corresponding ex command (defined in [[../../private/hlissner/+commands.el][private/hlissner/+commands.el]]).
+Here is a list of my commonly used commands, their default keybinds (defined in
+[[../../private/default/+bindings.el][private/default/+bindings.el]]), and their corresponding ex command (defined in
+[[../../private/default/+evil-commands.el][private/default/+evil-commands.el]]).
| command | key / ex command | description |
|-------------------------------------+------------------------+------------------------------------------------------------------|
@@ -90,7 +115,8 @@ Here is a list of my commonly used commands, their default keybinds (defined in
| ~+ivy:swiper~ | ~:sw[iper] [QUERY]~ | Search current buffer |
| ~+ivy:todo~ | ~:todo[!]~ | List all TODO/FIXMEs in project (or current file if BANG) |
-While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new keybindings are available to you:
+While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new
+keybindings are available to you:
| key | description |
|-------------+--------------------------------------------------------------------------------|
@@ -99,10 +125,10 @@ While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new keybindi
| =M-RET= | Open the selected candidate in other-window |
** Hacks
-+ Functions with ivy/counsel equivalents have been globally remapped (like ~find-file~ => ~counsel-find-file~). So a keybinding to ~find-file~ will invoke ~counsel-find-file~ instead.
-+ ~counsel-[arp]g~'s 3-character limit was reduced to 1 (mainly for the ex command)
-+ ~counsel-[arp]g~'s parentheses quoting behavior was reversed. Now, if you
- want literal parentheses, you must escape them: e.g. ~\(match\)~ is literal,
- ~(match)~ is a regexp group.
++ Functions with ivy/counsel equivalents have been globally remapped (like
+ ~find-file~ => ~counsel-find-file~). So a keybinding to ~find-file~ will
+ invoke ~counsel-find-file~ instead.
++ ~counsel-[arp]g~'s 3-character limit was reduced to 1 (mainly for the ex
+ command)
diff --git a/modules/completion/ivy/config.el b/modules/completion/ivy/config.el
index bcd027078..fa707c5ea 100644
--- a/modules/completion/ivy/config.el
+++ b/modules/completion/ivy/config.el
@@ -43,8 +43,7 @@ immediately runs it on the current candidate (ending the ivy session)."
(after! magit (setq magit-completing-read-function #'ivy-completing-read))
(after! yasnippet (push #'+ivy-yas-prompt yas-prompt-functions))
- (map! :map ivy-mode-map
- [remap apropos] #'counsel-apropos
+ (map! [remap apropos] #'counsel-apropos
[remap describe-face] #'counsel-describe-face
[remap find-file] #'counsel-find-file
[remap switch-to-buffer] #'ivy-switch-buffer
@@ -52,7 +51,6 @@ immediately runs it on the current candidate (ending the ivy session)."
[remap recentf-open-files] #'counsel-recentf
[remap imenu] #'counsel-imenu
[remap bookmark-jump] #'counsel-bookmark
- [remap projectile-switch-project] #'counsel-projectile-switch-project
[remap projectile-find-file] #'counsel-projectile-find-file
[remap imenu-anywhere] #'ivy-imenu-anywhere
[remap execute-extended-command] #'counsel-M-x
diff --git a/modules/feature/eval/README.org b/modules/feature/eval/README.org
index eb9cf3084..851ea6a48 100644
--- a/modules/feature/eval/README.org
+++ b/modules/feature/eval/README.org
@@ -1,43 +1,52 @@
#+TITLE: :feature eval
-This modules adds support for evaluating code from inside Emacs. This includes REPLs and direct access to the interpreters and compilers of many languages.
+This modules adds support for evaluating code from inside Emacs, including
+REPLs.
* Table of Contents :TOC:
- [[#install][Install]]
- [[#usage][Usage]]
-- [[#configuration][Configuration]]
- [[#repls][REPLs]]
- - [[#code-evaluation][Code Evaluation]]
+ - [[#code-evaluation][*Code Evaluation*]]
+- [[#configuration][Configuration]]
+ - [[#repls-1][REPLs]]
+ - [[#code-evaluation-1][Code Evaluation]]
* Install
-This module has no external dependencies. However, specific languages may require additional setup.
+This module has no external dependencies. However, specific languages may
+require additional setup.
Check the README.org in that language's module for details.
* Usage
-+ *REPLs*
- Invoked via:
- + ~:repl~ (evil ex-command)
- + = o r= in normal mode (or visual mode, which sends the selection to the open REPL)
- + ~M-x +eval/open-repl~
- + ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active
+** REPLs
+Invoked via:
++ ~:repl~ (evil ex-command)
++ = o r= in normal mode (or visual mode, which sends the selection to
+ the open REPL)
++ ~M-x +eval/open-repl~
++ ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active
-+ *Code Evaluation*
- Quickrun can be invoked via:
- + ~M-x +eval/buffer~ (or ~gR~, or ~M-r~)
- + ~M-x +eval/region~
- + ~M-x +eval/region-and-replace~
- + Evil users can use the ~gr~ operator to select and run a region.
+** *Code Evaluation*
+Quickrun can be invoked via:
++ ~M-x +eval/buffer~ (or ~gR~, or ~M-r~)
++ ~M-x +eval/region~
++ ~M-x +eval/region-and-replace~
++ Evil users can use the ~gr~ operator to select and run a region.
* Configuration
** REPLs
-REPLs are defined for most of the languages Doom supports (check its README.org to see if it does).
+REPLs are defined for most of the languages Doom supports (check its README.org
+to see if it does).
-Otherwise, you can define your own for a specified major-mode with the =:repl= setting.
+Otherwise, you can define your own for a specified major-mode with the =:repl=
+setting.
~(set! :repl MAJOR-MODE FUNCTION)~
-FUNCTION must return the repl buffer. Any window changes are ignored, then handed off to shackle (assuming shackle-mode is on) to display in a popup window.
+FUNCTION must return the repl buffer. Any window changes are ignored, then
+handed off to shackle (assuming shackle-mode is on) to display in a popup
+window.
#+BEGIN_SRC emacs-lisp
(defun +emacs-lisp/repl ()
@@ -53,9 +62,14 @@ FUNCTION must return the repl buffer. Any window changes are ignored, then hande
#+END_SRC
** Code Evaluation
-Run regions or entire buffers with [[https://github.com/syohex/emacs-quickrun][Quickrun]]. Output will be sent to a popup window.
+Run regions or entire buffers with [[https://github.com/syohex/emacs-quickrun][Quickrun]]. Output is show in a popup window.
-Quickrun includes support for many languages, but occasionally, you'll find a language without support, such as [[https://crystal-lang.org/][Crystal]]. A "runner" can be defined like so:
+Quickrun includes support for many languages, usually by sending text directly
+to interpreters or compilers. However, occasionally, you'll find a language
+without support (like [[https://crystal-lang.org/][Crystal]]), or a language with better Emacs integration
+(like elisp).
+
+Here's how you define a "runner":
#+BEGIN_SRC emacs-lisp
(set! :eval 'crystal-mode
diff --git a/modules/feature/evil/README.org b/modules/feature/evil/README.org
index 1ba70d4cb..4093c770a 100644
--- a/modules/feature/evil/README.org
+++ b/modules/feature/evil/README.org
@@ -11,12 +11,14 @@ This holy module brings the vim experience to Emacs.
- [[#differences-from-vim][Differences from vim]]
* Removing evil-mode
-To get back a more vanilla Emacs experience, remove =:feature evil= from init.el. Evil-specific configuration and keybindings (defined with ~map!~) will be ignored without evil present (and removed when byte-compiling).
+See the [[https://github.com/hlissner/doom-emacs/wiki/FAQ#remove-vimevil-for-a-more-vanilla-emacs-experience][corresponding question in the FAQ]].
* Features
+ A better ~:g[lobal]~ command with incremental highlighting.
-+ Adds the ~:al[ign]~ ex command: offers an ex interface to ~align-regexp~ with incremental highlighting.
-+ Support for more of vim's filename modifiers in ex commands (like ~:p~, ~:p:h~ or ~:t~) than vanilla evil-mode offers.
++ Adds the ~:al[ign]~ ex command: offers an ex interface to ~align-regexp~ with
+ incremental highlighting.
++ Support for more of vim's filename modifiers in ex commands (like ~:p~, ~:p:h~
+ or ~:t~) than vanilla evil-mode offers.
+ A list of new text objects:
+ Blocks: ~B~ (from ~evil-textobj-anyblock~)
+ Args: ~a~ (from ~evil-args~)
@@ -31,20 +33,29 @@ To get back a more vanilla Emacs experience, remove =:feature evil= from init.el
+ =NERDTree= equivalent is available in =:tools neotree=
** Multiple-cursors
-Two multiple-cursor implementations exist in this module: ~evil-mc~ and ~evil-multiedit~. Together, these provide the functionality of ~vim-multiple-cursors~.
+Two multiple-cursor implementations exist in this module: ~evil-mc~ and
+~evil-multiedit~. Together, these provide the functionality of
+~vim-multiple-cursors~.
-The former lets you place "clone" cursors. The latter lets you interactively edit many regions from one place (like an interactive version of ~:%s~).
+The former lets you place "clone" cursors. The latter lets you interactively
+edit many regions at once (like an interactive version of ~:%s~).
** A hybrid code-folding system
-This module combines ~evil-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.
+This module combines ~evil-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.
** Hacks
+ Automatically moves to new window when splitting
-+ If in visual mode, =*= and =#= will search for the current selection instead of the word-at-point.
++ From visual mode, =*= and =#= will search for the current selection instead of
+ the word-at-point.
** 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~).
++ 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.
diff --git a/modules/feature/evil/autoload/files.el b/modules/feature/evil/autoload/files.el
index c247f6f46..c7d293281 100644
--- a/modules/feature/evil/autoload/files.el
+++ b/modules/feature/evil/autoload/files.el
@@ -35,7 +35,7 @@ kills the buffer. If FORCE-P, force the deletion (don't ask for confirmation)."
(error "Failed to delete %s" short-path)
;; Ensures that windows displaying this buffer will be switched
;; to real buffers (`doom-real-buffer-p')
- (doom-force-kill-buffer buf t)
+ (doom/kill-this-buffer-in-all-windows buf t)
(+evil--forget-file fname)
(message "Successfully deleted %s" short-path))))))))
diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el
index 4d24b856e..bf0efc808 100644
--- a/modules/feature/evil/config.el
+++ b/modules/feature/evil/config.el
@@ -388,8 +388,8 @@ the new algorithm is confusing, like in python or ruby."
;;
;; mc doesn't play well with evil, this attempts to assuage some of its problems
-;; so that certain plugins (which I have no control over) can still use it in
-;; relative safety.
+;; so that any plugins that depend on multiple-cursors (which I have no control
+;; over) can still use it in relative safety.
(after! multiple-cursors-core
(map! :map mc/keymap :ne "" #'mc/keyboard-quit)
diff --git a/modules/feature/evil/test/autoload-files.el b/modules/feature/evil/test/autoload-files.el
index 762e39fbe..b14185cd1 100644
--- a/modules/feature/evil/test/autoload-files.el
+++ b/modules/feature/evil/test/autoload-files.el
@@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; feature/evil/test/autoload-files.el
-(defmacro -with-temp-files! (src dest &rest body)
+(defmacro with-temp-files!! (src dest &rest body)
"Run FORMS in the context of a temporary package setup (as in, it won't
affects your Emacs packages)."
(declare (indent 2) (doc-string 3))
@@ -23,7 +23,7 @@ affects your Emacs packages)."
;;
(def-test! move-this-file
":mv"
- (-with-temp-files! "/tmp/doom-buffer" "/tmp/doom-buffer-new"
+ (with-temp-files!! "/tmp/doom-buffer" "/tmp/doom-buffer-new"
(should-error (+evil:move-this-file it))
(should (+evil:move-this-file other t))
(should (file-exists-p other))
@@ -31,7 +31,7 @@ affects your Emacs packages)."
(def-test! copy-this-file
":cp"
- (-with-temp-files! "/tmp/doom-buffer-2" "/tmp/doom-buffer-2-new"
+ (with-temp-files!! "/tmp/doom-buffer-2" "/tmp/doom-buffer-2-new"
(should-error (+evil:copy-this-file it))
(should (+evil:copy-this-file other t))
(should (file-exists-p other))
@@ -39,7 +39,7 @@ affects your Emacs packages)."
(def-test! delete-this-file
":rm"
- (-with-temp-files! "/tmp/doom-buffer-3" nil
+ (with-temp-files!! "/tmp/doom-buffer-3" nil
(should-error (+evil:delete-this-file "this-file-does-not-exist"))
(should (+evil:delete-this-file nil t))
(should (not (file-exists-p it)))))
diff --git a/modules/feature/evil/test/evil.el b/modules/feature/evil/test/evil.el
index 7fd0626a3..ffe6f92a1 100644
--- a/modules/feature/evil/test/evil.el
+++ b/modules/feature/evil/test/evil.el
@@ -3,6 +3,7 @@
(require! :feature evil)
+;;
;; `evil-ex-replace-special-filenames'
;; NOTE The majority of this function is tested in core/test/core-lib.el, this
;; only tests the evil-mode-specific functionality.
diff --git a/modules/feature/file-templates/config.el b/modules/feature/file-templates/config.el
index b8d6fcf10..db8feaafe 100644
--- a/modules/feature/file-templates/config.el
+++ b/modules/feature/file-templates/config.el
@@ -6,6 +6,11 @@
(expand-file-name "templates/" (file-name-directory load-file-name))
"The path to a directory of yasnippet folders to use for file templates.")
+
+;;
+;; Plugins
+;;
+
(def-package! autoinsert ; built-in
:defer 1
:init
@@ -18,12 +23,16 @@
(auto-insert-mode 1)
(defun +file-templates--expand (key &optional mode project-only)
- "Auto insert a snippet of yasnippet into new file."
+ "Auto insert a yasnippet snippet into the blank file."
(when (if project-only (doom-project-p) t)
(require 'yasnippet)
- (unless yas-minor-mode (yas-minor-mode-on))
+ (unless yas-minor-mode
+ (yas-minor-mode-on))
(when (and yas-minor-mode
- (yas-expand-snippet (yas-lookup-snippet key mode t))
+ (yas-expand-snippet
+ (yas--template-content
+ (cl-find key (yas--all-templates (yas--get-snippet-tables mode))
+ :key #'yas--template-key :test #'equal)))
(and (featurep 'evil) evil-mode)
(and yas--active-field-overlay
(overlay-buffer yas--active-field-overlay)
@@ -56,10 +65,9 @@
("\\.el$" "__initfile" emacs-lisp-mode)
("/.dir-locals.el$" nil)
("-test\\.el$" "__" emacs-ert-mode)
- ("/.emacs.d/.+\\.el$" "__doom-module" emacs-lisp-mode)
- ("/.emacs.d/.+/packages\\.el$" "__doom-packages" emacs-lisp-mode)
- ("/.emacs.d/.+/test\\.el$" "__doom-test" emacs-lisp-mode)
- ("/.emacs.d/.+/README\\.org$" "__doom-readme" org-mode)
+ ("/\\(?:.emacs.d\\|doom-emacs\\)?/.+\\.el$" "__doom-module" emacs-lisp-mode)
+ ("/\\(?:.emacs.d\\|doom-emacs\\)?/.+/packages\\.el$" "__doom-packages" emacs-lisp-mode)
+ ("/\\(?:.emacs.d\\|doom-emacs\\)?/.+/test/.+\\.el$" "__doom-test" emacs-lisp-mode)
(snippet-mode "__" snippet-mode)
;; Go
("\\.go$" "__.go" go-mode)
@@ -82,7 +90,8 @@
;; Markdown
("\\.md$" "__" markdown-mode)
;; Org
- ("\\.org$" "__" org-mode)
+ ("\\.org$" "__" org-mode)
+ ("/\\(?:.emacs.d\\|doom-emacs\\)?/.+/README\\.org$" "__doom-readme" org-mode)
;; PHP
("\\.php$" "__" php-mode)
("\\.class\\.php$" "__.class.php" php-mode)
@@ -110,5 +119,5 @@
("/\\(index\\|main\\)\\.slim$" "__" slim-mode)
;; Shell scripts
("\\.z?sh$" "__" sh-mode)
+ ("\\.fish$" "__" fish-mode)
("\\.zunit$" "__zunit" sh-mode))))
-
diff --git a/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-module b/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-module
index d2e44ba28..4f5468293 100644
--- a/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-module
+++ b/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-module
@@ -1,3 +1,3 @@
-;;; `(file-relative-name buffer-file-name doom-modules-dir)` -*- lexical-binding: t; -*-
+;;; `(file-relative-name buffer-file-truename doom-modules-dir)` -*- lexical-binding: t; -*-
$0
diff --git a/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-packages b/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-packages
index 789b9b983..a87f1eae8 100644
--- a/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-packages
+++ b/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-packages
@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
-;;; `(file-relative-name buffer-file-name doom-modules-dir)`
+;;; `(file-relative-name buffer-file-truename doom-modules-dir)`
$0
diff --git a/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-test b/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-test
index 9cd77f6ac..af428094a 100644
--- a/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-test
+++ b/modules/feature/file-templates/templates/emacs-lisp-mode/__doom-test
@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
-;;; `(file-relative-name buffer-file-name doom-modules-dir)`
+;;; `(file-relative-name buffer-file-truename doom-modules-dir)`
$0
\ No newline at end of file
diff --git a/modules/feature/file-templates/templates/fish-mode/__ b/modules/feature/file-templates/templates/fish-mode/__
new file mode 100644
index 000000000..a4ef95db3
--- /dev/null
+++ b/modules/feature/file-templates/templates/fish-mode/__
@@ -0,0 +1,3 @@
+#!/usr/bin/env fish
+
+$0
diff --git a/modules/feature/jump/autoload/jump.el b/modules/feature/jump/autoload/jump.el
index 21d951f3b..36ad3c49c 100644
--- a/modules/feature/jump/autoload/jump.el
+++ b/modules/feature/jump/autoload/jump.el
@@ -97,7 +97,9 @@ Tries `xref-find-references' and falls back to rg/ag."
(cond ((plist-member +jump-current-functions :documentation)
(+jump-to :documentation identifier))
(t
- (+jump/online (caar +jump-search-provider-alist) identifier))))
+ (+jump/online
+ identifier
+ (+jump--online-get-provider (not current-prefix-arg))))))
(defun +jump--online-get-provider (&optional force-p)
(or (and (not force-p)
diff --git a/modules/feature/jump/config.el b/modules/feature/jump/config.el
index db7a65069..f4e005446 100644
--- a/modules/feature/jump/config.el
+++ b/modules/feature/jump/config.el
@@ -29,7 +29,7 @@
"An alist that maps online resources to their search url or a function that
produces an url. Used by `+jump/online'.")
-(defconst +jump-search-browser-fn #'browse-url
+(defvar +jump-search-browser-fn #'browse-url
"Function to use to open search urls.")
(defvar +jump-function-alist nil
@@ -82,6 +82,18 @@ properties:
;; Packages
;;
+(def-package! ivy-xref
+ :when (featurep! :completion ivy)
+ :after xref
+ :config (setq xref-show-xrefs-function #'ivy-xref-show-xrefs))
+
+
+(def-package! helm-xref
+ :when (featurep! :completion helm)
+ :after xref
+ :config (setq xref-show-xrefs-function #'helm-xref-show-xrefs))
+
+
(def-package! dumb-jump
:commands (dumb-jump-go dumb-jump-quick-look
dumb-jump-back dumb-jump-result-follow)
@@ -92,28 +104,3 @@ properties:
((featurep! :completion helm) 'helm)
(t 'popup))))
-
-(def-package! gxref
- :commands (gxref-xref-backend
- gxref-create-db
- gxref-update-db
- gxref-single-update-db
- gxref-set-project-dir)
- :init
- (setq-default xref-backend-functions '(gxref-xref-backend t)))
-
-
-;; (def-package! ggtags
-;; :commands (ggtags-find-tag-dwim
-;; ggtags-find-tag-mouse
-;; ggtags-find-definition
-;; ggtags-find-reference
-;; ggtags-find-other-symbol
-;; ggtags-find-tag-regexp
-;; ggtags-idutils-query
-;; ggtags-grep
-;; ggtags-find-file
-;; ggtags-query-replace
-;; ggtags-delete-tags
-;; ggtags-explain-tags))
-
diff --git a/modules/feature/jump/packages.el b/modules/feature/jump/packages.el
index 4dce3ac0d..712158bb2 100644
--- a/modules/feature/jump/packages.el
+++ b/modules/feature/jump/packages.el
@@ -2,10 +2,7 @@
;;; feature/jump/packages.el
(package! dumb-jump)
-(package! gxref)
-;; (package! ggtags)
-;; (cond ((featurep! :completion ivy)
-;; (package! counsel-gtags))
-;; ((featurep! :completion helm)
-;; (package! helm-gtags)))
-
+(when (featurep! :completion ivy)
+ (package! ivy-xref))
+(when (featurep! :completion helm)
+ (package! helm-xref))
diff --git a/modules/feature/snippets/README.org b/modules/feature/snippets/README.org
index 3a81372b6..d22278f1b 100644
--- a/modules/feature/snippets/README.org
+++ b/modules/feature/snippets/README.org
@@ -8,20 +8,5 @@ This module adds snippets to Emacs, powered by yasnippet.
* Install
There are no extra dependencies for this module.
-By default, this module uses the snippet library included with yasnippet.
-
-For the best experience, I'd suggest installing mine from https://github.com/hlissner/emacs-snippets -- they have been tailored specifically for Doom.
-
-1. Clone the repo to your private module:
- #+BEGIN_SRC bash
- git clone https://github.com/hlissner/emacs-snippets ~/.emacs.d/modules/private/$(whoami)/snippets
- #+END_SRC
-2. Tell yasnippet where to look for them:
- #+BEGIN_SRC emacs-lisp
- ;; modules/private/{USERNAME}/config.el
- (after! yasnippet
- (setq yas-snippet-dirs
- (append (list (expand-file-name "snippets/" (file-name-directory load-file-name)))
- (delq 'yas-installed-snippets-dir yas-snippet-dirs))))
- #+END_SRC
-
+By default, =private/default= installs a snippet library tailored exclusively
+for Doom Emacs.
diff --git a/modules/feature/snippets/config.el b/modules/feature/snippets/config.el
index a00450d79..68c1a9a97 100644
--- a/modules/feature/snippets/config.el
+++ b/modules/feature/snippets/config.el
@@ -11,8 +11,6 @@
(defvar yas-minor-mode-map (make-sparse-keymap))
:init
- (setq yas-snippet-dirs '(yas-installed-snippets-dir))
-
;; Ensure `yas-reload-all' is called as late as possible. Other modules could
;; have additional configuration for yasnippet. For example, file-templates.
(add-transient-hook! 'yas-minor-mode-hook (yas-reload-all))
@@ -21,11 +19,9 @@
#'yas-minor-mode-on)
:config
- (setq yas-verbosity 0
- yas-indent-line 'auto
+ (setq yas-verbosity (if doom-debug-mode 3 0)
yas-also-auto-indent-first-line t
- yas-prompt-functions '(yas-completing-prompt yas-ido-prompt yas-no-prompt)
- yas-use-menu nil
+ yas-prompt-functions (delq 'yas-dropdown-prompt yas-prompt-functions)
;; Allow nested snippets
yas-triggers-in-field t)
@@ -40,27 +36,8 @@
;; fix an error caused by smartparens interfering with yasnippet bindings
(advice-add #'yas-expand :before #'sp-remove-active-pair-overlay)
- (after! evil
- ;; Exit snippets on ESC in normal mode
- (add-hook '+evil-esc-hook #'yas-exit-all-snippets)
- ;; Once you're in normal mode, you're out
- (add-hook 'evil-normal-state-entry-hook #'yas-abort-snippet)
- ;; Strip out whitespace before a line selection
- (defun +snippets|yas-before-expand ()
- "Strip out the shitespace before a line selection."
- (when (and (evil-visual-state-p)
- (eq (evil-visual-type) 'line))
- (setq yas-selected-text
- (replace-regexp-in-string
- "\\(^\\s-*\\|\n? $\\)" ""
- (buffer-substring-no-properties evil-visual-beginning
- evil-visual-end)))))
- (add-hook 'yas-before-expand-snippet-hook #'+snippets|yas-before-expand)
-
- (defun +snippets|yas-after-expand ()
- "Fix previous hook persisting yas-selected-text between expansions."
- (setq yas-selected-text nil))
- (add-hook 'yas-after-exit-snippet-hook #'+snippets|yas-after-expand)))
+ ;; Exit snippets on ESC from normal mode
+ (add-hook '+evil-esc-hook #'yas-exit-all-snippets))
(def-package! auto-yasnippet
diff --git a/modules/feature/version-control/+git.el b/modules/feature/version-control/+git.el
index 4467441bf..8a8770880 100644
--- a/modules/feature/version-control/+git.el
+++ b/modules/feature/version-control/+git.el
@@ -1,6 +1,10 @@
;;; feature/version-control/+git.el -*- lexical-binding: t; -*-
;;;###if (not (featurep! -git))
+(when (featurep! :feature evil)
+ (add-hook 'git-commit-mode-hook #'evil-insert-state))
+
+
(def-package! gitconfig-mode
:mode "/\\.?git/?config$"
:mode "/\\.gitmodules$")
diff --git a/modules/feature/workspaces/README.org b/modules/feature/workspaces/README.org
index c2e3f2c71..29f8dec1a 100644
--- a/modules/feature/workspaces/README.org
+++ b/modules/feature/workspaces/README.org
@@ -1,9 +1,15 @@
#+TITLE: :feature workspaces
-This module adds support for workspaces, powered by persp_mode, as well as a unified API for manipulating them.
+This module adds support for workspaces, powered by persp_mode, as well as a API
+for manipulating them.
#+begin_quote
-There are many ways to use workspaces. Some use them to group buffers/windows by project or categories (views, models, logic, etc). I use them differently: on a per-task basis, which may traverse multiple projects or aspects, but are tied to an objective. For example: implement a specific feature or fix a certain bug; sometimes unrelated to the project at hand.
+There are many ways to use workspaces. I spawn a workspace per task. Say I'm
+working in the main workspace, when I realize there is a bug in another part of
+my project. I open a new workspace and deal with it in there. In the meantime, I
+need to check my email, so mu4e gets its own workspace.
+
+Once I've completed the task, I close the workspace and return to main.
#+end_quote
* Table of Contents :TOC:
@@ -22,25 +28,33 @@ This module has no additional dependencies.
* Features
** Isolated buffer-list
-When persp-mode is active, ~doom-buffer-list~ becomes workspace-restricted. You can overcome this by using ~buffer-list~.
+When persp-mode is active, ~doom-buffer-list~ becomes workspace-restricted. You
+can overcome this by using ~buffer-list~.
** Automatic workspaces
A workspace is automatically created (and switched to) when you:
-+ Create a new frame (with =make-frame=; bound to =M-N= by default)
-+ Switch to a project using ~projectile-switch-project~ (or its ivy/helm equivalents)
++ Create a new frame (with =make-frame=; bound to =M-N= by default).
++ Switch to a project using ~projectile-switch-project~.
** Session persistence
-By default, your session is autosaved when you quit Emacs (or disable ~persp-mode~). You can load a previous session with ~M-x +workspace/load-session~ or ~:sl[oad]~ (ex command).
+By default, your session is autosaved when you quit Emacs (or disable
+~persp-mode~). You can load a previous session with ~M-x
++workspace/load-session~ or ~:sl[oad]~ (ex command).
-You can supply either a name to load a specific session to replace your current one.
+You can supply either a name to load a specific session to replace your current
+one.
** Workspace persistence
-If you'd like to save a specific workspace, use ~M-x +workspace/save~, which can be loaded into the current session (as another workspace) with ~M-x +workspace/load~.
+If you'd like to save a specific workspace, use ~M-x +workspace/save~, which can
+be loaded into the current session (as another workspace) with ~M-x
++workspace/load~.
* Appendix
** Commands & Keybindings
-Here is a list of available commands, their default keybindings (defined in private/hlissner/+bindings.el), and corresponding ex commands (if any -- defined in private/hlissner/+commands.el).
+Here is a list of available commands, their default keybindings (defined in
+[[../../private/default/+bindings.el][private/default/+bindings.el]]), and corresponding ex commands (if any -- defined
+in [[../../private/default/+evil-commands.el][private/default/+evil-commands.el]]).
| command | key / ex command | description |
|---------------------------+----------------------------+------------------------------------------------------------|
diff --git a/modules/feature/workspaces/autoload/workspaces.el b/modules/feature/workspaces/autoload/workspaces.el
index 8566cd860..7aff9382c 100644
--- a/modules/feature/workspaces/autoload/workspaces.el
+++ b/modules/feature/workspaces/autoload/workspaces.el
@@ -310,7 +310,7 @@ workspace to delete."
(doom/kill-all-buffers)
(let ((fallback-buf (doom-fallback-buffer)))
(switch-to-buffer fallback-buf)
- (doom/cleanup-buffers)))
+ (doom/cleanup-session)))
;;;###autoload
(defun +workspace/kill-session-and-quit ()
diff --git a/modules/feature/workspaces/config.el b/modules/feature/workspaces/config.el
index 6bcb58ffe..f03fb236f 100644
--- a/modules/feature/workspaces/config.el
+++ b/modules/feature/workspaces/config.el
@@ -47,10 +47,22 @@ renamed.")
;; per-frame and per-project workspaces
(setq persp-init-new-frame-behaviour-override nil
- persp-interactive-init-frame-behaviour-override #'+workspace-on-new-frame
- projectile-switch-project-action #'projectile-find-file)
+ persp-interactive-init-frame-behaviour-override #'+workspace-on-new-frame)
(add-hook 'delete-frame-functions #'+workspaces|delete-associated-workspace-maybe)
- (advice-add #'projectile-switch-project-by-name :around #'+workspaces*switch-project-by-name)
+
+ (defun +workspaces|per-project (&optional root)
+ "Open a new workspace when switching to another project.
+
+Ensures the scratch (or dashboard) buffers are CDed into the project's root."
+ (when persp-mode
+ (let ((cwd default-directory))
+ (+workspace-switch (projectile-project-name) t)
+ (switch-to-buffer (doom-fallback-buffer))
+ (setq default-directory cwd)
+ (+workspace-message
+ (format "Switched to '%s' in new workspace" (+workspace-current-name))
+ 'success))))
+ (setq projectile-switch-project-action #'+workspaces|per-project)
;; only auto-save when real buffers are present
(advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers)
@@ -68,7 +80,10 @@ renamed.")
(remove-hook 'delayed-warnings-hook #'display-delayed-warnings)
(defun +workspaces|init (&optional frame)
(unless persp-mode
- (persp-mode +1))
+ (persp-mode +1)
+ ;; Ensure `persp-kill-buffer-query-function' is last in kill-buffer-query-functions
+ (remove-hook 'kill-buffer-query-functions 'persp-kill-buffer-query-function)
+ (add-hook 'kill-buffer-query-functions 'persp-kill-buffer-query-function t))
(let ((frame (or frame (selected-frame))))
(unless noninteractive
;; The default perspective persp-mode makes (defined by
diff --git a/modules/feature/workspaces/test/autoload-workspaces.el b/modules/feature/workspaces/test/autoload-workspaces.el
index 3f1637aa2..ff69bfb67 100644
--- a/modules/feature/workspaces/test/autoload-workspaces.el
+++ b/modules/feature/workspaces/test/autoload-workspaces.el
@@ -3,7 +3,7 @@
(require! :feature workspaces)
-(defmacro -with-workspace! (buffer-args &rest body)
+(defmacro with-workspace!! (buffer-args &rest body)
(declare (indent defun))
(let ((buffers
(cl-loop for bsym in buffer-args
@@ -27,14 +27,19 @@
;;
(def-test! init
- (-with-workspace! ()
+ (with-workspace!! ()
(should (equal (+workspace-current-name) +workspaces-main))))
-(def-test! advice
- (should (advice-member-p #'+workspaces*auto-add-buffer #'switch-to-buffer)))
+(def-test! auto-add-buffer-to-persp
+ (let ((a (generate-new-buffer "a")))
+ (doom-set-buffer-real a t)
+ (with-workspace!! ()
+ (should-not (+workspace-contains-buffer-p a))
+ (switch-to-buffer a)
+ (should (+workspace-contains-buffer-p a)))))
(def-test! current
- (-with-workspace! ()
+ (with-workspace!! ()
(should (equal (+workspace-current-name) +workspaces-main))
(should (+workspace-exists-p +workspaces-main))
(let ((workspace (+workspace-get +workspaces-main))
@@ -45,7 +50,7 @@
(should (equal workspace current-workspace)))))
(def-test! workspace-list
- (-with-workspace! ()
+ (with-workspace!! ()
(should (equal (+workspace-list-names)
(list (+workspace-current-name))))
(should (equal (+workspace-list)
@@ -53,7 +58,7 @@
(def-test! workspace-crud
"Creating, reading, updating and deleting workspaces."
- (-with-workspace! ()
+ (with-workspace!! ()
(let ((new-workspace-name "*new-test*")
(renamed-workspace-name "*old-test*"))
(should (+workspace-new new-workspace-name))
@@ -67,14 +72,14 @@
(should (= (length (+workspace-list-names)) 1)))))
(def-test! workspace-switch
- (-with-workspace! ()
+ (with-workspace!! ()
(let ((new-workspace-name "*new-test*"))
(should-error (+workspace-switch new-workspace-name))
(should (+workspace-switch new-workspace-name t))
(should (equal (+workspace-current-name) new-workspace-name)))))
(def-test! buffer-list
- (-with-workspace! (a b)
+ (with-workspace!! (a b)
(let ((c (get-buffer-create "c"))
(d (get-buffer-create "d")))
(should (+workspace-contains-buffer-p a))
diff --git a/modules/lang/cc/README.org b/modules/lang/cc/README.org
index 767519879..ecb9d6f88 100644
--- a/modules/lang/cc/README.org
+++ b/modules/lang/cc/README.org
@@ -5,26 +5,36 @@ This module adds support for the C-family of languages: C, C++, and Objective-C.
+ Code completion (~company-irony~)
+ eldoc support (~irony-eldoc~)
+ Syntax-checking (~flycheck-irony~)
-+ Code navigation (~irony~)
++ Code navigation (~rtags~)
+ File Templates ([[../../feature/file-templates/templates/c-mode][c-mode]], [[../../feature/file-templates/templates/c++-mode][c++-mode]])
+ Snippets ([[https://github.com/hlissner/emacs-snippets/tree/master/cc-mode][cc-mode]], [[https://github.com/hlissner/emacs-snippets/tree/master/c-mode][c-mode]], [[https://github.com/hlissner/emacs-snippets/tree/master/c++-mode][c++-mode]])
+ Several improvements to C++11 indentation and syntax highlighting.
#+begin_quote
-C contends with Haskell and Ruby for my favorite language. That said, it's more accurate to say I write C, but with two or three C++ features.
+C contends with Haskell and Ruby for my favorite language. That said, it's more
+accurate to say I write C, but a C++ feature or three.
-The module provides nominal support for Objective-C, which I really only use to inspect generated glue code for iOS mobile apps. Otherwise, I prefer Swift.
+The module provides nominal support for Objective-C, which I really only use to
+inspect generated glue code for iOS mobile apps. Otherwise, I prefer Swift.
#+end_quote
* Table of Contents :TOC:
- [[#install][Install]]
- - [[#macos][MacOS]]
- - [[#arch-linux][Arch Linux]]
+ - [[#irony-server][irony-server]]
+ - [[#rtags][rtags]]
+- [[#configure][Configure]]
+ - [[#compile-settings][Compile settings]]
* Install
-This module requires ~irony-server~ for most of its features, which depends on ~cmake~ and ~libclang~.
+This module requires:
-** MacOS
++ irony-server
++ rtags
+
+** irony-server
+Irony powers the code completion, eldoc and syntax checking systems.
+
+*** MacOS
Due to linking issues, MacOS users must compile irony-server manually:
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
@@ -49,10 +59,46 @@ popd
rm -rf irony-mode
#+END_SRC
-** Arch Linux
+*** Arch Linux
#+BEGIN_SRC sh :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S clang cmake
#+END_SRC
Then run ~M-x irony-install-server~ in Emacs.
+** rtags
+Code navigation requires an [[https://github.com/Andersbakken/rtags][rtags]] server (~rdm~) installed and running. This
+should be available through your OS's package manager.
+
+This module will auto-start ~rdm~ when you open C/C++ buffers (so long as one
+isn't already). If you prefer to run it yourself, outside of Emacs:
+
+#+BEGIN_SRC sh
+rdm &
+rc -J $PROJECT_ROOT # loads PROJECT_ROOT's compile_commands.json
+#+END_SRC
+
+* Configure
+** Compile settings
+By default, a set of default compile settings are defined in
+~+cc-default-compiler-options~ for C, C++ and Objective C. Irony, rtags and
+flycheck will fall back to these.
+
+To make these tools aware of project specific build settings, you need a JSON
+[[https://sarcasm.github.io/notes/dev/compilation-database.html#ninja][compilation database]] present (i.e. a ~compile_commands.json~ file).
+
+There are [[https://sarcasm.github.io/notes/dev/compilation-database.html][many ways to generate one]]. I use [[http://www.cmake.org/][CMake]] and [[https://github.com/rizsotto/Bear][bear]]:
+
+#+BEGIN_SRC sh
+# For CMake projects
+cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
+
+# For non-CMake projects
+make clean
+bear make
+#+END_SRC
+
+#+begin_quote
+Use ~M-x +cc/reload-compile-db~ to reload your compile db in an already-open
+C/C++/ObjC buffer.
+#+end_quote
diff --git a/modules/lang/cc/autoload.el b/modules/lang/cc/autoload.el
index 046ed54db..d40bcd104 100644
--- a/modules/lang/cc/autoload.el
+++ b/modules/lang/cc/autoload.el
@@ -1,5 +1,24 @@
;;; lang/cc/autoload.el -*- lexical-binding: t; -*-
+;;;###autoload
+(defun +cc/reload-compile-db (&optional force-p)
+ "Reload the current project's JSON compilation database."
+ (interactive "P")
+ (unless (memq major-mode '(c-mode c++-mode objc-mode))
+ (user-error "Not a C/C++/ObjC buffer"))
+ (unless (doom-project-has! "compile_commands.json")
+ (user-error "No compile_commands.json file"))
+ ;; first rtag
+ (when (and (featurep 'rtags)
+ rtags-enabled
+ (executable-find "rc"))
+ (with-temp-buffer
+ (message "Reloaded compile commands for rtags daemon")
+ (rtags-call-rc :silent t "-J" (doom-project-root))))
+ ;; then irony
+ (when (and (featurep 'irony) irony-mode)
+ (+cc|irony-init-compile-options)))
+
;;;###autoload
(defun +cc*align-lambda-arglist (orig-fun &rest args)
"Improve indentation of continued C++11 lambda function opened as argument."
@@ -66,8 +85,8 @@
;;;###autoload
(defun +cc|irony-init-compile-options ()
"Initialize compiler options for irony-mode. It searches for the nearest
-compilation database and initailizes it. If none was found, it uses
-`+cc-c++-compiler-options'.
+compilation database and initailizes it, otherwise falling back on
+`+cc-default-compiler-options' and `+cc-default-include-paths'.
See https://github.com/Sarcasm/irony-mode#compilation-database for details on
compilation dbs."
@@ -75,8 +94,8 @@ compilation dbs."
(require 'irony-cdb)
(unless (irony-cdb-autosetup-compile-options)
(irony-cdb--update-compile-options
- (append (delq nil (cdr-safe (assq major-mode +cc-compiler-options)))
- (cl-loop for path in +cc-include-paths
+ (append (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))
+ (cl-loop for path in +cc-default-include-paths
nconc (list "-I" path)))
(doom-project-root)))))
diff --git a/modules/lang/cc/config.el b/modules/lang/cc/config.el
index 9563ef452..f5b61e172 100644
--- a/modules/lang/cc/config.el
+++ b/modules/lang/cc/config.el
@@ -1,13 +1,11 @@
;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*-
-(defvar +cc-include-paths (list "include/")
- "A list of paths, relative to a project root, to search for headers in C/C++.
-Paths can be absolute.
+(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 JSON
+compilation database.")
-The purpose of this variable is to ensure syntax checkers and code-completion
-knows where to look for headers.")
-
-(defvar +cc-compiler-options
+(defvar +cc-default-compiler-options
`((c-mode . nil)
(c++-mode
. ,(list "-std=c++11" ; use C++11 by default
@@ -112,12 +110,16 @@ compilation database is present in the project.")
:after cc-mode
:commands irony-install-server
:preface (setq irony-server-install-prefix (concat doom-etc-dir "irony-server/"))
- :hook ((c-mode c++-mode objc-mode) . irony-mode)
+ :init
+ (defun +cc|init-irony-mode ()
+ (when (memq major-mode '(c-mode c++-mode objc-mode))
+ (irony-mode +1)))
+ (add-hook! (c-mode c++-mode objc-mode) #'+cc|init-irony-mode)
:config
(unless (file-directory-p irony-server-install-prefix)
(warn "irony-mode: server isn't installed; run M-x irony-install-server"))
;; Initialize compilation database, if present. Otherwise, fall back on
- ;; `+cc-compiler-options'.
+ ;; `+cc-default-compiler-options'.
(add-hook 'irony-mode-hook #'+cc|irony-init-compile-options))
(def-package! irony-eldoc
@@ -144,7 +146,8 @@ compilation database is present in the project.")
;;
(def-package! cmake-mode
- :mode "CMakeLists\\.txt$"
+ :mode "/CMakeLists\\.txt$"
+ :mode "\\.cmake\\$"
:config
(set! :company-backend 'cmake-mode '(company-cmake company-yasnippet)))
@@ -163,19 +166,76 @@ compilation database is present in the project.")
;;
-;; Plugins
+;; Company plugins
;;
-(when (featurep! :completion company)
- (def-package! company-cmake :after cmake-mode)
+(def-package! company-cmake
+ :when (featurep! :completion company)
+ :after cmake-mode)
- (def-package! company-irony :after irony)
+(def-package! company-irony
+ :when (featurep! :completion company)
+ :after irony)
- (def-package! company-irony-c-headers :after company-irony)
+(def-package! company-irony-c-headers
+ :when (featurep! :completion company)
+ :after company-irony)
- (def-package! company-glsl
- :after glsl-mode
- :config
- (if (executable-find "glslangValidator")
- (warn "glsl-mode: couldn't find glslangValidator, disabling company-glsl")
- (set! :company-backend 'glsl-mode '(company-glsl)))))
+(def-package! company-glsl
+ :when (featurep! :completion company)
+ :after glsl-mode
+ :config
+ (if (executable-find "glslangValidator")
+ (warn "glsl-mode: couldn't find glslangValidator, disabling company-glsl")
+ (set! :company-backend 'glsl-mode '(company-glsl))))
+
+
+;;
+;; Rtags Support
+;;
+
+(def-package! rtags
+ :after cc-mode
+ :config
+ (setq rtags-autostart-diagnostics t
+ rtags-use-bookmarks nil
+ rtags-completions-enabled nil
+ ;; If not using ivy or helm to view results, use a pop-up window rather
+ ;; than displaying it in the current window...
+ rtags-results-buffer-other-window t
+ ;; ...and don't auto-jump to first match before making a selection.
+ rtags-jump-to-first-match nil)
+
+ (let ((bins (cl-remove-if-not #'executable-find '("rdm" "rc"))))
+ (if (/= (length bins) 2)
+ (warn "cc-mode: couldn't find %s, disabling rtags support" bins)
+ (add-hook! (c-mode c++-mode) #'rtags-start-process-unless-running)
+ (set! :jump '(c-mode c++-mode)
+ :definition #'rtags-find-symbol-at-point
+ :references #'rtags-find-references-at-point)))
+
+ (add-hook 'doom-cleanup-hook #'rtags-cancel-process)
+ (add-hook! kill-emacs (ignore-errors (rtags-cancel-process)))
+
+ ;; Use rtags-imenu instead of imenu/counsel-imenu
+ (map! :map (c-mode-map c++-mode-map) [remap imenu] #'rtags-imenu)
+
+ (add-hook 'rtags-jump-hook #'evil-set-jump)
+ (add-hook 'rtags-after-find-file-hook #'recenter))
+
+(def-package! ivy-rtags
+ :when (featurep! :completion ivy)
+ :after rtags
+ :init
+ ;; NOTE Ivy integration breaks when rtags is byte-compiled with Emacs 26 or
+ ;; later, so we un-byte-compile it before we load it.
+ (eval-when-compile
+ (when (>= emacs-major-version 26)
+ (when-let* ((elc-file (locate-library "rtags.elc" t doom--package-load-path)))
+ (delete-file elc-file))))
+ :config (setq rtags-display-result-backend 'ivy))
+
+(def-package! helm-rtags
+ :when (featurep! :completion helm)
+ :after rtags
+ :config (setq rtags-display-result-backend 'helm))
diff --git a/modules/lang/cc/packages.el b/modules/lang/cc/packages.el
index 8109c1886..8151bc4fd 100644
--- a/modules/lang/cc/packages.el
+++ b/modules/lang/cc/packages.el
@@ -8,8 +8,8 @@
(package! glsl-mode)
(package! irony)
(package! irony-eldoc)
-(package! opencl-mode)
(package! modern-cpp-font-lock)
+(package! opencl-mode)
(when (featurep! :feature syntax-checker)
(package! flycheck-irony))
@@ -19,3 +19,8 @@
(package! company-irony)
(package! company-irony-c-headers))
+(package! rtags)
+(when (featurep! :completion ivy)
+ (package! ivy-rtags))
+(when (featurep! :completion helm)
+ (package! helm-rtags))
diff --git a/modules/lang/emacs-lisp/autoload.el b/modules/lang/emacs-lisp/autoload.el
index 50549485c..949a401fc 100644
--- a/modules/lang/emacs-lisp/autoload.el
+++ b/modules/lang/emacs-lisp/autoload.el
@@ -16,7 +16,7 @@
"Evaluate a region and print it to the echo area (if one line long), otherwise
to a pop up buffer."
(require 'pp)
- (let ((result (eval (read (buffer-substring-no-properties beg end))))
+ (let ((result (eval (read (concat "(progn " (buffer-substring-no-properties beg end) "\n)"))))
(buf (get-buffer-create "*doom eval*"))
(inhibit-read-only t)
lines)
diff --git a/modules/lang/java/+meghanada.el b/modules/lang/java/+meghanada.el
index 4b7fe91cf..70fc4d404 100644
--- a/modules/lang/java/+meghanada.el
+++ b/modules/lang/java/+meghanada.el
@@ -10,19 +10,12 @@
meghanada-use-eldoc t
meghanada-use-auto-start t)
- (add-hook 'java-mode-hook #'rainbow-delimiters-mode)
-
- ;; Setup on first use
- (unless (bound-and-true-p byte-compile-current-file)
- (meghanada-install-server)
- (if (file-exists-p (meghanada--locate-server-jar))
- (add-hook! 'meghanada-mode-hook #'(flycheck-mode eldoc-mode))
- (warn "java-mode: meghanada-server not installed, java-mode will run with reduced functionality")))
-
(set! :jump 'java-mode
:definition #'meghanada-jump-declaration
:references #'meghanada-reference)
+ (add-hook! 'meghanada-mode-hook #'(flycheck-mode eldoc-mode))
+
;;
(def-menu! +java/refactor-menu
"Refactoring commands for `java-mode' buffers."
diff --git a/modules/lang/java/config.el b/modules/lang/java/config.el
index e96aaee00..8194c7923 100644
--- a/modules/lang/java/config.el
+++ b/modules/lang/java/config.el
@@ -1,5 +1,7 @@
;;; lang/java/config.el -*- lexical-binding: t; -*-
+(add-hook 'java-mode-hook #'rainbow-delimiters-mode)
+
(cond ((featurep! +meghanada) (load! +meghanada))
((featurep! +eclim) ; FIXME lang/java +eclim
;;(load! +eclim)
diff --git a/modules/lang/org/+attach.el b/modules/lang/org/+attach.el
index 94988d99e..564bb02e8 100644
--- a/modules/lang/org/+attach.el
+++ b/modules/lang/org/+attach.el
@@ -15,7 +15,7 @@
;; + `+org-attach/url'
;; + :org [FILE/URL]
-(defvar +org-attach-dir (expand-file-name ".attach/" +org-dir)
+(defvar +org-attach-dir ".attach/"
"Where to store attachments (relative to current org file).")
@@ -30,7 +30,7 @@
(advice-add #'org-download-enable :override #'ignore)
:config
- (setq-default org-download-image-dir +org-attach-dir
+ (setq-default org-download-image-dir org-attach-directory
org-download-heading-lvl nil
org-download-timestamp "_%Y%m%d_%H%M%S")
@@ -61,12 +61,12 @@
;;
(after! org
- (setq org-attach-directory +org-attach-dir)
+ (setq org-attach-directory (expand-file-name +org-attach-dir +org-dir))
(push (car (last (split-string +org-attach-dir "/" t)))
projectile-globally-ignored-directories)
(after! recentf
- (push (format "%s.+$" (regexp-quote +org-attach-dir))
+ (push (format "%s.+$" (regexp-quote org-attach-directory))
recentf-exclude)))
diff --git a/modules/lang/org/+capture.el b/modules/lang/org/+capture.el
index b7c34a869..5debb99a4 100644
--- a/modules/lang/org/+capture.el
+++ b/modules/lang/org/+capture.el
@@ -10,16 +10,19 @@
;; anywhere I can call org-capture (whether or not Emacs is open/running),
;; like, say, from qutebrowser, vimperator, dmenu or a global keybinding.
+(defvar +org-default-todo-file "todo.org"
+ "TODO")
+
(defvar +org-default-notes-file "notes.org"
"TODO")
(defvar org-capture-templates
'(("t" "Todo" entry
- (file+headline (expand-file-name "todo.org" +org-dir) "Inbox")
+ (file+headline +org-default-todo-file "Inbox")
"* [ ] %?\n%i" :prepend t :kill-buffer t)
("n" "Notes" entry
- (file+headline org-default-notes-file "Inbox")
+ (file+headline +org-default-notes-file "Inbox")
"* %u %?\n%i" :prepend t :kill-buffer t)))
diff --git a/modules/lang/org/README.org b/modules/lang/org/README.org
index e69de29bb..ecda00c6c 100644
--- a/modules/lang/org/README.org
+++ b/modules/lang/org/README.org
@@ -0,0 +1,59 @@
+#+TITLE: :lang org
+
+This module provides support for org-mode.
+
++ A custom attachment system that keeps files in a centralized location.
++ Drag-and-drop support for images (with inline preview) and media files (drops
+ a file icon and a short link).
++ Executable code blocks with support for a variety of languages and tools,
+ including REST requests, SQL, google translate, plantuml, and matlab.
++ An org-capture workflow that works from outside Emacs (through the
+ =bin/org-capture= shell script).
++ Exported documents are saved to a centralized location.
++ A configuration for using org-mode for slide-show presentations, or exporting
+ org files to reveal.js slideshows.
++ (TODO) A static site generator based in org-mode and Emacs.
+
+#+begin_quote
+org-mode is a beast, and Doom's most difficult module to maintain. And its most
+important. This module is /highly/ opinionated and experimental; my foray into
+learning org is a neverending quest.
+#+end_quote
+
+* Table of Contents :TOC:
+- [[#install][Install]]
+ - [[#macos][MacOS]]
+ - [[#arch-linux][Arch Linux]]
+- [[#configuration][Configuration]]
+- [[#usage][Usage]]
+- [[#appendix][Appendix]]
+
+* Install
+Org has no hard dependencies, but there are some things you'll need to make use of Org's more esoteric features.
+
++ For inline LaTeX previews, you need ~latex~ and ~dvipng~.
++ To run babel code blocks, you need whatever dependencies those languages
+ need. It is recommended you enable the associated module in =lang/= and ensure
+ its dependencies are met.
++ The =+crm= module uses a sqlite database to manage your contacts, invoices,
+ and projects; this needs sqlite installed.
+
+** MacOS
+#+BEGIN_SRC sh
+brew cask install mactex
+brew install sqlite
+#+END_SRC
+
+** Arch Linux
+#+BEGIN_SRC sh
+sudo pacman --needed --noconfirm -S texlive-core texlive-bin texlive-science sqlite
+#+END_SRC
+
+* Configuration
+(Coming soon)
+
+* Usage
+(Coming soon)
+
+* Appendix
+(Coming soon)
diff --git a/modules/lang/org/autoload/org-attach.el b/modules/lang/org/autoload/org-attach.el
index 0cd9a7380..554549575 100644
--- a/modules/lang/org/autoload/org-attach.el
+++ b/modules/lang/org/autoload/org-attach.el
@@ -78,7 +78,7 @@ the cursor."
(defun +org-attach-download-dnd (uri action)
"TODO"
(if (eq major-mode 'org-mode)
- (+org-attach:url uri)
+ (+org-attach/uri uri)
(let ((dnd-protocol-alist
(rassq-delete-all '+org-attach-download-dnd
(copy-alist dnd-protocol-alist))))
@@ -98,7 +98,7 @@ the cursor."
(delete-region (match-beginning 0) (match-end 0))
(newline))
(cond ((image-type-from-file-name filename)
- (when (file-in-directory-p filename +org-attach-dir)
+ (when (file-in-directory-p filename org-attach-directory)
(setq filename (file-relative-name filename +org-dir)))
(insert
(concat (if (= org-download-image-html-width 0)
@@ -113,9 +113,9 @@ the cursor."
(t
(insert
(format "%s [[./%s][%s]] "
- (org-attach--icon filename)
+ (+org-attach--icon filename)
(file-relative-name filename buffer-file-name)
- (file-name-nondirectory (directory-file-name rel-path)))))))
+ (file-name-nondirectory (directory-file-name filename)))))))
;;;###autoload
(defun +org-attach*relative-to-attach-dir (orig-fn &rest args)
@@ -124,9 +124,7 @@ the cursor."
(let* ((context (save-match-data (org-element-context)))
(file (org-link-unescape (org-element-property :path context)))
(default-directory
- (if (string-prefix-p
- (concat "./" (car (last (split-string +org-attach-dir "/" t))))
- file)
+ (if (file-in-directory-p file org-attach-directory)
+org-dir
default-directory)))
(apply orig-fn args))
diff --git a/modules/lang/org/config.el b/modules/lang/org/config.el
index 182afcf31..1f0096f43 100644
--- a/modules/lang/org/config.el
+++ b/modules/lang/org/config.el
@@ -28,8 +28,7 @@
:commands org-crypt-use-before-save-magic
:config
(setq org-tags-exclude-from-inheritance '("crypt")
- org-crypt-key user-mail-address
- epa-file-encrypt-to user-mail-address))
+ org-crypt-key user-mail-address))
(def-package! org-bullets
:commands org-bullets-mode)
@@ -91,12 +90,13 @@ unfold to point on startup."
(sp--looking-at-p "\\s-*]")))
;; make delimiter auto-closing a little more conservative
- (sp-with-modes 'org-mode
- (sp-local-pair "*" nil :unless '(sp-point-after-word-p sp-point-before-word-p sp-point-at-bol-p))
- (sp-local-pair "_" nil :unless '(sp-point-after-word-p sp-point-before-word-p))
- (sp-local-pair "/" nil :unless '(sp-point-after-word-p sp-point-before-word-p +org-sp-point-in-checkbox-p))
- (sp-local-pair "~" nil :unless '(sp-point-after-word-p sp-point-before-word-p))
- (sp-local-pair "=" nil :unless '(sp-point-after-word-p sp-point-before-word-p))))
+ (after! smartparens
+ (sp-with-modes 'org-mode
+ (sp-local-pair "*" nil :unless '(sp-point-after-word-p sp-point-before-word-p sp-point-at-bol-p))
+ (sp-local-pair "_" nil :unless '(sp-point-after-word-p sp-point-before-word-p))
+ (sp-local-pair "/" nil :unless '(sp-point-after-word-p sp-point-before-word-p +org-sp-point-in-checkbox-p))
+ (sp-local-pair "~" nil :unless '(sp-point-after-word-p sp-point-before-word-p))
+ (sp-local-pair "=" nil :unless '(sp-point-after-word-p sp-point-before-word-p)))))
(defun +org|enable-auto-reformat-tables ()
"Realign tables exiting insert mode (`evil-mode')."
diff --git a/modules/lang/org/packages.el b/modules/lang/org/packages.el
index 84999f094..37f729a8f 100644
--- a/modules/lang/org/packages.el
+++ b/modules/lang/org/packages.el
@@ -1,11 +1,12 @@
;; -*- no-byte-compile: t; -*-
;;; lang/org/packages.el
-;; NOTE This is an insecure source, but unavoidable if we want org 9.0+ (which
-;; this module requires). orgmode.org offers no secure access to this repo. If
-;; this bothers you, comment out this `package!' block and download
-;; org-plus-contrib from orgmode.org.
-(package! org-plus-contrib :recipe (:fetcher git :url "http://orgmode.org/org-mode.git"))
+(when (version< emacs-version "26.1")
+ ;; We want org 9.1.x, but the org packaged with Emacs 25.x and under is 8.x.
+ ;; The only secure (and reasonably trustworthy) source for this is via
+ ;; emacsmirror. Emacs 26+ comes with Org 9.1.4.
+ (package! org-plus-contrib
+ :recipe (:fetcher github :repo "emacsmirror/org" :files (:defaults "contrib/lisp/*.el"))))
(package! org-bullets :recipe (:fetcher github :repo "hlissner/org-bullets"))
(package! toc-org)
diff --git a/modules/lang/org/test/autoload-org.el b/modules/lang/org/test/autoload-org.el
index 2402f9aac..567f1abcf 100644
--- a/modules/lang/org/test/autoload-org.el
+++ b/modules/lang/org/test/autoload-org.el
@@ -1,40 +1,40 @@
;; -*- no-byte-compile: t; -*-
;;; lang/org/test/autoload-org.el
-(defmacro should-org-buffer! (source expected &rest body)
- `(should-buffer! ,source ,expected
+(defmacro should-org-buffer!! (source expected &rest body)
+ `(should-buffer!! ,source ,expected
(org-mode)
,@body))
-
+;;
;; `+org/insert-item'
(def-test! insert-item-h1
"Should append/prepend new first-level headers with an extra newline."
- (should-org-buffer! ("* {0}Header") ("* Header\n\n* {|}")
+ (should-org-buffer!! ("* {0}Header") ("* Header\n\n* {|}")
(+org/insert-item 'below))
- (should-org-buffer! ("* {0}Header") ("* {|}\n\n* Header")
+ (should-org-buffer!! ("* {0}Header") ("* {|}\n\n* Header")
(+org/insert-item 'above)))
(def-test! insert-item-h2
"Should append/prepend new second-level (and higher) headers without an extra
newline."
- (should-org-buffer! ("** {0}Header") ("** Header\n** {|}")
+ (should-org-buffer!! ("** {0}Header") ("** Header\n** {|}")
(+org/insert-item 'below))
- (should-org-buffer! ("** {0}Header") ("** {|}\n** Header")
+ (should-org-buffer!! ("** {0}Header") ("** {|}\n** Header")
(+org/insert-item 'above)))
(def-test! insert-item-plain-list
"Should append/prepend new second-level (and higher) headers without an extra
newline."
- (should-org-buffer! ("+ {0}List item") ("+ List item\n+ {|}")
+ (should-org-buffer!! ("+ {0}List item") ("+ List item\n+ {|}")
(+org/insert-item 'below))
- (should-org-buffer! ("+ {0}List item"
+ (should-org-buffer!! ("+ {0}List item"
" + Sub item")
("+ List item"
" + Sub item"
"+ {|}")
(+org/insert-item 'below))
- (should-org-buffer! ("+ {0}List item"
+ (should-org-buffer!! ("+ {0}List item"
"+ Next item")
("+ List item"
"+ {|}"
diff --git a/modules/lang/org/test/org.el b/modules/lang/org/test/org.el
index e69f7a261..9b77e67db 100644
--- a/modules/lang/org/test/org.el
+++ b/modules/lang/org/test/org.el
@@ -5,3 +5,5 @@
(require! :lang org)
(require 'org (locate-library "org" nil doom--package-load-path))
+
+;;
diff --git a/modules/lang/php/config.el b/modules/lang/php/config.el
index 33b9d3373..3dfc1aa4e 100644
--- a/modules/lang/php/config.el
+++ b/modules/lang/php/config.el
@@ -84,8 +84,7 @@
:config
(unless (executable-find "phpctags")
(warn "php-mode: phpctags isn't installed, auto-completion will be gimped"))
-
- (setq ac-php-tags-path (concat doom-etc-dir "ac-php/")))
+ (setq ac-php-tags-path (concat doom-cache-dir "ac-php/")))
;;
diff --git a/modules/private/README.org b/modules/private/README.org
index 1046141fa..b9723dbc7 100644
--- a/modules/private/README.org
+++ b/modules/private/README.org
@@ -5,4 +5,4 @@ Use this directory to store your private configuration modules.
Mine is included as a reference. I recommend you neither delete nor rename it, to avoid merge conflicts upstream.
-----
-You'll find [[/wiki/Customization][more information about customizing Doom]] on the [[/wiki][wiki]].
+You'll find [[https://github.com/hlissner/doom-emacs/wiki/Customization][more information about customizing Doom]] on the [[https://github.com/hlissner/doom-emacs/wiki][wiki]].
diff --git a/modules/private/default/+bindings.el b/modules/private/default/+bindings.el
new file mode 100644
index 000000000..a525a5a1c
--- /dev/null
+++ b/modules/private/default/+bindings.el
@@ -0,0 +1,733 @@
+;;; private/default/+bindings.el -*- lexical-binding: t; -*-
+
+;; This files defines a Spacemacs-esque keybinding scheme
+
+(map! [remap evil-jump-to-tag] #'projectile-find-tag
+ [remap find-tag] #'projectile-find-tag
+
+ ;; Ensure there are no conflicts
+ :nmvo doom-leader-key nil
+ :nmvo doom-localleader-key nil
+
+ ;; --- Global keybindings ---------------------------
+ ;; Make M-x available everywhere
+ :gnvime "M-x" #'execute-extended-command
+ :gnvime "A-x" #'execute-extended-command
+
+ ;; A little sandbox to run code in
+ :gnvime "M-;" #'eval-expression
+ :gnvime "M-:" #'doom/open-scratch-buffer
+
+ ;; Text-scaling
+ "M-+" (λ! (text-scale-set 0))
+ "M-=" #'text-scale-increase
+ "M--" #'text-scale-decrease
+
+ ;; Simple window navigation/manipulation
+ "C-`" #'doom/popup-toggle
+ "C-~" #'doom/popup-raise
+ "M-t" #'+workspace/new
+ "M-T" #'+workspace/display
+ "M-w" #'delete-window
+ "M-W" #'+workspace/close-workspace-or-frame
+ "M-n" #'evil-buffer-new
+ "M-N" #'make-frame
+ "M-1" (λ! (+workspace/switch-to 0))
+ "M-2" (λ! (+workspace/switch-to 1))
+ "M-3" (λ! (+workspace/switch-to 2))
+ "M-4" (λ! (+workspace/switch-to 3))
+ "M-5" (λ! (+workspace/switch-to 4))
+ "M-6" (λ! (+workspace/switch-to 5))
+ "M-7" (λ! (+workspace/switch-to 6))
+ "M-8" (λ! (+workspace/switch-to 7))
+ "M-9" (λ! (+workspace/switch-to 8))
+ "M-0" #'+workspace/switch-to-last
+
+ ;; Other sensible, textmate-esque global bindings
+ :ne "M-r" #'+eval/buffer
+ :ne "M-R" #'+eval/region-and-replace
+ :ne "M-b" #'+eval/build
+ :ne "M-a" #'mark-whole-buffer
+ :ne "M-c" #'evil-yank
+ :ne "M-q" (if (daemonp) #'delete-frame #'save-buffers-kill-emacs)
+ :ne "M-f" #'swiper
+ :ne "C-M-f" #'doom/toggle-fullscreen
+ :n "M-s" #'save-buffer
+ :m "A-j" #'+default:multi-next-line
+ :m "A-k" #'+default:multi-previous-line
+ :nv "C-SPC" #'+evil:fold-toggle
+ :gnvimer "M-v" #'clipboard-yank
+ ;; Easier window navigation
+ :en "C-h" #'evil-window-left
+ :en "C-j" #'evil-window-down
+ :en "C-k" #'evil-window-up
+ :en "C-l" #'evil-window-right
+
+ "C-x p" #'doom/other-popup
+
+
+ ;; --- -------------------------------------
+ (:leader
+ :desc "Ex command" :nv ";" #'evil-ex
+ :desc "M-x" :nv ":" #'execute-extended-command
+ :desc "Pop up scratch buffer" :nv "x" #'doom/open-scratch-buffer
+ :desc "Org Capture" :nv "X" #'+org-capture/open
+
+ ;; Most commonly used
+ :desc "Find file in project" :n "SPC" #'projectile-find-file
+ :desc "Switch workspace buffer" :n "," #'persp-switch-to-buffer
+ :desc "Switch buffer" :n "<" #'switch-to-buffer
+ :desc "Browse files" :n "." #'find-file
+ :desc "Toggle last popup" :n "~" #'doom/popup-toggle
+ :desc "Eval expression" :n "`" #'eval-expression
+ :desc "Blink cursor line" :n "DEL" #'+doom/blink-cursor
+ :desc "Jump to bookmark" :n "RET" #'bookmark-jump
+
+ ;; C-u is used by evil
+ :desc "Universal argument" :n "u" #'universal-argument
+ :desc "window" :n "w" evil-window-map
+
+ (:desc "previous..." :prefix "["
+ :desc "Text size" :nv "[" #'text-scale-decrease
+ :desc "Buffer" :nv "b" #'doom/previous-buffer
+ :desc "Diff Hunk" :nv "d" #'git-gutter:previous-hunk
+ :desc "Todo" :nv "t" #'hl-todo-previous
+ :desc "Error" :nv "e" #'previous-error
+ :desc "Workspace" :nv "w" #'+workspace/switch-left
+ :desc "Smart jump" :nv "h" #'smart-backward
+ :desc "Spelling error" :nv "s" #'evil-prev-flyspell-error
+ :desc "Spelling correction" :n "S" #'flyspell-correct-previous-word-generic)
+
+ (:desc "next..." :prefix "]"
+ :desc "Text size" :nv "]" #'text-scale-increase
+ :desc "Buffer" :nv "b" #'doom/next-buffer
+ :desc "Diff Hunk" :nv "d" #'git-gutter:next-hunk
+ :desc "Todo" :nv "t" #'hl-todo-next
+ :desc "Error" :nv "e" #'next-error
+ :desc "Workspace" :nv "w" #'+workspace/switch-right
+ :desc "Smart jump" :nv "l" #'smart-forward
+ :desc "Spelling error" :nv "s" #'evil-next-flyspell-error
+ :desc "Spelling correction" :n "S" #'flyspell-correct-word-generic)
+
+ (:desc "search" :prefix "/"
+ :desc "Swiper" :nv "/" #'swiper
+ :desc "Imenu" :nv "i" #'imenu
+ :desc "Imenu across buffers" :nv "I" #'imenu-anywhere
+ :desc "Online providers" :nv "o" #'+jump/online-select)
+
+ (:desc "workspace" :prefix "TAB"
+ :desc "Display tab bar" :n "TAB" #'+workspace/display
+ :desc "New workspace" :n "n" #'+workspace/new
+ :desc "Load workspace from file" :n "l" #'+workspace/load
+ :desc "Load last session" :n "L" (λ! (+workspace/load-session))
+ :desc "Save workspace to file" :n "s" #'+workspace/save
+ :desc "Autosave current session" :n "S" #'+workspace/save-session
+ :desc "Switch workspace" :n "." #'+workspace/switch-to
+ :desc "Kill all buffers" :n "x" #'doom/kill-all-buffers
+ :desc "Delete session" :n "X" #'+workspace/kill-session
+ :desc "Delete this workspace" :n "d" #'+workspace/delete
+ :desc "Load session" :n "L" #'+workspace/load-session
+ :desc "Next workspace" :n "]" #'+workspace/switch-right
+ :desc "Previous workspace" :n "[" #'+workspace/switch-left
+ :desc "Switch to 1st workspace" :n "1" (λ! (+workspace/switch-to 0))
+ :desc "Switch to 2nd workspace" :n "2" (λ! (+workspace/switch-to 1))
+ :desc "Switch to 3rd workspace" :n "3" (λ! (+workspace/switch-to 2))
+ :desc "Switch to 4th workspace" :n "4" (λ! (+workspace/switch-to 3))
+ :desc "Switch to 5th workspace" :n "5" (λ! (+workspace/switch-to 4))
+ :desc "Switch to 6th workspace" :n "6" (λ! (+workspace/switch-to 5))
+ :desc "Switch to 7th workspace" :n "7" (λ! (+workspace/switch-to 6))
+ :desc "Switch to 8th workspace" :n "8" (λ! (+workspace/switch-to 7))
+ :desc "Switch to 9th workspace" :n "9" (λ! (+workspace/switch-to 8))
+ :desc "Switch to last workspace" :n "0" #'+workspace/switch-to-last)
+
+ (:desc "buffer" :prefix "b"
+ :desc "New empty buffer" :n "n" #'evil-buffer-new
+ :desc "Switch workspace buffer" :n "b" #'persp-switch-to-buffer
+ :desc "Switch buffer" :n "B" #'switch-to-buffer
+ :desc "Kill buffer" :n "k" #'doom/kill-this-buffer
+ :desc "Kill other buffers" :n "o" #'doom/kill-other-buffers
+ :desc "Save buffer" :n "s" #'save-buffer
+ :desc "Pop scratch buffer" :n "x" #'doom/open-scratch-buffer
+ :desc "Bury buffer" :n "z" #'bury-buffer
+ :desc "Next buffer" :n "]" #'doom/next-buffer
+ :desc "Previous buffer" :n "[" #'doom/previous-buffer
+ :desc "Sudo edit this file" :n "S" #'doom/sudo-this-file)
+
+ (:desc "code" :prefix "c"
+ :desc "List errors" :n "x" #'flycheck-list-errors
+ :desc "Evaluate buffer/region" :n "e" #'+eval/buffer
+ :v "e" #'+eval/region
+ :desc "Evaluate & replace region" :nv "E" #'+eval:replace-region
+ :desc "Build tasks" :nv "b" #'+eval/build
+ :desc "Jump to definition" :n "d" #'+jump/definition
+ :desc "Jump to references" :n "D" #'+jump/references
+ :desc "Open REPL" :n "r" #'+eval/open-repl
+ :v "r" #'+eval:repl)
+
+ (:desc "file" :prefix "f"
+ :desc "Find file" :n "." #'find-file
+ :desc "Sudo find file" :n ">" #'doom/sudo-find-file
+ :desc "Find file in project" :n "/" #'projectile-find-file
+ :desc "Find file from here" :n "?" #'counsel-file-jump
+ :desc "Find other file" :n "a" #'projectile-find-other-file
+ :desc "Open project editorconfig" :n "c" #'editorconfig-find-current-editorconfig
+ :desc "Find file in dotfiles" :n "d" #'+default/find-in-dotfiles
+ :desc "Browse dotfiles" :n "D" #'+default/browse-dotfiles
+ :desc "Find file in emacs.d" :n "e" #'+default/find-in-emacsd
+ :desc "Browse emacs.d" :n "E" #'+default/browse-emacsd
+ :desc "Recent files" :n "r" #'recentf-open-files
+ :desc "Recent project files" :n "R" #'projectile-recentf
+ :desc "Yank filename" :n "y" #'+default/yank-buffer-filename)
+
+ (:desc "git" :prefix "g"
+ :desc "Git status" :n "S" #'magit-status
+ :desc "Git blame" :n "b" #'magit-blame
+ :desc "Git time machine" :n "t" #'git-timemachine-toggle
+ :desc "Git stage hunk" :n "s" #'git-gutter:stage-hunk
+ :desc "Git revert hunk" :n "r" #'git-gutter:revert-hunk
+ :desc "Git revert buffer" :n "R" #'vc-revert
+ :desc "List gists" :n "g" #'+gist:list
+ :desc "Next hunk" :nv "]" #'git-gutter:next-hunk
+ :desc "Previous hunk" :nv "[" #'git-gutter:previous-hunk)
+
+ (:desc "help" :prefix "h"
+ :n "h" help-map
+ :desc "Apropos" :n "a" #'apropos
+ :desc "Reload theme" :n "R" #'doom//reload-theme
+ :desc "Find library" :n "l" #'find-library
+ :desc "Toggle Emacs log" :n "m" #'doom/popup-toggle-messages
+ :desc "Command log" :n "L" #'global-command-log-mode
+ :desc "Describe function" :n "f" #'describe-function
+ :desc "Describe key" :n "k" #'describe-key
+ :desc "Describe char" :n "c" #'describe-char
+ :desc "Describe mode" :n "M" #'describe-mode
+ :desc "Describe variable" :n "v" #'describe-variable
+ :desc "Describe face" :n "F" #'describe-face
+ :desc "Describe DOOM setting" :n "s" #'doom/describe-setting
+ :desc "Describe DOOM module" :n "d" #'doom/describe-module
+ :desc "Find definition" :n "." #'+jump/definition
+ :desc "Find references" :n "/" #'+jump/references
+ :desc "Find documentation" :n "h" #'+jump/documentation
+ :desc "What face" :n "'" #'doom/what-face
+ :desc "What minor modes" :n ";" #'doom/what-minor-mode
+ :desc "Info" :n "i" #'info
+ :desc "Toggle profiler" :n "p" #'doom/toggle-profiler)
+
+ (:desc "insert" :prefix "i"
+ :desc "From kill-ring" :nv "y" #'counsel-yank-pop
+ :desc "From snippet" :nv "s" #'yas-insert-snippet)
+
+ (:desc "notes" :prefix "n"
+ :desc "Find file in notes" :n "n" #'+default/find-in-notes
+ :desc "Browse notes" :n "N" #'+default/browse-notes
+ :desc "Org capture" :n "x" #'+org-capture/open
+ :desc "Browse mode notes" :n "m" #'+org/browse-notes-for-major-mode
+ :desc "Browse project notes" :n "p" #'+org/browse-notes-for-project)
+
+ (:desc "open" :prefix "o"
+ :desc "Default browser" :n "b" #'browse-url-of-file
+ :desc "Debugger" :n "d" #'+debug/open
+ :desc "REPL" :n "r" #'+eval/open-repl
+ :v "r" #'+eval:repl
+ :desc "Neotree" :n "n" #'+neotree/toggle
+ :desc "Terminal" :n "t" #'+term/open-popup
+ :desc "Terminal in project" :n "T" #'+term/open-popup-in-project
+
+ ;; applications
+ :desc "APP: elfeed" :n "E" #'=rss
+ :desc "APP: email" :n "M" #'=email
+ :desc "APP: twitter" :n "T" #'=twitter
+ :desc "APP: regex" :n "X" #'=regex
+
+ ;; macos
+ (:when IS-MAC
+ :desc "Reveal in Finder" :n "o" #'+macos/reveal-in-finder
+ :desc "Reveal project in Finder" :n "O" #'+macos/reveal-project-in-finder
+ :desc "Send to Transmit" :n "u" #'+macos/send-to-transmit
+ :desc "Send project to Transmit" :n "U" #'+macos/send-project-to-transmit
+ :desc "Send to Launchbar" :n "l" #'+macos/send-to-launchbar
+ :desc "Send project to Launchbar" :n "L" #'+macos/send-project-to-launchbar))
+
+ (:desc "project" :prefix "p"
+ :desc "Browse project" :n "." #'+default/browse-project
+ :desc "Find file in project" :n "/" #'projectile-find-file
+ :desc "Run cmd in project root" :nv "!" #'projectile-run-shell-command-in-root
+ :desc "Switch project" :n "p" #'projectile-switch-project
+ :desc "Recent project files" :n "r" #'projectile-recentf
+ :desc "List project tasks" :n "t" #'+ivy/tasks
+ :desc "Pop term in project" :n "o" #'+term/open-popup-in-project
+ :desc "Invalidate cache" :n "x" #'projectile-invalidate-cache)
+
+ (:desc "quit" :prefix "q"
+ :desc "Quit" :n "q" #'evil-save-and-quit
+ :desc "Quit (forget session)" :n "Q" #'+workspace/kill-session-and-quit)
+
+ (:desc "remote" :prefix "r"
+ :desc "Upload local" :n "u" #'+upload/local
+ :desc "Upload local (force)" :n "U" (λ! (+upload/local t))
+ :desc "Download remote" :n "d" #'+upload/remote-download
+ :desc "Diff local & remote" :n "D" #'+upload/diff
+ :desc "Browse remote files" :n "." #'+upload/browse
+ :desc "Detect remote changes" :n ">" #'+upload/check-remote)
+
+ (:desc "snippets" :prefix "s"
+ :desc "New snippet" :n "n" #'yas-new-snippet
+ :desc "Insert snippet" :nv "i" #'yas-insert-snippet
+ :desc "Find snippet for mode" :n "s" #'yas-visit-snippet-file
+ :desc "Find snippet" :n "S" #'+default/find-in-snippets)
+
+ (:desc "toggle" :prefix "t"
+ :desc "Flyspell" :n "s" #'flyspell-mode
+ :desc "Flycheck" :n "f" #'flycheck-mode
+ :desc "Line numbers" :n "l" #'doom/toggle-line-numbers
+ :desc "Fullscreen" :n "f" #'doom/toggle-fullscreen
+ :desc "Indent guides" :n "i" #'highlight-indentation-mode
+ :desc "Indent guides (column)" :n "I" #'highlight-indentation-current-column-mode
+ :desc "Impatient mode" :n "h" #'+impatient-mode/toggle
+ :desc "Big mode" :n "b" #'doom-big-font-mode
+ :desc "Evil goggles" :n "g" #'+evil-goggles/toggle))
+
+
+ ;; --- Personal vim-esque bindings ------------------
+ :n "zx" #'doom/kill-this-buffer
+ :n "ZX" #'bury-buffer
+ :n "]b" #'doom/next-buffer
+ :n "[b" #'doom/previous-buffer
+ :n "]w" #'+workspace/switch-right
+ :n "[w" #'+workspace/switch-left
+ :m "gt" #'+workspace/switch-right
+ :m "gT" #'+workspace/switch-left
+ :m "gd" #'+jump/definition
+ :m "gD" #'+jump/references
+ :m "gh" #'+jump/documentation
+ :n "gp" #'+evil/reselect-paste
+ :n "gr" #'+eval:region
+ :n "gR" #'+eval/buffer
+ :v "gR" #'+eval:replace-region
+ :v "@" #'+evil:macro-on-all-lines
+ :n "g@" #'+evil:macro-on-all-lines
+ ;; repeat in visual mode (FIXME buggy)
+ :v "." #'evil-repeat
+ ;; don't leave visual mode after shifting
+ :v "<" #'+evil/visual-dedent ; vnoremap < " #'+evil/visual-indent ; vnoremap > >gv
+ ;; paste from recent yank register (which isn't overwritten)
+ :v "C-p" "\"0p"
+
+ (:map evil-window-map ; prefix "C-w"
+ ;; Navigation
+ "C-h" #'evil-window-left
+ "C-j" #'evil-window-down
+ "C-k" #'evil-window-up
+ "C-l" #'evil-window-right
+ "C-w" #'ace-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
+ ;; Delete window
+ "c" #'+workspace/close-window-or-workspace
+ "C-C" #'ace-delete-window)
+
+
+ ;; --- Plugin bindings ------------------------------
+ ;; auto-yasnippet
+ :i [C-tab] #'aya-expand
+ :nv [C-tab] #'aya-create
+
+ ;; company-mode (vim-like omnicompletion)
+ :i "C-SPC" #'+company/complete
+ (:prefix "C-x"
+ :i "C-l" #'+company/whole-lines
+ :i "C-k" #'+company/dict-or-keywords
+ :i "C-f" #'company-files
+ :i "C-]" #'company-etags
+ :i "s" #'company-ispell
+ :i "C-s" #'company-yasnippet
+ :i "C-o" #'company-capf
+ :i "C-n" #'company-dabbrev-code
+ :i "C-p" #'+company/dabbrev-code-previous)
+ (:after company
+ (:map company-active-map
+ ;; Don't interfere with `evil-delete-backward-word' in insert mode
+ "C-w" nil
+ "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-s" #'company-search-candidates
+ "C-s" #'company-filter-candidates
+ "C-SPC" #'company-complete-common
+ "C-h" #'company-quickhelp-manual-begin
+ [tab] #'company-complete-common-or-cycle
+ [backtab] #'company-select-previous
+ [escape] (λ! (company-abort) (evil-normal-state 1)))
+ ;; Automatically applies to `company-filter-map'
+ (:map company-search-map
+ "C-n" #'company-search-repeat-forward
+ "C-p" #'company-search-repeat-backward
+ "C-s" (λ! (company-search-abort) (company-filter-candidates))
+ [escape] #'company-search-abort))
+
+ ;; counsel
+ (: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)))
+
+ ;; evil-commentary
+ :n "gc" #'evil-commentary
+
+ ;; evil-exchange
+ :n "gx" #'evil-exchange
+
+ ;; evil-matchit
+ :nv [tab] #'+evil/matchit-or-toggle-fold
+
+ ;; evil-magit
+ (:after evil-magit
+ :map (magit-status-mode-map magit-revision-mode-map)
+ :n "C-j" nil
+ :n "C-k" nil)
+
+ ;; evil-mc
+ (:prefix "gz"
+ :nv "m" #'evil-mc-make-all-cursors
+ :nv "u" #'evil-mc-undo-all-cursors
+ :nv "z" #'+evil/mc-make-cursor-here
+ :nv "t" #'+evil/mc-toggle-cursors
+ :nv "n" #'evil-mc-make-and-goto-next-cursor
+ :nv "p" #'evil-mc-make-and-goto-prev-cursor
+ :nv "N" #'evil-mc-make-and-goto-last-cursor
+ :nv "P" #'evil-mc-make-and-goto-first-cursor
+ :nv "d" #'evil-mc-make-and-goto-next-match
+ :nv "D" #'evil-mc-make-and-goto-prev-match)
+ (:after evil-mc
+ :map evil-mc-key-map
+ :nv "C-n" #'evil-mc-make-and-goto-next-cursor
+ :nv "C-N" #'evil-mc-make-and-goto-last-cursor
+ :nv "C-p" #'evil-mc-make-and-goto-prev-cursor
+ :nv "C-P" #'evil-mc-make-and-goto-first-cursor)
+
+ ;; evil-multiedit
+ :v "R" #'evil-multiedit-match-all
+ :n "M-d" #'evil-multiedit-match-symbol-and-next
+ :n "M-D" #'evil-multiedit-match-symbol-and-prev
+ :v "M-d" #'evil-multiedit-match-and-next
+ :v "M-D" #'evil-multiedit-match-and-prev
+ :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)
+ (:map (evil-multiedit-state-map evil-multiedit-insert-state-map)
+ "C-n" #'evil-multiedit-next
+ "C-p" #'evil-multiedit-prev))
+
+ ;; evil-snipe
+ (:after evil-snipe
+ (:after evil-easymotion
+ ;; Binding to switch to evil-easymotion/avy after a 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
+
+ ;; expand-region
+ :v "v" #'er/expand-region
+ :v "V" #'er/contract-region
+
+ ;; flycheck
+ :m "]e" #'next-error
+ :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)
+
+ ;; flyspell
+ :m "]S" #'flyspell-correct-word-generic
+ :m "[S" #'flyspell-correct-previous-word-generic
+
+ ;; git-gutter
+ :m "]d" #'git-gutter:next-hunk
+ :m "[d" #'git-gutter:previous-hunk
+
+ ;; git-timemachine
+ (:after git-timemachine
+ (:map git-timemachine-mode-map
+ :n "C-p" #'git-timemachine-show-previous-revision
+ :n "C-n" #'git-timemachine-show-next-revision
+ :n "[[" #'git-timemachine-show-previous-revision
+ :n "]]" #'git-timemachine-show-next-revision
+ :n "q" #'git-timemachine-quit
+ :n "gb" #'git-timemachine-blame))
+
+ ;; gist
+ (:after gist
+ :map gist-list-menu-mode-map
+ :n "RET" #'+gist/open-current
+ :n "b" #'gist-browse-current-url
+ :n "c" #'gist-add-buffer
+ :n "d" #'gist-kill-current
+ :n "f" #'gist-fork
+ :n "q" #'quit-window
+ :n "r" #'gist-list-reload
+ :n "s" #'gist-star
+ :n "S" #'gist-unstar
+ :n "y" #'gist-print-current-url)
+
+ ;; helm
+ (:after helm
+ (:map helm-map
+ "ESC" nil
+ "C-S-n" #'helm-next-source
+ "C-S-p" #'helm-previous-source
+ "C-u" #'helm-delete-minibuffer-contents
+ "C-w" #'backward-kill-word
+ "C-r" #'evil-paste-from-register ; Evil registers in helm! Glorious!
+ "C-b" #'backward-word
+ [left] #'backward-char
+ [right] #'forward-char
+ [escape] #'helm-keyboard-quit
+ [tab] #'helm-execute-persistent-action)
+
+ (:after helm-files
+ (:map helm-generic-files-map
+ :e "ESC" #'helm-keyboard-quit)
+ (:map helm-find-files-map
+ "C-w" #'helm-find-files-up-one-level
+ "TAB" #'helm-execute-persistent-action))
+
+ (:after helm-ag
+ (:map helm-ag-map
+ "" #'helm-ag-edit)))
+
+ ;; hl-todo
+ :m "]t" #'hl-todo-next
+ :m "[t" #'hl-todo-previous
+
+ ;; ivy
+ (:after ivy
+ :map ivy-minibuffer-map
+ [escape] #'keyboard-escape-quit
+ "C-SPC" #'ivy-call-and-recenter
+ "M-v" #'yank
+ "M-z" #'undo
+ "C-r" #'evil-paste-from-register
+ "C-k" #'ivy-previous-line
+ "C-j" #'ivy-next-line
+ "C-l" #'ivy-alt-done
+ "C-w" #'ivy-backward-kill-word
+ "C-u" #'ivy-kill-line
+ "C-b" #'backward-word
+ "C-f" #'forward-word)
+
+ ;; neotree
+ (:after neotree
+ :map neotree-mode-map
+ :n "g" nil
+ :n [tab] #'neotree-quick-look
+ :n "RET" #'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)
+
+ ;; realgud
+ (:after realgud
+ :map realgud:shortkey-mode-map
+ :n "j" #'evil-next-line
+ :n "k" #'evil-previous-line
+ :n "h" #'evil-backward-char
+ :n "l" #'evil-forward-char
+ :m "n" #'realgud:cmd-next
+ :m "b" #'realgud:cmd-break
+ :m "B" #'realgud:cmd-clear
+ :n "c" #'realgud:cmd-continue)
+
+ ;; rotate-text
+ :n "!" #'rotate-text
+
+ ;; smart-forward
+ :nv "K" #'smart-up
+ :m "g]" #'smart-forward
+ :m "g[" #'smart-backward
+
+ ;; undo-tree -- undo/redo for visual regions
+ :v "C-u" #'undo-tree-undo
+ :v "C-r" #'undo-tree-redo
+
+ ;; yasnippet
+ (:after yasnippet
+ (:map yas-keymap
+ "C-e" #'+snippets/goto-end-of-field
+ "C-a" #'+snippets/goto-start-of-field
+ "" #'+snippets/goto-end-of-field
+ "" #'+snippets/goto-start-of-field
+ "" #'+snippets/delete-to-start-of-field
+ [escape] #'evil-normal-state
+ [backspace] #'+snippets/delete-backward-char
+ [delete] #'+snippets/delete-forward-char-or-field)
+ (:map yas-minor-mode-map
+ :i "" yas-maybe-expand
+ :v "" #'+snippets/expand-on-region))
+
+
+ ;; --- Major mode bindings --------------------------
+ (:after markdown-mode
+ (:map markdown-mode-map
+ ;; fix conflicts with private bindings
+ "" nil
+ "" nil
+ "" nil))
+
+
+ ;; --- Custom evil text-objects ---------------------
+ :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 "I" #'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
+
+
+ ;; --- Built-in plugins -----------------------------
+ (:after comint
+ ;; TAB auto-completion in term buffers
+ :map comint-mode-map [tab] #'company-complete)
+
+ (:after debug
+ ;; For elisp debugging
+ :map debugger-mode-map
+ :n "RET" #'debug-help-follow
+ :n "e" #'debugger-eval-expression
+ :n "n" #'debugger-step-through
+ :n "c" #'debugger-continue)
+
+ (:map help-mode-map
+ :n "[[" #'help-go-back
+ :n "]]" #'help-go-forward
+ :n "o" #'ace-link-help
+ :n "q" #'quit-window
+ :n "Q" #'+ivy-quit-and-resume)
+
+ (:after vc-annotate
+ :map vc-annotate-mode-map
+ :n "q" #'kill-this-buffer
+ :n "d" #'vc-annotate-show-diff-revision-at-line
+ :n "D" #'vc-annotate-show-changeset-diff-revision-at-line
+ :n "SPC" #'vc-annotate-show-log-revision-at-line
+ :n "]]" #'vc-annotate-next-revision
+ :n "[[" #'vc-annotate-prev-revision
+ :n "TAB" #'vc-annotate-toggle-annotation-visibility
+ :n "RET" #'vc-annotate-find-revision-at-line))
+
+
+;;
+;; Keybinding fixes
+;;
+
+;; This section is dedicated to "fixing" certain keys so that they behave
+;; properly, more like vim, or how I like it.
+
+(map! (:map input-decode-map
+ [S-iso-lefttab] [backtab]
+ (:unless window-system "TAB" [tab])) ; Fix TAB in terminal
+
+ ;; I want C-a and C-e to be a little smarter. 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 and trailing whitespace before
+ ;; jumping to eol.
+ :i "C-a" #'doom/backward-to-bol-or-indent
+ :i "C-e" #'doom/forward-to-last-non-comment-or-eol
+ :i "C-u" #'doom/backward-kill-to-bol-and-indent
+
+ ;; textmate-esque newline insertion
+ :i [M-return] #'evil-open-below
+ :i [S-M-return] #'evil-open-above
+ ;; textmate-esque deletion
+ [M-backspace] #'doom/backward-kill-to-bol-and-indent
+ :i [backspace] #'delete-backward-char
+ :i [M-backspace] #'doom/backward-kill-to-bol-and-indent
+ ;; Emacsien motions for insert mode
+ :i "C-b" #'backward-word
+ :i "C-f" #'forward-word
+
+ ;; Highjacks space/backspace to:
+ ;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
+ ;; b) delete space-indented blocks intelligently
+ ;; c) do none of this when inside a string
+ :i "SPC" #'doom/inflate-space-maybe
+ :i [remap delete-backward-char] #'doom/deflate-space-maybe
+ :i [remap newline] #'doom/newline-and-indent
+
+ (:after org
+ (:map org-mode-map
+ :i [remap doom/inflate-space-maybe] #'org-self-insert-command
+ :i "C-e" #'org-end-of-line
+ :i "C-a" #'org-beginning-of-line))
+
+ ;; Restore common editing keys (and ESC) in minibuffer
+ (:map (minibuffer-local-map
+ minibuffer-local-ns-map
+ minibuffer-local-completion-map
+ minibuffer-local-must-match-map
+ minibuffer-local-isearch-map
+ evil-ex-completion-map
+ evil-ex-search-keymap
+ read-expression-map)
+ [escape] #'abort-recursive-edit
+ "C-r" #'evil-paste-from-register
+ "C-a" #'move-beginning-of-line
+ "C-w" #'doom/minibuffer-kill-word
+ "C-u" #'doom/minibuffer-kill-line
+ "C-b" #'backward-word
+ "C-f" #'forward-word
+ "M-z" #'doom/minibuffer-undo)
+
+ (:map messages-buffer-mode-map
+ "M-;" #'eval-expression
+ "A-;" #'eval-expression)
+
+ (:map tabulated-list-mode-map
+ [remap evil-record-macro] #'doom/popup-close-maybe)
+
+ (:after view
+ (:map view-mode-map "" #'View-quit-all)))
diff --git a/modules/private/hlissner/+commands.el b/modules/private/default/+evil-commands.el
similarity index 91%
rename from modules/private/hlissner/+commands.el
rename to modules/private/default/+evil-commands.el
index 260a4d761..306ea8834 100644
--- a/modules/private/hlissner/+commands.el
+++ b/modules/private/default/+evil-commands.el
@@ -1,12 +1,12 @@
-;;; private/hlissner/+commands.el -*- lexical-binding: t; -*-
+;;; private/default/+evil-commands.el -*- lexical-binding: t; -*-
(defalias 'ex! 'evil-ex-define-cmd)
-;;; Commands defined elsewhere
+ ;;; Commands defined elsewhere
;;(ex! "al[ign]" #'+evil:align)
;;(ex! "g[lobal]" #'+evil:global)
-;;; Custom commands
+ ;;; Custom commands
;; Editing
(ex! "@" #'+evil:macro-on-all-lines) ; TODO Test me
(ex! "al[ign]" #'+evil:align)
@@ -16,7 +16,6 @@
(ex! "iedit" #'evil-multiedit-ex-match)
(ex! "na[rrow]" #'+evil:narrow-buffer)
(ex! "retab" #'+evil:retab)
-
;; External resources
;; TODO (ex! "db" #'doom:db)
;; TODO (ex! "dbu[se]" #'doom:db-select)
@@ -29,7 +28,6 @@
(ex! "t[mux]" #'+tmux:run) ; send to tmux
(ex! "tcd" #'+tmux:cd-here) ; cd to default-directory in tmux
(ex! "x" #'doom/open-project-scratch-buffer)
-
;; GIT
(ex! "gist" #'+gist:send) ; send current buffer/region to gist
(ex! "gistl" #'+gist:list) ; list gists by user
@@ -40,20 +38,18 @@
(ex! "gunstage" #'magit-unstage)
(ex! "gblame" #'magit-blame)
(ex! "grevert" #'git-gutter:revert-hunk)
-
;; Dealing with buffers
-(ex! "clean[up]" #'doom/cleanup-buffers)
+(ex! "clean[up]" #'doom/cleanup-session)
(ex! "k[ill]" #'doom/kill-this-buffer)
-(ex! "k[ill]all" #'+hlissner:kill-all-buffers)
-(ex! "k[ill]m" #'+hlissner:kill-matching-buffers)
+(ex! "k[ill]all" #'+default:kill-all-buffers)
+(ex! "k[ill]m" #'+default:kill-matching-buffers)
(ex! "k[ill]o" #'doom/kill-other-buffers)
(ex! "l[ast]" #'doom/popup-restore)
(ex! "m[sg]" #'view-echo-area-messages)
(ex! "pop[up]" #'doom/popup-this-buffer)
-
;; Project navigation
(ex! "a" #'projectile-find-other-file)
-(ex! "cd" #'+hlissner:cd)
+(ex! "cd" #'+default:cd)
(cond ((featurep! :completion ivy)
(ex! "ag" #'+ivy:ag)
(ex! "agc[wd]" #'+ivy:ag-cwd)
@@ -68,17 +64,14 @@
(ex! "rgc[wd]" #'+helm:rg-cwd)
(ex! "sw[oop]" #'+helm:swoop)
(ex! "todo" #'+helm:todo)))
-
;; Project tools
(ex! "build" #'+eval/build)
(ex! "debug" #'+debug/run)
(ex! "er[rors]" #'flycheck-list-errors)
-
;; File operations
(ex! "cp" #'+evil:copy-this-file)
(ex! "mv" #'+evil:move-this-file)
(ex! "rm" #'+evil:delete-this-file)
-
;; Sessions/tabs
(ex! "sclear" #'+workspace/kill-session)
(ex! "sl[oad]" #'+workspace:load-session)
@@ -93,6 +86,6 @@
(ex! "tabr[ename]" #'+workspace:rename)
(ex! "tabs" #'+workspace/display)
(ex! "tabsave" #'+workspace:save)
-
;; Org-mode
(ex! "cap" #'+org-capture/dwim)
+
diff --git a/modules/private/default/autoload/default.el b/modules/private/default/autoload/default.el
new file mode 100644
index 000000000..4381c044b
--- /dev/null
+++ b/modules/private/default/autoload/default.el
@@ -0,0 +1,47 @@
+;; private/default/autoload/default.el -*- lexical-binding: t; -*-
+
+;;;###autoload
+(defun +default/yank-buffer-filename ()
+ "Copy the current buffer's path to the kill ring."
+ (interactive)
+ (if-let* ((filename (or buffer-file-name (bound-and-true-p list-buffers-directory))))
+ (message (kill-new (abbreviate-file-name filename)))
+ (error "Couldn't find filename in current buffer")))
+
+;;;###autoload
+(defmacro +default--def-browse-in! (name dir)
+ (let ((prefix (cdr (doom-module-from-path (or load-file-name byte-compile-current-file)))))
+ `(defun ,(intern (format "%s/browse-%s" prefix name)) ()
+ (interactive)
+ (doom-project-browse ,dir))))
+
+;;;###autoload
+(defmacro +default--def-find-in! (name dir)
+ (let ((prefix (cdr (doom-module-from-path (or load-file-name byte-compile-current-file)))))
+ `(defun ,(intern (format "+%s/find-in-%s" prefix name)) ()
+ (interactive)
+ (doom-project-find-file ,dir))))
+
+
+;;;###autoload (autoload '+default/browse-project "private/default/autoload/default" nil t)
+(+default--def-browse-in! project (doom-project-root))
+
+;;;###autoload (autoload '+default/find-in-templates "private/default/autoload/default" nil t)
+(+default--def-find-in! templates +file-templates-dir)
+;;;###autoload (autoload '+default/browse-templates "private/default/autoload/default" nil t)
+(+default--def-browse-in! templates +file-templates-dir)
+
+;;;###autoload (autoload '+default/find-in-emacsd "private/default/autoload/default" nil t)
+(+default--def-find-in! emacsd doom-emacs-dir)
+;;;###autoload (autoload '+default/browse-emacsd "private/default/autoload/default" nil t)
+(+default--def-browse-in! emacsd doom-emacs-dir)
+
+;;;###autoload (autoload '+default/find-in-notes "private/default/autoload/default" nil t)
+(+default--def-find-in! notes +org-dir)
+;;;###autoload (autoload '+default/browse-notes "private/default/autoload/default" nil t)
+(+default--def-browse-in! notes +org-dir)
+
+;;;###autoload (autoload '+default/find-in-snippets "private/default/autoload/default" nil t)
+(+default--def-find-in! snippets +default-snippets-dir)
+;; NOTE No need for a browse-snippets variant, use `yas-visit-snippet-file'
+
diff --git a/modules/private/default/autoload/evil.el b/modules/private/default/autoload/evil.el
new file mode 100644
index 000000000..01a37f28c
--- /dev/null
+++ b/modules/private/default/autoload/evil.el
@@ -0,0 +1,38 @@
+;; private/default/autoload/evil.el -*- lexical-binding: t; -*-
+;;;###if (featurep! :feature evil)
+
+;;;###autoload (autoload '+default:multi-next-line "private/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))))
+ (evil-line-move (* 6 (or count 1)))))
+
+;;;###autoload (autoload '+default:multi-previous-line "private/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))))
+ (evil-line-move (- (* 6 (or count 1))))))
+
+;;;###autoload (autoload '+default:cd "private/default/autoload/evil" nil t)
+(evil-define-command +default:cd ()
+ "Change `default-directory' with `cd'."
+ (interactive "")
+ (cd input))
+
+;;;###autoload (autoload '+default:kill-all-buffers "private/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 "private/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 "")
+ (doom/kill-matching-buffers pattern bang))
+
diff --git a/modules/private/default/config.el b/modules/private/default/config.el
new file mode 100644
index 000000000..4379a6955
--- /dev/null
+++ b/modules/private/default/config.el
@@ -0,0 +1,80 @@
+;;; private/default/config.el -*- lexical-binding: t; -*-
+
+(load! +bindings)
+
+
+;;
+;; Plugins
+;;
+
+(def-package! emacs-snippets :after yasnippet)
+
+
+;;
+;; Config
+;;
+
+(after! epa
+ (setq epa-file-encrypt-to (or epa-file-encrypt-to user-mail-address)
+ ;; With GPG 2.1, this forces gpg-agent to use the Emacs minibuffer to
+ ;; prompt for the key passphrase.
+ epa-pinentry-mode 'loopback))
+
+
+(when (featurep 'evil)
+ (load! +evil-commands)
+
+ ;; Makes ; and , the universal repeat-keys in evil-mode
+ (defmacro do-repeat! (command next-func prev-func)
+ "Repeat motions with ;/,"
+ (let ((fn-sym (intern (format "+evil*repeat-%s" command))))
+ `(progn
+ (defun ,fn-sym (&rest _)
+ (define-key evil-motion-state-map (kbd ";") ',next-func)
+ (define-key evil-motion-state-map (kbd ",") ',prev-func))
+ (advice-add #',command :before #',fn-sym))))
+
+ ;; n/N
+ (do-repeat! evil-ex-search-next evil-ex-search-next evil-ex-search-previous)
+ (do-repeat! evil-ex-search-previous evil-ex-search-next evil-ex-search-previous)
+ (do-repeat! evil-ex-search-forward evil-ex-search-next evil-ex-search-previous)
+ (do-repeat! evil-ex-search-backward evil-ex-search-next evil-ex-search-previous)
+
+ ;; f/F/t/T/s/S
+ (after! evil-snipe
+ (setq evil-snipe-repeat-keys nil
+ evil-snipe-override-evil-repeat-keys nil) ; causes problems with remapped ;
+
+ (do-repeat! evil-snipe-f evil-snipe-repeat evil-snipe-repeat-reverse)
+ (do-repeat! evil-snipe-F evil-snipe-repeat evil-snipe-repeat-reverse)
+ (do-repeat! evil-snipe-t evil-snipe-repeat evil-snipe-repeat-reverse)
+ (do-repeat! evil-snipe-T evil-snipe-repeat evil-snipe-repeat-reverse)
+ (do-repeat! evil-snipe-s evil-snipe-repeat evil-snipe-repeat-reverse)
+ (do-repeat! evil-snipe-S evil-snipe-repeat evil-snipe-repeat-reverse)
+ (do-repeat! evil-snipe-x evil-snipe-repeat evil-snipe-repeat-reverse)
+ (do-repeat! evil-snipe-X evil-snipe-repeat evil-snipe-repeat-reverse))
+
+ ;; */#
+ (after! evil-visualstar
+ (do-repeat! evil-visualstar/begin-search-forward
+ evil-ex-search-next evil-ex-search-previous)
+ (do-repeat! evil-visualstar/begin-search-backward
+ evil-ex-search-previous evil-ex-search-next))
+
+ (after! evil-easymotion
+ (let ((prefix (concat doom-leader-key " /")))
+ ;; NOTE `evilem-default-keybinds' unsets all other keys on the prefix (in
+ ;; motion state)
+ (evilem-default-keybindings prefix)
+ (evilem-define (kbd (concat prefix " n")) #'evil-ex-search-next)
+ (evilem-define (kbd (concat prefix " N")) #'evil-ex-search-previous)
+ (evilem-define (kbd (concat prefix " s")) #'evil-snipe-repeat
+ :pre-hook (save-excursion (call-interactively #'evil-snipe-s))
+ :bind ((evil-snipe-scope 'buffer)
+ (evil-snipe-enable-highlight)
+ (evil-snipe-enable-incremental-highlight)))
+ (evilem-define (kbd (concat prefix " S")) #'evil-snipe-repeat-reverse
+ :pre-hook (save-excursion (call-interactively #'evil-snipe-s))
+ :bind ((evil-snipe-scope 'buffer)
+ (evil-snipe-enable-highlight)
+ (evil-snipe-enable-incremental-highlight))))))
diff --git a/modules/private/default/packages.el b/modules/private/default/packages.el
new file mode 100644
index 000000000..08571bf1e
--- /dev/null
+++ b/modules/private/default/packages.el
@@ -0,0 +1,7 @@
+;; -*- no-byte-compile: t; -*-
+;;; private/default/packages.el
+
+(package! emacs-snippets
+ :recipe (:fetcher github
+ :repo "hlissner/emacs-snippets"
+ :files ("*")))
diff --git a/modules/private/hlissner/+bindings.el b/modules/private/hlissner/+bindings.el
deleted file mode 100644
index 7ad4807d2..000000000
--- a/modules/private/hlissner/+bindings.el
+++ /dev/null
@@ -1,795 +0,0 @@
-;;; private/hlissner/+bindings.el -*- lexical-binding: t; -*-
-
-(defmacro find-file-in! (path &optional project-p)
- "Returns an interactive function for searching files."
- `(lambda () (interactive)
- (let ((default-directory ,path))
- (call-interactively
- ',(command-remapping
- (if project-p
- #'projectile-find-file
- #'find-file))))))
-
-(map!
- [remap evil-jump-to-tag] #'projectile-find-tag
- [remap find-tag] #'projectile-find-tag
- ;; ensure there are no conflicts
- :nmvo doom-leader-key nil
- :nmvo doom-localleader-key nil)
-
-(map!
- ;; --- Global keybindings ---------------------------
- ;; Make M-x available everywhere
- :gnvime "M-x" #'execute-extended-command
- :gnvime "A-x" #'execute-extended-command
- ;; Emacs debug utilities
- :gnvime "M-;" #'eval-expression
- :gnvime "M-:" #'doom/open-scratch-buffer
- ;; Text-scaling
- "M-+" (λ! (text-scale-set 0))
- "M-=" #'text-scale-increase
- "M--" #'text-scale-decrease
- ;; Simple window navigation/manipulation
- "C-`" #'doom/popup-toggle
- "C-~" #'doom/popup-raise
- "M-t" #'+workspace/new
- "M-T" #'+workspace/display
- "M-w" #'delete-window
- "M-W" #'+workspace/close-workspace-or-frame
- "M-n" #'evil-buffer-new
- "M-N" #'make-frame
- "M-1" (λ! (+workspace/switch-to 0))
- "M-2" (λ! (+workspace/switch-to 1))
- "M-3" (λ! (+workspace/switch-to 2))
- "M-4" (λ! (+workspace/switch-to 3))
- "M-5" (λ! (+workspace/switch-to 4))
- "M-6" (λ! (+workspace/switch-to 5))
- "M-7" (λ! (+workspace/switch-to 6))
- "M-8" (λ! (+workspace/switch-to 7))
- "M-9" (λ! (+workspace/switch-to 8))
- "M-0" #'+workspace/switch-to-last
- ;; Other sensible, textmate-esque global bindings
- :ne "M-r" #'+eval/buffer
- :ne "M-R" #'+eval/region-and-replace
- :ne "M-b" #'+eval/build
- :ne "M-a" #'mark-whole-buffer
- :ne "M-c" #'evil-yank
- :ne "M-q" (if (daemonp) #'delete-frame #'save-buffers-kill-emacs)
- :ne "M-f" #'swiper
- :ne "C-M-f" #'doom/toggle-fullscreen
- :n "M-s" #'save-buffer
- :m "A-j" #'+hlissner:multi-next-line
- :m "A-k" #'+hlissner:multi-previous-line
- :nv "C-SPC" #'+evil:fold-toggle
- :gnvimer "M-v" #'clipboard-yank
- ;; Easier window navigation
- :en "C-h" #'evil-window-left
- :en "C-j" #'evil-window-down
- :en "C-k" #'evil-window-up
- :en "C-l" #'evil-window-right
-
- "C-x p" #'doom/other-popup
-
-
- ;; --- -------------------------------------
- (:leader
- :desc "Ex command" :nv ";" #'evil-ex
- :desc "M-x" :nv ":" #'execute-extended-command
- :desc "Pop up scratch buffer" :nv "x" #'doom/open-scratch-buffer
- :desc "Org Capture" :nv "X" #'+org-capture/open
-
- ;; Most commonly used
- :desc "Find file in project" :n "SPC" #'projectile-find-file
- :desc "Switch workspace buffer" :n "," #'persp-switch-to-buffer
- :desc "Switch buffer" :n "<" #'switch-to-buffer
- :desc "Browse files" :n "." #'find-file
- :desc "Toggle last popup" :n "~" #'doom/popup-toggle
- :desc "Eval expression" :n "`" #'eval-expression
- :desc "Blink cursor line" :n "DEL" #'+doom/blink-cursor
- :desc "Jump to bookmark" :n "RET" #'bookmark-jump
-
- ;; C-u is used by evil
- :desc "Universal argument" :n "u" #'universal-argument
- :desc "window" :n "w" evil-window-map
-
- (:desc "previous..." :prefix "["
- :desc "Text size" :nv "[" #'text-scale-decrease
- :desc "Buffer" :nv "b" #'doom/previous-buffer
- :desc "Diff Hunk" :nv "d" #'git-gutter:previous-hunk
- :desc "Todo" :nv "t" #'hl-todo-previous
- :desc "Error" :nv "e" #'previous-error
- :desc "Workspace" :nv "w" #'+workspace/switch-left
- :desc "Smart jump" :nv "h" #'smart-backward
- :desc "Spelling error" :nv "s" #'evil-prev-flyspell-error
- :desc "Spelling correction" :n "S" #'flyspell-correct-previous-word-generic)
-
- (:desc "next..." :prefix "]"
- :desc "Text size" :nv "]" #'text-scale-increase
- :desc "Buffer" :nv "b" #'doom/next-buffer
- :desc "Diff Hunk" :nv "d" #'git-gutter:next-hunk
- :desc "Todo" :nv "t" #'hl-todo-next
- :desc "Error" :nv "e" #'next-error
- :desc "Workspace" :nv "w" #'+workspace/switch-right
- :desc "Smart jump" :nv "l" #'smart-forward
- :desc "Spelling error" :nv "s" #'evil-next-flyspell-error
- :desc "Spelling correction" :n "S" #'flyspell-correct-word-generic)
-
- (:desc "search" :prefix "/"
- :desc "Swiper" :nv "/" #'swiper
- :desc "Imenu" :nv "i" #'imenu
- :desc "Imenu across buffers" :nv "I" #'imenu-anywhere
- :desc "Online providers" :nv "o" #'+jump/online-select)
-
- (:desc "workspace" :prefix "TAB"
- :desc "Display tab bar" :n "TAB" #'+workspace/display
- :desc "New workspace" :n "n" #'+workspace/new
- :desc "Load workspace from file" :n "l" #'+workspace/load
- :desc "Load last session" :n "L" (λ! (+workspace/load-session))
- :desc "Save workspace to file" :n "s" #'+workspace/save
- :desc "Autosave current session" :n "S" #'+workspace/save-session
- :desc "Switch workspace" :n "." #'+workspace/switch-to
- :desc "Kill all buffers" :n "x" #'doom/kill-all-buffers
- :desc "Delete session" :n "X" #'+workspace/kill-session
- :desc "Delete this workspace" :n "d" #'+workspace/delete
- :desc "Load session" :n "L" #'+workspace/load-session
- :desc "Next workspace" :n "]" #'+workspace/switch-right
- :desc "Previous workspace" :n "[" #'+workspace/switch-left
- :desc "Switch to 1st workspace" :n "1" (λ! (+workspace/switch-to 0))
- :desc "Switch to 2nd workspace" :n "2" (λ! (+workspace/switch-to 1))
- :desc "Switch to 3rd workspace" :n "3" (λ! (+workspace/switch-to 2))
- :desc "Switch to 4th workspace" :n "4" (λ! (+workspace/switch-to 3))
- :desc "Switch to 5th workspace" :n "5" (λ! (+workspace/switch-to 4))
- :desc "Switch to 6th workspace" :n "6" (λ! (+workspace/switch-to 5))
- :desc "Switch to 7th workspace" :n "7" (λ! (+workspace/switch-to 6))
- :desc "Switch to 8th workspace" :n "8" (λ! (+workspace/switch-to 7))
- :desc "Switch to 9th workspace" :n "9" (λ! (+workspace/switch-to 8))
- :desc "Switch to last workspace" :n "0" #'+workspace/switch-to-last)
-
- (:desc "buffer" :prefix "b"
- :desc "New empty buffer" :n "n" #'evil-buffer-new
- :desc "Switch workspace buffer" :n "b" #'persp-switch-to-buffer
- :desc "Switch buffer" :n "B" #'switch-to-buffer
- :desc "Kill buffer" :n "k" #'doom/kill-this-buffer
- :desc "Kill other buffers" :n "o" #'doom/kill-other-buffers
- :desc "Save buffer" :n "s" #'save-buffer
- :desc "Pop scratch buffer" :n "x" #'doom/open-scratch-buffer
- :desc "Bury buffer" :n "z" #'bury-buffer
- :desc "Next buffer" :n "]" #'doom/next-buffer
- :desc "Previous buffer" :n "[" #'doom/previous-buffer
- :desc "Sudo edit this file" :n "S" #'doom/sudo-this-file)
-
- (:desc "code" :prefix "c"
- :desc "List errors" :n "x" #'flycheck-list-errors
- :desc "Evaluate buffer/region" :n "e" #'+eval/buffer
- :v "e" #'+eval/region
- :desc "Evaluate & replace region" :nv "E" #'+eval:replace-region
- :desc "Build tasks" :nv "b" #'+eval/build
- :desc "Jump to definition" :n "d" #'+jump/definition
- :desc "Jump to references" :n "D" #'+jump/references
- :desc "Open REPL" :n "r" #'+eval/open-repl
- :v "r" #'+eval:repl)
-
- (:desc "file" :prefix "f"
- :desc "Find file" :n "." #'find-file
- :desc "Sudo find file" :n ">" #'doom/sudo-find-file
- :desc "Find file in project" :n "/" #'projectile-find-file
- :desc "Find file from here" :n "?" #'counsel-file-jump
- :desc "Find other file" :n "a" #'projectile-find-other-file
- :desc "Open project editorconfig" :n "c" #'editorconfig-find-current-editorconfig
- :desc "Find file in dotfiles" :n "d" #'+hlissner/find-in-dotfiles
- :desc "Browse dotfiles" :n "D" #'+hlissner/browse-dotfiles
- :desc "Find file in emacs.d" :n "e" #'+hlissner/find-in-emacsd
- :desc "Browse emacs.d" :n "E" #'+hlissner/browse-emacsd
- :desc "Recent files" :n "r" #'recentf-open-files
- :desc "Recent project files" :n "R" #'projectile-recentf
- :desc "Yank filename" :n "y" #'+hlissner/yank-buffer-filename)
-
- (:desc "git" :prefix "g"
- :desc "Git status" :n "S" #'magit-status
- :desc "Git blame" :n "b" #'magit-blame
- :desc "Git time machine" :n "t" #'git-timemachine-toggle
- :desc "Git stage hunk" :n "s" #'git-gutter:stage-hunk
- :desc "Git revert hunk" :n "r" #'git-gutter:revert-hunk
- :desc "Git revert buffer" :n "R" #'vc-revert
- :desc "List gists" :n "g" #'+gist:list
- :desc "Next hunk" :nv "]" #'git-gutter:next-hunk
- :desc "Previous hunk" :nv "[" #'git-gutter:previous-hunk)
-
- (:desc "help" :prefix "h"
- :n "h" help-map
- :desc "Apropos" :n "a" #'apropos
- :desc "Reload theme" :n "R" #'doom//reload-theme
- :desc "Find library" :n "l" #'find-library
- :desc "Toggle Emacs log" :n "m" #'doom/popup-toggle-messages
- :desc "Command log" :n "L" #'global-command-log-mode
- :desc "Describe function" :n "f" #'describe-function
- :desc "Describe key" :n "k" #'describe-key
- :desc "Describe char" :n "c" #'describe-char
- :desc "Describe mode" :n "M" #'describe-mode
- :desc "Describe variable" :n "v" #'describe-variable
- :desc "Describe face" :n "F" #'describe-face
- :desc "Describe DOOM setting" :n "s" #'doom/describe-setting
- :desc "Describe DOOM module" :n "d" #'doom/describe-module
- :desc "Find definition" :n "." #'+jump/definition
- :desc "Find references" :n "/" #'+jump/references
- :desc "Find documentation" :n "h" #'+jump/documentation
- :desc "What face" :n "'" #'doom/what-face
- :desc "What minor modes" :n ";" #'doom/what-minor-mode
- :desc "Info" :n "i" #'info
- :desc "Toggle profiler" :n "p" #'doom/toggle-profiler)
-
- (:desc "insert" :prefix "i"
- :desc "From kill-ring" :nv "y" #'counsel-yank-pop
- :desc "From snippet" :nv "s" #'yas-insert-snippet)
-
- (:desc "notes" :prefix "n"
- :desc "Find file in notes" :n "n" #'+hlissner/find-in-notes
- :desc "Browse notes" :n "N" #'+hlissner/browse-notes
- :desc "Org capture" :n "x" #'+org-capture/open
- :desc "Browse mode notes" :n "m" #'+org/browse-notes-for-major-mode
- :desc "Browse project notes" :n "p" #'+org/browse-notes-for-project)
-
- (:desc "open" :prefix "o"
- :desc "Default browser" :n "b" #'browse-url-of-file
- :desc "Debugger" :n "d" #'+debug/open
- :desc "REPL" :n "r" #'+eval/open-repl
- :v "r" #'+eval:repl
- :desc "Neotree" :n "n" #'+neotree/toggle
- :desc "Terminal" :n "t" #'+term/open-popup
- :desc "Terminal in project" :n "T" #'+term/open-popup-in-project
-
- ;; applications
- :desc "APP: elfeed" :n "E" #'=rss
- :desc "APP: email" :n "M" #'=email
- :desc "APP: twitter" :n "T" #'=twitter
- :desc "APP: regex" :n "X" #'=regex
-
- ;; macos
- (:when IS-MAC
- :desc "Reveal in Finder" :n "o" #'+macos/reveal-in-finder
- :desc "Reveal project in Finder" :n "O" #'+macos/reveal-project-in-finder
- :desc "Send to Transmit" :n "u" #'+macos/send-to-transmit
- :desc "Send project to Transmit" :n "U" #'+macos/send-project-to-transmit
- :desc "Send to Launchbar" :n "l" #'+macos/send-to-launchbar
- :desc "Send project to Launchbar" :n "L" #'+macos/send-project-to-launchbar))
-
- (:desc "project" :prefix "p"
- :desc "Browse project" :n "." (find-file-in! (doom-project-root))
- :desc "Find file in project" :n "/" #'projectile-find-file
- :desc "Run cmd in project root" :nv "!" #'projectile-run-shell-command-in-root
- :desc "Switch project" :n "p" #'projectile-switch-project
- :desc "Recent project files" :n "r" #'projectile-recentf
- :desc "List project tasks" :n "t" #'+ivy/tasks
- :desc "Pop term in project" :n "o" #'+term/open-popup-in-project
- :desc "Invalidate cache" :n "x" #'projectile-invalidate-cache)
-
- (:desc "quit" :prefix "q"
- :desc "Quit" :n "q" #'evil-save-and-quit
- :desc "Quit (forget session)" :n "Q" #'+workspace/kill-session-and-quit)
-
- (:desc "remote" :prefix "r"
- :desc "Upload local" :n "u" #'+upload/local
- :desc "Upload local (force)" :n "U" (λ! (+upload/local t))
- :desc "Download remote" :n "d" #'+upload/remote-download
- :desc "Diff local & remote" :n "D" #'+upload/diff
- :desc "Browse remote files" :n "." #'+upload/browse
- :desc "Detect remote changes" :n ">" #'+upload/check-remote)
-
- (:desc "snippets" :prefix "s"
- :desc "New snippet" :n "n" #'yas-new-snippet
- :desc "Insert snippet" :nv "i" #'yas-insert-snippet
- :desc "Find snippet for mode" :n "s" #'yas-visit-snippet-file
- :desc "Find snippet" :n "S" #'+hlissner/find-in-snippets)
-
- (:desc "toggle" :prefix "t"
- :desc "Flyspell" :n "s" #'flyspell-mode
- :desc "Flycheck" :n "f" #'flycheck-mode
- :desc "Line numbers" :n "l" #'doom/toggle-line-numbers
- :desc "Fullscreen" :n "f" #'doom/toggle-fullscreen
- :desc "Indent guides" :n "i" #'highlight-indentation-mode
- :desc "Indent guides (column)" :n "I" #'highlight-indentation-current-column-mode
- :desc "Impatient mode" :n "h" #'+impatient-mode/toggle
- :desc "Big mode" :n "b" #'doom-big-font-mode
- :desc "Evil goggles" :n "g" #'+evil-goggles/toggle))
-
-
- ;; --- Personal vim-esque bindings ------------------
- :n "zx" #'doom/kill-this-buffer
- :n "ZX" #'bury-buffer
- :n "]b" #'doom/next-buffer
- :n "[b" #'doom/previous-buffer
- :n "]w" #'+workspace/switch-right
- :n "[w" #'+workspace/switch-left
- :m "gt" #'+workspace/switch-right
- :m "gT" #'+workspace/switch-left
- :m "gd" #'+jump/definition
- :m "gD" #'+jump/references
- :m "gh" #'+jump/documentation
- :n "gp" #'+evil/reselect-paste
- :n "gr" #'+eval:region
- :n "gR" #'+eval/buffer
- :v "gR" #'+eval:replace-region
- :v "@" #'+evil:macro-on-all-lines
- :n "g@" #'+evil:macro-on-all-lines
- ;; repeat in visual mode (FIXME buggy)
- :v "." #'evil-repeat
- ;; don't leave visual mode after shifting
- :v "<" #'+evil/visual-dedent ; vnoremap < " #'+evil/visual-indent ; vnoremap > >gv
- ;; paste from recent yank register (which isn't overwritten)
- :v "C-p" "\"0p"
-
- (:map evil-window-map ; prefix "C-w"
- ;; Navigation
- "C-h" #'evil-window-left
- "C-j" #'evil-window-down
- "C-k" #'evil-window-up
- "C-l" #'evil-window-right
- "C-w" #'ace-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
- ;; Delete window
- "c" #'+workspace/close-window-or-workspace
- "C-C" #'ace-delete-window)
-
-
- ;; --- Plugin bindings ------------------------------
- ;; auto-yasnippet
- :i [C-tab] #'aya-expand
- :nv [C-tab] #'aya-create
-
- ;; company-mode (vim-like omnicompletion)
- :i "C-SPC" #'+company/complete
- (:prefix "C-x"
- :i "C-l" #'+company/whole-lines
- :i "C-k" #'+company/dict-or-keywords
- :i "C-f" #'company-files
- :i "C-]" #'company-etags
- :i "s" #'company-ispell
- :i "C-s" #'company-yasnippet
- :i "C-o" #'company-capf
- :i "C-n" #'company-dabbrev-code
- :i "C-p" #'+company/dabbrev-code-previous)
- (:after company
- (:map company-active-map
- ;; Don't interfere with `evil-delete-backward-word' in insert mode
- "C-w" nil
- "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-s" #'company-search-candidates
- "C-s" #'company-filter-candidates
- "C-SPC" #'company-complete-common
- "C-h" #'company-quickhelp-manual-begin
- [tab] #'company-complete-common-or-cycle
- [backtab] #'company-select-previous
- [escape] (λ! (company-abort) (evil-normal-state 1)))
- ;; Automatically applies to `company-filter-map'
- (:map company-search-map
- "C-n" #'company-search-repeat-forward
- "C-p" #'company-search-repeat-backward
- "C-s" (λ! (company-search-abort) (company-filter-candidates))
- [escape] #'company-search-abort))
-
- ;; counsel
- (: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)))
-
- ;; evil-commentary
- :n "gc" #'evil-commentary
-
- ;; evil-exchange
- :n "gx" #'evil-exchange
-
- ;; evil-matchit
- :nv [tab] #'+evil/matchit-or-toggle-fold
-
- ;; evil-magit
- (:after evil-magit
- :map (magit-status-mode-map magit-revision-mode-map)
- :n "C-j" nil
- :n "C-k" nil)
-
- ;; evil-mc
- (:prefix "gz"
- :nv "m" #'evil-mc-make-all-cursors
- :nv "u" #'evil-mc-undo-all-cursors
- :nv "z" #'+evil/mc-make-cursor-here
- :nv "t" #'+evil/mc-toggle-cursors
- :nv "n" #'evil-mc-make-and-goto-next-cursor
- :nv "p" #'evil-mc-make-and-goto-prev-cursor
- :nv "N" #'evil-mc-make-and-goto-last-cursor
- :nv "P" #'evil-mc-make-and-goto-first-cursor
- :nv "d" #'evil-mc-make-and-goto-next-match
- :nv "D" #'evil-mc-make-and-goto-prev-match)
- (:after evil-mc
- :map evil-mc-key-map
- :nv "C-n" #'evil-mc-make-and-goto-next-cursor
- :nv "C-N" #'evil-mc-make-and-goto-last-cursor
- :nv "C-p" #'evil-mc-make-and-goto-prev-cursor
- :nv "C-P" #'evil-mc-make-and-goto-first-cursor)
-
- ;; evil-multiedit
- :v "R" #'evil-multiedit-match-all
- :n "M-d" #'evil-multiedit-match-symbol-and-next
- :n "M-D" #'evil-multiedit-match-symbol-and-prev
- :v "M-d" #'evil-multiedit-match-and-next
- :v "M-D" #'evil-multiedit-match-and-prev
- :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)
- (:map (evil-multiedit-state-map evil-multiedit-insert-state-map)
- "C-n" #'evil-multiedit-next
- "C-p" #'evil-multiedit-prev))
-
- ;; evil-snipe
- (:after evil-snipe
- ;; Binding to switch to evil-easymotion/avy after a 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
-
- ;; expand-region
- :v "v" #'er/expand-region
- :v "V" #'er/contract-region
-
- ;; flycheck
- :m "]e" #'next-error
- :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)
-
- ;; flyspell
- :m "]S" #'flyspell-correct-word-generic
- :m "[S" #'flyspell-correct-previous-word-generic
-
- ;; git-gutter
- :m "]d" #'git-gutter:next-hunk
- :m "[d" #'git-gutter:previous-hunk
-
- ;; git-timemachine
- (:after git-timemachine
- (:map git-timemachine-mode-map
- :n "C-p" #'git-timemachine-show-previous-revision
- :n "C-n" #'git-timemachine-show-next-revision
- :n "[[" #'git-timemachine-show-previous-revision
- :n "]]" #'git-timemachine-show-next-revision
- :n "q" #'git-timemachine-quit
- :n "gb" #'git-timemachine-blame))
-
- ;; gist
- (:after gist
- :map gist-list-menu-mode-map
- :n "RET" #'+gist/open-current
- :n "b" #'gist-browse-current-url
- :n "c" #'gist-add-buffer
- :n "d" #'gist-kill-current
- :n "f" #'gist-fork
- :n "q" #'quit-window
- :n "r" #'gist-list-reload
- :n "s" #'gist-star
- :n "S" #'gist-unstar
- :n "y" #'gist-print-current-url)
-
- ;; helm
- (:after helm
- (:map helm-map
- "ESC" nil
- "C-S-n" #'helm-next-source
- "C-S-p" #'helm-previous-source
- "C-u" #'helm-delete-minibuffer-contents
- "C-w" #'backward-kill-word
- "C-r" #'evil-paste-from-register ; Evil registers in helm! Glorious!
- "C-b" #'backward-word
- [left] #'backward-char
- [right] #'forward-char
- [escape] #'helm-keyboard-quit
- [tab] #'helm-execute-persistent-action)
-
- (:after helm-files
- (:map helm-generic-files-map
- :e "ESC" #'helm-keyboard-quit)
- (:map helm-find-files-map
- "C-w" #'helm-find-files-up-one-level
- "TAB" #'helm-execute-persistent-action))
-
- (:after helm-ag
- (:map helm-ag-map
- "" #'helm-ag-edit)))
-
- ;; hl-todo
- :m "]t" #'hl-todo-next
- :m "[t" #'hl-todo-previous
-
- ;; ivy
- (:after ivy
- :map ivy-minibuffer-map
- [escape] #'keyboard-escape-quit
- "C-SPC" #'ivy-call-and-recenter
- "TAB" #'ivy-partial
- "M-v" #'yank
- "M-z" #'undo
- "C-r" #'evil-paste-from-register
- "C-k" #'ivy-previous-line
- "C-j" #'ivy-next-line
- "C-l" #'ivy-alt-done
- "C-w" #'ivy-backward-kill-word
- "C-u" #'ivy-kill-line
- "C-b" #'backward-word
- "C-f" #'forward-word)
-
- ;; neotree
- (:after neotree
- :map neotree-mode-map
- :n "g" nil
- :n [tab] #'neotree-quick-look
- :n "RET" #'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)
-
- ;; realgud
- (:after realgud
- :map realgud:shortkey-mode-map
- :n "j" #'evil-next-line
- :n "k" #'evil-previous-line
- :n "h" #'evil-backward-char
- :n "l" #'evil-forward-char
- :m "n" #'realgud:cmd-next
- :m "b" #'realgud:cmd-break
- :m "B" #'realgud:cmd-clear
- :n "c" #'realgud:cmd-continue)
-
- ;; rotate-text
- :n "!" #'rotate-text
-
- ;; smart-forward
- :nv "K" #'smart-up
- :m "g]" #'smart-forward
- :m "g[" #'smart-backward
-
- ;; undo-tree -- undo/redo for visual regions
- :v "C-u" #'undo-tree-undo
- :v "C-r" #'undo-tree-redo
-
- ;; yasnippet
- (:after yasnippet
- (:map yas-keymap
- "C-e" #'+snippets/goto-end-of-field
- "C-a" #'+snippets/goto-start-of-field
- "" #'+snippets/goto-end-of-field
- "" #'+snippets/goto-start-of-field
- "" #'+snippets/delete-to-start-of-field
- [escape] #'evil-normal-state
- [backspace] #'+snippets/delete-backward-char
- [delete] #'+snippets/delete-forward-char-or-field)
- (:map yas-minor-mode-map
- :i "" yas-maybe-expand
- :v "" #'+snippets/expand-on-region))
-
-
- ;; --- Major mode bindings --------------------------
- (:after markdown-mode
- (:map markdown-mode-map
- ;; fix conflicts with private bindings
- "" nil
- "" nil
- "" nil))
-
-
- ;; --- Custom evil text-objects ---------------------
- :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 "I" #'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
-
-
- ;; --- Built-in plugins -----------------------------
- (:after comint
- ;; TAB auto-completion in term buffers
- :map comint-mode-map [tab] #'company-complete)
-
- (:after debug
- ;; For elisp debugging
- :map debugger-mode-map
- :n "RET" #'debug-help-follow
- :n "e" #'debugger-eval-expression
- :n "n" #'debugger-step-through
- :n "c" #'debugger-continue)
-
- (:map help-mode-map
- :n "[[" #'help-go-back
- :n "]]" #'help-go-forward
- :n "o" #'ace-link-help
- :n "q" #'quit-window
- :n "Q" #'+ivy-quit-and-resume)
-
- (:after vc-annotate
- :map vc-annotate-mode-map
- :n "q" #'kill-this-buffer
- :n "d" #'vc-annotate-show-diff-revision-at-line
- :n "D" #'vc-annotate-show-changeset-diff-revision-at-line
- :n "SPC" #'vc-annotate-show-log-revision-at-line
- :n "]]" #'vc-annotate-next-revision
- :n "[[" #'vc-annotate-prev-revision
- :n "TAB" #'vc-annotate-toggle-annotation-visibility
- :n "RET" #'vc-annotate-find-revision-at-line))
-
-
-;; --- Custom key functionality ---------------------
-(defmacro do-repeat! (command next-func prev-func)
- "Repeat motions with ;/,"
- (let ((fn-sym (intern (format "+evil*repeat-%s" command))))
- `(progn
- (defun ,fn-sym (&rest _)
- (define-key evil-motion-state-map (kbd ";") ',next-func)
- (define-key evil-motion-state-map (kbd ",") ',prev-func))
- (advice-add #',command :before #',fn-sym))))
-
-;; n/N
-(do-repeat! evil-ex-search-next evil-ex-search-next evil-ex-search-previous)
-(do-repeat! evil-ex-search-previous evil-ex-search-next evil-ex-search-previous)
-(do-repeat! evil-ex-search-forward evil-ex-search-next evil-ex-search-previous)
-(do-repeat! evil-ex-search-backward evil-ex-search-next evil-ex-search-previous)
-
-;; f/F/t/T/s/S
-(after! evil-snipe
- (setq evil-snipe-repeat-keys nil
- evil-snipe-override-evil-repeat-keys nil) ; causes problems with remapped ;
-
- (do-repeat! evil-snipe-f evil-snipe-repeat evil-snipe-repeat-reverse)
- (do-repeat! evil-snipe-F evil-snipe-repeat evil-snipe-repeat-reverse)
- (do-repeat! evil-snipe-t evil-snipe-repeat evil-snipe-repeat-reverse)
- (do-repeat! evil-snipe-T evil-snipe-repeat evil-snipe-repeat-reverse)
- (do-repeat! evil-snipe-s evil-snipe-repeat evil-snipe-repeat-reverse)
- (do-repeat! evil-snipe-S evil-snipe-repeat evil-snipe-repeat-reverse)
- (do-repeat! evil-snipe-x evil-snipe-repeat evil-snipe-repeat-reverse)
- (do-repeat! evil-snipe-X evil-snipe-repeat evil-snipe-repeat-reverse))
-
-;; */#
-(after! evil-visualstar
- (do-repeat! evil-visualstar/begin-search-forward
- evil-ex-search-next evil-ex-search-previous)
- (do-repeat! evil-visualstar/begin-search-backward
- evil-ex-search-previous evil-ex-search-next))
-
-;; evil-easymotion
-(after! evil-easymotion
- (let ((prefix (concat doom-leader-key " /")))
- ;; NOTE `evilem-default-keybinds' unsets all other keys on the prefix (in
- ;; motion state)
- (evilem-default-keybindings prefix)
- (evilem-define (kbd (concat prefix " n")) #'evil-ex-search-next)
- (evilem-define (kbd (concat prefix " N")) #'evil-ex-search-previous)
- (evilem-define (kbd (concat prefix " s")) #'evil-snipe-repeat
- :pre-hook (save-excursion (call-interactively #'evil-snipe-s))
- :bind ((evil-snipe-scope 'buffer)
- (evil-snipe-enable-highlight)
- (evil-snipe-enable-incremental-highlight)))
- (evilem-define (kbd (concat prefix " S")) #'evil-snipe-repeat-reverse
- :pre-hook (save-excursion (call-interactively #'evil-snipe-s))
- :bind ((evil-snipe-scope 'buffer)
- (evil-snipe-enable-highlight)
- (evil-snipe-enable-incremental-highlight)))))
-
-
-;;
-;; Keybinding fixes
-;;
-
-;; This section is dedicated to "fixing" certain keys so that they behave
-;; properly, more like vim, or how I like it.
-
-(map! (:map input-decode-map
- [S-iso-lefttab] [backtab]
- (:unless window-system "TAB" [tab])) ; Fix TAB in terminal
-
- ;; I want C-a and C-e to be a little smarter. 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 and trailing whitespace before
- ;; jumping to eol.
- :i "C-a" #'doom/backward-to-bol-or-indent
- :i "C-e" #'doom/forward-to-last-non-comment-or-eol
- :i "C-u" #'doom/backward-kill-to-bol-and-indent
-
- ;; textmate-esque newline insertion
- :i [M-return] #'evil-open-below
- :i [S-M-return] #'evil-open-above
- ;; textmate-esque deletion
- [M-backspace] #'doom/backward-kill-to-bol-and-indent
- :i [backspace] #'delete-backward-char
- :i [M-backspace] #'doom/backward-kill-to-bol-and-indent
- ;; Emacsien motions for insert mode
- :i "C-b" #'backward-word
- :i "C-f" #'forward-word
-
- ;; Highjacks space/backspace to:
- ;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
- ;; b) delete space-indented blocks intelligently
- ;; c) do none of this when inside a string
- :i "SPC" #'doom/inflate-space-maybe
- :i [remap delete-backward-char] #'doom/deflate-space-maybe
- :i [remap newline] #'doom/newline-and-indent
-
- (:after org
- (:map org-mode-map
- :i [remap doom/inflate-space-maybe] #'org-self-insert-command
- :i "C-e" #'org-end-of-line
- :i "C-a" #'org-beginning-of-line))
-
- ;; Restore common editing keys (and ESC) in minibuffer
- (:map (minibuffer-local-map
- minibuffer-local-ns-map
- minibuffer-local-completion-map
- minibuffer-local-must-match-map
- minibuffer-local-isearch-map
- evil-ex-completion-map
- evil-ex-search-keymap
- read-expression-map)
- [escape] #'abort-recursive-edit
- "C-r" #'evil-paste-from-register
- "C-a" #'move-beginning-of-line
- "C-w" #'doom/minibuffer-kill-word
- "C-u" #'doom/minibuffer-kill-line
- "C-b" #'backward-word
- "C-f" #'forward-word
- "M-z" #'doom/minibuffer-undo)
-
- (:map messages-buffer-mode-map
- "M-;" #'eval-expression
- "A-;" #'eval-expression)
-
- (:map tabulated-list-mode-map
- [remap evil-record-macro] #'doom/popup-close-maybe)
-
- (:after view
- (:map view-mode-map "" #'View-quit-all)))
diff --git a/modules/private/hlissner/.gitignore b/modules/private/hlissner/.gitignore
deleted file mode 100644
index d31426933..000000000
--- a/modules/private/hlissner/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-snippets
-.authinfo.gpg
diff --git a/modules/private/hlissner/autoload/evil.el b/modules/private/hlissner/autoload/evil.el
deleted file mode 100644
index 0845af2d2..000000000
--- a/modules/private/hlissner/autoload/evil.el
+++ /dev/null
@@ -1,37 +0,0 @@
-;;; private/hlissner/autoload/evil.el -*- lexical-binding: t; -*-
-;;;###if (featurep! :feature evil)
-
-;;;###autoload (autoload '+hlissner:multi-next-line "private/hlissner/autoload/evil" nil t)
-(evil-define-motion +hlissner:multi-next-line (count)
- "Move down 6 lines."
- :type line
- (let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode))))
- (evil-line-move (* 6 (or count 1)))))
-
-;;;###autoload (autoload '+hlissner:multi-previous-line "private/hlissner/autoload/evil" nil t)
-(evil-define-motion +hlissner:multi-previous-line (count)
- "Move up 6 lines."
- :type line
- (let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode))))
- (evil-line-move (- (* 6 (or count 1))))))
-
-;;;###autoload (autoload '+hlissner:cd "private/hlissner/autoload/evil" nil t)
-(evil-define-command +hlissner:cd ()
- "Change `default-directory' with `cd'."
- (interactive "")
- (cd input))
-
-;;;###autoload (autoload '+hlissner:kill-all-buffers "private/hlissner/autoload/evil" nil t)
-(evil-define-command +hlissner: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 '+hlissner:kill-matching-buffers "private/hlissner/autoload/evil" nil t)
-(evil-define-command +hlissner:kill-matching-buffers (&optional bang pattern)
- "Kill all buffers matching PATTERN regexp. If BANG, only match project
-buffers."
- (interactive "")
- (doom/kill-matching-buffers pattern bang))
diff --git a/modules/private/hlissner/autoload/hlissner.el b/modules/private/hlissner/autoload/hlissner.el
deleted file mode 100644
index 236676fc2..000000000
--- a/modules/private/hlissner/autoload/hlissner.el
+++ /dev/null
@@ -1,53 +0,0 @@
-;;; private/hlissner/autoload/hlissner.el -*- lexical-binding: t; -*-
-
-;;;###autoload
-(defun +hlissner/install-snippets ()
- "Install my snippets from https://github.com/hlissner/emacs-snippets into
-private/hlissner/snippets."
- (interactive)
- (doom-fetch :github "hlissner/emacs-snippets"
- (expand-file-name "snippets" (doom-module-path :private 'hlissner))))
-
-;;;###autoload
-(defun +hlissner/yank-buffer-filename ()
- "Copy the current buffer's path to the kill ring."
- (interactive)
- (if-let* ((filename (or buffer-file-name (bound-and-true-p list-buffers-directory))))
- (message (kill-new (abbreviate-file-name filename)))
- (error "Couldn't find filename in current buffer")))
-
-(defmacro +hlissner-def-finder! (name dir)
- "Define a pair of find-file and browse functions."
- `(progn
- (defun ,(intern (format "+hlissner/find-in-%s" name)) ()
- (interactive)
- (let ((default-directory ,dir)
- projectile-project-name
- projectile-require-project-root
- projectile-cached-buffer-file-name
- projectile-cached-project-root)
- (call-interactively (command-remapping #'projectile-find-file))))
- (defun ,(intern (format "+hlissner/browse-%s" name)) ()
- (interactive)
- (let ((default-directory ,dir))
- (call-interactively (command-remapping #'find-file))))))
-
-;;;###autoload (autoload '+hlissner/find-in-templates "private/hlissner/autoload/hlissner" nil t)
-;;;###autoload (autoload '+hlissner/browse-templates "private/hlissner/autoload/hlissner" nil t)
-(+hlissner-def-finder! templates +file-templates-dir)
-
-;;;###autoload (autoload '+hlissner/find-in-snippets "private/hlissner/autoload/hlissner" nil t)
-;;;###autoload (autoload '+hlissner/browse-snippets "private/hlissner/autoload/hlissner" nil t)
-(+hlissner-def-finder! snippets +hlissner-snippets-dir)
-
-;;;###autoload (autoload '+hlissner/find-in-dotfiles "private/hlissner/autoload/hlissner" nil t)
-;;;###autoload (autoload '+hlissner/browse-dotfiles "private/hlissner/autoload/hlissner" nil t)
-(+hlissner-def-finder! dotfiles (expand-file-name ".dotfiles" "~"))
-
-;;;###autoload (autoload '+hlissner/find-in-emacsd "private/hlissner/autoload/hlissner" nil t)
-;;;###autoload (autoload '+hlissner/browse-emacsd "private/hlissner/autoload/hlissner" nil t)
-(+hlissner-def-finder! emacsd doom-emacs-dir)
-
-;;;###autoload (autoload '+hlissner/find-in-notes "private/hlissner/autoload/hlissner" nil t)
-;;;###autoload (autoload '+hlissner/browse-notes "private/hlissner/autoload/hlissner" nil t)
-(+hlissner-def-finder! notes +org-dir)
diff --git a/modules/private/hlissner/config.el b/modules/private/hlissner/config.el
deleted file mode 100644
index b034ad8c9..000000000
--- a/modules/private/hlissner/config.el
+++ /dev/null
@@ -1,108 +0,0 @@
-;;; private/hlissner/config.el -*- lexical-binding: t; -*-
-
-(defvar +hlissner-dir (file-name-directory load-file-name))
-(defvar +hlissner-snippets-dir (expand-file-name "snippets/" +hlissner-dir))
-
-;;
-(when (featurep! :feature evil)
- (load! +bindings) ; my key bindings
- (load! +commands)) ; my custom ex commands
-
-
-;;
-;; Global config
-;;
-
-(setq epa-file-encrypt-to user-mail-address
- auth-sources (list (expand-file-name ".authinfo.gpg" +hlissner-dir))
- +doom-modeline-buffer-file-name-style 'relative-from-project)
-
-(defun +hlissner*no-authinfo-for-tramp (orig-fn &rest args)
- "Don't look into .authinfo for local sudo TRAMP buffers."
- (let ((auth-sources (if (equal tramp-current-method "sudo") nil auth-sources)))
- (apply orig-fn args)))
-(advice-add #'tramp-read-passwd :around #'+hlissner*no-authinfo-for-tramp)
-
-
-;;
-;; Modules
-;;
-
-(after! smartparens
- ;; Auto-close more conservatively and expand braces on RET
- (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))
- (sp-pair "{" nil :post-handlers '(("||\n[i]" "RET") ("| " " "))
- :unless '(sp-point-before-word-p sp-point-before-same-p))
- (sp-pair "(" nil :post-handlers '(("||\n[i]" "RET") ("| " " "))
- :unless '(sp-point-before-word-p sp-point-before-same-p))
- (sp-pair "[" nil :post-handlers '(("| " " "))
- :unless '(sp-point-before-word-p sp-point-before-same-p)))
-
-;; feature/evil
-(after! evil-mc
- ;; Make evil-mc resume its cursors when I switch to insert mode
- (add-hook! 'evil-mc-before-cursors-created
- (add-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors nil t))
- (add-hook! 'evil-mc-after-cursors-deleted
- (remove-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors t)))
-
-;; feature/snippets
-(after! yasnippet
- ;; Don't use default snippets, use mine.
- (setq yas-snippet-dirs
- (append (list '+hlissner-snippets-dir)
- (delq 'yas-installed-snippets-dir yas-snippet-dirs))))
-
-;; completion/helm
-(after! helm
- ;; Hide header lines in helm. I don't like them
- (set-face-attribute 'helm-source-header nil :height 0.1))
-
-;; lang/org
-(after! org-bullets
- ;; The standard unicode characters are usually misaligned depending on the
- ;; font. This bugs me. Personally, markdown #-marks for headlines are more
- ;; elegant, so we use those.
- (setq org-bullets-bullet-list '("#")))
-
-;; app/irc
-(after! circe
- (setq +irc-notifications-watch-strings '("v0" "vnought" "hlissner"))
-
- (set! :irc "irc.snoonet.org"
- `(:tls t
- :nick "v0"
- :port 6697
- :sasl-username ,(+pass-get-user "irc/snoonet.org")
- :sasl-password ,(+pass-get-secret "irc/snoonet.org")
- :channels (:after-auth "#ynought"))))
-
-;; app/email
-(after! mu4e
- (setq smtpmail-stream-type 'starttls
- smtpmail-default-smtp-server "smtp.gmail.com"
- smtpmail-smtp-server "smtp.gmail.com"
- smtpmail-smtp-service 587)
-
- (set! :email "gmail.com"
- '((mu4e-sent-folder . "/gmail.com/Sent Mail")
- (mu4e-drafts-folder . "/gmail.com/Drafts")
- (mu4e-trash-folder . "/gmail.com/Trash")
- (mu4e-refile-folder . "/gmail.com/All Mail")
- (smtpmail-smtp-user . "hlissner")
- (user-mail-address . "hlissner@gmail.com")
- (mu4e-compose-signature . "---\nHenrik")))
-
- (set! :email "lissner.net"
- '((mu4e-sent-folder . "/lissner.net/Sent Mail")
- (mu4e-drafts-folder . "/lissner.net/Drafts")
- (mu4e-trash-folder . "/lissner.net/Trash")
- (mu4e-refile-folder . "/lissner.net/All Mail")
- (smtpmail-smtp-user . "henrik@lissner.net")
- (user-mail-address . "henrik@lissner.net")
- (mu4e-compose-signature . "---\nHenrik Lissner"))
- t))
diff --git a/modules/private/hlissner/init.el b/modules/private/hlissner/init.el
deleted file mode 100644
index 37eb5c43a..000000000
--- a/modules/private/hlissner/init.el
+++ /dev/null
@@ -1,52 +0,0 @@
-;;; private/hlissner/init.el -*- lexical-binding: t; -*-
-
-;; An extra measure to prevent the flash of unstyled mode-line while Emacs is
-;; booting up (when Doom is byte-compiled).
-(setq-default mode-line-format nil)
-
-;; I've swapped these keys on my keyboard
-(setq x-super-keysym 'alt
- x-alt-keysym 'meta)
-
-(setq user-mail-address "henrik@lissner.net"
- user-full-name "Henrik Lissner")
-
-(setq doom-big-font (font-spec :family "Fira Mono" :size 19))
-
-(pcase (system-name)
- ("proteus"
- ;; My 13" laptop has very little screen estate, so we use a bitmap font
- ;; there. For Doom, that means we need to take up less space!
- (setq-default line-spacing 1)
-
- (setq doom-font (font-spec :family "kakwa kakwafont" :size 12)
- doom-variable-pitch-font (font-spec :family "kakwa kakwafont")
- doom-unicode-font (font-spec :family "UT Ttyp0")
- ;; ui/doom-modeline
- +doom-modeline-height 23
- ;; `doom-themes'
- doom-neotree-enable-variable-pitch nil
- doom-neotree-project-size 1.2
- doom-neotree-line-spacing 0
- doom-neotree-folder-size 1.0
- doom-neotree-chevron-size 0.6)
- (add-hook! doom-big-font-mode
- (setq +doom-modeline-height (if doom-big-font-mode 37 23)))
-
- ;; No highlighted bar in the mode-line
- (setq +doom-modeline-bar-width 1)
- (custom-set-faces '(doom-modeline-bar ((t (:background nil))))))
-
- (_
- ;; Everywhere else, I have big displays and plenty of space, so use it!
- (setq doom-font (font-spec :family "Fira Mono" :size 12)
- doom-variable-pitch-font (font-spec :family "Fira Sans")
- doom-unicode-font (font-spec :family "DejaVu Sans Mono")
- org-ellipsis " ")
-
- ;; Fira Mono doesn't have italics, so we highlight it instead.
- (add-hook! doom-post-init
- (set-face-attribute 'italic nil :weight 'ultra-light :foreground "#ffffff"))
-
- (add-hook! doom-big-font-mode
- (setq +doom-modeline-height (if doom-big-font-mode 37 29)))))
diff --git a/modules/tools/neotree/README.org b/modules/tools/neotree/README.org
index 280a97c3d..efbf410c1 100644
--- a/modules/tools/neotree/README.org
+++ b/modules/tools/neotree/README.org
@@ -1,7 +1,9 @@
#+TITLE: :evil neotree
-This module brings a side panel for browsing project files, inspired by vim's NERDTree.
+This module brings a side panel for browsing project files, inspired by vim's
+NERDTree.
#+begin_quote
-Sure, there's dired and projectile, but sometimes I'd like a bird's eye view of a project.
+Sure, there's dired and projectile, but sometimes I'd like a bird's eye view of
+a project.
#+end_quote
diff --git a/modules/tools/neotree/autoload.el b/modules/tools/neotree/autoload.el
index 3a3c87ee9..c24ebe1ff 100644
--- a/modules/tools/neotree/autoload.el
+++ b/modules/tools/neotree/autoload.el
@@ -9,13 +9,15 @@
(require 'neotree)
(cond ((and (neo-global--window-exists-p)
(get-buffer-window neo-buffer-name t))
- (neotree-find path project-root))
+ (neotree-find path project-root)
+ (neotree-refresh))
((not (and (neo-global--window-exists-p)
(equal (file-truename (neo-global--with-buffer neo-buffer--start-node))
(file-truename project-root))))
(neotree-dir project-root)
(neotree-find path project-root))
- (t (neotree-find path project-root)))))
+ (t
+ (neotree-find path project-root)))))
;;;###autoload
(defun +neotree/collapse-or-up ()
diff --git a/modules/tools/password-store/autoload.el b/modules/tools/password-store/autoload.el
index 6705fa6a8..f22d18393 100644
--- a/modules/tools/password-store/autoload.el
+++ b/modules/tools/password-store/autoload.el
@@ -37,7 +37,7 @@
(and (or (string-match-p "https?://" url)
(error "Field for %s doesn't look like an url" item))
(browse-url url))
- (error "Username not found.")))
+ (error "url not found.")))
(defun +pass-ivy-action--get-field (item)
(let* ((data (+pass--get-entry item))
diff --git a/modules/tools/password-store/test/autoload-pass.el b/modules/tools/password-store/test/autoload-pass.el
index 083c2f0d8..d9d190097 100644
--- a/modules/tools/password-store/test/autoload-pass.el
+++ b/modules/tools/password-store/test/autoload-pass.el
@@ -3,7 +3,7 @@
(load! ../autoload)
-(defmacro -with-passwords! (buffer-args &rest body)
+(defmacro with-passwords!! (buffer-args &rest body)
(declare (indent defun))
`(cl-letf
(((symbol-function '+pass--get-entry)
@@ -18,7 +18,7 @@
;;
(def-test! get-field
- (-with-passwords!
+ (with-passwords!!
(should (equal (+pass-get-field "fake/source" "login")
"HL2532-GANDI"))
(should (equal (+pass-get-field "fake/source" "email")
@@ -29,14 +29,14 @@
"henrik@lissner.net"))))
(def-test! missing-fields-return-nil
- (-with-passwords!
+ (with-passwords!!
(should-not (+pass-get-field "fake/source" '("x" "y" "z")))))
(def-test! missing-entries-throw-error
- (-with-passwords!
+ (with-passwords!!
(should-error (+pass-get-field "nonexistent/source" "login"))))
(def-test! get-login
- (-with-passwords!
+ (with-passwords!!
(should (equal (+pass-get-user "fake/source") "HL2532-GANDI"))
(should (equal (+pass-get-secret "fake/source") "defuse-account-gad"))))
diff --git a/modules/ui/doom-dashboard/config.el b/modules/ui/doom-dashboard/config.el
index 1929f5438..debcc73fc 100644
--- a/modules/ui/doom-dashboard/config.el
+++ b/modules/ui/doom-dashboard/config.el
@@ -3,20 +3,38 @@
(defvar +doom-dashboard-name " *doom*"
"The name to use for the dashboard buffer.")
-(defvar +doom-dashboard-inhibit-refresh nil
- "If non-nil, the doom buffer won't be refreshed.")
-
(defvar +doom-dashboard-widgets '(banner shortmenu loaded)
"List of widgets to display in a blank scratch buffer.")
+(defvar +doom-dashboard-inhibit-refresh nil
+ "If non-nil, the doom buffer won't be refreshed.")
+
(defvar +doom-dashboard-inhibit-functions ()
- "A list of functions that determine whether to inhibit the dashboard the
+ "A list of functions that determine whether to inhibit the dashboard from
loading.")
+(defvar +doom-dashboard-pwd-policy 'last-project
+ "The policy to use when setting the `default-directory' in the dashboard.
+
+Possible values:
+
+ 'last-project the `doom-project-root' of the last open buffer
+ 'last the `default-directory' of the last open buffer
+ a FUNCTION a function run with the `default-directory' of the last
+ open buffer, that returns a directory path
+ a STRING a fixed path
+ nil `default-directory' will never change")
+
+;;
+(defvar +doom-dashboard--last-cwd nil)
(defvar +doom-dashboard--width 80)
(defvar +doom-dashboard--height 0)
(defvar +doom-dashboard--old-fringe-indicator fringe-indicator-alist)
+(defvar all-the-icons-scale-factor)
+(defvar all-the-icons-default-adjust)
+
+;;
(setq doom-fallback-buffer +doom-dashboard-name)
@@ -25,6 +43,8 @@ loading.")
"Major mode for the DOOM dashboard buffer."
(read-only-mode +1)
(setq truncate-lines t)
+ (setq-local whitespace-style nil)
+ (setq-local show-trailing-whitespace nil)
(cl-loop for (car . _cdr) in fringe-indicator-alist
collect (cons car nil) into alist
finally do (setq fringe-indicator-alist alist)))
@@ -51,15 +71,25 @@ loading.")
if in a GUI/non-daemon session."
(add-hook 'window-configuration-change-hook #'+doom-dashboard-reload)
(add-hook 'focus-in-hook #'+doom-dashboard-reload)
- (add-hook 'kill-buffer-query-functions #'+doom-dashboard|kill-buffer-query-fn)
+ (add-hook 'kill-buffer-query-functions #'+doom-dashboard|reload-on-kill)
(when (and (display-graphic-p) (not (daemonp)))
(let ((default-directory doom-emacs-dir))
(+doom-dashboard/open (selected-frame)))))
-(defun +doom-dashboard|kill-buffer-query-fn ()
- (or (not (+doom-dashboard-p))
- (ignore (let (+doom-dashboard-inhibit-refresh)
- (ignore-errors (+doom-dashboard-reload))))))
+(defun +doom-dashboard|reload-on-kill ()
+ "If this isn't a dashboard buffer, move along, but record its
+`default-directory' if the buffer is real. See `doom-real-buffer-p' for an
+explanation for what 'real' means.
+
+If this is the dashboard buffer, reload the dashboard."
+ (or (unless (+doom-dashboard-p)
+ (when (doom-real-buffer-p)
+ (setq +doom-dashboard--last-cwd default-directory)
+ (+doom-dashboard-update-pwd))
+ t)
+ (ignore
+ (let (+doom-dashboard-inhibit-refresh)
+ (ignore-errors (+doom-dashboard-reload))))))
(defun +doom-dashboard|make-frame (frame)
"Reload the dashboard after a brief pause. This is necessary for new frames,
@@ -85,55 +115,87 @@ whose dimensions may not be fully initialized by the time this is run."
(+doom-dashboard-reload)))
(setq +doom-dashboard-inhibit-refresh nil)))
+;
(defun +doom-dashboard-p (&optional buffer)
"Returns t if BUFFER is the dashboard buffer."
- (let ((buffer (or buffer (current-buffer))))
- (and (buffer-live-p buffer)
- (eq buffer (doom-fallback-buffer)))))
+ (eq (or buffer (current-buffer))
+ (doom-fallback-buffer)))
-(defun +doom-dashboard-center (len s)
- (concat (make-string (ceiling (max 0 (- len (length s))) 2) ? )
- s))
+(defun +doom-dashboard-update-pwd ()
+ "TODO"
+ (with-current-buffer (doom-fallback-buffer)
+ (cd (or (+doom-dashboard--get-pwd)
+ default-directory))))
-(defun +doom-dashboard-reload (&optional dir)
+(defun +doom-dashboard-reload (&optional force)
"Update the DOOM scratch buffer (or create it, if it doesn't exist)."
- (when (get-buffer-window (doom-fallback-buffer))
- (unless (or +doom-dashboard-inhibit-refresh
- (window-minibuffer-p (frame-selected-window)))
- (let ((old-pwd (or dir default-directory))
- (fallback-buffer (doom-fallback-buffer)))
- (with-current-buffer fallback-buffer
- (with-silent-modifications
- (unless (eq major-mode '+doom-dashboard-mode)
- (+doom-dashboard-mode))
- (erase-buffer)
- (setq default-directory old-pwd)
- (let ((+doom-dashboard--height (window-height (get-buffer-window fallback-buffer)))
- (lines 1)
- content)
- (with-temp-buffer
- (dolist (widget-name +doom-dashboard-widgets)
- (funcall (intern (format "doom-dashboard-widget--%s" widget-name)))
- (insert "\n"))
- (setq content (buffer-string)
- lines (count-lines (point-min) (point-max))))
- (insert (make-string (max 0 (- (/ +doom-dashboard--height 2)
- (/ lines 2)))
- ?\n)
- content))
- (unless (button-at (point))
- (goto-char (next-button (point-min))))))))
+ (let ((fallback-buffer (doom-fallback-buffer)))
+ (when (or (and after-init-time
+ (not +doom-dashboard-inhibit-refresh)
+ (get-buffer-window fallback-buffer)
+ (not (window-minibuffer-p (frame-selected-window))))
+ force)
+ (with-current-buffer fallback-buffer
+ (+doom-dashboard-update-pwd)
+ (with-silent-modifications
+ (unless (eq major-mode '+doom-dashboard-mode)
+ (+doom-dashboard-mode))
+ (erase-buffer)
+ (let ((+doom-dashboard--height
+ (window-height (get-buffer-window fallback-buffer)))
+ (lines 1)
+ content)
+ (with-temp-buffer
+ (dolist (widget-name +doom-dashboard-widgets)
+ (funcall (intern (format "doom-dashboard-widget--%s" widget-name)))
+ (insert "\n"))
+ (setq content (buffer-string)
+ lines (count-lines (point-min) (point-max))))
+ (insert (make-string (max 0 (- (/ +doom-dashboard--height 2)
+ (/ lines 2)))
+ ?\n)
+ content))
+ (unless (button-at (point))
+ (goto-char (next-button (point-min)))))))
;; Update all dashboard windows
- (dolist (win (get-buffer-window-list (doom-fallback-buffer) nil t))
+ (dolist (win (get-buffer-window-list fallback-buffer nil t))
(set-window-fringes win 0 0)
(set-window-margins
win (max 0 (/ (- (window-total-width win) +doom-dashboard--width) 2)))))
t)
+;; helpers
+(defun +doom-dashboard--center (len s)
+ (concat (make-string (ceiling (max 0 (- len (length s))) 2) ? )
+ s))
+
+(defun +doom-dashboard--get-pwd ()
+ (let ((lastcwd +doom-dashboard--last-cwd)
+ (policy +doom-dashboard-pwd-policy))
+ (cond ((null policy)
+ default-directory)
+ ((stringp policy)
+ (expand-file-name policy lastcwd))
+ ((functionp policy)
+ (funcall policy lastcwd))
+ ((null lastcwd)
+ default-directory)
+ ((eq policy 'last-project)
+ (let ((cwd default-directory)
+ (default-directory lastcwd))
+ (if (doom-project-p)
+ (doom-project-root)
+ cwd)))
+ ((eq policy 'last)
+ lastcwd)
+ (t
+ (warn "`+doom-dashboard-pwd-policy' has an invalid value of '%s'"
+ policy)))))
+
;; widgets
(defun doom-dashboard-widget--banner ()
(mapc (lambda (line)
- (insert (propertize (+doom-dashboard-center +doom-dashboard--width line)
+ (insert (propertize (+doom-dashboard--center +doom-dashboard--width line)
'face 'font-lock-comment-face) " ")
(insert "\n"))
'("================= =============== =============== ======== ========"
@@ -160,17 +222,15 @@ whose dimensions may not be fully initialized by the time this is run."
(insert
"\n"
(propertize
- (+doom-dashboard-center
+ (+doom-dashboard--center
+doom-dashboard--width
(format "Loaded %d packages in %d modules in %.02fs"
- (- (length load-path) (length doom--base-load-path))
+ (length doom--package-load-path)
(hash-table-size doom-modules)
(if (floatp doom-init-time) doom-init-time 0.0)))
'face 'font-lock-comment-face)
"\n"))
-(defvar all-the-icons-scale-factor)
-(defvar all-the-icons-default-adjust)
(defun doom-dashboard-widget--shortmenu ()
(let ((all-the-icons-scale-factor 1.45)
(all-the-icons-default-adjust -0.02))
@@ -184,7 +244,7 @@ whose dimensions may not be fully initialized by the time this is run."
(propertize (concat " " label) 'face 'font-lock-keyword-face))
'action `(lambda (_) ,fn)
'follow-link t)
- (+doom-dashboard-center (- +doom-dashboard--width 2) (buffer-string)))
+ (+doom-dashboard--center (- +doom-dashboard--width 2) (buffer-string)))
"\n\n"))))
`(("Homepage" "mark-github"
(browse-url "https://github.com/hlissner/doom-emacs"))
diff --git a/modules/ui/doom-dashboard/test/doom-dashboard.el b/modules/ui/doom-dashboard/test/doom-dashboard.el
new file mode 100644
index 000000000..b08188837
--- /dev/null
+++ b/modules/ui/doom-dashboard/test/doom-dashboard.el
@@ -0,0 +1,51 @@
+;; -*- no-byte-compile: t; -*-
+;;; ui/doom-dashboard/test/doom-dashboard.el
+
+(require! :ui doom-dashboard)
+(+doom-dashboard|init)
+
+(defun -dashboard-test-pwd (spec file)
+ (let ((kill-buffer-query-functions '(+doom-dashboard|reload-on-kill))
+ (+doom-dashboard-pwd-policy (car spec))
+ (fallback-buffer (doom-fallback-buffer))
+ +doom-dashboard--last-cwd
+ projectile-enable-caching)
+ (with-temp-buffer
+ (setq buffer-file-name file
+ default-directory (file-name-directory file)
+ doom-real-buffer-p t))
+ (should +doom-dashboard--last-cwd)
+ (+doom-dashboard-update-pwd)
+ (should (equal (buffer-local-value 'default-directory fallback-buffer)
+ (cdr spec)))))
+
+;;
+(def-test! dashboard-p
+ (let ((fallback-buffer (doom-fallback-buffer)))
+ (should (equal (buffer-name fallback-buffer) +doom-dashboard-name))
+ (should (+doom-dashboard-p fallback-buffer))
+ (with-current-buffer fallback-buffer
+ (should (+doom-dashboard-p)))))
+
+(def-test! get-pwd
+ (let ((default-directory doom-core-dir)
+ (+doom-dashboard--last-cwd doom-core-dir)
+ projectile-enable-caching)
+ (dolist (spec (list (cons 'last-project doom-emacs-dir)
+ (cons 'last doom-core-dir)
+ (cons (lambda (x) "x") "x")
+ (cons "~" (expand-file-name "~"))
+ (cons nil default-directory)))
+ (let ((+doom-dashboard-pwd-policy (car spec)))
+ (should (equal (+doom-dashboard--get-pwd) (cdr spec)))))))
+
+(def-test! pwd-policy
+ (dolist (spec (list (cons 'last-project doom-emacs-dir)
+ (cons 'last doom-core-dir)
+ (cons "~" (expand-file-name "~/"))
+ (cons (lambda (x) "/tmp") "/tmp/")))
+ (-dashboard-test-pwd spec (expand-file-name "core.el" doom-core-dir))))
+
+;;
+(def-test! inhibit-refresh :skip t)
+(def-test! inhibit-functions :skip t)