unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [GNU ELPA] New package proposal: aggressive-completion.el
@ 2021-04-03  7:53 Tassilo Horn
  2021-04-03  8:37 ` Tassilo Horn
                   ` (7 more replies)
  0 siblings, 8 replies; 30+ messages in thread
From: Tassilo Horn @ 2021-04-03  7:53 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 973 bytes --]

Hi all,

I'd like to propose the attached aggressive-completion.el as a new GNU
ELPA package.  I've used this since several months and now had the time
to extract it from my ~/.emacs and make a proper minor-mode out of it.

What is it?
===========

I've used several different minibuffer completion frameworks in the past
(including ivy, raven, and selectrum) in the past but always came back
to the standard emacs minibuffer completion with its nice configuration
means in terms of `completion-category-overrides' and friends.

What I've liked with the other frameworks, however, was that the
completion candidates are immediately visible and in many scenarios I
needed less typing (especially less pinky-stressing TAB-ing).

So the central idea of aggressive-completion.el is that it

  1) automatically completes for you after a short delay, and it
  2) always shows the completion help (unless there are too many).

Without further ado, here it is (comments welcome):


[-- Attachment #2: aggressive-completion.el --]
[-- Type: text/plain, Size: 7239 bytes --]

;;; 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.

(defgroup aggressive-completion nil
  "Aggressive completion completes for you.")

(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.")

(defvar aggressive-completion--timer nil)

(defun aggressive-completion--do ()
  (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-start ()
  (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 ()
  "Toggles automatic completion."
  (interactive)
  (setq aggressive-completion-auto-complete
        (not aggressive-completion-auto-complete)))

(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-start nil t)))

;; 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.")

(define-minor-mode aggressive-completion-mode
  "Perform aggressive minibuffer completion."
  :lighter "ACmp"
  (if aggressive-completion-mode
      (add-hook 'minibuffer-setup-hook #'aggressive-completion--setup)
    (remove-hook 'minibuffer-setup-hook #'aggressive-completion--setup)))

[-- Attachment #3: Type: text/plain, Size: 14 bytes --]


Bye,
Tassilo

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2021-04-05 14:21 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-03  7:53 [GNU ELPA] New package proposal: aggressive-completion.el Tassilo Horn
2021-04-03  8:37 ` Tassilo Horn
2021-04-03  9:11 ` Manuel Uberti
2021-04-03  9:42   ` Tassilo Horn
2021-04-03 10:14     ` Jean Louis
2021-04-03 11:17     ` Jean Louis
2021-04-03 10:07   ` Jean Louis
2021-04-03  9:36 ` Jean Louis
2021-04-03 10:03   ` Tassilo Horn
2021-04-03 10:19     ` Jean Louis
2021-04-03 10:24       ` Tassilo Horn
2021-04-04 13:53     ` Basil L. Contovounesios
2021-04-04 19:05       ` Tassilo Horn
2021-04-04 20:12         ` T.V Raman
2021-04-05  7:01           ` Tassilo Horn
2021-04-05 14:21             ` T.V Raman
2021-04-04 20:26         ` Stefan Monnier
2021-04-05  7:17           ` Tassilo Horn
2021-04-03  9:49 ` Jean Louis
2021-04-03 10:05   ` Tassilo Horn
2021-04-03 11:53 ` Philip Kaludercic
2021-04-03 11:55 ` Philip Kaludercic
2021-04-03 13:43   ` Tassilo Horn
2021-04-03 17:22     ` [GNU ELPA] New package proposal: aggressive-completion.El Philip Kaludercic
2021-04-03 18:03       ` Tassilo Horn
2021-04-03 14:04 ` [GNU ELPA] New package proposal: aggressive-completion.el Stefan Monnier
2021-04-03 18:29   ` Tassilo Horn
2021-04-03 19:30     ` Tassilo Horn
2021-04-03 21:01       ` Stefan Monnier
2021-04-03 20:02 ` Gabriel

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).