CLOSED: [2016-04-09 Sat 13:10] SCHEDULED: <2016-04-09 Sat> :PROPERTIES: :ID: 2016-04-09-chosing-emacs-search-method :CREATED: [2016-04-09 Sat 12:01] :END: :LOGBOOK: - State "DONE" from "STARTED" [2016-04-09 Sat 13:10] :END: The issue: [[https://github.com/abo-abo/swiper][Swiper]] is a great search method. However, for large files, it takes very long from search process invocation to be actually able to enter the search query. I added to a [[https://github.com/abo-abo/swiper/issues/416#issuecomment-207767436][bug report on Github]] for this issue. Until this issue is fixed, I have to think about a workaround. What are the alternative search methods? Before Swiper, I was using [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Incremental-Search.html][incremental search]] (~isearch-forward~). It might be the case that ~search-forward~ is even faster. But I won't settle for less than isearch. A different alternative would be ~occur~. For now, standard incremental search is sufficient for large files. So: how about switching search method of ~C-s~ depending on the number of lines of the current buffer? Small files gets the advanced Swiper search, large files gets the basic incremental search. Let's do it. *** Deeper Analysis of the Issue To prevent me from chasing the wrong things, I did a profiler-run: #+BEGIN_EXAMPLE Function CPU Samples % - command-execute 34706 98% - call-interactively 34706 98% - swiper 34618 98% - apply 34618 98% - compiled 0x156eb5d 34618 98% - swiper--ivy 34618 98% - swiper--candidates 32825 93% - replace-regexp-in-string 88 0% apply 24 0% + funcall 8 0% + ivy-read 196 0% + byte-code 49 0% + minibuffer-complete 31 0% + execute-extended-command 8 0% + ... 452 1% + yas--post-command-handler 16 0% + timer-event-handler 6 0% + redisplay_internal (C function) 4 0% #+END_EXAMPLE OK, the culprit seems to be ~swiper--candidates~. Then, I had to find the sweetspot. How many lines does a buffer have until Swiper gets slow? For this purpose, I did some very basic performance measurements from the invocation of the search command until I am really able to enter my search query: | Lines of Buffer | Seconds until Searching | |-----------------+-------------------------| | 48000 | 20 | | 30000 | 8 | | 14000 | 1 | | 6700 | 1 | It seems to be the case at approximately 20,000 lines. Here, ~swiper-20160124.429~ from elpa gets slow on my intel i5 with GNU Emacs 24.4.1 on Debian GNU/Linux. Now we have found out more about the background, let's continue with coding our workaround. *** Implementing Buffer-Sized Search Method Switching As an Elisp amateur, I always get a bit nervous when I have to actually generate Elisp code. But this should be an easy one even for me. Counting lines of a buffer works quite fast in large files: #+BEGIN_SRC elisp (count-lines (point-min) (point-max))) #+END_SRC This is how the definition of two different search methods looks like: #+BEGIN_SRC elisp (global-set-key "\C-s" 'swiper) ;;fancy search ;; ... OR ... (global-set-key "\C-s" 'isearch-forward) ;;normal search #+END_SRC This is my workaround that switches the search method according to the number of lines in the current buffer: #+BEGIN_SRC elisp (defun my-search-method-according-to-numlines () "Determines the number of lines of current buffer and chooses a search method accordingly" (interactive) (if (< (count-lines (point-min) (point-max)) 20000) (swiper) (isearch-forward) ) ) (global-set-key "\C-s" 'my-search-method-according-to-numlines) #+END_SRC *** Using Oleh Krehel's Method :PROPERTIES: :END: While I was working on my workaround above, [[https://github.com/abo-abo/swiper/issues/416#issuecomment-207770727][Oleh Krehel answered to my GitHub issue with his solution]] to the same issue: #+BEGIN_SRC elisp (defun ora-swiper () (interactive) (if (and (buffer-file-name) (not (ignore-errors (file-remote-p (buffer-file-name)))) (if (eq major-mode 'org-mode) (> (buffer-size) 60000) (> (buffer-size) 300000))) (progn (save-buffer) (counsel-grep)) (swiper--ivy (swiper--candidates)))) (global-set-key "\C-s" 'ora-swiper) #+END_SRC This is clearly more elegant than mine. He checks on buffer size, distinguishes Org-mode buffers from the rest, and uses other (advanced) search methods such as ~counsel~. Unfortunately, I got issues with ~counsel-grep~ and his swiper command: ~(swiper--ivy (swiper--candidates))~ results in ~(wrong-type-argument stringp (#(~ followed by a string containing the whole buffer. counsel-grep results in ~Symbol's function definition is void: ivy-set-display-transformer~. I found [[https://github.com/abo-abo/swiper/issues/404][#404]] but could not resolve the issue with it. [[https://github.com/abo-abo/swiper/issues/416#issuecomment-207780648][Another helpful comment by Oleh]] and I found out that most of my Emacs packages were /very/ outdated due to a misconfigured ~package-archives~ setting. After a huge update session, ~counsel~ as well as ~swiper~ are doing great! The performance boost is astonishing! There is a [[https://www.reddit.com/r/emacs/comments/4e599o/use_different_search_methods_depending_on_number/][reddit-thread on this topic]].