diff --git a/common/.local/bin/cht b/common/.local/bin/cht index 2f662aca..56f8bbaf 100755 --- a/common/.local/bin/cht +++ b/common/.local/bin/cht @@ -33,57 +33,54 @@ __CHTSH_DATETIME="2021-04-25 12:30:30 +0200" # CHTSH_HOME=${CHTSH:-"$HOME"/.cht.sh} [ -z "$CHTSH_CONF" ] && CHTSH_CONF=$CHTSH_HOME/cht.sh.conf -# shellcheck disable=SC1090,SC2002 +# shellcheck disable=SC1090 [ -e "$CHTSH_CONF" ] && source "$CHTSH_CONF" [ -z "$CHTSH_URL" ] && CHTSH_URL=https://cht.sh # currently we support only two modes: # * lite = access the server using curl # * auto = try standalone usage first -CHTSH_MODE="$(cat "$CHTSH_HOME"/mode 2> /dev/null)" +CHTSH_MODE="$(cat "$CHTSH_HOME"/mode 2>/dev/null)" [ "$CHTSH_MODE" != lite ] && CHTSH_MODE=auto -CHEATSH_INSTALLATION="$(cat "$CHTSH_HOME/standalone" 2> /dev/null)" - +CHEATSH_INSTALLATION="$(cat "$CHTSH_HOME/standalone" 2>/dev/null)" export LESSSECURE=1 STEALTH_MAX_SELECTION_LENGTH=5 case "$(uname -s)" in - Darwin) is_macos=yes ;; - *) is_macos=no ;; +Darwin) is_macos=yes ;; +*) is_macos=no ;; esac # for KSH93 # shellcheck disable=SC2034,SC2039,SC2168 if echo "$KSH_VERSION" | grep -q ' 93' && ! local foo 2>/dev/null; then - alias local=typeset + alias local=typeset fi -fatal() -{ - echo "ERROR: $*" >&2 - exit 1 +fatal() { + echo "ERROR: $*" >&2 + exit 1 } -_say_what_i_do() -{ - [ -n "$LOG" ] && echo "$(date '+[%Y-%m-%d %H:%M%S]') $*" >> "$LOG" +_say_what_i_do() { + [ -n "$LOG" ] && echo "$(date '+[%Y-%m-%d %H:%M%S]') $*" >>"$LOG" - local this_prompt="\033[0;1;4;32m>>\033[0m" - printf "\n${this_prompt}%s\033[0m\n" " $* " + local this_prompt="\033[0;1;4;32m>>\033[0m" + printf "\n${this_prompt}%s\033[0m\n" " $* " } -cheatsh_standalone_install() -{ - # the function installs cheat.sh with the upstream repositories - # in the standalone mode - local installdir; installdir="$1" - local default_installdir="$HOME/.cheat.sh" +cheatsh_standalone_install() { + # the function installs cheat.sh with the upstream repositories + # in the standalone mode + local installdir + installdir="$1" + local default_installdir="$HOME/.cheat.sh" - [ -z "$installdir" ] && installdir=${default_installdir} + [ -z "$installdir" ] && installdir=${default_installdir} - if [ "$installdir" = help ]; then - cat <<EOF + if [ "$installdir" = help ]; then + cat <<EOF Install cheat.sh in the standalone mode. After the installation, cheat.sh can be used locally, without accessing @@ -117,143 +114,148 @@ You can switch the mode with the --mode switch: For intallation and standalone usage, you need \`git\`, \`python\`, and \`virtualenv\` to be installed locally. EOF - return - fi - - local _exit_code=0 - - local dependencies=(python git virtualenv) - for dep in "${dependencies[@]}"; do - command -v "$dep" >/dev/null || \ - { echo "DEPENDENCY: \"$dep\" is needed to install cheat.sh in the standalone mode" >&2; _exit_code=1; } - done - [ "$_exit_code" -ne 0 ] && return "$_exit_code" - - while true; do - local _installdir - echo -n "Where should cheat.sh be installed [$installdir]? "; read -r _installdir - [ -n "$_installdir" ] && installdir=$_installdir - - if [ "$installdir" = y ] \ - || [ "$installdir" = Y ] \ - || [ "$(echo "$installdir" | tr "[:upper:]" "[:lower:]")" = yes ] - then - echo Please enter the directory name - echo If it was the directory name already, please prepend it with \"./\": "./$installdir" - else - break + return fi - done - if [ -e "$installdir" ]; then - echo "ERROR: Installation directory [$installdir] exists already" - echo "Please remove it first before continuing" - return 1 - fi + local _exit_code=0 - if ! mkdir -p "$installdir"; then - echo "ERROR: Could not create the installation directory \"$installdir\"" - echo "ERROR: Please check the permissions and start the script again" - return 1 - fi + local dependencies=(python git virtualenv) + for dep in "${dependencies[@]}"; do + command -v "$dep" >/dev/null || + { + echo "DEPENDENCY: \"$dep\" is needed to install cheat.sh in the standalone mode" >&2 + _exit_code=1 + } + done + [ "$_exit_code" -ne 0 ] && return "$_exit_code" - local space_needed=700 - local space_available; space_available=$(($(df -k "$installdir" | awk '{print $4}' | tail -1)/1024)) + while true; do + local _installdir + echo -n "Where should cheat.sh be installed [$installdir]? " + read -r _installdir + [ -n "$_installdir" ] && installdir=$_installdir - if [ "$space_available" -lt "$space_needed" ]; then - echo "ERROR: Installation directory has no enough space (needed: ${space_needed}M, available: ${space_available}M" - echo "ERROR: Please clean up and start the script again" + if [ "$installdir" = y ] || + [ "$installdir" = Y ] || + [ "$(echo "$installdir" | tr "[:upper:]" "[:lower:]")" = yes ]; then + echo Please enter the directory name + echo If it was the directory name already, please prepend it with \"./\": "./$installdir" + else + break + fi + done + + if [ -e "$installdir" ]; then + echo "ERROR: Installation directory [$installdir] exists already" + echo "Please remove it first before continuing" + return 1 + fi + + if ! mkdir -p "$installdir"; then + echo "ERROR: Could not create the installation directory \"$installdir\"" + echo "ERROR: Please check the permissions and start the script again" + return 1 + fi + + local space_needed=700 + local space_available + space_available=$(($(df -k "$installdir" | awk '{print $4}' | tail -1) / 1024)) + + if [ "$space_available" -lt "$space_needed" ]; then + echo "ERROR: Installation directory has no enough space (needed: ${space_needed}M, available: ${space_available}M" + echo "ERROR: Please clean up and start the script again" + rmdir "$installdir" + return 1 + fi + + _say_what_i_do Cloning cheat.sh locally + local url=https://github.com/chubin/cheat.sh rmdir "$installdir" - return 1 - fi + git clone "$url" "$installdir" || fatal Could not clone "$url" with git into "$installdir" + cd "$installdir" || fatal "Cannot cd into $installdir" - _say_what_i_do Cloning cheat.sh locally - local url=https://github.com/chubin/cheat.sh - rmdir "$installdir" - git clone "$url" "$installdir" || fatal Could not clone "$url" with git into "$installdir" - cd "$installdir" || fatal "Cannot cd into $installdir" + # after the repository cloned, we may have the log directory + # and we can write our installation log into it + mkdir -p "log/" + LOG="$PWD/log/install.log" - # after the repository cloned, we may have the log directory - # and we can write our installation log into it - mkdir -p "log/" - LOG="$PWD/log/install.log" + # we use tee everywhere so we should set -o pipefail + set -o pipefail - # we use tee everywhere so we should set -o pipefail - set -o pipefail - - # currently the script uses python 2, - # but cheat.sh supports python 3 too - # if you want to switch it to python 3 - # set PYTHON2 to NO: - # PYTHON2=NO - # - PYTHON2=NO - if [[ $PYTHON2 = YES ]]; then - python="python2" - pip="pip" - virtualenv_python3_option=() - else - python="python3" - pip="pip3" - virtualenv_python3_option=(-p python3) - fi - - _say_what_i_do Creating virtual environment - virtualenv "${virtualenv_python3_option[@]}" ve \ - || fatal "Could not create virtual environment with 'virtualenv ve'" - - export CHEATSH_PATH_WORKDIR=$PWD - - # rapidfuzz does not support Python 2, - # so if we are using Python 2, install fuzzywuzzy instead - if [[ $PYTHON2 = YES ]]; then - sed -i s/rapidfuzz/fuzzywuzzy/ requirements.txt - echo "python-Levenshtein" >> requirements.txt - fi - - _say_what_i_do Installing python requirements into the virtual environment - ve/bin/"$pip" install -r requirements.txt > "$LOG" \ - || { - - echo "ERROR:" - echo "---" - tail -n 10 "$LOG" - echo "---" - echo "See $LOG for more" - fatal Could not install python dependencies into the virtual environment - } - echo "$(ve/bin/"$pip" freeze | wc -l) dependencies were successfully installed" - - _say_what_i_do Fetching the upstream cheat sheets repositories - ve/bin/python lib/fetch.py fetch-all | tee -a "$LOG" - - _say_what_i_do Running self-tests - ( - cd tests || exit - - if CHEATSH_TEST_STANDALONE=YES \ - CHEATSH_TEST_SKIP_ONLINE=NO \ - CHEATSH_TEST_SHOW_DETAILS=NO \ - PYTHON=../ve/bin/python bash run-tests.sh | tee -a "$LOG" - then - printf "\033[0;32m%s\033[0m\n" "SUCCESS" + # currently the script uses python 2, + # but cheat.sh supports python 3 too + # if you want to switch it to python 3 + # set PYTHON2 to NO: + # PYTHON2=NO + # + PYTHON2=NO + if [[ $PYTHON2 = YES ]]; then + python="python2" + pip="pip" + virtualenv_python3_option=() else - printf "\033[0;31m%s\033[0m\n" "FAILED" - echo "Some tests were failed. Run the tests manually for further investigation:" - echo " cd $PWD; bash run-tests.sh)" + python="python3" + pip="pip3" + virtualenv_python3_option=(-p python3) fi - ) - mkdir -p "$CHTSH_HOME" - echo "$installdir" > "$CHTSH_HOME/standalone" - echo auto > "$CHTSH_HOME/mode" + _say_what_i_do Creating virtual environment + virtualenv "${virtualenv_python3_option[@]}" ve || + fatal "Could not create virtual environment with 'virtualenv ve'" - _say_what_i_do Done + export CHEATSH_PATH_WORKDIR=$PWD - local v1; v1=$(printf "\033[0;1;32m") - local v2; v2=$(printf "\033[0m") + # rapidfuzz does not support Python 2, + # so if we are using Python 2, install fuzzywuzzy instead + if [[ $PYTHON2 = YES ]]; then + sed -i s/rapidfuzz/fuzzywuzzy/ requirements.txt + echo "python-Levenshtein" >>requirements.txt + fi - cat <<EOF | sed "s/{/$v1/; s/}/$v2/" + _say_what_i_do Installing python requirements into the virtual environment + ve/bin/"$pip" install -r requirements.txt >"$LOG" || + { + + echo "ERROR:" + echo "---" + tail -n 10 "$LOG" + echo "---" + echo "See $LOG for more" + fatal Could not install python dependencies into the virtual environment + } + echo "$(ve/bin/"$pip" freeze | wc -l) dependencies were successfully installed" + + _say_what_i_do Fetching the upstream cheat sheets repositories + ve/bin/python lib/fetch.py fetch-all | tee -a "$LOG" + + _say_what_i_do Running self-tests + ( + cd tests || exit + + if CHEATSH_TEST_STANDALONE=YES \ + CHEATSH_TEST_SKIP_ONLINE=NO \ + CHEATSH_TEST_SHOW_DETAILS=NO \ + PYTHON=../ve/bin/python bash run-tests.sh | tee -a "$LOG"; then + printf "\033[0;32m%s\033[0m\n" "SUCCESS" + else + printf "\033[0;31m%s\033[0m\n" "FAILED" + echo "Some tests were failed. Run the tests manually for further investigation:" + echo " cd $PWD; bash run-tests.sh)" + fi + ) + + mkdir -p "$CHTSH_HOME" + echo "$installdir" >"$CHTSH_HOME/standalone" + echo auto >"$CHTSH_HOME/mode" + + _say_what_i_do Done + + local v1 + v1=$(printf "\033[0;1;32m") + local v2 + v2=$(printf "\033[0m") + + cat <<EOF | sed "s/{/$v1/; s/}/$v2/" { _ } { \\ \\ } The installation is successfully finished. @@ -286,164 +288,172 @@ with the ENTRY-POINT from the URL https://ENTRY-POINT/:actualize specified EOF } -chtsh_mode() -{ - local mode="$1" +chtsh_mode() { + local mode="$1" - local text; text=$( - echo " auto use the standalone installation first" - echo " lite use the cheat sheets server directly" - ) + local text + text=$( + echo " auto use the standalone installation first" + echo " lite use the cheat sheets server directly" + ) - if [ -z "$mode" ]; then - echo "current mode: $CHTSH_MODE ($(printf "%s" "$text" | grep "$CHTSH_MODE" | sed "s/$CHTSH_MODE//; s/^ *//; s/ \+/ /"))" - if [ -d "$CHEATSH_INSTALLATION" ]; then - echo "cheat.sh standalone installation: $CHEATSH_INSTALLATION" + if [ -z "$mode" ]; then + echo "current mode: $CHTSH_MODE ($(printf "%s" "$text" | grep "$CHTSH_MODE" | sed "s/$CHTSH_MODE//; s/^ *//; s/ \+/ /"))" + if [ -d "$CHEATSH_INSTALLATION" ]; then + echo "cheat.sh standalone installation: $CHEATSH_INSTALLATION" + else + echo 'cheat.sh standalone installation not found; falling back to the "lite" mode' + fi + elif [ "$mode" = auto ] || [ "$mode" = lite ]; then + if [ "$mode" = "$CHTSH_MODE" ]; then + echo "The configured mode was \"$CHTSH_MODE\"; nothing changed" + else + mkdir -p "$CHTSH_HOME" + echo "$mode" >"$CHTSH_HOME/mode" + echo "Configured mode: $mode" + fi else - echo 'cheat.sh standalone installation not found; falling back to the "lite" mode' + echo "Unknown mode: $mode" + echo Supported modes: + echo " auto use the standalone installation first" + echo " lite use the cheat sheets server directly" fi - elif [ "$mode" = auto ] || [ "$mode" = lite ]; then - if [ "$mode" = "$CHTSH_MODE" ]; then - echo "The configured mode was \"$CHTSH_MODE\"; nothing changed" +} + +get_query_options() { + local query="$*" + if [ -n "$CHTSH_QUERY_OPTIONS" ]; then + case $query in + *\?*) query="$query&${CHTSH_QUERY_OPTIONS}" ;; + *) query="$query?${CHTSH_QUERY_OPTIONS}" ;; + esac + fi + printf "%s" "$query" +} + +do_query() { + local query="$*" + local b_opts= + local uri="${CHTSH_URL}/\"\$(get_query_options $query)\"" + + if [ -e "$CHTSH_HOME/id" ]; then + b_opts="-b \"\$CHTSH_HOME/id\"" + fi + + eval curl "$b_opts" -s "$uri" >"$TMP1" + + if [ -z "$lines" ] || [ "$(wc -l "$TMP1" | awk '{print $1}')" -lt "$lines" ]; then + cat "$TMP1" else - mkdir -p "$CHTSH_HOME" - echo "$mode" > "$CHTSH_HOME/mode" - echo "Configured mode: $mode" + ${PAGER:-$defpager} "$TMP1" fi - else - echo "Unknown mode: $mode" - echo Supported modes: - echo " auto use the standalone installation first" - echo " lite use the cheat sheets server directly" - fi } -get_query_options() -{ - local query="$*" - if [ -n "$CHTSH_QUERY_OPTIONS" ]; then - case $query in - *\?*) query="$query&${CHTSH_QUERY_OPTIONS}";; - *) query="$query?${CHTSH_QUERY_OPTIONS}";; - esac - fi - printf "%s" "$query" -} +prepare_query() { + local section="$1" + shift + local input="$1" + shift + local arguments="$1" -do_query() -{ - local query="$*" - local b_opts= - local uri="${CHTSH_URL}/\"\$(get_query_options $query)\"" - - if [ -e "$CHTSH_HOME/id" ]; then - b_opts="-b \"\$CHTSH_HOME/id\"" - fi - - eval curl "$b_opts" -s "$uri" > "$TMP1" - - if [ -z "$lines" ] || [ "$(wc -l "$TMP1" | awk '{print $1}')" -lt "$lines" ]; then - cat "$TMP1" - else - ${PAGER:-$defpager} "$TMP1" - fi -} - -prepare_query() -{ - local section="$1"; shift - local input="$1"; shift - local arguments="$1" - - local query - if [ -z "$section" ] || [ x"${input}" != x"${input#/}" ]; then - query=$(printf %s "$input" | sed 's@ @/@; s@ @+@g') - else - query=$(printf %s "$section/$input" | sed 's@ @+@g') - fi - - [ -n "$arguments" ] && arguments="?$arguments" - printf %s "$query$arguments" -} - -get_list_of_sections() -{ - curl -s "${CHTSH_URL}"/:list | grep -v '/.*/' | grep '/$' | xargs -} - -gen_random_str() -( - len=$1 - if command -v openssl >/dev/null; then - openssl rand -base64 $((len*3/4)) | awk -v ORS='' // - else - rdev=/dev/urandom - for d in /dev/{srandom,random,arandom}; do - test -r "$d" && rdev=$d - done - if command -v hexdump >/dev/null; then - hexdump -vn $((len/2)) -e '1/1 "%02X" 1 ""' "$rdev" - elif command -v xxd >/dev/null; then - xxd -l $((len/2)) -ps "$rdev" | awk -v ORS='' // + local query + if [ -z "$section" ] || [ x"${input}" != x"${input#/}" ]; then + query=$(printf %s "$input" | sed 's@ @/@; s@ @+@g') else - cd /tmp || { echo Cannot cd into /tmp >&2; exit 1; } - s= - # shellcheck disable=SC2000 - while [ "$(echo "$s" | wc -c)" -lt "$len" ]; do - s="$s$(mktemp -u XXXXXXXXXX)" - done - printf "%.${len}s" "$s" + query=$(printf %s "$section/$input" | sed 's@ @+@g') + fi + + [ -n "$arguments" ] && arguments="?$arguments" + printf %s "$query$arguments" +} + +get_list_of_sections() { + curl -s "${CHTSH_URL}"/:list | grep -v '/.*/' | grep '/$' | xargs +} + +gen_random_str() ( + len=$1 + if command -v openssl >/dev/null; then + openssl rand -base64 $((len * 3 / 4)) | awk -v ORS='' // + else + rdev=/dev/urandom + for d in /dev/{srandom,random,arandom}; do + test -r "$d" && rdev=$d + done + if command -v hexdump >/dev/null; then + hexdump -vn $((len / 2)) -e '1/1 "%02X" 1 ""' "$rdev" + elif command -v xxd >/dev/null; then + xxd -l $((len / 2)) -ps "$rdev" | awk -v ORS='' // + else + cd /tmp || { + echo Cannot cd into /tmp >&2 + exit 1 + } + s= + # shellcheck disable=SC2000 + while [ "$(echo "$s" | wc -c)" -lt "$len" ]; do + s="$s$(mktemp -u XXXXXXXXXX)" + done + printf "%.${len}s" "$s" + fi fi - fi ) if [ "$CHTSH_MODE" = auto ] && [ -d "$CHEATSH_INSTALLATION" ]; then - curl() { - # ignoring all options - # currently the standalone.py does not support them anyway - local opt - while getopts "b:s" opt; do - : - done - shift $((OPTIND - 1)) - - local url; url="$1"; shift - PYTHONIOENCODING=UTF-8 "$CHEATSH_INSTALLATION/ve/bin/python" "$CHEATSH_INSTALLATION/lib/standalone.py" "${url#"$CHTSH_URL"}" "$@" - } -elif [ "$(uname -s)" = OpenBSD ] && [ -x /usr/bin/ftp ]; then - # any better test not involving either OS matching or actual query? - curl() { - local opt args="-o -" - while getopts "b:s" opt; do - case $opt in - b) args="$args -c $OPTARG";; - s) args="$args -M -V";; - *) echo "internal error: unsupported cURL option '$opt'" >&2; exit 1;; - esac - done - shift $((OPTIND - 1)) - /usr/bin/ftp "$args" "$@" - } -else - command -v curl >/dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } - _CURL=$(command -v curl) - if [ x"$CHTSH_CURL_OPTIONS" != x ]; then curl() { - $_CURL "${CHTSH_CURL_OPTIONS}" "$@" + # ignoring all options + # currently the standalone.py does not support them anyway + local opt + while getopts "b:s" opt; do + : + done + shift $((OPTIND - 1)) + + local url + url="$1" + shift + PYTHONIOENCODING=UTF-8 "$CHEATSH_INSTALLATION/ve/bin/python" "$CHEATSH_INSTALLATION/lib/standalone.py" "${url#"$CHTSH_URL"}" "$@" } - fi +elif [ "$(uname -s)" = OpenBSD ] && [ -x /usr/bin/ftp ]; then + # any better test not involving either OS matching or actual query? + curl() { + local opt args="-o -" + while getopts "b:s" opt; do + case $opt in + b) args="$args -c $OPTARG" ;; + s) args="$args -M -V" ;; + *) + echo "internal error: unsupported cURL option '$opt'" >&2 + exit 1 + ;; + esac + done + shift $((OPTIND - 1)) + /usr/bin/ftp "$args" "$@" + } +else + command -v curl >/dev/null || { + echo 'DEPENDENCY: install "curl" to use cht.sh' >&2 + exit 1 + } + _CURL=$(command -v curl) + if [ x"$CHTSH_CURL_OPTIONS" != x ]; then + curl() { + $_CURL "${CHTSH_CURL_OPTIONS}" "$@" + } + fi fi if [ "$1" = --read ]; then - read -r a || a="exit" - printf "%s\n" "$a" - exit 0 + read -r a || a="exit" + printf "%s\n" "$a" + exit 0 elif [ x"$1" = x--help ] || [ -z "$1" ]; then - n=${0##*/} - s=$(echo "$n" | sed "s/./ /"g) + n=${0##*/} + s=$(echo "$n" | sed "s/./ /"g) - cat <<EOF + cat <<EOF Usage: $n [OPTIONS|QUERY] @@ -464,146 +474,157 @@ Options: * lite - use the cheat sheet server EOF - exit 0 + exit 0 elif [ x"$1" = x--shell ]; then - shell_mode=yes - shift + shell_mode=yes + shift elif [ x"$1" = x--standalone-install ]; then - shift - cheatsh_standalone_install "$@" - exit "$?" + shift + cheatsh_standalone_install "$@" + exit "$?" elif [ x"$1" = x--mode ]; then - shift - chtsh_mode "$@" - exit "$?" + shift + chtsh_mode "$@" + exit "$?" fi prompt="cht.sh" opts="" input="" for o; do - if [ x"$o" != x"${o#-}" ]; then - opts="${opts}${o#-}" - else - input="$input $o" - fi + if [ x"$o" != x"${o#-}" ]; then + opts="${opts}${o#-}" + else + input="$input $o" + fi done query=$(echo "$input" | sed 's@ *$@@; s@^ *@@; s@ @/@; s@ @+@g') if [ "$shell_mode" != yes ]; then - curl -s "${CHTSH_URL}"/"$(get_query_options "$query")" - exit 0 -else - new_section="$1" - valid_sections=$(get_list_of_sections) - valid=no; for q in $valid_sections; do [ "$q" = "$new_section/" ] && { valid=yes; break; }; done - - if [ "$valid" = yes ]; then - section="$new_section" - # shellcheck disable=SC2001 - this_query="$(echo "$input" | sed 's@ *[^ ]* *@@')" - this_prompt="\033[0;32mcht.sh/$section>\033[0m " - else - this_query="$input" - this_prompt="\033[0;32mcht.sh>\033[0m " - fi - if [ -n "$this_query" ] && [ -z "$CHEATSH_RESTART" ]; then - printf "$this_prompt$this_query\n" curl -s "${CHTSH_URL}"/"$(get_query_options "$query")" - fi + exit 0 +else + new_section="$1" + valid_sections=$(get_list_of_sections) + valid=no + for q in $valid_sections; do [ "$q" = "$new_section/" ] && { + valid=yes + break + }; done + + if [ "$valid" = yes ]; then + section="$new_section" + # shellcheck disable=SC2001 + this_query="$(echo "$input" | sed 's@ *[^ ]* *@@')" + this_prompt="\033[0;32mcht.sh/$section>\033[0m " + else + this_query="$input" + this_prompt="\033[0;32mcht.sh>\033[0m " + fi + if [ -n "$this_query" ] && [ -z "$CHEATSH_RESTART" ]; then + printf "$this_prompt$this_query\n" + curl -s "${CHTSH_URL}"/"$(get_query_options "$query")" + fi fi if [ "$is_macos" != yes ]; then - if [ "$XDG_SESSION_TYPE" = wayland ]; then - command -v wl-copy >/dev/null || echo 'DEPENDENCY: please install "wl-copy" for "copy"' >&2 - else - command -v xsel >/dev/null || echo 'DEPENDENCY: please install "xsel" for "copy"' >&2 - fi + if [ "$XDG_SESSION_TYPE" = wayland ]; then + command -v wl-copy >/dev/null || echo 'DEPENDENCY: please install "wl-copy" for "copy"' >&2 + else + command -v xsel >/dev/null || echo 'DEPENDENCY: please install "xsel" for "copy"' >&2 + fi fi -command -v rlwrap >/dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } +command -v rlwrap >/dev/null || { + echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2 + exit 1 +} mkdir -p "$CHTSH_HOME/" lines=$(tput lines) if command -v less >/dev/null; then - defpager="less -R" + defpager="less -R" elif command -v more >/dev/null; then - defpager="more" + defpager="more" else - defpager="cat" + defpager="cat" fi cmd_cd() { - if [ $# -eq 0 ]; then - section="" - else - new_section=$(echo "$input" | sed 's/cd *//; s@/*$@@; s@^/*@@') - if [ -z "$new_section" ] || [ ".." = "$new_section" ]; then - section="" + if [ $# -eq 0 ]; then + section="" else - valid_sections=$(get_list_of_sections) - valid=no; for q in $valid_sections; do [ "$q" = "$new_section/" ] && { valid=yes; break; }; done - if [ "$valid" = no ]; then - echo "Invalid section: $new_section" - echo "Valid sections:" - echo "$valid_sections" \ - | xargs printf "%-10s\n" \ - | tr ' ' . \ - | xargs -n 10 \ - | sed 's/\./ /g; s/^/ /' - else - section="$new_section" - fi + new_section=$(echo "$input" | sed 's/cd *//; s@/*$@@; s@^/*@@') + if [ -z "$new_section" ] || [ ".." = "$new_section" ]; then + section="" + else + valid_sections=$(get_list_of_sections) + valid=no + for q in $valid_sections; do [ "$q" = "$new_section/" ] && { + valid=yes + break + }; done + if [ "$valid" = no ]; then + echo "Invalid section: $new_section" + echo "Valid sections:" + echo "$valid_sections" | + xargs printf "%-10s\n" | + tr ' ' . | + xargs -n 10 | + sed 's/\./ /g; s/^/ /' + else + section="$new_section" + fi + fi fi - fi } cmd_copy() { - if [ -z "$DISPLAY" ]; then - echo copy: supported only in the Desktop version - elif [ -z "$input" ]; then - echo copy: Make at least one query first. - else - curl -s "${CHTSH_URL}"/"$(get_query_options "$query"?T)" > "$TMP1" - if [ "$is_macos" != yes ]; then - if [ "$XDG_SESSION_TYPE" = wayland ]; then - wl-copy < "$TMP1" - else - xsel -bi < "$TMP1" - fi + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + elif [ -z "$input" ]; then + echo copy: Make at least one query first. else - pbcopy < "$TMP1" + curl -s "${CHTSH_URL}"/"$(get_query_options "$query"?T)" >"$TMP1" + if [ "$is_macos" != yes ]; then + if [ "$XDG_SESSION_TYPE" = wayland ]; then + wl-copy <"$TMP1" + else + xsel -bi <"$TMP1" + fi + else + pbcopy <"$TMP1" + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" fi - echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" - fi } cmd_ccopy() { - if [ -z "$DISPLAY" ]; then - echo copy: supported only in the Desktop version - elif [ -z "$input" ]; then - echo copy: Make at least one query first. - else - curl -s "${CHTSH_URL}"/"$(get_query_options "$query"?TQ)" > "$TMP1" - if [ "$is_macos" != yes ]; then - if [ "$XDG_SESSION_TYPE" = wayland ]; then - wl-copy < "$TMP1" - else - xsel -bi < "$TMP1" - fi + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + elif [ -z "$input" ]; then + echo copy: Make at least one query first. else - pbcopy < "$TMP1" + curl -s "${CHTSH_URL}"/"$(get_query_options "$query"?TQ)" >"$TMP1" + if [ "$is_macos" != yes ]; then + if [ "$XDG_SESSION_TYPE" = wayland ]; then + wl-copy <"$TMP1" + else + xsel -bi <"$TMP1" + fi + else + pbcopy <"$TMP1" + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" fi - echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" - fi } cmd_exit() { - exit 0 + exit 0 } cmd_help() { - cat <<EOF + cat <<EOF help - show this help hush - do not show the 'help' string at start anymore cd LANG - change the language context @@ -623,138 +644,141 @@ EOF } cmd_hush() { - mkdir -p "$CHTSH_HOME/" && touch "$CHTSH_HOME/.hushlogin" && echo "Initial 'use help' message was disabled" + mkdir -p "$CHTSH_HOME/" && touch "$CHTSH_HOME/.hushlogin" && echo "Initial 'use help' message was disabled" } cmd_id() { - id_file="$CHTSH_HOME/id" + id_file="$CHTSH_HOME/id" - if [ id = "$input" ]; then - new_id="" - else - new_id=$(echo "$input" | sed 's/id *//; s/ *$//; s/ /+/g') - fi - if [ "$new_id" = remove ]; then - if [ -e "$id_file" ]; then - rm -f -- "$id_file" && echo "id is removed" + if [ id = "$input" ]; then + new_id="" else - echo "id was not set, so you can't remove it" + new_id=$(echo "$input" | sed 's/id *//; s/ *$//; s/ /+/g') fi - return - fi - if [ -n "$new_id" ] && [ reset != "$new_id" ] && [ "$(/bin/echo -n "$new_id" | wc -c)" -lt 16 ]; then - echo "ERROR: $new_id: Too short id. Minimal id length is 16. Use 'id reset' for a random id" - return - fi - if [ -z "$new_id" ]; then - # if new_id is not specified check if we have some id already - # if yes, just show it - # if not, generate a new id - if [ -e "$id_file" ]; then - awk '$6 == "id" {print $NF}' <"$id_file" | tail -n 1 - return + if [ "$new_id" = remove ]; then + if [ -e "$id_file" ]; then + rm -f -- "$id_file" && echo "id is removed" + else + echo "id was not set, so you can't remove it" + fi + return + fi + if [ -n "$new_id" ] && [ reset != "$new_id" ] && [ "$(/bin/echo -n "$new_id" | wc -c)" -lt 16 ]; then + echo "ERROR: $new_id: Too short id. Minimal id length is 16. Use 'id reset' for a random id" + return + fi + if [ -z "$new_id" ]; then + # if new_id is not specified check if we have some id already + # if yes, just show it + # if not, generate a new id + if [ -e "$id_file" ]; then + awk '$6 == "id" {print $NF}' <"$id_file" | tail -n 1 + return + else + new_id=reset + fi + fi + if [ "$new_id" = reset ]; then + new_id=$(gen_random_str 12) else - new_id=reset + echo WARNING: if someone gueses your id, he can read your cht.sh search history fi - fi - if [ "$new_id" = reset ]; then - new_id=$(gen_random_str 12) - else - echo WARNING: if someone gueses your id, he can read your cht.sh search history - fi - if [ -e "$id_file" ] && grep -q '\tid\t[^\t][^\t]*$' "$id_file" 2> /dev/null; then - sed -i 's/\tid\t[^\t][^\t]*$/ id '"$new_id"'/' "$id_file" - else - if ! [ -e "$id_file" ]; then - printf '#\n\n' > "$id_file" + if [ -e "$id_file" ] && grep -q '\tid\t[^\t][^\t]*$' "$id_file" 2>/dev/null; then + sed -i 's/\tid\t[^\t][^\t]*$/ id '"$new_id"'/' "$id_file" + else + if ! [ -e "$id_file" ]; then + printf '#\n\n' >"$id_file" + fi + printf ".cht.sh\tTRUE\t/\tTRUE\t0\tid\t$new_id\n" >>"$id_file" fi - printf ".cht.sh\tTRUE\t/\tTRUE\t0\tid\t$new_id\n" >> "$id_file" - fi - echo "$new_id" + echo "$new_id" } cmd_query() { - query=$(prepare_query "$section" "$input") - do_query "$query" + query=$(prepare_query "$section" "$input") + do_query "$query" } cmd_stealth() { - if [ "$input" != stealth ]; then - arguments=$(echo "$input" | sed 's/stealth //; s/ /\&/') - fi - trap break INT - if [ "$is_macos" = yes ]; then - past=$(pbpaste) - else - if [ "$XDG_SESSION_TYPE" = wayland ]; then - past=$(wl-paste -p) - else - past=$(xsel -o) + if [ "$input" != stealth ]; then + arguments=$(echo "$input" | sed 's/stealth //; s/ /\&/') fi - fi - printf "\033[0;31mstealth:\033[0m you are in the stealth mode; select any text in any window for a query\n" - printf "\033[0;31mstealth:\033[0m selections longer than $STEALTH_MAX_SELECTION_LENGTH words are ignored\n" - if [ -n "$arguments" ]; then - printf "\033[0;31mstealth:\033[0m query arguments: ?$arguments\n" - fi - printf "\033[0;31mstealth:\033[0m use ^C to leave this mode\n" - while true; do + trap break INT if [ "$is_macos" = yes ]; then - current=$(pbpaste) + past=$(pbpaste) else - if [ "$XDG_SESSION_TYPE" = wayland ]; then - current=$(wl-paste -p) - else - current=$(xsel -o) - fi + if [ "$XDG_SESSION_TYPE" = wayland ]; then + past=$(wl-paste -p) + else + past=$(xsel -o) + fi fi - if [ "$past" != "$current" ]; then - past=$current - current_text="$(echo $current | tr -c '[a-zA-Z0-9]' ' ')" - if [ "$(echo "$current_text" | wc -w)" -gt "$STEALTH_MAX_SELECTION_LENGTH" ]; then - printf "\033[0;31mstealth:\033[0m selection length is longer than $STEALTH_MAX_SELECTION_LENGTH words; ignoring\n" - continue - else - printf "\n\033[0;31mstealth: \033[7m $current_text\033[0m\n" - query=$(prepare_query "$section" "$current_text" "$arguments") - do_query "$query" - fi + printf "\033[0;31mstealth:\033[0m you are in the stealth mode; select any text in any window for a query\n" + printf "\033[0;31mstealth:\033[0m selections longer than $STEALTH_MAX_SELECTION_LENGTH words are ignored\n" + if [ -n "$arguments" ]; then + printf "\033[0;31mstealth:\033[0m query arguments: ?$arguments\n" fi - sleep 1; - done - trap - INT + printf "\033[0;31mstealth:\033[0m use ^C to leave this mode\n" + while true; do + if [ "$is_macos" = yes ]; then + current=$(pbpaste) + else + if [ "$XDG_SESSION_TYPE" = wayland ]; then + current=$(wl-paste -p) + else + current=$(xsel -o) + fi + fi + if [ "$past" != "$current" ]; then + past=$current + current_text="$(echo $current | tr -c '[a-zA-Z0-9]' ' ')" + if [ "$(echo "$current_text" | wc -w)" -gt "$STEALTH_MAX_SELECTION_LENGTH" ]; then + printf "\033[0;31mstealth:\033[0m selection length is longer than $STEALTH_MAX_SELECTION_LENGTH words; ignoring\n" + continue + else + printf "\n\033[0;31mstealth: \033[7m $current_text\033[0m\n" + query=$(prepare_query "$section" "$current_text" "$arguments") + do_query "$query" + fi + fi + sleep 1 + done + trap - INT } cmd_update() { - [ -w "$0" ] || { echo "The script is readonly; please update manually: curl -s ${CHTSH_URL}/:cht.sh | sudo tee $0"; return; } - TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) - curl -s "${CHTSH_URL}"/:cht.sh > "$TMP2" - if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then - if grep -q ^__CHTSH_VERSION= "$TMP2"; then - # section was vaildated by us already - args=(--shell "$section") - cp "$TMP2" "$0" && echo "Updated. Restarting..." && rm "$TMP2" && CHEATSH_RESTART=1 exec "$0" "${args[@]}" + [ -w "$0" ] || { + echo "The script is readonly; please update manually: curl -s ${CHTSH_URL}/:cht.sh | sudo tee $0" + return + } + TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) + curl -s "${CHTSH_URL}"/:cht.sh >"$TMP2" + if ! cmp "$0" "$TMP2" >/dev/null 2>&1; then + if grep -q ^__CHTSH_VERSION= "$TMP2"; then + # section was vaildated by us already + args=(--shell "$section") + cp "$TMP2" "$0" && echo "Updated. Restarting..." && rm "$TMP2" && CHEATSH_RESTART=1 exec "$0" "${args[@]}" + else + echo "Something went wrong. Please update manually" + fi else - echo "Something went wrong. Please update manually" + echo "cht.sh is up to date. No update needed" fi - else - echo "cht.sh is up to date. No update needed" - fi - rm -f "$TMP2" > /dev/null 2>&1 + rm -f "$TMP2" >/dev/null 2>&1 } cmd_version() { - insttime=$(ls -l -- "$0" | sed 's/ */ /g' | cut -d ' ' -f 6-8) - echo "cht.sh version $__CHTSH_VERSION of $__CHTSH_DATETIME; installed at: $insttime" - TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) - if curl -s "${CHTSH_URL}"/:cht.sh > "$TMP2"; then - if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then - echo "Update needed (type 'update' for that)". - else - echo "Up to date. No update needed" + insttime=$(ls -l -- "$0" | sed 's/ */ /g' | cut -d ' ' -f 6-8) + echo "cht.sh version $__CHTSH_VERSION of $__CHTSH_DATETIME; installed at: $insttime" + TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) + if curl -s "${CHTSH_URL}"/:cht.sh >"$TMP2"; then + if ! cmp "$0" "$TMP2" >/dev/null 2>&1; then + echo "Update needed (type 'update' for that)". + else + echo "Up to date. No update needed" + fi fi - fi - rm -f "$TMP2" > /dev/null 2>&1 + rm -f "$TMP2" >/dev/null 2>&1 } TMP1=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) @@ -762,35 +786,38 @@ trap 'rm -f $TMP1 $TMP2' EXIT trap 'true' INT if ! [ -e "$CHTSH_HOME/.hushlogin" ] && [ -z "$this_query" ]; then - echo "type 'help' for the cht.sh shell help" + echo "type 'help' for the cht.sh shell help" fi while true; do - if [ "$section" != "" ]; then - full_prompt="$prompt/$section> " - else - full_prompt="$prompt> " - fi + if [ "$section" != "" ]; then + full_prompt="$prompt/$section> " + else + full_prompt="$prompt> " + fi - input=$( - rlwrap -H "$CHTSH_HOME/history" -pgreen -C cht.sh -S "$full_prompt" bash "$0" --read | sed 's/ *#.*//' - ) + input=$( + rlwrap -H "$CHTSH_HOME/history" -pgreen -C cht.sh -S "$full_prompt" bash "$0" --read | sed 's/ *#.*//' + ) - cmd_name=${input%% *} - cmd_args=${input#* } - case $cmd_name in - "") continue;; # skip empty input lines - '?'|h|help) cmd_name=help;; - hush) cmd_name=hush;; - cd) cmd_name="cd";; - exit|quit) cmd_name="exit";; - copy|yank|c|y) cmd_name=copy;; - ccopy|cc|C|Y) cmd_name=ccopy;; - id) cmd_name=id;; - stealth) cmd_name=stealth;; - update) cmd_name=update;; - version) cmd_name=version;; - *) cmd_name="query"; cmd_args="$input";; - esac - "cmd_$cmd_name" $cmd_args + cmd_name=${input%% *} + cmd_args=${input#* } + case $cmd_name in + "") continue ;; # skip empty input lines + '?' | h | help) cmd_name=help ;; + hush) cmd_name=hush ;; + cd) cmd_name="cd" ;; + exit | quit) cmd_name="exit" ;; + copy | yank | c | y) cmd_name=copy ;; + ccopy | cc | C | Y) cmd_name=ccopy ;; + id) cmd_name=id ;; + stealth) cmd_name=stealth ;; + update) cmd_name=update ;; + version) cmd_name=version ;; + *) + cmd_name="query" + cmd_args="$input" + ;; + esac + "cmd_$cmd_name" $cmd_args done diff --git a/common/.local/bin/opener b/common/.local/bin/opener index 38dd7313..4463f223 100755 --- a/common/.local/bin/opener +++ b/common/.local/bin/opener @@ -1,5 +1,4 @@ #!/bin/sh -# shellcheck disable=2154 term= [ -n "$SCRATCHPAD" ] && { diff --git a/common/.local/bin/openproject_hours b/common/.local/bin/openproject_hours index 4abde03a..9e2bfcbc 100755 --- a/common/.local/bin/openproject_hours +++ b/common/.local/bin/openproject_hours @@ -1,5 +1,4 @@ #!/bin/sh -# shellcheck disable=2089,2090 year=$1 month=$2 @@ -25,12 +24,12 @@ filters='[ ]' curl -s \ - -u "apikey:${API_KEY}" \ - -G "${API_URL}/api/v3/time_entries" \ - --data-urlencode "filters=${filters}" \ - --data-urlencode "pageSize=${PAGE_SIZE}" | - jq -r '._embedded.elements | map(.hours) | join(" ")' | - awk '{ + -u "apikey:${API_KEY}" \ + -G "${API_URL}/api/v3/time_entries" \ + --data-urlencode "filters=${filters}" \ + --data-urlencode "pageSize=${PAGE_SIZE}" | + jq -r '._embedded.elements | map(.hours) | join(" ")' | + awk '{ gsub(/PT/, ""); gsub(/H/, "H "); gsub(/M/, "M ");