Compare commits

...

10 Commits

Author SHA1 Message Date
NRK
87b1a43888 fix README formatting
the list somehow messes up the indented codeblocks...
2022-11-19 03:15:37 +06:00
NRK
975409b01b sxbm_dmenu: cosmetics 2022-11-12 10:22:32 +06:00
NRK
15abf3c12a sxbm_dmenu: remove $sxbm var
if someone installed it as something different, it's just going to be a
simple search and replace.
2022-11-12 10:21:26 +06:00
NRK
929602ffc9 bump version -> v0.5.1 2022-11-08 07:57:36 +06:00
NRK
f4e160754d code-style: cosmetics 2022-11-05 02:53:35 +06:00
NRK
1684db17a2 code-style: use tabs for indent 2022-11-05 02:45:54 +06:00
NRK
736d4e142d README: some reformatting 2022-11-04 04:19:23 +06:00
NRK
61c7fdec63 code-style: don't use allcaps variable names 2022-11-04 03:22:20 +06:00
NRK
cfc5a9fbcb update TODO, new plans 2022-11-04 03:13:37 +06:00
NRK
1fd58627a8 README: add CodeBerg badge and some formatting 2022-06-23 15:50:20 +06:00
3 changed files with 182 additions and 176 deletions

View File

@ -1,43 +1,51 @@
# sxbm
[![CodeBerg](https://img.shields.io/badge/Hosted_at-Codeberg-%232185D0?style=flat-square&logo=CodeBerg)](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.

View File

@ -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
View File

@ -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