-
-
Save alphapapa/a3433c54a631b693ba9d to your computer and use it in GitHub Desktop.
;;;;;; Fix Helm org tag completion | |
;; From Anders Johansson <https://groups.google.com/d/msg/emacs-helm/tA6cn6TUdRY/G1S3TIdzBwAJ> | |
;; This works great! He posted it on 3 Mar 2016, on a thread that was | |
;; started in Oct 2013. He also posted this message on 2 Apr 2014, | |
;; maybe an earlier attempt at a solution: | |
;; <http://article.gmane.org/gmane.emacs.orgmode/84495> I've just | |
;; tidied it up a bit and adjusted the prompt. | |
(add-to-list 'helm-completing-read-handlers-alist '(org-capture . aj/org-completing-read-tags)) | |
(add-to-list 'helm-completing-read-handlers-alist '(org-set-tags . aj/org-completing-read-tags)) | |
(defun aj/org-completing-read-tags (prompt coll pred req initial hist def inh) | |
(if (not (string= "Tags: " prompt)) | |
;; Not a tags prompt. Use normal completion by calling | |
;; `org-icompleting-read' again without this function in | |
;; `helm-completing-read-handlers-alist' | |
(let ((helm-completing-read-handlers-alist (rassq-delete-all | |
'aj/org-completing-read-tags | |
helm-completing-read-handlers-alist))) | |
(org-icompleting-read prompt coll pred req initial hist def inh)) | |
;; Tags prompt | |
(let* ((initial (and (stringp initial) | |
(not (string= initial "")) | |
initial)) | |
(curr (when initial | |
(org-split-string initial ":"))) | |
(table (org-uniquify | |
(mapcar 'car org-last-tags-completion-table))) | |
(table (if curr | |
;; Remove current tags from list | |
(cl-delete-if (lambda (x) | |
(member x curr)) | |
table) | |
table)) | |
(prompt (if initial | |
(concat "Tags " initial) | |
prompt))) | |
(concat initial (mapconcat 'identity | |
(nreverse (aj/helm-completing-read-multiple | |
prompt table pred nil nil hist def | |
t "Org tags" "*Helm org tags*" ":")) | |
":"))))) | |
(defun aj/helm-completing-read-multiple (prompt choices | |
&optional predicate require-match initial-input hist def | |
inherit-input-method name buffer sentinel) | |
"Read multiple items with `helm-completing-read-default-1'. Reading stops | |
when the user enters SENTINEL. By default, SENTINEL is | |
\"*done*\". SENTINEL is disambiguated with clashing completions | |
by appending _ to SENTINEL until it becomes unique. So if there | |
are multiple values that look like SENTINEL, the one with the | |
most _ at the end is the actual sentinel value. See | |
documentation for `ido-completing-read' for details on the | |
other parameters." | |
(let ((sentinel (or sentinel "*done*")) | |
this-choice res done-reading) | |
;; Uniquify the SENTINEL value | |
(while (cl-find sentinel choices) | |
(setq sentinel (concat sentinel "_"))) | |
(setq choices (cons sentinel choices)) | |
;; Read choices | |
(while (not done-reading) | |
(setq this-choice (helm-completing-read-default-1 prompt choices | |
predicate require-match initial-input hist def | |
inherit-input-method name buffer nil t)) | |
(if (equal this-choice sentinel) | |
(setq done-reading t) | |
(setq res (cons this-choice res)) | |
(setq prompt (concat prompt this-choice ":")))) | |
res)) |
I wonder why org-set-tags
doesn't use completing-read-multiple
itself.
(defun org-set-tags-command-multiple (orig &optional arg)
(cl-letf (((symbol-function #'completing-read)
(lambda (prompt collection &optional predicate require-match initial-input
hist def inherit-input-method)
(when initial-input
(setq initial-input
(replace-regexp-in-string
":" ","
(replace-regexp-in-string
"\\`:" "" initial-input))))
(let ((res (completing-read-multiple
prompt collection predicate require-match initial-input
hist def inherit-input-method)))
(mapconcat #'identity res ":")))))
(let ((current-prefix-arg arg))
(call-interactively orig))))
(advice-add #'org-set-tags-command :around #'org-set-tags-command-multiple)
Thanks, works great @clemera
@robertsck Oops, I didn't notice your comment for a few years. :) You would need to write a command to do that, which could use these tag completion functions to do so.
@clemera Thanks. If you haven't already, would you propose that on the Org mailing list?
@alphapapa I have, it stopped here. I only use the simplest org features myself and only noticed this problem via a bug report so I wasn't motivated enough to proceed.
@clemera Thanks. For my own use, I'm satisfied with the code in this gist, but maybe I'll look at the CRM version again sometime.
As this is currently one of the top search results for 'org-mode helm select tag multiple', I'd like to point to
The mentioned fix works for me on GNU Emacs 27.0.50 and Org 9.3.6:
(require 'helm-org)
(add-to-list 'helm-completing-read-handlers-alist '(org-set-tags-command . helm-org-completing-read-tags))
Thanks for posting this - this works great! Quick question - is there an easy way to make this work on FILETAGS: property entries as well as headings? I noticed when I try to use it there I get a message that I'm not on a heading. I'm a beginner at elisp and couldn't find an obvious way to expand the function to handle that use case.