Updating Doom Emacs.

This commit is contained in:
Derek Taylor
2020-06-19 22:43:40 -05:00
parent 0f664d532a
commit a5c86c514a
453 changed files with 13527 additions and 12455 deletions

View File

@@ -1,10 +1,10 @@
;; -*- no-byte-compile: t; -*-
;;; tools/ansible/packages.el
(package! yaml-mode)
(package! ansible :recipe (:nonrecursive t))
(package! ansible-doc)
(package! jinja2-mode)
(package! ansible :recipe (:nonrecursive t) :pin "c6532e52161a381ed3dddfeaa7c92ae636d3f052")
(package! ansible-doc :pin "86083a7bb2ed0468ca64e52076b06441a2f8e9e0")
(package! jinja2-mode :pin "4540f99a3e363403a633587e05a9707605c16473")
(package! yaml-mode :pin "34648f2502f52f4744d62758fa381fa35db1da49")
(when (featurep! :completion company)
(package! company-ansible))
(package! company-ansible :pin "79dd421b161efa49fbdffad57fa40edb41f484a3"))

View File

@@ -10,7 +10,7 @@
(pcase major-mode
((or 'c-mode 'c++-mode)
(realgud:gdb (if path (concat "gdb " path))))
((or 'ruby-mode 'enh-ruby-mode)
('ruby-mode
;; FIXME
(doom:repl nil (format "run '%s'" (file-name-nondirectory (or path buffer-file-name)))))
('sh-mode

View File

@@ -1,52 +1,28 @@
;;; tools/debugger/config.el -*- lexical-binding: t; -*-
(defvar +debugger--realgud-alist
'((realgud:zshdb :modes (sh-mode))
(realgud:kshdb :modes (sh-mode))
(realgud:rdebug :modes (ruby-mode enh-ruby-mode))
(realgud:pdb :modes (python-mode))
(realgud:trepan2 :modes (python-mode))
(realgud:gub :modes (go-mode))
'((realgud:bashdb :modes (sh-mode))
(realgud:gdb)
(realgud:trepan :modes (perl-mode perl6-mode))
(realgud:trepanpl :modes (perl-mode perl6-mode))
(realgud:trepanjs :modes (javascript-mode js2-mode js3-mode))
(realgud:gub :modes (go-mode))
(realgud:kshdb :modes (sh-mode))
(realgud:pdb :modes (python-mode))
(realgud:perldb :modes (perl-mode perl6-mode))
(realgud:rdebug :modes (ruby-mode))
(realgud:remake)
(realgud:trepan :modes (perl-mode perl6-mode))
(realgud:trepan2 :modes (python-mode))
(realgud:trepan3k :modes (python-mode))
(realgud:bashdb :modes (sh-mode))
(realgud:perldb :modes (perl-mode perl6-mode))))
(realgud:trepanjs :modes (javascript-mode js2-mode js3-mode))
(realgud:trepanpl :modes (perl-mode perl6-mode))
(realgud:zshdb :modes (sh-mode))))
;;
;;; Packages
(use-package! dap-mode
:when (featurep! :tools lsp)
:hook (dap-mode . dap-ui-mode)
:after lsp-mode
:init
(setq dap--breakpoints-file (concat doom-etc-dir "dap-breakpoints"))
:config
(dap-mode 1)
(dolist (module '(((:lang . cc) ccls dap-lldb dap-gdb-lldb)
((:lang . elixir) elixir-mode dap-elixir)
((:lang . go) go-mode dap-go)
((:lang . java) lsp-java dap-java)
((:lang . php) php-mode dap-php)
((:lang . python) python dap-python)
((:lang . ruby) enh-ruby-mode dap-ruby)
((:lang . rust) rust-mode dap-lldb)))
(when (doom-module-p (caar module) (cdar module) '+lsp)
(with-eval-after-load (nth 1 module)
(mapc #'require (cddr module)))))
(when (featurep! :lang javascript +lsp)
(with-eval-after-load 'js2-mode
(require 'dap-node)
(require 'dap-chrome)
(require 'dap-firefox)
(when IS-WINDOWS
(require 'dap-edge)))))
;;;###package gdb
(setq gdb-show-main t
gdb-many-windows t)
(use-package! realgud
@@ -104,9 +80,47 @@
(if (boundp 'starting-directory)
(realgud-cmdbuf-info-starting-directory= starting-directory))
(set minibuffer-history-var
(cl-remove-duplicates (cons cmd-str minibuffer-history)
(cl-remove-duplicates (cons cmd-str (eval minibuffer-history-var))
:from-end t))))))
(t
(if cmd-buf (switch-to-buffer cmd-buf))
(message "Error running command: %s" (mapconcat #'identity cmd-args " "))))
cmd-buf)))
(use-package! dap-mode
:when (and (featurep! +lsp) (not (featurep! :tools lsp +eglot)))
:hook (dap-mode . dap-tooltip-mode)
:after lsp-mode
:demand t
:preface
(setq dap-breakpoints-file (concat doom-etc-dir "dap-breakpoints")
dap-utils-extension-path (concat doom-etc-dir "dap-extension/"))
:config
(dolist (module '(((:lang . cc) ccls dap-lldb dap-gdb-lldb)
((:lang . elixir) elixir-mode dap-elixir)
((:lang . go) go-mode dap-go)
((:lang . java) lsp-java dap-java)
((:lang . php) php-mode dap-php)
((:lang . python) python dap-python)
((:lang . ruby) ruby-mode dap-ruby)
((:lang . rust) rust-mode dap-lldb)))
(when (doom-module-p (caar module) (cdar module) '+lsp)
(with-eval-after-load (nth 1 module)
(mapc #'require (cddr module)))))
(when (featurep! :lang javascript +lsp)
(after! (:or js2-mode typescript-mode)
(require 'dap-node)
(require 'dap-chrome)
(require 'dap-firefox)
(when IS-WINDOWS
(require 'dap-edge))))
(dap-mode 1))
(use-package! dap-ui-mode
:when (featurep! +lsp)
:hook (dap-mode . dap-ui-mode)
:hook (dap-ui-mode . dap-ui-controls-mode))

View File

@@ -1,9 +1,10 @@
;; -*- no-byte-compile: t; -*-
;;; tools/debugger/packages.el
(when (package! realgud)
(when (package! realgud :pin "1238d8e72945a84bb06cd39d7ded75f37105d4d2")
(when (featurep! :lang javascript)
(package! realgud-trepan-ni)))
(package! realgud-trepan-ni :pin "6e9cac5e8097018aadf41c88de541168036cc227")))
(when (featurep! :tools lsp)
(package! dap-mode))
(when (featurep! +lsp)
(package! dap-mode :pin "7ad915794b75481f12b3f02ac8f5c9bcfddd6938")
(package! posframe :pin "6285217711bc846e565940261829b523e298f82e"))

View File

@@ -67,27 +67,8 @@ Or ~nix-env -i direnv~
* Troubleshooting
** direnv + nix is slow
Consider augmenting direnv with [[https://github.com/target/lorri][lorri]], which will cache nix builds and speed up
direnv tremendously.
At the time of writing, the lorri package in nixpkgs simply emits an error
message, telling you to install it manually. You can get around this with:
direnv tremendously:
#+BEGIN_SRC nix
nixpkgs.overlays = [
(self: super: {
lorri =
let src = (super.fetchFromGitHub {
owner = "target";
repo = "lorri";
rev = "38eae3d487526ece9d1b8c9bb0d27fb45cf60816";
sha256 = "11k9lxg9cv6dlxj4haydvw4dhcfyszwvx7jx9p24jadqsy9jmbj4";
});
in import src { inherit src; };
})
];
environment.systemPackages = [ pkgs.lorri ];
services.lorri.enable = true;
#+END_SRC
Otherwise, follow [[https://github.com/target/lorri#installing-lorri][the instructions in lorri's README]] on how to install it
manually.

View File

@@ -1,69 +1,34 @@
;;; tools/direnv/config.el -*- lexical-binding: t; -*-
(defvar +direnv--keywords
(defvar +direnv-keywords
'("direnv_layout_dir" "PATH_add" "path_add" "log_status" "log_error" "has"
"join_args" "expand_path" "dotenv" "user_rel_path" "find_up" "source_env"
"watch_file" "source_up" "direnv_load" "MANPATH_add" "load_prefix" "layout"
"use" "rvm" "use_nix" "use_guix")
"TODO")
;;
;;; Packages
(use-package! direnv
:after-call after-find-file dired-initial-position-hook
:hook (before-hack-local-variables . direnv--maybe-update-environment)
:hook (flycheck-before-syntax-check . direnv--maybe-update-environment)
:hook (direnv-envrc-mode . +direnv-envrc-fontify-keywords-h)
:config
(add-hook! 'direnv-mode-hook
(defun +direnv-init-h ()
"Instead of checking for direnv on `post-command-hook', check only once,
when the file is first opened/major mode is activated. This is significantly
less expensive, but is less sensitive to changes to .envrc done outside of
Emacs."
(direnv--disable)
(when direnv-mode
(add-hook 'after-change-major-mode-hook
#'direnv--maybe-update-environment))))
(add-to-list 'direnv-non-file-modes 'vterm-mode)
(defadvice! +direnv--make-process-environment-buffer-local-a (items)
:filter-return #'direnv--export
(when items
(mapc 'kill-local-variable '(process-environment exec-path))
(mapc 'make-local-variable '(process-environment exec-path)))
items)
(defun +direnv-envrc-fontify-keywords-h ()
"Fontify special .envrc keywords; it's a good indication of whether or not
we've typed them correctly."
(font-lock-add-keywords
nil `((,(regexp-opt +direnv-keywords 'symbols)
(0 font-lock-keyword-face)))))
;; Fontify special .envrc keywords; it's a good indication of whether or not
;; we've typed them correctly.
(add-hook! 'direnv-envrc-mode-hook
(defun +direnv-envrc-fontify-keywords-h ()
(font-lock-add-keywords
nil `((,(regexp-opt +direnv--keywords 'symbols)
(0 font-lock-keyword-face)))))
(defun +direnv-update-on-save-h ()
(add-hook 'after-save-hook #'direnv--maybe-update-environment
nil 'local)))
(defadvice! +direnv-update-a (&rest _)
"Update direnv. Useful to advise functions that may run
environment-sensitive logic like `flycheck-default-executable-find'. This fixes
flycheck issues with direnv and on nix."
:before #'flycheck-default-executable-find
(direnv--maybe-update-environment))
(defadvice! +direnv--fail-gracefully-a (orig-fn)
"Don't try to update direnv if the executable isn't present."
:around #'direnv--maybe-update-environment
(if (executable-find "direnv")
(when (file-readable-p (or buffer-file-name default-directory))
(funcall orig-fn))
(doom-log "Couldn't find direnv executable")))
(defadvice! +direnv-update-async-shell-command-a (command &optional output-buffer _error-buffer)
:before #'shell-command
(when (string-match "[ \t]*&[ \t]*\\'" command)
(let ((environment process-environment)
(path exec-path)
(shell shell-file-name))
(with-current-buffer
(get-buffer-create (or output-buffer "*Async Shell Command*"))
(setq-local process-environment environment)
(setq-local exec-path path)
(setq-local shell-file-name shell)))))
(defadvice! +direnv--fail-gracefully-a (&rest _)
"Don't try to use direnv if the executable isn't present."
:before-while #'direnv-update-directory-environment
(or (executable-find "direnv")
(ignore (doom-log "Couldn't find direnv executable"))))
(direnv-mode +1))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/direnv/packages.el
(package! direnv)
(package! direnv :pin "f5484b0fc33d4e5116612626294efb362ff9ecd4")

View File

@@ -29,7 +29,7 @@ convenience functions allow images to be built easily.
=docker-tramp.el= offers a [[https://www.gnu.org/software/tramp/][TRAMP]] method for Docker containers.
** Module Flags
This module provides no flags.
+ =+lsp= Enables integration for the Dockerfile Language Server.
** Plugins
+ [[https://github.com/Silex/docker.el][docker]]
@@ -40,6 +40,10 @@ This module provides no flags.
This module assumes =docker=, =docker-compose= and =docker-machine= binaries
are installed and accessible from your PATH.
Optionally, this module also uses the following programs:
+ =docker-langserver= (for LSP users): ~npm install -g dockerfile-language-server-nodejs~
* Features
** Docker control
Use =M-x docker=, select a resource, and then mark or unmark items using the

View File

@@ -8,3 +8,9 @@
docker-volume-mode
docker-machine-mode)
'emacs))
(after! dockerfile-mode
(set-docsets! 'dockerfile-mode "Docker")
(when (featurep! +lsp)
(add-hook 'dockerfile-mode-local-vars-hook #'lsp!)))

View File

@@ -1,6 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; tools/docker/packages.el
(package! docker)
(package! docker-tramp)
(package! dockerfile-mode)
(package! docker :pin "d6233bdb9ccaee4da7cdc0ef162bfe4727227142")
(package! docker-tramp :pin "8e2b671eff7a81af43b76d9dfcf94ddaa8333a23")
(package! dockerfile-mode :pin "d31f7685ebc5832d957e25070a930aa42984327d")

View File

@@ -6,7 +6,6 @@
;; appending an extension to `buffer-file-name' when we talk to editorconfig.
(defvar +editorconfig-mode-alist
'((emacs-lisp-mode . "el")
(enh-ruby-mode . "rb")
(js2-mode . "js")
(perl-mode . "pl")
(php-mode . "php")
@@ -20,8 +19,11 @@
;; Handles whitespace (tabs/spaces) settings externally. This way projects can
;; specify their own formatting rules.
(use-package! editorconfig
:after-call doom-switch-buffer-hook after-find-file
:hook (doom-first-buffer . editorconfig-mode)
:config
(when (require 'ws-butler nil t)
(setq editorconfig-trim-whitespaces-mode 'ws-butler-mode))
(defadvice! +editorconfig--smart-detection-a (orig-fn)
"Retrieve the properties for the current file. If it doesn't have an
extension, try to guess one."
@@ -31,25 +33,15 @@ extension, try to guess one."
(file-name-extension buffer-file-name))
buffer-file-name
(format "%s%s" (buffer-file-name (buffer-base-buffer))
(if-let* ((ext (cdr (assq major-mode +editorconfig-mode-alist))))
(if-let (ext (alist-get major-mode +editorconfig-mode-alist))
(concat "." ext)
"")))))
(funcall orig-fn)))
(add-hook! 'editorconfig-after-apply-functions
(defun +editorconfig-disable-ws-butler-maybe-h (props)
"Disable `ws-butler-mode' if trim_trailing_whitespace is true."
(when (and (equal (gethash 'trim_trailing_whitespace props) "true")
(bound-and-true-p ws-butler-mode))
(ws-butler-mode -1))))
(add-hook! 'editorconfig-after-apply-functions
(defun +editorconfig-disable-indent-detection-h (props)
"Inhibit `dtrt-indent' if an explicit indent_style and indent_size is
specified by editorconfig."
(when (or (gethash 'indent_style props)
(gethash 'indent_size props))
(setq doom-inhibit-indent-detection 'editorconfig))))
;;
(editorconfig-mode +1))
(setq doom-inhibit-indent-detection 'editorconfig)))))

View File

@@ -1,4 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; tools/editorconfig/packages.el
(package! editorconfig :recipe (:nonrecursive t))
(package! editorconfig
:recipe (:nonrecursive t)
:pin "9a73ff743b9fe820301ea9b5c5c7804bfc967324")

View File

@@ -9,10 +9,6 @@
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#features][Features]]
- [[#interaction-with-a-jupyter-server][Interaction with a Jupyter server]]
- [[#configuration][Configuration]]
- [[#setting-the-default-location-of-your-notebooks][Setting the default location of your notebooks]]
- [[#using-hydra][Using hydra]]
* Description
Adds Jupyter notebook integration into emacs.
@@ -27,41 +23,4 @@ This module provides no flags.
This module has no prereqisites.
* Features
** Interaction with a Jupyter server
Three functions are available to start EIN:
1. ~ein:jupyter-server-start~ --- Start a jupyter server within emacs
2. ~ein:notebooklist-login~ --- Login to an existing jupyter server
3. ~ein:notebooklist-open~ --- Open the list of jupyter notebooks
These functions do not have default key bindings.
When ~ein:jupyter-server-start~ is called, after successfully finishing,
~ein:notebooklist-login~ and ~ein:notebooklist-open~ will be automatically
called.
When in the ~Notebook List~ buffer, the key =o= calls ~ace-link~ to speed up the
process of selecting links in the buffer.
If ~company-mode~ is enabled as a module, ~company-ein~ will handle completion.
* Configuration
** Setting the default location of your notebooks
Change ~+ein-notebook-dir~ to tell ein where to find your Jupityr notebooks.
#+BEGIN_SRC emacs-lisp
(setq +ein-notebook-dir "~/my-notebooks")
#+END_SRC
** Using hydra
This module provides a batteries-included hydra - ~+ein/hydra~ - to make using ein
easier. Things like navigating between cells, workbook management etc, are greatly
simplified and are easily accessible. However, by default, it's not bound to any key.
Here's an example of how to bind it:
#+BEGIN_SRC emacs-lisp
(map! :map ein:notebook-mode-map
:localleader
"," #'+ein/hydra/body)
#+END_SRC
Please refer [[https://github.com/millejoh/emacs-ipython-notebook][millejoh/emacs-ipython-notebook's README]].

View File

@@ -1,24 +0,0 @@
;;; tools/ein/autoload.el -*- lexical-binding: t; -*-
(defun +ein--collect-ein-buffer-links ()
(let ((end (window-end))
points)
(save-excursion
(goto-char (window-start))
(while (re-search-forward "~?/.+\\|\s\\[" end t)
(push (+ (match-beginning 0) 1) points))
(nreverse points))))
;;;###autoload
(defun +ein/ace-link-ein ()
"Ace jump to links in ein notebooklist."
(interactive)
(require 'avy)
(let ((res (avy-with +ein/ace-link-ein
(avy--process
(+ein--collect-ein-buffer-links)
#'avy--overlay-pre))))
;(avy--style-fn avy-style)))))
(when (numberp res)
(goto-char (1+ res))
(widget-button-press (point)))))

View File

@@ -1,47 +0,0 @@
;;; tools/ein/autoload/hydra.el -*- lexical-binding: t; -*-
;;;###if (featurep! :ui hydra)
;;;###autoload (autoload '+ein/hydra/body "tools/ein/autoload/hydra" nil t)
(defhydra +ein/hydra (:hint t :color red)
"
Operations on Cells^^^^^^ Other
----------------------------^^^^^^ ----------------------------------^^^^
[_k_/_j_]^^ select prev/next [_t_]^^ toggle output
[_K_/_J_]^^ move up/down [_C-l_/_C-S-l_] clear/clear all output
[_C-k_/_C-j_]^^ merge above/below [_C-o_]^^ open console
[_O_/_o_]^^ insert above/below [_C-s_/_C-r_] save/rename notebook
[_y_/_p_/_d_] copy/paste [_x_]^^ close notebook
[_u_]^^^^ change type [_q_]^^ quit
[_RET_]^^^^ execute
"
("q" nil :exit t)
("h" ein:notebook-worksheet-open-prev-or-last)
("j" ein:worksheet-goto-next-input)
("k" ein:worksheet-goto-prev-input)
("l" ein:notebook-worksheet-open-next-or-first)
("H" ein:notebook-worksheet-move-prev)
("J" ein:worksheet-move-cell-down)
("K" ein:worksheet-move-cell-up)
("L" ein:notebook-worksheet-move-next)
("t" ein:worksheet-toggle-output)
("d" ein:worksheet-kill-cell)
("R" ein:worksheet-rename-sheet)
("y" ein:worksheet-copy-cell)
("p" ein:worksheet-yank-cell)
("o" ein:worksheet-insert-cell-below)
("O" ein:worksheet-insert-cell-above)
("u" ein:worksheet-change-cell-type)
("RET" ein:worksheet-execute-cell-and-goto-next)
;; Output
("C-l" ein:worksheet-clear-output)
("C-S-l" ein:worksheet-clear-all-output)
;;Console
("C-o" ein:console-open :exit t)
;; Merge and split cells
("C-k" ein:worksheet-merge-cell)
("C-j" spacemacs/ein:worksheet-merge-cell-next)
("s" ein:worksheet-split-cell-at-point)
;; Notebook
("C-s" ein:notebook-save-notebook-command)
("C-r" ein:notebook-rename-command)
("x" ein:notebook-close :exit t))

View File

@@ -1,43 +1,14 @@
;;; tools/ein/config.el -*- lexical-binding: t; -*-
(defvar +ein-notebook-dir "~/"
"Default directory from where Jupyter notebooks are to be opened.")
;;
;; Packages
(after! ein
(setq ein:notebook-modes
'(ein:notebook-multilang-mode
ein:notebook-python-mode
ein:notebook-plain-mode)
;; Slice images into rows; easier to navigate around images
ein:slice-image t)
(set-popup-rules!
'(("\\*ein: .*" :ignore t)
("\\*ein:tb .*" :side 'bottom :size 0.3 :quit t :ttl nil :select nil)
("\\*ein:notebooklist *" :side 'left :size 50 :select nil)))
(when (featurep! :completion company)
;; Code completion with company
(setq ein:completion-backend 'ein:use-company-backend)
(set-company-backend! '(ein:notebook-multilang-mode
ein:notebook-python-mode
ein:notebook-plain-mode)
'ein:company-backend))
(after! ein-jupyter
(setq ein:jupyter-server-args '("--no-browser"))
(unless ein:jupyter-default-notebook-directory
(setq ein:jupyter-default-notebook-directory "~/")))
;;; Packages
(after! ein-notebook
(defun +ein-buffer-p (buf)
(string-match-p "^\\*ein: .*" (buffer-name buf)))
(or (memq buf (ein:notebook-opened-buffers))
(memq buf (mapcar #'ein:notebooklist-get-buffer (ein:notebooklist-keys)))))
(add-to-list 'doom-real-buffer-functions #'+ein-buffer-p nil #'eq)
(map! :map ein:notebook-mode-map
"M-s" #'ein:notebook-save-notebook-command
"M-s" #'ein:notebook-save-notebook-command-km
:map ein:notebooklist-mode-map
"o" #'+ein/ace-link-ein))
"o" #'ein:notebook-open-km))

View File

@@ -1,5 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/ein/packages.el
(package! ein)
(package! avy)
(package! ein :pin "ee31cdb77de397bdff01abf5ffa087f384517f0c")

View File

@@ -3,27 +3,22 @@
;;;###autoload
(defun +eval-display-results-in-popup (output &optional _source-buffer)
"Display OUTPUT in a popup buffer."
(if (with-temp-buffer
(insert output)
(>= (count-lines (point-min) (point-max))
+eval-popup-min-lines))
(let ((output-buffer (get-buffer-create "*doom eval*"))
(origin (selected-window)))
(with-current-buffer output-buffer
(setq-local scroll-margin 0)
(erase-buffer)
(insert output)
(goto-char (point-min))
(if (fboundp '+word-wrap-mode)
(+word-wrap-mode +1)
(visual-line-mode +1)))
(when-let (win (display-buffer output-buffer))
(fit-window-to-buffer
win (/ (frame-height) 2)
nil (/ (frame-width) 2)))
(select-window origin)
output-buffer)
(message "%s" output)))
(let ((output-buffer (get-buffer-create "*doom eval*"))
(origin (selected-window)))
(with-current-buffer output-buffer
(setq-local scroll-margin 0)
(erase-buffer)
(insert output)
(goto-char (point-min))
(if (fboundp '+word-wrap-mode)
(+word-wrap-mode +1)
(visual-line-mode +1)))
(when-let (win (display-buffer output-buffer))
(fit-window-to-buffer
win (/ (frame-height) 2)
nil (/ (frame-width) 2)))
(select-window origin)
output-buffer))
;;;###autoload
(defun +eval-display-results-in-overlay (output &optional source-buffer)
@@ -42,8 +37,14 @@
(funcall (if (or current-prefix-arg
(with-temp-buffer
(insert output)
(>= (count-lines (point-min) (point-max))
+eval-popup-min-lines))
(or (>= (count-lines (point-min) (point-max))
+eval-popup-min-lines)
(>= (string-width
(buffer-substring (point-min)
(save-excursion
(goto-char (point-min))
(line-end-position))))
(window-width))))
(not (require 'eros nil t)))
#'+eval-display-results-in-popup
#'+eval-display-results-in-overlay)

View File

@@ -37,8 +37,10 @@ recognized:
"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'.
(defun set-eval-handler! (modes command)
"Define a code evaluator for major mode MODES with `quickrun'.
MODES can be list of major mode symbols, or a single one.
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'.
@@ -50,17 +52,18 @@ recognized:
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)))))
(dolist (mode (doom-enlist modes))
(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

@@ -68,23 +68,32 @@ buffer rather than an overlay on the line at point or the minibuffer.")
(with-selected-window win
(goto-char (point-min))))))
;; Display evaluation results in an overlay next to the cursor. If the output
;; is more than 4 lines long, it is displayed in a popup.
;; Display evaluation results in an overlay at the end of the current line. If
;; the output is more than `+eval-popup-min-lines' (4) lines long, it is
;; displayed in a popup.
(when (featurep! +overlay)
(defadvice! +eval--show-output-in-overlay-a (fn)
:filter-return #'quickrun--make-sentinel
(lambda (process event)
(funcall fn process event)
(with-current-buffer quickrun--buffer-name
(when (> (buffer-size) 0)
(+eval-display-results
(string-trim (buffer-string))
quickrun--original-buffer)))))
;; Suppress quickrun's popup window because we're using an overlay instead.
(defadvice! +eval--inhibit-quickrun-popup-a (buf cb)
:override #'quickrun--pop-to-buffer
(setq quickrun--original-buffer (current-buffer))
(with-current-buffer buf
(setq quickrun-option-outputter #'ignore)
(funcall cb)))
(save-window-excursion
(with-current-buffer (pop-to-buffer buf)
(setq quickrun-option-outputter #'ignore)
(funcall cb))))
(advice-add #'quickrun--recenter :override #'ignore)
(add-hook! 'quickrun-after-run-hook
(defun +eval-display-in-popup-overlay-h ()
(+eval-display-results
(with-current-buffer quickrun--buffer-name
(string-trim (buffer-string)))
quickrun--original-buffer)))))
;; HACK Without this, `+eval--inhibit-quickrun-popup-a' throws a
;; window-live-p error because no window exists to be recentered!
(advice-add #'quickrun--recenter :override #'ignore)))
(use-package! eros

View File

@@ -1,6 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; tools/eval/packages.el
(package! quickrun)
(package! quickrun :pin "c6ce1f315b768af8688d06bc57d2eb403f875a63")
(when (featurep! +overlay)
(package! eros))
(package! eros :pin "dd8910279226259e100dab798b073a52f9b4233a"))

View File

@@ -1,13 +0,0 @@
;;; tools/flycheck/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +flycheck-init-popups-h ()
"Activate `flycheck-posframe-mode' if available and in GUI Emacs.
Activate `flycheck-popup-tip-mode' otherwise.
Do nothing if `lsp-ui-mode' is active and `lsp-ui-sideline-enable' is non-nil."
(unless (and (bound-and-true-p lsp-ui-mode)
lsp-ui-sideline-enable)
(if (and (fboundp 'flycheck-posframe-mode)
(display-graphic-p))
(flycheck-posframe-mode +1)
(flycheck-popup-tip-mode +1))))

View File

@@ -1,80 +0,0 @@
;;; tools/flycheck/config.el -*- lexical-binding: t; -*-
(defvar +flycheck-lazy-idle-delay 3.0
"The delay before flycheck checks the buffer, after a check that produces no
errors.")
;;
;;; Packages
(use-package! flycheck
:commands flycheck-list-errors flycheck-buffer
:after-call doom-switch-buffer-hook after-find-file
:config
(setq flycheck-emacs-lisp-load-path 'inherit)
;; Check only when saving or opening files. Newline & idle checks are a mote
;; excessive, especially when that can easily catch code in an incomplete
;; state, so we removed them.
(setq flycheck-check-syntax-automatically '(save mode-enabled))
;; Display errors a little quicker (default is 0.9s)
(setq flycheck-display-errors-delay 0.25)
;; Don't commandeer input focus if the error message pops up (happens when
;; tooltips and childframes are disabled).
(set-popup-rule! "^\\*Flycheck error messages\\*" :select nil)
(add-hook! 'doom-escape-hook :append
(defun +flycheck-buffer-h ()
"Flycheck buffer on ESC in normal mode."
(when flycheck-mode
(ignore-errors (flycheck-buffer))
nil)))
(map! :map flycheck-error-list-mode-map
:n "C-n" #'flycheck-error-list-next-error
:n "C-p" #'flycheck-error-list-previous-error
:n "j" #'flycheck-error-list-next-error
:n "k" #'flycheck-error-list-previous-error
:n "RET" #'flycheck-error-list-goto-error
:n [return] #'flycheck-error-list-goto-error)
(global-flycheck-mode +1))
(use-package! flycheck-popup-tip
:commands flycheck-popup-tip-show-popup flycheck-popup-tip-delete-popup
:init (add-hook 'flycheck-mode-hook #'+flycheck-init-popups-h)
:config
(setq flycheck-popup-tip-error-prefix "")
(after! evil
;; Don't display popups while in insert or replace mode, as it can affect
;; the cursor's position or cause disruptive input delays.
(add-hook! '(evil-insert-state-entry-hook evil-replace-state-entry-hook)
#'flycheck-popup-tip-delete-popup)
(defadvice! +flycheck--disable-popup-tip-maybe-a (&rest _)
:before-while #'flycheck-popup-tip-show-popup
(if evil-local-mode
(eq evil-state 'normal)
(not (bound-and-true-p company-backend))))))
(use-package! flycheck-posframe
:when (featurep! +childframe)
:defer t
:init (add-hook 'flycheck-mode-hook #'+flycheck-init-popups-h)
:config
(setq flycheck-posframe-warning-prefix ""
flycheck-posframe-info-prefix "··· "
flycheck-posframe-error-prefix "")
(after! company
;; Don't display popups if company is open
(add-hook 'flycheck-posframe-inhibit-functions #'company--active-p))
(after! evil
;; Don't display popups while in insert or replace mode, as it can affect
;; the cursor's position or cause disruptive input delays.
(add-hook! 'flycheck-posframe-inhibit-functions
#'evil-insert-state-p
#'evil-replace-state-p)))

View File

@@ -1,7 +0,0 @@
;; -*- no-byte-compile: t; -*-
;;; tools/flycheck/packages.el
(package! flycheck)
(package! flycheck-popup-tip)
(when (featurep! +childframe)
(package! flycheck-posframe))

View File

@@ -1,27 +0,0 @@
;;; tools/flyspell/autoload.el -*- lexical-binding: t; -*-
;;;###autodef
(defalias 'flyspell-mode! #'flyspell-mode)
(defvar +flyspell--predicate-alist nil
"TODO")
;;;###autodef
(defun set-flyspell-predicate! (modes predicate)
"TODO"
(declare (indent defun))
(dolist (mode (doom-enlist modes) +flyspell--predicate-alist)
(add-to-list '+flyspell--predicate-alist (cons mode predicate))))
;;;###autoload
(defun +flyspell-init-predicate-h ()
"TODO"
(when-let (pred (assq major-mode +flyspell--predicate-alist))
(setq-local flyspell-generic-check-word-predicate (cdr pred))))
;;;###autoload
(defun +flyspell-correction-at-point-p (&optional point)
"TODO"
(cl-loop for ov in (overlays-at (or point (point)))
if (overlay-get ov 'flyspell-overlay)
return t))

View File

@@ -1,84 +0,0 @@
;;; tools/flyspell/config.el -*- lexical-binding: t; -*-
;;
;;; Packages
(after! ispell
(add-to-list 'ispell-extra-args "--dont-tex-check-comments")
;; Don't spellcheck org blocks
(pushnew! ispell-skip-region-alist
'(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:")
'("#\\+BEGIN_SRC" . "#\\+END_SRC")
'("#\\+BEGIN_EXAMPLE" . "#\\+END_EXAMPLE"))
;; Enable either aspell or hunspell.
;; If no module flags are given, enable either aspell or hunspell if their
;; binary is found.
;; If one of the flags `+aspell' or `+hunspell' is given, only enable that
;; spell checker.
(pcase (cond ((featurep! +aspell) 'aspell)
((featurep! +hunspell) 'hunspell)
((executable-find "aspell") 'aspell)
((executable-find "hunspell") 'hunspell))
(`aspell
(setq ispell-program-name "aspell"
ispell-extra-args '("--sug-mode=ultra" "--run-together"))
(add-hook! 'text-mode-hook
(defun +flyspell-remove-run-together-switch-for-aspell-h ()
(setq-local ispell-extra-args (remove "--run-together" ispell-extra-args))))
(defun +flyspell-setup-ispell-extra-args-a (orig-fun &rest args)
:around '(ispell-word flyspell-auto-correct-word)
(let ((ispell-extra-args (remove "--run-together" ispell-extra-args)))
(ispell-kill-ispell t)
(apply orig-fun args)
(ispell-kill-ispell t))))
(`hunspell
(setq ispell-program-name "hunspell"))
(_ (doom-log "Spell checker not found. Either install `aspell' or `hunspell'"))))
;;;###package flyspell
(progn ; built-in
(setq flyspell-issue-welcome-flag nil
;; Significantly speeds up flyspell, which would otherwise print
;; messages for every word when checking the entire buffer
flyspell-issue-message-flag nil)
(add-hook 'text-mode-hook #'flyspell-mode)
(when (featurep! +prog)
(add-hook 'prog-mode-hook #'flyspell-prog-mode))
(add-hook! 'flyspell-mode-hook
(defun +flyspell-inhibit-duplicate-detection-maybe-h ()
"Don't mark duplicates when style/grammar linters are present.
e.g. proselint and langtool."
(when (or (and (bound-and-true-p flycheck-mode)
(executable-find "proselint"))
(featurep 'langtool))
(setq-local flyspell-mark-duplications-flag nil))))
;; Ensure mode-local predicates declared with `set-flyspell-predicate!' are
;; used in their respective major modes.
(add-hook 'flyspell-mode-hook #'+flyspell-init-predicate-h)
(map! :map flyspell-mouse-map
"RET" #'flyspell-correct-word-generic
[return] #'flyspell-correct-word-generic
[mouse-1] #'flyspell-correct-word-generic))
(use-package! flyspell-correct
:commands flyspell-correct-word-generic flyspell-correct-previous-word-generic
:config
(cond ((and (featurep! :completion helm)
(require 'flyspell-correct-helm nil t)))
((and (featurep! :completion ivy)
(require 'flyspell-correct-ivy nil t)))
((require 'flyspell-correct-popup nil t)
(setq flyspell-popup-correct-delay 0.8)
(define-key popup-menu-keymap [escape] #'keyboard-quit))))

View File

@@ -1,4 +0,0 @@
(unless (or (executable-find "aspell")
(executable-find "hunspell"))
(warn! "Could not find aspell or hunspell. Flyspell will fall back to ispell, which may not work."))

View File

@@ -1,9 +0,0 @@
;; -*- no-byte-compile: t; -*-
;;; tools/flyspell/packages.el
(package! flyspell-correct)
(cond ((featurep! :completion ivy)
(package! flyspell-correct-ivy))
((featurep! :completion helm)
(package! flyspell-correct-helm))
((package! flyspell-correct-popup)))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/gist/packages.el
(package! gist)
(package! gist :pin "314fe6ab80fae35b95f0734eceb82f72813b6f41")

View File

@@ -10,6 +10,7 @@
- [[#prerequisites][Prerequisites]]
- [[#macos][MacOS]]
- [[#arch-linux][Arch Linux]]
- [[#nixos][NixOS]]
- [[#features][Features]]
- [[#jump-to-definition][Jump to definition]]
- [[#find-references][Find references]]
@@ -24,33 +25,51 @@
- [[#commands][Commands]]
* Description
Integrates with code navigation and documentation tools to help you quickly look
up definitions, references and documentation.
This module adds code navigation and documentation lookup tools to help you
quickly look up definitions, references, documentation, dictionary definitions
or synonyms.
+ 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).
+ Search online providers like devdocs.io, stackoverflow, google, duckduckgo or
youtube (duckduckgo and google have live suggestions).
+ Integration with Dash.app docsets.
+ Support for online (and offline) dictionaries and thesauruses.
** Module Flags
+ ~+dictionary~ Enable word definition and thesaurus lookup functionality.
+ ~+offline~ Install and prefer offline dictionary/thesaurus.
+ ~+docsets~ Enable integration with Dash.app docsets.
+ ~+xwidget~ Enable integration with [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Embedded-WebKit-Widgets.html][Embedded Webkit Widgets]].
** 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]]
+ [[https://github.com/tkf/emacs-request][request]]
+ =+docsets=
+ [[https://github.com/dash-docs-el/dash-docs][dash-docs]]
+ [[https://github.com/nathankot/counsel-dash][counsel-dash]] or [[https://github.com/areina/helm-dash][helm-dash]]
+ =+dictionary=
+ if macOS
+ [[https://github.com/xuchunyang/osx-dictionary.el][osx-dictionary]]* (on macOS)
+ else
+ [[https://github.com/abo-abo/define-word][define-word]]
+ [[https://github.com/maxchaos/emacs-powerthesaurus][powerthesaurus]]
+ =+offline=
+ [[https://github.com/gromnitsky/wordnut][wordnut]]
+ [[https://github.com/hpdeifel/synosaurus][synosaurus]]
* Prerequisites
This module has several soft dependencies:
+ ~the_silver_searcher~ or ~ripgrep~ (recommended) as a last-resort fallback for
jump-to-definition/find-references.
+ ~sqlite3~ for Dash docset support.
+ ~ripgrep~ as a last-resort fallback for jump-to-definition/find-references.
+ ~sqlite3~ for Dash docset support (if you have =+docsets= enabled)
+ ~wordnet~ for offline dictionary and thesaurus support (if you have
=+dictionary +offline= enabled).
** MacOS
#+BEGIN_SRC sh
brew install the_silver_searcher ripgrep
brew install ripgrep wordnet
# An older version of sqlite is included in MacOS. If it causes you problems (and
# folks have reported it will), install it through homebrew:
@@ -62,7 +81,17 @@ export PATH="/usr/local/opt/sqlite/bin:$PATH"
** Arch Linux
#+BEGIN_SRC sh
sudo pacman -S sqlite the_silver_searcher ripgrep
sudo pacman -S sqlite ripgrep
yay -S wordnet-cli
#+END_SRC
** NixOS
#+BEGIN_SRC nix
environment.systemPackages = with pkgs; [
ripgrep
sqlite
wordnet
];
#+END_SRC
* Features
@@ -77,7 +106,7 @@ following sources before giving up:
~: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.
3. An ordinary project-wide text search with ripgrep.
5. If ~evil-mode~ is active, use ~evil-goto-definition~, which preforms a simple
text search within the current buffer.
@@ -93,7 +122,7 @@ 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.
3. An ordinary project-wide text search with ripgrep.
If there are multiple results, you will be prompted to select one.

View File

@@ -86,11 +86,12 @@ installed with `dash-docs-install-docset'."
(interactive "P")
(require 'dash-docs)
(let ((dash-docs-common-docsets)
(dash-docs-browser-func +lookup-open-url-fn)
(dash-docs-docsets
(if arg
(dash-docs-installed-docsets)
(cl-remove-if-not #'dash-docs-docset-path (or docsets dash-docs-docsets))))
(query (or query (+lookup-symbol-or-region) "")))
(query (doom-thing-at-point-or-region query)))
(doom-log "Searching docsets %s" dash-docs-docsets)
(cond ((featurep! :completion helm)
(helm-dash query))

View File

@@ -15,6 +15,12 @@ properties:
:definition FN
Run when jumping to a symbol's definition. Used by `+lookup/definition'.
:implementations FN
Run when looking for implementations of a symbol in the current project. Used
by `+lookup/implementations'.
:type-definition FN
Run when jumping to a symbol's type definition. Used by
`+lookup/type-definition'.
:references FN
Run when looking for usage references of a symbol in the current project. Used
by `+lookup/references'.
@@ -46,6 +52,7 @@ change the current buffer or window or return non-nil when it succeeds.
If it doesn't change the current buffer, or it returns nil, the lookup module
will fall back to the next handler in `+lookup-definition-functions',
`+lookup-implementations-functions', `+lookup-type-definition-functions',
`+lookup-references-functions', `+lookup-file-functions' or
`+lookup-documentation-functions'.
@@ -57,35 +64,40 @@ This can be passed nil as its second argument to unset handlers for MODES. e.g.
(set-lookup-handlers! 'python-mode nil)
\(fn MODES &key DEFINITION REFERENCES DOCUMENTATION FILE XREF-BACKEND ASYNC)"
\(fn MODES &key DEFINITION IMPLEMENTATIONS TYPE-DEFINITION REFERENCES DOCUMENTATION FILE XREF-BACKEND ASYNC)"
(declare (indent defun))
(dolist (mode (doom-enlist modes))
(let ((hook (intern (format "%s-hook" mode)))
(fn (intern (format "+lookup--init-%s-handlers-h" mode))))
(cond ((null (car plist))
(remove-hook hook fn)
(unintern fn nil))
((fset
fn
(lambda ()
(cl-destructuring-bind (&key definition references documentation file xref-backend async)
plist
(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)
(make-list 5 async)
(make-list 5 (or (eq major-mode mode)
(and (boundp mode)
(symbol-value mode))))))))
(add-hook hook fn))))))
(if (null (car plist))
(progn
(remove-hook hook fn)
(unintern fn nil))
(fset
fn
(lambda ()
(cl-destructuring-bind (&key definition implementations type-definition references documentation file xref-backend async)
plist
(cl-mapc #'+lookup--set-handler
(list definition
implementations
type-definition
references
documentation
file
xref-backend)
(list '+lookup-definition-functions
'+lookup-implementations-functions
'+lookup-type-definition-functions
'+lookup-references-functions
'+lookup-documentation-functions
'+lookup-file-functions
'xref-backend-functions)
(make-list 5 async)
(make-list 5 (or (eq major-mode mode)
(and (boundp mode)
(symbol-value mode))))))))
(add-hook hook fn)))))
;;
@@ -130,20 +142,24 @@ This can be passed nil as its second argument to unset handlers for MODES. e.g.
(defun +lookup--jump-to (prop identifier &optional display-fn arg)
(let* ((origin (point-marker))
(handlers (plist-get (list :definition '+lookup-definition-functions
:references '+lookup-references-functions
:documentation '+lookup-documentation-functions
:file '+lookup-file-functions)
prop))
(handlers
(plist-get (list :definition '+lookup-definition-functions
:implementations '+lookup-implementations-functions
:type-definition '+lookup-type-definition-functions
:references '+lookup-references-functions
:documentation '+lookup-documentation-functions
:file '+lookup-file-functions)
prop))
(result
(if arg
(if-let*
((handler (intern-soft
(completing-read "Select lookup handler: "
(delete-dups
(remq t (append (symbol-value handlers)
(default-value handlers))))
nil t))))
(if-let
(handler
(intern-soft
(completing-read "Select lookup handler: "
(delete-dups
(remq t (append (symbol-value handlers)
(default-value handlers))))
nil t)))
(+lookup--run-handlers handler identifier origin)
(user-error "No lookup handler selected"))
(run-hook-wrapped handlers #'+lookup--run-handlers identifier origin))))
@@ -160,40 +176,29 @@ This can be passed nil as its second argument to unset handlers for MODES. e.g.
(better-jumper-set-jump (marker-position origin)))
result)))
;;;###autoload
(defun +lookup-symbol-or-region (&optional initial)
"Grab the symbol at point or selected region."
(cond ((stringp initial)
initial)
((use-region-p)
(buffer-substring-no-properties (region-beginning)
(region-end)))
((require 'xref nil t)
;; A little smarter than using `symbol-at-point', though in most cases,
;; xref ends up using `symbol-at-point' anyway.
(xref-backend-identifier-at-point (xref-find-backend)))))
;;
;;; Lookup backends
(defun +lookup--xref-show (fn identifier)
(defun +lookup--xref-show (fn identifier &optional show-fn)
(let ((xrefs (funcall fn
(xref-find-backend)
identifier)))
(when xrefs
(xref--show-xrefs xrefs nil)
(funcall (or show-fn #'xref--show-defs)
(lambda () xrefs)
nil)
(if (cdr xrefs)
'deferred
t))))
(defun +lookup-xref-definitions-backend-fn (identifier)
"Non-interactive wrapper for `xref-find-definitions'"
(+lookup--xref-show 'xref-backend-definitions identifier))
(+lookup--xref-show 'xref-backend-definitions identifier #'xref--show-defs))
(defun +lookup-xref-references-backend-fn (identifier)
"Non-interactive wrapper for `xref-find-references'"
(+lookup--xref-show 'xref-backend-references identifier))
(+lookup--xref-show 'xref-backend-references identifier #'xref--show-xrefs))
(defun +lookup-dumb-jump-backend-fn (_identifier)
"Look up the symbol at point (or selection) with `dumb-jump', which conducts a
@@ -243,12 +248,36 @@ 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)
(interactive (list (doom-thing-at-point-or-region)
current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point"))
((+lookup--jump-to :definition identifier nil arg))
((error "Couldn't find the definition of %S" identifier))))
;;;###autoload
(defun +lookup/implementations (identifier &optional arg)
"Jump to the implementations of IDENTIFIER (defaults to the symbol at point).
Each function in `+lookup-implementations-functions' is tried until one changes
the point or current buffer."
(interactive (list (doom-thing-at-point-or-region)
current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point"))
((+lookup--jump-to :implementations identifier nil arg))
((error "Couldn't find the implementations of %S" identifier))))
;;;###autoload
(defun +lookup/type-definition (identifier &optional arg)
"Jump to the type definition of IDENTIFIER (defaults to the symbol at point).
Each function in `+lookup-type-definition-functions' is tried until one changes
the point or current buffer."
(interactive (list (doom-thing-at-point-or-region)
current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point"))
((+lookup--jump-to :type-definition identifier nil arg))
((error "Couldn't find the definition of %S" identifier))))
;;;###autoload
(defun +lookup/references (identifier &optional arg)
"Show a list of usages of IDENTIFIER (defaults to the symbol at point)
@@ -256,7 +285,7 @@ evil-mode is active."
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)
(interactive (list (doom-thing-at-point-or-region)
current-prefix-arg))
(cond ((null identifier) (user-error "Nothing under point"))
((+lookup--jump-to :references identifier nil arg))
@@ -269,7 +298,7 @@ search otherwise."
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)
(interactive (list (doom-thing-at-point-or-region)
current-prefix-arg))
(cond ((+lookup--jump-to :documentation identifier #'pop-to-buffer arg))
((user-error "Couldn't find documentation for %S" identifier))))
@@ -290,33 +319,56 @@ Otherwise, falls back on `find-file-at-point'."
(or (ffap-guesser)
(ffap-read-file-or-url
(if ffap-url-regexp "Find file or URL: " "Find file: ")
(+lookup-symbol-or-region))))))
(doom-thing-at-point-or-region))))))
(require 'ffap)
(cond ((not path)
(call-interactively #'find-file-at-point))
(cond ((and path
buffer-file-name
(file-equal-p path buffer-file-name)
(user-error "Already here")))
((ffap-url-p path)
(find-file-at-point path))
((+lookup--jump-to :file path))
((not (+lookup--jump-to :file path))
(let ((fullpath (doom-path 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 (doom-glob fullpath))
#'find-file)
((ignore-errors (file-in-directory-p fullpath project-root))
(lambda (dir)
(let* ((default-directory dir)
projectile-project-name
projectile-project-root
(projectile-project-root-cache (make-hash-table :test 'equal))
(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))))))
((stringp path) (find-file-at-point path))
((call-interactively #'find-file-at-point))))
;;
;;; Dictionary
;;;###autoload
(defun +lookup/dictionary-definition (identifier &optional arg)
"Look up the definition of the word at point (or selection)."
(interactive
(list (or (doom-thing-at-point-or-region 'word)
(read-string "Look up in dictionary: "))
current-prefix-arg))
(message "Looking up definition for %S" identifier)
(cond ((and IS-MAC (require 'osx-dictionary nil t))
(osx-dictionary--view-result identifier))
((and +lookup-dictionary-prefer-offline
(require 'wordnut nil t))
(unless (executable-find wordnut-cmd)
(user-error "Couldn't find %S installed on your system"
wordnut-cmd))
(wordnut-search identifier))
((require 'define-word nil t)
(define-word identifier nil arg))
((user-error "No dictionary backend is available"))))
;;;###autoload
(defun +lookup/synonyms (identifier &optional _arg)
"Look up and insert a synonym for the word at point (or selection)."
(interactive
(list (doom-thing-at-point-or-region 'word) ; TODO actually use this
current-prefix-arg))
(message "Looking up synonyms for %S" identifier)
(cond ((and +lookup-dictionary-prefer-offline
(require 'synosaurus-wordnet nil t))
(unless (executable-find synosaurus-wordnet--command)
(user-error "Couldn't find %S installed on your system"
synosaurus-wordnet--command))
(synosaurus-choose-and-replace))
((require 'powerthesaurus nil t)
(powerthesaurus-lookup-word-dwim))
((user-error "No thesaurus backend is available"))))

View File

@@ -25,8 +25,8 @@ argument is non-nil)."
(+lookup--online-provider (not current-prefix-arg))))
;;;###autoload
(defun +lookup/online (arg &optional query provider)
"Looks up QUERY (a string) in you browser using PROVIDER.
(defun +lookup/online (query provider)
"Looks up QUERY (a string) in you browser usin PROVIDER.
PROVIDER should be a key of `+lookup-provider-url-alist'.
@@ -34,14 +34,13 @@ 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 "P")
(let* ((provider (or provider (+lookup--online-provider arg)))
(query (or query (+lookup-symbol-or-region)))
(backend (cl-find-if (lambda (x) (or (stringp x) (fboundp x)))
(cdr (assoc provider +lookup-provider-url-alist)))))
(if (and (functionp backend)
(commandp backend))
(call-interactively backend)
(interactive
(list (if (use-region-p) (doom-thing-at-point-or-region))
(+lookup--online-provider current-prefix-arg)))
(let ((backend (cl-find-if (lambda (x) (or (stringp x) (fboundp x)))
(cdr (assoc provider +lookup-provider-url-alist)))))
(unless (and (functionp backend)
(funcall backend query))
(unless backend
(user-error "%S is an invalid query engine backend for %S provider"
backend provider))
@@ -69,3 +68,32 @@ for the provider."
(interactive)
(let ((current-prefix-arg t))
(call-interactively #'+lookup/online)))
;;
;;; Special provider frontends
(defvar ivy-initial-inputs-alist)
(defvar counsel-search-engine)
;;;###autoload
(defun +lookup--online-backend-google (query)
"Search google, starting with QUERY, with live autocompletion."
(cond ((fboundp 'counsel-search)
(let ((ivy-initial-inputs-alist `((t . ,query)))
(counsel-search-engine 'google))
(call-interactively #'counsel-search)
t))
((require 'helm-net nil t)
(helm :sources 'helm-source-google-suggest
:buffer "*helm google*"
:input query)
t)))
;;;###autoload
(defun +lookup--online-backend-duckduckgo (query)
"Search duckduckgo, starting with QUERY, with live autocompletion."
(cond ((fboundp 'counsel-search)
(let ((ivy-initial-inputs-alist `((t . ,query)))
(counsel-search-engine 'ddg))
(call-interactively #'counsel-search)
t))))

View File

@@ -3,6 +3,8 @@
;; "What am I looking at?" This module helps you answer this question.
;;
;; + `+lookup/definition': a jump-to-definition that should 'just work'
;; + `+lookup/implementations': find a symbol's implementations in the current
;; project
;; + `+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
@@ -13,11 +15,12 @@
;; `dumb-jump' to find what you want.
(defvar +lookup-provider-url-alist
(append '(("Google" counsel-search helm-google-suggest "https://google.com/search?q=%s")
(append '(("Doom Emacs issues" "https://github.com/hlissner/doom-emacs/issues?q=is%%3Aissue+%s")
("Google" +lookup--online-backend-google "https://google.com/search?q=%s")
("Google images" "https://www.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" counsel-search "https://duckduckgo.com/?q=%s")
("DuckDuckGo" +lookup--online-backend-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")
@@ -51,6 +54,24 @@ If the argument is interactive (satisfies `commandp'), it is called with
argument: the identifier at point. See `set-lookup-handlers!' about adding to
this list.")
(defvar +lookup-implementations-functions ()
"Function for `+lookup/implementations' to try. 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. See `set-lookup-handlers!' about adding to
this list.")
(defvar +lookup-type-definition-functions ()
"Functions for `+lookup/type-definition' to try. 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. See `set-lookup-handlers!' about adding to
this list.")
(defvar +lookup-references-functions
'(+lookup-xref-references-backend-fn
+lookup-project-search-backend-fn)
@@ -84,6 +105,19 @@ If the argument is interactive (satisfies `commandp'), it is called with
argument: the identifier at point. See `set-lookup-handlers!' about adding to
this list.")
(defvar +lookup-dictionary-prefer-offline (featurep! +offline)
"If non-nil, look up dictionaries online.
Setting this to nil will force it to use offline backends, which may be less
than perfect, but available without an internet connection.
Used by `+lookup/dictionary-definition' and `+lookup/synonyms'.
For `+lookup/dictionary-definition', this is ignored on Mac, where Emacs users
Dictionary.app behind the scenes to get definitions.")
(defvar +lookup--dash-docs-xwidget-webkit-last-session-buffer nil)
;;
;;; dumb-jump
@@ -92,6 +126,7 @@ this list.")
:commands dumb-jump-result-follow
:config
(setq dumb-jump-default-project doom-emacs-dir
dumb-jump-prefer-searcher 'rg
dumb-jump-aggressive nil
dumb-jump-selector
(cond ((featurep! :completion ivy) 'ivy)
@@ -124,12 +159,17 @@ this list.")
(use-package! ivy-xref
:when (featurep! :completion ivy)
:config
(setq xref-show-xrefs-function #'ivy-xref-show-xrefs)
(set-popup-rule! "^\\*xref\\*$" :ignore t))
(set-popup-rule! "^\\*xref\\*$" :ignore t)
;; xref initialization is different in Emacs 27 - there are two different
;; variables which can be set rather than just one
(when EMACS27+
(setq xref-show-definitions-function #'ivy-xref-show-defs))
;; Necessary in Emacs <27. In Emacs 27 it will affect all xref-based
;; commands other than xref-find-definitions too (eg project-find-regexp)
(setq xref-show-xrefs-function #'ivy-xref-show-xrefs))
(use-package! helm-xref
:when (featurep! :completion helm)
:config (setq xref-show-xrefs-function #'helm-xref-show-xrefs)))
:when (featurep! :completion helm)))
;;
@@ -141,7 +181,7 @@ this list.")
:init
(add-hook '+lookup-documentation-functions #'+lookup-dash-docsets-backend-fn)
:config
(setq dash-docs-enable-debugging doom-debug-mode
(setq dash-docs-enable-debugging doom-debug-p
dash-docs-docsets-path (concat doom-etc-dir "docsets/")
dash-docs-min-length 2
dash-docs-browser-func #'eww)
@@ -160,8 +200,44 @@ See https://github.com/magit/ghub/issues/81"
(let ((gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3"))
(funcall orig-fn url)))
(use-package! helm-dash
:when (featurep! :completion helm))
;; Dash docset + Xwidget integration
(when (featurep! +xwidget)
(defun +lookup-dash-docs-xwidget-webkit-browse-url-fn (url &optional new-session)
(if (not (display-graphic-p))
(eww url new-session)
(setq xwidget-webkit-last-session-buffer +lookup--dash-docs-xwidget-webkit-last-session-buffer)
(save-window-excursion
(xwidget-webkit-browse-url url new-session))
(with-popup-rules! '(("^\\*xwidget" :vslot -11 :size 0.35 :select nil))
(pop-to-buffer xwidget-webkit-last-session-buffer))
(setq +lookup--dash-docs-xwidget-webkit-last-session-buffer xwidget-webkit-last-session-buffer
xwidget-webkit-last-session-buffer nil)))
(setq dash-docs-browser-func #'+lookup-dash-docs-xwidget-webkit-browse-url-fn))
(use-package! counsel-dash
:when (featurep! :completion ivy)))
(cond ((featurep! :completion helm)
(require 'helm-dash nil t))
((featurep! :completion ivy)
(require 'counsel-dash nil t))))
;;
;;; Dictionary integration
(use-package! define-word
:when (featurep! +dictionary)
:unless IS-MAC
:defer t
:config
(setq define-word-displayfn-alist
(cl-loop for (service . _) in define-word-services
collect (cons service #'+eval-display-results-in-popup))))
(when (featurep! +dictionary)
(define-key! text-mode-map
[remap +lookup/definition] #'+lookup/dictionary-definition
[remap +lookup/references] #'+lookup/synonyms))
;;;###package synosaurus
(setq synosaurus-choose-method 'default) ; use ivy/helm instead of ido

View File

@@ -8,18 +8,31 @@
(package! helm))
;;
(package! dumb-jump)
(package! dumb-jump :pin "d86f59c4c0eb9371dd84bc2aaff5d7445f04ba27")
(when (featurep! :completion ivy)
(package! ivy-xref)
;; Need for Google/DuckDuckGo auto-completion on `+lookup/online'
(package! request))
(package! ivy-xref :pin "3d4c35fe2b243d948d8fe02a1f0d76a249d63de9"))
(when (featurep! :completion helm)
(package! helm-google)
(package! helm-xref))
(package! helm-xref :pin "6b4a8bd91f5eaf82f51bd31b03f6587387fe6983"))
;; For dictionary and online lookup
(package! request :pin "912525c772984c6af0fd84acd6699ee43d91037a")
(when (featurep! +docsets)
(package! dash-docs)
(package! dash-docs :pin "dafc8fc9f1ddb2e4e39e0b8d066c42d5d7ce8d06")
(when (featurep! :completion helm)
(package! helm-dash))
(package! helm-dash :pin "7f853bd34da666f0e9a883011c80f451b06f6c59"))
(when (featurep! :completion ivy)
(package! counsel-dash)))
(package! counsel-dash :pin "370d5f6f14b5294d0eb717f7b2a6a8e93df1ed24")))
(when (featurep! +dictionary)
(if IS-MAC
(package! osx-dictionary :pin "1b79ff64c72485cb078db9ab7ee3256b11a99f4b")
(package! define-word :pin "08c71b1ff4fd07bf0c78d1fcf77efeaafc8f7443")
;; HACK Fix #2945: the main package is broken due to
;; SavchenkoValeriy/emacs-powerthesaurus#11
(package! powerthesaurus
:recipe (:host github :repo "maxchaos/emacs-powerthesaurus" :branch "pt-api-change")
:pin "4a834782a394f2dc70fc02d68b6962b44d87f0cf")
(when (featurep! +offline)
(package! wordnut :pin "feac531404041855312c1a046bde7ea18c674915")
(package! synosaurus :pin "14d34fc92a77c3a916b4d58400424c44ae99cd81"))))

View File

@@ -7,8 +7,10 @@
- [[#description][Description]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#hacks][Hacks]]
- [[#prerequisites][Prerequisites]]
- [[#features][Features]]
- [[#lsp-powered-project-search][LSP-powered project search]]
- [[#configuration][Configuration]]
- [[#troubleshooting][Troubleshooting]]
@@ -40,23 +42,36 @@ As of this writing, this is the state of LSP support in Doom Emacs:
| [[../../lang/haskell/README.org][:lang haskell]] | haskell-mode | haskell-ide-engine |
| [[../../lang/java/README.org][:lang java]] | java-mode | lsp-java |
| [[../../lang/javascript/README.org][:lang javascript]] | js2-mode, rjsx-mode, typescript-mode | typescript-language-server |
| [[../../lang/ocaml/README.org][:lang ocaml]] | taureg-mode | ocaml-language-server |
| [[../../lang/ocaml/README.org][:lang ocaml]] | tuareg-mode | ocaml-language-server |
| [[../../lang/php/README.org][:lang php]] | php-mode | php-language-server |
| [[../../lang/python/README.org][:lang python]] | python-mode | lsp-python-ms |
| [[../../lang/ruby/README.org][:lang ruby]] | ruby-mode, enh-ruby-mode | solargraph |
| [[../../lang/ruby/README.org][:lang ruby]] | ruby-mode | solargraph |
| [[../../lang/rust/README.org][:lang rust]] | rust-mode | rls |
| [[../../lang/scala/README.org][:lang scala]] | scala-mode | metals |
| [[../../lang/sh/README.org][:lang sh]] | sh-mode | bash-language-server |
| [[../../lang/swift/README.org][:lang swift]] | swift-mode | sourcekit |
| [[../../lang/web/README.org][:lang web]] | web-mode, css-mode, scss-mode, sass-mode, less-css-mode | vscode-css-languageserver-bin, vscode-html-languageserver-bin |
| [[../../lang/purescript/README.org][:lang purescript]] | purescript-mode | purescript-language-server |
** Module Flags
This module provides no flags.
+ =+peek= Use =lsp-ui-peek= when looking up definitions and references with
functionality from the =:tools lookup= module.
+ =+eglot= Use [[https://elpa.gnu.org/packages/eglot.html][Eglot]] instead of [[https://github.com/emacs-lsp/lsp-mode][LSP-mode]] to implement the LSP client in
Emacs.
** Plugins
+ [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]]
+ [[https://github.com/emacs-lsp/lsp-ui][lsp-ui]]
+ [[https://github.com/tigersoldier/company-lsp][company-lsp]]*
+ [[https://github.com/emacs-lsp/lsp-ivy][lsp-ivy]]
+ [[https://github.com/emacs-lsp/helm-lsp][helm-lsp]]
+ [[https://github.com/joaotavora/eglot][eglot]]
** Hacks
+ ~lsp-mode~ has been modified not to automatically install missing LSP servers.
This is done to adhere to our "Your system, your rules" mantra, which insist
that it is better etiquette to let the user decide when their development
environment is modified. Use ~M-x lsp-install-server~ to install LSP servers
manually.
* Prerequisites
This module has no direct prerequisites, but major-modes require you to install
@@ -66,8 +81,37 @@ You'll find a table that lists available language servers and how to install
them [[https://github.com/emacs-lsp/lsp-mode#supported-languages][in the lsp-mode project README]]. The documentation of the module for your
targeted language will contain brief instructions as well.
For eglot users, you can see the list of [[https://github.com/joaotavora/eglot/blob/master/README.md#connecting-to-a-server][default servers supported in the README]].
There is also instructions to add another server easily.
* TODO Features
** LSP-powered project search
Without the =+eglot= flag, and when =:completion ivy= or =:completion helm= is
active, LSP is used to search a symbol indexed by the LSP server :
| Keybind | Description |
|-----------+-------------------------------------|
| =SPC c j= | Jump to symbol in current workspace |
| =SPC c J= | Jump to symbol in any workspace |
** Differences between eglot and lsp-mode
Entering the debate about which one to use would be useless. Doom provides an
easy way to switch out lsp client implementations so you can test for yourself
which one you prefer.
Mainly, from a code point of view, lsp-mode has a lot of custom code for UI
(=lsp-ui-peek=, =lsp-ui-sideline=, ...), while eglot is more barebones with a
closer integration with "more basic" emacs packages (=eldoc=, =xref=, ...).
* TODO Configuration
* TODO Troubleshooting
** My language server is not found
Check the entry in the [[../../../docs/faq.org][FAQ]] about "Doom can't find my executables/doesn't inherit
the correct ~PATH~"
** LSP/Eglot is not started automatically in my buffer
Make sure that you added the =+lsp= flag to the language you're using too in
your init.el :
#+BEGIN_SRC diff
:lang
-python
+(python +lsp)
#+END_SRC

View File

@@ -1,4 +0,0 @@
;;; feature/lsp/autoload.el -*- lexical-binding: t; -*-
;;;###autodef
(defalias 'lsp! #'lsp-deferred)

View File

@@ -1,150 +1,16 @@
;;; tools/lsp/config.el -*- lexical-binding: t; -*-
(defvar +lsp-company-backend 'company-lsp
"What backend to prepend to `company-backends' when `lsp-mode' is active.
(defvar +lsp-defer-shutdown 3
"If non-nil, defer shutdown of LSP servers for this many seconds after last
workspace buffer is closed.
This can be a single company backend or a list thereof. It can be anything
`company-backends' will accept.")
This delay prevents premature server shutdown when a user still intends on
working on that project after closing the last buffer.")
;;
;;; Packages
;;; Implementations
(use-package! lsp-mode
:defer t
:init
(setq lsp-session-file (concat doom-etc-dir "lsp-session"))
;; Don't prompt the user for the project root every time we open a new
;; lsp-worthy file, instead, try to guess it with projectile.
(setq lsp-auto-guess-root t)
;; Auto-kill LSP server once you've killed the last buffer associated with its
;; project.
(setq lsp-keep-workspace-alive nil)
;; For `lsp-clients'
(setq lsp-fsharp-server-install-dir (concat doom-etc-dir "lsp-fsharp/")
lsp-groovy-server-install-dir (concat doom-etc-dir "lsp-groovy/")
lsp-intelephense-storage-path (concat doom-cache-dir "lsp-intelephense/"))
:config
(set-lookup-handlers! 'lsp-mode :async t
:documentation 'lsp-describe-thing-at-point
:definition 'lsp-find-definition
:references 'lsp-find-references)
(defvar +lsp--deferred-shutdown-timer nil)
(defadvice! +lsp-defer-server-shutdown-a (orig-fn)
"Defer server shutdown for a few seconds.
This gives the user a chance to open other project files before the server is
auto-killed (which is usually an expensive process)."
:around #'lsp--shutdown-workspace
(if (or lsp-keep-workspace-alive
(eq (lsp--workspace-shutdown-action lsp--cur-workspace)
'restart))
(funcall orig-fn)
(when (timerp +lsp--deferred-shutdown-timer)
(cancel-timer +lsp--deferred-shutdown-timer))
(setq +lsp--deferred-shutdown-timer
(run-at-time
3 nil (lambda (workspace)
(let ((lsp--cur-workspace workspace))
(unless (lsp--workspace-buffers lsp--cur-workspace)
(funcall orig-fn))))
lsp--cur-workspace))))
(defadvice! +lsp-prompt-if-no-project-a (session file-name)
"Prompt for the project root only if no project was found."
:after-until #'lsp--calculate-root
(cond ((not lsp-auto-guess-root)
nil)
((cl-find-if (lambda (dir)
(and (lsp--files-same-host dir file-name)
(file-in-directory-p file-name dir)))
(lsp-session-folders-blacklist session))
nil)
((lsp--find-root-interactively session))))
(defadvice! +lsp-init-a (&optional arg)
"Enable `lsp-mode' in the current buffer.
Meant to be a lighter alternative to `lsp', which is too eager about
initializing lsp-ui-mode, company, yasnippet and flycheck. Instead, these have
been moved out to their respective modules, or these hooks:
+ `+lsp-init-company-h' (on `lsp-mode-hook')
+ `+lsp-init-ui-flycheck-or-flymake-h' (on `lsp-ui-mode-hook')
Also logs the resolved project root, if found."
:override #'lsp
(interactive "P")
(require 'lsp-mode)
(when lsp-auto-configure
(require 'lsp-clients))
(and (buffer-file-name)
(setq-local
lsp--buffer-workspaces
(or (lsp--try-open-in-library-workspace)
(lsp--try-project-root-workspaces
(equal arg '(4))
(and arg (not (equal arg 1))))))
(prog1 (lsp-mode 1)
;; Announce what project root we're using, for diagnostic purposes
(if-let (root (lsp--calculate-root (lsp-session) (buffer-file-name)))
(lsp--info "Guessed project root is %s" (abbreviate-file-name root))
(lsp--info "Could not guess project root."))
(lsp--info "Connected to %s."
(apply #'concat
(mapcar
(lambda (it) (format "[%s]" (lsp--workspace-print it)))
lsp--buffer-workspaces))))))
;; Don't prompt to restart LSP servers while quitting Emacs
(add-hook! 'kill-emacs-hook (setq lsp-restart 'ignore)))
(use-package! lsp-ui
:hook (lsp-mode . lsp-ui-mode)
:init
(add-hook! 'lsp-ui-mode-hook
(defun +lsp-init-ui-flycheck-or-flymake-h ()
"Sets up flymake-mode or flycheck-mode, depending on `lsp-prefer-flymake'."
(cond ((eq :none lsp-prefer-flymake))
(lsp-prefer-flymake
(lsp--flymake-setup))
((require 'flycheck nil t)
(require 'lsp-ui-flycheck)
(lsp-ui-flycheck-enable t)))))
:config
(setq lsp-prefer-flymake nil
lsp-ui-doc-max-height 8
lsp-ui-doc-max-width 35
lsp-ui-sideline-ignore-duplicate t
;; lsp-ui-doc is redundant with and more invasive than
;; `+lookup/documentation'
lsp-ui-doc-enable nil
;; Don't show symbol definitions in the sideline. They are pretty noisy,
;; and there is a bug preventing Flycheck errors from being shown (the
;; errors flash briefly and then disappear).
lsp-ui-sideline-show-hover nil)
(set-lookup-handlers! 'lsp-ui-mode :async t
:definition 'lsp-ui-peek-find-definitions
:references 'lsp-ui-peek-find-references))
(use-package! company-lsp
:when (featurep! :completion company)
:defer t
:init
;; Make sure that `company-capf' is disabled since it is incompatible with
;; `company-lsp' (see lsp-mode#884)
(add-hook! 'lsp-mode-hook
(defun +lsp-init-company-h ()
(if (not (bound-and-true-p company-mode))
(add-hook 'company-mode-hook #'+lsp-init-company-h t t)
(setq-local company-backends
(cons +lsp-company-backend
(remq 'company-capf company-backends)))
(remove-hook 'company-mode-hook #'+lsp-init-company-h t))))
:config
(setq company-lsp-cache-candidates 'auto)) ;; cache candidates for better performance
(if (featurep! +eglot)
(load! "+eglot")
(load! "+lsp"))

View File

@@ -1,7 +1,15 @@
;; -*- no-byte-compile: t; -*-
;;; tools/lsp/packages.el
(package! lsp-mode)
(package! lsp-ui)
(when (featurep! :completion company)
(package! company-lsp))
(if (featurep! +eglot)
(progn
(package! eglot :pin "ac9239bed5e3bfbf057382d1a75cdfa23f2caddd")
(package! project
:recipe (:host github :repo "emacs-straight/project")
:pin "da0333a697b18f0a863c1b1523d2fc7991b31174"))
(package! lsp-mode :pin "5f3f9848b2d4afc69049121c60126a6405447106")
(package! lsp-ui :pin "d92cf83d95c9ca177b735500ead88cf68dc2e2db")
(when (featurep! :completion ivy)
(package! lsp-ivy :pin "dce58b5509271bbedb53ba9d0278dcb563a43977"))
(when (featurep! :completion helm)
(package! helm-lsp :pin "5018af9c709a783de1b9e101e07c948cceed67f1")))

View File

@@ -49,3 +49,6 @@
;;;###autoload (autoload '+macos/send-project-to-launchbar "tools/macos/autoload" nil t)
(+macos--open-with send-project-to-launchbar "LaunchBar"
(or (doom-project-root) default-directory))
;;;###autoload (autoload '+macos/open-in-iterm "tools/macos/autoload" nil t)
(+macos--open-with open-in-iterm "iTerm" default-directory)

View File

@@ -1,10 +1,26 @@
;;; tools/magit/autoload.el -*- lexical-binding: t; -*-
;; HACK Magit complains loudly when it can't determine its own version, which is
;; the case when magit is built through straight. The warning is harmless,
;; however, so we just need it to shut up.
;; HACK Magit complains loudly (but harmlessly) when it can't determine its own
;; version in a sparse clone. This was fixed upstream in
;; magit/magit@b1b2683, but only for macOS and Linux users. Windows doesn't
;; support symlinks as unix knows them, so `magit-version' can't resolve
;; its own repo's path.
;;;###autoload
(advice-add #'magit-version :override #'ignore)
(when! IS-WINDOWS
(defadvice! +magit--ignore-version-a (&optional print-dest)
:override #'magit-version
(when print-dest
(defvar magit-git-debug)
(princ (format "Magit (unknown), Git %s, Emacs %s, %s"
(or (let ((magit-git-debug
(lambda (err)
(display-warning '(magit git) err :error))))
(magit-git-version t))
"(unknown)")
emacs-version
system-type)
print-dest))
nil))
;;;###autoload
(defun +magit-display-buffer-fn (buffer)
@@ -41,28 +57,42 @@
;;
;; Commands
;;; Auto-revert
(defun +magit--refresh-vc-in-buffer (buffer)
(defvar +magit--stale-p nil)
(defun +magit--revert-buffer (buffer)
(with-current-buffer buffer
(when (and vc-mode (fboundp 'vc-refresh-state))
(vc-refresh-state))
(when (and (bound-and-true-p git-gutter-mode)
(fboundp '+version-control|update-git-gutter))
(+version-control|update-git-gutter))
(setq +magit--vc-is-stale-p nil)))
(kill-local-variable '+magit--stale-p)
(when buffer-file-name
(if (buffer-modified-p (current-buffer))
(when (bound-and-true-p vc-mode)
(vc-refresh-state)
(force-mode-line-update))
(revert-buffer t t)))))
;;;###autoload
(defvar-local +magit--vc-is-stale-p nil)
(defun +magit-mark-stale-buffers-h ()
"Revert all visible buffers and mark buried buffers as stale.
Stale buffers are reverted when they are switched to, assuming they haven't been
modified."
(dolist (buffer (buffer-list))
(when (buffer-live-p buffer)
(if (get-buffer-window buffer)
(+magit--revert-buffer buffer)
(with-current-buffer buffer
(setq-local +magit--stale-p t))))))
;;;###autoload
(defun +magit-refresh-vc-state-maybe-h ()
(defun +magit-revert-buffer-maybe-h ()
"Update `vc' and `git-gutter' if out of date."
(when +magit--vc-is-stale-p
(+magit--refresh-vc-in-buffer (current-buffer))))
(when +magit--stale-p
(+magit--revert-buffer (current-buffer))))
;;;###autoload
(add-hook 'doom-switch-buffer-hook #'+magit-refresh-vc-state-maybe-h)
;;
;;; Commands
;;;###autoload
(defun +magit/quit (&optional kill-buffer)
@@ -76,12 +106,7 @@ control in buffers."
(eq major-mode 'magit-status-mode)))
(window-list)))
(mapc #'+magit--kill-buffer (magit-mode-get-buffers))
(dolist (buffer (buffer-list))
(when (buffer-live-p buffer)
(if (get-buffer-window buffer)
(+magit--refresh-vc-in-buffer buffer)
(with-current-buffer buffer
(setq +magit--vc-is-stale-p t)))))))
(+magit-mark-stale-buffers-h)))
(defun +magit--kill-buffer (buf)
"TODO"

View File

@@ -1,13 +1,10 @@
;;; tools/magit/config.el -*- lexical-binding: t; -*-
;;
;;; Packages
(use-package! magit
:commands magit-file-delete
:defer-incrementally (dash f s with-editor git-commit package eieio lv transient)
:init
(setq magit-auto-revert-mode nil) ; we do this ourselves
(setq magit-auto-revert-mode nil) ; we do this ourselves further down
;; Must be set early to prevent ~/.emacs.d/transient from being created
(setq transient-levels-file (concat doom-etc-dir "transient/levels")
transient-values-file (concat doom-etc-dir "transient/values")
@@ -19,12 +16,27 @@
;; Don't autosave repo buffers. This is too magical, and saving can
;; trigger a bunch of unwanted side-effects, like save hooks and
;; formatters. Trust us to know what we're doing.
magit-save-repository-buffers nil)
magit-save-repository-buffers nil
;; Magit runs git *a lot*. Having to scan your PATH so many times can
;; add up with each invokation, especially on Catalina (macOS) or
;; Windows, so we resolve it once.
magit-git-executable (executable-find magit-git-executable))
(add-hook 'magit-process-mode-hook #'goto-address-mode)
(defadvice! +magit-invalidate-projectile-cache-a (&rest _args)
;; We ignore the args to `magit-checkout'.
(defadvice! +magit-revert-repo-buffers-deferred-a (&rest _)
:after '(magit-checkout magit-branch-and-checkout)
(projectile-invalidate-cache nil))
;; Since the project likely now contains new files, best we undo the
;; projectile cache so it can be regenerated later.
(projectile-invalidate-cache nil)
;; Use a more efficient strategy to auto-revert buffers whose git state has
;; changed: refresh the visible buffers immediately...
(+magit-mark-stale-buffers-h))
;; ...then refresh the rest only when we switch to them, not all at once.
(add-hook 'doom-switch-buffer-hook #'+magit-revert-buffer-maybe-h)
;; Center the target file, because it's poor UX to have it at the bottom of
;; the window after invoking `magit-status-here'.
(advice-add #'magit-status-here :after #'doom-recenter-a)
;; The default location for git-credential-cache is in
;; ~/.cache/git/credential. However, if ~/.git-credential-cache/ exists, then
@@ -36,6 +48,20 @@
"~/.cache/")
"git/credential/socket")))
;; Prevent scrolling when manipulating magit-status hunks. Otherwise you must
;; reorient yourself every time you stage/unstage/discard/etc a hunk.
;; Especially so on larger projects."
(defvar +magit--pos nil)
(add-hook! 'magit-pre-refresh-hook
(defun +magit--set-window-state-h ()
(setq-local +magit--pos (list (current-buffer) (point) (window-start)))))
(add-hook! 'magit-post-refresh-hook
(defun +magit--restore-window-state-h ()
(when (and +magit--pos (eq (current-buffer) (car +magit--pos)))
(goto-char (cadr +magit--pos))
(set-window-start nil (caddr +magit--pos) t)
(kill-local-variable '+magit--pos))))
;; Magit uses `magit-display-buffer-traditional' to display windows, by
;; default, which is a little primitive. `+magit-display-buffer' marries
;; `magit-display-buffer-fullcolumn-most-v1' with
@@ -50,7 +76,7 @@
(set-popup-rule! "^\\(?:\\*magit\\|magit:\\| \\*transient\\*\\)" :ignore t)
(add-hook 'magit-popup-mode-hook #'hide-mode-line-mode)
;; Add --tags switch
;; Add additional switches that seem common enough
(transient-append-suffix 'magit-fetch "-p"
'("-t" "Fetch all tags" ("-t" "--tags")))
(transient-append-suffix 'magit-pull "-r"
@@ -63,7 +89,8 @@
(and (derived-mode-p 'magit-mode)
(not (eq major-mode 'magit-process-mode))))))
;; properly kill leftover magit buffers on quit
;; Clean up after magit by killing leftover magit buffers and reverting
;; affected buffers (or at least marking them as need-to-be-reverted).
(define-key magit-status-mode-map [remap magit-mode-bury-buffer] #'+magit/quit)
;; Close transient with ESC
@@ -71,10 +98,12 @@
(use-package! forge
:when (featurep! +forge)
;; We defer loading even further because forge's dependencies will try to
;; compile emacsql, which is a slow and blocking operation.
:after-call magit-status
:init
:commands forge-create-pullreq forge-create-issue
:preface
(setq forge-database-file (concat doom-etc-dir "forge/forge-database.sqlite"))
:config
;; All forge list modes are derived from `forge-topic-list-mode'
@@ -101,8 +130,8 @@ ensure it is built when we actually use Forge."
(message (concat "Failed to build emacsql; forge may not work correctly.\n"
"See *Compile-Log* buffer for details"))
;; HACK Due to changes upstream, forge doesn't initialize completely if
;; it doesn't find `emacsql-sqlite-executable', so we have to do it
;; manually after installing it.
;; it doesn't find `emacsql-sqlite-executable', so we have to do it
;; manually after installing it.
(setq forge--sqlite-available-p t)
(magit-add-section-hook 'magit-status-sections-hook 'forge-insert-pullreqs nil t)
(magit-add-section-hook 'magit-status-sections-hook 'forge-insert-issues nil t)
@@ -142,7 +171,7 @@ ensure it is built when we actually use Forge."
(setq evil-magit-state 'normal
evil-magit-use-z-for-folds t)
:config
(unmap! magit-mode-map
(undefine-key! magit-mode-map
;; Replaced by z1, z2, z3, etc
"M-1" "M-2" "M-3" "M-4"
"1" "2" "3" "4"

View File

@@ -1,10 +1,11 @@
;; -*- no-byte-compile: t; -*-
;;; tools/magit/packages.el
(when (package! magit)
(package! forge)
(package! magit-gitflow)
(package! magit-todos)
(package! github-review)
(when (package! magit :pin "793e387a508984ae2586b93ff78afddf7a1164ac")
(when (featurep! +forge)
(package! forge :pin "6f299d2d84a0c92a6656a6db03656c2d554d2cac"))
(package! magit-gitflow :pin "cc41b561ec6eea947fe9a176349fb4f771ed865b")
(package! magit-todos :pin "a0e5d1f3c7dfcb4f18c1b0d57f1746a4872df5c6")
(package! github-review :pin "50c6bcc7cf4d7193577b3f74eea4dd72f2b7795b")
(when (featurep! :editor evil +everywhere)
(package! evil-magit)))
(package! evil-magit :pin "88dc26ce59dbf4acb4e2891c79c4bd329553ba56")))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/make/packages.el
(package! makefile-executor)
(package! makefile-executor :pin "9a7d78f814a4b372d8f8179819cb1b37b83b1973")

View File

@@ -1,16 +1,17 @@
;; -*- no-byte-compile: t; -*-
;;; tools/pass/packages.el
(package! pass)
(package! password-store)
(package! password-store-otp)
(package! pass :pin "919d8e3826d556433ab67d4ee21a509d209d1baa")
(package! password-store :pin "07b169ec32ad6961ed8625a0b932a663abcb01d2")
(package! password-store-otp :pin "04998c8578a060ab4a4e8f46f2ee0aafad4ab4d5")
;; an older version of `auto-source-pass' is built into Emacs 26+, so we must
;; install the new version directly from the source and with a psuedonym.
(package! auth-source-pass
:recipe (:host github :repo "DamienCassou/auth-password-store"))
:recipe (:host github :repo "DamienCassou/auth-password-store")
:pin "ff4940c647786914b3cbef69103d96a4ea334111")
(when (featurep! :completion ivy)
(package! ivy-pass))
(package! ivy-pass :pin "5b523de1151f2109fdd6a8114d0af12eef83d3c5"))
(when (featurep! :completion helm)
(package! helm-pass))
(package! helm-pass :pin "ed5798f2d83937575e8f23fde33323bca9e85131"))

View File

@@ -1,11 +1,9 @@
;;; tools/pdf/config.el -*- lexical-binding: t; -*-
(use-package! pdf-tools
(use-package! pdf-view
:mode ("\\.[pP][dD][fF]\\'" . pdf-view-mode)
:magic ("%PDF" . pdf-view-mode)
:config
(map! :map pdf-view-mode-map :gn "q" #'kill-current-buffer)
:init
(after! pdf-annot
(defun +pdf-cleanup-windows-h ()
"Kill left-over annotation buffers when the document is killed."
@@ -19,9 +17,27 @@
(add-hook! 'pdf-view-mode-hook
(add-hook 'kill-buffer-hook #'+pdf-cleanup-windows-h nil t)))
(setq-default pdf-view-display-size 'fit-page
pdf-view-use-scaling t
pdf-view-use-imagemagick nil)
:config
(map! :map pdf-view-mode-map :gn "q" #'kill-current-buffer)
(setq-default pdf-view-display-size 'fit-page)
;; Enable hiDPI support, but at the cost of memory! See politza/pdf-tools#51
(setq pdf-view-use-scaling t
pdf-view-use-imagemagick nil)
;; Persist current page for PDF files viewed in Emacs
(defvar +pdf--page-restored-p nil)
(add-hook! 'pdf-view-change-page-hook
(defun +pdf-remember-page-number-h ()
(when-let (page (and buffer-file-name (pdf-view-current-page)))
(doom-store-put buffer-file-name page nil "pdf-view"))))
(add-hook! 'pdf-view-mode-hook
(defun +pdf-restore-page-number-h ()
(when-let (page (and buffer-file-name (doom-store-get buffer-file-name "pdf-view")))
(and (not +pdf--page-restored-p)
(<= page (or (pdf-cache-number-of-pages) 1))
(pdf-view-goto-page page)
(setq-local +pdf--page-restored-p t)))))
;; Add retina support for MacOS users
(when IS-MAC
@@ -31,44 +47,48 @@
:around '(pdf-annot-show-annotation
pdf-isearch-hl-matches
pdf-view-display-region)
(cl-letf* ((old-create-image (symbol-function #'create-image))
((symbol-function #'create-image)
(lambda (file-or-data &optional type data-p &rest props)
(apply old-create-image file-or-data type data-p
:width (car (pdf-view-image-size))
props))))
(letf! (defun create-image (file-or-data &optional type data-p &rest props)
(apply create-image file-or-data type data-p
:width (car (pdf-view-image-size))
props))
(apply orig-fn args))))
;; Turn off cua so copy works
(add-hook! 'pdf-view-mode-hook (cua-mode 0))
;; Handle PDF-tools related popups better
(set-popup-rule! "^\\*Outline*" :side 'right :size 40 :select nil)
(set-popup-rule! "\\(?:^\\*Contents\\|'s annots\\*$\\)" :ignore t)
(set-popup-rules!
'(("^\\*Outline*" :side right :size 40 :select nil)
("\\(?:^\\*Contents\\|'s annots\\*$\\)" :ignore t)))
;; The mode-line does serve any useful purpose is annotation windows
(add-hook 'pdf-annot-list-mode-hook #'hide-mode-line-mode)
;; Fix #1107: flickering pdfs when evil-mode is enabled
;; HACK Fix #1107: flickering pdfs when evil-mode is enabled
(setq-hook! 'pdf-view-mode-hook evil-normal-state-cursor (list nil))
;; Install epdfinfo binary if needed, blocking until it is finished
(unless (file-executable-p pdf-info-epdfinfo-program)
(let ((wconf (current-window-configuration)))
(pdf-tools-install)
(message "Building epdfinfo, this will take a moment...")
;; HACK We reset all `pdf-view-mode' buffers to fundamental mode so that
;; `pdf-tools-install' has a chance to reinitialize them as
;; `pdf-view-mode' buffers. This is necessary because `pdf-tools-install'
;; won't do this to buffers that are already in pdf-view-mode.
(dolist (buffer (doom-buffers-in-mode 'pdf-view-mode))
(with-current-buffer buffer (fundamental-mode)))
(while compilation-in-progress
;; Block until `pdf-tools-install' is done
(sleep-for 1))
;; HACK If pdf-tools was loaded by you opening a pdf file, once
;; `pdf-tools-install' completes, `pdf-view-mode' will throw an error
;; because the compilation buffer is focused, not the pdf buffer.
;; Therefore, it is imperative that the window config is restored.
(when (file-executable-p pdf-info-epdfinfo-program)
(set-window-configuration wconf))))
(when doom-interactive-p
(require 'pdf-tools)
(unless (file-executable-p pdf-info-epdfinfo-program)
(let ((wconf (current-window-configuration)))
(pdf-tools-install)
(message "Building epdfinfo, this will take a moment...")
;; HACK We reset all `pdf-view-mode' buffers to fundamental mode so that
;; `pdf-tools-install' has a chance to reinitialize them as
;; `pdf-view-mode' buffers. This is necessary because
;; `pdf-tools-install' won't do this to buffers that are already in
;; pdf-view-mode.
(dolist (buffer (doom-buffers-in-mode 'pdf-view-mode))
(with-current-buffer buffer (fundamental-mode)))
(while compilation-in-progress
;; Block until `pdf-tools-install' is done
(redisplay)
(sleep-for 1))
;; HACK If pdf-tools was loaded by you opening a pdf file, once
;; `pdf-tools-install' completes, `pdf-view-mode' will throw an error
;; because the compilation buffer is focused, not the pdf buffer.
;; Therefore, it is imperative that the window config is restored.
(when (file-executable-p pdf-info-epdfinfo-program)
(set-window-configuration wconf))))
;; Sets up `pdf-tools-enable-minor-modes', `pdf-occur-global-minor-mode' and
;; `pdf-virtual-global-minor-mode'.
(pdf-tools-install-noverify))
;; Sets up `pdf-tools-enable-minor-modes', `pdf-occur-global-minor-mode' and
;; `pdf-virtual-global-minor-mode'.
(pdf-tools-install-noverify)))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/pdf/packages.el
(package! pdf-tools)
(package! pdf-tools :pin "c510442ab89c8a9e9881230eeb364f4663f59e76")

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/prodigy/packages.el
(package! prodigy)
(package! prodigy :pin "6ae71f27b09b172f03fb55b9eeef001206baacd3")

View File

@@ -1,5 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; tools/rgb/packages.el
(package! rainbow-mode)
(package! kurecolor)
(package! rainbow-mode :pin "f780ddb18c2a73a666d093f606df92058e5601ea")
(package! kurecolor :pin "3fc84840cbbd75e646cafa2fd3a00004b55e37ec")

View File

@@ -1,11 +1,15 @@
;;; tools/terraform/config.el -*- lexical-binding: t; -*-
(when (featurep! +lsp)
(add-hook 'terraform-mode-local-vars-hook #'lsp!))
(map! :after terraform-mode
:map terraform-mode-map
:localleader
:desc "terraform apply" "a" (λ! (compile "terraform apply"))
:desc "terraform init" "i" (λ! (compile "terraform init"))
:desc "terraform plan" "p" (λ! (compile "terraform plan")))
:desc "terraform apply" "a" (cmd! (compile "terraform apply" t))
:desc "terraform init" "i" (cmd! (compile "terraform init"))
:desc "terraform plan" "p" (cmd! (compile "terraform plan")))
(use-package! company-terraform

View File

@@ -1,6 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; tools/terraform/packages.el
(package! terraform-mode)
(package! terraform-mode :pin "2967e7bdc05d15617e121052f6e43c61439b9070")
(when (featurep! :completion company)
(package! company-terraform))
(package! company-terraform :pin "2d11a21fee2f298e48968e479ddcaeda4d736e12"))

View File

@@ -104,7 +104,7 @@ but do not execute them."
(if-let* ((lines
(+tmux (format "list-windows %s -F '#{window_id};#{session_id};#{window_active};#{window_name};#{window_activity_flag}'"
(if session
(concat "-t " (car session))
(concat "-t " (shell-quote-argument (car session)))
"-a")))))
(cl-loop for line in (split-string lines "\n" t)
collect (let ((window (split-string line ";")))
@@ -122,7 +122,7 @@ but do not execute them."
(if sess-or-win
(concat (if (string-prefix-p "$" (car sess-or-win)) "-s ")
"-t "
(car sess-or-win))
(shell-quote-argument (car sess-or-win)))
"-a")))))
(cl-loop for line in (split-string lines "\n" t)
collect (let ((pane (split-string line ";")))

View File

@@ -1,5 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; tools/upload/packages.el
(package! ssh-deploy)
(package! ssh-deploy :pin "1bb2f821d4a78d483c147759348a29531486cdc4")