From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms0.migadu.com with LMTPS id GJGPJlvk52BIzAAAgWs5BA (envelope-from ) for ; Fri, 09 Jul 2021 07:53:31 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1 with LMTPS id yLpBIlvk52AuBQAAbx9fmQ (envelope-from ) for ; Fri, 09 Jul 2021 05:53:31 +0000 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 6D4901CAEB for ; Fri, 9 Jul 2021 07:53:30 +0200 (CEST) Received: from localhost ([::1]:48940 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1m1jS3-0000KW-Mi for larch@yhetil.org; Fri, 09 Jul 2021 01:53:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:36400) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1m1j1i-00013K-NY for emacs-orgmode@gnu.org; Fri, 09 Jul 2021 01:26:14 -0400 Received: from mail-pj1-x102e.google.com ([2607:f8b0:4864:20::102e]:35553) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1m1j1g-0005qn-C7 for emacs-orgmode@gnu.org; Fri, 09 Jul 2021 01:26:14 -0400 Received: by mail-pj1-x102e.google.com with SMTP id h1-20020a17090a3d01b0290172d33bb8bcso7607057pjc.0 for ; Thu, 08 Jul 2021 22:26:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=felesatra-moe.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:mime-version; bh=sWuweSVbDhxwPo2Z+Jfe5oPrI0tbSROPwE9CkARPXLw=; b=BYpDQnk3APft1COUQaUc5/ungUMmS7iNWocCaJ6Vsv0A8Aej0TIlKppxetz+KwkJkI tdJkKyGpJ8A9x6Jm2/rPo0wTiTFw5EqhK1I1M7t8pMuRbqaKLc7xyLfrJnLnvOdYzp5s nAw4Q2R3FLp2v2XC0xdBThSzWdrfLFp0zFlpguSVpW4b8yFoP7C2GAfZ2h1LZqzNw+y9 TfGMs4PBoUe4EuNxqIjwuuneMvmw2UMlBDzbyNlneUnpnA3tn/krnVNRCjr+trmMRzJY pMkJ+gUarfbTAp/Lx0VMDL6XrdDZ5buwdlq2KU2FRjNPnjgasV5KlggYgkKJDtKiOKxc 1jmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version; bh=sWuweSVbDhxwPo2Z+Jfe5oPrI0tbSROPwE9CkARPXLw=; b=F4vpyNpGkctCFw+yxNt29XOL7VolIozp+l7sRcrgwTh7JISdFYNnZbjMBCCpY21EBV GjtdkJSSCXPbSD7IZ/Up9LNe4NNrtaA7yI49noR248vOQ78P7TgD/57CfSd7LTYIL9rj 38FxXmXP6Fz0bxV9PTdISrCty1rLjgb+lyDVWNsAmlIu1xStLs8VZ0wmPI+TrsqZhQ7o zbAon594IhUGzdo5YWmMRwxoNjEocNY11i0/rdeZKDEjMs04nhVW9hUFWoYAowdzRi7R 0Vr92QTcS2J3LpJyde0tkjOGnZnEiR7KTJ5eSfsWZhmU52cQzvHaX705w6gT4oozXi6B 7yWQ== X-Gm-Message-State: AOAM531QKwXxBIBaye2Ga/xGAY5xf3K49If+4GY/hpQ7GeKsDk/YUiRx FYLUzOt8UtVg92/ISHQRSN9cNm3W9UZjIQ== X-Google-Smtp-Source: ABdhPJyqS4Ucxhq14zpx34GaleDXCfE+fyc/hgbtSL5UTqb+6NQCiyli2CCaPsBaoeT+xRhHtdK58Q== X-Received: by 2002:a17:90a:1f43:: with SMTP id y3mr13724310pjy.0.1625808369716; Thu, 08 Jul 2021 22:26:09 -0700 (PDT) Received: from localhost ([2600:1700:7270:7d1f:fa59:71ff:fe00:10cc]) by smtp.gmail.com with ESMTPSA id w69sm3364491pfc.58.2021.07.08.22.26.08 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Jul 2021 22:26:09 -0700 (PDT) From: Allen Li To: emacs-orgmode@gnu.org Subject: Bug: [PATCH] Use crm for tag completion [9.4.6 (9.4.6-gab9f2a @ /home/ionasal/.emacs.d/elpa/org-9.4.6/)] Date: Thu, 08 Jul 2021 22:26:07 -0700 Message-ID: <80mtqw3vo0.fsf@felesatra.moe> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=2607:f8b0:4864:20::102e; envelope-from=darkfeline@felesatra.moe; helo=mail-pj1-x102e.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: "Emacs-orgmode" X-Migadu-Flow: FLOW_IN ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1625810010; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=sWuweSVbDhxwPo2Z+Jfe5oPrI0tbSROPwE9CkARPXLw=; b=VCCz2SElNY2s+LMxnSXyd/SIQMciAxFGYl7BqCkXHBaSCjcpNCJQXKT7x1cKDceqP8tSz1 TY6iwuBT10i7BAhhO+rC9CXS/em7vWASKuN6msQLA5DW3YItnUM97QzbRTlmgUzHEOB/Su KbLFAxWCRcOWym+DNWtHnkvC5MdvKEcsQb6LxTu0FXHLzfzqsLBjLXbpOk3g6NWkDPHjwz YfXZPeKV2Aw//h0AfEdZtmNhFFYfyNiSTLXJyb0FvcLVCv2HbtCVNVYmV8MGrPM2dPv5U1 uYo4WsUSrP2+U/zzMBt4aEu2/W9Z5yK8j9bb8EUsGPgmCKmpIfvC+za0tKQgzQ== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1625810010; a=rsa-sha256; cv=none; b=EMWlepeUDHXkNwqpoVa7IjUUuPajUR2TLKAYxVOgDjpIbzWqLyt6Inr4BU20QY7gQBJCh9 N77bknSrxQIX53pIsf0UiHpvMXmMEPT6wtPyBce0F4LnWC0zt04scc0Q1/TnaSSQYVIUYu tvznmLBQIf0b3p7YEfuF8n+Iov771fMHP7ymRBgHzTKJMqOUMoh9uPDauqUAbiv5c7lVCI P4UAElaw1pNcD7vYUGFX5yOLHfvy7EOzSoM7Xe5HQTHH78DYCgQz8ehyDDmK0GroB/a0na zPJc38tm3u2HiswBp20WNcXYLZ8lf0rck4Gxy7dsT1uJfj6P0kni7twlh4Hgow== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=felesatra-moe.20150623.gappssmtp.com header.s=20150623 header.b=BYpDQnk3; spf=pass (aspmx1.migadu.com: domain of emacs-orgmode-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=emacs-orgmode-bounces@gnu.org X-Migadu-Spam-Score: -2.60 Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=felesatra-moe.20150623.gappssmtp.com header.s=20150623 header.b=BYpDQnk3; dmarc=none; spf=pass (aspmx1.migadu.com: domain of emacs-orgmode-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=emacs-orgmode-bounces@gnu.org X-Migadu-Queue-Id: 6D4901CAEB X-Spam-Score: -2.60 X-Migadu-Scanner: scn1.migadu.com X-TUID: sWahpBap6nYL --=-=-= Content-Type: text/plain Org mode's tag completion commands all use a custom completion function, which makes it difficult for alternative completion functions to support well. Emacs already has a function for reading multiple things, completing-read-multiple, which can be used for the tag completion use case. I have attached a patch for this change, which I have tested manually a few times and also fixed the existing tests. I have tested this with vertico, which claims to strictly follow Emacs's completion API. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-org-Use-crm-for-completing-tags.patch Content-Description: patch >From 933dc914694c14889af86c06ba0a8bbd88a316cf Mon Sep 17 00:00:00 2001 From: Allen Li Date: Thu, 8 Jul 2021 21:35:34 -0700 Subject: [PATCH] org: Use crm for completing tags Change various places which use `completing-read' to read tags using a custom completion function to instead use `completing-read-multiple' with a completion table instead. This makes tab completion play better with alternative completion frameworks such as vertico, selectrum, etc. `org-change-tag-in-region' only reads a single tag, so it is changed to use a completion table with `completing-read'. This also makes it play better with alternative completion frameworks. Note that there is still one use for `org-tags-completion-function', which is for completing tag matches. Completing tag matches is different from completing lists of tags since the separators (+, -, etc) have semantic meaning. This commit does not address that use case. * lisp/org-capture.el (org-capture-fill-template): Changed to use completing-read-multiple. * lisp/org.el (org-set-tags-command): Changed to use completing-read-multiple. (org-change-tag-in-region): Changed to use a simple completion table. * testing/lisp/test-org.el (test-org/set-tags-command): Fixed tests. * etc/ORG-NEWS (Tag completion now uses =completing-read-multiple=): Added news. --- etc/ORG-NEWS | 6 +++++ lisp/org-capture.el | 12 +++++----- lisp/org.el | 18 +++++++++------ testing/lisp/test-org.el | 50 ++++++++++++++++------------------------ 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 3f3971961..719ac3547 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -409,6 +409,12 @@ The function does not allow for a third optional parameter anymore. If a babel src block produces a raw LaTeX environment, it will now be recognised as a result, and so replaced when re-evaluated. +*** Tag completion now uses =completing-read-multiple= + +Tag completion now uses =completing-read-multiple= with a simple +completion table, which should allow better interoperability with +custom completion functions. + * Version 9.4 ** Incompatible changes *** Possibly broken internal file links: please check and fix diff --git a/lisp/org-capture.el b/lisp/org-capture.el index 5ecec6309..c51744680 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -69,6 +69,7 @@ (declare-function org-table-goto-line "org-table" (N)) (defvar dired-buffers) +(defvar crm-separator) (defvar org-end-time-was-given) (defvar org-keyword-properties) (defvar org-remember-default-headline) @@ -1739,12 +1740,11 @@ The template may still contain \"%?\" for cursor positioning." (org-add-colon-after-tag-completion t) (ins (mapconcat #'identity - (org-split-string - (completing-read - (if prompt (concat prompt ": ") "Tags: ") - 'org-tags-completion-function nil nil nil - 'org-tags-history) - "[^[:alnum:]_@#%]+") + (let ((crm-separator "[ \t]*:[ \t]*")) + (completing-read-multiple + (if prompt (concat prompt ": ") "Tags: ") + org-last-tags-completion-table nil nil nil + 'org-tags-history)) ":"))) (when (org-string-nw-p ins) (unless (eq (char-before) ?:) (insert ":")) diff --git a/lisp/org.el b/lisp/org.el index 4fd8b6fa6..ed3ee3a1c 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -201,6 +201,8 @@ Stars are put in group 1 and the trimmed body in group 2.") ;; load languages based on value of `org-babel-load-languages' (defvar org-babel-load-languages) +(defvar crm-separator) ; dynamically scoped param + ;;;###autoload (defun org-babel-do-load-languages (sym value) "Load the languages defined in `org-babel-load-languages'." @@ -12054,12 +12056,14 @@ in Lisp code use `org-set-tags' instead." inherited-tags table (and org-fast-tag-selection-include-todo org-todo-key-alist)) - (let ((org-add-colon-after-tag-completion (< 1 (length table)))) - (org-trim (completing-read - "Tags: " - #'org-tags-completion-function - nil nil (org-make-tag-string current-tags) - 'org-tags-history))))))) + (let ((org-add-colon-after-tag-completion (< 1 (length table))) + (crm-separator "[ \t]*:[ \t]*")) + (string-join (completing-read-multiple + "Tags: " + org-last-tags-completion-table + nil nil (org-make-tag-string current-tags) + 'org-tags-history) + ":")))))) (org-set-tags tags))))) ;; `save-excursion' may not replace the point at the right ;; position. @@ -12139,7 +12143,7 @@ This works in the agenda, and also in an Org buffer." (org-global-tags-completion-table)) (org-global-tags-completion-table)))) (completing-read - "Tag: " 'org-tags-completion-function nil nil nil + "Tag: " org-last-tags-completion-table nil nil nil 'org-tags-history)) (progn (message "[s]et or [r]emove? ") diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 95ffb0a80..de3c6f3c9 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -6969,8 +6969,8 @@ Paragraph" (should (equal "* H1 :foo:" (org-test-with-temp-text "* H1" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) @@ -6979,8 +6979,8 @@ Paragraph" (should (equal "* H1 :foo:\nContents" (org-test-with-temp-text "* H1\nContents" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) @@ -6988,30 +6988,20 @@ Paragraph" (should-not (equal "* H1 :foo:\nContents2" (org-test-with-temp-text "* H1\nContents2" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) (org-at-heading-p)))) - ;; Strip all forbidden characters from user-entered tags. - (should - (equal "* H1 :foo:" - (org-test-with-temp-text "* H1" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ": foo *:"))) - (let ((org-use-fast-tag-selection nil) - (org-tags-column 1)) - (org-set-tags-command))) - (buffer-string)))) ;; When a region is active and ;; `org-loop-over-headlines-in-active-region' is non-nil, insert the ;; same value in all headlines in region. (should (equal "* H1 :foo:\nContents\n* H2 :foo:" (org-test-with-temp-text "* H1\nContents\n* H2" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-loop-over-headlines-in-active-region t) (org-tags-column 1)) @@ -7023,8 +7013,8 @@ Paragraph" (should (equal "* H1\nContents\n* H2 :foo:" (org-test-with-temp-text "* H1\nContents\n* H2" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-loop-over-headlines-in-active-region nil) (org-tags-column 1)) @@ -7043,8 +7033,8 @@ Paragraph" (should (equal ":foo:" (org-test-with-temp-text "* " - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) @@ -7053,8 +7043,8 @@ Paragraph" (should (equal "* H1 :foo:" (org-test-with-temp-text "* H1" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) @@ -7063,8 +7053,8 @@ Paragraph" (should (equal "* H1 :foo:" (org-test-with-temp-text "** H1" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) @@ -7073,8 +7063,8 @@ Paragraph" (should (equal " b :foo:" (org-test-with-temp-text "* a b" - (cl-letf (((symbol-function 'completing-read) - (lambda (&rest args) ":foo:"))) + (cl-letf (((symbol-function 'completing-read-multiple) + (lambda (&rest args) '("foo")))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) @@ -7083,9 +7073,9 @@ Paragraph" (should (equal "b :foo:" (org-test-with-temp-text "* a :foo:\n** b :foo:" - (cl-letf (((symbol-function 'completing-read) + (cl-letf (((symbol-function 'completing-read-multiple) (lambda (prompt coll &optional pred req initial &rest args) - initial))) + (list initial)))) (let ((org-use-fast-tag-selection nil) (org-tags-column 1)) (org-set-tags-command))) -- 2.32.0 --=-=-=--