branch: master commit ea79f0e487ef444f0d01b7498fcb25de6f5d0d3a Author: Oleh Krehel <ohwoeo...@gmail.com> Commit: Oleh Krehel <ohwoeo...@gmail.com>
New API function ivy-set-display-transformer * ivy.el (ivy--display-transformers-list): New defvar. (ivy-set-display-transformer): New defun. Keys are :caller, values are str->str lambda. (ivy-state): New field display-transformer-fn. (ivy-read): Set :display-transformer-fn. (ivy--format): Apply :display-transformer-fn to each displayed candidate, in the context of ivy-window. * counsel.el (ivy-set-display-transformer): Set for `counsel-M-x'. (counsel-M-x-transformer): Promote from `counsel--M-x-transformer'. Now takes a string instead of a cons cell. (counsel-M-x): No more messing with `ivy-format-function'. Re #399 --- counsel.el | 31 +++++++++++-------------------- ivy.el | 35 +++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/counsel.el b/counsel.el index e6a2bad..fc69a1e 100644 --- a/counsel.el +++ b/counsel.el @@ -445,19 +445,18 @@ Update the minibuffer with the amount of lines collected every 'counsel-M-x '(("d" counsel--find-symbol "definition"))) -(defun counsel--M-x-transformer (cand-pair) - "Add a binding to CAND-PAIR cdr if the car is bound in the current window. -CAND-PAIR is (command-name . extra-info)." - (let* ((command-name (car cand-pair)) - (extra-info (cdr cand-pair)) - (binding (substitute-command-keys (format "\\[%s]" command-name)))) +(ivy-set-display-transformer + 'counsel-M-x + 'counsel-M-x-transformer) + +(defun counsel-M-x-transformer (cmd) + "Return CMD appended with the corresponding binding in the current window." + (let ((binding (substitute-command-keys (format "\\[%s]" cmd)))) (setq binding (replace-regexp-in-string "C-x 6" "<f2>" binding)) (if (string-match "^M-x" binding) - cand-pair - (cons command-name - (if extra-info - (format " %s (%s)" extra-info (propertize binding 'face 'font-lock-keyword-face)) - (format " (%s)" (propertize binding 'face 'font-lock-keyword-face))))))) + cmd + (format "%s (%s)" + cmd (propertize binding 'face 'font-lock-keyword-face))))) (defvar smex-initialized-p) (defvar smex-ido-cache) @@ -488,14 +487,7 @@ Optional INITIAL-INPUT is the initial input in the minibuffer." (unless initial-input (setq initial-input (cdr (assoc this-command ivy-initial-inputs-alist)))) - (let* ((store ivy-format-function) - (ivy-format-function - (lambda (cand-pairs) - (funcall - store - (with-ivy-window - (mapcar #'counsel--M-x-transformer cand-pairs))))) - (cands obarray) + (let* ((cands obarray) (pred 'commandp) (sort t)) (when (require 'smex nil 'noerror) @@ -515,7 +507,6 @@ Optional INITIAL-INPUT is the initial input in the minibuffer." (when (featurep 'smex) (smex-rank (intern cmd))) (let ((prefix-arg current-prefix-arg) - (ivy-format-function store) (this-command (intern cmd))) (command-execute (intern cmd) 'record))) :sort sort diff --git a/ivy.el b/ivy.el index 5e59717..bff2454 100644 --- a/ivy.el +++ b/ivy.el @@ -168,6 +168,21 @@ Only \"./\" and \"../\" apply here. They appear in reverse order." (setq ivy--actions-list (plist-put ivy--actions-list cmd actions))) +(defvar ivy--display-transformers-list nil + "A list of str->str transformers per command.") + +(defun ivy-set-display-transformer (cmd transformer) + "Set CMD a displayed candidate TRANSFORMER. + +It's a lambda that takes a string one of the candidates in the +collection and returns a string for display, the same candidate +plus some extra information. + +This lambda is called only on the `ivy-height' candidates that +are about to be displayed, not on the whole collection." + (setq ivy--display-transformers-list + (plist-put ivy--display-transformers-list cmd transformer))) + (defvar ivy--sources-list nil "A list of extra sources per command.") @@ -269,6 +284,8 @@ Example: matcher ;; When this is non-nil, call it for each input change to get new candidates dynamic-collection + ;; A lambda that transforms candidates only for display + display-transformer-fn caller) (defvar ivy-last (make-ivy-state) @@ -1241,7 +1258,8 @@ customizations apply to the current completion session." (list (car source) (funcall (car source))) ivy--extra-candidates)))))) (setq ivy--extra-candidates '((original-source))))) - (let ((recursive-ivy-last (and (active-minibuffer-window) ivy-last))) + (let ((recursive-ivy-last (and (active-minibuffer-window) ivy-last)) + (transformer-fn (plist-get ivy--display-transformers-list caller))) (setq ivy-last (make-ivy-state :prompt prompt @@ -1261,6 +1279,7 @@ customizations apply to the current completion session." :re-builder re-builder :matcher matcher :dynamic-collection dynamic-collection + :display-transformer-fn transformer-fn :caller caller)) (ivy--reset-state ivy-last) (prog1 @@ -2380,7 +2399,8 @@ CANDS is a list of strings." (end (min (+ start (1- ivy-height)) ivy--length)) (start (max 0 (min start (- end (1- ivy-height))))) (cands (cl-subseq cands start end)) - (index (- ivy--index start))) + (index (- ivy--index start)) + transformer-fn) (cond (ivy--directory (setq cands (mapcar (lambda (x) (if (string-match-p "/\\'" x) @@ -2397,11 +2417,14 @@ CANDS is a list of strings." x))) cands)))) (setq ivy--current (copy-sequence (nth index cands))) + (when (setq transformer-fn (ivy-state-display-transformer-fn ivy-last)) + (with-ivy-window + (setq cands (mapcar transformer-fn cands)))) (let* ((ivy--index index) - (cand-pairs (mapcar - (lambda (cand) - (cons (ivy--format-minibuffer-line cand) nil)) cands)) - (res (concat "\n" (funcall ivy-format-function cand-pairs)))) + (cands (mapcar + (lambda (cand) + (cons (ivy--format-minibuffer-line cand) nil)) cands)) + (res (concat "\n" (funcall ivy-format-function cands)))) (put-text-property 0 (length res) 'read-only nil res) res))))