💥 Remove :feature category

:feature was a "catch-all" category. Many of its modules fit better in
other categories, so they've been moved:

- feature/debugger -> tools/debugger
- feature/evil -> editor/evil
- feature/eval -> tools/eval
- feature/lookup -> tools/lookup
- feature/snippets -> editor/snippets
- feature/file-templates -> editor/file-templates
- feature/workspaces -> ui/workspaces

More potential changes in the future:

- A new :term category for terminal emulation modules (eshell, term and
  vterm).
- A new :os category for modules dedicated to os-specific functionality.
  The :tools macos module would fit here, but so would modules for nixos
  and arch.
- A new :services category for web-service integration, like wakatime,
  twitter, elfeed, gist and pastebin services.
This commit is contained in:
Henrik Lissner 2019-04-21 19:59:44 -04:00
parent 52eed893fe
commit 77e4cc4d58
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
193 changed files with 304 additions and 303 deletions

View file

@ -0,0 +1,11 @@
;;; tools/debugger/autoload/debug.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +debugger/quit ()
"Quit the active debugger, if any."
(interactive)
(ignore-errors (call-interactively #'realgud:cmd-quit))
(doom/popup-close)
(when (featurep 'evil)
(evil-normal-state)))

View file

@ -0,0 +1,34 @@
;; tools/debugger/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :editor evil)
;;;###autoload (autoload '+debugger:start "tools/debugger/autoload/evil" nil t)
(evil-define-command +debugger:start (&optional path)
"Initiate debugger for current major mode"
(interactive "<f>")
;; TODO Add python debugging
(let ((default-directory (doom-project-root)))
(pcase major-mode
((or 'c-mode 'c++-mode)
(realgud:gdb (if path (concat "gdb " path))))
((or 'ruby-mode 'enh-ruby-mode)
;; FIXME
(doom:repl nil (format "run '%s'" (file-name-nondirectory (or path buffer-file-name)))))
('sh-mode
(let ((shell sh-shell))
(when (string= shell "sh")
(setq shell "bash"))
(pcase shell
("bash"
(realgud:bashdb (if path (concat "bashdb " path))))
("zsh"
(realgud:zshdb (if path (concat "zshdb " path))))
(_ (user-error "No shell debugger for %s" shell)))))
((or 'js-mode 'js2-mode 'js3-mode)
(realgud:trepanjs))
('haskell-mode (haskell-debug))
(_ (user-error "No debugger for %s" major-mode)))))
;;;###autoload (autoload '+debugger:toggle-breakpoint "tools/debugger/autoload/evil" nil t)
(evil-define-command +debugger:toggle-breakpoint (&optional bang)
(interactive "<!>")
(call-interactively (if bang #'realgud:cmd-clear #'realgud:cmd-break)))

View file

@ -0,0 +1,44 @@
;;; tools/debugger/config.el -*- lexical-binding: t; -*-
(def-package! realgud
:commands (realgud:gdb realgud:trepanjs realgud:bashdb realgud:zshdb)
:config
(set-popup-rule! "^\\*\\(?:trepanjs:\\(?:g\\|zsh\\|bash\\)db\\)" :size 20)
;; TODO Temporary Ex commands for the debugger
;; (def-tmp-excmd! doom:def-debug-on doom:def-debug-off
;; ("n[ext]" . realgud:cmd-next)
;; ("s[tep]" . realgud:cmd-step)
;; ("b[reak]" . +debug:toggle-breakpoint)
;; ("c[ontinue]" . realgud:cmd-continue))
;; (advice-add #'realgud-cmdbuf-init :after #'doom:def-debug-on)
;; (advice-add #'realgud:cmd-quit :after #'doom:def-debug-off)
;; Monkey-patch `realgud:run-process' to run in a popup.
;; TODO Find a more elegant solution
;; FIXME Causes realgud:cmd-* to focus popup on every invocation
(defun +debugger*realgud-run-process
(debugger-name script-filename cmd-args minibuffer-history-var &optional no-reset)
(let* ((cmd-buf (apply #'realgud-exec-shell debugger-name script-filename
(car cmd-args) no-reset (cdr cmd-args)))
(process (get-buffer-process cmd-buf)))
(cond ((and process (eq 'run (process-status process)))
(pop-to-buffer cmd-buf)
(define-key evil-emacs-state-local-map (kbd "ESC ESC") #'+debug/quit)
(realgud:track-set-debugger debugger-name)
(realgud-cmdbuf-info-in-debugger?= 't)
(realgud-cmdbuf-info-cmd-args= cmd-args)
(when cmd-buf
(switch-to-buffer cmd-buf)
(when realgud-cmdbuf-info
(let* ((info realgud-cmdbuf-info)
(cmd-args (realgud-cmdbuf-info-cmd-args info))
(cmd-str (mapconcat #'identity cmd-args " ")))
(set minibuffer-history-var
(list-utils-uniq (cons cmd-str (eval minibuffer-history-var))))))))
(t
(if cmd-buf (switch-to-buffer cmd-buf))
(message "Error running command: %s" (mapconcat #'identity cmd-args " "))))
cmd-buf))
(advice-add #'realgud:run-process :override #'+debugger*realgud-run-process))

View file

@ -0,0 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/debugger/packages.el
(package! realgud)

View file

@ -0,0 +1,7 @@
;;; tools/editorconfig/autoload.el -*- lexical-binding: t; -*-
;;;###autodef
(defun set-editorconfig-indent-var! (mode &rest vars)
"Add (MODE VARS...) to `editorconfig-indentation-alist'."
(after! editorconfig
(nconc editorconfig-indentation-alist (cons mode vars))))

View file

@ -0,0 +1,117 @@
#+TITLE: tools/eval
#+DATE: February 13, 2017
#+SINCE: v2.0
#+STARTUP: inlineimages
* Table of Contents :TOC_3:noexport:
- [[Description][Description]]
- [[Module Flags][Module Flags]]
- [[Plugins][Plugins]]
- [[Hacks][Hacks]]
- [[Prerequisites][Prerequisites]]
- [[Features][Features]]
- [[Inline Code Evaluation][Inline Code Evaluation]]
- [[REPLs][REPLs]]
- [[Configuration][Configuration]]
- [[Register a REPL for a major-mode][Register a REPL for a major-mode]]
- [[Change how code is evaluated in a major mode][Change how code is evaluated in a major mode]]
- [[Troubleshooting][Troubleshooting]]
* Description
This modules adds inline code evaluation support to Emacs, and supplies a
universal interface for opening and interacting with REPLs.
** Module Flags
This module has no flags.
** Plugins
+ [[https://github.com/syohex/emacs-quickrun][quickrun]]
** Hacks
+ Quickrun has been modified to:
+ Use only one output window, in case of consecutive execution of code.
+ The quickrun window will resize itself to fit its output, once the
underlying process is finished executing the code.
* Prerequisites
This module has no direct prerequisites.
However, specific languages may require additional setup. Check the
documentation of that language's module for details.
* Features
** Inline 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.
** REPLs
Invoked via:
+ =SPC o r= or ~:repl~ will open a REPL in a popup window. =C-u SPC o r= or
~:repl!~ will open a REPL in the current window. If a REPL is already open and
a selection is active, it will be sent to the REPL.
+ ~M-x +eval/open-repl-other-window~
+ ~M-x +eval/open-repl-same-window~
+ ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active
* Configuration
** Register a REPL for a major-mode
REPLs are defined for most languages Doom supports. Check that language module's
README.org to see if it does (and if it requires additional setup).
To use them, you may use ~M-x +eval/open-repl-other-window~, ~M-x
+eval/open-repl-same-window~, ~:repl~ (for evil users) or the default binding:
=SPC o r=. These will open a REPL in a popup window.
#+begin_quote
You can simply call that mode's REPL command manually. e.g. ~M-x ielm~, but
#+end_quote
Otherwise, you can define your own for a specified major mode:
~(set-repl-handler! MAJOR-MODE FUNCTION)~
FUNCTION should return a repl buffer. Any window changes in this function are
ignored, then the REPL is opened in a popup window.
#+BEGIN_SRC emacs-lisp
(defun +lua/open-repl ()
(interactive)
(lua-start-process "lua" "lua")
(pop-to-buffer lua-process-buffer))
(set-repl-handler! 'lua-mode #'+lua/open-repl)
#+END_SRC
** Change how code is evaluated in a major mode
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, 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-handler! 'crystal-mode
'((:command . "crystal")
(:exec . "%c %s")
(:description . "Run Crystal script")))
#+END_SRC
A simpler version is simply to use the path to the binary:
#+BEGIN_SRC emacs-lisp
(set-eval-handler! 'groovy-mode "groovy")
#+END_SRC
Or if you'd rather run an elisp command:
#+BEGIN_SRC emacs-lisp
(set-eval-handler! 'emacs-lisp-mode #'+emacs-lisp-eval)
#+END_SRC
* Troubleshooting

View file

@ -0,0 +1,49 @@
;;; tools/eval/autoload/eval.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +eval/buffer ()
"Evaluate the whole buffer."
(interactive)
(cond ((assq major-mode +eval-runners)
(+eval/region (point-min) (point-max)))
(t (quickrun))))
;;;###autoload
(defun +eval/region (beg end)
"Evaluate a region between BEG and END and display the output."
(interactive "r")
(let ((load-file-name buffer-file-name))
(if-let* ((runner (cdr (assq major-mode +eval-runners))))
(funcall runner beg end)
(quickrun-region beg end))))
;;;###autoload
(defun +eval/line-or-region ()
"Evaluate the current line or selected region."
(interactive)
(if (use-region-p)
(call-interactively #'+eval/region)
(+eval/region (line-beginning-position) (line-end-position))))
;;;###autoload
(defun +eval/buffer-or-region ()
"Evaluate the whole buffer."
(interactive)
(call-interactively
(if (use-region-p)
#'+eval/region
#'+eval/buffer)))
;;;###autoload
(defun +eval/region-and-replace (beg end)
"Evaluation a region between BEG and END, and replace it with the result."
(interactive "r")
(cond ((eq major-mode 'emacs-lisp-mode)
(kill-region beg end)
(condition-case nil
(prin1 (eval (read (current-kill 0)))
(current-buffer))
(error (message "Invalid expression")
(insert (current-kill 0)))))
(t (quickrun-replace-region beg end))))

View file

@ -0,0 +1,23 @@
;; tools/eval/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :editor evil)
;;;###autoload (autoload '+eval:region "tools/eval/autoload/evil" nil t)
(evil-define-operator +eval:region (beg end)
"Send region to the currently open repl, if available."
:move-point nil
(interactive "<r>")
(+eval/region beg end))
;;;###autoload (autoload '+eval:replace-region "tools/eval/autoload/evil" nil t)
(evil-define-operator +eval:replace-region (beg end)
:move-point nil
(interactive "<r>")
(+eval/region-and-replace beg end))
;;;###autoload (autoload '+eval:repl "tools/eval/autoload/evil" nil t)
(evil-define-operator +eval:repl (beg end &optional bang)
:move-point nil
(interactive "<r><!>")
(if (evil-normal-state-p)
(+eval/open-repl-other-window bang)
(+eval/send-region-to-repl beg end bang)))

View file

@ -0,0 +1,102 @@
;;; tools/eval/autoload/repl.el -*- lexical-binding: t; -*-
(defvar +eval-repl-buffers (make-hash-table :test 'equal)
"The buffer of the last open repl.")
(define-minor-mode +eval-repl-mode
"A minor mode for REPL buffers.")
(defun +eval--ensure-in-repl-buffer (&optional command other-window-p)
(maphash (lambda (key buffer)
(unless (buffer-live-p buffer)
(remhash key +eval-repl-buffers)))
+eval-repl-buffers)
(let* ((project-root (doom-project-root))
(key (cons major-mode project-root))
(buffer (gethash key +eval-repl-buffers)))
(cl-check-type buffer (or buffer null))
(unless (eq buffer (current-buffer))
(funcall (if other-window-p #'pop-to-buffer #'switch-to-buffer)
(if (buffer-live-p buffer)
buffer
(setq buffer
(save-window-excursion
(if (commandp command)
(call-interactively command)
(funcall command))))
(cond ((null buffer)
(error "REPL handler %S couldn't open the REPL buffer" command))
((not (bufferp buffer))
(error "REPL handler %S failed to return a buffer" command)))
(with-current-buffer buffer
(+eval-repl-mode +1))
(puthash key buffer +eval-repl-buffers)
buffer)))
(with-current-buffer buffer
(goto-char (if (and (derived-mode-p 'comint-mode)
(cdr comint-last-prompt))
(cdr comint-last-prompt)
(point-max)))
buffer)))
(defun +eval-open-repl (prompt-p &optional other-window-p)
(let ((command (cdr (assq major-mode +eval-repls))))
(when (or (not command) prompt-p)
(let* ((choices (or (cl-loop for sym being the symbols
for sym-name = (symbol-name sym)
if (string-match "^\\(?:\\+\\)?\\([^/]+\\)/open-\\(?:\\(.+\\)-\\)?repl$" sym-name)
collect
(format "%s (%s)"
(match-string-no-properties 1 sym-name)
(or (match-string-no-properties 2 sym-name) "default")))
(user-error "There are no known available REPLs")))
(choice (or (completing-read "Open a REPL for: " choices)
(user-error "Aborting")))
(choice-split (split-string choice " " t))
(module (car choice-split))
(repl (substring (cadr choice-split) 1 -1)))
(setq command
(intern-soft
(format "+%s/open-%srepl" module
(if (string= repl "default")
""
repl))))))
(unless (commandp command)
(error "Couldn't find a valid REPL for %s" major-mode))
(when (+eval--ensure-in-repl-buffer command other-window-p)
(when (bound-and-true-p evil-mode)
(call-interactively #'evil-append-line))
t)))
;;;###autoload
(defun +eval/open-repl-same-window (&optional arg)
"Opens (or reopens) the REPL associated with the current major-mode and place
the cursor at the prompt.
If ARG (universal argument), prompt for a specific REPL to open."
(interactive "P")
(+eval-open-repl arg))
;;;###autoload
(defun +eval/open-repl-other-window (&optional arg)
"Does `+eval/open-repl', but in a popup window.
If ARG (universal argument), prompt for a specific REPL to open."
(interactive "P")
(+eval-open-repl arg t))
;;;###autoload
(defun +eval/send-region-to-repl (beg end &optional auto-execute-p)
"REPL must be open! Sends a selected region to it. If AUTO-EXECUTE-P, then
execute it immediately after."
(interactive "r")
(let ((selection (buffer-substring-no-properties beg end)))
(unless (+eval--ensure-in-repl-buffer)
(error "No REPL open"))
(when (bound-and-true-p evil-mode)
(call-interactively #'evil-append-line))
(insert (string-trim selection))
(when auto-execute-p
;; I don't use `comint-send-input' because different REPLs may have their
;; own. So I just emulate the keypress.
(execute-kbd-macro (kbd "RET")))))

View file

@ -0,0 +1,58 @@
;;; tools/eval/autoload/settings.el -*- lexical-binding: t; -*-
;;
;; REPLs
;;;###autoload
(defvar +eval-repls nil
"An alist mapping major modes to plists that describe REPLs. Used by
`+eval/open-repl-other-window' and filled with the `:repl' setting.")
;;;###autodef
(defun set-repl-handler! (modes command)
"Defines a REPL for MODES.
MODES is either a single major mode symbol or a list of them. COMMAND is a
function that creates and returns the REPL buffer.
COMMAND can either be a function that takes no arguments, or an interactive
command that will be called interactively."
(dolist (mode (doom-enlist modes))
(setf (alist-get mode +eval-repls) command)))
;;
;; Evaluation
;;;###autoload
(defvar +eval-runners nil
"Alist mapping major modes to interactive runner functions.")
;;;###autodef
(defun set-eval-handler! (mode command)
"Define a code evaluator for major mode MODE with `quickrun'.
1. If MODE is a string and COMMAND is the string, MODE is a file regexp and
COMMAND is a string key for an entry in `quickrun-file-alist'.
2. If MODE is not a string and COMMAND is a string, MODE is a major-mode symbol
and COMMAND is a key (for `quickrun--language-alist'), and will be registered
in `quickrun--major-mode-alist'.
3. If MODE is not a string and COMMAND is an alist, see `quickrun-add-command':
(quickrun-add-command MODE COMMAND :mode MODE).
4. If MODE is not a string and COMMANd is a symbol, add it to
`+eval-runners', which is used by `+eval/region'."
(declare (indent defun))
(cond ((symbolp command)
(push (cons mode command) +eval-runners))
((stringp command)
(after! quickrun
(push (cons mode command)
(if (stringp mode)
quickrun-file-alist
quickrun--major-mode-alist))))
((listp command)
(after! quickrun
(quickrun-add-command
(or (cdr (assq mode quickrun--major-mode-alist))
(string-remove-suffix "-mode" (symbol-name mode)))
command :mode mode)))))

View file

@ -0,0 +1,38 @@
;;; tools/eval/config.el -*- lexical-binding: t; -*-
;; remove ellipsis when printing sexps in message buffer
(setq eval-expression-print-length nil
eval-expression-print-level nil)
;;
;; Packages
(after! quickrun
(setq quickrun-focus-p nil)
(set-popup-rule! "^\\*quickrun" :size 0.3 :ttl 0)
(defun +eval*quickrun-auto-close (&rest _)
"Allows us to silently re-run quickrun from within the quickrun buffer."
(when-let* ((win (get-buffer-window quickrun--buffer-name)))
(let ((inhibit-message t))
(quickrun--kill-running-process)
(message ""))
(delete-window win)))
(advice-add #'quickrun :before #'+eval*quickrun-auto-close)
(advice-add #'quickrun-region :before #'+eval*quickrun-auto-close)
(defun +eval|quickrun-shrink-window ()
"Shrink the quickrun output window once code evaluation is complete."
(with-selected-window (get-buffer-window quickrun--buffer-name)
(let ((ignore-window-parameters t))
(shrink-window-if-larger-than-buffer))))
(add-hook 'quickrun-after-run-hook #'+eval|quickrun-shrink-window)
(defun +eval|quickrun-scroll-to-bof ()
"Ensures window is scrolled to BOF on invocation."
(with-selected-window (get-buffer-window quickrun--buffer-name)
(goto-char (point-min))))
(add-hook 'quickrun-after-run-hook #'+eval|quickrun-scroll-to-bof))

View file

@ -0,0 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; tools/eval/packages.el
(package! quickrun)

View file

@ -1,5 +1,5 @@
;;; tools/gist/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :feature evil)
;;;###if (featurep! :editor evil)
;;;###autoload (autoload '+gist:send "tools/gist/autoload/evil" nil t)
(evil-define-operator +gist:send (bang)

View file

@ -0,0 +1,189 @@
#+TITLE: tools/lookup
#+DATE: January 4, 2018
#+SINCE: v2.0.9
#+STARTUP: inlineimages
* Table of Contents :TOC:
- [[Description][Description]]
- [[Module Flags][Module Flags]]
- [[Plugins][Plugins]]
- [[Install][Install]]
- [[Module flags][Module flags]]
- [[Dependencies][Dependencies]]
- [[Features][Features]]
- [[Jump to definition][Jump to definition]]
- [[Find references][Find references]]
- [[Look up documentation][Look up documentation]]
- [[Search a specific documentation backend][Search a specific documentation backend]]
- [[Configuration][Configuration]]
- [[Settings][Settings]]
- [[Open in eww instead of browser][Open in eww instead of browser]]
- [[Appendix][Appendix]]
- [[Commands][Commands]]
* Description
Integrates with code navigation and documentation tools to help you quickly look
up definitions, references and documentation.
+ Jump-to-definition and find-references implementations that just work.
+ Powerful xref integration for languages that support it.
+ Documentation lookup for a variety of online sources (like devdocs.io,
stackoverflow or youtube).
+ Integration with Dash.app docsets.
** Module Flags
+ ~+docsets~ Enable integration with Dash.app docsets.
** Plugins
+ [[https://github.com/jacktasia/dumb-jump][dumb-jump]]
+ [[https://github.com/alexmurray/ivy-xref][ivy-xref]] or [[https://github.com/brotzeit/helm-xref][helm-xref]]
+ [[https://github.com/nathankot/counsel-dash][counsel-dash]] or [[https://github.com/areina/helm-dash][helm-dash]]
* Install
To enable the module add =:tools lookup= to your ~doom!~ block in
=~/.emacs.d/init.el=.
** Module flags
This module provides two flags:
+ ~+docsets~ Enables integration with Dash docsets.
** Dependencies
This module has several soft dependencies:
+ ~the_silver_searcher~ and/or ~ripgrep~ as a last-resort fallback for
jump-to-definition/find-references.
+ Optionally, ~sqlite3~ for Dash docset support.
*** MacOS
#+BEGIN_SRC sh
brew install the_silver_searcher ripgrep
# An older version of sqlite is included in MacOS. If it causes you problems (and
# it has been reported that it will), install it through homebrew:
brew install sqlite
# Note that it's keg-only, meaning it isn't symlinked to /usr/local/bin. You'll
# have to add it to PATH yourself (or symlink it into your PATH somewhere). e.g.
export PATH="/usr/local/opt/sqlite/bin:$PATH"
#+END_SRC
*** Arch Linux
#+BEGIN_SRC sh
sudo pacman -S sqlite the_silver_searcher ripgrep
#+END_SRC
* Features
** Jump to definition
Use ~+lookup/definition~ (bound to =gd= in normal mode) to jump to the
definition of the symbol at point
This module provides a goto-definition implementation that will try the
following sources before giving up:
1. Whatever ~:definition~ function is registered for the current buffer with the
~:lookup~ setting (see "Configuration" section).
2. Any available xref backends.
3. ~dumb-jump~ (a text search with aides to reduce false positives).
3. An ordinary project-wide text search with ripgrep or the_silver_searcher.
5. If ~evil-mode~ is active, use ~evil-goto-definition~, which preforms a simple
text search within the current buffer.
If there are multiple results, you will be prompted to select one.
** Find references
Use ~+lookup/references~ (bound to =gD= in normal mode) to see a list of
references for the symbol at point from throughout your project.
Like ~+lookup/definition~, this tries a number of sources before giving up. It
will try:
1. Whatever ~:references~ function is registered for the current buffer with the
~:lookup~ setting (see "Configuration" section).
2. Any available xref backends.
3. An ordinary project-wide text search with ripgrep or the_silver_searcher.
If there are multiple results, you will be prompted to select one.
** Look up documentation
~+lookup/documentation~ (bound to =K= in normal mode) will open documentation
for the symbol at point.
Depending on your configuration, this will try a list of sources:
1. Whatever ~:documentation~ function is registered for the current buffer with
the ~:lookup~ setting (see "Configuration" section).
2. Any Dash.app docsets, if any are installed for the current major mode.
3. devdocs.io, if it has a docset for the current mode.
4. An online search; using the last engine used (it will prompt you the first
time, or if ~current-prefix-arg~ is non-nil).
** Search a specific documentation backend
You can perform a documentation lookup on any backends directly:
+ Dash Docsets: ~+lookup/in-docsets~, or ~:dash QUERY~ for evil users.
+ devdocs.io: ~+lookup/in-devdocs~, or ~:dd QUERY~ for evil users.
+ Online (generic): ~+lookup/online~ or ~+lookup/online-select~ (bound to =SPC /
o=), or ~:lo[okup] QUERY~ for evil users.
* Configuration
** Settings
This module provides two setters:
*** ~set-lookup-handlers! MODES &rest PLIST~
Defines a lookup target for major MODES (one major-mode symbol or a list
thereof). PLIST accepts the following optional properties:
+ ~:definition FN~ :: Run when jumping to a symbol's definition. Used by
~+lookup/definition~.
+ ~:references FN~ :: Run when looking for usage references of a symbol in the
current project. Used by ~+lookup/references~.
+ ~:documentation FN~ :: Run when looking up documentation for a symbol. Used by
~+lookup/documentation~.
+ ~:file FN~ :: Run when looking up the file for a symbol/string. Typically a
file path. Used by ~+lookup/file~.
+ ~:xref-backend FN~ :: Defines an xref backend for a major-mode. With this,
:definition and :references are unnecessary.
**** Example
#+BEGIN_SRC emacs-lisp
;; For python-mode, anaconda-mode offers a backend for all three lookup
;; functions. We can register them like so:
(set-lookup-handlers! 'python-mode
:definition #'anaconda-mode-find-definitions
:references #'anaconda-mode-find-references
:documentation #'anaconda-mode-show-doc)
;; If a language or plugin provides a custom xref backend available for it, use
;; that instead. It will provide the best jump-to-definition and find-references
;; experience. You can specify custom xref backends with:
(set-lookup-handlers! 'js2-mode :xref-backend #'xref-js2-xref-backend)
;; NOTE: xref doesn't provide a :documentation backend.
#+END_SRC
*** ~set-docsets! MODES &rest DOCSETS~
Registers DOCSETS (one string or list of strings) for MODES (one major mode
symbol or a list of them). It is used by ~+lookup/in-docsets~ and
~+lookup/documentation~.
#+BEGIN_SRC emacs-lisp
(set-docsets! 'js2-mode "JavaScript" "JQuery")
;; Add docsets to minor modes by starting DOCSETS with :add
(set-docsets! 'rjsx-mode :add "React")
;; Or remove docsets from minor modes
(set-docsets! 'nodejs-mode :remove "JQuery")
#+END_SRC
** Open in eww instead of browser
#+BEGIN_SRC emacs-lisp
(setq +lookup-open-url-fn 'eww)
#+END_SRC
* Appendix
** Commands
+ ~+lookup/definition~
+ ~+lookup/references~
+ ~+lookup/documentation~
+ ~+lookup/online~
+ ~+lookup/online-select~
+ ~+lookup/in-devdocs~
+ ~+lookup/in-docsets~

View file

@ -0,0 +1,100 @@
;;; tools/lookup/autoload/docsets.el -*- lexical-binding: t; -*-
;;;###if (featurep! +docsets)
(defvar +lookup-docset-alist nil
"An alist mapping major and minor modes to lists of Dash docsets.
Entries are added by `set-docsets!' and used by `+lookup-docsets-for-buffer' to
assemble a list of installed & active docsets.")
;;;###autodef
(defun set-docsets! (modes &rest docsets)
"Registers a list of DOCSETS for MODES.
MODES can be one major mode, or a list thereof.
DOCSETS can be strings, each representing a dash docset, or a vector with the
structure [DOCSET FORM]. If FORM evaluates to nil, the DOCSET is omitted. If it
is non-nil, (format DOCSET FORM) is used as the docset.
The first element in DOCSETS can be :add or :remove, making it easy for users to
add to or remove default docsets from modes.
DOCSETS can also contain sublists, which will be flattened.
Example:
(set-docsets! '(js2-mode rjsx-mode) \"JavaScript\"
[\"React\" (eq major-mode 'rjsx-mode)]
[\"TypeScript\" (bound-and-true-p tide-mode)])
Used by `+lookup/in-docsets' and `+lookup/documentation'."
(declare (indent defun))
(dolist (mode (doom-enlist modes))
(if (null docsets)
(setq +lookup-docset-alist
(delq (assq mode +lookup-docset-alist)
+lookup-docset-alist))
(let ((action (if (keywordp (car docsets)) (pop docsets)))
(docsets (mapcan #'doom-enlist docsets))) ; flatten list
(setf (alist-get mode +lookup-docset-alist)
(pcase action
(:add (append docsets (alist-get mode +lookup-docset-alist)))
(:remove (cl-set-difference (alist-get mode +lookup-docset-alist) docsets))
(_ docsets)))))))
;;
;; Library
;;;###autoload
(defun +lookup-docsets-for-buffer ()
"Return list of installed & selected docsets for the current major mode.
This list is built from `+lookup-docset-alist'."
(cl-loop for docset in (cdr (assq major-mode +lookup-docset-alist))
when (or (stringp docset)
(and (vectorp docset)
(eval (aref docset 1) t)))
collect docset))
;;;###autoload
(defun +lookup-docset-installed-p (docset)
"Return t if DOCSET is installed."
(let ((path (helm-dash-docsets-path)))
(file-directory-p
(expand-file-name (format "%s.docset" docset)
path))))
;;;###autoload
(autoload 'helm-dash-installed-docsets "helm-dash")
;;;###autoload
(autoload 'helm-dash-docset-installed-p "helm-dash")
;;
;; Commands
;;;###autoload
(defalias '+lookup/install-docset #'helm-dash-install-docset)
(defvar counsel-dash-docsets)
(defvar helm-dash-docsets)
;;;###autoload
(defun +lookup/in-docsets (&optional query docsets)
"Lookup QUERY in dash DOCSETS.
QUERY is a string and docsets in an array of strings, each a name of a Dash
docset. Requires either helm or ivy.
Use `+lookup/install-docset' to install docsets."
(interactive)
(let* ((counsel-dash-docsets (or docsets (+lookup-docsets-for-buffer)))
(helm-dash-docsets counsel-dash-docsets)
(query (or query (+lookup--symbol-or-region) "")))
(cond ((featurep! :completion helm)
(helm-dash query))
((featurep! :completion ivy)
(counsel-dash query))
((user-error "No dash backend is installed, enable ivy or helm.")))))

View file

@ -0,0 +1,22 @@
;;; tools/lookup/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :editor evil)
;;;###autoload (autoload '+lookup:online "tools/lookup/autoload/evil" nil t)
(evil-define-command +lookup:online (query &optional bang)
"Look up QUERY online. Will prompt for search engine the first time, then
reuse it on consecutive uses of this command. If BANG, always prompt for search
engine."
(interactive "<a><!>")
(+lookup/online query (+lookup--online-provider bang 'evil-ex)))
;;;###autoload (autoload '+lookup:dash "tools/lookup/autoload/evil" nil t)
(evil-define-command +lookup:dash (query &optional bang)
"Look up QUERY in your dash docsets. If BANG, prompt to select a docset (and
install it if necessary)."
(interactive "<a><!>")
(let (selected)
(when bang
(setq selected (helm-dash-read-docset "Select docset" (helm-dash-official-docsets)))
(unless (+lookup-docset-installed-p selected)
(+lookup/install-docset selected)))
(+lookup/in-docsets query (or selected (+lookup-docsets-for-buffer)))))

View file

@ -0,0 +1,320 @@
;;; tools/lookup/autoload/lookup.el -*- lexical-binding: t; -*-
(defvar +lookup--handler-alist nil)
;;;###autodef
(cl-defun set-lookup-handlers!
(modes &rest plist &key definition references documentation file xref-backend async)
"Define a jump target for major MODES.
This overwrites previously defined handlers for MODES. If used on minor modes,
they are combined with handlers defined for other minor modes or the major mode
it's activated in.
This can be passed nil as its second argument to unset handlers for MODES. e.g.
(set-lookup-handlers! 'python-mode nil)
Otherwise, these properties are available to be set:
:definition FN
Run when jumping to a symbol's definition.
Used by `+lookup/definition'.
:references FN
Run when looking for usage references of a symbol in the current project.
Used by `+lookup/references'.
:documentation FN
Run when looking up documentation for a symbol.
Used by `+lookup/documentation'.
:file FN
Run when looking up the file for a symbol/string. Typically a file path.
Used by `+lookup/file'.
:xref-backend FN
Defines an xref backend for a major-mode. If you define :definition and
:references along with :xref-backend, those will have higher precedence.
:async BOOL
Indicates that the supplied handlers *after* this property are asynchronous.
Note: async handlers do not fall back to the default handlers, due to their
nature. To get around this, you must write specialized wrappers to wait for
the async response and return 'fallback."
(declare (indent defun))
(dolist (mode (doom-enlist modes))
(let ((hook (intern (format "%s-hook" mode)))
(fn (intern (format "+lookup|init-%s" mode))))
(cond ((null (car plist))
(remove-hook hook fn)
(delq! mode +lookup--handler-alist 'assq)
(unintern fn nil))
((fset fn
(lambda ()
(when (or (eq major-mode mode)
(and (boundp mode)
(symbol-value mode)))
(cl-mapc #'+lookup--set-handler
(list definition
references
documentation
file
xref-backend)
(list '+lookup-definition-functions
'+lookup-references-functions
'+lookup-documentation-functions
'+lookup-file-functions
'xref-backend-functions)))))
(add-hook hook fn))))))
;;
;;; Helpers
(defun +lookup--set-handler (spec functions-var &optional async)
(when spec
(cl-destructuring-bind (fn . plist)
(doom-enlist spec)
(put fn '+lookup-plist (plist-put plist :async async))
(add-hook functions-var fn nil t))))
(defun +lookup--symbol-or-region (&optional initial)
(cond ((stringp initial)
initial)
((use-region-p)
(buffer-substring-no-properties (region-beginning)
(region-end)))
((require 'xref nil t)
(xref-backend-identifier-at-point (xref-find-backend)))))
(defun +lookup--run-handler (handler identifier)
(if (commandp handler)
(call-interactively handler)
(funcall handler identifier)))
(defun +lookup--run-handlers (handler identifier origin &optional other-window)
(doom-log "Looking up '%s' with '%s'" identifier handler)
(condition-case e
(let ((plist (get handler '+lookup-plist)))
(cond ((plist-get plist :async)
(when other-window
;; If async, we can't catch the window change or destination
;; buffer reliably, so we set up the new window ahead of time.
(switch-to-buffer-other-window (current-buffer))
(goto-char (marker-position origin)))
(+lookup--run-handler handler identifier)
t)
((save-window-excursion
(and (or (+lookup--run-handler handler identifier)
(null origin)
(/= (point-marker) origin))
(point-marker))))))
((error user-error debug)
(message "Lookup handler %S: %s" handler e)
nil)))
(defun +lookup--jump-to (prop identifier &optional other-window)
(let ((result
(run-hook-wrapped
(plist-get (list :definition '+lookup-definition-functions
:references '+lookup-references-functions
:documentation '+lookup-documentation-functions
:file '+lookup-file-functions)
prop)
#'+lookup--run-handlers
identifier
(point-marker)
other-window)))
(if (not (markerp result))
(ignore (message "No lookup handler could find %S" identifier))
(funcall (if other-window
#'switch-to-buffer-other-window
#'switch-to-buffer)
(marker-buffer result))
(goto-char result)
(recenter)
result)))
;;
;;; Lookup backends
(defun +lookup-xref-definitions-backend (identifier)
"Non-interactive wrapper for `xref-find-definitions'"
(xref-find-definitions identifier))
(defun +lookup-xref-references-backend (identifier)
"Non-interactive wrapper for `xref-find-references'"
(xref-find-references identifier))
(defun +lookup-dumb-jump-backend (_identifier)
"Look up the symbol at point (or selection) with `dumb-jump', which conducts a
project search with ag, rg, pt, or git-grep, combined with extra heuristics to
reduce false positives.
This backend prefers \"just working\" over accuracy."
(when (require 'dumb-jump nil t)
;; dumb-jump doesn't tell us if it succeeded or not
(plist-get (dumb-jump-go) :results)))
(defun +lookup-project-search-backend (identifier)
"Conducts a simple project text search for IDENTIFIER.
Uses and requires `+ivy-file-search' or `+helm-file-search'. Will return nil if
neither is available. These search backends will use ag, rg, or pt (in an order
dictated by `+ivy-project-search-engines' or `+helm-project-search-engines',
falling back to git-grep)."
(unless identifier
(let ((query (rxt-quote-pcre identifier)))
(ignore-errors
(cond ((featurep! :completion ivy)
(+ivy-file-search nil :query query)
t)
((featurep! :completion helm)
(+helm-file-search nil :query query)
t))))))
(defun +lookup-evil-goto-definition-backend (_identifier)
"Uses `evil-goto-definition' to conduct a text search for IDENTIFIER in the
current buffer."
(and (fboundp 'evil-goto-definition)
(ignore-errors
(cl-destructuring-bind (beg . end)
(bounds-of-thing-at-point 'symbol)
(evil-goto-definition)
(let ((pt (point)))
(not (and (>= pt beg)
(< pt end))))))))
(defun +lookup-dash-docsets-backend (identifier)
"Looks up IDENTIFIER in available Dash docsets, if any are installed.
Docsets must be installed with `+lookup/install-docset'. These can also be
accessed via `+lookup/in-docsets'."
(and (featurep! +docsets)
(or (require 'counsel-dash nil t)
(require 'helm-dash nil t))
(let ((docsets (+lookup-docsets-for-buffer)))
(when (cl-some #'+lookup-docset-installed-p docsets)
(+lookup/in-docsets identifier docsets)
t))))
;;
;;; Main commands
;;;###autoload
(defun +lookup/definition (identifier &optional other-window)
"Jump to the definition of IDENTIFIER (defaults to the symbol at point).
If OTHER-WINDOW (universal argument), open the result in another window.
Each function in `+lookup-definition-functions' is tried until one changes the
point or current buffer. Falls back to dumb-jump, naive
ripgrep/the_silver_searcher text search, then `evil-goto-definition' if
evil-mode is active."
(interactive
(list (+lookup--symbol-or-region)
current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point"))
((+lookup--jump-to :definition identifier other-window))
((error "Couldn't find the definition of '%s'" identifier))))
;;;###autoload
(defun +lookup/references (identifier &optional other-window)
"Show a list of usages of IDENTIFIER (defaults to the symbol at point)
Tries each function in `+lookup-references-functions' until one changes the
point and/or current buffer. Falls back to a naive ripgrep/the_silver_searcher
search otherwise."
(interactive
(list (+lookup--symbol-or-region)
current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point"))
((+lookup--jump-to :references identifier other-window))
((error "Couldn't find references of '%s'" identifier))))
;;;###autoload
(defun +lookup/documentation (identifier &optional _arg)
"Show documentation for IDENTIFIER (defaults to symbol at point or selection.
First attempts the :documentation handler specified with `set-lookup-handlers!'
for the current mode/buffer (if any), then falls back to the backends in
`+lookup-documentation-functions'."
(interactive
(list (+lookup--symbol-or-region)
current-prefix-arg))
(cond ((+lookup--jump-to :documentation identifier t))
((user-error "Couldn't find documentation for '%s'" identifier))))
(defvar ffap-file-finder)
;;;###autoload
(defun +lookup/file (path)
"Figure out PATH from whatever is at point and open it.
Each function in `+lookup-file-functions' is tried until one changes the point
or the current buffer.
Otherwise, falls back on `find-file-at-point'."
(interactive
(progn
(require 'ffap)
(list
(or (ffap-guesser)
(ffap-read-file-or-url
(if ffap-url-regexp "Find file or URL: " "Find file: ")
(+lookup--symbol-or-region))))))
(require 'ffap)
(cond ((not path)
(call-interactively #'find-file-at-point))
((ffap-url-p path)
(find-file-at-point path))
((not (+lookup--jump-to :file path))
(let ((fullpath (expand-file-name path)))
(when (and buffer-file-name (file-equal-p fullpath buffer-file-name))
(user-error "Already here"))
(let* ((insert-default-directory t)
(project-root (doom-project-root))
(ffap-file-finder
(cond ((not (file-directory-p fullpath))
#'find-file)
((file-in-directory-p fullpath project-root)
(lambda (dir)
(let ((default-directory dir))
(without-project-cache!
(let ((file (projectile-completing-read "Find file: "
(projectile-current-project-files)
:initial-input path)))
(find-file (expand-file-name file (doom-project-root)))
(run-hooks 'projectile-find-file-hook))))))
(#'doom-project-browse))))
(find-file-at-point path))))))
;;
;;; Source-specific commands
(defvar counsel-dash-docsets)
(defvar helm-dash-docsets)
;;;###autoload
(defun +lookup/in-docsets (&optional query docsets)
"Looks up QUERY (a string) in available Dash docsets for the current buffer.
DOCSETS is a list of docset strings. Docsets can be installed with
`+lookup/install-docset'."
(interactive)
(let* ((counsel-dash-docsets
(unless (eq docsets 'blank)
(or docsets
(or (bound-and-true-p counsel-dash-docsets)
(bound-and-true-p helm-dash-docsets)))))
(helm-dash-docsets counsel-dash-docsets)
(query (or query (+lookup--symbol-or-region) "")))
(cond ((featurep! :completion helm)
(helm-dash query))
((featurep! :completion ivy)
(counsel-dash query))
((user-error "No dash backend is installed, enable ivy or helm.")))))

View file

@ -0,0 +1,65 @@
;;; tools/lookup/autoload/online.el -*- lexical-binding: t; -*-
(defvar +lookup--last-provider nil)
(defun +lookup--online-provider (&optional force-p namespace)
(let ((key (or namespace major-mode)))
(or (and (not force-p)
(cdr (assq key +lookup--last-provider)))
(when-let* ((provider
(completing-read
"Search on: "
(mapcar #'car +lookup-provider-url-alist)
nil t)))
(setf (alist-get key +lookup--last-provider) provider)
provider))))
(defun +lookup-online-backend (identifier)
"Opens the browser and searches for IDENTIFIER online.
Will prompt for which search engine to use the first time (or if the universal
argument is non-nil)."
(+lookup/online
identifier
(+lookup--online-provider (not current-prefix-arg))))
;;;###autoload
(defun +lookup/online (search &optional provider)
"Looks up SEARCH (a string) in you browser using PROVIDER.
PROVIDER should be a key of `+lookup-provider-url-alist'.
When used interactively, it will prompt for a query and, for the first time, the
provider from `+lookup-provider-url-alist'. On consecutive uses, the last
provider will be reused. If the universal argument is supplied, always prompt
for the provider."
(interactive
(let ((provider (+lookup--online-provider current-prefix-arg)))
(list (or (and (use-region-p)
(buffer-substring-no-properties (region-beginning)
(region-end)))
(read-string (format "Search for (on %s): " provider)
(thing-at-point 'symbol t)))
provider)))
(condition-case-unless-debug e
(let ((url (cdr (assoc provider +lookup-provider-url-alist))))
(unless url
(user-error "'%s' is an invalid search engine" provider))
(when (or (functionp url) (symbolp url))
(setq url (funcall url)))
(cl-assert (stringp url))
(when (string-empty-p search)
(user-error "The search query is empty"))
(funcall +lookup-open-url-fn (format url (url-encode-url search))))
(error
(setq +lookup--last-provider
(delq (assq major-mode +lookup--last-provider)
+lookup--last-provider))
(signal (car e) (cdr e)))))
;;;###autoload
(defun +lookup/online-select ()
"Runs `+lookup/online', but always prompts for the provider to use."
(interactive)
(let ((current-prefix-arg t))
(call-interactively #'+lookup/online)))

View file

@ -0,0 +1,144 @@
;;; tools/lookup/config.el -*- lexical-binding: t; -*-
;; "What am I looking at?" This module helps you answer this question.
;;
;; + `+lookup/definition': a jump-to-definition that should 'just work'
;; + `+lookup/references': find a symbol's references in the current project
;; + `+lookup/file': open the file referenced at point
;; + `+lookup/online'; look up a symbol on online resources
;; + `+lookup/in-docsets': look up in Dash docsets
;;
;; This module uses `xref', an experimental new library in Emacs. It may change
;; in the future. When xref can't be depended on it will fall back to
;; `dumb-jump' to find what you want.
(defvar +lookup-provider-url-alist
'(("Google" . "https://google.com/search?q=%s")
("Google images" . "https://google.com/images?q=%s")
("Google maps" . "https://maps.google.com/maps?q=%s")
("Project Gutenberg" . "http://www.gutenberg.org/ebooks/search/?query=%s")
("DuckDuckGo" . "https://duckduckgo.com/?q=%s")
("DevDocs.io" . "https://devdocs.io/#q=%s")
("StackOverflow" . "https://stackoverflow.com/search?q=%s")
("Github" . "https://github.com/search?ref=simplesearch&q=%s")
("Youtube" . "https://youtube.com/results?aq=f&oq=&search_query=%s")
("Wolfram alpha" . "https://wolframalpha.com/input/?i=%s")
("Wikipedia" . "https://wikipedia.org/search-redirect.php?language=en&go=Go&search=%s"))
"An alist that maps online resources to their search url or a function that
produces an url. Used by `+lookup/online'.")
(defvar +lookup-open-url-fn #'browse-url
"Function to use to open search urls.")
(defvar +lookup-definition-functions
'(+lookup-xref-definitions-backend
+lookup-dumb-jump-backend
+lookup-project-search-backend
+lookup-evil-goto-definition-backend)
"Functions for `+lookup/definition' to try, before resorting to `dumb-jump'.
Stops at the first function to return non-nil or change the current
window/point.
If the argument is interactive (satisfies `commandp'), it is called with
`call-interactively' (with no arguments). Otherwise, it is called with one
argument: the identifier at point.")
(defvar +lookup-references-functions
'(+lookup-xref-references-backend
+lookup-project-search-backend)
"Functions for `+lookup/references' to try, before resorting to `dumb-jump'.
Stops at the first function to return non-nil or change the current
window/point.
If the argument is interactive (satisfies `commandp'), it is called with
`call-interactively' (with no arguments). Otherwise, it is called with one
argument: the identifier at point.")
(defvar +lookup-documentation-functions
'(+lookup-dash-docsets-backend
+lookup-online-backend)
"Functions for `+lookup/documentation' to try, before resorting to
`dumb-jump'. Stops at the first function to return non-nil or change the current
window/point.
If the argument is interactive (satisfies `commandp'), it is called with
`call-interactively' (with no arguments). Otherwise, it is called with one
argument: the identifier at point.")
(defvar +lookup-file-functions ()
"Function for `+lookup/file' to try, before restoring to `find-file-at-point'.
Stops at the first function to return non-nil or change the current
window/point.
If the argument is interactive (satisfies `commandp'), it is called with
`call-interactively' (with no arguments). Otherwise, it is called with one
argument: the identifier at point.")
;; Recenter buffer after certain jumps
(add-hook!
'(imenu-after-jump-hook evil-jumps-post-jump-hook
counsel-grep-post-action-hook dumb-jump-after-jump-hook)
#'recenter)
;;
;;; dumb-jump
(def-package! dumb-jump
:commands dumb-jump-result-follow
:config
(setq dumb-jump-default-project doom-emacs-dir
dumb-jump-aggressive nil
dumb-jump-selector
(cond ((featurep! :completion ivy) 'ivy)
((featurep! :completion helm) 'helm)
('popup))))
;;
;;; xref
;; By default, `etags--xref-backend' is the default xref backend. No need. We'll
;; set these up ourselves in other modules.
(setq-default xref-backend-functions '(t))
;; ...however, it breaks `projectile-find-tag', unless we put it back.
(defun +lookup*projectile-find-tag (orig-fn)
(let ((xref-backend-functions '(etags--xref-backend t)))
(funcall orig-fn)))
(advice-add #'projectile-find-tag :around #'+lookup*projectile-find-tag)
(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))
;;
;;; Dash docset integration
;; Both packages depend on helm-dash, for now
(def-package! helm-dash
:when (featurep! +docsets)
:defer t
:init
(setq helm-dash-enable-debugging doom-debug-mode
helm-dash-browser-func #'eww)
:config
(unless (file-directory-p helm-dash-docsets-path)
(setq helm-dash-docsets-path (concat doom-etc-dir "docsets/")))
(unless (file-directory-p helm-dash-docsets-path)
(make-directory helm-dash-docsets-path t)))
(def-package! counsel-dash
:when (and (featurep! +docsets)
(featurep! :completion ivy))
:commands counsel-dash-install-docset
:config (setq counsel-dash-min-length 2))

View file

@ -0,0 +1,21 @@
;; -*- no-byte-compile: t; -*-
;;; tools/lookup/packages.el
;; `dumb-jump' uses the `helm-build-sync-source' macro, but this requires helm
;; be loaded before it is byte-compiled during installation. To ensure this, we
;; declare helm before dumb-jump.
(when (featurep! :completion helm)
(package! helm))
;;
(package! dumb-jump)
(when (featurep! :completion ivy)
(package! ivy-xref))
(when (featurep! :completion helm)
(package! helm-xref))
(when (featurep! +docsets)
(when (featurep! :completion helm)
(package! helm-dash))
(when (featurep! :completion ivy)
(package! counsel-dash)))

View file

@ -68,7 +68,7 @@ It is passed a user and repository name.")
(def-package! evil-magit
:when (featurep! :feature evil +everywhere)
:when (featurep! :editor evil +everywhere)
:after magit
:init
(setq evil-magit-state 'normal

View file

@ -5,5 +5,5 @@
(package! forge)
(package! magit-gitflow)
(package! magit-todos)
(when (featurep! :feature evil +everywhere)
(when (featurep! :editor evil +everywhere)
(package! evil-magit)))

View file

@ -1,5 +1,5 @@
;;; tools/tmux/autoload/evil.el -*- lexical-binding: t; -*-
;;;###if (featurep! :feature evil)
;;;###if (featurep! :editor evil)
;;;###autoload (autoload '+tmux:run "tools/tmux/autoload/evil" nil t)
(evil-define-command +tmux:run (bang &optional command)

View file

@ -11,7 +11,7 @@
;; Automatically kill buffer when vterm exits.
(add-to-list 'vterm-exit-functions (lambda (buffer) (if buffer (kill-buffer buffer))))
(when (featurep! :feature evil)
(when (featurep! :editor evil)
(evil-set-initial-state 'vterm-mode 'insert)
;; Go back to normal state but don't move cursor backwards. Moving cursor
;; backwards is the default Vim behavior but it is not appropriate in some