#!/bin/sh # # Description: A cli bookmark manager written in POSIX shell # # Author: NRK ########## # CONFIG # ########## # 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}/sxbm" 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 ENCRYPTION="0" # Auto fetch title. 1 to enable, 0 to disable TITLE_FETCH="1" ################# ### functions ### ################# die(){ [ -z "$1" ] || printf "$@\n" > /dev/stderr exit 1 } usage(){ printf "Usage: sxbm []\n" printf " COMMANDS: add [title] [+tags] ls|list [-c|--disable-colors] [title] [+tags] open [-f|--force] rm|remove [-f|--force] edit [line_num|title|+tags] -h|--help print this text and exit -v|--version print the version and exit\n\n" } bm_add(){ [ -z "$1" ] && die "No arguments provided. Use 'sxbm -h' for help" # TODO while functional, this is extremely fucking stupid. # there has to be a better way to do this. local LINK=$( echo "$@" | grep -o "[^[:space:]]\+\.[^[:space:]]\+" ) [ -z "$LINK" ] && die "No links found" [ "$( echo "$LINK" | wc -l )" -gt 1 ] && die "Too many links!!\n$LINK" local REMAINING=$( echo "$@" | tr " " "\n" | grep -v "[^[:space:]]\+\.[^[:space:]]\+" ) [ -n "$REMAINING" ] && local TAGS=$( echo "$REMAINING" | grep "^\\+[^[:space:]]" | tr "\n" " " ) && local TITLE=$( echo "$REMAINING" | grep -v "^\\+[^[:space:]]" | tr "\n" " " ) echo "$LINK $TITLE $TAGS" >> $DATA_FILE && echo "Link $(wc -l < "$DATA_FILE") added successfully!" || die "Couldn't add link" } bm_list(){ local QUERY_TAG local QUERY_TITLE local QUERY_STRICT="||" while [ -n "$1" ]; do case "$1" in "-c"|"--disable-colors") COL_LINK=""; COL_TITLE=""; COL_LINE_NUM=""; shift ;; "-s"|"--strict") local 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="/[[:space:]]\\$1[[:space:]]/" || QUERY_TAG="${QUERY_TAG} $QUERY_STRICT /[[:space:]]\\$1[[:space:]]/" shift ;; *) if [ "$QUERY_STRICT" = "&&" ]; then [ -z "$QUERY_TITLE" ] && QUERY_TITLE="grep -i -e \"$1\"" || QUERY_TITLE="${QUERY_TITLE} | grep -i -e \"$1\"" else [ -z "$QUERY_TITLE" ] && QUERY_TITLE="grep -i -e \"$1\"" || QUERY_TITLE="${QUERY_TITLE} -e \"$1\"" fi shift ;; esac done [ -z "$QUERY_TITLE" ] && awk --posix -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" [ -n "$QUERY_TITLE" ] && awk --posix -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" | eval "$QUERY_TITLE" } bm_open(){ if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then local FORCE=1 shift fi [ -z "$1" ] && die "No arguments given" if [ -z "$2" ] && [ "$1" -eq "$1" 2>/dev/null ]; then local LINK=$( awk -v F="$1" 'NR == F {print NR" "$1}' $DATA_FILE ) else local LINK=$( bm_list "-c" "$@" ) fi [ -n "$LINK" ] && local LINK_NUM=$( echo "$LINK" | wc -l ) || die "No links found" if [ "$LINK_NUM" -gt 1 ] && [ -z "$FORCE" ]; then die "Too many links\nUse 'sxbm open -f' to force open them all\n\n$( echo "$LINK" )" fi while [ "$LINK_NUM" -gt 0 ]; do $BROWSER $( echo "$LINK" | awk "NR == $LINK_NUM {print \$2}" ) LINK_NUM=$(($LINK_NUM - 1)) done } ############ ### main ### ############ [ -z "$1" ] && usage && die "No command given" [ -d "$DATA_DIR" ] || mkdir "$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") ;; "edit") ;; "-h"|"--help") usage && die ;; "-v"|"--version") ;; *) die "Invalid command. Use 'sxbm -h' for help!" ;; esac