Merge branch 'develop'

* develop: (145 commits)
  v2.0.9 bump
  tools/neotree: refresh pane when jumping to it
  Fix doom module file templates when emacs.d is a symlink
  Update changelog
  ibuffer-use-other-window = t (hand off to popup system)
  Improve docstring for doom-real-buffer-functions
  Conform unit test macros to naming scheme
  Move doom*quit-window to core-editor
  feature/snippets: use default yas-snippet-dirs (harmless)
  lang/org: wrap smartparens config in after!
  Fix file template for Doom module readmes
  Fix some file-templates not being inserted
  lang/cc: fix irony-mode complaining in non-C modes, like php-mode
  Update & reformat module readmes for v2.0.9
  Minor, general refactor & comment updates
  +jump/documentation: always prompt for provider with online fallback
  core-projects: refactor projectile var init
  Refactor doom/info
  Fix interactive usage of doom//byte-compile-core
  Fix async package functions not running from right cwd
  ...
This commit is contained in:
Henrik Lissner 2018-01-01 21:24:01 -05:00
commit 5dacbb7cb1
88 changed files with 2547 additions and 2018 deletions

39
.github/ISSUE_TEMPLATE vendored Normal file
View file

@ -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
<details>
<summary>Click to expand</summary>
```
Replace this line with the output of *one* of these commands:
+ `M-x doom/info` (from inside Emacs)
+ `DEBUG=1 make doctor` (command line)
```
</details>

5
.github/PULL_REQUEST_TEMPLATE vendored Normal file
View file

@ -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.

1
.gitignore vendored
View file

@ -2,6 +2,7 @@
.cask/ .cask/
var/ var/
/init.el /init.el
modules/private/
# emacs tempfiles that shouldn't be there # emacs tempfiles that shouldn't be there
.mc-lists.el .mc-lists.el

View file

@ -12,6 +12,91 @@
- [[#200-jan-17-2017][2.0.0 (Jan 17, 2017)]] - [[#200-jan-17-2017][2.0.0 (Jan 17, 2017)]]
* Unreleased (develop) * 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) * 2.0.8 (Dec 09, 2017)
+ *Module changes:* + *Module changes:*

View file

@ -8,6 +8,7 @@
;; In case it isn't defined (in really old versions of Emacs, like the one that ;; In case it isn't defined (in really old versions of Emacs, like the one that
;; ships with MacOS). ;; ships with MacOS).
(defvar user-emacs-directory (expand-file-name "~/.emacs.d/")) (defvar user-emacs-directory (expand-file-name "~/.emacs.d/"))
(defvar doom-debug-mode (getenv "DEBUG"))
(unless (equal (expand-file-name user-emacs-directory) (unless (equal (expand-file-name user-emacs-directory)
(expand-file-name "~/.emacs.d/")) (expand-file-name "~/.emacs.d/"))
@ -15,14 +16,20 @@
(require 'pp) (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-init-p nil)
(defvar doom-errors 0) (defvar doom-errors 0)
(defmacro check! (cond &rest body) (defmacro check! (cond &rest body)
(declare (indent defun)) (declare (indent defun))
`(when ,cond `(let ((it ,cond))
(when it
,@body ,@body
(setq doom-errors (1+ doom-errors)))) (setq doom-errors (1+ doom-errors)))))
(defun indented (spc msg) (defun indented (spc msg)
(declare (indent defun)) (declare (indent defun))
@ -57,26 +64,18 @@
"\n"))) "\n")))
(buffer-string))) (buffer-string)))
(defmacro wait-for! (var if-body &optional else-body) (defun sh (cmd)
(declare (indent defun)) (string-trim-right (shell-command-to-string cmd)))
`(let ((i 0))
(while (and (not ,var)
(< i 5))
(sleep-for 1)
(setq i (1+ i)))
(if ,var
,if-body
,else-body)))
(defun color (code msg &rest args) (defun color (code msg &rest args)
(format "\e[%dm%s\e[%dm" code (apply #'format msg args) 0)) (format "\e[%dm%s\e[%dm" code (apply #'format msg args) 0))
(defalias 'msg! #'message) (defalias 'msg! #'message)
(defmacro error! (&rest args) `(message (color 1 (color 31 ,@args)))) (defmacro error! (&rest args) `(msg! (color 1 (color 31 ,@args))))
(defmacro warn! (&rest args) `(message (color 1 (color 33 ,@args)))) (defmacro warn! (&rest args) `(msg! (color 1 (color 33 ,@args))))
(defmacro success! (&rest args) `(message (color 1 (color 32 ,@args)))) (defmacro success! (&rest args) `(msg! (color 1 (color 32 ,@args))))
(defmacro log! (&rest args) `(if doom-debug-mode (message (color 34 ,@args)))) (defmacro section! (&rest args) `(msg! (color 34 ,@args)))
(defmacro explain! (&rest args) `(message (indented 2 (autofill ,@args)))) (defmacro explain! (&rest args) `(msg! (indented 2 (autofill ,@args))))
;;; Polyfills ;;; Polyfills
;; early versions of emacs won't have this ;; early versions of emacs won't have this
@ -88,15 +87,21 @@
;; --- start a'doctorin' -------------------------------------- ;; --- 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 "DOOM Doctor")
(color 1 emacs-version) (color 1 emacs-version)
(if (executable-find "git") (if (executable-find "git")
(shell-command-to-string "git rev-parse HEAD") (sh "git rev-parse HEAD")
"n/a")) "n/a"))
(msg! "shell: %s%s"
(getenv "SHELL")
(if (equal (getenv "SHELL") (sh "echo $SHELL"))
""
(color 31 " (mismatch)")))
(when (boundp 'system-configuration-features) (when (boundp 'system-configuration-features)
(msg! "Compiled with:\n%s" (indented 2 (autofill 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) (let (doom-core-packages doom-debug-mode)
(condition-case ex (condition-case ex
@ -108,11 +113,10 @@
(doom|finalize) (doom|finalize)
(success! "Attempt to load DOOM: success! Loaded v%s" doom-version) (success! "Attempt to load DOOM: success! Loaded v%s" doom-version)
(when (executable-find "git") (when (executable-find "git")
(msg! "Revision %s" (msg! "Revision %s\n"
(or (ignore-errors (ignore-errors
(let ((default-directory user-emacs-directory)) (let ((default-directory user-emacs-directory))
(shell-command-to-string "git rev-parse HEAD"))) (sh "git rev-parse HEAD"))))))
"\n"))))
('error (warn! "Attempt to load DOOM: failed\n %s\n" ('error (warn! "Attempt to load DOOM: failed\n %s\n"
(or (cdr-safe ex) (car ex)))))) (or (cdr-safe ex) (car ex))))))
@ -120,7 +124,7 @@
;; --- is emacs set up properly? ------------------------------ ;; --- is emacs set up properly? ------------------------------
(log! "test-emacs") (section! "test-emacs")
(check! (version< emacs-version "25.1") (check! (version< emacs-version "25.1")
(error! "Important: Emacs %s detected [%s]" emacs-version (executable-find "emacs")) (error! "Important: Emacs %s detected [%s]" emacs-version (executable-find "emacs"))
(explain! (explain!
@ -133,13 +137,13 @@
;; --- is the environment set up properly? -------------------- ;; --- is the environment set up properly? --------------------
;; windows? windows ;; windows? windows
(log! "test-windows") (section! "test-windows")
(check! (memq system-type '(windows-nt ms-dos cygwin)) (check! (memq system-type '(windows-nt ms-dos cygwin))
(warn! "Warning: Windows detected") (warn! "Warning: Windows detected")
(explain! "DOOM was designed for MacOS and Linux. Expect a bumpy ride!")) (explain! "DOOM was designed for MacOS and Linux. Expect a bumpy ride!"))
;; are all default fonts present ;; are all default fonts present
(log! "test-fonts") (section! "test-fonts")
(if (not (fboundp 'find-font)) (if (not (fboundp 'find-font))
(progn (progn
(warn! "Warning: unable to detect font") (warn! "Warning: unable to detect font")
@ -162,19 +166,19 @@
"case, ignore this warning.")))))) "case, ignore this warning."))))))
;; gnutls-cli & openssl ;; gnutls-cli & openssl
(log! "test-gnutls") (section! "test-gnutls")
(cond ((executable-find "gnutls-cli")) (cond ((executable-find "gnutls-cli"))
((executable-find "openssl") ((executable-find "openssl")
(let* ((output (shell-command-to-string "openssl ciphers -v")) (let* ((output (sh "openssl ciphers -v"))
(protocols (protocols
(let (protos) (let (protos)
(mapcar (lambda (row) (mapcar (lambda (row)
(add-to-list 'protos (cadr (split-string row " " t)))) (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)))) (delq nil protos))))
(check! (not (or (member "TLSv1.1" protocols) (check! (not (or (member "TLSv1.1" protocols)
(member "TLSv1.2" 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) (warn! "Warning: couldn't find gnutls-cli, and OpenSSL is out-of-date (v%s)" version)
(explain! (explain!
"This may not affect your Emacs experience, but there are security " "This may not affect your Emacs experience, but there are security "
@ -198,7 +202,7 @@
"network, provider, government, neckbearded mother-in-laws, geeky roommates, " "network, provider, government, neckbearded mother-in-laws, geeky roommates, "
"or just about anyone who knows more about computers than you do!")))) "or just about anyone who knows more about computers than you do!"))))
(log! "test-tls") (section! "test-tls")
(cond ((not (string-match-p "\\_<GNUTLS\\_>" system-configuration-features)) (cond ((not (string-match-p "\\_<GNUTLS\\_>" system-configuration-features))
(warn! "Warning: You didn't install Emacs with gnutls support") (warn! "Warning: You didn't install Emacs with gnutls support")
(explain! (explain!
@ -211,53 +215,50 @@
" brew tap d12frosted/emacs-plus" " brew tap d12frosted/emacs-plus"
" brew install 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") ((or (executable-find "gnutls-cli")
(executable-find "openssl")) (executable-find "openssl"))
(let ((tls-checktrust t) (let ((tls-checktrust t)
(gnutls-verify-error t)) (gnutls-verify-error t))
(dolist (url '("https://elpa.gnu.org" (dolist (url '("https://elpa.gnu.org" "https://melpa.org"))
"https://melpa.org")) (check! (condition-case-unless-debug e
(condition-case-unless-debug ex (if (let ((inhibit-message t)) (url-retrieve-synchronously url))
(let (result) (ignore (success! "Validated %s" url))
(let ((inhibit-message t)) 'empty)
(url-retrieve url (lambda (status &rest _) (setq result status)))) ('timed-out 'timeout)
(wait-for! result ('error e))
(when (getenv "DEBUG") (pcase it
(success! "Verified %s" (nth 2 (split-string url "/")))) (`empty (error! "Couldn't reach %s" url))
(signal 'timed-out url))) (`timeout (error! "Timed out trying to contact %s" ex))
('timed-out (_
(error! "Timed out trying to contact %s" ex)) (error! "Failed to validate %s" url)
('error (when doom-debug-mode
(check! t (explain! (pp-to-string it)))))))
(error! "Rejected %s" url)
(explain! (pp-to-string ex))))))
(dolist (url '("https://self-signed.badssl.com" (dolist (url '("https://self-signed.badssl.com"
"https://wrong.host.badssl.com/")) "https://wrong.host.badssl.com/"))
(condition-case-unless-debug ex (check! (condition-case-unless-debug e
(let (result) (if (let ((inhibit-message t)) (url-retrieve-synchronously url))
(let ((inhibit-message t)) t
(url-retrieve url (lambda (status &rest _) (setq result status)))) 'empty)
(wait-for! result ('timed-out 'timeout)
(check! t ('error (ignore (success! "Successfully rejected %s" url))))
(warn! "Verified %s (this shouldn't happen!)" (nth 2 (split-string url "/"))) (pcase it
(explain! (pp-to-string result))) (`empty (error! "Couldn't reach %s" url))
(signal 'timed-out url))) (`timeout (error! "Timed out trying to contact %s" ex))
('timed-out (_
(error! "Timed out trying to contact %s" ex)) (error! "Validated %s (this shouldn't happen!)" url)))))))
('error
(when (getenv "DEBUG")
(success! "Rejected %s (a good thing!)" url)
(explain! (pp-to-string ex))))))))
(t (t
(error! "Nope!"))) (error! "Nope!")))
;; bsd vs gnu tar ;; bsd vs gnu tar
(log! "test-tar") (section! "test-tar")
(let ((tar-bin (or (executable-find "gtar") (let ((tar-bin (or (executable-find "gtar")
(executable-find "tar")))) (executable-find "tar"))))
(if tar-bin (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") (warn! "Warning: BSD tar detected")
(explain! (explain!
"QUELPA (through package-build) uses the system tar to build plugins, but it " "QUELPA (through package-build) uses the system tar to build plugins, but it "
@ -275,7 +276,7 @@
;; --- report! ------------------------------------------------ ;; --- report! ------------------------------------------------
(when (getenv "DEBUG") (when doom-debug-mode
(msg! "\n====\nHave some debug information:\n") (msg! "\n====\nHave some debug information:\n")
(when (bound-and-true-p doom-modules) (when (bound-and-true-p doom-modules)
@ -290,11 +291,12 @@
(msg! " + enabled packages:\n%s" (msg! " + enabled packages:\n%s"
(indented 4 (indented 4
(columns 2 35 (columns 2 35
(delq nil
(mapcar (lambda (pkg) (mapcar (lambda (pkg)
(let ((desc (cadr (assq pkg package-alist)))) (let ((desc (cadr (assq pkg package-alist))))
(when desc (when desc
(package-desc-full-name desc)))) (package-desc-full-name desc))))
(sort (mapcar #'car doom-packages) #'string-lessp)))))) (sort (mapcar #'car doom-packages) #'string-lessp)))))))
(msg! " + byte-compiled files:\n%s" (msg! " + byte-compiled files:\n%s"
(indented 4 (indented 4
@ -318,7 +320,7 @@
(success! "Everything seems fine, happy Emacs'ing!") (success! "Everything seems fine, happy Emacs'ing!")
(message "\n----") (message "\n----")
(warn! "There were issues!") (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! "\nHopefully these can help you find problems. If not, run this doctor again with DEBUG=1:")
(msg! "\n DEBUG=1 make doctor\n") (msg! "\n DEBUG=1 make doctor\n")
(msg! "And file a bug report with its output at https://github.com/hlissner/.emacs.d/issues"))) (msg! "And file a bug report with its output at https://github.com/hlissner/.emacs.d/issues")))

View file

@ -4,8 +4,12 @@
;;;###autoload ;;;###autoload
(defvar doom-real-buffer-functions '() (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 (defvar-local doom-real-buffer-p nil
"If non-nil, this buffer should be considered real no matter what.") "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 "The name of the buffer to fall back to if no other buffers exist (will create
it if it doesn't exist).") it if it doesn't exist).")
;;
;; Functions
;;
;;;###autoload ;;;###autoload
(defun doom-fallback-buffer () (defun doom-fallback-buffer ()
"Returns the fallback buffer, creating it if necessary. By default this is the "Returns the fallback buffer, creating it if necessary. By default this is the
scratch buffer." scratch buffer."
(get-buffer-create doom-fallback-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 ;;;###autoload
(defalias 'doom-buffer-list #'buffer-list) (defalias 'doom-buffer-list #'buffer-list)
@ -66,6 +51,28 @@ If no project is active, return all buffers."
if (doom-real-buffer-p buf) if (doom-real-buffer-p buf)
collect 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 ;;;###autoload
(defun doom-buffers-in-mode (modes &optional buffer-list derived-p) (defun doom-buffers-in-mode (modes &optional buffer-list derived-p)
"Return a list of buffers whose `major-mode' is `eq' to MODE(S). "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 "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 buffers. If there's nothing left, switch to `doom-fallback-buffer'. See
`doom-real-buffer-p' for what 'real' means." `doom-real-buffer-p' for what 'real' means."
(let ((buffers (delq (current-buffer) (doom-real-buffer-list))) (let ((buffers (delq (current-buffer) (doom-real-buffer-list))))
(project-dir (doom-project-root)))
(cond ((or (not buffers) (cond ((or (not buffers)
(zerop (% n (1+ (length buffers))))) (zerop (% n (1+ (length buffers)))))
(switch-to-buffer (doom-fallback-buffer) nil t)) (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 do
(dotimes (_i (abs n)) (dotimes (_i (abs n))
(funcall move-func))))) (funcall move-func)))))
(when (eq (current-buffer) (doom-fallback-buffer)) (force-mode-line-update)
(cd project-dir))
(current-buffer))) (current-buffer)))
;;;###autoload ;;;###autoload
(defun doom-real-buffer-p (&optional buffer-or-name) (defun doom-set-buffer-real (buffer flag)
"Returns t if BUFFER-OR-NAME is a 'real' buffer. The complete criteria for a "Forcibly mark BUFFER as FLAG (non-nil = real)."
real buffer is: (with-current-buffer buffer
(setq doom-real-buffer-p flag)))
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))
;;;###autoload ;;;###autoload
(defun doom-kill-buffer (&optional buffer dont-save) (defun doom-kill-buffer (&optional buffer dont-save)
"Kill BUFFER (falls back to current buffer if omitted) then switch to a real "Kill BUFFER (defaults to current buffer), but make sure we land on a real
buffer. If the buffer is present in another window, only bury it. buffer. Bury the buffer if the buffer is present in another window.
Will prompt to save unsaved buffers when attempting to kill them, unless Will prompt to save unsaved buffers when attempting to kill them, unless
DONT-SAVE is non-nil. DONT-SAVE is non-nil.
See `doom-real-buffer-p' for what 'real' means." See `doom-real-buffer-p' for what 'real' means."
(setq buffer (or buffer (current-buffer))) (unless buffer
(when (and (bufferp buffer) (buffer-live-p buffer)) (setq buffer (current-buffer)))
(let ((buffer-win (get-buffer-window buffer)) (when (and (bufferp buffer)
(only-buffer-window-p (= 1 (length (get-buffer-window-list buffer nil t))))) (buffer-live-p buffer))
;; deal with unsaved buffers (let ((buffer-win (get-buffer-window buffer)))
(when (and only-buffer-window-p ;; deal with modified buffers
(buffer-file-name buffer) (when (and (buffer-file-name buffer)
(buffer-modified-p buffer)) (buffer-modified-p buffer))
(with-current-buffer buffer (with-current-buffer buffer
(if (and (not dont-save) (if (and (not dont-save)
(yes-or-no-p "Buffer is unsaved, save it?")) (yes-or-no-p "Buffer is unsaved, save it?"))
(save-buffer) (save-buffer)
(set-buffer-modified-p nil)))) (set-buffer-modified-p nil))))
(if buffer-win ;; kill the buffer (or close dedicated window)
;; deal with dedicated windows (cond ((not buffer-win)
(if (window-dedicated-p buffer-win) (kill-buffer buffer))
((window-dedicated-p buffer-win)
(unless (window--delete buffer-win t t) (unless (window--delete buffer-win t t)
(split-window buffer-win) (split-window buffer-win)
(window--delete buffer-win t t)) (window--delete buffer-win t t)))
;; cycle to a real buffer (t ; cycle to a real buffer
(with-selected-window buffer-win (with-selected-window buffer-win
(doom--cycle-real-buffers -1) (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))))) (kill-buffer buffer)))))
(not (eq (current-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))))))
;;;###autoload ;;;###autoload
(defun doom-kill-buffer-and-windows (buffer) (defun doom-kill-buffer-and-windows (buffer)
@ -229,23 +188,6 @@ switched to a real buffer."
(delete-window window))) (delete-window window)))
(kill-buffer buffer)) (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 ;;;###autoload
(defun doom-kill-matching-buffers (pattern &optional buffer-list) (defun doom-kill-matching-buffers (pattern &optional buffer-list)
"Kill all buffers (in current workspace OR in BUFFER-LIST) that match the "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)) (dolist (buf buffers (length buffers))
(doom-kill-buffer buf t)))) (doom-kill-buffer buf t))))
;;
;; Interactive commands
;;
;;;###autoload ;;;###autoload
(defun doom/kill-this-buffer () (defun doom/kill-this-buffer (&optional interactive-p)
"Use `doom-kill-buffer' on the current buffer." "Use `doom-kill-buffer' on the current buffer."
(interactive) (interactive (list 'interactive))
(when (and (not (doom-kill-buffer)) (called-interactively-p 'interactive)) (when (and (not (doom-kill-buffer)) interactive-p)
(message "Nowhere left to go!"))) (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 ;;;###autoload
(defun doom/kill-all-buffers (&optional project-p) (defun doom/kill-all-buffers (&optional project-p)
"Kill all buffers and closes their windows. "Kill all buffers and closes their windows.
@ -305,18 +267,46 @@ project."
(message "Killed %s buffers" n)))) (message "Killed %s buffers" n))))
;;;###autoload ;;;###autoload
(defun doom/cleanup-buffers (&optional all-p) (defun doom/cleanup-session (&optional all-p)
"Clean up buried and inactive process buffers in the current workspace." "Clean up buried buries and orphaned processes in the current workspace. If
ALL-P (universal argument), clean them up globally."
(interactive "P") (interactive "P")
(run-hooks 'doom-cleanup-hook)
(let ((buffers (doom-buried-buffers (if all-p (buffer-list)))) (let ((buffers (doom-buried-buffers (if all-p (buffer-list))))
(n 0)) (n 0)
kill-buffer-query-functions)
(mapc #'kill-buffer buffers) (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) (when (called-interactively-p 'interactive)
(message "Cleaned up %s buffers" n)))) (message "Cleaned up %s buffers" n))))
;;;###autoload ;;;###autoload
(defun doom-set-buffer-real (buffer flag) (defun doom/cleanup-processes ()
"Forcibly mark a buffer's real property, no matter what." "Kill all processes that have no visible associated buffers. Return number of
(with-current-buffer buffer processes killed."
(setq doom-real-buffer-p flag))) (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))

View file

@ -65,7 +65,7 @@ selection of all minor-modes, active or not."
in '("https://wrong.host.badssl.com/" in '("https://wrong.host.badssl.com/"
"https://self-signed.badssl.com/") "https://self-signed.badssl.com/")
if (condition-case _e if (condition-case _e
(url-retrieve bad (lambda (_retrieved) t)) (url-retrieve-synchronously bad)
(error nil)) (error nil))
collect bad))) collect bad)))
(error (format "tls seems to be misconfigured (it got %s)." (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-report)
(profiler-stop)) (profiler-stop))
(setq doom--profiler (not doom--profiler))) (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!")))

View file

@ -2,7 +2,7 @@
;;;###autoload ;;;###autoload
(defun doom/sudo-find-file (file) (defun doom/sudo-find-file (file)
"Open a file as root." "Open FILE as root."
(interactive (interactive
(list (read-file-name "Open as root: "))) (list (read-file-name "Open as root: ")))
(find-file (if (file-writable-p file) (find-file (if (file-writable-p file)
@ -218,8 +218,29 @@ consistent throughout a selected region, depending on `indent-tab-mode'."
(tabify beg end) (tabify beg end)
(untabify 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 ;;;###autoload
(defun doom|enable-delete-trailing-whitespace () (defun doom|enable-delete-trailing-whitespace ()
"Attaches `delete-trailing-whitespace' to a buffer-local `before-save-hook'." "Attaches `delete-trailing-whitespace' to a buffer-local `before-save-hook'."
(add-hook 'before-save-hook #'delete-trailing-whitespace nil t)) (add-hook 'before-save-hook #'delete-trailing-whitespace nil t))

View file

@ -1,11 +1,13 @@
;;; core/autoload/packages.el -*- lexical-binding: t; -*- ;;; core/autoload/packages.el -*- lexical-binding: t; -*-
(require 'use-package)
(require 'quelpa)
(defvar doom--last-refresh nil) (defvar doom--last-refresh nil)
;;;###autoload ;;;###autoload
(defun doom-refresh-packages (&optional force-p) (defun doom-refresh-packages (&optional force-p)
"Refresh ELPA packages." "Refresh ELPA packages."
(doom-initialize)
(when force-p (when force-p
(doom-refresh-clear-cache)) (doom-refresh-clear-cache))
(unless (or (persistent-soft-fetch 'last-pkg-refresh "emacs") (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 "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." quelpa. Throws an error if NOERROR is nil and the package isn't installed."
(cl-assert (symbolp name) t) (cl-assert (symbolp name) t)
(doom-initialize)
(cond ((and (or (quelpa-setup-p) (cond ((and (or (quelpa-setup-p)
(error "Could not initialize quelpa")) (error "Could not initialize quelpa"))
(assq name quelpa-cache)) (assq name quelpa-cache))
'quelpa) 'quelpa)
((assq name package-alist) ((assq name package-alist)
'elpa) 'elpa)
((package-built-in-p name)
'emacs)
((not noerror) ((not noerror)
(error "%s package is not installed" name)))) (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) (doom-initialize-packages)
(and (package-installed-p name) (and (package-installed-p name)
(let* ((plist (cdr (assq name doom-packages))) (let* ((plist (cdr (assq name doom-packages)))
(old-backend (doom-package-backend name t)) (old-backend (doom-package-backend name 'noerror))
(new-backend (if (plist-get plist :recipe) 'quelpa 'elpa))) (new-backend (if (plist-get plist :recipe) 'quelpa 'elpa)))
(not (eq old-backend new-backend))))) (not (eq old-backend new-backend)))))
@ -114,14 +117,12 @@ If INSTALLED-ONLY-P, only return packages that are installed."
;;;###autoload ;;;###autoload
(defun doom-get-depending-on (name) (defun doom-get-depending-on (name)
"Return a list of packages that depend on the package named NAME." "Return a list of packages that depend on the package named NAME."
(doom-initialize)
(when-let* ((desc (cadr (assq name package-alist)))) (when-let* ((desc (cadr (assq name package-alist))))
(mapcar #'package-desc-name (package--used-elsewhere-p desc nil t)))) (mapcar #'package-desc-name (package--used-elsewhere-p desc nil t))))
;;;###autoload ;;;###autoload
(defun doom-get-dependencies-for (name &optional only) (defun doom-get-dependencies-for (name &optional only)
"Return a list of dependencies for a package." "Return a list of dependencies for a package."
(doom-initialize)
(package--get-deps name only)) (package--get-deps name only))
;;;###autoload ;;;###autoload
@ -156,8 +157,9 @@ Used by `doom//packages-update'."
(load ,(expand-file-name "core.el" doom-core-dir))) (load ,(expand-file-name "core.el" doom-core-dir)))
(doom-package-outdated-p ',pkg))) (doom-package-outdated-p ',pkg)))
futures)) futures))
(append (delq nil (mapcar #'doom-package-outdated-p elpa-pkgs)) (delq nil
(delq nil (mapcar #'async-get (reverse futures))))))) (append (mapcar #'doom-package-outdated-p elpa-pkgs)
(mapcar #'async-get (reverse futures)))))))
;;;###autoload ;;;###autoload
(defun doom-get-orphaned-packages () (defun doom-get-orphaned-packages ()
@ -170,7 +172,8 @@ Used by `doom//packages-autoremove'."
(append (mapcar #'car doom-packages) doom-core-packages))) (append (mapcar #'car doom-packages) doom-core-packages)))
(append (package--removable-packages) (append (package--removable-packages)
(cl-loop for pkg in package-selected-packages (cl-loop for pkg in package-selected-packages
if (doom-package-different-backend-p pkg) if (and (doom-package-different-backend-p pkg)
(not (package-built-in-p pkg)))
collect pkg)))) collect pkg))))
;;;###autoload ;;;###autoload
@ -213,7 +216,6 @@ Used by `doom//packages-install'."
(symbol-name (car other)))) (symbol-name (car other))))
(defun doom--packages-choose (prompt) (defun doom--packages-choose (prompt)
(doom-initialize)
(let ((table (cl-loop for pkg in package-alist (let ((table (cl-loop for pkg in package-alist
unless (package-built-in-p (cdr pkg)) unless (package-built-in-p (cdr pkg))
collect (cons (package-desc-full-name (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) (defun doom-update-package (name &optional force-p)
"Updates package NAME (a symbol) if it is out of date, using quelpa or "Updates package NAME (a symbol) if it is out of date, using quelpa or
package.el as appropriate." package.el as appropriate."
(doom-initialize)
(unless (package-installed-p name) (unless (package-installed-p name)
(user-error "%s isn't installed" name)) (user-error "%s isn't installed" name))
(when (doom-package-different-backend-p name) (when (doom-package-different-backend-p name)
@ -298,7 +299,6 @@ package.el as appropriate."
(defun doom-delete-package (name &optional force-p) (defun doom-delete-package (name &optional force-p)
"Uninstalls package NAME if it exists, and clears it from `quelpa-cache'." "Uninstalls package NAME if it exists, and clears it from `quelpa-cache'."
(doom-initialize)
(unless (package-installed-p name) (unless (package-installed-p name)
(user-error "%s isn't installed" name)) (user-error "%s isn't installed" name))
(let ((inhibit-message (not doom-debug-mode)) (let ((inhibit-message (not doom-debug-mode))
@ -318,13 +318,14 @@ package.el as appropriate."
;; ;;
;; Interactive commands ;; Batch/interactive commands
;; ;;
;;;###autoload ;;;###autoload
(defun doom//packages-install () (defun doom//packages-install ()
"Interactive command for installing missing packages." "Interactive command for installing missing packages."
(interactive) (interactive)
(message! "Looking for packages to install...")
(let ((packages (doom-get-missing-packages))) (let ((packages (doom-get-missing-packages)))
(cond ((not packages) (cond ((not packages)
(message! (green "No packages to install!"))) (message! (green "No packages to install!")))
@ -357,17 +358,17 @@ package.el as appropriate."
(message! "%s%s" (message! "%s%s"
(cond ((and (package-installed-p (car pkg)) (cond ((and (package-installed-p (car pkg))
(not (doom-package-different-backend-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)) ((doom-install-package (car pkg) (cdr pkg))
(green "DONE")) (green "DONE"))
(t (t
(red "FAILED"))) (red "FAILED")))
(if (plist-member (cdr pkg) :pin) (if (plist-member (cdr pkg) :pin)
(format " [pinned: %s]" (plist-get (cdr pkg) :pin)) (format " [pinned: %s]" (plist-get (cdr pkg) :pin))
""))))) ""))))
(message! (bold (green "Finished!"))) (message! (bold (green "Finished!")))
(doom//reload-load-path)))) (doom//reload-load-path)))))
;;;###autoload ;;;###autoload
(defun doom//packages-update () (defun doom//packages-update ()
@ -404,8 +405,7 @@ package.el as appropriate."
(message! (message!
(let ((result (doom-update-package (car pkg) t))) (let ((result (doom-update-package (car pkg) t)))
(color (if result 'green 'red) (color (if result 'green 'red)
" %s" (if result "✓ DONE" "✕ FAILED"))))))
(if result "DONE" "FAILED"))))))
(message! (bold (green "Finished!"))) (message! (bold (green "Finished!")))
(doom//reload-load-path))))) (doom//reload-load-path)))))
@ -414,27 +414,26 @@ package.el as appropriate."
(defun doom//packages-autoremove () (defun doom//packages-autoremove ()
"Interactive command for auto-removing orphaned packages." "Interactive command for auto-removing orphaned packages."
(interactive) (interactive)
(message! "Looking for orphaned packages...")
(let ((packages (doom-get-orphaned-packages))) (let ((packages (doom-get-orphaned-packages)))
(cond ((not packages) (cond ((not packages)
(message! (green "No unused packages to remove"))) (message! (green "No unused packages to remove")))
((not (or (getenv "YES") ((not
(or (getenv "YES")
(y-or-n-p (y-or-n-p
(format "%s packages will be deleted:\n\n%s\n\nProceed?" (format
"%s packages will be deleted:\n\n%s\n\nProceed?"
(length packages) (length packages)
(mapconcat (mapconcat
(lambda (sym) (lambda (sym)
(format (format "+ %s (%s)" sym
"+ %s (%s)"
sym
(let ((backend (doom-package-backend sym))) (let ((backend (doom-package-backend sym)))
(if (doom-package-different-backend-p sym) (if (doom-package-different-backend-p sym)
(if (eq backend 'quelpa) (if (eq backend 'quelpa)
"QUELPA->ELPA" "QUELPA->ELPA"
"ELPA->QUELPA") "ELPA->QUELPA")
(if (eq backend 'quelpa) (upcase (symbol-name backend))))))
"QUELPA"
"ELPA")))))
(sort (cl-copy-list packages) #'string-lessp) (sort (cl-copy-list packages) #'string-lessp)
"\n"))))) "\n")))))
(message! (yellow "Aborted!"))) (message! (yellow "Aborted!")))
@ -446,13 +445,17 @@ package.el as appropriate."
(let ((result (doom-delete-package pkg t))) (let ((result (doom-delete-package pkg t)))
(color (if result 'green 'red) (color (if result 'green 'red)
"%s %s" "%s %s"
(if result "Removed" "Failed to remove") (if result "Removed" "Failed to remove")
pkg))))) pkg)))))
(message! (bold (green "Finished!"))) (message! (bold (green "Finished!")))
(doom//reload-load-path))))) (doom//reload-load-path)))))
;;
;; Interactive commands
;;
;;;###autoload ;;;###autoload
(defalias 'doom/install-package #'package-install) (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 (package-installed-p package)
(if (y-or-n-p (format "%s will be deleted. Confirm?" package)) (if (y-or-n-p (format "%s will be deleted. Confirm?" package))
(message "%s %s" (message "%s %s"
(if (doom-delete-package package t) "Deleted" "Failed to delete") (if (doom-delete-package package t)
"Deleted"
"Failed to delete")
package) package)
(message "Aborted")) (message "Aborted"))
(message "%s isn't installed" package)))) (message "%s isn't installed" package))))

View file

@ -239,7 +239,7 @@ without leaving any trace behind (muahaha)."
(if (featurep 'evil) (if (featurep 'evil)
#'evil-force-normal-state #'evil-force-normal-state
#'keyboard-quit)) #'keyboard-quit))
(delete-window))) (quit-restore-window nil 'kill)))
;;;###autoload ;;;###autoload
(defun doom/popup-this-buffer () (defun doom/popup-this-buffer ()
@ -413,12 +413,4 @@ properties."
(when (doom-popup-p window) (when (doom-popup-p window)
(setq doom-popup-windows (delq window doom-popup-windows)) (setq doom-popup-windows (delq window doom-popup-windows))
(when doom-popup-remember-history (when doom-popup-remember-history
(setq doom-popup-history (list (doom--popup-data window)))) (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)))))))

View file

@ -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, Requires the corresponding client, e.g. git for git repos, hg for mercurial,
etc." etc."
(let* ((command (pcase fetcher (let* ((command (pcase fetcher
(:github "git clone --depth 1 --recursive https://github.com/%s.git") (:github "git clone --recursive https://github.com/%s.git")
(:git "git clone --depth 1 --recursive %s") (:git "git clone --recursive %s")
(:gist "git clone https://gist.github.com/%s.git") (:gist "git clone https://gist.github.com/%s.git")
;; TODO Add hg ;; TODO Add hg
(_ (error "%s is not a valid fetcher" fetcher)))) (_ (error "%s is not a valid fetcher" fetcher))))
@ -61,8 +61,8 @@ etc."
(error "%s couldn't be found" command)) (error "%s couldn't be found" command))
(unless (file-directory-p dest) (unless (file-directory-p dest)
(funcall (if noninteractive (funcall (if noninteractive
(lambda (&rest args) (princ (shell-command-to-string args))) (lambda (c) (princ (shell-command-to-string c)))
#'async-shell-command) #'async-shell-command)
(format "%s %s %s" bin args (shell-quote-argument dest))) (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)))))

View file

@ -74,17 +74,32 @@ If neither is available, run all tests in all enabled modules."
(defmacro def-test! (name &rest body) (defmacro def-test! (name &rest body)
"Define a namespaced ERT test." "Define a namespaced ERT test."
(declare (indent defun) (doc-string 2)) (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 `(ert-deftest
,(cl-loop with path = (file-relative-name (file-name-sans-extension load-file-name) ,(cl-loop with path = (file-relative-name (file-name-sans-extension load-file-name)
doom-emacs-dir) doom-emacs-dir)
for (rep . with) in '(("/test/" . "/") ("/" . ":")) for (rep . with) in '(("/test/" . "/") ("/" . ":"))
do (setq path (replace-regexp-in-string rep with path t t)) do (setq path (replace-regexp-in-string rep with path t t))
finally return (intern (format "%s::%s" path name))) () finally return (intern (format "%s::%s" path name)))
() ()
,@body))) (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. "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 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) (lambda (m1 m2) (< (marker-position m1)
(marker-position m2)))) (marker-position m2))))
(when (equal (caar marker-list) "0") (when (equal (caar marker-list) "0")
(goto-char! 0))) (goto-char!! 0)))
,@body ,@body
(let ((result-text (buffer-substring-no-properties (point-min) (point-max))) (let ((result-text (buffer-substring-no-properties (point-min) (point-max)))
(point (point)) (point (point))
@ -130,15 +145,22 @@ against."
(should (equal expected-text result-text)) (should (equal expected-text result-text))
(should same-point))))))) (should same-point)))))))
(defmacro goto-char! (index) (defmacro goto-char!! (index)
"Meant to be used with `should-buffer!'. Will move the cursor to one of the "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)." cursor markers. e.g. Go to marker {2} with (goto-char!! 2)."
`(goto-char (point! ,index))) `(goto-char (point!! ,index)))
(defmacro point! (index) (defmacro point!! (index)
"Meant to be used with `should-buffer!'. Returns the position of a cursor "Meant to be used with `should-buffer!!'. Returns the position of a cursor
marker. e.g. {2} can be retrieved with (point! 2)." marker. e.g. {2} can be retrieved with (point!! 2)."
`(cdr (assoc ,(cond ((numberp index) (number-to-string index)) `(cdr (assoc ,(cond ((numberp index) (number-to-string index))
((symbolp index) (symbol-name index)) ((symbolp index) (symbol-name index))
((stringp index) index)) ((stringp index) index))
marker-list))) marker-list)))
(defmacro with-minor-mode!! (mode &rest body)
"TODO"
(declare (indent defun))
`(progn (,mode +1)
,@body
(,mode -1)))

View file

@ -58,6 +58,12 @@ modes are active and the buffer is read-only.")
(ignore (bury-buffer)))) (ignore (bury-buffer))))
(add-hook 'kill-buffer-query-functions #'doom|dont-kill-scratch-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 () (defun doom|check-large-file ()
"Check if the buffer's file is large (see `doom-large-file-size'). If so, ask "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 for confirmation to open it literally (read-only, disabled undo and in
@ -75,43 +81,6 @@ fundamental-mode) for performance sake."
(fundamental-mode)))) (fundamental-mode))))
(add-hook 'find-file-hook #'doom|check-large-file) (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) (push '("/LICENSE$" . text-mode) auto-mode-alist)
@ -138,16 +107,15 @@ with functions that require it (like modeline segments)."
(def-package! recentf (def-package! recentf
:hook (doom-init . recentf-mode) :hook (doom-init . recentf-mode)
:config :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-menu-items 0
recentf-max-saved-items 300 recentf-max-saved-items 300
recentf-filename-handlers '(file-truename)
recentf-exclude recentf-exclude
(list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$" (list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$"
"^/var/folders/.+$" "^/var/folders/.+$"
;; ignore private DOOM temp files (but not all of them) ;; ignore private DOOM temp files (but not all of them)
(concat "^" (replace-regexp-in-string (concat "^" (file-truename doom-local-dir)))))
(concat "@" (regexp-quote (system-name)))
"@" (abbreviate-file-name doom-host-dir))))))
;; ;;
@ -206,8 +174,8 @@ extension, try to guess one."
;; Auto-close delimiters and blocks as you type ;; Auto-close delimiters and blocks as you type
(def-package! smartparens (def-package! smartparens
:hook (doom-init . smartparens-global-mode)
:config :config
(add-hook 'doom-init-hook #'smartparens-global-mode)
(require 'smartparens-config) (require 'smartparens-config)
(setq sp-autowrap-region nil ; let evil-surround handle this (setq sp-autowrap-region nil ; let evil-surround handle this

View file

@ -1,6 +1,5 @@
;;; core-lib.el -*- lexical-binding: t; -*- ;;; core-lib.el -*- lexical-binding: t; -*-
(require 'cl-lib)
(require 'subr-x) (require 'subr-x)
(load "async-autoloads" nil t) (load "async-autoloads" nil t)
(load "persistent-soft-autoloads" nil t) (load "persistent-soft-autoloads" nil t)

View file

@ -51,11 +51,6 @@
"Non-nil if doom is done initializing (once `doom-post-init-hook' is done). If "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.") 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 (defvar doom-init-time nil
"The time it took, in seconds, for DOOM Emacs to initialize.") "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.") "The load path of built in Emacs libraries.")
(defvar doom--package-load-path () (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 (defvar doom--base-load-path
(append (list doom-core-dir doom-modules-dir) (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 If you byte-compile core/core.el, this function will be avoided to speed up
startup." startup."
;; Called early during initialization; only use native functions! ;; Called early during initialization; only use native (and cl-lib) functions!
(when (or (not doom-package-init-p) force-p) (when (or force-p (not doom-init-p))
(setq load-path doom--base-load-path ;; Speed things up with a `load-path' for only the bare essentials
package-activated-list nil) (let ((load-path doom--base-load-path))
;; Ensure core folders exist ;; Ensure core folders exist, otherwise we get errors
(dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir package-user-dir)) (dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir doom-packages-dir))
(unless (file-directory-p dir) (unless (file-directory-p dir)
(make-directory dir t))) (make-directory dir t)))
;; Ensure package.el is initialized; we use its state
(setq package-activated-list nil)
(condition-case _ (package-initialize t) (condition-case _ (package-initialize t)
('error ('error (package-refresh-contents)
(package-refresh-contents)
(setq doom--refreshed-p t) (setq doom--refreshed-p t)
(package-initialize 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 ;; We could let `package-initialize' fill `load-path', but it does more than
;; that alone (like load autoload files). If you want something prematurely ;; that alone (like load autoload files). If you want something prematurely
;; optimizated right, ya gotta do it yourself. ;; optimizated right, ya gotta do it yourself.
@ -155,23 +168,7 @@ startup."
;; Also, in some edge cases involving package initialization during a ;; Also, in some edge cases involving package initialization during a
;; non-interactive session, `package-initialize' fails to fill `load-path'. ;; non-interactive session, `package-initialize' fails to fill `load-path'.
(setq doom--package-load-path (directory-files package-user-dir t "^[^.]" t) (setq doom--package-load-path (directory-files package-user-dir t "^[^.]" t)
load-path (append load-path doom--package-load-path)) load-path (append doom--base-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"))))
(defun doom-initialize-autoloads () (defun doom-initialize-autoloads ()
"Ensures that `doom-autoload-file' exists and is loaded. Otherwise run "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. If FORCE-P is non-nil, do it even if they are.
This aggressively reloads core autoload files." 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 (with-temp-buffer ; prevent buffer-local settings from propagating
(let ((noninteractive t) (cl-flet
(load-prefer-newer t) ((_load
(load-fn (file &optional noerror interactive)
(lambda (file &optional noerror)
(condition-case-unless-debug ex (condition-case-unless-debug ex
(load file noerror :nomessage :nosuffix) (let ((load-prefer-newer t)
(noninteractive (not interactive)))
(load file noerror :nomessage :nosuffix))
('error ('error
(error (format "(doom-initialize-packages) %s in %s: %s" (lwarn 'doom-initialize-packages :warning
"%s in %s: %s"
(car ex) (car ex)
(file-relative-name file doom-emacs-dir) (file-relative-name file doom-emacs-dir)
(error-message-string ex)) (error-message-string ex))))))
:error))))))
(when (or force-p (not doom-modules)) (when (or force-p (not doom-modules))
(setq doom-modules nil) (setq doom-modules nil
(let (noninteractive) doom-packages nil)
(load (concat doom-core-dir "core.el") nil t)) (_load (concat doom-core-dir "core.el") nil 'interactive)
(funcall load-fn (expand-file-name "init.el" doom-emacs-dir)) (_load (expand-file-name "init.el" doom-emacs-dir))
(when load-p (when load-p
(let (noninteractive) (mapc #'_load (file-expand-wildcards (expand-file-name "autoload/*.el" doom-core-dir)))
(funcall load-fn (doom-module-path :private user-login-name "init.el") t)) (_load (expand-file-name "init.el" doom-emacs-dir) nil 'interactive)))
(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))))
(when (or force-p (not doom-packages)) (when (or force-p (not doom-packages))
(setq doom-packages nil) (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) (cl-loop for (module . submodule) in (doom-module-pairs)
for path = (doom-module-path module submodule "packages.el") for path = (doom-module-path module submodule "packages.el")
do (funcall load-fn path t))))) do (_load path 'noerror))))))
(doom|finalize))
(defun doom-initialize-modules (modules) (defun doom-initialize-modules (modules)
"Adds MODULES to `doom-modules'. MODULES must be in mplist format. "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 ;; Certainly imprecise, especially where custom additions to
;; load-path are concerned, but I don't mind a [small] margin of ;; load-path are concerned, but I don't mind a [small] margin of
;; error in the plugin count in exchange for faster startup. ;; 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) (hash-table-size doom-modules)
(setq doom-init-time (float-time (time-subtract after-init-time before-init-time))))) (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) (doom-initialize-modules modules)
`(let (file-name-handler-alist) `(let (file-name-handler-alist)
(setq doom-modules ',doom-modules) (setq doom-modules ',doom-modules)
(unless noninteractive (unless noninteractive
(message "Doom initialized")
,@(cl-loop for (module . submodule) in (doom-module-pairs) ,@(cl-loop for (module . submodule) in (doom-module-pairs)
for module-path = (doom-module-path module submodule) for module-path = (doom-module-path module submodule)
collect `(load! init ,module-path t) into inits collect `(load! init ,module-path t) into inits
collect `(load! config ,module-path t) into configs collect `(load! config ,module-path t) into configs
finally return (append inits configs)) finally return (append inits configs))
(when (display-graphic-p) (when (display-graphic-p)
(require 'server) (require 'server)
(unless (server-running-p) (unless (server-running-p)
(server-start))) (server-start)))
(add-hook 'doom-init-hook #'doom-packages--display-benchmark t) (add-hook 'doom-init-hook #'doom-packages--display-benchmark t)
(message "Doom modules initialized")))) (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' ;; Ignore package if NAME is in `doom-disabled-packages'
(when (and (memq name doom-disabled-packages) (when (and (memq name doom-disabled-packages)
(not (memq :disabled plist))) (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. ;; If byte-compiling, ignore this package if it doesn't meet the condition.
;; This avoids false-positive load errors. ;; This avoids false-positive load errors.
(unless (and (bound-and-true-p byte-compile-current-file) (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'). "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 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 where to look for the file (a string representing a directory path). If omitted,
it is relative to `load-file-name', `byte-compile-current-file' or the lookup is relative to `load-file-name', `byte-compile-current-file' or
`buffer-file-name' (in that order). `buffer-file-name' (in that order).
If NOERROR is non-nil, don't throw an error if the file doesn't exist." 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)) (cl-assert (symbolp filesym) t)
(and (stringp path) path) (let ((path (or path
(and (listp path) (eval path))))
(and load-file-name (file-name-directory load-file-name)) (and load-file-name (file-name-directory load-file-name))
(and (bound-and-true-p byte-compile-current-file) (and (bound-and-true-p byte-compile-current-file)
(file-name-directory byte-compile-current-file)) (file-name-directory byte-compile-current-file))
(and buffer-file-name (and buffer-file-name
(file-name-directory buffer-file-name)))) (file-name-directory buffer-file-name))
(filename (cond ((stringp filesym) filesym) (error "Could not detect path to look for '%s' in" filesym)))
((symbolp filesym) (symbol-name filesym)) (filename (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))
(let ((file (expand-file-name (concat filename ".el") path))) (let ((file (expand-file-name (concat filename ".el") path)))
(if (file-exists-p file) (if (file-exists-p file)
`(load ,(file-name-sans-extension file) ,noerror `(load ,(file-name-sans-extension file) ,noerror
,(not doom-debug-mode)) ,(not doom-debug-mode))
(unless noerror (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) (defmacro require! (module submodule &optional flags reload-p)
"Loads the module specified by MODULE (a property) and SUBMODULE (a symbol). "Loads the module specified by MODULE (a property) and SUBMODULE (a symbol).
@ -507,7 +493,8 @@ loads MODULE SUBMODULE's packages.el file."
t))) t)))
(defun doom-packages--async-run (fn) (defun doom-packages--async-run (fn)
(let ((compilation-filter-hook (let* ((default-directory doom-emacs-dir)
(compilation-filter-hook
(list (lambda () (ansi-color-apply-on-region compilation-filter-start (point)))))) (list (lambda () (ansi-color-apply-on-region compilation-filter-start (point))))))
(compile (format "%s --quick --batch -l core/core.el -f %s" (compile (format "%s --quick --batch -l core/core.el -f %s"
(executable-find "emacs") (executable-find "emacs")
@ -527,15 +514,14 @@ call `doom/reload-load-path' remotely (through emacsclient)."
(interactive) (interactive)
(byte-recompile-file (expand-file-name "core.el" doom-core-dir) t) (byte-recompile-file (expand-file-name "core.el" doom-core-dir) t)
(cond (noninteractive (cond (noninteractive
(message "Reloading...")
(require 'server) (require 'server)
(when (server-running-p) (when (server-running-p)
(message "Reloading active Emacs session...")
(server-eval-at server-name '(doom//reload-load-path)))) (server-eval-at server-name '(doom//reload-load-path))))
(t ((let ((noninteractive t))
(doom-initialize t) (doom-initialize-load-path t)
(message "Reloaded %d packages" (length doom--package-load-path)) (message "%d packages reloaded" (length doom--package-load-path))
(run-with-timer 1 nil #'redraw-display) (run-hooks 'doom-reload-hook)))))
(run-hooks 'doom-reload-hook))))
(defun doom//reload-autoloads () (defun doom//reload-autoloads ()
"Refreshes the autoloads.el file, specified by `doom-autoload-file'. "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. ;; state. `doom-initialize-packages' will have side effects otherwise.
(and (doom-packages--async-run 'doom//reload-autoloads) (and (doom-packages--async-run 'doom//reload-autoloads)
(load doom-autoload-file)) (load doom-autoload-file))
(doom-initialize-packages) (doom-initialize-packages t)
(let ((targets (let ((targets
(file-expand-wildcards (file-expand-wildcards
(expand-file-name "autoload/*.el" doom-core-dir)))) (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) (delete-file doom-autoload-file)
(message "Deleted old autoloads.el")) (message "Deleted old autoloads.el"))
(dolist (file (reverse targets)) (dolist (file (reverse targets))
(message (cond ((not (doom-packages--read-if-cookies file)) (message
"Ignoring %s") (cond ((not (doom-packages--read-if-cookies file))
"⚠ Ignoring %s")
((update-file-autoloads file nil doom-autoload-file) ((update-file-autoloads file nil doom-autoload-file)
"Nothing in %s") "Nothing in %s")
(t (t
"Scanned %s")) "Scanned %s"))
(file-relative-name file doom-emacs-dir))) (file-relative-name file doom-emacs-dir)))
(make-directory (file-name-directory doom-autoload-file) t)
(let ((buf (get-file-buffer doom-autoload-file)) (let ((buf (get-file-buffer doom-autoload-file))
current-sexp) current-sexp)
(unwind-protect (unwind-protect
@ -646,6 +634,8 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
(error "No targets to compile")) (error "No targets to compile"))
(let ((use-package-expand-minimally t)) (let ((use-package-expand-minimally t))
(push (expand-file-name "init.el" doom-emacs-dir) compile-targets) (push (expand-file-name "init.el" doom-emacs-dir) compile-targets)
(condition-case ex
(progn
(dolist (target compile-targets) (dolist (target compile-targets)
(when (or (not recompile-p) (when (or (not recompile-p)
(let ((elc-file (byte-compile-dest-file target))) (let ((elc-file (byte-compile-dest-file target)))
@ -657,13 +647,13 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
(short-name (file-relative-name target doom-emacs-dir))) (short-name (file-relative-name target doom-emacs-dir)))
(cl-incf (cl-incf
(cond ((eq result 'no-byte-compile) (cond ((eq result 'no-byte-compile)
(message! (dark (white "Ignored %s" short-name))) (message! (dark (white "Ignored %s" short-name)))
total-noop) total-noop)
((null result) ((null result)
(message! (red "Failed to compile %s" short-name)) (message! (red "Failed to compile %s" short-name))
total-fail) total-fail)
(t (t
(message! (green "Compiled %s" short-name)) (message! (green "Compiled %s" short-name))
(quiet! (load target t t)) (quiet! (load target t t))
total-ok)))))) total-ok))))))
(message! (message!
@ -672,7 +662,14 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
"%s %s file(s) %s" "%s %s file(s) %s"
(if recompile-p "Recompiled" "Compiled") (if recompile-p "Recompiled" "Compiled")
(format "%d/%d" total-ok (- (length compile-targets) total-noop)) (format "%d/%d" total-ok (- (length compile-targets) total-noop))
(format "(%s ignored)" 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) (defun doom//byte-compile-core (&optional recompile-p)
"Byte compile the core Doom files. "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." If RECOMPILE-P is non-nil, only recompile out-of-date core files."
(interactive "P") (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 () (defun doom//byte-recompile-plugins ()
"Recompile all installed plugins. If you're getting odd errors after upgrading "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)) (byte-recompile-directory package-user-dir 0 t))
(defun doom//clean-byte-compiled-files () (defun doom//clean-byte-compiled-files ()
"Delete all the compiled elc files in your Emacs configuration. "Delete all the compiled elc files in your Emacs configuration. This excludes
compiled packages.'"
This excludes compiled packages in `doom-packages-dir'.'"
(interactive) (interactive)
(let ((targets (append (list (expand-file-name "init.elc" doom-emacs-dir)) (let ((targets (append (list (expand-file-name "init.elc" doom-emacs-dir))
(directory-files-recursively doom-core-dir "\\.elc$") (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 (unless (cl-loop for path in targets
if (file-exists-p path) if (file-exists-p path)
collect path collect path
and do (delete-file 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")))) (message "Everything is clean"))))

View file

@ -87,13 +87,13 @@ recognized by DOOM's popup system. They are:
;; ;;
;; ;;
(defvar doom-popup-parameters ;; (defvar doom-popup-parameters
'(:esc :modeline :transient :fit :align :size) ;; '(:esc :modeline :transient :fit :align :size)
"TODO") ;; "TODO")
(defvar doom-popup-whitelist ;; (defvar doom-popup-whitelist
'(("^ ?\\*" :size 15 :noselect t :autokill t :autoclose t)) ;; '(("^ ?\\*" :size 15 :noselect t :autokill t :autoclose t))
"TODO") ;; "TODO")
(defvar doom-popup-blacklist (defvar doom-popup-blacklist
'("^\\*magit") '("^\\*magit")
@ -122,7 +122,7 @@ recognized by DOOM's popup system. They are:
("*Backtrace*" :size 20 :noselect t) ("*Backtrace*" :size 20 :noselect t)
("*Warnings*" :size 12 :noselect t :autofit t) ("*Warnings*" :size 12 :noselect t :autofit t)
("*Messages*" :size 12 :noselect 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) ("^\\*.*Shell Command.*\\*$" :regexp t :size 20 :noselect t :autokill t)
(apropos-mode :size 0.3 :autokill t :autoclose t) (apropos-mode :size 0.3 :autokill t :autoclose t)
(Buffer-menu-mode :size 20 :autokill 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) (defun doom-display-buffer-action (buffer alist)
(shackle-display-buffer buffer alist (shackle-match buffer))) (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 (add-hook! doom-post-init
(setq display-buffer-alist (setq display-buffer-alist
(cons '(doom-display-buffer-condition doom-display-buffer-action) (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 ;; no modeline in popups
(add-hook 'doom-popup-mode-hook #'doom|hide-modeline-in-popup) (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 [escape] #'doom/popup-close-maybe)
(define-key map (kbd "ESC") #'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 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-right] #'ignore)
(define-key map [remap split-window-below] #'ignore) (define-key map [remap split-window-below] #'ignore)
(define-key map [remap split-window-horizontally] #'ignore) (define-key map [remap split-window-horizontally] #'ignore)

View file

@ -1,10 +1,7 @@
;;; core-projects.el -*- lexical-binding: t; -*- ;;; 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 (def-package! projectile
:hook (doom-init . projectile-mode)
:init :init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache") (setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
projectile-enable-caching (not noninteractive) projectile-enable-caching (not noninteractive)
@ -14,17 +11,23 @@ state are passed in.")
projectile-globally-ignored-files '(".DS_Store" "Icon " "TAGS") projectile-globally-ignored-files '(".DS_Store" "Icon " "TAGS")
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o")) projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o"))
(add-hook 'doom-init-hook #'projectile-mode)
:config :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 ;; a more generic project root file
(push ".project" projectile-project-root-files-bottom-up) (push ".project" projectile-project-root-files-bottom-up)
(nconc projectile-globally-ignored-directories (list (abbreviate-file-name doom-local-dir) ".sync")) (setq projectile-globally-ignored-directories
(nconc projectile-other-file-alist '(("css" . ("scss" "sass" "less" "style")) (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")) ("scss" . ("css"))
("sass" . ("css")) ("sass" . ("css"))
("less" . ("css")) ("less" . ("css"))
("styl" . ("css")))) ("styl" . ("css")))))
;; Projectile root-searching functions can cause an infinite loop on TRAMP ;; Projectile root-searching functions can cause an infinite loop on TRAMP
;; connections, so disable them. ;; 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." they are absolute."
(doom--resolve-path-forms files (doom-project-root))) (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 ;; Projects
;; ;;
(defvar-local doom-project nil (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 () (defun doom|autoload-project-mode ()
"Auto-enable projects listed in `doom-project', which is meant to be set from "Auto-enable the project(s) listed in `doom-project'."
.dir-locals.el files." (when doom-project
(if (symbolp doom-project)
(funcall doom-project)
(cl-loop for mode in doom-project (cl-loop for mode in doom-project
unless (symbol-value mode) unless (symbol-value mode)
do (funcall mode))) do (funcall mode)))))
(add-hook 'after-change-major-mode-hook #'doom|autoload-project-mode)
(defmacro def-project-mode! (name &rest plist) (defmacro def-project-mode! (name &rest plist)
"Define a project minor-mode named NAME (a symbol) and declare where and how "Define a project minor-mode named NAME (a symbol) and declare where and how
@ -101,8 +131,7 @@ own settings, keymaps, hooks, snippets, etc.
This creates NAME-hook and NAME-map as well. 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 A project can be enabled through .dir-locals.el too, by setting `doom-project'.
the name (symbol) of the project mode(s) to enable.
PLIST may contain any of these properties, which are all checked to see if NAME 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. should be activated. If they are *all* true, NAME is activated.
@ -151,7 +180,7 @@ Relevant: `doom-project-hook'."
:keymap (make-sparse-keymap) :keymap (make-sparse-keymap)
(if (not ,name) (if (not ,name)
,exit-form ,exit-form
(run-hook-with-args 'doom-project-hook ',name) (run-hook-with-args 'doom-project-hook ',name ,name)
,(when load-form ,(when load-form
`(unless ,init-var `(unless ,init-var
,load-form ,load-form

View file

@ -50,6 +50,7 @@ shorter major mode name in the mode-line. See `doom|set-mode-name'.")
max-mini-window-height 0.3 max-mini-window-height 0.3
mode-line-default-help-echo nil ; disable mode-line mouseovers mode-line-default-help-echo nil ; disable mode-line mouseovers
mouse-yank-at-point t ; middle-click paste at point, not at click 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 resize-mini-windows 'grow-only ; Minibuffer resizing
show-help-function nil ; hide :help-echo text show-help-function nil ; hide :help-echo text
split-width-threshold 160 ; favor horizontal splits split-width-threshold 160 ; favor horizontal splits
@ -182,9 +183,13 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(when (fontp doom-variable-pitch-font) (when (fontp doom-variable-pitch-font)
(set-face-attribute 'variable-pitch frame :font doom-variable-pitch-font))) (set-face-attribute 'variable-pitch frame :font doom-variable-pitch-font)))
('error ('error
(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 (lwarn 'doom-ui :error
"Failed to set fonts because %s" "Unexpected error while initializing fonts: %s"
(error-message-string ex)))) (error-message-string ex)))))
(run-hooks 'doom-init-ui-hook)) (run-hooks 'doom-init-ui-hook))
(defun doom|reload-ui-in-daemon (frame) (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) (add-hook! '(doom-post-init-hook minibuffer-setup-hook)
#'doom|no-fringes-in-minibuffer) #'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 ;; 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) (defun doom*disable-all-the-icons-in-tty (orig-fn &rest args)
(when (display-graphic-p) (when (display-graphic-p)
(apply orig-fn args))) (apply orig-fn args)))
;; all-the-icons doesn't work in the terminal, so we "disable" it. ;; 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) (dolist (fn '(all-the-icons-octicon all-the-icons-material
(advice-add #'all-the-icons-material :around #'doom*disable-all-the-icons-in-tty) all-the-icons-faicon all-the-icons-fileicon
(advice-add #'all-the-icons-faicon :around #'doom*disable-all-the-icons-in-tty) all-the-icons-wicon all-the-icons-alltheicon))
(advice-add #'all-the-icons-fileicon :around #'doom*disable-all-the-icons-in-tty) (advice-add fn :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))
(def-package! fringe-helper (def-package! fringe-helper
:commands (fringe-helper-define fringe-helper-convert) :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 (def-package! hideshow ; built-in
:commands (hs-minor-mode hs-toggle-hiding hs-already-hidden-p) :commands (hs-minor-mode hs-toggle-hiding hs-already-hidden-p)
:config :config (setq hs-hide-comments-when-hiding-all nil))
(setq hs-hide-comments-when-hiding-all nil))
(def-package! highlight-indentation (def-package! highlight-indentation
:commands (highlight-indentation-mode highlight-indentation-current-column-mode)) :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 ;; Helps us distinguish stacked delimiter pairs. Especially in parentheses-drunk
;; languages like Lisp. ;; languages like Lisp.
(def-package! rainbow-delimiters (def-package! rainbow-delimiters
:commands rainbow-delimiters-mode :hook (lisp-mode . rainbow-delimiters-mode)
:config (setq rainbow-delimiters-max-face-count 3) :config (setq rainbow-delimiters-max-face-count 3))
:init (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode))
;; For a distractions-free-like UI, that dynamically resizes margets and can ;; For a distractions-free-like UI, that dynamically resizes margets and can
;; center a buffer. ;; center a buffer.
(def-package! visual-fill-column (def-package! visual-fill-column
:commands visual-fill-column-mode :commands visual-fill-column-mode
:config :config
(setq-default visual-fill-column-center-text nil (setq-default
visual-fill-column-width fill-column)) 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)))
;; ;;

View file

@ -18,14 +18,14 @@
;; Autoloaded functions are in core/autoload/*.el and modules/*/*/autoload.el or ;; Autoloaded functions are in core/autoload/*.el and modules/*/*/autoload.el or
;; modules/*/*/autoload/*.el. ;; modules/*/*/autoload/*.el.
(defvar doom-version "2.0.8" (defvar doom-version "2.0.9"
"Current version of DOOM emacs.") "Current version of DOOM emacs.")
(defvar doom-debug-mode (or (getenv "DEBUG") init-file-debug) (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 "If non-nil, all doom functions will be verbose. Set DEBUG=1 in the command
line or use --debug-init to enable this.") 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.") "The path to this emacs.d directory.")
(defvar doom-core-dir (concat doom-emacs-dir "core/") (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/") (defvar doom-modules-dir (concat doom-emacs-dir "modules/")
"Where configuration modules are stored.") "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/") (defvar doom-local-dir (concat doom-emacs-dir ".local/")
"Root directory for local Emacs files. Use this as permanent storage for files "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 that are safe to share across systems (if this config is symlinked across
several computers).") several computers).")
(defvar doom-host-dir (concat doom-local-dir "@" (system-name)) (defvar doom-etc-dir (concat doom-local-dir "etc/")
"Directory for hostname-specific file storage. Used by `doom-etc-dir' and "Directory for non-volatile storage.
`doom-cache-dir'.")
(defvar doom-etc-dir (concat doom-host-dir "/etc/") Use this for files that don't change much, like servers binaries, external
"Host-namespaced directory for non-volatile storage. These are not deleted or dependencies or long-term shared data.")
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).")
(defvar doom-cache-dir (concat doom-host-dir "/cache/") (defvar doom-cache-dir (concat doom-local-dir "cache/")
"Host-namespaced directory for volatile storage. Deleted when `doom/reset' is "Directory for volatile storage.
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 Use this for files that change often, like cache files.")
problems.")
(defvar doom-packages-dir (concat doom-local-dir "packages/") (defvar doom-packages-dir (concat doom-local-dir "packages/")
"Where package.el and quelpa plugins (and their caches) are stored.") "Where package.el and quelpa plugins (and their caches) are stored.")
(defvar doom-autoload-file (concat doom-local-dir "autoloads.el") (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 (defgroup doom nil
"DOOM Emacs, an Emacs configuration for a stubborn, shell-dwelling and "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) (load custom-file t t)
;; be quiet at startup; don't load or display anything unnecessary ;; be quiet at startup; don't load or display anything unnecessary
(unless noninteractive
(advice-add #'display-startup-echo-area-message :override #'ignore) (advice-add #'display-startup-echo-area-message :override #'ignore)
(setq inhibit-startup-message t (setq inhibit-startup-message t
inhibit-startup-echo-area-message user-login-name inhibit-startup-echo-area-message user-login-name
inhibit-default-init t inhibit-default-init t
initial-major-mode 'fundamental-mode initial-major-mode 'fundamental-mode
initial-scratch-message nil initial-scratch-message nil
mode-line-format nil) mode-line-format nil))
;; Custom init hooks; clearer than `after-init-hook', `emacs-startup-hook', and ;; Custom init hooks; clearer than `after-init-hook', `emacs-startup-hook', and
;; `window-setup-hook'. ;; `window-setup-hook'.
@ -152,33 +142,23 @@ ability to invoke the debugger in debug mode."
(car ex) fn (error-message-string ex)))) (car ex) fn (error-message-string ex))))
nil) 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 ;; Initialize
(eval-and-compile (eval-and-compile
(defvar doom--file-name-handler-alist file-name-handler-alist) (defvar doom--file-name-handler-alist file-name-handler-alist)
(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 (setq gc-cons-threshold 402653184
gc-cons-percentage 0.6 gc-cons-percentage 0.6
file-name-handler-alist nil) file-name-handler-alist nil))
(require 'core-packages (concat doom-core-dir "core-packages")) (require 'cl-lib)
(eval-when-compile (load (concat doom-core-dir "core-packages") nil t)
(doom-initialize)) (setq load-path (eval-when-compile (doom-initialize t)
(setq load-path (eval-when-compile load-path) (doom-initialize-load-path t))
doom--package-load-path (eval-when-compile doom--package-load-path)) doom--package-load-path (eval-when-compile doom--package-load-path))
(load! core-lib) (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-popups) ; taming sudden yet inevitable windows
(load! core-editor) ; baseline configuration for text editing (load! core-editor) ; baseline configuration for text editing
(load! core-projects) ; making Emacs project-aware (load! core-projects) ; making Emacs project-aware
(load! core-keybinds))) ; centralized keybind system + which-key (load! core-keybinds)) ; centralized keybind system + which-key
(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) (add-hook! '(emacs-startup-hook doom-reload-hook)
#'doom|finalize) #'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) (provide 'core)
;;; core.el ends here ;;; core.el ends here

View file

@ -1,24 +1,23 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/autoload-buffers.el ;;; core/test/autoload-buffers.el
(defmacro -with-temp-buffers! (buffer-args &rest body) (defmacro with-temp-buffers!! (buffer-args &rest body)
(declare (indent defun)) (declare (indent defun))
(let (buffers) (let (buffers)
(dolist (bsym buffer-args) (dolist (bsym buffer-args)
(push `(,bsym (get-buffer-create ,(symbol-name bsym))) (push `(,bsym (get-buffer-create ,(symbol-name bsym)))
buffers)) buffers))
`(save-window-excursion `(cl-flet ((buffer-list
(cl-flet ((buffer-list
(lambda () (lambda ()
(cl-remove-if-not #'buffer-live-p (list ,@(reverse (mapcar #'car buffers))))))) (cl-remove-if-not #'buffer-live-p (list ,@(reverse (mapcar #'car buffers)))))))
(let* (persp-mode (let* (persp-mode
,@buffers) ,@buffers)
,@body ,@body
(mapc #'kill-buffer (buffer-list))))))) (mapc #'kill-buffer (buffer-list))))))
;; ;;
(def-test! get-buffers (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 (cl-every #'buffer-live-p (buffer-list)))
(should (equal (buffer-list) (list a b c))) (should (equal (buffer-list) (list a b c)))
(dolist (buf (list (cons a doom-emacs-dir) (dolist (buf (list (cons a doom-emacs-dir)
@ -26,6 +25,7 @@
(cons c "/tmp/"))) (cons c "/tmp/")))
(with-current-buffer (car buf) (with-current-buffer (car buf)
(setq-local default-directory (cdr buf)))) (setq-local default-directory (cdr buf))))
(projectile-mode +1)
(with-current-buffer a (with-current-buffer a
;; should produce all buffers ;; should produce all buffers
(let ((buffers (doom-buffer-list))) (let ((buffers (doom-buffer-list)))
@ -37,11 +37,12 @@
;; If no project is available, just get all buffers ;; If no project is available, just get all buffers
(with-current-buffer c (with-current-buffer c
(let ((buffers (doom-project-buffer-list))) (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 (def-test! real-buffers
(let (doom-real-buffer-functions) (let (doom-real-buffer-functions)
(-with-temp-buffers! (a b c d) (with-temp-buffers!! (a b c d)
(dolist (buf (list a b)) (dolist (buf (list a b))
(with-current-buffer buf (with-current-buffer buf
(setq-local buffer-file-name "x"))) (setq-local buffer-file-name "x")))
@ -62,7 +63,7 @@
;; `doom-visible-buffers' ;; `doom-visible-buffers'
;; `doom-buried-buffers' ;; `doom-buried-buffers'
(def-test! visible-buffers-and-windows (def-test! visible-buffers-and-windows
(-with-temp-buffers! (a b c d) (with-temp-buffers!! (a b c d)
(switch-to-buffer a) (switch-to-buffer a)
(should (eq (current-buffer) a)) (should (eq (current-buffer) a))
(should (eq (selected-window) (get-buffer-window a))) (should (eq (selected-window) (get-buffer-window a)))
@ -77,7 +78,7 @@
;; `doom-matching-buffers' ;; `doom-matching-buffers'
(def-test! matching-buffers (def-test! matching-buffers
(-with-temp-buffers! (a b c) (with-temp-buffers!! (a b c)
(let ((buffers (doom-matching-buffers "^[ac]$"))) (let ((buffers (doom-matching-buffers "^[ac]$")))
(should (= 2 (length buffers))) (should (= 2 (length buffers)))
(should (cl-every #'bufferp buffers)) (should (cl-every #'bufferp buffers))
@ -86,7 +87,7 @@
;; `doom-buffers-in-mode' ;; `doom-buffers-in-mode'
(def-test! 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)) (dolist (buf (list a b))
(with-current-buffer buf (with-current-buffer buf
(emacs-lisp-mode))) (emacs-lisp-mode)))
@ -101,7 +102,7 @@
;; `doom-kill-buffer' ;; `doom-kill-buffer'
(def-test! kill-buffer (def-test! kill-buffer
(-with-temp-buffers! (a b) (with-temp-buffers!! (a b)
(doom-kill-buffer a) (doom-kill-buffer a)
(should-not (buffer-live-p a)) (should-not (buffer-live-p a))
;; modified buffer ;; modified buffer
@ -112,7 +113,7 @@
;; `doom--cycle-real-buffers' ;; `doom--cycle-real-buffers'
(def-test! kill-buffer-then-show-real-buffer (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)) (dolist (buf (list a b d))
(with-current-buffer buf (with-current-buffer buf
(setq-local buffer-file-name "x"))) (setq-local buffer-file-name "x")))
@ -131,4 +132,4 @@
;; TODO doom/kill-all-buffers ;; TODO doom/kill-all-buffers
;; TODO doom/kill-other-buffers ;; TODO doom/kill-other-buffers
;; TODO doom/kill-matching-buffers ;; TODO doom/kill-matching-buffers
;; TODO doom/cleanup-buffers ;; TODO doom/cleanup-session

View file

@ -2,18 +2,16 @@
;;; core/test/autoload-debug.el ;;; core/test/autoload-debug.el
(def-test! what-face (def-test! what-face
(with-temp-buffer
(insert (propertize "Hello " 'face 'font-lock-keyword-face)) (insert (propertize "Hello " 'face 'font-lock-keyword-face))
(insert "world") (insert "world")
(should (equal (doom/what-face (point-min)) '((font-lock-keyword-face) ()))) (should (equal (doom/what-face (point-min)) '((font-lock-keyword-face) ())))
(should-not (doom/what-face (point-max))))) (should-not (doom/what-face (point-max))))
(def-test! what-face-overlays (def-test! what-face-overlays
(with-temp-buffer
(insert "Hello world") (insert "Hello world")
(let ((ov (make-overlay 1 6))) (let ((ov (make-overlay 1 6)))
(overlay-put ov 'face 'font-lock-keyword-face)) (overlay-put ov 'face 'font-lock-keyword-face))
(should (equal (doom/what-face (point-min)) '(() (font-lock-keyword-face)))) (should (equal (doom/what-face (point-min)) '(() (font-lock-keyword-face))))
(should-not (doom/what-face (point-max))))) (should-not (doom/what-face (point-max))))

View file

@ -1,30 +1,21 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/autoload-package.el ;;; 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)) (package-desc-create :name name :version version :reqs reqs))
(defmacro -with-temp-packages! (&rest forms) (defmacro with-packages!! (packages package-descs &rest body)
"Run FORMS in the context of a temporary package setup (as in, it won't `(let* ((doom-packages-dir ,(expand-file-name "packages/" (file-name-directory load-file-name)))
affects your Emacs packages)." (package-user-dir ,(expand-file-name "elpa" doom-packages-dir))
`(let* ((doom-local-dir ,(expand-file-name "test/.local/" doom-emacs-dir)) (quelpa-dir ,(expand-file-name "quelpa" doom-packages-dir)))
(doom-packages-dir (concat doom-local-dir "packages/")) ;; (make-directory doom-packages-dir t)
(doom-etc-dir (concat doom-local-dir "etc/")) (let ((doom-packages ,packages)
(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)
(package-alist ,package-descs) (package-alist ,package-descs)
doom-core-packages) doom-core-packages)
(cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _))) (cl-letf (((symbol-function 'doom-initialize-packages) (lambda (&rest _))))
((symbol-function 'package-installed-p) (lambda (name &rest _) (assq name package-alist)))) ,@body))
,@body))) ;; (delete-directory doom-packages-dir t)
))
;; ;;
@ -32,18 +23,19 @@ affects your Emacs packages)."
;; ;;
(def-test! backend-detection (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-cache '((doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist")))
(quelpa-initialized-p t)) (quelpa-initialized-p t))
(should (eq (doom-package-backend 'doom-dummy) 'elpa)) (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 (def-test! elpa-outdated-detection
(let* ((doom--last-refresh (current-time)) (let* ((doom--last-refresh (current-time))
(package-alist (package-alist
`((doom-dummy ,(-new-package 'doom-dummy '(20160405 1234))))) `((doom-dummy ,(-pkg 'doom-dummy '(20160405 1234)))))
(package-archive-contents (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 _)))) (cl-letf (((symbol-function 'package-refresh-contents) (lambda (&rest _))))
(should (equal (doom-package-outdated-p 'doom-dummy) (should (equal (doom-package-outdated-p 'doom-dummy)
'(doom-dummy (20160405 1234) (20170405 1234))))))) '(doom-dummy (20160405 1234) (20170405 1234)))))))
@ -52,7 +44,7 @@ affects your Emacs packages)."
(def-test! get-packages (def-test! get-packages
(let ((quelpa-initialized-p t)) (let ((quelpa-initialized-p t))
(-with-packages! (with-packages!!
'((doom-dummy)) '((doom-dummy))
'((doom-dummy nil) '((doom-dummy nil)
(doom-dummy-unwanted nil) (doom-dummy-unwanted nil)
@ -62,17 +54,17 @@ affects your Emacs packages)."
(def-test! orphaned-packages (def-test! orphaned-packages
"Test `doom-get-orphaned-packages', which gets a list of packages that are "Test `doom-get-orphaned-packages', which gets a list of packages that are
no longer enabled or depended on." no longer enabled or depended on."
(-with-packages! (with-packages!!
'((doom-dummy)) '((doom-dummy))
`((doom-dummy ,(-new-package 'doom-dummy '(20160405 1234) '((doom-dummy-dep (1 0))))) `((doom-dummy ,(-pkg 'doom-dummy '(20160405 1234) '((doom-dummy-dep (1 0)))))
(doom-dummy-unwanted ,(-new-package 'doom-dummy-unwanted '(20160601 1234))) (doom-dummy-unwanted ,(-pkg 'doom-dummy-unwanted '(20160601 1234)))
(doom-dummy-dep ,(-new-package 'doom-dummy-dep '(20160301 1234)))) (doom-dummy-dep ,(-pkg 'doom-dummy-dep '(20160301 1234))))
(should (equal (doom-get-orphaned-packages) '(doom-dummy-unwanted))))) (should (equal (doom-get-orphaned-packages) '(doom-dummy-unwanted)))))
(def-test! missing-packages (def-test! missing-packages
"Test `doom-get-missing-packages, which gets a list of enabled packages that "Test `doom-get-missing-packages, which gets a list of enabled packages that
aren't installed." aren't installed."
(-with-packages! (with-packages!!
'((doom-dummy) (doom-dummy-installed)) '((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)))))) (should (equal (doom-get-missing-packages) '((doom-dummy))))))

View file

@ -147,10 +147,13 @@
;; --- Settings --------------------------- ;; --- Settings ---------------------------
(def-setting! :-test-setting (x) x)
(def-test! set (def-test! set
(eval-and-compile
(let (doom-settings)
(def-setting! :-test-setting (x) `(setq result ,x))
(should (assq :-test-setting doom-settings)) (should (assq :-test-setting doom-settings))
(should (set! :-test-setting t)) (let ((inhibit-message t)
(let ((inhibit-message t)) result)
(should-not (set! :non-existant-setting (error "This shouldn't trigger"))))) (set! :-test-setting t)
(should result)
(set! :non-existant-setting (error "This shouldn't trigger"))))))

View file

@ -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")))))

45
core/test/core-ui.el Normal file
View file

@ -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)))))

View file

@ -130,7 +130,10 @@
;twitter ; twitter client https://twitter.com/vnought ;twitter ; twitter client https://twitter.com/vnought
;write ; emacs as a word processor (latex + org + markdown) ;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. ;; for your own.
:private hlissner) :private default)

View file

@ -9,6 +9,9 @@
:completion :completion
company company
:ui
doom-dashboard
:tools :tools
password-store password-store

View file

@ -56,7 +56,7 @@
(def-package! elfeed-org (def-package! elfeed-org
:after elfeed :after (:all org elfeed)
:config :config
(setq rmh-elfeed-org-files (setq rmh-elfeed-org-files
(let ((default-directory +org-dir)) (let ((default-directory +org-dir))

View file

@ -14,20 +14,23 @@ This module adds code-completion support, powered by [[https://github.com/compan
- [[#troubleshooting][Troubleshooting]] - [[#troubleshooting][Troubleshooting]]
* Install * 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. Check the README.org in that language's module for details.
* Configure * Configure
** Auto-completion ** 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: To enable auto-completion you must:
1. Load ~company~, 1. Load ~company~,
2. and change ~company-idle-delay~ to a non-nil float (the default is 0.5) 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/<username>/config.el~ module: For example:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(require 'company) (require 'company)
@ -36,8 +39,10 @@ For example, add the following to your ~modules/private/<username>/config.el~ mo
#+END_SRC #+END_SRC
* Troubleshooting * 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. + If what you are expecting is popup-as-you-type completion (which is disabled
+ Certain languages may have extra dependencies in order for auto-completion to work. Please look for that module's README.org for details. by default), see the "Configure > Auto-completion" section above, which will
+ Some languages don't have any auto-completion support. instruct you on how to enable this.
+ Some languages don't have any auto-completion support at all.

View file

@ -4,20 +4,21 @@
(require! :completion company) (require! :completion company)
(require 'company) (require 'company)
;;
(def-test! set-company-backend (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 'emacs-lisp-mode '(backend-1))
(set! :company-backend 'lisp-interaction-mode 'backend-1 'backend-2) (set! :company-backend 'lisp-interaction-mode 'backend-1 'backend-2)
(set! :company-backend 'text-mode 'backend-1) (set! :company-backend 'text-mode 'backend-1)
(with-temp-buffer (with-temp-buffer
(emacs-lisp-mode) (emacs-lisp-mode)
(should (equal (car company-backends) '(backend-1)))) (should (equal company-backends '((backend-1) default))))
(with-temp-buffer (with-temp-buffer
(lisp-interaction-mode) (lisp-interaction-mode)
(should (equal company-backends (should (equal company-backends '(backend-1 backend-2 default))))
(append '(backend-1 backend-2) default-backends))))
(with-temp-buffer (with-temp-buffer
(text-mode) (text-mode)
(should (eq (car company-backends) 'backend-1))) (should (equal company-backends '(backend-1 default))))
;; global backends shouldn't be affected ;; global backends shouldn't be affected
(should (equal company-backends default-backends)))) (should (equal company-backends '(default)))))

View file

@ -3,11 +3,13 @@
This module adds Ivy, a completion backend. This module adds Ivy, a completion backend.
#+begin_quote #+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 #+end_quote
+ Project-wide search & replace powered by ~rg~ or ~ag~ + 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. + Ivy integration for ~M-x~, ~imenu~, ~recentf~ and others.
+ A powerful, interactive in-buffer search using ~swiper~. + A powerful, interactive in-buffer search using ~swiper~.
+ Ivy-powered TODO/FIXME navigation + 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 * Install
This module optionally depends on [[https://github.com/BurntSushi/ripgrep][ripgrep]] and [[https://github.com/ggreer/the_silver_searcher][the_silver_searcher]]. 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 ** MacOS
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes") #+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 #+END_SRC
* Usage * 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 ** 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]] [[/../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]] [[/../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 ** 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]] [[/../screenshots/modules/completion/ivy/ivy-projectile.gif]]
** In-buffer searching ** 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]] [[/../screenshots/modules/completion/ivy/ivy-swiper.gif]]
** Task lookup ** 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]] [[/../screenshots/modules/completion/ivy/ivy-todo.gif]]
* Appendix * Appendix
** Commands ** 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 | | 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:swiper~ | ~:sw[iper] [QUERY]~ | Search current buffer |
| ~+ivy:todo~ | ~:todo[!]~ | List all TODO/FIXMEs in project (or current file if BANG) | | ~+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 | | 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 | | =M-RET= | Open the selected candidate in other-window |
** Hacks ** 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. + Functions with ivy/counsel equivalents have been globally remapped (like
+ ~counsel-[arp]g~'s 3-character limit was reduced to 1 (mainly for the ex command) ~find-file~ => ~counsel-find-file~). So a keybinding to ~find-file~ will
+ ~counsel-[arp]g~'s parentheses quoting behavior was reversed. Now, if you invoke ~counsel-find-file~ instead.
want literal parentheses, you must escape them: e.g. ~\(match\)~ is literal, + ~counsel-[arp]g~'s 3-character limit was reduced to 1 (mainly for the ex
~(match)~ is a regexp group. command)

View file

@ -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! magit (setq magit-completing-read-function #'ivy-completing-read))
(after! yasnippet (push #'+ivy-yas-prompt yas-prompt-functions)) (after! yasnippet (push #'+ivy-yas-prompt yas-prompt-functions))
(map! :map ivy-mode-map (map! [remap apropos] #'counsel-apropos
[remap apropos] #'counsel-apropos
[remap describe-face] #'counsel-describe-face [remap describe-face] #'counsel-describe-face
[remap find-file] #'counsel-find-file [remap find-file] #'counsel-find-file
[remap switch-to-buffer] #'ivy-switch-buffer [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 recentf-open-files] #'counsel-recentf
[remap imenu] #'counsel-imenu [remap imenu] #'counsel-imenu
[remap bookmark-jump] #'counsel-bookmark [remap bookmark-jump] #'counsel-bookmark
[remap projectile-switch-project] #'counsel-projectile-switch-project
[remap projectile-find-file] #'counsel-projectile-find-file [remap projectile-find-file] #'counsel-projectile-find-file
[remap imenu-anywhere] #'ivy-imenu-anywhere [remap imenu-anywhere] #'ivy-imenu-anywhere
[remap execute-extended-command] #'counsel-M-x [remap execute-extended-command] #'counsel-M-x

View file

@ -1,28 +1,33 @@
#+TITLE: :feature eval #+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: * Table of Contents :TOC:
- [[#install][Install]] - [[#install][Install]]
- [[#usage][Usage]] - [[#usage][Usage]]
- [[#configuration][Configuration]]
- [[#repls][REPLs]] - [[#repls][REPLs]]
- [[#code-evaluation][Code Evaluation]] - [[#code-evaluation][*Code Evaluation*]]
- [[#configuration][Configuration]]
- [[#repls-1][REPLs]]
- [[#code-evaluation-1][Code Evaluation]]
* Install * 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. Check the README.org in that language's module for details.
* Usage * Usage
+ *REPLs* ** REPLs
Invoked via: Invoked via:
+ ~:repl~ (evil ex-command) + ~:repl~ (evil ex-command)
+ =<leader> o r= in normal mode (or visual mode, which sends the selection to the open REPL) + =<leader> o r= in normal mode (or visual mode, which sends the selection to
the open REPL)
+ ~M-x +eval/open-repl~ + ~M-x +eval/open-repl~
+ ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active + ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active
+ *Code Evaluation* ** *Code Evaluation*
Quickrun can be invoked via: Quickrun can be invoked via:
+ ~M-x +eval/buffer~ (or ~gR~, or ~M-r~) + ~M-x +eval/buffer~ (or ~gR~, or ~M-r~)
+ ~M-x +eval/region~ + ~M-x +eval/region~
@ -31,13 +36,17 @@ Check the README.org in that language's module for details.
* Configuration * Configuration
** REPLs ** 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)~ ~(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 #+BEGIN_SRC emacs-lisp
(defun +emacs-lisp/repl () (defun +emacs-lisp/repl ()
@ -53,9 +62,14 @@ FUNCTION must return the repl buffer. Any window changes are ignored, then hande
#+END_SRC #+END_SRC
** Code Evaluation ** 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 #+BEGIN_SRC emacs-lisp
(set! :eval 'crystal-mode (set! :eval 'crystal-mode

View file

@ -11,12 +11,14 @@ This holy module brings the vim experience to Emacs.
- [[#differences-from-vim][Differences from vim]] - [[#differences-from-vim][Differences from vim]]
* Removing evil-mode * 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 * Features
+ A better ~:g[lobal]~ command with incremental highlighting. + A better ~:g[lobal]~ command with incremental highlighting.
+ Adds the ~:al[ign]~ ex command: offers an ex interface to ~align-regexp~ with incremental highlighting. + Adds the ~:al[ign]~ ex command: offers an ex interface to ~align-regexp~ with
+ Support for more of vim's filename modifiers in ex commands (like ~:p~, ~:p:h~ or ~:t~) than vanilla evil-mode offers. 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: + A list of new text objects:
+ Blocks: ~B~ (from ~evil-textobj-anyblock~) + Blocks: ~B~ (from ~evil-textobj-anyblock~)
+ Args: ~a~ (from ~evil-args~) + 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= + =NERDTree= equivalent is available in =:tools neotree=
** Multiple-cursors ** 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 ** 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. Most vim folding keys should work, e.g. =zr=, =zm=, =za=, =zo=, etc.
** Hacks ** Hacks
+ Automatically moves to new window when splitting + 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 ** 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. + =:g= will incrementally highlight buffer matches.

View file

@ -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) (error "Failed to delete %s" short-path)
;; Ensures that windows displaying this buffer will be switched ;; Ensures that windows displaying this buffer will be switched
;; to real buffers (`doom-real-buffer-p') ;; 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) (+evil--forget-file fname)
(message "Successfully deleted %s" short-path)))))))) (message "Successfully deleted %s" short-path))))))))

View file

@ -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 ;; 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 ;; so that any plugins that depend on multiple-cursors (which I have no control
;; relative safety. ;; over) can still use it in relative safety.
(after! multiple-cursors-core (after! multiple-cursors-core
(map! :map mc/keymap :ne "<escape>" #'mc/keyboard-quit) (map! :map mc/keymap :ne "<escape>" #'mc/keyboard-quit)

View file

@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; feature/evil/test/autoload-files.el ;;; 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 "Run FORMS in the context of a temporary package setup (as in, it won't
affects your Emacs packages)." affects your Emacs packages)."
(declare (indent 2) (doc-string 3)) (declare (indent 2) (doc-string 3))
@ -23,7 +23,7 @@ affects your Emacs packages)."
;; ;;
(def-test! move-this-file (def-test! move-this-file
":mv" ":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-error (+evil:move-this-file it))
(should (+evil:move-this-file other t)) (should (+evil:move-this-file other t))
(should (file-exists-p other)) (should (file-exists-p other))
@ -31,7 +31,7 @@ affects your Emacs packages)."
(def-test! copy-this-file (def-test! copy-this-file
":cp" ":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-error (+evil:copy-this-file it))
(should (+evil:copy-this-file other t)) (should (+evil:copy-this-file other t))
(should (file-exists-p other)) (should (file-exists-p other))
@ -39,7 +39,7 @@ affects your Emacs packages)."
(def-test! delete-this-file (def-test! delete-this-file
":rm" ":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-error (+evil:delete-this-file "this-file-does-not-exist"))
(should (+evil:delete-this-file nil t)) (should (+evil:delete-this-file nil t))
(should (not (file-exists-p it))))) (should (not (file-exists-p it)))))

View file

@ -3,6 +3,7 @@
(require! :feature evil) (require! :feature evil)
;;
;; `evil-ex-replace-special-filenames' ;; `evil-ex-replace-special-filenames'
;; NOTE The majority of this function is tested in core/test/core-lib.el, this ;; NOTE The majority of this function is tested in core/test/core-lib.el, this
;; only tests the evil-mode-specific functionality. ;; only tests the evil-mode-specific functionality.

View file

@ -6,6 +6,11 @@
(expand-file-name "templates/" (file-name-directory load-file-name)) (expand-file-name "templates/" (file-name-directory load-file-name))
"The path to a directory of yasnippet folders to use for file templates.") "The path to a directory of yasnippet folders to use for file templates.")
;;
;; Plugins
;;
(def-package! autoinsert ; built-in (def-package! autoinsert ; built-in
:defer 1 :defer 1
:init :init
@ -18,12 +23,16 @@
(auto-insert-mode 1) (auto-insert-mode 1)
(defun +file-templates--expand (key &optional mode project-only) (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) (when (if project-only (doom-project-p) t)
(require 'yasnippet) (require 'yasnippet)
(unless yas-minor-mode (yas-minor-mode-on)) (unless yas-minor-mode
(yas-minor-mode-on))
(when (and yas-minor-mode (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 (featurep 'evil) evil-mode)
(and yas--active-field-overlay (and yas--active-field-overlay
(overlay-buffer yas--active-field-overlay) (overlay-buffer yas--active-field-overlay)
@ -56,10 +65,9 @@
("\\.el$" "__initfile" emacs-lisp-mode) ("\\.el$" "__initfile" emacs-lisp-mode)
("/.dir-locals.el$" nil) ("/.dir-locals.el$" nil)
("-test\\.el$" "__" emacs-ert-mode) ("-test\\.el$" "__" emacs-ert-mode)
("/.emacs.d/.+\\.el$" "__doom-module" emacs-lisp-mode) ("/\\(?:.emacs.d\\|doom-emacs\\)?/.+\\.el$" "__doom-module" emacs-lisp-mode)
("/.emacs.d/.+/packages\\.el$" "__doom-packages" emacs-lisp-mode) ("/\\(?:.emacs.d\\|doom-emacs\\)?/.+/packages\\.el$" "__doom-packages" emacs-lisp-mode)
("/.emacs.d/.+/test\\.el$" "__doom-test" emacs-lisp-mode) ("/\\(?:.emacs.d\\|doom-emacs\\)?/.+/test/.+\\.el$" "__doom-test" emacs-lisp-mode)
("/.emacs.d/.+/README\\.org$" "__doom-readme" org-mode)
(snippet-mode "__" snippet-mode) (snippet-mode "__" snippet-mode)
;; Go ;; Go
("\\.go$" "__.go" go-mode) ("\\.go$" "__.go" go-mode)
@ -83,6 +91,7 @@
("\\.md$" "__" markdown-mode) ("\\.md$" "__" markdown-mode)
;; Org ;; Org
("\\.org$" "__" org-mode) ("\\.org$" "__" org-mode)
("/\\(?:.emacs.d\\|doom-emacs\\)?/.+/README\\.org$" "__doom-readme" org-mode)
;; PHP ;; PHP
("\\.php$" "__" php-mode) ("\\.php$" "__" php-mode)
("\\.class\\.php$" "__.class.php" php-mode) ("\\.class\\.php$" "__.class.php" php-mode)
@ -110,5 +119,5 @@
("/\\(index\\|main\\)\\.slim$" "__" slim-mode) ("/\\(index\\|main\\)\\.slim$" "__" slim-mode)
;; Shell scripts ;; Shell scripts
("\\.z?sh$" "__" sh-mode) ("\\.z?sh$" "__" sh-mode)
("\\.fish$" "__" fish-mode)
("\\.zunit$" "__zunit" sh-mode)))) ("\\.zunit$" "__zunit" sh-mode))))

View file

@ -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 $0

View file

@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; `(file-relative-name buffer-file-name doom-modules-dir)` ;;; `(file-relative-name buffer-file-truename doom-modules-dir)`
$0 $0

View file

@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; `(file-relative-name buffer-file-name doom-modules-dir)` ;;; `(file-relative-name buffer-file-truename doom-modules-dir)`
$0 $0

View file

@ -0,0 +1,3 @@
#!/usr/bin/env fish
$0

View file

@ -97,7 +97,9 @@ Tries `xref-find-references' and falls back to rg/ag."
(cond ((plist-member +jump-current-functions :documentation) (cond ((plist-member +jump-current-functions :documentation)
(+jump-to :documentation identifier)) (+jump-to :documentation identifier))
(t (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) (defun +jump--online-get-provider (&optional force-p)
(or (and (not force-p) (or (and (not force-p)

View file

@ -29,7 +29,7 @@
"An alist that maps online resources to their search url or a function that "An alist that maps online resources to their search url or a function that
produces an url. Used by `+jump/online'.") 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.") "Function to use to open search urls.")
(defvar +jump-function-alist nil (defvar +jump-function-alist nil
@ -82,6 +82,18 @@ properties:
;; Packages ;; 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 (def-package! dumb-jump
:commands (dumb-jump-go dumb-jump-quick-look :commands (dumb-jump-go dumb-jump-quick-look
dumb-jump-back dumb-jump-result-follow) dumb-jump-back dumb-jump-result-follow)
@ -92,28 +104,3 @@ properties:
((featurep! :completion helm) 'helm) ((featurep! :completion helm) 'helm)
(t 'popup)))) (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))

View file

@ -2,10 +2,7 @@
;;; feature/jump/packages.el ;;; feature/jump/packages.el
(package! dumb-jump) (package! dumb-jump)
(package! gxref) (when (featurep! :completion ivy)
;; (package! ggtags) (package! ivy-xref))
;; (cond ((featurep! :completion ivy) (when (featurep! :completion helm)
;; (package! counsel-gtags)) (package! helm-xref))
;; ((featurep! :completion helm)
;; (package! helm-gtags)))

View file

@ -8,20 +8,5 @@ This module adds snippets to Emacs, powered by yasnippet.
* Install * Install
There are no extra dependencies for this module. There are no extra dependencies for this module.
By default, this module uses the snippet library included with yasnippet. By default, =private/default= installs a snippet library tailored exclusively
for Doom Emacs.
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

View file

@ -11,8 +11,6 @@
(defvar yas-minor-mode-map (make-sparse-keymap)) (defvar yas-minor-mode-map (make-sparse-keymap))
:init :init
(setq yas-snippet-dirs '(yas-installed-snippets-dir))
;; Ensure `yas-reload-all' is called as late as possible. Other modules could ;; Ensure `yas-reload-all' is called as late as possible. Other modules could
;; have additional configuration for yasnippet. For example, file-templates. ;; have additional configuration for yasnippet. For example, file-templates.
(add-transient-hook! 'yas-minor-mode-hook (yas-reload-all)) (add-transient-hook! 'yas-minor-mode-hook (yas-reload-all))
@ -21,11 +19,9 @@
#'yas-minor-mode-on) #'yas-minor-mode-on)
:config :config
(setq yas-verbosity 0 (setq yas-verbosity (if doom-debug-mode 3 0)
yas-indent-line 'auto
yas-also-auto-indent-first-line t yas-also-auto-indent-first-line t
yas-prompt-functions '(yas-completing-prompt yas-ido-prompt yas-no-prompt) yas-prompt-functions (delq 'yas-dropdown-prompt yas-prompt-functions)
yas-use-menu nil
;; Allow nested snippets ;; Allow nested snippets
yas-triggers-in-field t) yas-triggers-in-field t)
@ -40,27 +36,8 @@
;; fix an error caused by smartparens interfering with yasnippet bindings ;; fix an error caused by smartparens interfering with yasnippet bindings
(advice-add #'yas-expand :before #'sp-remove-active-pair-overlay) (advice-add #'yas-expand :before #'sp-remove-active-pair-overlay)
(after! evil ;; Exit snippets on ESC from normal mode
;; Exit snippets on ESC in normal mode (add-hook '+evil-esc-hook #'yas-exit-all-snippets))
(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)))
(def-package! auto-yasnippet (def-package! auto-yasnippet

View file

@ -1,6 +1,10 @@
;;; feature/version-control/+git.el -*- lexical-binding: t; -*- ;;; feature/version-control/+git.el -*- lexical-binding: t; -*-
;;;###if (not (featurep! -git)) ;;;###if (not (featurep! -git))
(when (featurep! :feature evil)
(add-hook 'git-commit-mode-hook #'evil-insert-state))
(def-package! gitconfig-mode (def-package! gitconfig-mode
:mode "/\\.?git/?config$" :mode "/\\.?git/?config$"
:mode "/\\.gitmodules$") :mode "/\\.gitmodules$")

View file

@ -1,9 +1,15 @@
#+TITLE: :feature workspaces #+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 #+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 #+end_quote
* Table of Contents :TOC: * Table of Contents :TOC:
@ -22,25 +28,33 @@ This module has no additional dependencies.
* Features * Features
** Isolated buffer-list ** 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 ** Automatic workspaces
A workspace is automatically created (and switched to) when you: A workspace is automatically created (and switched to) when you:
+ Create a new frame (with =make-frame=; bound to =M-N= by default) + 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) + Switch to a project using ~projectile-switch-project~.
** Session persistence ** 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 ** 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 * Appendix
** Commands & Keybindings ** 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 | | command | key / ex command | description |
|---------------------------+----------------------------+------------------------------------------------------------| |---------------------------+----------------------------+------------------------------------------------------------|

View file

@ -310,7 +310,7 @@ workspace to delete."
(doom/kill-all-buffers) (doom/kill-all-buffers)
(let ((fallback-buf (doom-fallback-buffer))) (let ((fallback-buf (doom-fallback-buffer)))
(switch-to-buffer fallback-buf) (switch-to-buffer fallback-buf)
(doom/cleanup-buffers))) (doom/cleanup-session)))
;;;###autoload ;;;###autoload
(defun +workspace/kill-session-and-quit () (defun +workspace/kill-session-and-quit ()

View file

@ -47,10 +47,22 @@ renamed.")
;; per-frame and per-project workspaces ;; per-frame and per-project workspaces
(setq persp-init-new-frame-behaviour-override nil (setq persp-init-new-frame-behaviour-override nil
persp-interactive-init-frame-behaviour-override #'+workspace-on-new-frame persp-interactive-init-frame-behaviour-override #'+workspace-on-new-frame)
projectile-switch-project-action #'projectile-find-file)
(add-hook 'delete-frame-functions #'+workspaces|delete-associated-workspace-maybe) (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 ;; only auto-save when real buffers are present
(advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers) (advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers)
@ -68,7 +80,10 @@ renamed.")
(remove-hook 'delayed-warnings-hook #'display-delayed-warnings) (remove-hook 'delayed-warnings-hook #'display-delayed-warnings)
(defun +workspaces|init (&optional frame) (defun +workspaces|init (&optional frame)
(unless persp-mode (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)))) (let ((frame (or frame (selected-frame))))
(unless noninteractive (unless noninteractive
;; The default perspective persp-mode makes (defined by ;; The default perspective persp-mode makes (defined by

View file

@ -3,7 +3,7 @@
(require! :feature workspaces) (require! :feature workspaces)
(defmacro -with-workspace! (buffer-args &rest body) (defmacro with-workspace!! (buffer-args &rest body)
(declare (indent defun)) (declare (indent defun))
(let ((buffers (let ((buffers
(cl-loop for bsym in buffer-args (cl-loop for bsym in buffer-args
@ -27,14 +27,19 @@
;; ;;
(def-test! init (def-test! init
(-with-workspace! () (with-workspace!! ()
(should (equal (+workspace-current-name) +workspaces-main)))) (should (equal (+workspace-current-name) +workspaces-main))))
(def-test! advice (def-test! auto-add-buffer-to-persp
(should (advice-member-p #'+workspaces*auto-add-buffer #'switch-to-buffer))) (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 (def-test! current
(-with-workspace! () (with-workspace!! ()
(should (equal (+workspace-current-name) +workspaces-main)) (should (equal (+workspace-current-name) +workspaces-main))
(should (+workspace-exists-p +workspaces-main)) (should (+workspace-exists-p +workspaces-main))
(let ((workspace (+workspace-get +workspaces-main)) (let ((workspace (+workspace-get +workspaces-main))
@ -45,7 +50,7 @@
(should (equal workspace current-workspace))))) (should (equal workspace current-workspace)))))
(def-test! workspace-list (def-test! workspace-list
(-with-workspace! () (with-workspace!! ()
(should (equal (+workspace-list-names) (should (equal (+workspace-list-names)
(list (+workspace-current-name)))) (list (+workspace-current-name))))
(should (equal (+workspace-list) (should (equal (+workspace-list)
@ -53,7 +58,7 @@
(def-test! workspace-crud (def-test! workspace-crud
"Creating, reading, updating and deleting workspaces." "Creating, reading, updating and deleting workspaces."
(-with-workspace! () (with-workspace!! ()
(let ((new-workspace-name "*new-test*") (let ((new-workspace-name "*new-test*")
(renamed-workspace-name "*old-test*")) (renamed-workspace-name "*old-test*"))
(should (+workspace-new new-workspace-name)) (should (+workspace-new new-workspace-name))
@ -67,14 +72,14 @@
(should (= (length (+workspace-list-names)) 1))))) (should (= (length (+workspace-list-names)) 1)))))
(def-test! workspace-switch (def-test! workspace-switch
(-with-workspace! () (with-workspace!! ()
(let ((new-workspace-name "*new-test*")) (let ((new-workspace-name "*new-test*"))
(should-error (+workspace-switch new-workspace-name)) (should-error (+workspace-switch new-workspace-name))
(should (+workspace-switch new-workspace-name t)) (should (+workspace-switch new-workspace-name t))
(should (equal (+workspace-current-name) new-workspace-name))))) (should (equal (+workspace-current-name) new-workspace-name)))))
(def-test! buffer-list (def-test! buffer-list
(-with-workspace! (a b) (with-workspace!! (a b)
(let ((c (get-buffer-create "c")) (let ((c (get-buffer-create "c"))
(d (get-buffer-create "d"))) (d (get-buffer-create "d")))
(should (+workspace-contains-buffer-p a)) (should (+workspace-contains-buffer-p a))

View file

@ -5,26 +5,36 @@ This module adds support for the C-family of languages: C, C++, and Objective-C.
+ Code completion (~company-irony~) + Code completion (~company-irony~)
+ eldoc support (~irony-eldoc~) + eldoc support (~irony-eldoc~)
+ Syntax-checking (~flycheck-irony~) + 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]]) + 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]]) + 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. + Several improvements to C++11 indentation and syntax highlighting.
#+begin_quote #+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 #+end_quote
* Table of Contents :TOC: * Table of Contents :TOC:
- [[#install][Install]] - [[#install][Install]]
- [[#macos][MacOS]] - [[#irony-server][irony-server]]
- [[#arch-linux][Arch Linux]] - [[#rtags][rtags]]
- [[#configure][Configure]]
- [[#compile-settings][Compile settings]]
* Install * 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: Due to linking issues, MacOS users must compile irony-server manually:
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes") #+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
@ -49,10 +59,46 @@ popd
rm -rf irony-mode rm -rf irony-mode
#+END_SRC #+END_SRC
** Arch Linux *** Arch Linux
#+BEGIN_SRC sh :tangle (if (doom-system-os 'arch) "yes") #+BEGIN_SRC sh :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S clang cmake sudo pacman --needed --noconfirm -S clang cmake
#+END_SRC #+END_SRC
Then run ~M-x irony-install-server~ in Emacs. 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

View file

@ -1,5 +1,24 @@
;;; lang/cc/autoload.el -*- lexical-binding: t; -*- ;;; 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 ;;;###autoload
(defun +cc*align-lambda-arglist (orig-fun &rest args) (defun +cc*align-lambda-arglist (orig-fun &rest args)
"Improve indentation of continued C++11 lambda function opened as argument." "Improve indentation of continued C++11 lambda function opened as argument."
@ -66,8 +85,8 @@
;;;###autoload ;;;###autoload
(defun +cc|irony-init-compile-options () (defun +cc|irony-init-compile-options ()
"Initialize compiler options for irony-mode. It searches for the nearest "Initialize compiler options for irony-mode. It searches for the nearest
compilation database and initailizes it. If none was found, it uses compilation database and initailizes it, otherwise falling back on
`+cc-c++-compiler-options'. `+cc-default-compiler-options' and `+cc-default-include-paths'.
See https://github.com/Sarcasm/irony-mode#compilation-database for details on See https://github.com/Sarcasm/irony-mode#compilation-database for details on
compilation dbs." compilation dbs."
@ -75,8 +94,8 @@ compilation dbs."
(require 'irony-cdb) (require 'irony-cdb)
(unless (irony-cdb-autosetup-compile-options) (unless (irony-cdb-autosetup-compile-options)
(irony-cdb--update-compile-options (irony-cdb--update-compile-options
(append (delq nil (cdr-safe (assq major-mode +cc-compiler-options))) (append (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))
(cl-loop for path in +cc-include-paths (cl-loop for path in +cc-default-include-paths
nconc (list "-I" path))) nconc (list "-I" path)))
(doom-project-root))))) (doom-project-root)))))

View file

@ -1,13 +1,11 @@
;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*- ;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*-
(defvar +cc-include-paths (list "include/") (defvar +cc-default-include-paths (list "include/")
"A list of paths, relative to a project root, to search for headers in C/C++. "A list of default paths, relative to a project root, to search for headers in
Paths can be absolute. 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 (defvar +cc-default-compiler-options
knows where to look for headers.")
(defvar +cc-compiler-options
`((c-mode . nil) `((c-mode . nil)
(c++-mode (c++-mode
. ,(list "-std=c++11" ; use C++11 by default . ,(list "-std=c++11" ; use C++11 by default
@ -112,12 +110,16 @@ compilation database is present in the project.")
:after cc-mode :after cc-mode
:commands irony-install-server :commands irony-install-server
:preface (setq irony-server-install-prefix (concat doom-etc-dir "irony-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 :config
(unless (file-directory-p irony-server-install-prefix) (unless (file-directory-p irony-server-install-prefix)
(warn "irony-mode: server isn't installed; run M-x irony-install-server")) (warn "irony-mode: server isn't installed; run M-x irony-install-server"))
;; Initialize compilation database, if present. Otherwise, fall back on ;; 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)) (add-hook 'irony-mode-hook #'+cc|irony-init-compile-options))
(def-package! irony-eldoc (def-package! irony-eldoc
@ -144,7 +146,8 @@ compilation database is present in the project.")
;; ;;
(def-package! cmake-mode (def-package! cmake-mode
:mode "CMakeLists\\.txt$" :mode "/CMakeLists\\.txt$"
:mode "\\.cmake\\$"
:config :config
(set! :company-backend 'cmake-mode '(company-cmake company-yasnippet))) (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
(def-package! company-cmake :after cmake-mode) :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 (def-package! company-glsl
:when (featurep! :completion company)
:after glsl-mode :after glsl-mode
:config :config
(if (executable-find "glslangValidator") (if (executable-find "glslangValidator")
(warn "glsl-mode: couldn't find glslangValidator, disabling company-glsl") (warn "glsl-mode: couldn't find glslangValidator, disabling company-glsl")
(set! :company-backend 'glsl-mode '(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))

View file

@ -8,8 +8,8 @@
(package! glsl-mode) (package! glsl-mode)
(package! irony) (package! irony)
(package! irony-eldoc) (package! irony-eldoc)
(package! opencl-mode)
(package! modern-cpp-font-lock) (package! modern-cpp-font-lock)
(package! opencl-mode)
(when (featurep! :feature syntax-checker) (when (featurep! :feature syntax-checker)
(package! flycheck-irony)) (package! flycheck-irony))
@ -19,3 +19,8 @@
(package! company-irony) (package! company-irony)
(package! company-irony-c-headers)) (package! company-irony-c-headers))
(package! rtags)
(when (featurep! :completion ivy)
(package! ivy-rtags))
(when (featurep! :completion helm)
(package! helm-rtags))

View file

@ -16,7 +16,7 @@
"Evaluate a region and print it to the echo area (if one line long), otherwise "Evaluate a region and print it to the echo area (if one line long), otherwise
to a pop up buffer." to a pop up buffer."
(require 'pp) (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*")) (buf (get-buffer-create "*doom eval*"))
(inhibit-read-only t) (inhibit-read-only t)
lines) lines)

View file

@ -10,19 +10,12 @@
meghanada-use-eldoc t meghanada-use-eldoc t
meghanada-use-auto-start 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 (set! :jump 'java-mode
:definition #'meghanada-jump-declaration :definition #'meghanada-jump-declaration
:references #'meghanada-reference) :references #'meghanada-reference)
(add-hook! 'meghanada-mode-hook #'(flycheck-mode eldoc-mode))
;; ;;
(def-menu! +java/refactor-menu (def-menu! +java/refactor-menu
"Refactoring commands for `java-mode' buffers." "Refactoring commands for `java-mode' buffers."

View file

@ -1,5 +1,7 @@
;;; lang/java/config.el -*- lexical-binding: t; -*- ;;; lang/java/config.el -*- lexical-binding: t; -*-
(add-hook 'java-mode-hook #'rainbow-delimiters-mode)
(cond ((featurep! +meghanada) (load! +meghanada)) (cond ((featurep! +meghanada) (load! +meghanada))
((featurep! +eclim) ; FIXME lang/java +eclim ((featurep! +eclim) ; FIXME lang/java +eclim
;;(load! +eclim) ;;(load! +eclim)

View file

@ -15,7 +15,7 @@
;; + `+org-attach/url' ;; + `+org-attach/url'
;; + :org [FILE/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).") "Where to store attachments (relative to current org file).")
@ -30,7 +30,7 @@
(advice-add #'org-download-enable :override #'ignore) (advice-add #'org-download-enable :override #'ignore)
:config :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-heading-lvl nil
org-download-timestamp "_%Y%m%d_%H%M%S") org-download-timestamp "_%Y%m%d_%H%M%S")
@ -61,12 +61,12 @@
;; ;;
(after! org (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))) (push (car (last (split-string +org-attach-dir "/" t)))
projectile-globally-ignored-directories) projectile-globally-ignored-directories)
(after! recentf (after! recentf
(push (format "%s.+$" (regexp-quote +org-attach-dir)) (push (format "%s.+$" (regexp-quote org-attach-directory))
recentf-exclude))) recentf-exclude)))

View file

@ -10,16 +10,19 @@
;; anywhere I can call org-capture (whether or not Emacs is open/running), ;; anywhere I can call org-capture (whether or not Emacs is open/running),
;; like, say, from qutebrowser, vimperator, dmenu or a global keybinding. ;; 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" (defvar +org-default-notes-file "notes.org"
"TODO") "TODO")
(defvar org-capture-templates (defvar org-capture-templates
'(("t" "Todo" entry '(("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%i" :prepend t :kill-buffer t)
("n" "Notes" entry ("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))) "* %u %?\n%i" :prepend t :kill-buffer t)))

View file

@ -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)

View file

@ -78,7 +78,7 @@ the cursor."
(defun +org-attach-download-dnd (uri action) (defun +org-attach-download-dnd (uri action)
"TODO" "TODO"
(if (eq major-mode 'org-mode) (if (eq major-mode 'org-mode)
(+org-attach:url uri) (+org-attach/uri uri)
(let ((dnd-protocol-alist (let ((dnd-protocol-alist
(rassq-delete-all '+org-attach-download-dnd (rassq-delete-all '+org-attach-download-dnd
(copy-alist dnd-protocol-alist)))) (copy-alist dnd-protocol-alist))))
@ -98,7 +98,7 @@ the cursor."
(delete-region (match-beginning 0) (match-end 0)) (delete-region (match-beginning 0) (match-end 0))
(newline)) (newline))
(cond ((image-type-from-file-name filename) (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))) (setq filename (file-relative-name filename +org-dir)))
(insert (insert
(concat (if (= org-download-image-html-width 0) (concat (if (= org-download-image-html-width 0)
@ -113,9 +113,9 @@ the cursor."
(t (t
(insert (insert
(format "%s [[./%s][%s]] " (format "%s [[./%s][%s]] "
(org-attach--icon filename) (+org-attach--icon filename)
(file-relative-name filename buffer-file-name) (file-relative-name filename buffer-file-name)
(file-name-nondirectory (directory-file-name rel-path))))))) (file-name-nondirectory (directory-file-name filename)))))))
;;;###autoload ;;;###autoload
(defun +org-attach*relative-to-attach-dir (orig-fn &rest args) (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))) (let* ((context (save-match-data (org-element-context)))
(file (org-link-unescape (org-element-property :path context))) (file (org-link-unescape (org-element-property :path context)))
(default-directory (default-directory
(if (string-prefix-p (if (file-in-directory-p file org-attach-directory)
(concat "./" (car (last (split-string +org-attach-dir "/" t))))
file)
+org-dir +org-dir
default-directory))) default-directory)))
(apply orig-fn args)) (apply orig-fn args))

View file

@ -28,8 +28,7 @@
:commands org-crypt-use-before-save-magic :commands org-crypt-use-before-save-magic
:config :config
(setq org-tags-exclude-from-inheritance '("crypt") (setq org-tags-exclude-from-inheritance '("crypt")
org-crypt-key user-mail-address org-crypt-key user-mail-address))
epa-file-encrypt-to user-mail-address))
(def-package! org-bullets (def-package! org-bullets
:commands org-bullets-mode) :commands org-bullets-mode)
@ -91,12 +90,13 @@ unfold to point on startup."
(sp--looking-at-p "\\s-*]"))) (sp--looking-at-p "\\s-*]")))
;; make delimiter auto-closing a little more conservative ;; make delimiter auto-closing a little more conservative
(after! smartparens
(sp-with-modes 'org-mode (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-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))
(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 +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))
(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 () (defun +org|enable-auto-reformat-tables ()
"Realign tables exiting insert mode (`evil-mode')." "Realign tables exiting insert mode (`evil-mode')."

View file

@ -1,11 +1,12 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; lang/org/packages.el ;;; lang/org/packages.el
;; NOTE This is an insecure source, but unavoidable if we want org 9.0+ (which (when (version< emacs-version "26.1")
;; this module requires). orgmode.org offers no secure access to this repo. If ;; We want org 9.1.x, but the org packaged with Emacs 25.x and under is 8.x.
;; this bothers you, comment out this `package!' block and download ;; The only secure (and reasonably trustworthy) source for this is via
;; org-plus-contrib from orgmode.org. ;; emacsmirror. Emacs 26+ comes with Org 9.1.4.
(package! org-plus-contrib :recipe (:fetcher git :url "http://orgmode.org/org-mode.git")) (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! org-bullets :recipe (:fetcher github :repo "hlissner/org-bullets"))
(package! toc-org) (package! toc-org)

View file

@ -1,40 +1,40 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; lang/org/test/autoload-org.el ;;; lang/org/test/autoload-org.el
(defmacro should-org-buffer! (source expected &rest body) (defmacro should-org-buffer!! (source expected &rest body)
`(should-buffer! ,source ,expected `(should-buffer!! ,source ,expected
(org-mode) (org-mode)
,@body)) ,@body))
;;
;; `+org/insert-item' ;; `+org/insert-item'
(def-test! insert-item-h1 (def-test! insert-item-h1
"Should append/prepend new first-level headers with an extra newline." "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)) (+org/insert-item 'below))
(should-org-buffer! ("* {0}Header") ("* {|}\n\n* Header") (should-org-buffer!! ("* {0}Header") ("* {|}\n\n* Header")
(+org/insert-item 'above))) (+org/insert-item 'above)))
(def-test! insert-item-h2 (def-test! insert-item-h2
"Should append/prepend new second-level (and higher) headers without an extra "Should append/prepend new second-level (and higher) headers without an extra
newline." newline."
(should-org-buffer! ("** {0}Header") ("** Header\n** {|}") (should-org-buffer!! ("** {0}Header") ("** Header\n** {|}")
(+org/insert-item 'below)) (+org/insert-item 'below))
(should-org-buffer! ("** {0}Header") ("** {|}\n** Header") (should-org-buffer!! ("** {0}Header") ("** {|}\n** Header")
(+org/insert-item 'above))) (+org/insert-item 'above)))
(def-test! insert-item-plain-list (def-test! insert-item-plain-list
"Should append/prepend new second-level (and higher) headers without an extra "Should append/prepend new second-level (and higher) headers without an extra
newline." newline."
(should-org-buffer! ("+ {0}List item") ("+ List item\n+ {|}") (should-org-buffer!! ("+ {0}List item") ("+ List item\n+ {|}")
(+org/insert-item 'below)) (+org/insert-item 'below))
(should-org-buffer! ("+ {0}List item" (should-org-buffer!! ("+ {0}List item"
" + Sub item") " + Sub item")
("+ List item" ("+ List item"
" + Sub item" " + Sub item"
"+ {|}") "+ {|}")
(+org/insert-item 'below)) (+org/insert-item 'below))
(should-org-buffer! ("+ {0}List item" (should-org-buffer!! ("+ {0}List item"
"+ Next item") "+ Next item")
("+ List item" ("+ List item"
"+ {|}" "+ {|}"

View file

@ -5,3 +5,5 @@
(require! :lang org) (require! :lang org)
(require 'org (locate-library "org" nil doom--package-load-path)) (require 'org (locate-library "org" nil doom--package-load-path))
;;

View file

@ -84,8 +84,7 @@
:config :config
(unless (executable-find "phpctags") (unless (executable-find "phpctags")
(warn "php-mode: phpctags isn't installed, auto-completion will be gimped")) (warn "php-mode: phpctags isn't installed, auto-completion will be gimped"))
(setq ac-php-tags-path (concat doom-cache-dir "ac-php/")))
(setq ac-php-tags-path (concat doom-etc-dir "ac-php/")))
;; ;;

View file

@ -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. 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]].

View file

@ -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> -------------------------------------
(: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 < <gv
:v ">" #'+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
"<backtab>" #'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
"<M-right>" #'+snippets/goto-end-of-field
"<M-left>" #'+snippets/goto-start-of-field
"<M-backspace>" #'+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 "<tab>" yas-maybe-expand
:v "<tab>" #'+snippets/expand-on-region))
;; --- Major mode bindings --------------------------
(:after markdown-mode
(:map markdown-mode-map
;; fix conflicts with private bindings
"<backspace>" nil
"<M-left>" nil
"<M-right>" 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 "<escape>" #'View-quit-all)))

View file

@ -1,4 +1,4 @@
;;; private/hlissner/+commands.el -*- lexical-binding: t; -*- ;;; private/default/+evil-commands.el -*- lexical-binding: t; -*-
(defalias 'ex! 'evil-ex-define-cmd) (defalias 'ex! 'evil-ex-define-cmd)
@ -16,7 +16,6 @@
(ex! "iedit" #'evil-multiedit-ex-match) (ex! "iedit" #'evil-multiedit-ex-match)
(ex! "na[rrow]" #'+evil:narrow-buffer) (ex! "na[rrow]" #'+evil:narrow-buffer)
(ex! "retab" #'+evil:retab) (ex! "retab" #'+evil:retab)
;; External resources ;; External resources
;; TODO (ex! "db" #'doom:db) ;; TODO (ex! "db" #'doom:db)
;; TODO (ex! "dbu[se]" #'doom:db-select) ;; TODO (ex! "dbu[se]" #'doom:db-select)
@ -29,7 +28,6 @@
(ex! "t[mux]" #'+tmux:run) ; send to tmux (ex! "t[mux]" #'+tmux:run) ; send to tmux
(ex! "tcd" #'+tmux:cd-here) ; cd to default-directory in tmux (ex! "tcd" #'+tmux:cd-here) ; cd to default-directory in tmux
(ex! "x" #'doom/open-project-scratch-buffer) (ex! "x" #'doom/open-project-scratch-buffer)
;; GIT ;; GIT
(ex! "gist" #'+gist:send) ; send current buffer/region to gist (ex! "gist" #'+gist:send) ; send current buffer/region to gist
(ex! "gistl" #'+gist:list) ; list gists by user (ex! "gistl" #'+gist:list) ; list gists by user
@ -40,20 +38,18 @@
(ex! "gunstage" #'magit-unstage) (ex! "gunstage" #'magit-unstage)
(ex! "gblame" #'magit-blame) (ex! "gblame" #'magit-blame)
(ex! "grevert" #'git-gutter:revert-hunk) (ex! "grevert" #'git-gutter:revert-hunk)
;; Dealing with buffers ;; 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]" #'doom/kill-this-buffer)
(ex! "k[ill]all" #'+hlissner:kill-all-buffers) (ex! "k[ill]all" #'+default:kill-all-buffers)
(ex! "k[ill]m" #'+hlissner:kill-matching-buffers) (ex! "k[ill]m" #'+default:kill-matching-buffers)
(ex! "k[ill]o" #'doom/kill-other-buffers) (ex! "k[ill]o" #'doom/kill-other-buffers)
(ex! "l[ast]" #'doom/popup-restore) (ex! "l[ast]" #'doom/popup-restore)
(ex! "m[sg]" #'view-echo-area-messages) (ex! "m[sg]" #'view-echo-area-messages)
(ex! "pop[up]" #'doom/popup-this-buffer) (ex! "pop[up]" #'doom/popup-this-buffer)
;; Project navigation ;; Project navigation
(ex! "a" #'projectile-find-other-file) (ex! "a" #'projectile-find-other-file)
(ex! "cd" #'+hlissner:cd) (ex! "cd" #'+default:cd)
(cond ((featurep! :completion ivy) (cond ((featurep! :completion ivy)
(ex! "ag" #'+ivy:ag) (ex! "ag" #'+ivy:ag)
(ex! "agc[wd]" #'+ivy:ag-cwd) (ex! "agc[wd]" #'+ivy:ag-cwd)
@ -68,17 +64,14 @@
(ex! "rgc[wd]" #'+helm:rg-cwd) (ex! "rgc[wd]" #'+helm:rg-cwd)
(ex! "sw[oop]" #'+helm:swoop) (ex! "sw[oop]" #'+helm:swoop)
(ex! "todo" #'+helm:todo))) (ex! "todo" #'+helm:todo)))
;; Project tools ;; Project tools
(ex! "build" #'+eval/build) (ex! "build" #'+eval/build)
(ex! "debug" #'+debug/run) (ex! "debug" #'+debug/run)
(ex! "er[rors]" #'flycheck-list-errors) (ex! "er[rors]" #'flycheck-list-errors)
;; File operations ;; File operations
(ex! "cp" #'+evil:copy-this-file) (ex! "cp" #'+evil:copy-this-file)
(ex! "mv" #'+evil:move-this-file) (ex! "mv" #'+evil:move-this-file)
(ex! "rm" #'+evil:delete-this-file) (ex! "rm" #'+evil:delete-this-file)
;; Sessions/tabs ;; Sessions/tabs
(ex! "sclear" #'+workspace/kill-session) (ex! "sclear" #'+workspace/kill-session)
(ex! "sl[oad]" #'+workspace:load-session) (ex! "sl[oad]" #'+workspace:load-session)
@ -93,6 +86,6 @@
(ex! "tabr[ename]" #'+workspace:rename) (ex! "tabr[ename]" #'+workspace:rename)
(ex! "tabs" #'+workspace/display) (ex! "tabs" #'+workspace/display)
(ex! "tabsave" #'+workspace:save) (ex! "tabsave" #'+workspace:save)
;; Org-mode ;; Org-mode
(ex! "cap" #'+org-capture/dwim) (ex! "cap" #'+org-capture/dwim)

View file

@ -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'

View file

@ -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 "<f>")
(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 "<a>")
(doom/kill-matching-buffers pattern bang))

View file

@ -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))))))

View file

@ -0,0 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; private/default/packages.el
(package! emacs-snippets
:recipe (:fetcher github
:repo "hlissner/emacs-snippets"
:files ("*")))

View file

@ -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> -------------------------------------
(: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 < <gv
:v ">" #'+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
"<backtab>" #'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
"<M-right>" #'+snippets/goto-end-of-field
"<M-left>" #'+snippets/goto-start-of-field
"<M-backspace>" #'+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 "<tab>" yas-maybe-expand
:v "<tab>" #'+snippets/expand-on-region))
;; --- Major mode bindings --------------------------
(:after markdown-mode
(:map markdown-mode-map
;; fix conflicts with private bindings
"<backspace>" nil
"<M-left>" nil
"<M-right>" 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 "<escape>" #'View-quit-all)))

View file

@ -1,2 +0,0 @@
snippets
.authinfo.gpg

View file

@ -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 "<f>")
(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 "<a>")
(doom/kill-matching-buffers pattern bang))

View file

@ -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)

View file

@ -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))

View file

@ -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)))))

View file

@ -1,7 +1,9 @@
#+TITLE: :evil neotree #+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 #+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 #+end_quote

View file

@ -9,13 +9,15 @@
(require 'neotree) (require 'neotree)
(cond ((and (neo-global--window-exists-p) (cond ((and (neo-global--window-exists-p)
(get-buffer-window neo-buffer-name t)) (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) ((not (and (neo-global--window-exists-p)
(equal (file-truename (neo-global--with-buffer neo-buffer--start-node)) (equal (file-truename (neo-global--with-buffer neo-buffer--start-node))
(file-truename project-root)))) (file-truename project-root))))
(neotree-dir project-root) (neotree-dir project-root)
(neotree-find path project-root)) (neotree-find path project-root))
(t (neotree-find path project-root))))) (t
(neotree-find path project-root)))))
;;;###autoload ;;;###autoload
(defun +neotree/collapse-or-up () (defun +neotree/collapse-or-up ()

View file

@ -37,7 +37,7 @@
(and (or (string-match-p "https?://" url) (and (or (string-match-p "https?://" url)
(error "Field for %s doesn't look like an url" item)) (error "Field for %s doesn't look like an url" item))
(browse-url url)) (browse-url url))
(error "Username not found."))) (error "url not found.")))
(defun +pass-ivy-action--get-field (item) (defun +pass-ivy-action--get-field (item)
(let* ((data (+pass--get-entry item)) (let* ((data (+pass--get-entry item))

View file

@ -3,7 +3,7 @@
(load! ../autoload) (load! ../autoload)
(defmacro -with-passwords! (buffer-args &rest body) (defmacro with-passwords!! (buffer-args &rest body)
(declare (indent defun)) (declare (indent defun))
`(cl-letf `(cl-letf
(((symbol-function '+pass--get-entry) (((symbol-function '+pass--get-entry)
@ -18,7 +18,7 @@
;; ;;
(def-test! get-field (def-test! get-field
(-with-passwords! (with-passwords!!
(should (equal (+pass-get-field "fake/source" "login") (should (equal (+pass-get-field "fake/source" "login")
"HL2532-GANDI")) "HL2532-GANDI"))
(should (equal (+pass-get-field "fake/source" "email") (should (equal (+pass-get-field "fake/source" "email")
@ -29,14 +29,14 @@
"henrik@lissner.net")))) "henrik@lissner.net"))))
(def-test! missing-fields-return-nil (def-test! missing-fields-return-nil
(-with-passwords! (with-passwords!!
(should-not (+pass-get-field "fake/source" '("x" "y" "z"))))) (should-not (+pass-get-field "fake/source" '("x" "y" "z")))))
(def-test! missing-entries-throw-error (def-test! missing-entries-throw-error
(-with-passwords! (with-passwords!!
(should-error (+pass-get-field "nonexistent/source" "login")))) (should-error (+pass-get-field "nonexistent/source" "login"))))
(def-test! get-login (def-test! get-login
(-with-passwords! (with-passwords!!
(should (equal (+pass-get-user "fake/source") "HL2532-GANDI")) (should (equal (+pass-get-user "fake/source") "HL2532-GANDI"))
(should (equal (+pass-get-secret "fake/source") "defuse-account-gad")))) (should (equal (+pass-get-secret "fake/source") "defuse-account-gad"))))

View file

@ -3,20 +3,38 @@
(defvar +doom-dashboard-name " *doom*" (defvar +doom-dashboard-name " *doom*"
"The name to use for the dashboard buffer.") "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) (defvar +doom-dashboard-widgets '(banner shortmenu loaded)
"List of widgets to display in a blank scratch buffer.") "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 () (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.") 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--width 80)
(defvar +doom-dashboard--height 0) (defvar +doom-dashboard--height 0)
(defvar +doom-dashboard--old-fringe-indicator fringe-indicator-alist) (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) (setq doom-fallback-buffer +doom-dashboard-name)
@ -25,6 +43,8 @@ loading.")
"Major mode for the DOOM dashboard buffer." "Major mode for the DOOM dashboard buffer."
(read-only-mode +1) (read-only-mode +1)
(setq truncate-lines t) (setq truncate-lines t)
(setq-local whitespace-style nil)
(setq-local show-trailing-whitespace nil)
(cl-loop for (car . _cdr) in fringe-indicator-alist (cl-loop for (car . _cdr) in fringe-indicator-alist
collect (cons car nil) into alist collect (cons car nil) into alist
finally do (setq fringe-indicator-alist alist))) finally do (setq fringe-indicator-alist alist)))
@ -51,14 +71,24 @@ loading.")
if in a GUI/non-daemon session." if in a GUI/non-daemon session."
(add-hook 'window-configuration-change-hook #'+doom-dashboard-reload) (add-hook 'window-configuration-change-hook #'+doom-dashboard-reload)
(add-hook 'focus-in-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))) (when (and (display-graphic-p) (not (daemonp)))
(let ((default-directory doom-emacs-dir)) (let ((default-directory doom-emacs-dir))
(+doom-dashboard/open (selected-frame))))) (+doom-dashboard/open (selected-frame)))))
(defun +doom-dashboard|kill-buffer-query-fn () (defun +doom-dashboard|reload-on-kill ()
(or (not (+doom-dashboard-p)) "If this isn't a dashboard buffer, move along, but record its
(ignore (let (+doom-dashboard-inhibit-refresh) `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)))))) (ignore-errors (+doom-dashboard-reload))))))
(defun +doom-dashboard|make-frame (frame) (defun +doom-dashboard|make-frame (frame)
@ -85,30 +115,34 @@ whose dimensions may not be fully initialized by the time this is run."
(+doom-dashboard-reload))) (+doom-dashboard-reload)))
(setq +doom-dashboard-inhibit-refresh nil))) (setq +doom-dashboard-inhibit-refresh nil)))
;
(defun +doom-dashboard-p (&optional buffer) (defun +doom-dashboard-p (&optional buffer)
"Returns t if BUFFER is the dashboard buffer." "Returns t if BUFFER is the dashboard buffer."
(let ((buffer (or buffer (current-buffer)))) (eq (or buffer (current-buffer))
(and (buffer-live-p buffer) (doom-fallback-buffer)))
(eq buffer (doom-fallback-buffer)))))
(defun +doom-dashboard-center (len s) (defun +doom-dashboard-update-pwd ()
(concat (make-string (ceiling (max 0 (- len (length s))) 2) ? ) "TODO"
s)) (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)." "Update the DOOM scratch buffer (or create it, if it doesn't exist)."
(when (get-buffer-window (doom-fallback-buffer)) (let ((fallback-buffer (doom-fallback-buffer)))
(unless (or +doom-dashboard-inhibit-refresh (when (or (and after-init-time
(window-minibuffer-p (frame-selected-window))) (not +doom-dashboard-inhibit-refresh)
(let ((old-pwd (or dir default-directory)) (get-buffer-window fallback-buffer)
(fallback-buffer (doom-fallback-buffer))) (not (window-minibuffer-p (frame-selected-window))))
force)
(with-current-buffer fallback-buffer (with-current-buffer fallback-buffer
(+doom-dashboard-update-pwd)
(with-silent-modifications (with-silent-modifications
(unless (eq major-mode '+doom-dashboard-mode) (unless (eq major-mode '+doom-dashboard-mode)
(+doom-dashboard-mode)) (+doom-dashboard-mode))
(erase-buffer) (erase-buffer)
(setq default-directory old-pwd) (let ((+doom-dashboard--height
(let ((+doom-dashboard--height (window-height (get-buffer-window fallback-buffer))) (window-height (get-buffer-window fallback-buffer)))
(lines 1) (lines 1)
content) content)
(with-temp-buffer (with-temp-buffer
@ -122,18 +156,46 @@ whose dimensions may not be fully initialized by the time this is run."
?\n) ?\n)
content)) content))
(unless (button-at (point)) (unless (button-at (point))
(goto-char (next-button (point-min)))))))) (goto-char (next-button (point-min)))))))
;; Update all dashboard windows ;; 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-fringes win 0 0)
(set-window-margins (set-window-margins
win (max 0 (/ (- (window-total-width win) +doom-dashboard--width) 2))))) win (max 0 (/ (- (window-total-width win) +doom-dashboard--width) 2)))))
t) 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 ;; widgets
(defun doom-dashboard-widget--banner () (defun doom-dashboard-widget--banner ()
(mapc (lambda (line) (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) " ") 'face 'font-lock-comment-face) " ")
(insert "\n")) (insert "\n"))
'("================= =============== =============== ======== ========" '("================= =============== =============== ======== ========"
@ -160,17 +222,15 @@ whose dimensions may not be fully initialized by the time this is run."
(insert (insert
"\n" "\n"
(propertize (propertize
(+doom-dashboard-center (+doom-dashboard--center
+doom-dashboard--width +doom-dashboard--width
(format "Loaded %d packages in %d modules in %.02fs" (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) (hash-table-size doom-modules)
(if (floatp doom-init-time) doom-init-time 0.0))) (if (floatp doom-init-time) doom-init-time 0.0)))
'face 'font-lock-comment-face) 'face 'font-lock-comment-face)
"\n")) "\n"))
(defvar all-the-icons-scale-factor)
(defvar all-the-icons-default-adjust)
(defun doom-dashboard-widget--shortmenu () (defun doom-dashboard-widget--shortmenu ()
(let ((all-the-icons-scale-factor 1.45) (let ((all-the-icons-scale-factor 1.45)
(all-the-icons-default-adjust -0.02)) (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)) (propertize (concat " " label) 'face 'font-lock-keyword-face))
'action `(lambda (_) ,fn) 'action `(lambda (_) ,fn)
'follow-link t) 'follow-link t)
(+doom-dashboard-center (- +doom-dashboard--width 2) (buffer-string))) (+doom-dashboard--center (- +doom-dashboard--width 2) (buffer-string)))
"\n\n")))) "\n\n"))))
`(("Homepage" "mark-github" `(("Homepage" "mark-github"
(browse-url "https://github.com/hlissner/doom-emacs")) (browse-url "https://github.com/hlissner/doom-emacs"))

View file

@ -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)