Recently Written · git

sbm-suckless

sbm before the rewrite: bookmarks in a plain file, picked with dmenu. Suckless style.

git clone https://github.com/equwal/sbm-suckless

Log | Files | Refs


bm (3015 bytes)

1 #!/bin/sh
2 
3 # Don't forget to set $BOOKMARKS and $USERTAGS to files somewhere.
4 # TODO:
5 # - prevent duplicate URLs
6 # - make the top tag a null tag so a user accidentally pressing ENTER twice doesn't close out the tag dialogue
7 
8 DMENULINES=15
9 
10 check () {
11     [ -z "$1" ] && exit 1
12 }
13 
14 help () {
15     printf 'Call without an argument to be prompted with dmenu.\n'
16     printf 'Flags:\n-h, --help\n-c, --copy\n-a, --add\n-e, --edit\n'
17 }
18 
19 # lock: take the write lock of $BOOKMARKS, a directory beside it. bm-sync
20 # takes it too, so that neither writes over a change of the other. The lock
21 # of a process that is gone is taken over. bm waits $SBM_LOCK_WAIT seconds
22 # (default 10) for it.
23 lock () {
24     waited=0
25     until mkdir "$BOOKMARKS.lock" 2>/dev/null; do
26         pid=$(cat "$BOOKMARKS.lock/pid" 2>/dev/null)
27         if [ -n "$pid" ] && ! kill -0 "$pid" 2>/dev/null; then
28             [ "$(cat "$BOOKMARKS.lock/pid" 2>/dev/null)" != "$pid" ] || rm -rf "$BOOKMARKS.lock"
29             continue
30         fi
31         if [ "$waited" -ge "${SBM_LOCK_WAIT:-10}" ]; then
32             printf 'bm: %s is in use. If no bm-sync runs, remove %s.lock\n' \
33                 "$BOOKMARKS" "$BOOKMARKS" >&2
34             exit 1
35         fi
36         sleep 1
37         waited=$((waited + 1))
38     done
39     echo $$ > "$BOOKMARKS.lock/pid"
40     trap 'rm -rf "$BOOKMARKS.lock"' EXIT
41     trap 'exit 1' HUP INT TERM
42 }
43 
44 unlock () {
45     rm -rf "$BOOKMARKS.lock"
46     trap - EXIT
47 }
48 
49 copy () {
50     sort -t2 "$BOOKMARKS" | dmenu -i -l $DMENULINES -p "bookmark:" | awk '{ print $1 }' | xclip -i -selection clipboard
51 }
52 
53 add () {
54     url="$(xclip -o | dmenu -p 'url: ')"
55     check "$url"
56     desc="$(printf "" | dmenu -p 'description: ')"
57     tag=""
58     tags=""
59     while [ "$tag" != "done" ] ; do
60       tags="$tags $tag"
61       tag="$(printf "done | (choose when done)\n$(cat $USERTAGS)" \
62             | dmenu -i -l $DMENULINES -p 'tags: ' | sed 's/ *|.*$//')"
63     done
64     tags="$(printf "$tags" | tr ' ' '\n' | sort | uniq | tr '\n' ' ' \
65            | sed 's/ $//')"
66 
67     lock
68     printf "%s %s | %s\\n" "$url" "$desc" "$tags" >> "$BOOKMARKS"
69     unlock
70     # bm-sync, if installed, sends the bookmark to your other devices.
71     if command -v bm-sync >/dev/null 2>&1; then bm-sync -q >/dev/null 2>&1 & fi
72 }
73 
74 edit () {
75     echo "Not implemented. Edit \$BOOKMARKS yourself at $BOOKMARKS." && exit 1
76 }
77 
78 plumb () {
79     echo "Not implemented" && exit 1
80 }
81 
82 promptflag () {
83     action="$(printf 'copy\nadd\nedit (not implemented)\nplumb (not implemented)' | dmenu -l 4 -p 'action:')"
84     [ "$action" = "copy" ]  && copy
85     [ "$action" = "edit" ]  && edit
86     [ "$action" = "add" ]   && add
87     [ "$action" = "plumb" ] && plumb
88 
89     exit 0
90 }
91 
92 [ "$1" = '-h' ] || [ "$1" = '--help' ] && help
93 [ "$1" = '-c' ] || [ "$1" = '--copy' ] && copy
94 [ "$1" = '-a' ] || [ "$1" = '--add' ]  && add
95 [ "$1" = '-e' ] || [ "$1" = '--edit' ] && edit
96 [ "$1" = '-e' ] || [ "$1" = '--plumb' ] && plumb
97 [ -z "$1" ] && promptflag
98 [ -n "$2" ] && echo "Too many arguments: use one or none." && exit 1