From 2993e64ab47be4d441a20f80b57ed9273a852757 Mon Sep 17 00:00:00 2001 From: Ravi R Kiran Date: Mon, 13 Sep 2021 19:50:31 -0500 Subject: Add forgotten file diff --git a/lisp/ravi-init-completion.el b/lisp/ravi-init-completion.el new file mode 100644 index 0000000..d6f0d4f --- /dev/null +++ b/lisp/ravi-init-completion.el @@ -0,0 +1,363 @@ +;;; ravi-init-completion.el --- selectrum/prescient/orderless/marginalia/embark/consult -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Ravi R Kiran + +;; Author: Ravi R Kiran +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Try out newfangled completion UI + +;;; Code: + +;; Use selectrum as completion UI with orderless for filtering and +;; prescient for frecency sorting + +(use-package vlf) +(use-package sudo-edit) + +(use-package orderless + :if (member ravi/use-selection-system '(selectrum vertico)) + :custom (completion-styles '(orderless)) + :config + (when (equal ravi/use-selection-system 'selectrum) + (setq orderless-skip-highlighting (lambda () selectrum-is-active)))) + +(use-package selectrum + :if (equal ravi/use-selection-system 'selectrum) + :config + (setq selectrum-highlight-candidates-function #'orderless-highlight-matches) + (setq selectrum-max-window-height 22) + (selectrum-mode +1) + + (autoload 'ffap-guesser "ffap") + (setq minibuffer-default-add-function + (defun minibuffer-default-add-function+ () + (with-selected-window (minibuffer-selected-window) + (delete-dups + (delq nil + (list (thing-at-point 'symbol) + (thing-at-point 'list) + (ffap-guesser) + (thing-at-point-url-at-point)))))))) +(use-package selectrum-prescient + :if (equal ravi/use-selection-system 'selectrum) + :config + (setq selectrum-prescient-enable-filtering nil) + (selectrum-prescient-mode +1) + (prescient-persist-mode +1)) + +(use-package vertico + :if (equal ravi/use-selection-system 'vertico) + :init + (vertico-mode)) + +(use-package marginalia + :if (member ravi/use-selection-system '(selectrum vertico)) + :config (marginalia-mode)) +(use-package embark + :if (member ravi/use-selection-system '(selectrum vertico)) + :after (sudo-edit vlf) + :commands (embark-act) + :bind (:map + ;; selectrum-minibuffer-map + vertico-map + ("C-l" . embark-act) + :map + embark-file-map + ("s" . sudo-edit) + ("l" . vlf) + ("G" . embark-magit-status)) + :init + ;; Optionally replace the key help with a completing-read interface + (setq prefix-help-command #'embark-prefix-help-command) + (bind-key "C-l" #'embark-act + (pcase ravi/use-selection-system + ('selectrum selectrum-minibuffer-map) + ('vertico vertico-map))) + :config + (defun embark-magit-status (file) + "Run `magit-status` on repo containing the embark target." + (interactive "GFile: ") + (magit-status (locate-dominating-file file ".git"))) + + ;; Hide the mode line of the Embark live/completions buffers + (add-to-list 'display-buffer-alist + '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" + nil + (window-parameters (mode-line-format . none))))) + +(use-package consult + :if (member ravi/use-selection-system '(selectrum vertico)) + :after (which-key) + :bind (;; C-c bindings (mode-specific-map) + ("C-c h" . consult-history) + ("C-c m" . consult-mode-command) + ("C-c b" . consult-bookmark) + ("C-c k" . consult-kmacro) + ;; C-x bindings (ctl-x-map) + ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command + ("C-x b" . consult-buffer) ;; orig. switch-to-buffer + ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window + ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame + ;; Custom M-# bindings for fast register access + ("M-#" . consult-register-load) + ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated) + ("C-M-#" . consult-register) + ;; Other custom bindings + ("M-y" . consult-yank-pop) ;; orig. yank-pop + (" a" . consult-apropos) ;; orig. apropos-command + ;; M-g bindings (goto-map) + ("M-g e" . consult-compile-error) + ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck + ;; Don't use consult-goto-line because avy-goto-line keeps fingers on home row + ;; ("M-g g" . consult-goto-line) ;; orig. goto-line + ;; ("M-g M-g" . consult-goto-line) ;; orig. goto-line + ("M-g o" . consult-outline) ;; Alternative: consult-org-heading + ("M-g m" . consult-mark) + ("M-g k" . consult-global-mark) + ("M-g i" . consult-imenu) + ("M-g I" . consult-imenu-multi) + ;; M-s bindings (search-map) + ("M-s f" . consult-find) + ("M-s F" . consult-locate) + ("M-s g" . consult-grep) + ("M-s G" . consult-git-grep) + ;; ("M-s r" . consult-ripgrep) + ("M-i" . consult-line) + ("M-s l" . consult-line) + ("M-s L" . consult-line-multi) + ("M-s m" . consult-multi-occur) + ("M-s k" . consult-keep-lines) + ("M-s u" . consult-focus-lines) + ;; Isearch integration + ("M-s e" . consult-isearch) + :map isearch-mode-map + ("M-e" . consult-isearch) ;; orig. isearch-edit-string + ("M-s e" . consult-isearch) ;; orig. isearch-edit-string + ("M-s l" . consult-line) ;; needed by consult-line to detect isearch + ("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch + :map consult-narrow-map + ("C-r" . consult-narrow-cycle-backward) + ("C-s" . consult-narrow-cycle-forward)) + + ;; Enable automatic preview at point in the *Completions* buffer. + ;; This is relevant when you use the default completion UI, + ;; and not necessary for Vertico, Selectrum, etc. + ;; :hook (completion-list-mode . consult-preview-at-point-mode) + + ;; The :init configuration is always executed (Not lazy) + :init + + ;; Optionally configure the register formatting. This improves the register + ;; preview for `consult-register', `consult-register-load', + ;; `consult-register-store' and the Emacs built-ins. + (setq register-preview-delay 0 + register-preview-function #'consult-register-format) + + ;; Optionally tweak the register preview window. + ;; This adds thin lines, sorting and hides the mode line of the window. + (advice-add #'register-preview :override #'consult-register-window) + + ;; Optionally replace `completing-read-multiple' with an enhanced version. + (advice-add #'completing-read-multiple :override #'consult-completing-read-multiple) + + ;; Use Consult to select xref locations with preview + (setq xref-show-xrefs-function #'consult-xref + xref-show-definitions-function #'consult-xref) + + ;; Configure other variables and modes in the :config section, + ;; after lazily loading the package. + :config + + ;; Optionally configure preview. The default value + ;; is 'any, such that any key triggers the preview. + ;; (setq consult-preview-key 'any) + (setq consult-preview-key (kbd "C-o")) + ;; (setq consult-preview-key (list (kbd "") (kbd ""))) + ;; For some commands and buffer sources it is useful to configure the + ;; :preview-key on a per-command basis using the `consult-customize' macro. + (consult-customize + consult-theme + :preview-key '(:debounce 0.2 any) + consult-ripgrep consult-git-grep consult-grep consult-xref + :preview-key 'any + consult-bookmark consult-recent-file + consult--source-file consult--source-project-file consult--source-bookmark + :preview-key "C-o") + (consult-customize consult-buffer :preview-key nil) ; preview is just too intrusive + + ;; Optionally configure the narrowing key. + ;; Both < and C-+ work reasonably well. + (setq consult-narrow-key "<") ;; (kbd "C-+") + + ;; Optionally make narrowing help available in the minibuffer. + ;; You may want to use `embark-prefix-help-command' or which-key instead. + (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help) + + ;; Optionally configure a function which returns the project root directory. + ;; There are multiple reasonable alternatives to chose from. + ;;;; 1. project.el (project-roots) + ;; (setq consult-project-root-function + ;; (lambda () + ;; (when-let (project (project-current)) + ;; (car (project-roots project))))) + ;;;; 2. projectile.el (projectile-project-root) + (autoload 'projectile-project-root "projectile") + (setq consult-project-root-function #'projectile-project-root) + ;;;; 3. vc.el (vc-root-dir) + ;; (setq consult-project-root-function #'vc-root-dir) + ;;;; 4. locate-dominating-file + ;; (setq consult-project-root-function (lambda () (locate-dominating-file "." ".git"))) + + ;; First line as default is entirely useless + (consult-customize + consult-line consult-line-multi + :default nil) + + ;; Replace by embark-prefix-help-command? + (defun immediate-which-key-for-narrow (fun &rest args) + (let* ((refresh t) + (timer (and consult-narrow-key + (memq :narrow args) + (run-at-time 0.05 0.05 + (lambda () + (if (eq last-input-event (elt consult-narrow-key 0)) + (when refresh + (setq refresh nil) + (which-key--update)) + (setq refresh t))))))) + (unwind-protect + (apply fun args) + (when timer + (cancel-timer timer))))) + (advice-add #'consult--read :around #'immediate-which-key-for-narrow) + + (defun consult-narrow-cycle-backward () + "Cycle backward through the narrowing keys." + (interactive) + (when consult--narrow-keys + (consult-narrow + (if consult--narrow + (let ((idx (seq-position consult--narrow-keys + (assq consult--narrow consult--narrow-keys)))) + (unless (eq idx 0) + (car (nth (1- idx) consult--narrow-keys)))) + (caar (last consult--narrow-keys)))))) + + (defun consult-narrow-cycle-forward () + "Cycle forward through the narrowing keys." + (interactive) + (when consult--narrow-keys + (consult-narrow + (if consult--narrow + (let ((idx (seq-position consult--narrow-keys + (assq consult--narrow consult--narrow-keys)))) + (unless (eq idx (1- (length consult--narrow-keys))) + (car (nth (1+ idx) consult--narrow-keys)))) + (caar consult--narrow-keys))))) + ) + +(use-package embark-consult + :if (member ravi/use-selection-system '(selectrum vertico)) + :after (embark consult) + :demand t ; only necessary if you have the hook below + ;; if you want to have consult previews as you move around an + ;; auto-updating embark collect buffer + :hook + (embark-collect-mode . consult-preview-at-point-mode)) + +(use-package dash-docs + :if (member ravi/use-selection-system '(selectrum vertico)) + :bind (("M-s d" . 'ravi/dash) + ("M-s D" . 'ravi/dash-at-point)) + :config + (require 'cl-lib) ; for cl-remove-duplicates, cl-find-if + (require 'subr-x) ; for when-let + + (defvar ravi/dash-history-input nil) + (defvar ravi/dash--results nil + "Stores the previously retrieved docset results") + (defvar-local ravi/dash-docsets nil + "Docsets to use for this buffer") + + (advice-add #'dash-docs-buffer-local-docsets :around + (lambda (old-fun &rest args) + (let ((old (apply old-fun args))) + (cl-remove-duplicates (append old ravi/dash-docsets))))) + + (defun ravi/dash--collection (s &rest _) + "Given a string S, query docsets and retrieve result." + (message "Trying to search for: %s" (prin1-to-string s)) + (setq ravi/dash--results (dash-docs-search s)) + (mapcar 'car ravi/dash--results)) + + (defun ravi/dash--browse-matching-result (match) + "Given a MATCH, find matching result and browse it's url." + (when-let ((result + (cdr (cl-find-if (lambda (e) + (string= match (car e))) ravi/dash--results)))) + (dash-docs-browse-url result))) + + ;; The following does not work, because vertico and selectrum don't support dynamic completions + (defun ravi/dash (&optional initial) + "Query dash docsets. +INITIAL will be used as the initial input, if given." + (interactive) + (dash-docs-initialize-debugging-buffer) + (dash-docs-create-buffer-connections) + (dash-docs-create-common-connections) + (if t + (ravi/dash--browse-matching-result + (let ((cb (current-buffer))) + (completing-read + "Documentation for: " + ;; (completion-table-dynamic (lambda (s) (with-current-buffer cb (ravi/dash--collection s)))) + (completion-table-dynamic #'ravi/dash--collection t) + nil ; predicate + t ; require-match + nil ; initial-input + ravi/dash-history-input ; history + (when-let ((sym (thing-at-point 'symbol))) (substring-no-properties sym))))) ; default, a.k.a future history + (message "%s" (prin1-to-string (ravi/dash--collection "C++ throw"))))) + + (defun ravi/dash-at-point-what-it-should-be () + "Bring up a `ravi/dash' search interface with symbol at point." + (interactive) + (ravi/dash + (substring-no-properties (or (thing-at-point 'symbol) "")))) + + (defun ravi/dash-at-point () + "Bring up a `ravi/dash' search interface with symbol at point." + (interactive) + (dash-docs-initialize-debugging-buffer) + (dash-docs-create-buffer-connections) + (dash-docs-create-common-connections) + (if-let* ((sym (thing-at-point 'symbol)) + (sym-only (substring-no-properties sym)) + (cb (current-buffer)) + (table (with-current-buffer cb (ravi/dash--collection sym-only))) + (result (completing-read (format "Documentation for '%s':" sym-only) + table nil t nil ravi/dash-history-input))) + (progn + (ravi/dash--browse-matching-result result) + (add-to-list 'ravi/dash-history-input sym-only)) + (user-error "No symbol at point or documentation not found"))) + ) + +(provide 'ravi-init-completion) +;;; ravi-init-completion.el ends here -- cgit v0.10.1