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

How could I do search like this? #164

Closed
corasaurus-hex opened this issue Aug 7, 2020 · 14 comments
Closed

How could I do search like this? #164

corasaurus-hex opened this issue Aug 7, 2020 · 14 comments

Comments

@corasaurus-hex
Copy link

With counsel-rg and counsel-projectile I'm able to do search like this: http://monosnap.sutton.me/5EA75531-0F60-4294-B06F-91614E91818D.mov

I was trying to figure out if I can do this with selectrum. Do you think it's possible?

@clemera
Copy link
Collaborator

clemera commented Aug 7, 2020

Do you mean the 3 chars more to type thing?

@clemera clemera added the waiting on response Needs more info or follow-up, will be closed after 90 days if no response label Aug 7, 2020
@lorniu
Copy link
Contributor

lorniu commented Aug 7, 2020

Maybe like this?

This is what I just wrote to replace counsel-rg.

Selectrum is so interesting, and I will never go back to Ivy...

(cl-defmacro selectrum-make-action ((&rest args) &body body)
  "Make an action expression used in selectrum."
  (declare (indent 1))
  `(lambda ()
     (interactive)
     (put 'quit 'error-message "")
     (run-at-time nil nil
                  (lambda (,@args)
                    (put 'quit 'error-message "Quit")
                    (with-demoted-errors "Error: %S"
                      ,@body))
                  ,@(seq-take
                     `((if selectrum--refined-candidates (nth selectrum--current-candidate-index selectrum--refined-candidates))
                       selectrum--refined-candidates
                       (selectrum-get-current-input)
                       selectrum--current-candidate-index)
                     (length args)))
     (abort-recursive-edit)))

(defvar selectrum-search-rg-history nil)

(defun im/search-rg+ ()
  "Search like 'counsel-rg', C-c C-o to pop the Occur view."
  (interactive)
  (unless (executable-find "rg")
    (user-error "ripgrep must be installed."))
  (let* (type
         input
         (dir default-directory)
         (word (if (use-region-p)
                   (buffer-substring-no-properties (region-beginning) (region-end))
                 (let* ((sym (symbol-at-point)) (symn (symbol-name sym)))
                   (if (and sym (> 50 (length symn) 3)) symn nil))))
         (command (if (memq system-type '(ms-dos windows-nt))
                      "rg -M 240 --with-filename --no-heading --line-number --color never -S -e <R> ."
                    "rg -M 240 --with-filename --no-heading --line-number --color never -S -e <R>"))
         (cands (lambda (in)
                  (let ((msg)
                        (prop (lambda (cs)
                                (mapcar (lambda (c)
                                          (when (string-match "\\`\\([^:]+\\):\\([^:]+\\):" c)
                                            (add-face-text-property (match-beginning 1) (match-end 1) 'compilation-info nil c)
                                            (add-face-text-property (match-beginning 2) (match-end 2) '(:underline t :inherit compilation-line-number) nil c))
                                          c)
                                        cs))))
                    (cond
                      ;; search project
                      ((string-prefix-p "p " in)
                       (cond ((not (project-current))
                              (setq msg "This is not in a project."))
                             ((< (length in) 5)
                              (setq msg "Search in current project, input should more than 3."))
                             (t
                              (setq type 'project)
                              (setq dir (cdr (project-current)))
                              (setq in (cl-subseq in 2)))))
                      ;; search org-directory
                      ((string-prefix-p "o " in)
                       (cond ((not (file-exists-p org-directory))
                              (setq msg "Org Directory not exist?"))
                             ((< (length in) 5)
                              (setq msg "Search in org-directory, input should more than 3."))
                             (t
                              (setq type 'org)
                              (setq dir org-directory)
                              (setq in (cl-subseq in 2)))))
                      ;; search current directory
                      (t (if (< (length in) 3)
                             (setq msg "Input should more than 3."))
                         (setq type nil)
                         (setq dir default-directory)))
                    ;; take space in INPUT as .*?
                    (setq input
                          (replace-regexp-in-string "\\([^ ]\\) +\\(.\\)" "\\1.+?\\2" in))
                    (if msg (list msg)
                      (let* ((default-directory dir)
                             (cs (split-string
                                  (shell-command-to-string (grep-expand-template command in)) "\n")))
                        `((candidates . ,(funcall prop cs))
                          (input . ,input)))))))
         (cand (let ((selectrum-should-sort-p nil)
                     (selectrum-minibuffer-bindings
                      (append
                       selectrum-minibuffer-bindings
                       `(("C-c C-o" . ,(selectrum-make-action (c)
                                         ;; use rg.el to show the results in Occur buffer
                                         (require 'rg)
                                         (require 'compile)
                                         (let ((old-compilation-finish-functions compilation-finish-functions))
                                           (setq compilation-finish-functions
                                                 (list
                                                  (lambda (_a _b)
                                                    (unwind-protect
                                                         (progn
                                                           (pop-to-buffer (current-buffer))
                                                           (when (string-match "\\`\\(.*?\\):\\([0-9]+\\):\\(.*\\)\\'" c)
                                                             (let ((file-name (match-string-no-properties 1 c))
                                                                   (line-number (match-string-no-properties 2 c)))
                                                               (if rg-group-result
                                                                   (progn
                                                                     (re-search-forward (format "^File: %s" file-name) nil t)
                                                                     (re-search-forward (format "^ *%s" line-number) nil t)
                                                                     (re-search-forward input (point-at-eol) t))
                                                                 (re-search-forward (format "%s:%s:" file-name line-number) nil t)
                                                                 (re-search-forward input (point-at-eol) t)))))
                                                      (setq compilation-finish-functions old-compilation-finish-functions)))))
                                           (cond ((eq type 'project) (rg-project input "*"))
                                                 (t                  (rg input "*" dir))))))))))
                 (selectrum-read "rg: " cands
                                 :initial-input word
                                 :may-modify-candidates t
                                 :history 'selectrum-search-rg-history
                                 :require-match t))))
    (if (string-match "\\`\\(.*?\\):\\([0-9]+\\):\\(.*\\)\\'" cand)
        (let ((file-name (match-string-no-properties 1 cand))
              (line-number (match-string-no-properties 2 cand)))
          (find-file (expand-file-name file-name dir))
          (goto-char (point-min))
          (forward-line (1- (string-to-number line-number)))
          (re-search-forward input (point-at-eol) t)
          (recenter))
      (message "Bad candidate?"))))

@clemera
Copy link
Collaborator

clemera commented Aug 7, 2020

Nice, that is pretty cool, contribute it to the wiki if you like. You might be interested in embark which is more general solution for minibuffer-actions/occur functionality. Instead of returning the message as a candidate you could use minibuffer-message but there is a cursor jumping problem for now that I will look into to fix on selectrums side.

@lorniu
Copy link
Contributor

lorniu commented Aug 7, 2020

Yes, I will look into embark. I'm glad to see the improvement of selectrum, hope it will keep simple and clean.

@clemera
Copy link
Collaborator

clemera commented Aug 7, 2020

Right now the documentation of embark is a bit lacking. I will soon add instructions to the wiki how to set it up. Here should be all you need to get you started using it with selectrum:

(define-key minibuffer-local-map (kbd "M-m") 'embark-act)
(define-key minibuffer-local-map (kbd "C-M-m") 'embark-act-noexit)
(define-key minibuffer-local-map (kbd "C-M-g") 'embark-become)
(define-key minibuffer-local-map (kbd "C-c C-o") 'embark-export)



(add-hook 'embark-target-finders 'selectrum-get-current-candidate)
          
(add-hook 'embark-candidate-collectors
          (defun embark-selectrum-candidates+ ()
            (when selectrum-active-p
              (selectrum-get-current-candidates
               ;; Pass relative file names for dired.
               minibuffer-completing-file-name))))

(add-hook 'embark-setup-hook 'selectrum-set-selected-candidate)

(add-hook 'embark-input-getters
          (defun embark-selectrum-input-getter+ ()
            (when selectrum-active-p
              (let ((input (selectrum-get-current-input)))
                (if minibuffer-completing-file-name
                    (file-name-nondirectory input)
                  input)))))

;;; which key setup (optional)

(setq embark-action-indicator
      (defun embark-which-key-setup+ ()
        (let ((help-char nil)
              (which-key-show-transient-maps t)
              (which-key-replacement-alist
               (cons '(("^[0-9-]\\|kp-[0-9]\\|kp-subtract\\|C-u$" . nil) . ignore)
                     which-key-replacement-alist)))
          (setq-local which-key-show-prefix nil)
          (setq-local which-key-persistent-popup t)
          (which-key--update)))
      embark-become-indicator embark-action-indicator)

(add-hook 'embark-pre-action-hook
          (defun embark-which-key-tear-down+ ()
            (kill-local-variable 'which-key-persistent-popup)
            (kill-local-variable 'which-key-show-prefix)
            (unless which-key-persistent-popup
              (which-key--hide-popup-ignore-command))))

@clemera clemera removed the waiting on response Needs more info or follow-up, will be closed after 90 days if no response label Aug 7, 2020
@lorniu
Copy link
Contributor

lorniu commented Aug 7, 2020

Pretty good!

But I think instead of adding this to selectrum.el, maybe making it as an external plugin/file is a better choice. How to implement actions, there're different ideas. Maybe there will be something better than embark someday? Don't tight it too hard, keep selectrum KISS.

Just my opinion.

@clemera
Copy link
Collaborator

clemera commented Aug 7, 2020

You probably misunderstood me, there is nothing to worry about. Embark will not be added to selectrum and will stay a separate package.

@clemera
Copy link
Collaborator

clemera commented Aug 7, 2020

The cursor jumping by minibuffer-message is fixed by #165.

@clemera
Copy link
Collaborator

clemera commented Aug 7, 2020

I actually like showing the message in the candidates list better. Here is a quick fix for your function to stop Selectrum to filter during the message display:

...
(if msg
    (prog1 nil
      (setq-local selectrum-refine-candidates-function
                  (lambda (_ __) (list msg))))
  (kill-local-variable 'selectrum-refine-candidates-function)
...

You could also use that approach to dynamically change the count of chars which are left to type.

@lorniu
Copy link
Contributor

lorniu commented Aug 7, 2020

Very good.

I take it.

I have updated the WIKI with a few commands I wrote today. Maybe it will be helpful to some people.

  • search with rg (im/search-rg+)
  • search for imenu (im/imenu+)
  • search for pages (im/pages+)
  • toggle window view layout (im/views+)

@corasaurus-hex
Copy link
Author

I meant typing and having the results update with each keypress.

@corasaurus-hex
Copy link
Author

@lorniu Ill try that code when I'm back at my computer!

@clemera
Copy link
Collaborator

clemera commented Aug 7, 2020

I meant typing and having the results update with each keypress.

Like shown in the example command from @lorniu this can be achieved by passing a function to selectrum-read. You can also pass a completion table function to completing-read but currently dynamically computing the candidates from the table isn't implemented (see #114) and (info "(elisp) Programmed Completion").

@clemera clemera added the waiting on response Needs more info or follow-up, will be closed after 90 days if no response label Aug 7, 2020
@raxod502 raxod502 closed this as completed Nov 5, 2020
@raxod502
Copy link
Member

raxod502 commented Nov 5, 2020

This thread is being closed automatically by Tidier because it is labeled with "waiting on response" and has not seen any activity for 90 days. But don't worry—if you have any information that might advance the discussion, leave a comment and I will be happy to reopen the thread :)

@raxod502 raxod502 removed the waiting on response Needs more info or follow-up, will be closed after 90 days if no response label Dec 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants