I've been using helm
for many years, since I started to use emacs
itself. It was great because it is a "all in one" tool, very convenient when starting in emacs
world.
The problem(?)
Actually there is a not problem perse, just maybe the "startup time", I had the load deferred so the first time I call some function from helm
there was a little "wait", nothing really bad but a little annoying
Motivation
Just wanted to trying new things π
The new stuff
There are new tools that are gaining popularity because of their approach: "just do one thing", these tools are:
- vertico: UI for completion, based on minibuffer, it also has a option to use a separate buffer, just like
helm
- marginalia: Enhance the minibuffer with more context about the information shown
- orderless: completion style, add fuzzy search to filter between the data shown by
vertico
- consult: commands for search and navigation
- embark: runs commands given a context at point
All of these tools rely on emacs
builtin functionality as much as possible and try to adhere to the APIs of different builtin components, that's a nice approach :)
The migration
Before migrating I needed to confirm that there were a replacement for every(or at least more of them) feature I use in my workflow, these features are:
Fuzzy search in a project
I was using helm-ls-git, which works on top oh helm
and also put at the top all the files that have been modified, it uses git
to get that information, it very useful because it give more context when searching for a file.
I haven't found(yet) something that replace helm-ls-git
but for fuzzy search I just can call project-find-file
, which is builtin in emacs
.
Search and replace in a whole project
For this I was using helm-ag, it allow to search into project files content, make another filter using helm
and also create an editable buffer with the results, once all the edits are done we can modify all the matched files with a single command.
This can be done using embark-export
function, which export all the content in the minibuffer and create a new buffer and use wgrep to have a editable buffer, that's a lot of manual steps, in helm-ag
it was more easier so I wrote some code to have the same experience
(defun my/grep-edit-results ()
"Export results using `embark-export' and activate `wgrep'.
This only runs for ripgrep results"
(interactive)
(when (cl-search "Ripgrep" (buffer-string))
;; we use `run-at-time' to ensure all of these steps
;; will be executed in order
(run-at-time 0 nil #'embark-export)
(run-at-time 0 nil #'wgrep-change-to-wgrep-mode)
(run-at-time 0 nil #'evil-normal-state)))
(define-key minibuffer-mode-map (kbd "C-c C-e") #'my/grep-edit-results)
This can be executed from the minibuffer
and only when it is a Ripgrep
execution, this way I have the same as I used to with helm-ag
.
Navigate the kill ring
Many times I delete stuff from many buffers and put them together in a new buffer, to do that I rely on the kill-ring
history, helm
has a function helm-show-kill-ring
with allow to fuzzy search in the history and then paste the selected item into the current buffer. consult
has an option to that too consult-yank-from-kill-ring
. It is not show the options as helm
but it does the work.
Fuzzy search inside a buffer
For this I used helm-swoop, consult
already has a function that do the same, it is consult-line
Backup files
helm-backup is great, it create a backup of your current file on every save and store it in a git repository, it allow to look for all the versions using helm
, I wanted to still use it but I don't want to have helm
installed just for one package, fortunately the author has another package git-backup which has all the functionality for backups has no dependency on helm
, with this I was able to reproduce what I have and with some elisp
code.
(defvar my/backup-dir (expand-file-name "~/.git-backup"))
(defun my/git-backup-versioning ()
"Save a version of the current file."
(unless (featurep 'git-backup)
(require 'git-backup))
(git-backup-version-file (executable-find "git") my/backup-dir '() (buffer-file-name)))
(defun my/git-backup-run-action (command commit-hash)
"Execute COMMAND with COMMIT-HASH using another defaults arguments."
(apply command `(,(executable-find "git") ,my/backup-dir ,commit-hash ,(buffer-file-name))))
(defun my/git-backup ()
"Navigate in versions of the current file."
(interactive)
(unless (featurep 'git-backup)
(require 'git-backup))
;; for some reason an extra space after `%h|' is required to avoid an error when
;; the shell command is executed
(let* ((candidates (git-backup-list-file-change-time (executable-find "git") my/backup-dir "%cI|%h| %ar" (buffer-file-name)))
(selection (completing-read "Pick revision: " candidates))
(commit-hash (nth 1 (string-split selection "|")))
(action (completing-read "Choose action: " '("diff" "new buffer" "replace current buffer"))))
(cond ((string-equal action "diff") (my/git-backup-run-action 'git-backup-create-ediff commit-hash))
((string-equal action "new buffer") (my/git-backup-run-action 'git-backup-open-in-new-buffer commit-hash))
((string-equal action "replace current buffer") (my/git-backup-run-action 'git-backup-replace-current-buffer commit-hash))
(t (message "Not valid option")))))
(use-package git-backup
:ensure t
:hook (after-save . my/git-backup-versioning))
Final thoughts
For the time this post was written I've been using the new setup for just a few days, so far the experience was good, it feels a simple setup now and gave me some ideas for another features that I'd like to develop.
Also you can see the diff after the migration in my dotfiles
Special thanks to @oantolin, creator or embark
, for helping me with some doubts in the telegram channel of emacs in Spanish emacs-es
Top comments (0)