eshell ❤️ atuin
Find a file
Jeff Kreeftmeijer efaea1ef9f
Don't require history matches in completing-read
Currently, eshell-atuin's `eshell-atuin-history` doesn't allow
inserting commands that aren't yet in the history. This patch proposes
unmatched commands are inserted even if they don't match.

Consider the following scenario; you're running eshell-atuin with
`eshell-atuin-history` bound to `C-r`. In Eshell, you type part of a
command, let's say `ls`. Because the command you're looking for should
be in Atuin's database, you press `C-r` and find `ls -l`. That's
helpful, but not the full command you're looking for. You press
`<tab>` to insert the match and add `ah` to get `ls -lah`, the command
you meant to execute. However, after pressing `<ret>`, you find that
eshell-atuin won't let you insert a command that's not in the history
yet.

This patch flips the `REQUIRE-MATCH` boolean in the `completing-read`
call in `eshell-atuin-history` to `nil`, allowing for commands that
aren't in the history yet.

The resulting `compl` variable, which holds the command is then used
to find the command in the history. This is done to make sure any
changes to `eshell-atuin-history-format` don't affect the inserted
command. However, because there is no match in the history in this
scenario, the `command` variable remains empty.

In the end, what's inserted is either the cleaned `command` variable
which mached in the history, or the `compl` variable that didn't
match, and is inserted as-is.
2024-04-05 00:00:26 +02:00
.github/workflows eshell-atuin: initial commit 2024-03-07 22:58:15 +03:00
.gitignore eshell-atuin: initial commit 2024-03-07 22:58:15 +03:00
eshell-atuin.el Don't require history matches in completing-read 2024-04-05 00:00:26 +02:00
LICENSE eshell-atuin: initial commit 2024-03-07 22:58:15 +03:00
README.org Add MELPA badge 2024-04-01 17:34:02 +03:00

eshell-atuin

Integrate eshell with atuin.

atuin stores shell history in a database, which allows for having the same history across multiple shells, sessions, and optionally across different machines. See the project page for the complete list of features.

This package provides functionality to store and browse eshell history in atuin.

Installation

The package isn't yet available anywhere but in this repository. My preferred way for such cases is use-package and straight.el.

(use-package eshell-atuin
  :straight (:host github :repo "SqrtMinusOne/eshell-atuin")
  :after eshell
  :config
  (eshell-atuin-mode))

Alternatively, clone the repository, add it to the load-path, and require the package.

If your version of atuin is less than 18, turn off saving command durations:

(setq eshell-atuin-save-duration nil)

Configuration

If your atuin binary is located in a place unknown to executable-find, set the atuin-executable variable.

If you are using a vertical completion system such as Ivy, Selectrum, etc., you can configure the completion interface, e.g.:

(setq eshell-atuin-search-fields '(time duration command))
(setq eshell-atuin-history-format "%-160c %t + %d")

The available flags are:

Flag atuin field (see help atuin search) Required
%t time +
%c command +
%e exit
%d duration
%i directory
%u user
%h host
%r relativetime

See (emacs) Custom Format Strings for information on the general format-spec syntax.

I suspect the package might be slow if your history has a lot of records (I haven't checked yet). In this case, it might be worth setting a limit:

(setq eshell-atuin-search-options '("--exit" "0" "--limit" "10000"))

Usage

Enable eshell-atuin-mode to turn on storing eshell commands in atuin.

Run eshell-atuin-history inside an eshell buffer to browse the saved history. Accepting the completion will insert the command.

Implementation notes

I may have overengineered the package a bit to scale on lots of records.

The package caches the results of atuin search in eshell-atuin--history-cache (which see on the algorithm), and updates the cache incrementally. A formatted string for each entry is created at the moment of addition; entries are additionally "indexed" by a hashmap to lookup "raw" commands by their formatted versions.

So, the only places I see with the computational complexity of O(N), where N is the number of unique commands in atuin, are:

  • populating the cache at the first run of M-x eshell-atuin-history;
  • feeding the entirety of the cache to completing-read on each run of M-x eshell-atuin-history.