diff options
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | README.md | 29 | ||||
-rwxr-xr-x | remembering | 121 | ||||
-rw-r--r-- | remembering.1 | 87 | ||||
-rw-r--r-- | remembering.5 | 83 | ||||
-rwxr-xr-x | tests/all.sh | 2 |
6 files changed, 337 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..96cdace --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +.POSIX: +PREFIX = /usr/local + +all: + +install: + install -d $(DESTDIR)$(PREFIX)/bin + install -m 755 remembering $(DESTDIR)$(PREFIX)/bin/ + install -d $(DESTDIR)$(PREFIX)/share/man/man1 + install -m 644 remembering.1 $(DESTDIR)$(PREFIX)/share/man/man1/ + install -d $(DESTDIR)$(PREFIX)/share/man/man5 + install -m 644 remembering.5 $(DESTDIR)$(PREFIX)/share/man/man5/ + +check: + sh tests/all.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e12832 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# remembering + +Add memory to [`dmenu`][dmenu], [`fzf`][fzf] and similar tools. + +Replace: +```shell +$ ls | fzf +``` + +with: +```shell +$ ls | remembering -p fzf-sample -c fzf +``` + +and see your previous choices from `fzf` start to appear at the beginning of the list. + +[dmenu]: https://tools.suckless.org/dmenu/ +[fzf]: https://github.com/junegunn/fzf + +## Installation + +Get the latest tarball and install it: + +```shell +wget https://git.euandreh.xyz/remembering/snapshot/remembering-0.1.0.tar.gz +pax -rzf remembering-0.1.0.tar.gz +cd remembering-0.1.0 +[sudo] make install +``` diff --git a/remembering b/remembering new file mode 100755 index 0000000..08bccd4 --- /dev/null +++ b/remembering @@ -0,0 +1,121 @@ +#!/bin/sh +set -eu + +usage() { + # FIXME: improve help + printf 'Usage: %s: -p PROFILE -c "COMMAND"\n' "$0" +} + +missing() { + printf 'Missing option: %s\n' "$1" +} + +COMMANDFLAG= +PROFILEFLAG= +while getopts 'c:p:' name; do + case "$name" in + c) + COMMANDFLAG="$OPTARG" + ;; + p) + PROFILEFLAG="$OPTARG" + ;; + esac +done + +if [ -z "$COMMANDFLAG" ]; then + missing '-c "COMMAND"' + usage + exit 2 +fi + +if [ -z "$PROFILEFLAG" ]; then + missing '-p PROFILE' + usage + exit 2 +fi + +COMMAND="$COMMANDFLAG" +PROFILE="${XDG_DATA_HOME:-$HOME/.local/share/remember}/$PROFILEFLAG" + +if [ ! -e "$PROFILE" ]; then + mkdir -p "$(dirname "$PROFILE")" + touch "$PROFILE" +fi + +SORTED_STDIN="$(mktemp)" +cat | sort > "$SORTED_STDIN" + +cmp() { + BEFORE="$(printf '%s\n%s\n' "$1" "$2")" + AFTER="$(echo "$BEFORE" | sort)" # FIXME: is this a lexicographical sort? + if [ "$BEFORE" = "$AFTER" ]; then + return 0 + else + return 1 + fi +} + +getentry() { + echo "$1" | awk -F: '{print substr($0, length($1)+2)}' +} + +get_left() { + if ! IFS='' read -r LEFT <&3; then + exit 0 + fi +} + +get_right() { + if ! IFS='' read -r RIGHT_RANKED <&4; then + while IFS='' read -r LEFT; do + echo "0:$LEFT" >> "$MERGED" + done <&3 + exit 0 + fi +} + +MERGED="$(mktemp)" +( + get_right + get_left + while true; do + RIGHT="$(getentry "$RIGHT_RANKED")" + if [ "$LEFT" = "$RIGHT" ]; then + echo "$RIGHT_RANKED" >> "$MERGED" + get_right + get_left + continue + fi + + if cmp "$LEFT" "$RIGHT"; then + echo "0:$LEFT" >> "$MERGED" + get_left + continue + else + get_right + continue + fi + done +) 3<"$SORTED_STDIN" 4<"$PROFILE" + +CHOICE="$(sort -t: -k1nr,1 -k2,2 < "$MERGED" | \ + awk -F: '{print substr($0, length($1)+2)}' | \ + $COMMAND)" + +NEW_PROFILE="$(mktemp)" +if [ -n "$CHOICE" ]; then + while IFS='' read -r LINE_RANKED; do + LINE="$(getentry "$LINE_RANKED")" + if [ "$CHOICE" = "$LINE" ]; then + RANK="$(echo "$LINE_RANKED" | cut -d: -f1)" + NEW_RANK=$((RANK + 1)) + echo "$NEW_RANK:$LINE" >> "$NEW_PROFILE" + else + echo "$LINE_RANKED" >> "$NEW_PROFILE" + fi + done < "$MERGED" +fi + +mv "$NEW_PROFILE" "$PROFILE" +echo "$CHOICE" diff --git a/remembering.1 b/remembering.1 new file mode 100644 index 0000000..545c4a8 --- /dev/null +++ b/remembering.1 @@ -0,0 +1,87 @@ +.TH REMEMBERING 1 @DATE@ "remembering @VERSION@" +. +. +.SH NAME +remembering - sort list using previous choices as weight +. +. +.SH SYNOPSYS +.B remembering +.RB -p +.IR profile +.RB -c +.IR command +. +. +.SH DESCRIPTION +.B remembering +takes a command that chooses an option as its behaviour, such as +.B fzf +or +.B dmenu +and +.IR remembers +what option is chosen, and as it is used, will put the most used choices at the beginning of the list. +. +. +.SH OPTIONS +. +.TP +.B -c +The +.IR command +to be executed, reading from standard input (STDIN). +. +.TP +.B -p +The name of the +.IR profile +where to look up and store raking data. +. +. +.SH EXAMPLES +.P +List current directory and feed it to +.IR fzf +via +.B remembering: +.RS +.EX + +$ ls | remembering -p fzf-ls -c fzf +.EE +.RE +. +.P +Lists all executables available in +.B $PATH, +and feed those to +.IR dmenu +via +.B remembering, +and execute with +.B sh +the choice picked: +.RS +.EX + +$ dmenu_path | remembering -p dmenu-exe -c 'dmenu' | sh +.EE +.RE +. +.P +Successive invocations will put the frequent choices at the beginning. +. +. +.SH SEE ALSO +.IR remembering (5) +. +. +.SH AUTHORS +EuAndreh <eu@euandre.org> +. +. +.SH BUGS +Report bugs to: ~euandreh/public-inbox@lists.sr.ht +.br +Home page: https://remembering.euandreh.xyz diff --git a/remembering.5 b/remembering.5 new file mode 100644 index 0000000..944af63 --- /dev/null +++ b/remembering.5 @@ -0,0 +1,83 @@ +.TH REMEMBERING 5 @DATE@ "remembering @VERSION@" +. +. +.SH NAME +remembering - file format of +.IR profiles. +. +. +.SH PROFILE +The +.IR profile +is a text file, stored on $XDG_DATA_HOME/profile-name +if $XDG_DATA_HOME is defined. +Otherwise, it lives in ~/.local/share/remember/profile-name. +.P +Each line of the +.IR profile +contains two pieces of information: the +.B rank +of the current entry, and the +.B entry +itself. +. +.P +The +.B rank +is a number that, and the +.B entry +is all the text until the end of the line: +.RS +.EX + +0:an entry +0:banana +0:entry +0:something +0:zzz +.EE +.RE +.P +Above is an example of a +.IR profile +file where all the entries have the default +.B rank +value: +.B 0. +.P +If the +.IR command +runs and chooses "banana", the new +.IR profile +will be: +.RS +.EX + +0:an entry +1:banana +0:entry +0:something +0:zzz +.EE +.RE +.P +The entries of the +.IR profile +are created and kept sorted. +.B remembering +expects to always find sorted entries in the +.IR profile. +. +. +.SH SEE ALSO +.IR remembering (1) +. +. +.SH AUTHORS +EuAndreh <eu@euandre.org> +. +. +.SH BUGS +Report bugs to: ~euandreh/public-inbox@lists.sr.ht +.br +Home page: https://remembering.euandreh.xyz diff --git a/tests/all.sh b/tests/all.sh new file mode 100755 index 0000000..92b70ea --- /dev/null +++ b/tests/all.sh @@ -0,0 +1,2 @@ +#!/bin/sh +set -eu |