aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile15
-rw-r--r--README.md29
-rwxr-xr-xremembering121
-rw-r--r--remembering.187
-rw-r--r--remembering.583
-rwxr-xr-xtests/all.sh2
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