Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi-level menu with ivy? #1640

Open
et2010 opened this issue Jun 24, 2018 · 5 comments
Open

multi-level menu with ivy? #1640

et2010 opened this issue Jun 24, 2018 · 5 comments

Comments

@et2010
Copy link

et2010 commented Jun 24, 2018

Hi,

How to implement a multi-level menu with ivy? I tried on a simple two-level case:

test

This is accomplished by manipulating ivy-on-del-error-function and ivy-quit-and-run which is very cumbersome. Is there a canonical way to do this kind of job?

@abo-abo
Copy link
Owner

abo-abo commented Jun 25, 2018

Ivy is single-level. You can add multiple levels by calling ivy-read in the :action of the first ivy-read. Could you please show your code here, maybe it will be more clear what you want to do?

@et2010
Copy link
Author

et2010 commented Jun 25, 2018

As I showed in the gif. the first level menu contains some categories and the second level contains some synonyms of the chosen category to replace word at point. When I choose the wrong category and want to go back, I hit escape or backspace to go back to the previous menu. Such actions can be repeated infinitely. I found it hard to implement such feature with ivy API especially when the list structure is complex.

(defun stardict-thesaurus--do-replace (replacement)
 (if (use-region-p)
     (delete-region (region-beginning) (region-end))
   (let ((bounds (bounds-of-thing-at-point 'word)))
     (delete-region (car bounds) (cdr bounds))))
 (insert replacement))

(defun stardict-thesaurus--pick-synonym (synonyms)
 (let ((key (stardict-thesaurus--pick-lvl-1 synonyms)))
   (stardict-thesaurus--pick-lvl-2 key synonyms)))

(defun stardict-thesaurus--pick-lvl-1 (synonyms)
 (let ((keys (mapcar #'car synonyms)))
   (completing-read "Choose a key: " keys)))

(defun stardict-thesaurus--pick-lvl-2 (key synonyms)
 (let* ((repick (lambda ()
                  (interactive)
                  (ivy-quit-and-run
                    (stardict-thesaurus--pick-synonym synonyms))))
        (ivy-on-del-error-function repick)
        (kmap (make-sparse-keymap)))
   (define-key kmap (kbd "<escape>") repick)
   (ivy-read "Choose a synonym: "
             (assoc-default key synonyms)
             :require-match t
             :keymap kmap
             :action #'stardict-thesaurus--do-replace
             :caller 'stardict-thesaurus--pick-lvl-2)))

Here I play with ivy-quit-and-run and ivy-on-del-error-function to reach the goal. Any suggestions?

@abo-abo
Copy link
Owner

abo-abo commented Jun 26, 2018

I found it hard to implement such feature with ivy API especially when the list structure is complex.
Here I play with ivy-quit-and-run and ivy-on-del-error-function to reach the goal.

I think you went with a good approach. Re-using ivy-on-del-error-function is fine, you could also just stick with <escape> in your :keymap.

Your code looks good enough for me, you are using the API correctly to implement something more advanced than what the API was originally intended to do.

Any suggestions?

  • Extract repick into its own named command
  • Extract kmap into its own named variable
  • Don't use ivy-on-del-error-function, :keymap is enough

@et2010
Copy link
Author

et2010 commented Jun 27, 2018

Thanks for your suggestions! Any plan to extend the API to support such feature? Maybe a keyword argument such as :anchor or :parent?.

@abo-abo
Copy link
Owner

abo-abo commented Jun 27, 2018

Any plan to extend the API to support such feature?

There's no plan to do it. There's no need to complicate the API when the existing one can be used to create the same functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants