From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Tassilo Horn Newsgroups: gmane.emacs.devel Subject: [GNU ELPA] New package proposal: aggressive-completion.el Date: Sat, 03 Apr 2021 09:53:50 +0200 Message-ID: <87o8evok58.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="36917"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: mu4e 1.5.11; emacs 28.0.50 To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sat Apr 03 10:19:53 2021 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lSbVY-0009VO-K3 for ged-emacs-devel@m.gmane-mx.org; Sat, 03 Apr 2021 10:19:52 +0200 Original-Received: from localhost ([::1]:57620 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lSbVX-0003Kh-MO for ged-emacs-devel@m.gmane-mx.org; Sat, 03 Apr 2021 04:19:51 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:54558) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lSbV2-0002v4-IM for emacs-devel@gnu.org; Sat, 03 Apr 2021 04:19:20 -0400 Original-Received: from fencepost.gnu.org ([2001:470:142:3::e]:50612) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lSbV2-0004yk-Bi for emacs-devel@gnu.org; Sat, 03 Apr 2021 04:19:20 -0400 Original-Received: from auth1-smtp.messagingengine.com ([66.111.4.227]:53501) by fencepost.gnu.org with esmtpsa (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256) (Exim 4.82) (envelope-from ) id 1lSbV1-0000xA-Uk for emacs-devel@gnu.org; Sat, 03 Apr 2021 04:19:20 -0400 Original-Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailauth.nyi.internal (Postfix) with ESMTP id CE62627C0054 for ; Sat, 3 Apr 2021 04:19:18 -0400 (EDT) Original-Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Sat, 03 Apr 2021 04:19:18 -0400 X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrudeikedgtdefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpegfhffvufffkfggtgesmhdtreertd ertdenucfhrhhomhepvfgrshhsihhlohcujfhorhhnuceothhsughhsehgnhhurdhorhhg qeenucggtffrrghtthgvrhhnpeehffekheejheegueekhfevheffvdeghfffvdfggeffhe ekfffhueeiffdutefhudenucfkphepkeejrdduieefrdefuddrudehgeenucevlhhushht vghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehthhhorhhnodhmvghsmh htphgruhhthhhpvghrshhonhgrlhhithihqdekieejfeekjeekgedqieefhedvleekqdht shguhheppehgnhhurdhorhhgsehfrghsthhmrghilhdrfhhm X-ME-Proxy: Original-Received: from thinkpad-t440p (p57a31f9a.dip0.t-ipconnect.de [87.163.31.154]) by mail.messagingengine.com (Postfix) with ESMTPA id 544A724005E for ; Sat, 3 Apr 2021 04:19:18 -0400 (EDT) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:267321 Archived-At: --=-=-= Content-Type: text/plain 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): --=-=-= Content-Type: text/plain Content-Disposition: inline; filename=aggressive-completion.el ;;; aggressive-completion.el --- Automatic minibuffer completion -*- lexical-binding: t -*- ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Tassilo Horn ;; Maintainer: Tassilo Horn ;; 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 . ;;; 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))) --=-=-= Content-Type: text/plain Bye, Tassilo --=-=-=--