[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/aggressive-completion 4a6065a: Add new package aggressi
From: |
Tassilo Horn |
Subject: |
[elpa] externals/aggressive-completion 4a6065a: Add new package aggressive-completion.el |
Date: |
Sat, 3 Apr 2021 13:36:22 -0400 (EDT) |
branch: externals/aggressive-completion
commit 4a6065a29b190b43894112a0bac0f08af2bb2f32
Author: Tassilo Horn <tsdh@gnu.org>
Commit: Tassilo Horn <tsdh@gnu.org>
Add new package aggressive-completion.el
---
aggressive-completion.el | 181 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 181 insertions(+)
diff --git a/aggressive-completion.el b/aggressive-completion.el
new file mode 100644
index 0000000..d0f593a
--- /dev/null
+++ b/aggressive-completion.el
@@ -0,0 +1,181 @@
+;;; aggressive-completion.el --- Automatic minibuffer completion -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Tassilo Horn <tsdh@gnu.org>
+;; Maintainer: Tassilo Horn <tsdh@gnu.org>
+;; Keywords: minibuffer completion
+;; Package-Requires: ((emacs "27.1"))
+;; Version: 1.0
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Aggressive completion mode (`aggressive-completion-mode') is a minor mode
+;; which automatically completes for you after a short delay
+;; (`aggressive-completion-delay') and always shows all possible completions
+;; using the standard completion help (unless the number of possible
+;; completions exceeds `aggressive-completion-max-shown-completions').
+;;
+;; Automatic completion is temporarily disabled after all commands in
+;; `aggressive-completion-no-complete-commands'. Basically all deletion/kill
+;; commands are listed here in order not to complete back to the thing you just
+;; deleted.
+;;
+;; Aggressive completion can be toggled using
+;; `aggressive-completion-toggle-auto-complete' (bound to `M-t' by default)
+;; which is especially useful when trying to find a not yet existing file or
+;; switch to a new buffer.
+;;
+;; You can switch from minibuffer to *Completions* buffer and back again using
+;; `aggressive-completion-switch-to-completions' (bound to `M-c' by default).
+;; All keys bound to this command in `aggressive-completion-minibuffer-map'
+;; will be bound to `other-window' in `completion-list-mode-map' so that those
+;; keys act as switch-back-and-forth commands.
+
+;;; Code:
+
+(eval-when-compile
+ ;; For `when-let'.
+ (require 'subr-x))
+
+(defgroup aggressive-completion nil
+ "Aggressive completion completes for you."
+ :group 'completion)
+
+(defcustom aggressive-completion-delay 0.3
+ "Delay in seconds before aggressive completion kicks in."
+ :type 'number)
+
+(defcustom aggressive-completion-auto-complete t
+ "Complete automatically if non-nil.
+If nil, only show the completion help."
+ :type 'boolean)
+
+(defcustom aggressive-completion-max-shown-completions 1000
+ "Maximum number of possible completions for showing completion help."
+ :type 'integer)
+
+(defcustom aggressive-completion-no-complete-commands
+ '( left-char icomplete-fido-backward-updir minibuffer-complete
+ right-char delete-backward-char backward-kill-word
+ backward-kill-paragraph backward-kill-sentence backward-kill-sexp
+ delete-char kill-word kill-line completion-at-point)
+ "Commands after which automatic completion is not performed."
+ :type '(repeat command))
+
+(defvar aggressive-completion--timer nil)
+
+(defun aggressive-completion--do ()
+ "Perform aggressive completion."
+ (when (window-minibuffer-p)
+ (let* ((completions (completion-all-sorted-completions))
+ ;; Don't ding if there are no completions, etc.
+ (visible-bell nil)
+ (ring-bell-function #'ignore)
+ ;; Automatic completion should not cycle.
+ (completion-cycle-threshold nil)
+ (completion-cycling nil))
+ (let ((i 0))
+ (while (and (<= i aggressive-completion-max-shown-completions)
+ (consp completions))
+ (setq completions (cdr completions))
+ (cl-incf i))
+ (if (and (> i 0)
+ (< i aggressive-completion-max-shown-completions))
+ (if (or (null aggressive-completion-auto-complete)
+ (memq last-command
+ aggressive-completion-no-complete-commands))
+ ;; This ensures we still can repeatedly hit TAB to scroll
+ ;; through the list of completions.
+ (unless (and (= last-command-event ?\t)
+ (window-live-p
+ (get-buffer-window "*Completions*"))
+ (with-current-buffer "*Completions*"
+ (> (point) (point-min))))
+ (minibuffer-completion-help))
+ (minibuffer-complete)
+ (unless (window-live-p (get-buffer-window "*Completions*"))
+ (minibuffer-completion-help)))
+ ;; Close the *Completions* buffer if there are too many
+ ;; or zero completions.
+ (when-let ((win (get-buffer-window "*Completions*")))
+ (when (and (window-live-p win)
+ (not (memq last-command
+ '(minibuffer-completion-help
+ minibuffer-complete
+ completion-at-point))))
+ (quit-window nil win))))))))
+
+(defun aggressive-completion--timer-restart ()
+ "Restart `aggressive-completion--timer'."
+ (when aggressive-completion--timer
+ (cancel-timer aggressive-completion--timer))
+
+ (setq aggressive-completion--timer
+ (run-with-idle-timer aggressive-completion-delay nil
+ #'aggressive-completion--do)))
+
+(defun aggressive-completion-toggle-auto-complete ()
+ "Toggle automatic completion."
+ (interactive)
+ (setq aggressive-completion-auto-complete
+ (not aggressive-completion-auto-complete)))
+
+;; Add an alias so that we can find out the bound key using
+;; `where-is-internal'.
+(defalias 'aggressive-completion-switch-to-completions
+ #'switch-to-completions)
+
+(defvar aggressive-completion-minibuffer-map
+ (let ((map (make-sparse-keymap)))
+ (require 'icomplete)
+ (define-key map (kbd "DEL") #'icomplete-fido-backward-updir)
+ (define-key map (kbd "M-t") #'aggressive-completion-toggle-auto-complete)
+ (define-key map (kbd "M-c") #'aggressive-completion-switch-to-completions)
+ map)
+ "The local minibuffer keymap when `aggressive-completion-mode' is enabled.")
+
+(defun aggressive-completion--setup ()
+ "Setup aggressive completion."
+ (when (and (not executing-kbd-macro)
+ (window-minibuffer-p)
+ minibuffer-completion-table)
+ (set-keymap-parent aggressive-completion-minibuffer-map
(current-local-map))
+ (use-local-map aggressive-completion-minibuffer-map)
+
+ ;; If `aggressive-completion-switch-to-completions' is bound to keys, bind
+ ;; the same keys in `completion-list-mode-map' to `other-window' so that
+ ;; one can conveniently switch back and forth using the same key.
+ (dolist (key (where-is-internal
+ #'aggressive-completion-switch-to-completions))
+ (define-key completion-list-mode-map key #'other-window))
+
+ (add-hook 'post-command-hook
+ #'aggressive-completion--timer-restart nil t)))
+
+(define-minor-mode aggressive-completion-mode
+ "Perform aggressive minibuffer completion."
+ :lighter " ACmp"
+ :global t
+ (if aggressive-completion-mode
+ (add-hook 'minibuffer-setup-hook #'aggressive-completion--setup)
+ (remove-hook 'minibuffer-setup-hook #'aggressive-completion--setup)))
+
+(provide 'aggressive-completion)
+
+;;; aggressive-completion.el ends here