= remembering(1)



== NAME

remembering - add memory to dmenu, fzf and similar menu tools.



== SYNOPSYS

*remembering* [_-p PROFILE_] -- _COMMAND_...



== EXAMPLES


=== A dmenu launcher that learns

[source,sh]
....
$ printf 'firefox\nmpv\nmutt\n' | remembering -p apps -- dmenu
....

The first time, the menu comes up alphabetical.  Pick `mutt` a few
times and it comes up first.


=== Open a file with fzf, most-used first

[source,sh]
....
$ ls | remembering -- fzf
....

Without _-p_, the profile is derived from the current directory,
so every directory gets its own ranking with no setup.



== DESCRIPTION

*remembering* sits between a list of choices and the menu tool
that picks from them.  It reads the choices from _stdin_, feeds
them to _COMMAND_ sorted by how often each one was picked before,
takes what _COMMAND_ prints as the pick, bumps that pick's count
in the profile, and prints the pick.

The lines on _stdin_ define what is offered: the profile only
ranks them.  Most-picked lines come first; ties are broken in byte
order; never-picked lines keep their byte order at the bottom.

The pick does not have to be one of the offered lines --- whatever
_COMMAND_ prints is learnt, so menu tools that accept free text
(such as `dmenu`) grow new entries on first use.  Lines that were
offered but never picked are remembered with a count of zero, and
profile entries that stop appearing on _stdin_ are kept --- the
profile accumulates the universe of choices it has seen.

The profile is rewritten atomically (a sibling `.tmp` file plus
rename), so a crash never leaves a half-written profile.

*remembering* is transparent in pipelines: _COMMAND_'s _stderr_
(where dmenu and fzf draw their interface) passes through, and its
exit status is forwarded.  A cancelled menu --- a nonzero exit ---
aborts the run with the same status and learns nothing.  A
successful run that picks nothing (empty output) also learns
nothing, and exits 0.



== OPTIONS

*-p* _PROFILE_::
The profile name to gather and store the ranking under (default:
the current directory, with every `/` turned into `!`).  The
attached getopts form (`-pPROFILE`) is accepted too.



== IO


=== STDIN

The menu choices, one per line, in any order.


=== STDOUT

The pick, when there is one, followed by a newline.  _COMMAND_'s
own output is captured, not echoed.


=== STDERR

_COMMAND_'s _stderr_, passed through untouched, and error
messages.


=== INPUT AND OUTPUT FILES

The profile, at:

[source,sh]
....
${XDG_DATA_HOME:-$HOME/.local/share}/remembering/$PROFILE
....

It is a plain text file with one line per known choice:

[source,sh]
....
2 profile firefox
0 profile mpv
7 profile mutt
....

The count comes first, the literal word `profile` second, and the
choice's text --- spaces included --- runs to the end of the line.
Lines are kept in byte order, with a newly learnt pick appended at
the end.  The file is made to be hand-edited: delete a line to
forget it, edit a count to re-rank it.



== EXIT STATUS

0::  The pick was learnt and printed, or there was nothing to
learn (empty pick).

1::  A runtime error, such as an unreadable or unwritable profile.

2::  Usage error: an unknown option, or a missing _COMMAND_.

Otherwise, _COMMAND_'s own nonzero exit status, forwarded as-is
(or 128 plus the signal number when it was killed by a signal).



== SEE ALSO

dmenu(1), fzf(1), sort(1)



== AUTHORS

mailto:eu@euandre.org[EuAndreh] and contributors.



== BUGS

* Report bugs to the mailto:~euandreh/public-inbox@lists.sr.ht[mailing list].
  Use the subject "[remembering] BUG or TASK: <description>".
* Browse bugs https://euandre.org/git/remembering/TODOs.html[online].
* https://euandre.org/git/remembering/[Homepage].
* https://lists.sr.ht/~euandreh/public-inbox?search=%5Bremembering%5D[Comments and discussions].
