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/
var/
/init.el
modules/private/
# emacs tempfiles that shouldn't be there
.mc-lists.el

View file

@ -12,6 +12,91 @@
- [[#200-jan-17-2017][2.0.0 (Jan 17, 2017)]]
* Unreleased (develop)
+ *Module changes:*
+ Add =private/default= to replace =private/hlissner=, which is a more generic
"starter" module for new users. My private module is now at
[[https://github.com/hlissner/doom-emacs-private][hlissner/doom-emacs-private]].
+ =general=
+ Fix "peculiar error" messages when running =bin/doom-doctor=, caused by
poorly thought out error handling (see [[https://github.com/hlissner/doom-emacs/issues/175][#175]]).
+ Fix ~doom/am-i-secure~ command.
+ Add unicode symbols to package management commands. Looks a little nicer <3.
+ Transform =recentf= entries into their absolute paths with symlinks resolved
(using ~file-truename~).
+ Local data and cache files are no longer host-namespaced. Originally, this
was meant to facilitate using the same config files (symlinked) across
different computers (e.g. via dropbox). Byte-compiled packages on one
computer would cause errors on another, so I abandoned this practice, making
~doom-host-dir~ unnecessary.
+ Fix an issue during live byte-compilation (with auto-compile-on-save-mode)
where ~gc-cons-threshold~ would get set to 304mb in the user's active
session, causing freezes and stuttering.
+ Improve error handling when byte compiling Doom. It now cleans up after
itself if something goes wrong, with improved error handling overall.
+ Fix =stringp= error thrown by ~doom-fetch~ in noninteractive sessions.
+ =core= Improve GPG integration by setting ~epa-file-encrypt-to~ to
~user-mail-address~, and ~epa-pinentry-mode~ to ~'loopback~ (so that Emacs
will prompt you for the passphrase in the minibuffer).
+ =core-packages= Fix ~doom-module-pairs~ returning pairs in arbitrary order,
causing load order errors. This is because the ~hash-table-values~ function
in Emacs 25 and under uses ~maphash~, which reverses the hash-table, while
newer versions use ~cl-loop~, which doesn't.
+ =core-packages= Fix ~doom//*~ not running from the correct
default-directory, causing errors.
+ =core-ui= Fix cryptic missing-font errors (also, they are warnings now).
+ =core-ui= Account for Emacs 26 line numbers when calculating
~visual-fill-column-width~.
+ =core-editor= the =KILL= argument for ~quit-window &optional KILL WINDOW~
has been flipped and now kills the window's buffer by default.
+ =core-projects= Add ~doom-project-find-file~ and ~doom-project-browse~ for
interactively fuzzy-finding and opening files in a directory/project.
+ Add ~doom/info~ command for collecting information about your system and
session and puts it in the clipboard. This is to make it easier for those
reporting bugs to easily include it.
+ Fix ibuffer windows not being handed off to popup system (see [[https://github.com/hlissner/doom-emacs/issues/309][#309]]).
+ =feature=
+ =file-templates=
+ Add a file template for fish shell scripts (thanks to [[https://github.com/amosbird][amosbird]]).
+ Fix some file templates not being inserted, like module README.org files.
+ =version-control= When evil-mode is available, start git commit message
buffers in insert mode (see [[https://github.com/hlissner/doom-emacs/issues/300][#300]]).
+ =jump= Always prompt for provider when no major-mode specific online jumper
is defined (for ~+jump/online~ and ~+jump/documentation~).
+ =ui=
+ =doom-dashboard=
+ Fix ~whitespace-mode~ and ~show-trailing-whitespace~ turning the dashboard
into a Christmas tree.
+ Add the ~+doom-dashboard-pwd-policy~ option, giving you control over how
~default-directory~ is set in the dashboard. By default this is set to
~'last-project~, meaning the dashboard's cwd will match the project of the
last buffer you killed.
+ =completion=
+ =ivy= Fix TAB only half-triggering auto-completion (see [[https://github.com/hlissner/doom-emacs/issues/303][#303]]).
+ =lang=
+ =cc=
+ Add =rtags= support for better code navigation. This replaces gxtag and
etag support. Also includes automatic management of the rdm daemon.
+ Improved support for JSON compilation databases. Irony-mode (and by
extension its flycheck and company plugins will now pick them up with more
consistency). This ensures all these tools run with the same compile
options as your project.
+ New ~+cc/reload-compile-db~ commands forcibly refreshes the compilation db
of your current project, updating irony and running rtags daemon, if any.
+ The ~+cc-include-paths~ and ~+cc-compiler-options~ options have been
renamed to ~+cc-default-include-paths~ and ~+cc-default-compiler-options~
for clarity.
+ Fix irony-mode complaining when it is enabled in non-C major-modes.
+ =org=
+ Change repo source for org-plus-contrib to emacsmirror.
+ Fix ~+org-dir~ being resolved too soon, robbing the user of the
opportunity to change it in their private module.
+ Fix ~invalid file location~ error when capturing to a TODO template.
+ Prevent =org-plus-contrib= from being installed on Emacs 26+, as 9.1.4 is
included with it.
+ Fix invalid function errors when drag'n'dropping files into org buffers
(see [[https://github.com/hlissner/doom-emacs/issues/307][#307]]).
+ =java= Fix Doom install meghanada server while byte compiling your Emacs
configuration.
* 2.0.8 (Dec 09, 2017)
+ *Module changes:*

View file

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

View file

@ -4,8 +4,12 @@
;;;###autoload
(defvar doom-real-buffer-functions '()
"A list of functions that are run to determine if a buffer is real.")
"A list of predicate functions run to determine if a buffer is real. These
functions are iterated over with one argument, the buffer in question. If any
function returns non-nil, the procession stops and the buffer is qualified as
real.")
;;;###autoload
(defvar-local doom-real-buffer-p nil
"If non-nil, this buffer should be considered real no matter what.")
@ -14,36 +18,17 @@
"The name of the buffer to fall back to if no other buffers exist (will create
it if it doesn't exist).")
;;
;; Functions
;;
;;;###autoload
(defun doom-fallback-buffer ()
"Returns the fallback buffer, creating it if necessary. By default this is the
scratch buffer."
(get-buffer-create doom-fallback-buffer))
;;;###autoload
(defun doom-narrow-buffer (beg end &optional clone-p)
"Restrict editing in this buffer to the current region, indirectly. With CLONE-P,
clone the buffer and hard-narrow the selection. If mark isn't active, then widen
the buffer (if narrowed).
Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(interactive "r")
(cond ((region-active-p)
(deactivate-mark)
(when clone-p
(let ((old-buf (current-buffer)))
(switch-to-buffer (clone-indirect-buffer nil nil))
(setq doom-buffer--narrowed-origin old-buf)))
(narrow-to-region beg end))
(doom-buffer--narrowed-origin
(kill-this-buffer)
(switch-to-buffer doom-buffer--narrowed-origin)
(setq doom-buffer--narrowed-origin nil))
(t
(widen))))
;; Buffer Life and Death ;;;;;;;;;;;;;;;
;;;###autoload
(defalias 'doom-buffer-list #'buffer-list)
@ -66,6 +51,28 @@ If no project is active, return all buffers."
if (doom-real-buffer-p buf)
collect buf))
;;;###autoload
(defun doom-real-buffer-p (&optional buffer-or-name)
"Returns t if BUFFER-OR-NAME is a 'real' buffer. The complete criteria for a
real buffer is:
1. The buffer-local value of `doom-real-buffer-p' (variable) is non-nil OR
2. Any function in `doom-real-buffer-functions' must return non-nil when
passed this buffer OR
3. The current buffer:
a) has a `buffer-file-name' defined AND
b) is not in a popup window (see `doom-popup-p') AND
c) is not a special buffer (its name isn't something like *Help*)
If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
(when-let* ((buf (ignore-errors (window-normalize-buffer buffer-or-name))))
(or (buffer-local-value 'doom-real-buffer-p buf)
(run-hook-with-args-until-success 'doom-real-buffer-functions buf)
(not (or (doom-popup-p buf)
(minibufferp buf)
(string-match-p "^\\s-*\\*" (buffer-name buf))
(not (buffer-file-name buf)))))))
;;;###autoload
(defun doom-buffers-in-mode (modes &optional buffer-list derived-p)
"Return a list of buffers whose `major-mode' is `eq' to MODE(S).
@ -112,8 +119,7 @@ If DERIVED-P, test with `derived-mode-p', otherwise use `eq'."
"Switch to the next buffer N times (previous, if N < 0), skipping over unreal
buffers. If there's nothing left, switch to `doom-fallback-buffer'. See
`doom-real-buffer-p' for what 'real' means."
(let ((buffers (delq (current-buffer) (doom-real-buffer-list)))
(project-dir (doom-project-root)))
(let ((buffers (delq (current-buffer) (doom-real-buffer-list))))
(cond ((or (not buffers)
(zerop (% n (1+ (length buffers)))))
(switch-to-buffer (doom-fallback-buffer) nil t))
@ -130,96 +136,49 @@ buffers. If there's nothing left, switch to `doom-fallback-buffer'. See
do
(dotimes (_i (abs n))
(funcall move-func)))))
(when (eq (current-buffer) (doom-fallback-buffer))
(cd project-dir))
(force-mode-line-update)
(current-buffer)))
;;;###autoload
(defun doom-real-buffer-p (&optional buffer-or-name)
"Returns t if BUFFER-OR-NAME is a 'real' buffer. The complete criteria for a
real buffer is:
1. The buffer-local value of `doom-real-buffer-p' (variable) is non-nil OR
2. Any function in `doom-real-buffer-functions' must return non-nil when
passed this buffer OR
3. The current buffer:
a) has a `buffer-file-name' defined AND
b) is not in a popup window (see `doom-popup-p') AND
c) is not a special buffer (its name isn't something like *Help*)
If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
(when-let* ((buf (ignore-errors (window-normalize-buffer buffer-or-name))))
(or (buffer-local-value 'doom-real-buffer-p buf)
(run-hook-with-args-until-success 'doom-real-buffer-functions buf)
(not (or (doom-popup-p buf)
(minibufferp buf)
(string-match-p "^\\s-*\\*" (buffer-name buf))
(not (buffer-file-name buf)))))))
;;;###autoload
(defun doom/next-buffer ()
"Switch to the next real buffer, skipping non-real buffers. See
`doom-real-buffer-p' for what 'real' means."
(interactive)
(doom--cycle-real-buffers +1))
;;;###autoload
(defun doom/previous-buffer ()
"Switch to the previous real buffer, skipping non-real buffers. See
`doom-real-buffer-p' for what 'real' means."
(interactive)
(doom--cycle-real-buffers -1))
(defun doom-set-buffer-real (buffer flag)
"Forcibly mark BUFFER as FLAG (non-nil = real)."
(with-current-buffer buffer
(setq doom-real-buffer-p flag)))
;;;###autoload
(defun doom-kill-buffer (&optional buffer dont-save)
"Kill BUFFER (falls back to current buffer if omitted) then switch to a real
buffer. If the buffer is present in another window, only bury it.
"Kill BUFFER (defaults to current buffer), but make sure we land on a real
buffer. Bury the buffer if the buffer is present in another window.
Will prompt to save unsaved buffers when attempting to kill them, unless
DONT-SAVE is non-nil.
See `doom-real-buffer-p' for what 'real' means."
(setq buffer (or buffer (current-buffer)))
(when (and (bufferp buffer) (buffer-live-p buffer))
(let ((buffer-win (get-buffer-window buffer))
(only-buffer-window-p (= 1 (length (get-buffer-window-list buffer nil t)))))
;; deal with unsaved buffers
(when (and only-buffer-window-p
(buffer-file-name buffer)
(unless buffer
(setq buffer (current-buffer)))
(when (and (bufferp buffer)
(buffer-live-p buffer))
(let ((buffer-win (get-buffer-window buffer)))
;; deal with modified buffers
(when (and (buffer-file-name buffer)
(buffer-modified-p buffer))
(with-current-buffer buffer
(if (and (not dont-save)
(yes-or-no-p "Buffer is unsaved, save it?"))
(save-buffer)
(set-buffer-modified-p nil))))
(if buffer-win
;; deal with dedicated windows
(if (window-dedicated-p buffer-win)
(unless (window--delete buffer-win t t)
(split-window buffer-win)
(window--delete buffer-win t t))
;; cycle to a real buffer
(with-selected-window buffer-win
(doom--cycle-real-buffers -1)
(when buffer-win
(unrecord-window-buffer buffer-win buffer))
(when only-buffer-window-p
(kill-buffer buffer)))
(not (eq (current-buffer) buffer)))
(kill-buffer buffer)))))
;;;###autoload
(defun doom-force-kill-buffer (&optional buffer dont-save)
"Kill BUFFER globally and ensure all windows previously showing BUFFER have
switched to a real buffer."
(interactive)
(let* ((buffer (or buffer (current-buffer)))
(windows (get-buffer-window-list buffer nil t)))
(doom-kill-buffer buffer dont-save)
(dolist (win windows)
(with-selected-window win
(unless (doom-real-buffer-p)
(doom/previous-buffer))))))
;; kill the buffer (or close dedicated window)
(cond ((not buffer-win)
(kill-buffer buffer))
((window-dedicated-p buffer-win)
(unless (window--delete buffer-win t t)
(split-window buffer-win)
(window--delete buffer-win t t)))
(t ; cycle to a real buffer
(with-selected-window buffer-win
(doom--cycle-real-buffers -1)
(kill-buffer buffer)))))
(not (eq (current-buffer) buffer))))
;;;###autoload
(defun doom-kill-buffer-and-windows (buffer)
@ -229,23 +188,6 @@ switched to a real buffer."
(delete-window window)))
(kill-buffer buffer))
;;;###autoload
(defun doom-kill-process-buffers ()
"Kill all processes that have no visible associated buffers. Return number of
processes killed."
(interactive)
(let ((n 0))
(dolist (p (process-list))
(let ((process-buffer (process-buffer p)))
(when (and (process-live-p p)
(not (string= (process-name p) "server"))
(or (not process-buffer)
(and (bufferp process-buffer)
(not (buffer-live-p process-buffer)))))
(delete-process p)
(cl-incf n))))
n))
;;;###autoload
(defun doom-kill-matching-buffers (pattern &optional buffer-list)
"Kill all buffers (in current workspace OR in BUFFER-LIST) that match the
@ -254,13 +196,33 @@ regex PATTERN. Returns the number of killed buffers."
(dolist (buf buffers (length buffers))
(doom-kill-buffer buf t))))
;;
;; Interactive commands
;;
;;;###autoload
(defun doom/kill-this-buffer ()
(defun doom/kill-this-buffer (&optional interactive-p)
"Use `doom-kill-buffer' on the current buffer."
(interactive)
(when (and (not (doom-kill-buffer)) (called-interactively-p 'interactive))
(interactive (list 'interactive))
(when (and (not (doom-kill-buffer)) interactive-p)
(message "Nowhere left to go!")))
;;;###autoload
(defun doom/kill-this-buffer-in-all-windows (buffer &optional dont-save)
"Kill BUFFER globally and ensure all windows previously showing this buffer
have switched to a real buffer.
If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
(interactive
(list (current-buffer) current-prefix-arg))
(cl-assert (bufferp buffer) t)
(let ((windows (get-buffer-window-list buffer nil t)))
(doom-kill-buffer buffer dont-save)
(cl-loop for win in windows
if (doom-real-buffer-p (window-buffer win))
do (with-selected-window win (doom/previous-buffer)))))
;;;###autoload
(defun doom/kill-all-buffers (&optional project-p)
"Kill all buffers and closes their windows.
@ -305,18 +267,46 @@ project."
(message "Killed %s buffers" n))))
;;;###autoload
(defun doom/cleanup-buffers (&optional all-p)
"Clean up buried and inactive process buffers in the current workspace."
(defun doom/cleanup-session (&optional all-p)
"Clean up buried buries and orphaned processes in the current workspace. If
ALL-P (universal argument), clean them up globally."
(interactive "P")
(run-hooks 'doom-cleanup-hook)
(let ((buffers (doom-buried-buffers (if all-p (buffer-list))))
(n 0))
(n 0)
kill-buffer-query-functions)
(mapc #'kill-buffer buffers)
(setq n (+ n (length buffers) (doom-kill-process-buffers)))
(setq n (+ n (length buffers) (doom/cleanup-processes)))
(when (called-interactively-p 'interactive)
(message "Cleaned up %s buffers" n))))
;;;###autoload
(defun doom-set-buffer-real (buffer flag)
"Forcibly mark a buffer's real property, no matter what."
(with-current-buffer buffer
(setq doom-real-buffer-p flag)))
(defun doom/cleanup-processes ()
"Kill all processes that have no visible associated buffers. Return number of
processes killed."
(interactive)
(let ((n 0))
(dolist (p (process-list))
(let ((process-buffer (process-buffer p)))
(when (and (process-live-p p)
(not (string= (process-name p) "server"))
(or (not process-buffer)
(and (bufferp process-buffer)
(not (buffer-live-p process-buffer)))))
(delete-process p)
(cl-incf n))))
n))
;;;###autoload
(defun doom/next-buffer ()
"Switch to the next real buffer, skipping non-real buffers. See
`doom-real-buffer-p' for what 'real' means."
(interactive)
(doom--cycle-real-buffers +1))
;;;###autoload
(defun doom/previous-buffer ()
"Switch to the previous real buffer, skipping non-real buffers. See
`doom-real-buffer-p' for what 'real' means."
(interactive)
(doom--cycle-real-buffers -1))

View file

@ -65,7 +65,7 @@ selection of all minor-modes, active or not."
in '("https://wrong.host.badssl.com/"
"https://self-signed.badssl.com/")
if (condition-case _e
(url-retrieve bad (lambda (_retrieved) t))
(url-retrieve-synchronously bad)
(error nil))
collect bad)))
(error (format "tls seems to be misconfigured (it got %s)."
@ -86,3 +86,15 @@ selection of all minor-modes, active or not."
(profiler-report)
(profiler-stop))
(setq doom--profiler (not doom--profiler)))
;;;###autoload
(defun doom/info ()
"Collects information about this session of Doom Emacs and copies it to the
clipboard. Helpful when filing bug reports!"
(interactive)
(with-temp-buffer
(message "Producing information about your system...")
(call-process (expand-file-name "bin/doom-doctor" doom-emacs-dir) nil t)
(ansi-color-apply-on-region (point-min) (point-max))
(kill-new (buffer-string))
(message "Done. Copied to clipboard!")))

View file

@ -2,7 +2,7 @@
;;;###autoload
(defun doom/sudo-find-file (file)
"Open a file as root."
"Open FILE as root."
(interactive
(list (read-file-name "Open as root: ")))
(find-file (if (file-writable-p file)
@ -218,8 +218,29 @@ consistent throughout a selected region, depending on `indent-tab-mode'."
(tabify beg end)
(untabify beg end)))
;;;###autoload
(defun doom/narrow-buffer (beg end &optional clone-p)
"Restrict editing in this buffer to the current region, indirectly. With CLONE-P,
clone the buffer and hard-narrow the selection. If mark isn't active, then widen
the buffer (if narrowed).
Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(interactive "r")
(cond ((region-active-p)
(deactivate-mark)
(when clone-p
(let ((old-buf (current-buffer)))
(switch-to-buffer (clone-indirect-buffer nil nil))
(setq doom-buffer--narrowed-origin old-buf)))
(narrow-to-region beg end))
(doom-buffer--narrowed-origin
(kill-this-buffer)
(switch-to-buffer doom-buffer--narrowed-origin)
(setq doom-buffer--narrowed-origin nil))
(t
(widen))))
;;;###autoload
(defun doom|enable-delete-trailing-whitespace ()
"Attaches `delete-trailing-whitespace' to a buffer-local `before-save-hook'."
(add-hook 'before-save-hook #'delete-trailing-whitespace nil t))

View file

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

View file

@ -239,7 +239,7 @@ without leaving any trace behind (muahaha)."
(if (featurep 'evil)
#'evil-force-normal-state
#'keyboard-quit))
(delete-window)))
(quit-restore-window nil 'kill)))
;;;###autoload
(defun doom/popup-this-buffer ()
@ -413,12 +413,4 @@ properties."
(when (doom-popup-p window)
(setq doom-popup-windows (delq window doom-popup-windows))
(when doom-popup-remember-history
(setq doom-popup-history (list (doom--popup-data window))))
(let ((autokill-p (and (not doom-popup-inhibit-autokill)
(doom-popup-property :autokill window))))
(with-selected-window window
(doom-popup-mode -1)
(when autokill-p
(when-let* ((process (get-buffer-process (current-buffer))))
(set-process-query-on-exit-flag process nil))
(kill-buffer (current-buffer)))))))
(setq doom-popup-history (list (doom--popup-data window))))))

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

View file

@ -74,17 +74,32 @@ If neither is available, run all tests in all enabled modules."
(defmacro def-test! (name &rest body)
"Define a namespaced ERT test."
(declare (indent defun) (doc-string 2))
(unless (plist-get body :disabled)
(let (plist)
(while (keywordp (car body))
(push (pop body) plist))
(setq plist (reverse plist))
(when (plist-get plist :skip)
(setq body `((ert-skip nil) ,@body)))
(when-let* ((modes (doom-enlist (plist-get plist :minor-mode))))
(dolist (mode modes)
(setq body `((with-minor-mode!! ,mode ,@body)))))
(when-let* ((before (plist-get plist :before)))
(setq body `(,@before ,@body)))
(when-let* ((after (plist-get plist :after)))
(setq body `(,@body @after)))
`(ert-deftest
,(cl-loop with path = (file-relative-name (file-name-sans-extension load-file-name)
doom-emacs-dir)
for (rep . with) in '(("/test/" . "/") ("/" . ":"))
do (setq path (replace-regexp-in-string rep with path t t))
finally return (intern (format "%s::%s" path name))) ()
()
,@body)))
finally return (intern (format "%s::%s" path name)))
()
(with-temp-buffer
(save-mark-and-excursion
(save-window-excursion
,@body))))))
(defmacro should-buffer! (initial expected &rest body)
(defmacro should-buffer!! (initial expected &rest body)
"Test that a buffer with INITIAL text, run BODY, then test it against EXPECTED.
INITIAL will recognize cursor markers in the form {[0-9]}. A {0} marker marks
@ -112,7 +127,7 @@ against."
(lambda (m1 m2) (< (marker-position m1)
(marker-position m2))))
(when (equal (caar marker-list) "0")
(goto-char! 0)))
(goto-char!! 0)))
,@body
(let ((result-text (buffer-substring-no-properties (point-min) (point-max)))
(point (point))
@ -130,15 +145,22 @@ against."
(should (equal expected-text result-text))
(should same-point)))))))
(defmacro goto-char! (index)
"Meant to be used with `should-buffer!'. Will move the cursor to one of the
cursor markers. e.g. Go to marker {2} with (goto-char! 2)."
`(goto-char (point! ,index)))
(defmacro goto-char!! (index)
"Meant to be used with `should-buffer!!'. Will move the cursor to one of the
cursor markers. e.g. Go to marker {2} with (goto-char!! 2)."
`(goto-char (point!! ,index)))
(defmacro point! (index)
"Meant to be used with `should-buffer!'. Returns the position of a cursor
marker. e.g. {2} can be retrieved with (point! 2)."
(defmacro point!! (index)
"Meant to be used with `should-buffer!!'. Returns the position of a cursor
marker. e.g. {2} can be retrieved with (point!! 2)."
`(cdr (assoc ,(cond ((numberp index) (number-to-string index))
((symbolp index) (symbol-name index))
((stringp index) index))
marker-list)))
(defmacro with-minor-mode!! (mode &rest body)
"TODO"
(declare (indent defun))
`(progn (,mode +1)
,@body
(,mode -1)))

View file

@ -58,6 +58,12 @@ modes are active and the buffer is read-only.")
(ignore (bury-buffer))))
(add-hook 'kill-buffer-query-functions #'doom|dont-kill-scratch-buffer)
;; temporary windows often have q bound to `quit-window', which only buries the
;; contained buffer. I rarely don't want that buffer killed, so...
(defun doom*quit-window (orig-fn &optional kill window)
(funcall orig-fn (not kill) window))
(advice-add #'quit-window :around #'doom*quit-window)
(defun doom|check-large-file ()
"Check if the buffer's file is large (see `doom-large-file-size'). If so, ask
for confirmation to open it literally (read-only, disabled undo and in
@ -75,43 +81,6 @@ fundamental-mode) for performance sake."
(fundamental-mode))))
(add-hook 'find-file-hook #'doom|check-large-file)
;; Automatic minor modes
(defvar doom-auto-minor-mode-alist '()
"Alist mapping filename patterns to corresponding minor mode functions, like
`auto-mode-alist'. All elements of this alist are checked, meaning you can
enable multiple minor modes for the same regexp.")
(defun doom|enable-minor-mode-maybe ()
"Check file name against `doom-auto-minor-mode-alist'."
(when buffer-file-name
(let ((name buffer-file-name)
(remote-id (file-remote-p buffer-file-name))
(alist doom-auto-minor-mode-alist))
;; Remove backup-suffixes from file name.
(setq name (file-name-sans-versions name))
;; Remove remote file name identification.
(when (and (stringp remote-id)
(string-match-p (regexp-quote remote-id) name))
(setq name (substring name (match-end 0))))
(while (and alist (caar alist) (cdar alist))
(if (string-match-p (caar alist) name)
(funcall (cdar alist) 1))
(setq alist (cdr alist))))))
(add-hook 'find-file-hook #'doom|enable-minor-mode-maybe)
(defun doom*set-indirect-buffer-filename (orig-fn base-buffer name &optional clone)
"In indirect buffers, `buffer-file-name' is nil, which can cause problems
with functions that require it (like modeline segments)."
(let ((file-name (buffer-file-name base-buffer))
(buffer (funcall orig-fn base-buffer name clone)))
(when (and file-name buffer)
(with-current-buffer buffer
(unless buffer-file-name
(setq buffer-file-name file-name
buffer-file-truename (file-truename file-name)))))
buffer))
(advice-add #'make-indirect-buffer :around #'doom*set-indirect-buffer-filename)
(push '("/LICENSE$" . text-mode) auto-mode-alist)
@ -138,16 +107,15 @@ with functions that require it (like modeline segments)."
(def-package! recentf
:hook (doom-init . recentf-mode)
:config
(setq recentf-save-file (concat doom-etc-dir "recentf")
(setq recentf-save-file (concat doom-cache-dir "recentf")
recentf-max-menu-items 0
recentf-max-saved-items 300
recentf-filename-handlers '(file-truename)
recentf-exclude
(list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$"
"^/var/folders/.+$"
;; ignore private DOOM temp files (but not all of them)
(concat "^" (replace-regexp-in-string
(concat "@" (regexp-quote (system-name)))
"@" (abbreviate-file-name doom-host-dir))))))
(concat "^" (file-truename doom-local-dir)))))
;;
@ -206,8 +174,8 @@ extension, try to guess one."
;; Auto-close delimiters and blocks as you type
(def-package! smartparens
:hook (doom-init . smartparens-global-mode)
:config
(add-hook 'doom-init-hook #'smartparens-global-mode)
(require 'smartparens-config)
(setq sp-autowrap-region nil ; let evil-surround handle this

View file

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

View file

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

View file

@ -87,13 +87,13 @@ recognized by DOOM's popup system. They are:
;;
;;
(defvar doom-popup-parameters
'(:esc :modeline :transient :fit :align :size)
"TODO")
;; (defvar doom-popup-parameters
;; '(:esc :modeline :transient :fit :align :size)
;; "TODO")
(defvar doom-popup-whitelist
'(("^ ?\\*" :size 15 :noselect t :autokill t :autoclose t))
"TODO")
;; (defvar doom-popup-whitelist
;; '(("^ ?\\*" :size 15 :noselect t :autokill t :autoclose t))
;; "TODO")
(defvar doom-popup-blacklist
'("^\\*magit")
@ -122,7 +122,7 @@ recognized by DOOM's popup system. They are:
("*Backtrace*" :size 20 :noselect t)
("*Warnings*" :size 12 :noselect t :autofit t)
("*Messages*" :size 12 :noselect t)
("*Help*" :size 0.3)
("*Help*" :size 0.3 :autokill t)
("^\\*.*Shell Command.*\\*$" :regexp t :size 20 :noselect t :autokill t)
(apropos-mode :size 0.3 :autokill t :autoclose t)
(Buffer-menu-mode :size 20 :autokill t)
@ -144,10 +144,20 @@ recognized by DOOM's popup system. They are:
(defun doom-display-buffer-action (buffer alist)
(shackle-display-buffer buffer alist (shackle-match buffer)))
(defun doom|autokill-popups ()
(or (not (doom-popup-p))
(prog1 (when (and (not doom-popup-inhibit-autokill)
(plist-get doom-popup-rules :autokill))
(doom-popup-mode -1)
(when-let* ((process (get-buffer-process (current-buffer))))
(set-process-query-on-exit-flag process nil))
t))))
(add-hook! doom-post-init
(setq display-buffer-alist
(cons '(doom-display-buffer-condition doom-display-buffer-action)
display-buffer-alist)))
display-buffer-alist))
(add-hook 'kill-buffer-query-functions #'doom|autokill-popups))
;; no modeline in popups
(add-hook 'doom-popup-mode-hook #'doom|hide-modeline-in-popup)
@ -170,7 +180,7 @@ recognized by DOOM's popup system. They are:
(define-key map [escape] #'doom/popup-close-maybe)
(define-key map (kbd "ESC") #'doom/popup-close-maybe)
(define-key map [remap quit-window] #'doom/popup-close-maybe)
(define-key map [remap doom/kill-this-buffer] #'delete-window)
(define-key map [remap doom/kill-this-buffer] #'doom/popup-close-maybe)
(define-key map [remap split-window-right] #'ignore)
(define-key map [remap split-window-below] #'ignore)
(define-key map [remap split-window-horizontally] #'ignore)

View file

@ -1,10 +1,7 @@
;;; core-projects.el -*- lexical-binding: t; -*-
(defvar doom-project-hook nil
"Hook run when a project is enabled. The name of the project's mode and its
state are passed in.")
(def-package! projectile
:hook (doom-init . projectile-mode)
:init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
projectile-enable-caching (not noninteractive)
@ -14,17 +11,23 @@ state are passed in.")
projectile-globally-ignored-files '(".DS_Store" "Icon " "TAGS")
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o"))
(add-hook 'doom-init-hook #'projectile-mode)
:config
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
(add-hook 'find-file-hook #'doom|autoload-project-mode)
;; a more generic project root file
(push ".project" projectile-project-root-files-bottom-up)
(nconc projectile-globally-ignored-directories (list (abbreviate-file-name doom-local-dir) ".sync"))
(nconc projectile-other-file-alist '(("css" . ("scss" "sass" "less" "style"))
("scss" . ("css"))
("sass" . ("css"))
("less" . ("css"))
("styl" . ("css"))))
(setq projectile-globally-ignored-directories
(append projectile-globally-ignored-directories
(list (abbreviate-file-name doom-local-dir) ".sync"))
projectile-other-file-alist
(append projectile-other-file-alist
'(("css" . ("scss" "sass" "less" "styl"))
("scss" . ("css"))
("sass" . ("css"))
("less" . ("css"))
("styl" . ("css")))))
;; Projectile root-searching functions can cause an infinite loop on TRAMP
;; connections, so disable them.
@ -76,21 +79,48 @@ which case they're relative to `default-directory'). If they start with a slash,
they are absolute."
(doom--resolve-path-forms files (doom-project-root)))
(defun doom-project-find-file (dir)
"Fuzzy-find a file under DIR."
(let ((default-directory dir)
;; Necessary to isolate this search from the current project
projectile-project-name
projectile-require-project-root
projectile-cached-buffer-file-name
projectile-cached-project-root)
(call-interactively
;; completion modules may remap this command
(or (command-remapping #'projectile-find-file)
#'projectile-find-file))))
(defun doom-project-browse (dir)
"Traverse a file structure starting linearly from DIR."
(let ((default-directory dir))
(call-interactively
;; completion modules may remap this command
(or (command-remapping #'find-file)
#'find-file))))
;;
;; Projects
;;
(defvar-local doom-project nil
"A list of project mode to enable. Used for .dir-locals.el.")
"Either the symbol or a list of project modes you want to enable. Available
for .dir-locals.el.")
(defvar doom-project-hook nil
"Hook run when a project is enabled. The name of the project's mode and its
state are passed in.")
(defun doom|autoload-project-mode ()
"Auto-enable projects listed in `doom-project', which is meant to be set from
.dir-locals.el files."
(cl-loop for mode in doom-project
unless (symbol-value mode)
do (funcall mode)))
(add-hook 'after-change-major-mode-hook #'doom|autoload-project-mode)
"Auto-enable the project(s) listed in `doom-project'."
(when doom-project
(if (symbolp doom-project)
(funcall doom-project)
(cl-loop for mode in doom-project
unless (symbol-value mode)
do (funcall mode)))))
(defmacro def-project-mode! (name &rest plist)
"Define a project minor-mode named NAME (a symbol) and declare where and how
@ -101,8 +131,7 @@ own settings, keymaps, hooks, snippets, etc.
This creates NAME-hook and NAME-map as well.
A project can be enabled through .dir-locals.el too, if `doom-project' is set to
the name (symbol) of the project mode(s) to enable.
A project can be enabled through .dir-locals.el too, by setting `doom-project'.
PLIST may contain any of these properties, which are all checked to see if NAME
should be activated. If they are *all* true, NAME is activated.
@ -151,7 +180,7 @@ Relevant: `doom-project-hook'."
:keymap (make-sparse-keymap)
(if (not ,name)
,exit-form
(run-hook-with-args 'doom-project-hook ',name)
(run-hook-with-args 'doom-project-hook ',name ,name)
,(when load-form
`(unless ,init-var
,load-form

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
mode-line-default-help-echo nil ; disable mode-line mouseovers
mouse-yank-at-point t ; middle-click paste at point, not at click
ibuffer-use-other-window t
resize-mini-windows 'grow-only ; Minibuffer resizing
show-help-function nil ; hide :help-echo text
split-width-threshold 160 ; favor horizontal splits
@ -182,9 +183,13 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(when (fontp doom-variable-pitch-font)
(set-face-attribute 'variable-pitch frame :font doom-variable-pitch-font)))
('error
(lwarn 'doom-ui :error
"Failed to set fonts because %s"
(error-message-string ex))))
(if (string-prefix-p "Font not available: " (error-message-string ex))
(lwarn 'doom-ui :warning
"Could not find the '%s' font on your system, falling back to system font"
(font-get (caddr ex) :family))
(lwarn 'doom-ui :error
"Unexpected error while initializing fonts: %s"
(error-message-string ex)))))
(run-hooks 'doom-init-ui-hook))
(defun doom|reload-ui-in-daemon (frame)
@ -224,6 +229,14 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(add-hook! '(doom-post-init-hook minibuffer-setup-hook)
#'doom|no-fringes-in-minibuffer)
(defun doom|protect-visible-buffers ()
"Don't kill the current buffer if it is visible in another window (bury it
instead)."
(not (delq (selected-window)
(get-buffer-window-list nil nil t))))
(add-hook! doom-post-init
(add-hook 'kill-buffer-query-functions #'doom|protect-visible-buffers))
;;
;; Plugins
@ -237,14 +250,11 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(defun doom*disable-all-the-icons-in-tty (orig-fn &rest args)
(when (display-graphic-p)
(apply orig-fn args)))
;; all-the-icons doesn't work in the terminal, so we "disable" it.
(advice-add #'all-the-icons-octicon :around #'doom*disable-all-the-icons-in-tty)
(advice-add #'all-the-icons-material :around #'doom*disable-all-the-icons-in-tty)
(advice-add #'all-the-icons-faicon :around #'doom*disable-all-the-icons-in-tty)
(advice-add #'all-the-icons-fileicon :around #'doom*disable-all-the-icons-in-tty)
(advice-add #'all-the-icons-wicon :around #'doom*disable-all-the-icons-in-tty)
(advice-add #'all-the-icons-alltheicon :around #'doom*disable-all-the-icons-in-tty))
(dolist (fn '(all-the-icons-octicon all-the-icons-material
all-the-icons-faicon all-the-icons-fileicon
all-the-icons-wicon all-the-icons-alltheicon))
(advice-add fn :around #'doom*disable-all-the-icons-in-tty)))
(def-package! fringe-helper
:commands (fringe-helper-define fringe-helper-convert)
@ -255,8 +265,7 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(def-package! hideshow ; built-in
:commands (hs-minor-mode hs-toggle-hiding hs-already-hidden-p)
:config
(setq hs-hide-comments-when-hiding-all nil))
:config (setq hs-hide-comments-when-hiding-all nil))
(def-package! highlight-indentation
:commands (highlight-indentation-mode highlight-indentation-current-column-mode))
@ -306,17 +315,20 @@ local value, whether or not it's permanent-local. Therefore, we cycle
;; Helps us distinguish stacked delimiter pairs. Especially in parentheses-drunk
;; languages like Lisp.
(def-package! rainbow-delimiters
:commands rainbow-delimiters-mode
:config (setq rainbow-delimiters-max-face-count 3)
:init (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode))
:hook (lisp-mode . rainbow-delimiters-mode)
:config (setq rainbow-delimiters-max-face-count 3))
;; For a distractions-free-like UI, that dynamically resizes margets and can
;; center a buffer.
(def-package! visual-fill-column
:commands visual-fill-column-mode
:config
(setq-default visual-fill-column-center-text nil
visual-fill-column-width fill-column))
(setq-default
visual-fill-column-center-text t
visual-fill-column-width
;; take Emacs 26 line numbers into account
(+ (if (boundp 'display-line-numbers) 6 0)
fill-column)))
;;

View file

@ -18,14 +18,14 @@
;; Autoloaded functions are in core/autoload/*.el and modules/*/*/autoload.el or
;; modules/*/*/autoload/*.el.
(defvar doom-version "2.0.8"
(defvar doom-version "2.0.9"
"Current version of DOOM emacs.")
(defvar doom-debug-mode (or (getenv "DEBUG") init-file-debug)
"If non-nil, all doom functions will be verbose. Set DEBUG=1 in the command
line or use --debug-init to enable this.")
(defvar doom-emacs-dir (expand-file-name user-emacs-directory)
(defvar doom-emacs-dir (file-truename user-emacs-directory)
"The path to this emacs.d directory.")
(defvar doom-core-dir (concat doom-emacs-dir "core/")
@ -34,38 +34,27 @@ line or use --debug-init to enable this.")
(defvar doom-modules-dir (concat doom-emacs-dir "modules/")
"Where configuration modules are stored.")
;; Multi-host directories: I namespace `doom-etc-dir' and `doom-cache-dir' with
;; host names because I use the same (often symlinked) emacs.d across several
;; computers -- often simultaneously. Cache or other temporary files would
;; conflict otherwise.
(defvar doom-local-dir (concat doom-emacs-dir ".local/")
"Root directory for local Emacs files. Use this as permanent storage for files
that are safe to share across systems (if this config is symlinked across
several computers).")
(defvar doom-host-dir (concat doom-local-dir "@" (system-name))
"Directory for hostname-specific file storage. Used by `doom-etc-dir' and
`doom-cache-dir'.")
(defvar doom-etc-dir (concat doom-local-dir "etc/")
"Directory for non-volatile storage.
(defvar doom-etc-dir (concat doom-host-dir "/etc/")
"Host-namespaced directory for non-volatile storage. These are not deleted or
tampored with by DOOM functions. Use this for dependencies like servers or
config files that are stable (i.e. it should be unlikely that you need to delete
them if something goes wrong).")
Use this for files that don't change much, like servers binaries, external
dependencies or long-term shared data.")
(defvar doom-cache-dir (concat doom-host-dir "/cache/")
"Host-namespaced directory for volatile storage. Deleted when `doom/reset' is
called. Use this for transient files that are generated on the fly like caches
and temporary files. Anything that may need to be cleared if there are
problems.")
(defvar doom-cache-dir (concat doom-local-dir "cache/")
"Directory for volatile storage.
Use this for files that change often, like cache files.")
(defvar doom-packages-dir (concat doom-local-dir "packages/")
"Where package.el and quelpa plugins (and their caches) are stored.")
(defvar doom-autoload-file (concat doom-local-dir "autoloads.el")
"Location of the autoloads file generated by `doom/reload-autoloads'.")
"Where `doom//reload-autoloads' will generate its autoloads file.")
(defgroup doom nil
"DOOM Emacs, an Emacs configuration for a stubborn, shell-dwelling and
@ -121,13 +110,14 @@ melodramatic ex-vimmer disappointed with the text-editor status quo."
(load custom-file t t)
;; be quiet at startup; don't load or display anything unnecessary
(advice-add #'display-startup-echo-area-message :override #'ignore)
(setq inhibit-startup-message t
inhibit-startup-echo-area-message user-login-name
inhibit-default-init t
initial-major-mode 'fundamental-mode
initial-scratch-message nil
mode-line-format nil)
(unless noninteractive
(advice-add #'display-startup-echo-area-message :override #'ignore)
(setq inhibit-startup-message t
inhibit-startup-echo-area-message user-login-name
inhibit-default-init t
initial-major-mode 'fundamental-mode
initial-scratch-message nil
mode-line-format nil))
;; Custom init hooks; clearer than `after-init-hook', `emacs-startup-hook', and
;; `window-setup-hook'.
@ -152,33 +142,23 @@ ability to invoke the debugger in debug mode."
(car ex) fn (error-message-string ex))))
nil)
(defun doom|finalize ()
(unless (or doom-init-p noninteractive)
(dolist (hook '(doom-init-hook doom-post-init-hook))
(run-hook-wrapped hook #'doom-try-run-hook hook))
(setq doom-init-p t))
;; Don't keep gc-cons-threshold too high. It helps to stave off the GC while
;; Emacs starts up, but afterwards it causes stuttering and random freezes. So
;; reset it to a reasonable default.
(setq gc-cons-threshold 16777216
gc-cons-percentage 0.1
file-name-handler-alist doom--file-name-handler-alist)
t)
;;;
;; Initialize
(eval-and-compile
(defvar doom--file-name-handler-alist file-name-handler-alist)
(setq gc-cons-threshold 402653184
gc-cons-percentage 0.6
file-name-handler-alist nil)
(unless (or after-init-time noninteractive)
;; One of the contributors to long startup times is the garbage collector,
;; so we up its memory threshold, temporarily. It is reset later in
;; `doom|finalize'.
(setq gc-cons-threshold 402653184
gc-cons-percentage 0.6
file-name-handler-alist nil))
(require 'core-packages (concat doom-core-dir "core-packages"))
(eval-when-compile
(doom-initialize))
(setq load-path (eval-when-compile load-path)
(require 'cl-lib)
(load (concat doom-core-dir "core-packages") nil t)
(setq load-path (eval-when-compile (doom-initialize t)
(doom-initialize-load-path t))
doom--package-load-path (eval-when-compile doom--package-load-path))
(load! core-lib)
@ -195,10 +175,71 @@ ability to invoke the debugger in debug mode."
(load! core-popups) ; taming sudden yet inevitable windows
(load! core-editor) ; baseline configuration for text editing
(load! core-projects) ; making Emacs project-aware
(load! core-keybinds))) ; centralized keybind system + which-key
(load! core-keybinds)) ; centralized keybind system + which-key
(add-hook! '(emacs-startup-hook doom-reload-hook)
#'doom|finalize)
(defun doom|finalize ()
"Run `doom-init-hook', `doom-post-init-hook' and reset `gc-cons-threshold',
`gc-cons-percentage' and `file-name-handler-alist'."
(unless (or (not after-init-time) noninteractive)
(dolist (hook '(doom-init-hook doom-post-init-hook))
(run-hook-wrapped hook #'doom-try-run-hook hook)))
;; If you forget to reset this, you'll get stuttering and random freezes!
(setq gc-cons-threshold 16777216
gc-cons-percentage 0.1
file-name-handler-alist doom--file-name-handler-alist)
t)
(add-hook! '(emacs-startup-hook doom-reload-hook)
#'doom|finalize))
;;
;; Emacs fixes/hacks
;;
;; Automatic minor modes
(defvar doom-auto-minor-mode-alist '()
"Alist mapping filename patterns to corresponding minor mode functions, like
`auto-mode-alist'. All elements of this alist are checked, meaning you can
enable multiple minor modes for the same regexp.")
(defun doom|enable-minor-mode-maybe ()
"Check file name against `doom-auto-minor-mode-alist'."
(when buffer-file-name
(let ((name buffer-file-name)
(remote-id (file-remote-p buffer-file-name))
(alist doom-auto-minor-mode-alist))
;; Remove backup-suffixes from file name.
(setq name (file-name-sans-versions name))
;; Remove remote file name identification.
(when (and (stringp remote-id)
(string-match-p (regexp-quote remote-id) name))
(setq name (substring name (match-end 0))))
(while (and alist (caar alist) (cdar alist))
(if (string-match-p (caar alist) name)
(funcall (cdar alist) 1))
(setq alist (cdr alist))))))
(add-hook 'find-file-hook #'doom|enable-minor-mode-maybe)
(defun doom*set-indirect-buffer-filename (orig-fn base-buffer name &optional clone)
"In indirect buffers, `buffer-file-name' is nil, which can cause problems
with functions that require it (like modeline segments)."
(let ((file-name (buffer-file-name base-buffer))
(buffer (funcall orig-fn base-buffer name clone)))
(when (and file-name buffer)
(with-current-buffer buffer
(unless buffer-file-name
(setq buffer-file-name file-name
buffer-file-truename (file-truename file-name)))))
buffer))
(advice-add #'make-indirect-buffer :around #'doom*set-indirect-buffer-filename)
(defun doom*no-authinfo-for-tramp (orig-fn &rest args)
"Don't look into .authinfo for local sudo TRAMP buffers."
(let ((auth-sources (if (equal tramp-current-method "sudo") nil auth-sources)))
(apply orig-fn args)))
(advice-add #'tramp-read-passwd :around #'doom*no-authinfo-for-tramp)
(provide 'core)
;;; core.el ends here

View file

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

View file

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

View file

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

View file

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

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
;write ; emacs as a word processor (latex + org + markdown)
;; This is the private module of Doom's maintainer; use it as a reference
;; Private modules are where you place your personal configuration files.
;; By default, they are not tracked. There is one module included here,
;; the defaults module. It contains a Spacemacs-inspired keybinding
;; scheme and additional ex commands for evil-mode. Use it as a reference
;; for your own.
:private hlissner)
:private default)

View file

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

View file

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

View file

@ -14,20 +14,23 @@ This module adds code-completion support, powered by [[https://github.com/compan
- [[#troubleshooting][Troubleshooting]]
* Install
Certain languages may require additional setup, and some languages may have no completion support at all.
Some languages require additional setup, and some languages may have no
completion support at all.
Check the README.org in that language's module for details.
* Configure
** Auto-completion
By default, I've disabled auto-completion. This is my preference. I prefer to invoke company when I need it by calling ~company-complete~ manually (typically, bound to =C-SPC= in insert mode). However, some may not share my preference.
By default, I've disabled auto-completion. This is my preference. I prefer to
invoke company when I need it by calling ~company-complete~ manually (typically,
bound to =C-SPC= in insert mode). However, some may not share my preference.
To enable auto-completion you must:
1. Load ~company~,
2. and change ~company-idle-delay~ to a non-nil float (the default is 0.5)
For example, add the following to your ~modules/private/<username>/config.el~ module:
For example:
#+BEGIN_SRC emacs-lisp
(require 'company)
@ -36,8 +39,10 @@ For example, add the following to your ~modules/private/<username>/config.el~ mo
#+END_SRC
* Troubleshooting
If completion isn't working for you, please consider the following before posting a bug report:
If completion isn't working for you, please consider the following before
posting a bug report:
+ If what you are expecting is popup-as-you-type completion (which is disabled by default), see the "Customize" section above; it includes instructions on how to enable this.
+ Certain languages may have extra dependencies in order for auto-completion to work. Please look for that module's README.org for details.
+ Some languages don't have any auto-completion support.
+ If what you are expecting is popup-as-you-type completion (which is disabled
by default), see the "Configure > Auto-completion" section above, which will
instruct you on how to enable this.
+ Some languages don't have any auto-completion support at all.

View file

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

View file

@ -3,11 +3,13 @@
This module adds Ivy, a completion backend.
#+begin_quote
I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's lighter.
I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's
lighter.
#+end_quote
+ Project-wide search & replace powered by ~rg~ or ~ag~
+ Project jump-to navigation ala Command-T, Sublime Text's Jump-to-anywhere or Vim's CtrlP plugin.
+ Project jump-to navigation ala Command-T, Sublime Text's Jump-to-anywhere or
Vim's CtrlP plugin.
+ Ivy integration for ~M-x~, ~imenu~, ~recentf~ and others.
+ A powerful, interactive in-buffer search using ~swiper~.
+ Ivy-powered TODO/FIXME navigation
@ -28,7 +30,9 @@ I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's l
* Install
This module optionally depends on [[https://github.com/BurntSushi/ripgrep][ripgrep]] and [[https://github.com/ggreer/the_silver_searcher][the_silver_searcher]].
~rg~ is faster, but its results aren't deterministic, neither does it support multiline search or full PCRE, that's where ~ag~ is useful.
~rg~ is faster, but its results aren't deterministic, neither does it support
multiline search or full PCRE (at the time of writing), that's where ~ag~ is
useful.
** MacOS
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
@ -41,37 +45,58 @@ sudo pacman --needed --noconfirm -S ripgrep the_silver_searcher
#+END_SRC
* Usage
Here is some insight into how I use this module. Keep in mind that the referenced commands and keybindings are defined [[/modules/private/hlissner][in my private module]].
Here is some insight into how I use this module.
** Project search & replace
Ex interfaces to Ag (the silver searcher) and Rg (ripgrep) are available: ~:ag[!]~ and ~:rg[!]~, or their current-directory counterparts ~:agcwd[!]~ and ~:rgcwd[!]~.
There are four Ex interfaces for the silver searcher and ripgrep. They are:
+ ~:ag[!]~
+ ~:agcwd[!]~
+ ~:rg[!]~
+ ~:rgcwd[!]~
The optional BANG tells ag/rg to include ignored files in the search. And the
\*cwd variant of each command will only search in the current directory
(non-recursively).
[[/../screenshots/modules/completion/ivy/ivy-search.gif]]
From this session, you can press =S+Tab= to create a writeable occur-buffer in wgrep mode.
Now, how do we do text replacements? With the ivy popup open you can press
=S+Tab= to create an wgrep buffer out of the results.
[[/../screenshots/modules/completion/ivy/ivy-search-replace.gif]]
Make your modifications and press =C-c C-c= to commit them, or =C-c C-k= to abort.
Make your modifications and press =C-c C-c= to commit them, or =C-c C-k= to
abort.
** Jump-to-file project navigation
Inspired by Sublime Text's jump-to-anywhere, Vim's CtrlP or Unite plugins, and Textmate's Command-T, a marriage of ~projectile~ and ~ivy~ makes this available to you in Emacs. Invoke it with =SPC f /=, =SPC SPC= or ~counsel-projectile-find-file~.
Inspired by Sublime Text's jump-to-anywhere, Vim's CtrlP/Unite plugins, and
Textmate's Command-T, a marriage of ~projectile~ and ~ivy~ makes this available
in Emacs.
Invoke it with =SPC f /=, =SPC SPC= or ~M-x counsel-projectile-find-file~.
[[/../screenshots/modules/completion/ivy/ivy-projectile.gif]]
** In-buffer searching
I use ~evil-search~ (invoked by pressing =/= in normal mode) when jumping small/moderate (or predictable) distances. However, there are occasions where I need more feedback, so I turn to ~swiper~ (available directly with =M-x swiper RET=, or via ~:sw[iper]~).
I use ~evil-search~ (invoked by pressing =/= in normal mode) when jumping
small/moderate (or predictable) distances. However, there are occasions where I
need more feedback, so I turn to ~swiper~ (available directly with =M-x swiper
RET=, or via ~:sw[iper]~).
[[/../screenshots/modules/completion/ivy/ivy-swiper.gif]]
** Task lookup
I sprinkle my projects with TODO's & FIXME's. You can navigate to and peruse them via ~M-x +ivy/tasks~ or ~:todo[!]~ (ex command).
I sprinkle my projects with TODO's & FIXME's. You can navigate to and peruse
them via ~M-x +ivy/tasks~ or ~:todo[!]~ (ex command).
[[/../screenshots/modules/completion/ivy/ivy-todo.gif]]
* Appendix
** Commands
Here is a list of my commonly used commands, their default keybinds (defined in [[../../private/hlissner/+bindings.el][private/hlissner/+bindings.el]]), and their corresponding ex command (defined in [[../../private/hlissner/+commands.el][private/hlissner/+commands.el]]).
Here is a list of my commonly used commands, their default keybinds (defined in
[[../../private/default/+bindings.el][private/default/+bindings.el]]), and their corresponding ex command (defined in
[[../../private/default/+evil-commands.el][private/default/+evil-commands.el]]).
| command | key / ex command | description |
|-------------------------------------+------------------------+------------------------------------------------------------------|
@ -90,7 +115,8 @@ Here is a list of my commonly used commands, their default keybinds (defined in
| ~+ivy:swiper~ | ~:sw[iper] [QUERY]~ | Search current buffer |
| ~+ivy:todo~ | ~:todo[!]~ | List all TODO/FIXMEs in project (or current file if BANG) |
While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new keybindings are available to you:
While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new
keybindings are available to you:
| key | description |
|-------------+--------------------------------------------------------------------------------|
@ -99,10 +125,10 @@ While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new keybindi
| =M-RET= | Open the selected candidate in other-window |
** Hacks
+ Functions with ivy/counsel equivalents have been globally remapped (like ~find-file~ => ~counsel-find-file~). So a keybinding to ~find-file~ will invoke ~counsel-find-file~ instead.
+ ~counsel-[arp]g~'s 3-character limit was reduced to 1 (mainly for the ex command)
+ ~counsel-[arp]g~'s parentheses quoting behavior was reversed. Now, if you
want literal parentheses, you must escape them: e.g. ~\(match\)~ is literal,
~(match)~ is a regexp group.
+ Functions with ivy/counsel equivalents have been globally remapped (like
~find-file~ => ~counsel-find-file~). So a keybinding to ~find-file~ will
invoke ~counsel-find-file~ instead.
+ ~counsel-[arp]g~'s 3-character limit was reduced to 1 (mainly for the ex
command)

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! yasnippet (push #'+ivy-yas-prompt yas-prompt-functions))
(map! :map ivy-mode-map
[remap apropos] #'counsel-apropos
(map! [remap apropos] #'counsel-apropos
[remap describe-face] #'counsel-describe-face
[remap find-file] #'counsel-find-file
[remap switch-to-buffer] #'ivy-switch-buffer
@ -52,7 +51,6 @@ immediately runs it on the current candidate (ending the ivy session)."
[remap recentf-open-files] #'counsel-recentf
[remap imenu] #'counsel-imenu
[remap bookmark-jump] #'counsel-bookmark
[remap projectile-switch-project] #'counsel-projectile-switch-project
[remap projectile-find-file] #'counsel-projectile-find-file
[remap imenu-anywhere] #'ivy-imenu-anywhere
[remap execute-extended-command] #'counsel-M-x

View file

@ -1,43 +1,52 @@
#+TITLE: :feature eval
This modules adds support for evaluating code from inside Emacs. This includes REPLs and direct access to the interpreters and compilers of many languages.
This modules adds support for evaluating code from inside Emacs, including
REPLs.
* Table of Contents :TOC:
- [[#install][Install]]
- [[#usage][Usage]]
- [[#configuration][Configuration]]
- [[#repls][REPLs]]
- [[#code-evaluation][Code Evaluation]]
- [[#code-evaluation][*Code Evaluation*]]
- [[#configuration][Configuration]]
- [[#repls-1][REPLs]]
- [[#code-evaluation-1][Code Evaluation]]
* Install
This module has no external dependencies. However, specific languages may require additional setup.
This module has no external dependencies. However, specific languages may
require additional setup.
Check the README.org in that language's module for details.
* Usage
+ *REPLs*
Invoked via:
+ ~:repl~ (evil ex-command)
+ =<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/send-region-to-repl~ while a selection (and REPL) is active
** REPLs
Invoked via:
+ ~:repl~ (evil ex-command)
+ =<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/send-region-to-repl~ while a selection (and REPL) is active
+ *Code Evaluation*
Quickrun can be invoked via:
+ ~M-x +eval/buffer~ (or ~gR~, or ~M-r~)
+ ~M-x +eval/region~
+ ~M-x +eval/region-and-replace~
+ Evil users can use the ~gr~ operator to select and run a region.
** *Code Evaluation*
Quickrun can be invoked via:
+ ~M-x +eval/buffer~ (or ~gR~, or ~M-r~)
+ ~M-x +eval/region~
+ ~M-x +eval/region-and-replace~
+ Evil users can use the ~gr~ operator to select and run a region.
* Configuration
** REPLs
REPLs are defined for most of the languages Doom supports (check its README.org to see if it does).
REPLs are defined for most of the languages Doom supports (check its README.org
to see if it does).
Otherwise, you can define your own for a specified major-mode with the =:repl= setting.
Otherwise, you can define your own for a specified major-mode with the =:repl=
setting.
~(set! :repl MAJOR-MODE FUNCTION)~
FUNCTION must return the repl buffer. Any window changes are ignored, then handed off to shackle (assuming shackle-mode is on) to display in a popup window.
FUNCTION must return the repl buffer. Any window changes are ignored, then
handed off to shackle (assuming shackle-mode is on) to display in a popup
window.
#+BEGIN_SRC emacs-lisp
(defun +emacs-lisp/repl ()
@ -53,9 +62,14 @@ FUNCTION must return the repl buffer. Any window changes are ignored, then hande
#+END_SRC
** Code Evaluation
Run regions or entire buffers with [[https://github.com/syohex/emacs-quickrun][Quickrun]]. Output will be sent to a popup window.
Run regions or entire buffers with [[https://github.com/syohex/emacs-quickrun][Quickrun]]. Output is show in a popup window.
Quickrun includes support for many languages, but occasionally, you'll find a language without support, such as [[https://crystal-lang.org/][Crystal]]. A "runner" can be defined like so:
Quickrun includes support for many languages, usually by sending text directly
to interpreters or compilers. However, occasionally, you'll find a language
without support (like [[https://crystal-lang.org/][Crystal]]), or a language with better Emacs integration
(like elisp).
Here's how you define a "runner":
#+BEGIN_SRC emacs-lisp
(set! :eval 'crystal-mode

View file

@ -11,12 +11,14 @@ This holy module brings the vim experience to Emacs.
- [[#differences-from-vim][Differences from vim]]
* Removing evil-mode
To get back a more vanilla Emacs experience, remove =:feature evil= from init.el. Evil-specific configuration and keybindings (defined with ~map!~) will be ignored without evil present (and removed when byte-compiling).
See the [[https://github.com/hlissner/doom-emacs/wiki/FAQ#remove-vimevil-for-a-more-vanilla-emacs-experience][corresponding question in the FAQ]].
* Features
+ A better ~:g[lobal]~ command with incremental highlighting.
+ Adds the ~:al[ign]~ ex command: offers an ex interface to ~align-regexp~ with incremental highlighting.
+ Support for more of vim's filename modifiers in ex commands (like ~:p~, ~:p:h~ or ~:t~) than vanilla evil-mode offers.
+ Adds the ~:al[ign]~ ex command: offers an ex interface to ~align-regexp~ with
incremental highlighting.
+ Support for more of vim's filename modifiers in ex commands (like ~:p~, ~:p:h~
or ~:t~) than vanilla evil-mode offers.
+ A list of new text objects:
+ Blocks: ~B~ (from ~evil-textobj-anyblock~)
+ Args: ~a~ (from ~evil-args~)
@ -31,20 +33,29 @@ To get back a more vanilla Emacs experience, remove =:feature evil= from init.el
+ =NERDTree= equivalent is available in =:tools neotree=
** Multiple-cursors
Two multiple-cursor implementations exist in this module: ~evil-mc~ and ~evil-multiedit~. Together, these provide the functionality of ~vim-multiple-cursors~.
Two multiple-cursor implementations exist in this module: ~evil-mc~ and
~evil-multiedit~. Together, these provide the functionality of
~vim-multiple-cursors~.
The former lets you place "clone" cursors. The latter lets you interactively edit many regions from one place (like an interactive version of ~:%s~).
The former lets you place "clone" cursors. The latter lets you interactively
edit many regions at once (like an interactive version of ~:%s~).
** A hybrid code-folding system
This module combines ~evil-vimish-fold~ and ~hideshow~. The former allows arbitrary folds and the latter allows folds on markers and indentation. Together, they create a more consistent (and feature-complete) code-folding system.
This module combines ~evil-vimish-fold~ and ~hideshow~. The former allows
arbitrary folds and the latter allows folds on markers and indentation.
Together, they create a more consistent (and feature-complete) code-folding
system.
Most vim folding keys should work, e.g. =zr=, =zm=, =za=, =zo=, etc.
** Hacks
+ Automatically moves to new window when splitting
+ If in visual mode, =*= and =#= will search for the current selection instead of the word-at-point.
+ From visual mode, =*= and =#= will search for the current selection instead of
the word-at-point.
** Differences from vim
+ Column-wise ranges in ex commands are enabled by default. i.e. the range in =:'<,'>s/a/b= will only affects the visual selection, not full lines (see ~evil-ex-visual-char-range~).
+ Column-wise ranges in ex commands are enabled by default. i.e. the range in
=:'<,'>s/a/b= will only affects the visual selection, not full lines (see
~evil-ex-visual-char-range~).
+ =:g= will incrementally highlight buffer matches.

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)
;; Ensures that windows displaying this buffer will be switched
;; to real buffers (`doom-real-buffer-p')
(doom-force-kill-buffer buf t)
(doom/kill-this-buffer-in-all-windows buf t)
(+evil--forget-file fname)
(message "Successfully deleted %s" short-path))))))))

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

View file

@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; feature/evil/test/autoload-files.el
(defmacro -with-temp-files! (src dest &rest body)
(defmacro with-temp-files!! (src dest &rest body)
"Run FORMS in the context of a temporary package setup (as in, it won't
affects your Emacs packages)."
(declare (indent 2) (doc-string 3))
@ -23,7 +23,7 @@ affects your Emacs packages)."
;;
(def-test! move-this-file
":mv"
(-with-temp-files! "/tmp/doom-buffer" "/tmp/doom-buffer-new"
(with-temp-files!! "/tmp/doom-buffer" "/tmp/doom-buffer-new"
(should-error (+evil:move-this-file it))
(should (+evil:move-this-file other t))
(should (file-exists-p other))
@ -31,7 +31,7 @@ affects your Emacs packages)."
(def-test! copy-this-file
":cp"
(-with-temp-files! "/tmp/doom-buffer-2" "/tmp/doom-buffer-2-new"
(with-temp-files!! "/tmp/doom-buffer-2" "/tmp/doom-buffer-2-new"
(should-error (+evil:copy-this-file it))
(should (+evil:copy-this-file other t))
(should (file-exists-p other))
@ -39,7 +39,7 @@ affects your Emacs packages)."
(def-test! delete-this-file
":rm"
(-with-temp-files! "/tmp/doom-buffer-3" nil
(with-temp-files!! "/tmp/doom-buffer-3" nil
(should-error (+evil:delete-this-file "this-file-does-not-exist"))
(should (+evil:delete-this-file nil t))
(should (not (file-exists-p it)))))

View file

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

View file

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

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

View file

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

View file

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

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)
(+jump-to :documentation identifier))
(t
(+jump/online (caar +jump-search-provider-alist) identifier))))
(+jump/online
identifier
(+jump--online-get-provider (not current-prefix-arg))))))
(defun +jump--online-get-provider (&optional force-p)
(or (and (not force-p)

View file

@ -29,7 +29,7 @@
"An alist that maps online resources to their search url or a function that
produces an url. Used by `+jump/online'.")
(defconst +jump-search-browser-fn #'browse-url
(defvar +jump-search-browser-fn #'browse-url
"Function to use to open search urls.")
(defvar +jump-function-alist nil
@ -82,6 +82,18 @@ properties:
;; Packages
;;
(def-package! ivy-xref
:when (featurep! :completion ivy)
:after xref
:config (setq xref-show-xrefs-function #'ivy-xref-show-xrefs))
(def-package! helm-xref
:when (featurep! :completion helm)
:after xref
:config (setq xref-show-xrefs-function #'helm-xref-show-xrefs))
(def-package! dumb-jump
:commands (dumb-jump-go dumb-jump-quick-look
dumb-jump-back dumb-jump-result-follow)
@ -92,28 +104,3 @@ properties:
((featurep! :completion helm) 'helm)
(t 'popup))))
(def-package! gxref
:commands (gxref-xref-backend
gxref-create-db
gxref-update-db
gxref-single-update-db
gxref-set-project-dir)
:init
(setq-default xref-backend-functions '(gxref-xref-backend t)))
;; (def-package! ggtags
;; :commands (ggtags-find-tag-dwim
;; ggtags-find-tag-mouse
;; ggtags-find-definition
;; ggtags-find-reference
;; ggtags-find-other-symbol
;; ggtags-find-tag-regexp
;; ggtags-idutils-query
;; ggtags-grep
;; ggtags-find-file
;; ggtags-query-replace
;; ggtags-delete-tags
;; ggtags-explain-tags))

View file

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

View file

@ -8,20 +8,5 @@ This module adds snippets to Emacs, powered by yasnippet.
* Install
There are no extra dependencies for this module.
By default, this module uses the snippet library included with yasnippet.
For the best experience, I'd suggest installing mine from https://github.com/hlissner/emacs-snippets -- they have been tailored specifically for Doom.
1. Clone the repo to your private module:
#+BEGIN_SRC bash
git clone https://github.com/hlissner/emacs-snippets ~/.emacs.d/modules/private/$(whoami)/snippets
#+END_SRC
2. Tell yasnippet where to look for them:
#+BEGIN_SRC emacs-lisp
;; modules/private/{USERNAME}/config.el
(after! yasnippet
(setq yas-snippet-dirs
(append (list (expand-file-name "snippets/" (file-name-directory load-file-name)))
(delq 'yas-installed-snippets-dir yas-snippet-dirs))))
#+END_SRC
By default, =private/default= installs a snippet library tailored exclusively
for Doom Emacs.

View file

@ -11,8 +11,6 @@
(defvar yas-minor-mode-map (make-sparse-keymap))
:init
(setq yas-snippet-dirs '(yas-installed-snippets-dir))
;; Ensure `yas-reload-all' is called as late as possible. Other modules could
;; have additional configuration for yasnippet. For example, file-templates.
(add-transient-hook! 'yas-minor-mode-hook (yas-reload-all))
@ -21,11 +19,9 @@
#'yas-minor-mode-on)
:config
(setq yas-verbosity 0
yas-indent-line 'auto
(setq yas-verbosity (if doom-debug-mode 3 0)
yas-also-auto-indent-first-line t
yas-prompt-functions '(yas-completing-prompt yas-ido-prompt yas-no-prompt)
yas-use-menu nil
yas-prompt-functions (delq 'yas-dropdown-prompt yas-prompt-functions)
;; Allow nested snippets
yas-triggers-in-field t)
@ -40,27 +36,8 @@
;; fix an error caused by smartparens interfering with yasnippet bindings
(advice-add #'yas-expand :before #'sp-remove-active-pair-overlay)
(after! evil
;; Exit snippets on ESC in normal mode
(add-hook '+evil-esc-hook #'yas-exit-all-snippets)
;; Once you're in normal mode, you're out
(add-hook 'evil-normal-state-entry-hook #'yas-abort-snippet)
;; Strip out whitespace before a line selection
(defun +snippets|yas-before-expand ()
"Strip out the shitespace before a line selection."
(when (and (evil-visual-state-p)
(eq (evil-visual-type) 'line))
(setq yas-selected-text
(replace-regexp-in-string
"\\(^\\s-*\\|\n? $\\)" ""
(buffer-substring-no-properties evil-visual-beginning
evil-visual-end)))))
(add-hook 'yas-before-expand-snippet-hook #'+snippets|yas-before-expand)
(defun +snippets|yas-after-expand ()
"Fix previous hook persisting yas-selected-text between expansions."
(setq yas-selected-text nil))
(add-hook 'yas-after-exit-snippet-hook #'+snippets|yas-after-expand)))
;; Exit snippets on ESC from normal mode
(add-hook '+evil-esc-hook #'yas-exit-all-snippets))
(def-package! auto-yasnippet

View file

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

View file

@ -1,9 +1,15 @@
#+TITLE: :feature workspaces
This module adds support for workspaces, powered by persp_mode, as well as a unified API for manipulating them.
This module adds support for workspaces, powered by persp_mode, as well as a API
for manipulating them.
#+begin_quote
There are many ways to use workspaces. Some use them to group buffers/windows by project or categories (views, models, logic, etc). I use them differently: on a per-task basis, which may traverse multiple projects or aspects, but are tied to an objective. For example: implement a specific feature or fix a certain bug; sometimes unrelated to the project at hand.
There are many ways to use workspaces. I spawn a workspace per task. Say I'm
working in the main workspace, when I realize there is a bug in another part of
my project. I open a new workspace and deal with it in there. In the meantime, I
need to check my email, so mu4e gets its own workspace.
Once I've completed the task, I close the workspace and return to main.
#+end_quote
* Table of Contents :TOC:
@ -22,25 +28,33 @@ This module has no additional dependencies.
* Features
** Isolated buffer-list
When persp-mode is active, ~doom-buffer-list~ becomes workspace-restricted. You can overcome this by using ~buffer-list~.
When persp-mode is active, ~doom-buffer-list~ becomes workspace-restricted. You
can overcome this by using ~buffer-list~.
** Automatic workspaces
A workspace is automatically created (and switched to) when you:
+ Create a new frame (with =make-frame=; bound to =M-N= by default)
+ Switch to a project using ~projectile-switch-project~ (or its ivy/helm equivalents)
+ Create a new frame (with =make-frame=; bound to =M-N= by default).
+ Switch to a project using ~projectile-switch-project~.
** Session persistence
By default, your session is autosaved when you quit Emacs (or disable ~persp-mode~). You can load a previous session with ~M-x +workspace/load-session~ or ~:sl[oad]~ (ex command).
By default, your session is autosaved when you quit Emacs (or disable
~persp-mode~). You can load a previous session with ~M-x
+workspace/load-session~ or ~:sl[oad]~ (ex command).
You can supply either a name to load a specific session to replace your current one.
You can supply either a name to load a specific session to replace your current
one.
** Workspace persistence
If you'd like to save a specific workspace, use ~M-x +workspace/save~, which can be loaded into the current session (as another workspace) with ~M-x +workspace/load~.
If you'd like to save a specific workspace, use ~M-x +workspace/save~, which can
be loaded into the current session (as another workspace) with ~M-x
+workspace/load~.
* Appendix
** Commands & Keybindings
Here is a list of available commands, their default keybindings (defined in private/hlissner/+bindings.el), and corresponding ex commands (if any -- defined in private/hlissner/+commands.el).
Here is a list of available commands, their default keybindings (defined in
[[../../private/default/+bindings.el][private/default/+bindings.el]]), and corresponding ex commands (if any -- defined
in [[../../private/default/+evil-commands.el][private/default/+evil-commands.el]]).
| command | key / ex command | description |
|---------------------------+----------------------------+------------------------------------------------------------|

View file

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

View file

@ -47,10 +47,22 @@ renamed.")
;; per-frame and per-project workspaces
(setq persp-init-new-frame-behaviour-override nil
persp-interactive-init-frame-behaviour-override #'+workspace-on-new-frame
projectile-switch-project-action #'projectile-find-file)
persp-interactive-init-frame-behaviour-override #'+workspace-on-new-frame)
(add-hook 'delete-frame-functions #'+workspaces|delete-associated-workspace-maybe)
(advice-add #'projectile-switch-project-by-name :around #'+workspaces*switch-project-by-name)
(defun +workspaces|per-project (&optional root)
"Open a new workspace when switching to another project.
Ensures the scratch (or dashboard) buffers are CDed into the project's root."
(when persp-mode
(let ((cwd default-directory))
(+workspace-switch (projectile-project-name) t)
(switch-to-buffer (doom-fallback-buffer))
(setq default-directory cwd)
(+workspace-message
(format "Switched to '%s' in new workspace" (+workspace-current-name))
'success))))
(setq projectile-switch-project-action #'+workspaces|per-project)
;; only auto-save when real buffers are present
(advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers)
@ -68,7 +80,10 @@ renamed.")
(remove-hook 'delayed-warnings-hook #'display-delayed-warnings)
(defun +workspaces|init (&optional frame)
(unless persp-mode
(persp-mode +1))
(persp-mode +1)
;; Ensure `persp-kill-buffer-query-function' is last in kill-buffer-query-functions
(remove-hook 'kill-buffer-query-functions 'persp-kill-buffer-query-function)
(add-hook 'kill-buffer-query-functions 'persp-kill-buffer-query-function t))
(let ((frame (or frame (selected-frame))))
(unless noninteractive
;; The default perspective persp-mode makes (defined by

View file

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

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~)
+ eldoc support (~irony-eldoc~)
+ Syntax-checking (~flycheck-irony~)
+ Code navigation (~irony~)
+ Code navigation (~rtags~)
+ File Templates ([[../../feature/file-templates/templates/c-mode][c-mode]], [[../../feature/file-templates/templates/c++-mode][c++-mode]])
+ Snippets ([[https://github.com/hlissner/emacs-snippets/tree/master/cc-mode][cc-mode]], [[https://github.com/hlissner/emacs-snippets/tree/master/c-mode][c-mode]], [[https://github.com/hlissner/emacs-snippets/tree/master/c++-mode][c++-mode]])
+ Several improvements to C++11 indentation and syntax highlighting.
#+begin_quote
C contends with Haskell and Ruby for my favorite language. That said, it's more accurate to say I write C, but with two or three C++ features.
C contends with Haskell and Ruby for my favorite language. That said, it's more
accurate to say I write C, but a C++ feature or three.
The module provides nominal support for Objective-C, which I really only use to inspect generated glue code for iOS mobile apps. Otherwise, I prefer Swift.
The module provides nominal support for Objective-C, which I really only use to
inspect generated glue code for iOS mobile apps. Otherwise, I prefer Swift.
#+end_quote
* Table of Contents :TOC:
- [[#install][Install]]
- [[#macos][MacOS]]
- [[#arch-linux][Arch Linux]]
- [[#irony-server][irony-server]]
- [[#rtags][rtags]]
- [[#configure][Configure]]
- [[#compile-settings][Compile settings]]
* Install
This module requires ~irony-server~ for most of its features, which depends on ~cmake~ and ~libclang~.
This module requires:
** MacOS
+ irony-server
+ rtags
** irony-server
Irony powers the code completion, eldoc and syntax checking systems.
*** MacOS
Due to linking issues, MacOS users must compile irony-server manually:
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
@ -49,10 +59,46 @@ popd
rm -rf irony-mode
#+END_SRC
** Arch Linux
*** Arch Linux
#+BEGIN_SRC sh :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S clang cmake
#+END_SRC
Then run ~M-x irony-install-server~ in Emacs.
** rtags
Code navigation requires an [[https://github.com/Andersbakken/rtags][rtags]] server (~rdm~) installed and running. This
should be available through your OS's package manager.
This module will auto-start ~rdm~ when you open C/C++ buffers (so long as one
isn't already). If you prefer to run it yourself, outside of Emacs:
#+BEGIN_SRC sh
rdm &
rc -J $PROJECT_ROOT # loads PROJECT_ROOT's compile_commands.json
#+END_SRC
* Configure
** Compile settings
By default, a set of default compile settings are defined in
~+cc-default-compiler-options~ for C, C++ and Objective C. Irony, rtags and
flycheck will fall back to these.
To make these tools aware of project specific build settings, you need a JSON
[[https://sarcasm.github.io/notes/dev/compilation-database.html#ninja][compilation database]] present (i.e. a ~compile_commands.json~ file).
There are [[https://sarcasm.github.io/notes/dev/compilation-database.html][many ways to generate one]]. I use [[http://www.cmake.org/][CMake]] and [[https://github.com/rizsotto/Bear][bear]]:
#+BEGIN_SRC sh
# For CMake projects
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
# For non-CMake projects
make clean
bear make
#+END_SRC
#+begin_quote
Use ~M-x +cc/reload-compile-db~ to reload your compile db in an already-open
C/C++/ObjC buffer.
#+end_quote

View file

@ -1,5 +1,24 @@
;;; lang/cc/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +cc/reload-compile-db (&optional force-p)
"Reload the current project's JSON compilation database."
(interactive "P")
(unless (memq major-mode '(c-mode c++-mode objc-mode))
(user-error "Not a C/C++/ObjC buffer"))
(unless (doom-project-has! "compile_commands.json")
(user-error "No compile_commands.json file"))
;; first rtag
(when (and (featurep 'rtags)
rtags-enabled
(executable-find "rc"))
(with-temp-buffer
(message "Reloaded compile commands for rtags daemon")
(rtags-call-rc :silent t "-J" (doom-project-root))))
;; then irony
(when (and (featurep 'irony) irony-mode)
(+cc|irony-init-compile-options)))
;;;###autoload
(defun +cc*align-lambda-arglist (orig-fun &rest args)
"Improve indentation of continued C++11 lambda function opened as argument."
@ -66,8 +85,8 @@
;;;###autoload
(defun +cc|irony-init-compile-options ()
"Initialize compiler options for irony-mode. It searches for the nearest
compilation database and initailizes it. If none was found, it uses
`+cc-c++-compiler-options'.
compilation database and initailizes it, otherwise falling back on
`+cc-default-compiler-options' and `+cc-default-include-paths'.
See https://github.com/Sarcasm/irony-mode#compilation-database for details on
compilation dbs."
@ -75,8 +94,8 @@ compilation dbs."
(require 'irony-cdb)
(unless (irony-cdb-autosetup-compile-options)
(irony-cdb--update-compile-options
(append (delq nil (cdr-safe (assq major-mode +cc-compiler-options)))
(cl-loop for path in +cc-include-paths
(append (delq nil (cdr-safe (assq major-mode +cc-default-compiler-options)))
(cl-loop for path in +cc-default-include-paths
nconc (list "-I" path)))
(doom-project-root)))))

View file

@ -1,13 +1,11 @@
;;; lang/cc/config.el --- c, c++, and obj-c -*- lexical-binding: t; -*-
(defvar +cc-include-paths (list "include/")
"A list of paths, relative to a project root, to search for headers in C/C++.
Paths can be absolute.
(defvar +cc-default-include-paths (list "include/")
"A list of default paths, relative to a project root, to search for headers in
C/C++. Paths can be absolute. This is ignored if your project has a JSON
compilation database.")
The purpose of this variable is to ensure syntax checkers and code-completion
knows where to look for headers.")
(defvar +cc-compiler-options
(defvar +cc-default-compiler-options
`((c-mode . nil)
(c++-mode
. ,(list "-std=c++11" ; use C++11 by default
@ -112,12 +110,16 @@ compilation database is present in the project.")
:after cc-mode
:commands irony-install-server
:preface (setq irony-server-install-prefix (concat doom-etc-dir "irony-server/"))
:hook ((c-mode c++-mode objc-mode) . irony-mode)
:init
(defun +cc|init-irony-mode ()
(when (memq major-mode '(c-mode c++-mode objc-mode))
(irony-mode +1)))
(add-hook! (c-mode c++-mode objc-mode) #'+cc|init-irony-mode)
:config
(unless (file-directory-p irony-server-install-prefix)
(warn "irony-mode: server isn't installed; run M-x irony-install-server"))
;; Initialize compilation database, if present. Otherwise, fall back on
;; `+cc-compiler-options'.
;; `+cc-default-compiler-options'.
(add-hook 'irony-mode-hook #'+cc|irony-init-compile-options))
(def-package! irony-eldoc
@ -144,7 +146,8 @@ compilation database is present in the project.")
;;
(def-package! cmake-mode
:mode "CMakeLists\\.txt$"
:mode "/CMakeLists\\.txt$"
:mode "\\.cmake\\$"
:config
(set! :company-backend 'cmake-mode '(company-cmake company-yasnippet)))
@ -163,19 +166,76 @@ compilation database is present in the project.")
;;
;; Plugins
;; Company plugins
;;
(when (featurep! :completion company)
(def-package! company-cmake :after cmake-mode)
(def-package! company-cmake
:when (featurep! :completion company)
:after cmake-mode)
(def-package! company-irony :after irony)
(def-package! company-irony
:when (featurep! :completion company)
:after irony)
(def-package! company-irony-c-headers :after company-irony)
(def-package! company-irony-c-headers
:when (featurep! :completion company)
:after company-irony)
(def-package! company-glsl
:after glsl-mode
:config
(if (executable-find "glslangValidator")
(warn "glsl-mode: couldn't find glslangValidator, disabling company-glsl")
(set! :company-backend 'glsl-mode '(company-glsl)))))
(def-package! company-glsl
:when (featurep! :completion company)
:after glsl-mode
:config
(if (executable-find "glslangValidator")
(warn "glsl-mode: couldn't find glslangValidator, disabling company-glsl")
(set! :company-backend 'glsl-mode '(company-glsl))))
;;
;; Rtags Support
;;
(def-package! rtags
:after cc-mode
:config
(setq rtags-autostart-diagnostics t
rtags-use-bookmarks nil
rtags-completions-enabled nil
;; If not using ivy or helm to view results, use a pop-up window rather
;; than displaying it in the current window...
rtags-results-buffer-other-window t
;; ...and don't auto-jump to first match before making a selection.
rtags-jump-to-first-match nil)
(let ((bins (cl-remove-if-not #'executable-find '("rdm" "rc"))))
(if (/= (length bins) 2)
(warn "cc-mode: couldn't find %s, disabling rtags support" bins)
(add-hook! (c-mode c++-mode) #'rtags-start-process-unless-running)
(set! :jump '(c-mode c++-mode)
:definition #'rtags-find-symbol-at-point
:references #'rtags-find-references-at-point)))
(add-hook 'doom-cleanup-hook #'rtags-cancel-process)
(add-hook! kill-emacs (ignore-errors (rtags-cancel-process)))
;; Use rtags-imenu instead of imenu/counsel-imenu
(map! :map (c-mode-map c++-mode-map) [remap imenu] #'rtags-imenu)
(add-hook 'rtags-jump-hook #'evil-set-jump)
(add-hook 'rtags-after-find-file-hook #'recenter))
(def-package! ivy-rtags
:when (featurep! :completion ivy)
:after rtags
:init
;; NOTE Ivy integration breaks when rtags is byte-compiled with Emacs 26 or
;; later, so we un-byte-compile it before we load it.
(eval-when-compile
(when (>= emacs-major-version 26)
(when-let* ((elc-file (locate-library "rtags.elc" t doom--package-load-path)))
(delete-file elc-file))))
:config (setq rtags-display-result-backend 'ivy))
(def-package! helm-rtags
:when (featurep! :completion helm)
:after rtags
:config (setq rtags-display-result-backend 'helm))

View file

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

View file

@ -16,7 +16,7 @@
"Evaluate a region and print it to the echo area (if one line long), otherwise
to a pop up buffer."
(require 'pp)
(let ((result (eval (read (buffer-substring-no-properties beg end))))
(let ((result (eval (read (concat "(progn " (buffer-substring-no-properties beg end) "\n)"))))
(buf (get-buffer-create "*doom eval*"))
(inhibit-read-only t)
lines)

View file

@ -10,19 +10,12 @@
meghanada-use-eldoc t
meghanada-use-auto-start t)
(add-hook 'java-mode-hook #'rainbow-delimiters-mode)
;; Setup on first use
(unless (bound-and-true-p byte-compile-current-file)
(meghanada-install-server)
(if (file-exists-p (meghanada--locate-server-jar))
(add-hook! 'meghanada-mode-hook #'(flycheck-mode eldoc-mode))
(warn "java-mode: meghanada-server not installed, java-mode will run with reduced functionality")))
(set! :jump 'java-mode
:definition #'meghanada-jump-declaration
:references #'meghanada-reference)
(add-hook! 'meghanada-mode-hook #'(flycheck-mode eldoc-mode))
;;
(def-menu! +java/refactor-menu
"Refactoring commands for `java-mode' buffers."

View file

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

View file

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

View file

@ -10,16 +10,19 @@
;; anywhere I can call org-capture (whether or not Emacs is open/running),
;; like, say, from qutebrowser, vimperator, dmenu or a global keybinding.
(defvar +org-default-todo-file "todo.org"
"TODO")
(defvar +org-default-notes-file "notes.org"
"TODO")
(defvar org-capture-templates
'(("t" "Todo" entry
(file+headline (expand-file-name "todo.org" +org-dir) "Inbox")
(file+headline +org-default-todo-file "Inbox")
"* [ ] %?\n%i" :prepend t :kill-buffer t)
("n" "Notes" entry
(file+headline org-default-notes-file "Inbox")
(file+headline +org-default-notes-file "Inbox")
"* %u %?\n%i" :prepend t :kill-buffer t)))

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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
This module brings a side panel for browsing project files, inspired by vim's NERDTree.
This module brings a side panel for browsing project files, inspired by vim's
NERDTree.
#+begin_quote
Sure, there's dired and projectile, but sometimes I'd like a bird's eye view of a project.
Sure, there's dired and projectile, but sometimes I'd like a bird's eye view of
a project.
#+end_quote

View file

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

View file

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

View file

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

View file

@ -3,20 +3,38 @@
(defvar +doom-dashboard-name " *doom*"
"The name to use for the dashboard buffer.")
(defvar +doom-dashboard-inhibit-refresh nil
"If non-nil, the doom buffer won't be refreshed.")
(defvar +doom-dashboard-widgets '(banner shortmenu loaded)
"List of widgets to display in a blank scratch buffer.")
(defvar +doom-dashboard-inhibit-refresh nil
"If non-nil, the doom buffer won't be refreshed.")
(defvar +doom-dashboard-inhibit-functions ()
"A list of functions that determine whether to inhibit the dashboard the
"A list of functions that determine whether to inhibit the dashboard from
loading.")
(defvar +doom-dashboard-pwd-policy 'last-project
"The policy to use when setting the `default-directory' in the dashboard.
Possible values:
'last-project the `doom-project-root' of the last open buffer
'last the `default-directory' of the last open buffer
a FUNCTION a function run with the `default-directory' of the last
open buffer, that returns a directory path
a STRING a fixed path
nil `default-directory' will never change")
;;
(defvar +doom-dashboard--last-cwd nil)
(defvar +doom-dashboard--width 80)
(defvar +doom-dashboard--height 0)
(defvar +doom-dashboard--old-fringe-indicator fringe-indicator-alist)
(defvar all-the-icons-scale-factor)
(defvar all-the-icons-default-adjust)
;;
(setq doom-fallback-buffer +doom-dashboard-name)
@ -25,6 +43,8 @@ loading.")
"Major mode for the DOOM dashboard buffer."
(read-only-mode +1)
(setq truncate-lines t)
(setq-local whitespace-style nil)
(setq-local show-trailing-whitespace nil)
(cl-loop for (car . _cdr) in fringe-indicator-alist
collect (cons car nil) into alist
finally do (setq fringe-indicator-alist alist)))
@ -51,15 +71,25 @@ loading.")
if in a GUI/non-daemon session."
(add-hook 'window-configuration-change-hook #'+doom-dashboard-reload)
(add-hook 'focus-in-hook #'+doom-dashboard-reload)
(add-hook 'kill-buffer-query-functions #'+doom-dashboard|kill-buffer-query-fn)
(add-hook 'kill-buffer-query-functions #'+doom-dashboard|reload-on-kill)
(when (and (display-graphic-p) (not (daemonp)))
(let ((default-directory doom-emacs-dir))
(+doom-dashboard/open (selected-frame)))))
(defun +doom-dashboard|kill-buffer-query-fn ()
(or (not (+doom-dashboard-p))
(ignore (let (+doom-dashboard-inhibit-refresh)
(ignore-errors (+doom-dashboard-reload))))))
(defun +doom-dashboard|reload-on-kill ()
"If this isn't a dashboard buffer, move along, but record its
`default-directory' if the buffer is real. See `doom-real-buffer-p' for an
explanation for what 'real' means.
If this is the dashboard buffer, reload the dashboard."
(or (unless (+doom-dashboard-p)
(when (doom-real-buffer-p)
(setq +doom-dashboard--last-cwd default-directory)
(+doom-dashboard-update-pwd))
t)
(ignore
(let (+doom-dashboard-inhibit-refresh)
(ignore-errors (+doom-dashboard-reload))))))
(defun +doom-dashboard|make-frame (frame)
"Reload the dashboard after a brief pause. This is necessary for new frames,
@ -85,55 +115,87 @@ whose dimensions may not be fully initialized by the time this is run."
(+doom-dashboard-reload)))
(setq +doom-dashboard-inhibit-refresh nil)))
;
(defun +doom-dashboard-p (&optional buffer)
"Returns t if BUFFER is the dashboard buffer."
(let ((buffer (or buffer (current-buffer))))
(and (buffer-live-p buffer)
(eq buffer (doom-fallback-buffer)))))
(eq (or buffer (current-buffer))
(doom-fallback-buffer)))
(defun +doom-dashboard-center (len s)
(concat (make-string (ceiling (max 0 (- len (length s))) 2) ? )
s))
(defun +doom-dashboard-update-pwd ()
"TODO"
(with-current-buffer (doom-fallback-buffer)
(cd (or (+doom-dashboard--get-pwd)
default-directory))))
(defun +doom-dashboard-reload (&optional dir)
(defun +doom-dashboard-reload (&optional force)
"Update the DOOM scratch buffer (or create it, if it doesn't exist)."
(when (get-buffer-window (doom-fallback-buffer))
(unless (or +doom-dashboard-inhibit-refresh
(window-minibuffer-p (frame-selected-window)))
(let ((old-pwd (or dir default-directory))
(fallback-buffer (doom-fallback-buffer)))
(with-current-buffer fallback-buffer
(with-silent-modifications
(unless (eq major-mode '+doom-dashboard-mode)
(+doom-dashboard-mode))
(erase-buffer)
(setq default-directory old-pwd)
(let ((+doom-dashboard--height (window-height (get-buffer-window fallback-buffer)))
(lines 1)
content)
(with-temp-buffer
(dolist (widget-name +doom-dashboard-widgets)
(funcall (intern (format "doom-dashboard-widget--%s" widget-name)))
(insert "\n"))
(setq content (buffer-string)
lines (count-lines (point-min) (point-max))))
(insert (make-string (max 0 (- (/ +doom-dashboard--height 2)
(/ lines 2)))
?\n)
content))
(unless (button-at (point))
(goto-char (next-button (point-min))))))))
(let ((fallback-buffer (doom-fallback-buffer)))
(when (or (and after-init-time
(not +doom-dashboard-inhibit-refresh)
(get-buffer-window fallback-buffer)
(not (window-minibuffer-p (frame-selected-window))))
force)
(with-current-buffer fallback-buffer
(+doom-dashboard-update-pwd)
(with-silent-modifications
(unless (eq major-mode '+doom-dashboard-mode)
(+doom-dashboard-mode))
(erase-buffer)
(let ((+doom-dashboard--height
(window-height (get-buffer-window fallback-buffer)))
(lines 1)
content)
(with-temp-buffer
(dolist (widget-name +doom-dashboard-widgets)
(funcall (intern (format "doom-dashboard-widget--%s" widget-name)))
(insert "\n"))
(setq content (buffer-string)
lines (count-lines (point-min) (point-max))))
(insert (make-string (max 0 (- (/ +doom-dashboard--height 2)
(/ lines 2)))
?\n)
content))
(unless (button-at (point))
(goto-char (next-button (point-min)))))))
;; Update all dashboard windows
(dolist (win (get-buffer-window-list (doom-fallback-buffer) nil t))
(dolist (win (get-buffer-window-list fallback-buffer nil t))
(set-window-fringes win 0 0)
(set-window-margins
win (max 0 (/ (- (window-total-width win) +doom-dashboard--width) 2)))))
t)
;; helpers
(defun +doom-dashboard--center (len s)
(concat (make-string (ceiling (max 0 (- len (length s))) 2) ? )
s))
(defun +doom-dashboard--get-pwd ()
(let ((lastcwd +doom-dashboard--last-cwd)
(policy +doom-dashboard-pwd-policy))
(cond ((null policy)
default-directory)
((stringp policy)
(expand-file-name policy lastcwd))
((functionp policy)
(funcall policy lastcwd))
((null lastcwd)
default-directory)
((eq policy 'last-project)
(let ((cwd default-directory)
(default-directory lastcwd))
(if (doom-project-p)
(doom-project-root)
cwd)))
((eq policy 'last)
lastcwd)
(t
(warn "`+doom-dashboard-pwd-policy' has an invalid value of '%s'"
policy)))))
;; widgets
(defun doom-dashboard-widget--banner ()
(mapc (lambda (line)
(insert (propertize (+doom-dashboard-center +doom-dashboard--width line)
(insert (propertize (+doom-dashboard--center +doom-dashboard--width line)
'face 'font-lock-comment-face) " ")
(insert "\n"))
'("================= =============== =============== ======== ========"
@ -160,17 +222,15 @@ whose dimensions may not be fully initialized by the time this is run."
(insert
"\n"
(propertize
(+doom-dashboard-center
(+doom-dashboard--center
+doom-dashboard--width
(format "Loaded %d packages in %d modules in %.02fs"
(- (length load-path) (length doom--base-load-path))
(length doom--package-load-path)
(hash-table-size doom-modules)
(if (floatp doom-init-time) doom-init-time 0.0)))
'face 'font-lock-comment-face)
"\n"))
(defvar all-the-icons-scale-factor)
(defvar all-the-icons-default-adjust)
(defun doom-dashboard-widget--shortmenu ()
(let ((all-the-icons-scale-factor 1.45)
(all-the-icons-default-adjust -0.02))
@ -184,7 +244,7 @@ whose dimensions may not be fully initialized by the time this is run."
(propertize (concat " " label) 'face 'font-lock-keyword-face))
'action `(lambda (_) ,fn)
'follow-link t)
(+doom-dashboard-center (- +doom-dashboard--width 2) (buffer-string)))
(+doom-dashboard--center (- +doom-dashboard--width 2) (buffer-string)))
"\n\n"))))
`(("Homepage" "mark-github"
(browse-url "https://github.com/hlissner/doom-emacs"))

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)