Skip to content

add selectrum module #4519

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

Closed
wants to merge 4 commits into from
Closed

Conversation

jethrokuan
Copy link
Contributor

Been meaning to try selectrum, decided to package it as a doom module. Still WIP.

@hlissner hlissner added is:feature Adds or requests new features, or extends existing ones status:needs-work The issue/PR is accepted, but not yet in a state to be applied. re:modules Pertains to adding, removing and management of modules status:backlog labels Jan 15, 2021
Copy link
Member

@hlissner hlissner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need selectrum-powered-alternatives for +ivy/project-search, +ivy/project-search-from-cwd, and a project-wide search+replace workflow to replace SPC s p + C-c C-e.

Reaching parity with our ivy module is important, so it's unlikely that this PR (or any selectrum PR) will be merged soon, but it will be a helpful reference when I get around to it.

Comment on lines 4 to 12
(package! selectrum)
(when (featurep! +prescient)
(package! selectrum-prescient))

(package! consult)
(package! consult-flycheck)
(package! embark)
(package! embark-consult)
(package! marginalia)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pin these packages.

@loafofpiecrust
Copy link

loafofpiecrust commented Jan 16, 2021

consult now has consult-ripgrep and consult-find which bring us much closer to parity with the ivy module. There's just a few missing I think, like jumping to symbol in the project. I was actually planning on making a PR this weekend but here's my code so far. I've bound more consult commands and got embark working with which-key more effectively. I've been using this for two weeks now and it's great.

@jethrokuan
Copy link
Contributor Author

I've added a function for selectrum project search in this PR.

@loafofpiecrust
Copy link

What does your custom function for project search do that consult-ripgrep doesn't? I think we should focus on making that function great, if they're missing something not doom specific to make a PR to consult.

@jethrokuan
Copy link
Contributor Author

What does your custom function for project search do that consult-ripgrep doesn't?

It's doom-specific stuff:

  • whether to search in hidden files
  • which directory to search in
  • Making the prompt more meaningful

These are mainly so that the signature of the functions align with that of ivy and helm, I suppose.

@loafofpiecrust
Copy link

  • You can change consult-ripgrep-command to set whether to search hidden files.
  • you can pass the directory as first argument into consult-ripgrep or consult-find
  • I agree that "Ripgrep in project X" could maybe use improvement, but that doesn't feel worth a redefinition here.

It seems like (consult--grep "Search" '("rg" "--whatever") custom-directory nil) gives you most of this, no?

@jethrokuan
Copy link
Contributor Author

It seems like (consult--grep "Search" '("rg" "--whatever") custom-directory nil) gives you most of this, no?

That's exactly how it's implemented now.

@loafofpiecrust
Copy link

Totally my bad, I looked first on my phone and clearly didn't read the code closely enough.

Copy link
Contributor

@Townk Townk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have Selectrum & friends working on my personal config, so I though that I could point some things that stood out for me on this PR.

[remap load-theme] #'consult-theme
[remap recentf-open-files] #'consult-recent-file)
:config
(setq consult-project-root-function #'projectile-project-root))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use doom-project-root here?

"\\\\\\\\|")
((concat "\\\\" substr))))
(rxt-quote-pcre (doom-thing-at-point-or-region))))))
(ripgrep-command `("rg" ,@args "." "-e")))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this correctly, you converted args into a string to concatenate more arguments to it inside the let binding, than here, you expand it to a list again in order to store it on ripgrep-command variable.

Wouldn't be more efficient to only do list operations here?

I was thinking on something like this:

(let* ((this-command 'consult-ripgrep)
         (project-root (or (doom-project-root) default-directory))
         (directory (or in project-root))
         (prompt (or prompt
                     (format "%s [%s]: "
                             (mapconcat #'identity command " ")
                             (cond ((equal directory default-directory) "./")
                                   ((equal directory project-root) (projectile-project-name))
                                   ((file-relative-name directory project-root))))))
         (query (or query
                    (when (doom-region-active-p)
                      (replace-regexp-in-string
                       "[! |]" (lambda (substr)
                                 (cond ((string= substr " ") "  ")
                                       ((string= substr "|") "\\\\\\\\|")
                                       ((concat "\\\\" substr))))
                       (rxt-quote-pcre (doom-thing-at-point-or-region))))))
         (ripgrep-command (seq-remove 'null
                                      (append (butlast consult-ripgrep-command)
                                              (list
                                               (when all-files "-uu")
                                               (unless recursive " --maxdepth 1")
                                               "--hidden"
                                               "-g!.git")
                                              args
                                              '("-e")))))
    ...
    )

((concat "\\\\" substr))))
(rxt-quote-pcre (doom-thing-at-point-or-region))))))
(ripgrep-command `("rg" ,@args "." "-e")))
(consult--grep prompt ripgrep-command directory query)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ivy counterpart of this function, sets the variable deactivate-mark before running the grep command. Shouldn't you do the same?

@@ -0,0 +1,64 @@
;;; completion/selectrum/config.el -*- lexical-binding: t; -*-

(use-package! selectrum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you manually set the refine, and highlight candidates functions if +orderless is enabled? Also, if that is the case, and the user has +prescient enabled as well, you should set the preprocesscandidates function as well:

  (setq selectrum-refine-candidates-function #'orderless-filter 
        selectrum-highlight-candidates-function #'orderless-highlight-matches 
        selectrum-preprocess-candidates-function #'selectrum-prescient--preprocess)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to mention that if you want to use orderless and prescient, you should tell prescient to remember candidate selection:

  (add-hook 'selectrum-candidate-selected-hook #'selectrum-prescient--remember)
  (add-hook 'selectrum-candidate-inserted-hook #'selectrum-prescient--remember)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting separate refine and highlight functions is not necessary since Selectrum picks up the completion style, see radian-software/selectrum#330. However you should still set them in order to improve performance, since then Selectrum is applying highlighting only to the items which match the filter criterion! Note that the combination of Orderless and Prescient is a bit fragile since both packages compete about the filtering. I haven't checked what you are doing here, but selectrum-prescient-mode should be activated first, then orderless should overwrite the filter/highlighting functions. Furthermore orderless should be set as completion style.

(when (featurep! +prescient)
(use-package! selectrum-prescient
:after selectrum
:hook ((selectrum-mode . selectrum-prescient-mode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should only do this if use does not have +orderless enabled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment above, about the order of selectrum-prescient-mode and orderless.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't enable selectrum-prescient-mode, you can use prescient sorting plus storing with orderless filter and highlights with no problem. If the user don't want this combination, then you don't need to worry as I comment, but overall, my suggestion is to get this decision path:

(cond ((and (featurep! +prescient) (featurep! +orderless)) (set-functions-manually))
       ((featurep! +prescient) (enable-selectrum-prescient-mode))
       ((featurep! +orderless) (only-enable-orderless)))

So, the use-package! for selectrum would be something like this:

(use-package! selectrum
  :init
  (when (and (featurep! +prescient) (featurep! +orderless))
    (setq selectrum-refine-candidates-function #'orderless-filter 
          selectrum-highlight-candidates-function #'orderless-highlight-matches 
          selectrum-preprocess-candidates-function #'selectrum-prescient--preprocess)

    (add-hook 'selectrum-candidate-selected-hook #'selectrum-prescient--remember)
    (add-hook 'selectrum-candidate-inserted-hook #'selectrum-prescient--remember))
  :config
  ;; other configurations...
  )

And selectrum-prescient would be:

(use-package! selectrum-prescient
    :if (featurep! +prescient) 
    :after selectrum
    : init
    (when (not (featurep! +orderless))
      (add-hook 'selectrum-mode-hook 'selectrum-prescient-mode))
    :config
    ;; other configurations
    )

@@ -47,6 +48,7 @@ If prefix ARG is set, include ignored/hidden files."
(call-interactively
(cond ((featurep! :completion ivy) #'+ivy/project-search)
((featurep! :completion helm) #'+helm/project-search)
((featurep! :completion selectrum) #'+selectrum/project-search)
(#'projectile-ripgrep)))))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to change the +default/yank-pop as well:

;;;###autoload
(defun +default/yank-pop (&rest _)
  "Interactively select what text to insert from the kill ring."
  (interactive "P")
  (call-interactively
   (cond ((fboundp 'counsel-yank-pop)    #'counsel-yank-pop)
         ((fboundp 'consult-yank-pop)    #'consult-yank-pop)
         ((fboundp 'helm-show-kill-ring) #'helm-show-kill-ring)
         ((error "No kill-ring search backend available. Enable ivy or helm!")))))

(define-key!
"C-S-a" #'embark-act)
;; TODO need to figure out what keybindings to put here
(define-key! selectrum-minibuffer-map
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you adding these to selectrum-minibuffer-map? Embark is supposed to work without selectrum, so you can add these directly to the minibuffer-local-map, don't you?

"C-c C-c" #'embark-act-noexit))

(use-package! marginalia
:after selectrum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure you need to wait for selectrum to load here. I think just the hook is enough.

:init
(define-key!
"C-S-a" #'embark-act)
;; TODO need to figure out what keybindings to put here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embark wiki has excellent suggestions. I particularly like the "Very large files and sudo edit".

:hook ((selectrum-mode . selectrum-prescient-mode)
(selectrum-mode . prescient-persist-mode))))

(use-package! orderless
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we lazy initialize orderless as well? If we can't, a comment explaining why would be helpful.

Copy link
Contributor

@minad minad Jan 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be installed as completion-style, I recommed against loading it lazily. But I am not familiar with the doom infrastructure, maybe lazy loading after the first input would work? It could also be that it would not work since then the completion style is made available a little bit too late.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for context, this is the use-package! orderless section on my config:

(use-package! orderless
  :defer t
  :init
  (setq orderless-component-separator "[ &]"
        orderless-matching-styles '(orderless-prefixes
                                    orderless-initialism
                                    orderless-regexp))
  :custom
  (completion-styles '(orderless))
  :config
  (custom-set-faces!
    '('orderless-match-face-0 :background "#435300" :foreground "#b5bd68")
    '('orderless-match-face-1 :background "#4C2E60" :foreground "#b294bb")
    '('orderless-match-face-2 :background "#644E00" :foreground "#f0c674")
    '('orderless-match-face-3 :background "#1B2E47" :foreground "#81a2be"))

  (add-hook 'minibuffer-exit-hook #'orderless-remove-transient-configuration))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked, the orderless completion style and its corresponding completion style functions are indeed marked as autoload. Lazy loading works indeed 👍

@minad
Copy link
Contributor

minad commented Jan 24, 2021

@loafofpiecrust @jethrokuan I am looking forward to seeing the Selectrum/Consult/Embark suite of packages in Doom. Please let me know if you need anything on the side of Consult. I saw that you are offering a modified project search command here. Maybe some things should be exposed better on the Consult side to reduce the amount of code needed here? You are setting the consult-project-root-function; you should already get a project search which works out of the box. But maybe not as full featured as what you are implementing here?

@jethrokuan
Copy link
Contributor Author

fwiw my usage of the selectrum/consult/embark suite has been very minimal, and I'm likely to have gotten many things wrong here. Perhaps someone with more experience can provide a better PR.

@bdarcus
Copy link
Contributor

bdarcus commented Jan 24, 2021

FWIW, looks like a selectrum port of ivy/helm-bibtex should be coming soon.

tmalsburg/helm-bibtex#353

cc #2888

Comment on lines +21 to +25
(concat (if all-files "-uu")
(unless recursive "--maxdepth 1")
"--null --line-buffered --color=always --max-columns=500 --no-heading --line-number"
" --hidden -g!.git "
(mapconcat #'shell-quote-argument args " ")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a space in front of --hidden but not --maxdepth 1 or --null ?

@Townk
Copy link
Contributor

Townk commented Jan 30, 2021

Hy @jethrokuan, would you be able to commit a new patch with the requested changes, or do you prefer one of us to take over?

@jcf
Copy link
Contributor

jcf commented Jan 31, 2021

I've been using Selectrum, Orderless, Consult, and Embark for the last couple of weeks, and I'm loving it. I've found a few useful snippets in this pull request and in various repos that I thought I'd share: https://gist.github.com/jcf/ac6f57a5b0c49263619e4d2ee4a0c00a

I see Jethro mentioned someone with more experience might want to take the reigns on this pull request. While I'm not sure that's me I'd be happy to help test out any changes, and will keep sharing any useful code I add to my own configuration.

Update: in response so Henrik's comment:

and a project-wide search+replace workflow to replace SPC s p + C-c C-e.

This is supported via wgrep with the configuration I shared. Search the project, C-c C-o to export results via Embark, wgrep-change-to-wgrep-mode, and edit away.

Update: I've made a few changes to my private config, and I've updated the private gist. There are a few bindings I'm using too.

      (:when (featurep! :private selectrum)
       "*" #'+jcf/search-project-for-symbol-at-point
       :desc "Consult find" "SPC" #'consult-find
       :desc "Buffers"      ","   #'consult-buffer
       :desc "Modal M-x"    ":"   #'consult-mode-command
       :desc "Re-selectrum" "'"   #'selectrum-repeat)

@jethrokuan
Copy link
Contributor Author

Hy @jethrokuan, would you be able to commit a new patch with the requested changes, or do you prefer one of us to take over?

Do make another pull request, I started this because I was surprised to see that none has been made yet. My time is tied working on org-roam.

@edmundmiller
Copy link
Member

@Townk I think it sounds like you might be the best to take over, and then people and PR to your branch. Do you have a link to your personal config btw?

@Townk
Copy link
Contributor

Townk commented Jan 31, 2021

@Townk I think it sounds like you might be the best to take over, and then people and PR to your branch. Do you have a link to your personal config btw?

I'm working on a refactor for my config after my 1000th bankruptcy :P, but you can follow along here: https://github.com/Townk/doom-emacs-private

I'm trying a literate config this time. Let's see if I can finish.

Regarding the PR, let me work a bit on it today and see where I can get with it. Most likely I will need two PRs in order to get Selectrum fully working, and I won't push anything until later tonight or tomorrow morning (my 2 and 4 yo kids usually get in the way of such things). The parts that mater for this in my config are at "Personal preferences -> Completion framework" and "Personal preferences -> Workspaces".

(use-package! orderless
:when (featurep! +orderless)
:config
(setq completion-styles '(orderless)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here one may consider '(substring orderless) which ensures that TAB prefix completion works under more circumstances. Since substring matches a subset of orderless, this generally works well. Furthermore one could even set '(basic substring orderless), but in this case basic matches strictly less, so this can lead to unexpected behavior but ensures that matches with the current prefix are preferred.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current recommended Selectrum+Orderless configuration is as follows, which is compatible with completion styles and optimizes orderless highlighting.

(setq orderless-skip-highlighting (lambda () selectrum-active-p))
(setq selectrum-highlight-candidates-function #'orderless-highlight-matches)

@bdarcus
Copy link
Contributor

bdarcus commented Feb 18, 2021

Most likely I will need two PRs in order to get Selectrum fully working ...

So @emiller88 opened up a new PR for selectrum in #4664.

But we need another for the workspace module, to replace persp-mode with perspective.

On discord, however, @hlissner suggested "May be better to forgo persp-mode and perspective entirely for tab-bar-mode+desktop." That may be more forward-looking?

@minad
Copy link
Contributor

minad commented Feb 18, 2021

@bdarcus Regarding Selectrum and Persp-Mode, I wonder why there is a problem. Selectrum is not doing anything out of the ordinary, relying on nothing else but the minibuffer. Did you open an issue on the perp-mode repository or the Selectrum repository?

@bdarcus
Copy link
Contributor

bdarcus commented Feb 18, 2021

@bdarcus Regarding Selectrum and Persp-Mode, I wonder why there is a problem. Selectrum is not doing anything out of the ordinary, relying on nothing else but the minibuffer. Did you open an issue on the perp-mode repository or the Selectrum repository?

No @minad.

I don't understand the details; was just summarizing the status, based on what @Townk concluded. Perhaps he could submit a bug report?

Edit: he does explain his conclusion here.

I did find that the current code project search functionality doesn't work correctly though. Maybe that has something to do with it?

@jethrokuan
Copy link
Contributor Author

Closing in favour of #4664

@jethrokuan jethrokuan closed this Feb 19, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 1, 2021
@hlissner hlissner added this to the Backlog milestone Oct 4, 2021
@hlissner hlissner removed the backlog label Oct 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
is:feature Adds or requests new features, or extends existing ones re:modules Pertains to adding, removing and management of modules status:needs-work The issue/PR is accepted, but not yet in a state to be applied.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants