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 # 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. 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. 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. Bookmarks are categorized via tags as opposed to the inferior folder structure found in browsers.
## Installation ## Installation
Cone the repo. 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. 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. Instead of copying, you can also create a symlink. This way you can do a git pull to get updates.
## Usage ## Usage
Adding a bookmark (title and tag are optional.)
* Adding a bookmark (title and tag are optional.)
``` ```
sxbm add link.com title +tag sxbm add link.com title +tag
``` ```
Opening a bookmark. You need to specify a title, tag or line\_number. * 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. If there are multiple results use `sxbm open -f` to open them all.
``` ```
sxbm open <title|+tag|line_number> sxbm open <title|+tag|line_number>
``` ```
List all bookmarks. * List all bookmarks.
``` ```
sxbm ls sxbm ls
``` ```
Edit bookmarks. * Edit bookmarks.
``` ```
sxbm edit sxbm edit
``` ```
Remove a bookmark. * Remove a bookmark.
``` ```
sxbm rm <line_number> sxbm rm <line_number>
``` ```
@ -46,12 +54,14 @@ Run `sxbm --help` to see more detailed usage.
## Searching ## Searching
Searching by tag * Searching by tag
``` ```
sxbm ls +tag sxbm ls +tag
``` ```
Searching by title * Searching by title
``` ```
sxbm ls 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 `alpha` and `beta`. You can pass the `-S` option to search for entries that
contain either one of the queries. contain either one of the queries.
One more thing to keep in mind is that title search also matches links. The One more thing to keep in mind is that title search also matches links.
rational is that you may want to search `sxbm ls "gentoo.org"` to find The rational is that you may want to search `sxbm ls "gentoo.org"` to find
bookmarks with the specified url. bookmarks with the specified url.
## Using it with Dmenu/Rofi ## 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 `remove` arguments. Should take same arguments as `open`.
- [ ] Enhance `edit` arguments. Should take similar 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 # 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 # NOTE: i do not use rofi, and haven't tested if it works or not
prompt="dmenu -i -l 24" prompt="dmenu -i -l 24"
# Change this if you have renamed sxbm to something else
sxbm="sxbm"
bm_open() { bm_open() {
link_num="$("$sxbm" ls -c "$@" | $prompt | cut -d ")" -f 1)" link_num="$(sxbm ls -c "$@" | $prompt | cut -d ")" -f 1)"
[ -n "$link_num" ] && "$sxbm" open "$link_num" [ -n "$link_num" ] && sxbm open "$link_num"
} }
bm_yank() { bm_yank() {
link="$("$sxbm" ls -c "$@" | $prompt | cut -d " " -f 2)" link="$(sxbm ls -c "$@" | $prompt | cut -d " " -f 2)"
[ -n "$link" ] && echo "$link" | xclip -in -selection clipboard [ -n "$link" ] && echo "$link" | xclip -in -selection clipboard
} }
bm_add() { bm_add() {
"$sxbm" add "$@" 2>&1 | xargs -I{} $prompt -p {} sxbm add "$@" 2>&1 | xargs -I{} $prompt -p {}
} }
case "$1" in case "$1" in
"-a"|"--add") "-a"|"--add")
shift && bm_add "$@" shift && bm_add "$@"
;; ;;
"-y"|"--yank") "-y"|"--yank")
shift && bm_yank "$@" shift && bm_yank "$@"
;; ;;
*) *)
bm_open "$@" bm_open "$@"
;; ;;
esac esac

287
sxbm
View File

@ -12,38 +12,34 @@
########## ##########
# Appname and Version # Appname and Version
APPNAME="sxbm" appname="sxbm"
VERSION="v0.5" version="v0.5.1"
# Where all the bookmarks get stored # Where all the bookmarks get stored
# Respects XDG_DATA_HOME if set # Respects XDG_DATA_HOME if set
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/${APPNAME}" data_dir="${XDG_DATA_HOME:-$HOME/.local/share}/${appname}"
DATA_FILE="${DATA_DIR}/bookmarks" data_file="${data_dir}/bookmarks"
# Colors # Colors
# For a list of ANSI color codes, check the link below # For a list of ANSI color codes, check the link below
# https://gist.github.com/Prakasaka/219fe5695beeb4d6311583e79933a009 # https://gist.github.com/Prakasaka/219fe5695beeb4d6311583e79933a009
COL_LINK="\033[1;31m" # Red col_link="\033[1;31m" # Red
COL_TITLE="\033[0;33m" # Yellow col_title="\033[0;33m" # Yellow
COL_LINE_NUM="\033[1;34m" # Blue 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"
################# #
### functions ### # functions
################# #
die() { die() {
[ -n "$1" ] && printf "$*\n" >&2 [ -n "$1" ] && printf "$*\n" >&2
exit 1 exit 1
} }
usage() { usage() {
cat << EOF cat << EOF
Usage: $APPNAME <command> [<args>] Usage: $appname <command> [<args>]
COMMANDS: COMMANDS:
add <link> [title] [+tags] add <link> [title] [+tags]
@ -58,170 +54,171 @@ EOF
} }
version() { version() {
cat << EOF cat << EOF
$APPNAME $VERSION $appname $version
GPLv3 license GPLv3 license
https://codeberg.org/NRK/sxbm https://codeberg.org/NRK/sxbm
EOF EOF
} }
bm_add() { 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 while [ -n "$1" ]; do
case "$1" in case "$1" in
*.*) [ -z "$LINK" ] && *.*)
LINK="$1" || [ -n "$LINK" ] && die "too many links\n$LINK\n$1"
die "too many links\n$LINK\n$1" ;; LINK="$1"
+*) TAGS="${TAGS}$1 " ;; ;;
*) TITLE="${TITLE}$1 " ;; +*) TAGS="${TAGS}$1 "
esac ;;
shift *) TITLE="${TITLE}$1 "
done ;;
[ -z "$LINK" ] && die "No links found" esac
shift
done
[ -z "$LINK" ] && die "No links found"
echo "$LINK $TITLE $TAGS" >> "$DATA_FILE" && echo "$LINK $TITLE $TAGS" >> "$data_file" || die "Couldn't add link"
echo "Link $(wc -l < "$DATA_FILE") added successfully!" || echo "Link $(wc -l < "$data_file") added successfully!"
die "Couldn't add link"
} }
__awk_search() { __awk_search() {
awk -v CLINE="$COL_LINE_NUM" -v CLINK="$COL_LINK" -v CTITLE="$COL_TITLE" \ awk -v CLINE="$col_line_num" -v CLINK="$col_link" -v CTITLE="$col_title" \
"$*"' { "$*"' {
LINK=$1; $1=""; LINK=$1; $1="";
gsub(/[[:blank:]]\+.*($| )/,""); gsub(/[[:blank:]]\+.*($| )/,"");
print CLINE NR ") " CLINK LINK " " CTITLE $0 print CLINE NR ") " CLINK LINK " " CTITLE $0
}' "$DATA_FILE" }' "$data_file"
} }
bm_list() { bm_list() {
TAG_STRICT="||" tag_strict="||"
TITLE_STRICT="&&" title_strict="&&"
while [ -n "$1" ]; do while [ -n "$1" ]; do
case "$1" in case "$1" in
"-c"|"--disable-colors") "-c"|"--disable-colors")
unset COL_LINK COL_TITLE COL_LINE_NUM unset col_link col_title col_line_num
;; ;;
"-s"|"--strict") "-s"|"--strict")
TAG_STRICT="&&" tag_strict="&&"
;; ;;
"-S") "-S")
TITLE_STRICT="||" title_strict="||"
;; ;;
*) *)
break break
;; ;;
esac esac
shift shift
done done
while [ -n "$1" ]; do while [ -n "$1" ]; do
case "$1" in case "$1" in
+*) +*)
QUERY_TAG="/[[:blank:]]\\$1($| )/ $TAG_STRICT $QUERY_TAG" query_tag="/[[:blank:]]\\$1($| )/ $tag_strict $query_tag"
;; ;;
*) *)
tmp_title="$(echo "$1" | tr '[:lower:]' '[:upper:]')" tmp_title="$(echo "$1" | tr '[:lower:]' '[:upper:]')"
QUERY_TITLE="toupper(\$0)~\"[^+]$tmp_title\" $TITLE_STRICT $QUERY_TITLE" query_title="toupper(\$0)~\"[^+]$tmp_title\" $title_strict $query_title"
;; ;;
esac esac
shift shift
done done
QUERY_TAG="${QUERY_TAG%$TAG_STRICT }" query_tag="${query_tag%$tag_strict }"
QUERY_TITLE="${QUERY_TITLE%$TITLE_STRICT }" query_title="${query_title%$title_strict }"
if [ -n "$QUERY_TAG" ] && [ -n "$QUERY_TITLE" ]; then if [ -n "$query_tag" ] && [ -n "$query_title" ]; then
{ __awk_search "$QUERY_TAG" & __awk_search "$QUERY_TITLE"; } | { __awk_search "$query_tag" & __awk_search "$query_title"; } |
sort | uniq -d sort | uniq -d
elif [ -n "$QUERY_TITLE" ] && [ -z "$QUERY_TAG" ]; then elif [ -n "$query_title" ] && [ -z "$query_tag" ]; then
__awk_search "$QUERY_TITLE" __awk_search "$query_title"
else else
__awk_search "$QUERY_TAG" __awk_search "$query_tag"
fi fi
} }
bm_open() { bm_open() {
if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then
FORCE=1 force=1
shift shift
fi fi
[ -z "$1" ] && die "No arguments given" [ -z "$1" ] && die "No arguments given"
if [ -z "$2" ] && [ "$1" -eq "$1" 2>/dev/null ]; then if [ -z "$2" ] && [ "$1" -eq "$1" 2>/dev/null ]; then
LINK=$(sed -n "s| .*||;${1}p;" "$DATA_FILE") LINK=$(sed -n "s| .*||;${1}p;" "$data_file")
else else
LINK=$(bm_list "-c" "$@" | cut -d " " -f 2) LINK=$(bm_list "-c" "$@" | cut -d " " -f 2)
fi fi
[ -n "$LINK" ] && [ -n "$LINK" ] &&
LINK_NUM=$(echo "$LINK" | wc -l) || link_num=$(echo "$LINK" | wc -l) ||
die "No links found" die "No links found"
[ "$LINK_NUM" -gt 1 ] && [ -z "$FORCE" ] && [ "$link_num" -gt 1 ] && [ -z "$force" ] &&
die "Too many links\nUse '$APPNAME open -f' to force open them all\n\n$LINK" die "Too many links\nUse '$appname open -f' to force open them all\n\n$LINK"
exec $BROWSER $LINK exec $BROWSER $LINK
} }
bm_edit() { bm_edit() {
$EDITOR "$DATA_FILE" $EDITOR "$data_file"
} }
bm_remove() { bm_remove() {
[ -z "$1" ] && die "No arguments given" [ -z "$1" ] && die "No arguments given"
[ "$1" -eq "$1" 2>/dev/null ] && [ "$1" -eq "$1" 2>/dev/null ] &&
LINK=$(sed "${1}q;d" "$DATA_FILE") || LINK=$(sed "${1}q;d" "$data_file") ||
die "Link not found" die "Link not found"
printf "Delete this link? (y/n)\n$LINK\n" printf "Delete this link? (y/n)\n$LINK\n"
read ANSWER read answer
if [ "$ANSWER" = "y" ] || [ "$ANSWER" = "yes" ]; then if [ "$answer" = "y" ] || [ "$answer" = "yes" ]; then
sed -i --follow-symlinks "${1}d" "$DATA_FILE" && sed -i --follow-symlinks "${1}d" "$data_file" || die "Couldn't delete link"
echo "Deleted successfully" || echo "Deleted successfully"
die "Couldn't delete link" fi
fi
} }
############ #
### main ### # main
############ #
[ -z "$1" ] && { usage; die "No command given"; } [ -z "$1" ] && { usage; die "No command given"; }
[ -d "$DATA_DIR" ] || [ -d "$data_dir" ] ||
mkdir -p "$DATA_DIR" || mkdir -p "$data_dir" ||
die "Unable to create $DATA_DIR" die "Unable to create $data_dir"
case "$1" in case "$1" in
"add") "add")
shift shift
bm_add "$@" bm_add "$@"
;; ;;
"ls"|"list") "ls"|"list")
shift shift
bm_list "$@" bm_list "$@"
;; ;;
"open") "open")
shift shift
bm_open "$@" bm_open "$@"
;; ;;
"rm"|"remove") "rm"|"remove")
shift shift
bm_remove "$@" bm_remove "$@"
;; ;;
"edit") "edit")
shift shift
bm_edit "$@" bm_edit "$@"
;; ;;
"-h"|"--help") "-h"|"--help")
usage; exit 0 usage; exit 0
;; ;;
"-v"|"--version") "-v"|"--version")
version; exit 0 version; exit 0
;; ;;
*) *)
die "Invalid command. Use '$APPNAME -h' for help!" die "Invalid command. Use '$appname -h' for help!"
;; ;;
esac esac