2023-02-22	Candidate selection in Emacs

  TRIGGER WARNING: Strong opinions and a lot of sarcasm ahead.

Introductory thoughts
~~~~~~~~~~~~~~~~~~~~~

  Candidate selection/completion in Emacs is  a hot topic[1] where you
  can chose from a multitude  of different packages and configurations
  options.  In   the  ancient   times  there   was  only   helm[2].  A
  feature-rich,   bloated  and   laggy  "incremental   completion  and
  selection  narrowing  framework"  with  an  intimidating  amount  of
  functionality  and   documentation.  After   helm  came   Ivy[3]:  a
  supposedly  lightweight  alternative  to helm  which  suffered  from
  not-invented-here syndrome so it basically became just another helm.
  The newest  kid on the  block is  vertico[4]. But unlike  the others
  vertico is only  a tool for candidate selection but  offers not much
  else. To get the same functionality  as for example helm, one has to
  throw several other modularized packages like orderless, marginalia,
  embark,  etc  in  the  mix  so you  can  franken-stitch  together  a
  candidate selection framework of your  own liking. So now instead of
  one  big package  you have  to take  care of  five smaller  ones. Of
  course  tinkering with  Emacs  is fun  but it  is  also really  time
  consuming.

  Needless to  say I tried  all of  the aforementioned packages  but I
  always struggle using  any them for longer periods of  time. It does
  not  take  long  for  me  to encounter  some  minor  or  even  major
  annoyances with these  frameworks. I also found that  in my workflow
  flex-matching is  really annoying and  unhelpful. In the end  I keep
  going back to  vanilla Emacs with some  customized settings. Instead
  of tweaking every little aspect of how I want (or rather how I think
  I  want)  Emacs to  behave,  which  is  really a  challenging,  even
  mind-bending task,  I instead try  to stick  to defaults as  much as
  possible. Doing so some things seem to be a bit awkward at first but
  the power of muscle memory does mitigate this in the long run.


Configuration
~~~~~~~~~~~~~

  What  I have  done  here  is mimicking  the  behaviour  of the  bash
  shell[5]. The up-arrow key searches backwards through the minibuffer
  history for the already typed in string. For example on my system if
  I type

    M-x i n

  pressing the up-arrow key completes the command `indent-region` from
  my  minibuffer history.  If I'm  looking for  something different  I
  press UP again. If I want a  list of all possible completions I just
  press TAB. With M-v I can  easily jump into the completion window to
  select a candidate. Here is the whole config:
 
    ;; really important, saves minibuffer history between sessions	
    (savehist-mode 1)

    ;; delete duplicates from history
    (setq history-delete-duplicates t)

    ;; ignore case in the minibuffer
    (setq read-buffer-completion-ignore-case t) 
    (setq read-file-name-completion-ignore-case t)
    (setq completion-ignore-case t)

    ;; this is the real meat, type the first few letters of a
    ;; command/filename and then use the history elements to
    ;; complete it with UP/DOWN
    (define-key minibuffer-local-map
		(kbd "<up>") 'previous-complete-history-element)
    (define-key minibuffer-local-map
		(kbd "<down>") 'next-complete-history-element)

    ;; if there are only three completions candidates left cycle
    ;; though them with TAB
    (setq completion-cycle-threshold 3)

    ;; alternative keybinding for `switch-to-completions`
    (define-key minibuffer-local-map (kbd "M-SPC")
                                     'switch-to-completions)


Conclusion
~~~~~~~~~~

  Naturally this is the only sensible way of doing candidate selection
  in Emacs. Everything else would just be stupid *wink* *wink*.




Footnotes
~~~~~~~~~

[1] https://old.reddit.com/r/emacs/comments/117zdnu/what_are_the_benefits_of_vertico_over_helm_or_ivy/
[2] https://emacs-helm.github.io/helm/
[3] https://github.com/abo-abo/swiper
[4] https://github.com/minad/vertico 
[5] With these setting in the .bashrc:
      bind '"\e[A": history-search-backward'
      bind '"\e[B": history-search-forward'