Compare commits
10 Commits
b1ff0ad0bd
...
87b1a43888
| Author | SHA1 | Date | |
|---|---|---|---|
| 87b1a43888 | |||
| 975409b01b | |||
| 15abf3c12a | |||
| 929602ffc9 | |||
| f4e160754d | |||
| 1684db17a2 | |||
| 736d4e142d | |||
| 61c7fdec63 | |||
| cfc5a9fbcb | |||
| 1fd58627a8 |
41
README.md
41
README.md
@ -1,43 +1,51 @@
|
||||
# sxbm
|
||||
|
||||
[](https://codeberg.org/NRK/sxbm)
|
||||
|
||||
I needed a simple and browser-independent way of managing my bookmarks, leading to the creation of sxbm.
|
||||
It's written in strictly POSIX compliant shell, so it should work fine on all \*nix based operating system.
|
||||
|
||||
Sxbm stores your bookmarks in a plain text file making it easily portable.
|
||||
sxbm stores your bookmarks in a plain text file making it easily portable.
|
||||
Bookmarks are categorized via tags as opposed to the inferior folder structure found in browsers.
|
||||
|
||||
## Installation
|
||||
|
||||
Cone the repo.
|
||||
|
||||
```
|
||||
git clone https://codeberg.org/NRK/sxbm.git
|
||||
```
|
||||
git clone https://codeberg.org/NRK/sxbm.git
|
||||
|
||||
Then just copy/move the script into your $PATH.
|
||||
Instead of copying, you can also create a symlink. This way you can do a git pull to get updates.
|
||||
|
||||
## Usage
|
||||
Adding a bookmark (title and tag are optional.)
|
||||
|
||||
* Adding a bookmark (title and tag are optional.)
|
||||
|
||||
```
|
||||
sxbm add link.com title +tag
|
||||
```
|
||||
|
||||
Opening a bookmark. You need to specify a title, tag or line\_number.
|
||||
If there are multiple results use `sxbm open -f` to open them all.
|
||||
* Opening a bookmark. You need to specify a title, tag or line\_number.
|
||||
If there are multiple results use `sxbm open -f` to open them all.
|
||||
|
||||
```
|
||||
sxbm open <title|+tag|line_number>
|
||||
```
|
||||
|
||||
List all bookmarks.
|
||||
* List all bookmarks.
|
||||
|
||||
```
|
||||
sxbm ls
|
||||
```
|
||||
|
||||
Edit bookmarks.
|
||||
* Edit bookmarks.
|
||||
|
||||
```
|
||||
sxbm edit
|
||||
```
|
||||
|
||||
Remove a bookmark.
|
||||
* Remove a bookmark.
|
||||
|
||||
```
|
||||
sxbm rm <line_number>
|
||||
```
|
||||
@ -46,12 +54,14 @@ Run `sxbm --help` to see more detailed usage.
|
||||
|
||||
## Searching
|
||||
|
||||
Searching by tag
|
||||
* Searching by tag
|
||||
|
||||
```
|
||||
sxbm ls +tag
|
||||
```
|
||||
|
||||
Searching by title
|
||||
* Searching by title
|
||||
|
||||
```
|
||||
sxbm ls title
|
||||
```
|
||||
@ -68,8 +78,8 @@ As for titles, `sxbm ls aplha beta` will match bookmarks that contains BOTH
|
||||
`alpha` and `beta`. You can pass the `-S` option to search for entries that
|
||||
contain either one of the queries.
|
||||
|
||||
One more thing to keep in mind is that title search also matches links. The
|
||||
rational is that you may want to search `sxbm ls "gentoo.org"` to find
|
||||
One more thing to keep in mind is that title search also matches links.
|
||||
The rational is that you may want to search `sxbm ls "gentoo.org"` to find
|
||||
bookmarks with the specified url.
|
||||
|
||||
## Using it with Dmenu/Rofi
|
||||
@ -81,4 +91,5 @@ to open, copy and add bookmarks via dmenu/rofi.
|
||||
|
||||
- [ ] Enhance `remove` arguments. Should take same arguments as `open`.
|
||||
- [ ] Enhance `edit` arguments. Should take similar arguments as `open`.
|
||||
- [ ] Add PGP encryption.
|
||||
- [ ] Allow reading the bookmark file via stdin and writing it out via stdout.
|
||||
This would allow someone to easily encrypt their bookmarks if they wish.
|
||||
|
||||
@ -9,31 +9,29 @@
|
||||
# Change "dmenu" to "rofi -dmenu" if you wish to use rofi
|
||||
# NOTE: i do not use rofi, and haven't tested if it works or not
|
||||
prompt="dmenu -i -l 24"
|
||||
# Change this if you have renamed sxbm to something else
|
||||
sxbm="sxbm"
|
||||
|
||||
bm_open() {
|
||||
link_num="$("$sxbm" ls -c "$@" | $prompt | cut -d ")" -f 1)"
|
||||
[ -n "$link_num" ] && "$sxbm" open "$link_num"
|
||||
link_num="$(sxbm ls -c "$@" | $prompt | cut -d ")" -f 1)"
|
||||
[ -n "$link_num" ] && sxbm open "$link_num"
|
||||
}
|
||||
|
||||
bm_yank() {
|
||||
link="$("$sxbm" ls -c "$@" | $prompt | cut -d " " -f 2)"
|
||||
[ -n "$link" ] && echo "$link" | xclip -in -selection clipboard
|
||||
link="$(sxbm ls -c "$@" | $prompt | cut -d " " -f 2)"
|
||||
[ -n "$link" ] && echo "$link" | xclip -in -selection clipboard
|
||||
}
|
||||
|
||||
bm_add() {
|
||||
"$sxbm" add "$@" 2>&1 | xargs -I{} $prompt -p {}
|
||||
sxbm add "$@" 2>&1 | xargs -I{} $prompt -p {}
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
"-a"|"--add")
|
||||
shift && bm_add "$@"
|
||||
;;
|
||||
"-y"|"--yank")
|
||||
shift && bm_yank "$@"
|
||||
;;
|
||||
*)
|
||||
bm_open "$@"
|
||||
;;
|
||||
"-a"|"--add")
|
||||
shift && bm_add "$@"
|
||||
;;
|
||||
"-y"|"--yank")
|
||||
shift && bm_yank "$@"
|
||||
;;
|
||||
*)
|
||||
bm_open "$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
287
sxbm
287
sxbm
@ -12,38 +12,34 @@
|
||||
##########
|
||||
|
||||
# Appname and Version
|
||||
APPNAME="sxbm"
|
||||
VERSION="v0.5"
|
||||
appname="sxbm"
|
||||
version="v0.5.1"
|
||||
|
||||
# Where all the bookmarks get stored
|
||||
# Respects XDG_DATA_HOME if set
|
||||
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/${APPNAME}"
|
||||
DATA_FILE="${DATA_DIR}/bookmarks"
|
||||
data_dir="${XDG_DATA_HOME:-$HOME/.local/share}/${appname}"
|
||||
data_file="${data_dir}/bookmarks"
|
||||
|
||||
# Colors
|
||||
# For a list of ANSI color codes, check the link below
|
||||
# https://gist.github.com/Prakasaka/219fe5695beeb4d6311583e79933a009
|
||||
COL_LINK="\033[1;31m" # Red
|
||||
COL_TITLE="\033[0;33m" # Yellow
|
||||
COL_LINE_NUM="\033[1;34m" # Blue
|
||||
|
||||
# 1 to enable encryption, 0 to disable it
|
||||
# This currently does nothing, since the feature isn't implemented yet.
|
||||
ENCRYPTION="0"
|
||||
col_link="\033[1;31m" # Red
|
||||
col_title="\033[0;33m" # Yellow
|
||||
col_line_num="\033[1;34m" # Blue
|
||||
|
||||
|
||||
#################
|
||||
### functions ###
|
||||
#################
|
||||
#
|
||||
# functions
|
||||
#
|
||||
|
||||
die() {
|
||||
[ -n "$1" ] && printf "$*\n" >&2
|
||||
exit 1
|
||||
[ -n "$1" ] && printf "$*\n" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: $APPNAME <command> [<args>]
|
||||
cat << EOF
|
||||
Usage: $appname <command> [<args>]
|
||||
|
||||
COMMANDS:
|
||||
add <link> [title] [+tags]
|
||||
@ -58,170 +54,171 @@ EOF
|
||||
}
|
||||
|
||||
version() {
|
||||
cat << EOF
|
||||
$APPNAME $VERSION
|
||||
cat << EOF
|
||||
$appname $version
|
||||
GPLv3 license
|
||||
https://codeberg.org/NRK/sxbm
|
||||
EOF
|
||||
}
|
||||
|
||||
bm_add() {
|
||||
[ -z "$1" ] && die "No arguments provided. Use '$APPNAME -h' for help"
|
||||
[ -z "$1" ] && die "No arguments provided. Use '$appname -h' for help"
|
||||
|
||||
while [ -n "$1" ]; do
|
||||
case "$1" in
|
||||
*.*) [ -z "$LINK" ] &&
|
||||
LINK="$1" ||
|
||||
die "too many links\n$LINK\n$1" ;;
|
||||
+*) TAGS="${TAGS}$1 " ;;
|
||||
*) TITLE="${TITLE}$1 " ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
[ -z "$LINK" ] && die "No links found"
|
||||
while [ -n "$1" ]; do
|
||||
case "$1" in
|
||||
*.*)
|
||||
[ -n "$LINK" ] && die "too many links\n$LINK\n$1"
|
||||
LINK="$1"
|
||||
;;
|
||||
+*) TAGS="${TAGS}$1 "
|
||||
;;
|
||||
*) TITLE="${TITLE}$1 "
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
[ -z "$LINK" ] && die "No links found"
|
||||
|
||||
echo "$LINK $TITLE $TAGS" >> "$DATA_FILE" &&
|
||||
echo "Link $(wc -l < "$DATA_FILE") added successfully!" ||
|
||||
die "Couldn't add link"
|
||||
echo "$LINK $TITLE $TAGS" >> "$data_file" || die "Couldn't add link"
|
||||
echo "Link $(wc -l < "$data_file") added successfully!"
|
||||
}
|
||||
|
||||
__awk_search() {
|
||||
awk -v CLINE="$COL_LINE_NUM" -v CLINK="$COL_LINK" -v CTITLE="$COL_TITLE" \
|
||||
"$*"' {
|
||||
LINK=$1; $1="";
|
||||
gsub(/[[:blank:]]\+.*($| )/,"");
|
||||
print CLINE NR ") " CLINK LINK " " CTITLE $0
|
||||
}' "$DATA_FILE"
|
||||
awk -v CLINE="$col_line_num" -v CLINK="$col_link" -v CTITLE="$col_title" \
|
||||
"$*"' {
|
||||
LINK=$1; $1="";
|
||||
gsub(/[[:blank:]]\+.*($| )/,"");
|
||||
print CLINE NR ") " CLINK LINK " " CTITLE $0
|
||||
}' "$data_file"
|
||||
}
|
||||
|
||||
bm_list() {
|
||||
TAG_STRICT="||"
|
||||
TITLE_STRICT="&&"
|
||||
tag_strict="||"
|
||||
title_strict="&&"
|
||||
|
||||
while [ -n "$1" ]; do
|
||||
case "$1" in
|
||||
"-c"|"--disable-colors")
|
||||
unset COL_LINK COL_TITLE COL_LINE_NUM
|
||||
;;
|
||||
"-s"|"--strict")
|
||||
TAG_STRICT="&&"
|
||||
;;
|
||||
"-S")
|
||||
TITLE_STRICT="||"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
while [ -n "$1" ]; do
|
||||
case "$1" in
|
||||
"-c"|"--disable-colors")
|
||||
unset col_link col_title col_line_num
|
||||
;;
|
||||
"-s"|"--strict")
|
||||
tag_strict="&&"
|
||||
;;
|
||||
"-S")
|
||||
title_strict="||"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
while [ -n "$1" ]; do
|
||||
case "$1" in
|
||||
+*)
|
||||
QUERY_TAG="/[[:blank:]]\\$1($| )/ $TAG_STRICT $QUERY_TAG"
|
||||
;;
|
||||
*)
|
||||
tmp_title="$(echo "$1" | tr '[:lower:]' '[:upper:]')"
|
||||
QUERY_TITLE="toupper(\$0)~\"[^+]$tmp_title\" $TITLE_STRICT $QUERY_TITLE"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
QUERY_TAG="${QUERY_TAG%$TAG_STRICT }"
|
||||
QUERY_TITLE="${QUERY_TITLE%$TITLE_STRICT }"
|
||||
while [ -n "$1" ]; do
|
||||
case "$1" in
|
||||
+*)
|
||||
query_tag="/[[:blank:]]\\$1($| )/ $tag_strict $query_tag"
|
||||
;;
|
||||
*)
|
||||
tmp_title="$(echo "$1" | tr '[:lower:]' '[:upper:]')"
|
||||
query_title="toupper(\$0)~\"[^+]$tmp_title\" $title_strict $query_title"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
query_tag="${query_tag%$tag_strict }"
|
||||
query_title="${query_title%$title_strict }"
|
||||
|
||||
if [ -n "$QUERY_TAG" ] && [ -n "$QUERY_TITLE" ]; then
|
||||
{ __awk_search "$QUERY_TAG" & __awk_search "$QUERY_TITLE"; } |
|
||||
sort | uniq -d
|
||||
elif [ -n "$QUERY_TITLE" ] && [ -z "$QUERY_TAG" ]; then
|
||||
__awk_search "$QUERY_TITLE"
|
||||
else
|
||||
__awk_search "$QUERY_TAG"
|
||||
fi
|
||||
if [ -n "$query_tag" ] && [ -n "$query_title" ]; then
|
||||
{ __awk_search "$query_tag" & __awk_search "$query_title"; } |
|
||||
sort | uniq -d
|
||||
elif [ -n "$query_title" ] && [ -z "$query_tag" ]; then
|
||||
__awk_search "$query_title"
|
||||
else
|
||||
__awk_search "$query_tag"
|
||||
fi
|
||||
}
|
||||
|
||||
bm_open() {
|
||||
if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then
|
||||
FORCE=1
|
||||
shift
|
||||
fi
|
||||
[ -z "$1" ] && die "No arguments given"
|
||||
if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then
|
||||
force=1
|
||||
shift
|
||||
fi
|
||||
[ -z "$1" ] && die "No arguments given"
|
||||
|
||||
if [ -z "$2" ] && [ "$1" -eq "$1" 2>/dev/null ]; then
|
||||
LINK=$(sed -n "s| .*||;${1}p;" "$DATA_FILE")
|
||||
else
|
||||
LINK=$(bm_list "-c" "$@" | cut -d " " -f 2)
|
||||
fi
|
||||
if [ -z "$2" ] && [ "$1" -eq "$1" 2>/dev/null ]; then
|
||||
LINK=$(sed -n "s| .*||;${1}p;" "$data_file")
|
||||
else
|
||||
LINK=$(bm_list "-c" "$@" | cut -d " " -f 2)
|
||||
fi
|
||||
|
||||
[ -n "$LINK" ] &&
|
||||
LINK_NUM=$(echo "$LINK" | wc -l) ||
|
||||
die "No links found"
|
||||
[ -n "$LINK" ] &&
|
||||
link_num=$(echo "$LINK" | wc -l) ||
|
||||
die "No links found"
|
||||
|
||||
[ "$LINK_NUM" -gt 1 ] && [ -z "$FORCE" ] &&
|
||||
die "Too many links\nUse '$APPNAME open -f' to force open them all\n\n$LINK"
|
||||
[ "$link_num" -gt 1 ] && [ -z "$force" ] &&
|
||||
die "Too many links\nUse '$appname open -f' to force open them all\n\n$LINK"
|
||||
|
||||
exec $BROWSER $LINK
|
||||
exec $BROWSER $LINK
|
||||
}
|
||||
|
||||
bm_edit() {
|
||||
$EDITOR "$DATA_FILE"
|
||||
$EDITOR "$data_file"
|
||||
}
|
||||
|
||||
bm_remove() {
|
||||
[ -z "$1" ] && die "No arguments given"
|
||||
[ -z "$1" ] && die "No arguments given"
|
||||
|
||||
[ "$1" -eq "$1" 2>/dev/null ] &&
|
||||
LINK=$(sed "${1}q;d" "$DATA_FILE") ||
|
||||
die "Link not found"
|
||||
[ "$1" -eq "$1" 2>/dev/null ] &&
|
||||
LINK=$(sed "${1}q;d" "$data_file") ||
|
||||
die "Link not found"
|
||||
|
||||
printf "Delete this link? (y/n)\n$LINK\n"
|
||||
read ANSWER
|
||||
if [ "$ANSWER" = "y" ] || [ "$ANSWER" = "yes" ]; then
|
||||
sed -i --follow-symlinks "${1}d" "$DATA_FILE" &&
|
||||
echo "Deleted successfully" ||
|
||||
die "Couldn't delete link"
|
||||
fi
|
||||
printf "Delete this link? (y/n)\n$LINK\n"
|
||||
read answer
|
||||
if [ "$answer" = "y" ] || [ "$answer" = "yes" ]; then
|
||||
sed -i --follow-symlinks "${1}d" "$data_file" || die "Couldn't delete link"
|
||||
echo "Deleted successfully"
|
||||
fi
|
||||
}
|
||||
|
||||
############
|
||||
### main ###
|
||||
############
|
||||
#
|
||||
# main
|
||||
#
|
||||
|
||||
[ -z "$1" ] && { usage; die "No command given"; }
|
||||
|
||||
[ -d "$DATA_DIR" ] ||
|
||||
mkdir -p "$DATA_DIR" ||
|
||||
die "Unable to create $DATA_DIR"
|
||||
[ -d "$data_dir" ] ||
|
||||
mkdir -p "$data_dir" ||
|
||||
die "Unable to create $data_dir"
|
||||
|
||||
case "$1" in
|
||||
"add")
|
||||
shift
|
||||
bm_add "$@"
|
||||
;;
|
||||
"ls"|"list")
|
||||
shift
|
||||
bm_list "$@"
|
||||
;;
|
||||
"open")
|
||||
shift
|
||||
bm_open "$@"
|
||||
;;
|
||||
"rm"|"remove")
|
||||
shift
|
||||
bm_remove "$@"
|
||||
;;
|
||||
"edit")
|
||||
shift
|
||||
bm_edit "$@"
|
||||
;;
|
||||
"-h"|"--help")
|
||||
usage; exit 0
|
||||
;;
|
||||
"-v"|"--version")
|
||||
version; exit 0
|
||||
;;
|
||||
*)
|
||||
die "Invalid command. Use '$APPNAME -h' for help!"
|
||||
;;
|
||||
"add")
|
||||
shift
|
||||
bm_add "$@"
|
||||
;;
|
||||
"ls"|"list")
|
||||
shift
|
||||
bm_list "$@"
|
||||
;;
|
||||
"open")
|
||||
shift
|
||||
bm_open "$@"
|
||||
;;
|
||||
"rm"|"remove")
|
||||
shift
|
||||
bm_remove "$@"
|
||||
;;
|
||||
"edit")
|
||||
shift
|
||||
bm_edit "$@"
|
||||
;;
|
||||
"-h"|"--help")
|
||||
usage; exit 0
|
||||
;;
|
||||
"-v"|"--version")
|
||||
version; exit 0
|
||||
;;
|
||||
*)
|
||||
die "Invalid command. Use '$appname -h' for help!"
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user