#!/bin/sh # # Description: A cli bookmark manager written in POSIX shell # # Author: NRK ## Copyright 2021 NRK ## Licensed under GPL v3. See LICENSE for more details. ########## # CONFIG # ########## # Appname and Version APPNAME="sxbm" VERSION="v0.3" # Where all the data gets stored # Respects XDG_DATA_HOME if set [ -z "$XDG_DATA_HOME" ] && XDG_DATA_HOME="$HOME/.local/share" DATA_DIR="${XDG_DATA_HOME}/${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" ################# ### functions ### ################# die(){ [ -z "$1" ] || printf "$@\n" > /dev/stderr exit 1 } usage(){ printf "Usage: $APPNAME []\n" printf " COMMANDS: add [title] [+tags] ls|list [-s|--strict] [-c|--disable-colors] [title] [+tags] open [-f|--force] rm|remove edit -h|--help print this text and exit -v|--version print the version and exit\n\n" } version(){ printf "$APPNAME $VERSION\n" printf "GPLv3 license\n" printf "https://github.com/n-r-k/sxbm\n" } bm_add(){ [ -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" echo "$LINK $TITLE $TAGS" >> $DATA_FILE && echo "Link $(wc -l < "$DATA_FILE") added successfully!" || die "Couldn't add link" } bm_list(){ QUERY_TAG="" QUERY_TITLE="" QUERY_STRICT="||" while [ -n "$1" ]; do case "$1" in "-c"|"--disable-colors") COL_LINK=""; COL_TITLE=""; COL_LINE_NUM=""; shift ;; "-s"|"--strict") QUERY_STRICT="&&" shift ;; *) break ;; esac done # POSIX shell doesn't have arrays. # Desperate times calls for desperate measures! while [ -n "$1" ]; do case "$1" in +*) [ -z "$QUERY_TAG" ] && QUERY_TAG="/[[:blank:]]\\$1($| )/" || QUERY_TAG="${QUERY_TAG} $QUERY_STRICT /[[:blank:]]\\$1($| )/" ;; *) if [ -z "$QUERY_TITLE" ]; then QUERY_TITLE="grep -i -e \"$1\"" else [ "$QUERY_STRICT" = "&&" ] && QUERY_TITLE="${QUERY_TITLE} | grep -i -e \"$1\"" || QUERY_TITLE="${QUERY_TITLE} -e \"$1\"" fi ;; esac shift done __tag_search(){ awk -v COL_LINE_NUM="$COL_LINE_NUM" \ -v COL_LINK="$COL_LINK" -v COL_TITLE="$COL_TITLE" \ "$QUERY_TAG { LINK=\$1; \$1=\"\"; gsub(/[[:space:]]\+[^[:space:]]+/,\"\"); print COL_LINE_NUM NR \") \" COL_LINK LINK \" \" COL_TITLE \$0 }" \ "$DATA_FILE" } [ -z "$QUERY_TITLE" ] && __tag_search || __tag_search | eval "$QUERY_TITLE" } bm_open(){ 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=$( awk -v F="$1" 'NR == F {print NR" "$1}' $DATA_FILE ) else LINK=$( bm_list "-c" "$@" ) fi [ -n "$LINK" ] && LINK_NUM=$( echo "$LINK" | wc -l ) || die "No links found" if [ "$LINK_NUM" -gt 1 ] && [ -z "$FORCE" ]; then die "Too many links\nUse '$APPNAME open -f' to force open them all\n\n$( echo "$LINK" )" fi setsid $BROWSER $( echo "$LINK" | awk '{print $2;}' ) 1>/dev/null 2>&1 } bm_edit(){ $EDITOR "$DATA_FILE" } bm_remove(){ [ -z "$1" ] && die "No arguments given" [ "$1" -eq "$1" 2>/dev/null ] && LINK=$(sed "$1q;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 "$1d" "$DATA_FILE" && echo "Deleted successfully" || die "Couldn't delete link" fi } ############ ### main ### ############ [ -z "$1" ] && usage && die "No command given" [ -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!" ;; esac