Giter VIP home page Giter VIP logo

Comments (22)

minad avatar minad commented on August 29, 2024 1

What do you think about this version which always jumps to the candidate below the headline, also if vertico-previous-group is invoked? I like this a bit better since then I can jump back to the old position.

(defun vertico--goto-group (next)
  "Move to next group if NEXT is non-nil, otherwise move to previous group."
  (let* ((end (minibuffer-prompt-end))
         (metadata (completion-metadata (buffer-substring end (max end (point)))
                                        minibuffer-completion-table
                                        minibuffer-completion-predicate))
         (group-fun (or (completion-metadata-get metadata 'group-function) #'ignore))
         (title-fun (lambda (idx) (funcall group-fun (nth idx vertico--candidates) nil)))
         (orig-index vertico--index))
    (while (let ((last-index vertico--index))
             (if next (vertico-next) (vertico-previous))
             (if (or (= vertico--index orig-index) (= vertico--index last-index))
                 (and (vertico--goto orig-index) nil)
               (and (> vertico--index 0)
                   (equal (funcall title-fun (1- vertico--index))
                          (funcall title-fun vertico--index))))))))

from vertico.

minad avatar minad commented on August 29, 2024 1

@inigoserna Thanks for taking another look. I forgot to credit you in the commit - I force pushed the updated commit.

from vertico.

minad avatar minad commented on August 29, 2024

Instead of consult-multi, you should access the group-function of the completion metadata of the minibuffer-completion-table.

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

Instead of consult-multi, you should access the group-function of the completion metadata of the minibuffer-completion-table.

I see I could do it with (completion-metadata-get metadata 'group-function), but where/how I can get metadata from the candidate?

[...]

Ok, I've got it. Sorry for the noise.

(let* ((metadata (completion-metadata (minibuffer-contents)
                                     minibuffer-completion-table
                                     minibuffer-completion-predicate))
       (groupfun (completion-metadata-get metadata 'group-function)))
  (funcall groupfun (vertico--candidate) nil))

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

New version:

(defun completion--metadata-group-name (cand)
  (let* ((metadata (completion-metadata (minibuffer-contents)
                                        minibuffer-completion-table
                                        minibuffer-completion-predicate))
         (groupfun (completion-metadata-get metadata 'group-function)))
    (when groupfun
      (funcall groupfun cand nil))))

(defun vertico-next-group ()
  (interactive)
  (let ((group (completion--metadata-group-name (vertico--candidate)))
        (loop t))
    (while (and group loop)
      (if (= vertico--index (1- vertico--total))
          (progn
            (vertico-first)
            (setq loop nil))
        (vertico-next)
        (unless (string= group (completion--metadata-group-name (vertico--candidate)))
          (setq loop nil))))))

(defun vertico-previous-group ()
  (interactive)
  (let ((group (completion--metadata-group-name (vertico--candidate)))
        (loop t))
    (while (and group loop)
      (if (zerop vertico--index)
          (progn
            (vertico-last)
            (setq loop nil))
        (vertico-previous)
        (unless (string= group (completion--metadata-group-name (vertico--candidate)))
          (setq loop nil))))))

(define-key vertico-map '[C-left]  'vertico-previous-group)
(define-key vertico-map '[C-right] 'vertico-next-group)

from vertico.

astoff avatar astoff commented on August 29, 2024

Maybe remapping forward/backward paragraph or forward/backward page would be better keybindings.

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

Maybe remapping forward/backward paragraph or forward/backward page would be better keybindings.

Something like

(define-key vertico-map [remap backward-paragraph] 'vertico-previous-group)
(define-key vertico-map [remap forward-paragraph]  'vertico-next-group)

?

Uhmmm... yes, it looks better.

from vertico.

minad avatar minad commented on August 29, 2024

Paragraph sounds good 👍

from vertico.

minad avatar minad commented on August 29, 2024

@inigoserna Can you write the code above more compactly? There is too much code duplication above. Probably there should be a single vertico--goto-group function which takes a flag and is used by vertico-next-group/previous-group. Furthermore using vertico-first/last/next/previous does not seem ideal. I prefer an index computation and then a call to vertico--goto.

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

I thought they were tiny functions so some duplication was ok.
Anyway, here you have a new version.

(defun completion--metadata-group-name (cand)
  (let* ((metadata (completion-metadata (minibuffer-contents)
                                        minibuffer-completion-table
                                        minibuffer-completion-predicate))
         (groupfun (completion-metadata-get metadata 'group-function)))
    (when groupfun
      (funcall groupfun cand nil))))

(defun vertico-next-group (&optional backwards)
  "Move to next group.  If BACKWARDS is non nil go to previous group instead."
  (interactive)
  (let ((op (if backwards '1- '1+))
        (group (completion--metadata-group-name (vertico--candidate)))
        (loop t))
    (while (and group loop)
      (cond
       ((and (not backwards) (= vertico--index (1- vertico--total)))
        (vertico-first)
        (setq loop nil))
       ((and backwards (zerop vertico--index))
        (vertico-last)
        (setq loop nil))
       (t
        (vertico--goto (funcall op vertico--index))
        (unless (string= group (completion--metadata-group-name (vertico--candidate)))
          (setq loop nil)))))))

(defun vertico-previous-group ()
  "Move to previous group."
  (interactive)
  (vertico-next-group t))

(define-key selectrum-minibuffer-map [remap backward-paragraph] 'selectrum-previous-group)
(define-key selectrum-minibuffer-map [remap forward-paragraph]  'selectrum-next-group)

I'm not completely fond of the loop, but I can't think of a better and smaller way.
What do you think?

from vertico.

minad avatar minad commented on August 29, 2024

It is probably possible to write this more compactly. I will take a look soon. Furthermore vertico-cycle should be respected.

from vertico.

minad avatar minad commented on August 29, 2024

This is my current version. I am not entirely happy with it.

(defun vertico--goto-group (next)
  "Move to group given NEXT function."
  (let* ((pt (max 0 (- (point) (minibuffer-prompt-end))))
         (before (buffer-substring (minibuffer-prompt-end)
                                   (+ (minibuffer-prompt-end) pt)))
         (metadata (completion-metadata before
                                        minibuffer-completion-table
                                        minibuffer-completion-predicate))
         (group-fun (completion-metadata-get metadata 'group-function))
         (title-fun (lambda ()
                      (cond
                       ((< vertico--index 0) 'vertico--prompt)
                       (group-fun (funcall group-fun (nth vertico--index vertico--candidates) nil)))))
         (title (funcall title-fun))
         (old-index vertico--index))
    (while (and old-index (equal title (funcall title-fun)))
      (let ((index vertico--index))
        (funcall next)
        (when (or (= vertico--index old-index) (= index vertico--index))
          (vertico--goto old-index)
          (setq old-index nil))))))

(defun vertico-next-group ()
  "Move to next group."
  (interactive)
  (vertico--goto-group #'vertico-next))

(defun vertico-previous-group ()
  "Move to previous group."
  (interactive)
  (vertico--goto-group #'vertico-previous))

(define-key vertico-map [remap backward-paragraph] 'vertico-previous-group)
(define-key vertico-map [remap forward-paragraph]  'vertico-next-group)

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

This is my current version. I am not entirely happy with it.

Sorry, IMHO it looks more complex to understand and uglier than my last version.

Btw, why the use of before to get metadata?
I see that, in contrast to selectrum (where I took it from) which uses minibuffer-contents, you use only a portion of minibuffer contents in vertico... Is there any advantage in doing so?

from vertico.

minad avatar minad commented on August 29, 2024

Sorry, IMHO it looks more complex to understand and uglier than my last version.

Yes, but your version was not correct from what I've seen regarding the cycling (both vertico-cycle=nil/t must be supported). My version also has the ability to jump to the prompt. The prompt is treated as an extra paragraph. If you add this we can compare the versions! If you manage to beat my version, please do so!

Btw, why the use of before to get metadata?

This is the correct way to retrieve the metadata by definition of Emacs. The metadata can vary depending on the position in the input, which actually makes sense if you complete multiple fields separated by some characters. The completing read APIs are pretty baroque 🤷

But overall I am not happy with this yet. I have to think about it a bit more.

EDIT: See the branch https://github.com/minad/vertico/tree/group-jump. If you are interested you can give it a try.

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

New version:

  • respects vertico-cycle
  • jump to/from prompt
  • retrieve metadata using proper code. I keep the external defun for readibility reasons, but it could be inside the let-clause in main function if you prefer.
(defun completion--metadata-group-func ()
  (let* ((pt (max 0 (- (point) (minibuffer-prompt-end))))
         (before (buffer-substring (minibuffer-prompt-end)
                                   (+ (minibuffer-prompt-end) pt)))
         (metadata (completion-metadata before
                                        minibuffer-completion-table
                                        minibuffer-completion-predicate)))
    (completion-metadata-get metadata 'group-function)))

(defun vertico-next-group (&optional backwards)
  "Move to next group.  If BACKWARDS is non nil go to previous group instead."
  (interactive)
  (let* ((op (if backwards '1- '1+))
         (group-func (completion--metadata-group-func))
         (group (unless (or (= vertico--index -1) (not group-func))
                  (funcall group-func (vertico--candidate) nil)))
         (loop t))
    (if group
        (while loop
          (if (or (and (not backwards) (= vertico--index (1- vertico--total)))
                  (and backwards (zerop vertico--index)))
              (progn
                (when vertico-cycle
                  (vertico--goto -1))
                (setq loop nil))
            (vertico--goto (funcall op vertico--index))
            (unless (string= group (funcall group-func (vertico--candidate) nil))
              (setq loop nil))))
      (when group-func
        (vertico--goto (if backwards (1- vertico--total) 0))))))

(defun vertico-previous-group ()
  "Move to previous group."
  (interactive)
  (vertico-next-group t))

(define-key vertico-map [remap backward-paragraph] 'vertico-previous-group)
(define-key vertico-map [remap forward-paragraph]  'vertico-next-group)

from vertico.

minad avatar minad commented on August 29, 2024

@inigoserna With your recent version I cannot select the prompt when invoking 'vertico-previous-group from the first group. Furthermore if you are in the last group, and invoke 'vertico-next-group, the last element will be selected, which is not consistent. Also the usage of vertico--candidate is incorrect. These are all subtle details.

from vertico.

minad avatar minad commented on August 29, 2024

Current version:

(defun vertico--goto-group (next)
  "Move to next group if NEXT is non-nil, otherwise move to previous group."
  (let* ((end (minibuffer-prompt-end))
         (metadata (completion-metadata (buffer-substring end (max end (point)))
                                        minibuffer-completion-table
                                        minibuffer-completion-predicate))
         (group-fun (or (completion-metadata-get metadata 'group-function) #'ignore))
         (title-fun (lambda ()
                      (if (< vertico--index 0)
                          'vertico--prompt-selected
                        (funcall group-fun (nth vertico--index vertico--candidates) nil))))
         (orig-title (funcall title-fun))
         (orig-index vertico--index))
    (while (let ((last-index vertico--index))
             (if next (vertico-next) (vertico-previous))
             (if (or (= vertico--index orig-index) (= last-index vertico--index))
                 (and (vertico--goto orig-index) nil)
               (equal orig-title (funcall title-fun)))))))

(defun vertico-next-group ()
  "Move to next group."
  (interactive)
  (vertico--goto-group 'next))

(defun vertico-previous-group ()
  "Move to previous group."
  (interactive)
  (vertico--goto-group nil))

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

@inigoserna With your recent version I cannot select the prompt when invoking 'vertico-previous-group from the first group.

Can't understand, it works correctly here.

Furthermore if you are in the last group, and invoke 'vertico-next-group, the last element will be selected, which is not consistent.

Yeah, I haven't cached this because my last group only contained one entry in my tests and have vertico-cycle enabled.

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

Current version:

I like this version the more.
That let inside the while looks a bit hackish for me, but anyway, this last version is more compact. So it's ok for me.

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

What do you think about this version which always jumps to the candidate below the headline, also if vertico-previous-group is invoked? I like this a bit better since then I can jump back to the old position.

It's perfect!

from vertico.

inigoserna avatar inigoserna commented on August 29, 2024

@inigoserna Thanks for taking another look. I forgot to credit you in the commit - I force pushed the updated commit.

Oh, it was not necessary!
But thanks a lot, I appreciate it.

from vertico.

minad avatar minad commented on August 29, 2024

@inigoserna I am sorry, I had to force push the old commit again. Stefan Monnier just activated the autosync for Vertico to ELPA today and it seems that ELPA already synced in the meantime. This repository should not diverge from the ELPA branch. When I force pushed, the auto sync had not yet happened :(

Next time I will get it right I hope.

See https://git.savannah.gnu.org/cgit/emacs/elpa.git/commit/?h=externals/vertico&id=8232ad29cf99d1bb93fcad9658e89636c3d2e0a7

from vertico.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.