From c67fb616625b112623d44d716070c523030aa706 Mon Sep 17 00:00:00 2001 From: Vadim Zhukov Date: Tue, 10 Jul 2018 22:20:36 +0300 Subject: [PATCH 01/19] Make cht.sh work under POSIX environment. There are a few corner cases still, but normal desktop users should be satisfied on almost any *nix now. Verified with bash, ksh (OpenBSD) and dash. --- share/cht.sh.txt | 126 ++++++++++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 46 deletions(-) diff --git a/share/cht.sh.txt b/share/cht.sh.txt index b1b99fe..175dc39 100755 --- a/share/cht.sh.txt +++ b/share/cht.sh.txt @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh # # [X] open section # [X] one shot mode @@ -8,7 +8,7 @@ # [X] yank/y/copy/c # [X] Y/C # [X] eof problem -# [X] less +# [X] more # [X] stealth mode # # here are several examples for the stealth mode: @@ -38,30 +38,30 @@ get_query_options() { local query="$*" if [ -n "$CHTSH_QUERY_OPTIONS" ]; then - if [[ $query == *\?* ]]; then - query="$query&${CHTSH_QUERY_OPTIONS}" - else - query="$query?${CHTSH_QUERY_OPTIONS}" - fi + case $query in + *\?*) query="$query&${CHTSH_QUERY_OPTIONS}";; + *) query="$query?${CHTSH_QUERY_OPTIONS}";; + esac fi - echo "$query" + printf "%s" "$query" } do_query() { local query="$*" - local b_opts=() + local b_opts= + local uri="https://cht.sh/\"\$(get_query_options $query)\"" if [ -e "$HOME/.cht.sh/id" ]; then - b_opts=(-b "$HOME/.cht.sh/id") + b_opts="-b \"\$HOME/.cht.sh/id\"" fi - curl "${b_opts[@]}" -s https://cht.sh/"$(get_query_options $query)" > "$TMP1" + eval curl $b_opts -s $uri > "$TMP1" if [ -z "$lines" ] || [ "$(wc -l "$TMP1" | awk '{print $1}')" -lt "$lines" ]; then cat "$TMP1" else - less -R "$TMP1" + ${PAGER:-$defpager} "$TMP1" fi } @@ -69,17 +69,17 @@ prepare_query() { local section="$1"; shift local input="$1"; shift - local arguments="$1"; shift + local arguments="$1" local query - if [ -z "$section" ] || [[ "$input" = /* ]]; then - query=$(echo "$input" | sed 's@ @/@; s@ @+@g') + if [ -z "$section" ] || [ x"${input}" != x"${input#/}" ]; then + query=$(printf %s "$input" | sed 's@ @/@; s@ @+@g') else - query=$(echo "$section/$input" | sed 's@ @+@g') + query=$(printf %s "$section/$input" | sed 's@ @+@g') fi [ -n "$arguments" ] && arguments="?$arguments" - echo "$query$arguments" + printf %s "$query$arguments" } get_list_of_sections() @@ -87,16 +87,41 @@ get_list_of_sections() curl -s https://cht.sh/:list | grep -v '/.*/' | grep '/$' } +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 $dev | awk -v ORS='' // + else + cd /tmp + s= + while [ $(echo "$s" | wc -c) -lt $len ]; do + s="$s$(mktemp -u XXXXXXXXXX)" + done + printf %.${len}s "$s" + fi + fi +) + if [ -e "$HOME"/.cht.sh/cht.sh.conf ]; then # shellcheck disable=SC1090,SC2002 - source <( cat "$HOME"/.cht.sh/cht.sh.conf | sed 's/#.*//' | grep -xv '' | sed s/^/CHTSH_/ ) >& /dev/null + . "$HOME"/.cht.sh/cht.sh.conf fi -if [ "$1" == --read ]; then +if [ "$1" = --read ]; then read -r a || a=exit - echo $a + printf "%s\n" "$a" exit 0 -elif [ "$1" == --help ] || [ -z "$1" ]; then +elif [ x"$1" = x--help ] || [ -z "$1" ]; then cat <& /dev/null || { echo 'DEPENDENCY: please install "xsel" for "copy"' >&2; } + command -v xsel >/dev/null || echo 'DEPENDENCY: please install "xsel" for "copy"' >&2 fi -which rlwrap >& /dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } -which curl >& /dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } +command -v rlwrap >/dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } +command -v curl >/dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } mkdir -p "$HOME/.cht.sh/" lines=$(tput lines) +if command -v less >/dev/null; then + defpager="less -R" +elif command -v more >/dev/null; then + defpager=more +else + defpager=cat +fi + TMP1=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) trap 'rm -f $TMP1 $TMP2' EXIT trap 'true' INT @@ -171,7 +204,7 @@ while true; do fi input=$( - rlwrap -H $HOME/.cht.sh/history -pgreen -C cht.sh -S "$full_prompt" bash "$0" --read | sed 's/ *#.*//' + rlwrap -H "$HOME/.cht.sh/history" -pgreen -C cht.sh -S "$full_prompt" sh "$0" --read | sed 's/ *#.*//' ) case "$input" in @@ -204,12 +237,12 @@ EOF continue ;; "cd "*) - new_section=$(echo "$input" | sed 's/cd //; s/ .*//; s@/\+$@@; s@^/\+@@') - if [ "$new_section" = "" ] || [ "$new_section" = ".." ] || [ "$new_section" = / ]; then + 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 + 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:" @@ -265,20 +298,20 @@ EOF id|"id "*) id_file="$HOME/.cht.sh/id" - if [ "$input" = id ]; then + if [ id = "$input" ]; then new_id="" else - new_id=$(echo "$input" | sed 's/id \+//; s/ *$//; s/ /+/g') + 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" + rm -f -- "$id_file" && echo "id is removed" else echo "id was not set, so you can't remove it" fi continue fi - if [ -n "$new_id" ] && [ "$new_id" != reset ] && [ "$(echo $new_id | wc -c)" -lt 16 ]; then + 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" continue fi @@ -287,19 +320,19 @@ EOF # if yes, just show it # if not, generate a new id if [ -e "$id_file" ]; then - echo $(cat "$id_file" | awk '{if ($6 == "id") print $NF}' | head -1) + echo $(awk '$6 == "id" {print $NF}' <"$id_file" | tail -n 1) continue else new_id=reset fi fi if [ "$new_id" = reset ]; then - new_id="$(cat /dev/urandom 2> /dev/null | env LC_CTYPE=C tr -cd 'a-f0-9' 2> /dev/null | head -c 32)" + 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]\+$' "$id_file" 2> /dev/null; then - sed -i 's/\tid\t[^\t]\+$/ id '"$new_id"'/' "$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" @@ -354,9 +387,9 @@ EOF curl -s https://cht.sh/:cht.sh > "$TMP2" if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then if grep -q ^__CHTSH_VERSION= "$TMP2"; then - args=(--shell) - [ -n "$section" ] && args=("${args[@]}" "$section") - cp "$TMP2" "$0" && echo "Updated. Restarting..." && rm "$TMP2" && CHEATSH_RESTART=1 exec "$0" "${args[@]}" + # 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 @@ -367,7 +400,8 @@ EOF continue ;; version) - echo "cht.sh version $__CHTSH_VERSION of $__CHTSH_DATETIME; installed at: $(stat -c %y "$0" | sed 's@\..* @ @')" + insttime=$(ls -lT -- "$0" | sed 's/ / /g' | cut -d ' ' -f 6-9) + echo "cht.sh version $__CHTSH_VERSION of $__CHTSH_DATETIME; installed at: $insttime" TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) if curl -s https://cht.sh/:cht.sh > "$TMP2"; then if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then From 56b28daf4ac6e41a5fe6b960a79233bd9f42fcf1 Mon Sep 17 00:00:00 2001 From: Vadim Zhukov Date: Wed, 11 Jul 2018 11:36:38 +0300 Subject: [PATCH 02/19] Missed non-POSIX array expansion. --- share/cht.sh.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/cht.sh.txt b/share/cht.sh.txt index 175dc39..e42d899 100755 --- a/share/cht.sh.txt +++ b/share/cht.sh.txt @@ -246,7 +246,7 @@ EOF 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/^/ /' + echo $valid_sections | xargs printf "%-10s\n" | tr ' ' . | xargs -n 10 | sed 's/\./ /g; s/^/ /' continue else section="$new_section" From 3f16075d8992f3a84a68fc640dc6e7138412d5d1 Mon Sep 17 00:00:00 2001 From: Vadim Zhukov Date: Wed, 11 Jul 2018 11:37:07 +0300 Subject: [PATCH 03/19] The ksh93 shell doesn't have "local", but "typeset" could be used instead. --- share/cht.sh.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/share/cht.sh.txt b/share/cht.sh.txt index e42d899..7e1fa95 100755 --- a/share/cht.sh.txt +++ b/share/cht.sh.txt @@ -34,6 +34,11 @@ case "$OSTYPE" in *) is_macos=no ;; esac +# for KSH93 +if ! local foo 2>/dev/null; then + alias local=typeset +fi + get_query_options() { local query="$*" From 417f91119082a47d279dd2d8833cfd2ca6df5c6f Mon Sep 17 00:00:00 2001 From: Vadim Zhukov Date: Wed, 11 Jul 2018 11:37:54 +0300 Subject: [PATCH 04/19] Make zsh happy as well (in sh mode). --- share/cht.sh.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/cht.sh.txt b/share/cht.sh.txt index 7e1fa95..a7dcb89 100755 --- a/share/cht.sh.txt +++ b/share/cht.sh.txt @@ -89,7 +89,7 @@ prepare_query() get_list_of_sections() { - curl -s https://cht.sh/:list | grep -v '/.*/' | grep '/$' + curl -s https://cht.sh/:list | grep -v '/.*/' | grep '/$' | xargs } gen_random_str() From ada92527301e63e412c67530ae20822adb4aa561 Mon Sep 17 00:00:00 2001 From: Vadim Zhukov Date: Thu, 19 Jul 2018 16:48:50 +0300 Subject: [PATCH 05/19] ls -T isn't portable as well, as pointed out by pickfire@. Since we don't really use timestamp for anything except direct display, just extract fields 6-8 from "ls -l" output and be done with it. --- share/cht.sh.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/cht.sh.txt b/share/cht.sh.txt index a7dcb89..86afd70 100755 --- a/share/cht.sh.txt +++ b/share/cht.sh.txt @@ -405,7 +405,7 @@ EOF continue ;; version) - insttime=$(ls -lT -- "$0" | sed 's/ / /g' | cut -d ' ' -f 6-9) + 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 https://cht.sh/:cht.sh > "$TMP2"; then From 35155337c1d9e5a185250ed74f4a6f941fa0be02 Mon Sep 17 00:00:00 2001 From: Luciano Strika Date: Thu, 19 Jul 2018 17:49:13 -0300 Subject: [PATCH 06/19] refactor reverse palette for legibility and abstraction --- lib/colorize_internal.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/colorize_internal.py b/lib/colorize_internal.py index 746efc9..c19f71c 100644 --- a/lib/colorize_internal.py +++ b/lib/colorize_internal.py @@ -26,29 +26,29 @@ PALETTES = { }, } -PALETTES_REVERSE = { - 0: { - 1: Back.WHITE + Fore.BLACK, - 2: Style.DIM, - }, - 1: { - 1: Back.CYAN + Fore.BLACK, - 2: Style.DIM, - }, - 2: { - 1: Back.RED + Fore.BLACK, - 2: Style.DIM, - }, -} +def _reverse_palette(code): + return { + 1 : Fore.BLACK + _back_color(code), + 2 : Style.DIM + } + +def _back_color(code): + if code == 0 or code.lower()=="white": + return Back.WHITE + if code == 1 or code.lower()=="cyan": + return Back.WHITE + if code == 2 or code.lower()=="red": + return Back.WHITE + def colorize_internal(text, palette_number=1): """ Colorize `text`, use `palette` """ palette = PALETTES[palette_number] - palette_reverse = PALETTES_REVERSE[palette_number] + palette_reverse = _reverse_palette(palette_number) def _colorize_curlies_block(text): From 7d20c45ac57e740e14d68a8d7789d8d0cd51b36a Mon Sep 17 00:00:00 2001 From: Luciano Strika Date: Thu, 19 Jul 2018 17:49:48 -0300 Subject: [PATCH 07/19] remove unnecessary boolean assignment --- lib/colorize_internal.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/colorize_internal.py b/lib/colorize_internal.py index c19f71c..aebe564 100644 --- a/lib/colorize_internal.py +++ b/lib/colorize_internal.py @@ -31,7 +31,7 @@ PALETTES = { def _reverse_palette(code): return { 1 : Fore.BLACK + _back_color(code), - 2 : Style.DIM + 2 : Style.DIM } def _back_color(code): @@ -62,10 +62,9 @@ def colorize_internal(text, palette_number=1): if stripped.startswith('='): stripped = stripped[1:] - reverse = False - if color_number < 0: + reverse = (color_number < 0) + if reverse: color_number = -color_number - reverse = True if reverse: stripped = palette_reverse[color_number] + stripped + Style.RESET_ALL From e4d7fde7cf858986a5d809dd6edc098947924547 Mon Sep 17 00:00:00 2001 From: Luciano Strika Date: Thu, 19 Jul 2018 17:59:55 -0300 Subject: [PATCH 08/19] replace back color names --- lib/colorize_internal.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/colorize_internal.py b/lib/colorize_internal.py index aebe564..363ff46 100644 --- a/lib/colorize_internal.py +++ b/lib/colorize_internal.py @@ -38,9 +38,9 @@ def _back_color(code): if code == 0 or code.lower()=="white": return Back.WHITE if code == 1 or code.lower()=="cyan": - return Back.WHITE + return Back.CYAN if code == 2 or code.lower()=="red": - return Back.WHITE + return Back.RED def colorize_internal(text, palette_number=1): """ @@ -51,7 +51,6 @@ def colorize_internal(text, palette_number=1): palette_reverse = _reverse_palette(palette_number) def _colorize_curlies_block(text): - text = text.group()[1:-1] factor = 1 if text.startswith('-'): From 7201ce42517a82e27dd3f80d856f7eac94bcfe49 Mon Sep 17 00:00:00 2001 From: Luciano Strika Date: Thu, 19 Jul 2018 18:06:28 -0300 Subject: [PATCH 09/19] clean up colorizer --- lib/colorize_internal.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/colorize_internal.py b/lib/colorize_internal.py index 363ff46..2e7dd41 100644 --- a/lib/colorize_internal.py +++ b/lib/colorize_internal.py @@ -49,15 +49,22 @@ def colorize_internal(text, palette_number=1): palette = PALETTES[palette_number] palette_reverse = _reverse_palette(palette_number) - - def _colorize_curlies_block(text): + def _process_text(text): text = text.group()[1:-1] factor = 1 if text.startswith('-'): text = text[1:] factor = -1 stripped = text.lstrip('0123456789') - color_number = int(text[:len(text)-len(stripped)])*factor + return (text, stripped, factor) + + def _extract_color_number(text,stripped,factor = 1): + return int(text[:len(text)-len(stripped)])*factor + + def _colorize_curlies_block(text): + text, stripped, factor = _process_text(text) + color_number = _extract_color_number(text,stripped,factor) + if stripped.startswith('='): stripped = stripped[1:] From 604edfb7f789239df65deb29f5de5738bb01676c Mon Sep 17 00:00:00 2001 From: cclauss Date: Tue, 31 Jul 2018 00:04:15 +0200 Subject: [PATCH 10/19] import os to access os.path.join() flake8 testing of https://github.com/chubin/cheat.sh on Python 3.7.0 $ __flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics__ ``` ./lib/panela/panela_colors.py:636:16: F821 undefined name 'os' pagepath = os.join.path(MYDIR, "share/firstpage-v2.pnl") ^ 1 F821 undefined name 'os' 1 ``` --- lib/panela/panela_colors.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/panela/panela_colors.py b/lib/panela/panela_colors.py index ad5cd76..00bf58b 100644 --- a/lib/panela/panela_colors.py +++ b/lib/panela/panela_colors.py @@ -1,5 +1,6 @@ # vim: encoding=utf-8 +import os import sys import colored import itertools @@ -633,7 +634,7 @@ class Template(object): def main(): "Only for experiments" - pagepath = os.join.path(MYDIR, "share/firstpage-v2.pnl") + pagepath = os.path.join(MYDIR, "share/firstpage-v2.pnl") template = Template() template.read(pagepath) template.apply_mask() From 365c69dc19bade777f0f8a2b228edb30efebcd3a Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Thu, 2 Aug 2018 07:27:50 +0000 Subject: [PATCH 11/19] fixed typo in intro.txt (fixes #63) --- share/intro.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/intro.txt b/share/intro.txt index cc8a9bf..7138588 100644 --- a/share/intro.txt +++ b/share/intro.txt @@ -163,7 +163,7 @@ can use TAB completion when writing its queries in {1bash} Install the TAB completion script for that. Assuming you use bash, you have to do: - {1mkdir -p ~/.bash.d/cht.sh} + {1mkdir -p ~/.bash.d/} {1curl} {2https://cht.sh/:bash_completion} {1> ~/.bash.d/cht.sh} {1echo 'source ~/.bash.d/cht.sh' >> ~/.bashrc} {1source ~/.bash.d/cht.sh} From faa8c186871e1b164a4e12123bd872e18525cd9c Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Fri, 3 Aug 2018 07:37:18 +0000 Subject: [PATCH 12/19] added initial tests --- tests/results/0 | 16 ++ tests/results/1 | 17 ++ tests/results/10 | 3 + tests/results/11 | 3 + tests/results/12 | 32 ++++ tests/results/13 | 32 ++++ tests/results/2 | 17 ++ tests/results/3 | 54 +++++++ tests/results/4 | 3 + tests/results/5 | 216 +++++++++++++++++++++++++ tests/results/6 | 85 ++++++++++ tests/results/7 | 389 +++++++++++++++++++++++++++++++++++++++++++++ tests/results/8 | 16 ++ tests/results/9 | 16 ++ tests/run-tests.sh | 22 +++ tests/tests.txt | 14 ++ 16 files changed, 935 insertions(+) create mode 100644 tests/results/0 create mode 100644 tests/results/1 create mode 100644 tests/results/10 create mode 100644 tests/results/11 create mode 100644 tests/results/12 create mode 100644 tests/results/13 create mode 100644 tests/results/2 create mode 100644 tests/results/3 create mode 100644 tests/results/4 create mode 100644 tests/results/5 create mode 100644 tests/results/6 create mode 100644 tests/results/7 create mode 100644 tests/results/8 create mode 100644 tests/results/9 create mode 100644 tests/run-tests.sh create mode 100644 tests/tests.txt diff --git a/tests/results/0 b/tests/results/0 new file mode 100644 index 0000000..824872d --- /dev/null +++ b/tests/results/0 @@ -0,0 +1,16 @@ +1line +doc +func +hello +lambda +loops +recursion +Primitive_Datatypes_and_Operators +Variables_and_Collections +Control_Flow +Functions +Classes +Modules +Advanced +Comments +:learn diff --git a/tests/results/1 b/tests/results/1 new file mode 100644 index 0000000..7b1f52f --- /dev/null +++ b/tests/results/1 @@ -0,0 +1,17 @@ +# Displays everything in the target directory +ls path/to/the/target/directory + +# Displays everything including hidden files +ls -a + +# Displays all files, along with the size (with unit suffixes) and timestamp +ls -lh  + +# Display files, sorted by size +ls -S + +# Display directories only +ls -d */ + +# Display directories only, include hidden +ls -d .*/ */ diff --git a/tests/results/10 b/tests/results/10 new file mode 100644 index 0000000..d0db3d4 --- /dev/null +++ b/tests/results/10 @@ -0,0 +1,3 @@ +from shutil import copyfile + +copyfile(src, dst) diff --git a/tests/results/11 b/tests/results/11 new file mode 100644 index 0000000..7c53265 --- /dev/null +++ b/tests/results/11 @@ -0,0 +1,3 @@ +from shutil import copyfile + +copyfile(src, dst) diff --git a/tests/results/12 b/tests/results/12 new file mode 100644 index 0000000..8794df4 --- /dev/null +++ b/tests/results/12 @@ -0,0 +1,32 @@ + _ _ _ __    + ___| |__ ___ __ _| |_ ___| |__ \ \      The only cheat sheet you need    + / __| '_ \ / _ \/ _` | __| / __| '_ \ \ \  Unified access to the best     +| (__| | | | __/ (_| | |_ _\__ \ | | |/ /  community driven documentation + \___|_| |_|\___|\__,_|\__(_)___/_| |_/_/   repositories of the world      + ++------------------------+ +------------------------+ +------------------------+ +| $ curl cheat.sh/ls     | | $ cht.sh btrfs         | | $ cht.sh lua/:learn | +| $ curl cht.sh/btrfs    | | $ cht.sh tar~list      | | Learn any* programming | +| $ curl cht.sh/tar~list | | | | language not leaving | +| $ curl https://cht.sh  | | | | your shell | +| | | | | *) any of 60 | +| | | | | | ++-- queries with curl ---+ +- own optional client --+ +- learn, learn, learn! -+ ++------------------------+ +------------------------+ +------------------------+ +| $ cht.sh go/f<tab><tab>| | $ cht.sh --shell | | $ cht.sh go zip lists | +| go/for go/func | | cht.sh> help | | Ask any question using | +| $ cht.sh go/for | | ... | | cht.sh or curl cht.sh: | +| ... | | | | /go/zip+lists | +| | | | | (use /,+ when curling) | +| | | | | | ++---- TAB-completion ----+ +-- interactive shell ---+ +- programming questions-+ ++------------------------+ +------------------------+ +------------------------+ +| $ curl cht.sh/:help | | $ vim prg.py | | $ time curl cht.sh/ | +| see /:help and /:intro | | ... | | ... | +| for usage information | | zip lists _ | | real 0m0.075s | +| and README.md on GitHub| | <leader>KK | | | +| for the details | | *awesome* | | | +| *start here*| | | | | ++--- self-documented ----+ +- queries from editor! -+ +---- instant answers ---+ + +[Follow @igor_chubin for updates][github.com/chubin/cheat.sh] diff --git a/tests/results/13 b/tests/results/13 new file mode 100644 index 0000000..8794df4 --- /dev/null +++ b/tests/results/13 @@ -0,0 +1,32 @@ + _ _ _ __    + ___| |__ ___ __ _| |_ ___| |__ \ \      The only cheat sheet you need    + / __| '_ \ / _ \/ _` | __| / __| '_ \ \ \  Unified access to the best     +| (__| | | | __/ (_| | |_ _\__ \ | | |/ /  community driven documentation + \___|_| |_|\___|\__,_|\__(_)___/_| |_/_/   repositories of the world      + ++------------------------+ +------------------------+ +------------------------+ +| $ curl cheat.sh/ls     | | $ cht.sh btrfs         | | $ cht.sh lua/:learn | +| $ curl cht.sh/btrfs    | | $ cht.sh tar~list      | | Learn any* programming | +| $ curl cht.sh/tar~list | | | | language not leaving | +| $ curl https://cht.sh  | | | | your shell | +| | | | | *) any of 60 | +| | | | | | ++-- queries with curl ---+ +- own optional client --+ +- learn, learn, learn! -+ ++------------------------+ +------------------------+ +------------------------+ +| $ cht.sh go/f<tab><tab>| | $ cht.sh --shell | | $ cht.sh go zip lists | +| go/for go/func | | cht.sh> help | | Ask any question using | +| $ cht.sh go/for | | ... | | cht.sh or curl cht.sh: | +| ... | | | | /go/zip+lists | +| | | | | (use /,+ when curling) | +| | | | | | ++---- TAB-completion ----+ +-- interactive shell ---+ +- programming questions-+ ++------------------------+ +------------------------+ +------------------------+ +| $ curl cht.sh/:help | | $ vim prg.py | | $ time curl cht.sh/ | +| see /:help and /:intro | | ... | | ... | +| for usage information | | zip lists _ | | real 0m0.075s | +| and README.md on GitHub| | <leader>KK | | | +| for the details | | *awesome* | | | +| *start here*| | | | | ++--- self-documented ----+ +- queries from editor! -+ +---- instant answers ---+ + +[Follow @igor_chubin for updates][github.com/chubin/cheat.sh] diff --git a/tests/results/2 b/tests/results/2 new file mode 100644 index 0000000..41a116a --- /dev/null +++ b/tests/results/2 @@ -0,0 +1,17 @@ +# Displays everything in the target directory +ls path/to/the/target/directory + +# Displays everything including hidden files +ls -a + +# Displays all files, along with the size (with unit suffixes) and timestamp +ls -lh + +# Display files, sorted by size +ls -S + +# Display directories only +ls -d */ + +# Display directories only, include hidden +ls -d .*/ */ diff --git a/tests/results/3 b/tests/results/3 new file mode 100644 index 0000000..10b9309 --- /dev/null +++ b/tests/results/3 @@ -0,0 +1,54 @@ +# Create a btrfs file system on /dev/sdb, /dev/sdc, and /dev/sdd +mkfs.btrfs /dev/sdb /dev/sdc /dev/sdd + +# btrfs with just one hard drive, metadata not redundant  +# (this is danegerous: if your metadata is lost, your data is lost as well) +mkfs.btrfs -m single /dev/sdb + +# data to be redundant and metadata to be non-redundant: +mkfs.btrfs -m raid0 -d raid1 /dev/sdb /dev/sdc /dev/sdd + +# both data and metadata to be redundan +mkfs.btrfs -d raid1 /dev/sdb /dev/sdc /dev/sdd + +# To get a list of all btrfs file systems +btrfs filesystem show + +# detailed df for a fileesystem (mounted in /mnt) +btrfs filesystem df /mnt + +# resize btrfs online (-2g decreases, +2g increases) +btrfs filesystem resize -2g /mnt + +# use maximum space +btrfs filesystem resize max /mnt + +# add new device to a filesystem +btrfs device add /dev/sdf /mnt + +# remove devices from a filesystem +btrfs device delete missing /mnt + +# create the subvolume /mnt/sv1 in the /mnt volume +btrfs subvolume create /mnt/sv1 + +# list subvolumes +btrfs subvolume list /mnt + +# mount subvolume without mounting the main filesystem +mount -o subvol=sv1 /dev/sdb /mnt + +# delete subvolume +btrfs subvolume delete /mnt/sv1 + +# taking snapshot of a subvolume +btrfs subvolume snapshot /mnt/sv1 /mnt/sv1_snapshot + +# taking snapshot of a file (copy file by reference) +cp --reflink /mnt/sv1/test1 /mnt/sv1/test3 + +# convert ext3/ext4 to btrfs +btrfs-convert /dev/sdb1 + +# convert btrfs to ext3/ext4 +btrfs-convert -r /dev/sdb1 diff --git a/tests/results/4 b/tests/results/4 new file mode 100644 index 0000000..317da29 --- /dev/null +++ b/tests/results/4 @@ -0,0 +1,3 @@ + btrfs  +# create the subvolume /mnt/sv1 in the /mnt volume +btrfs subvolume create /mnt/sv1 diff --git a/tests/results/5 b/tests/results/5 new file mode 100644 index 0000000..0b9624b --- /dev/null +++ b/tests/results/5 @@ -0,0 +1,216 @@ +## curl cht.sh + +To access a cheat sheet you can simply issue a plain HTTP or HTTPS request +specifying the topic name in the query URL: + + curl cheat.sh/tar + curl https://cheat.sh/tar + +You can use the full service name, cheat.sh, or the shorter variant, cht.sh. +They are equivalent: + + curl https://cht.sh/tar + curl https://cheat.sh/tar + +The preferred access protocol is HTTPS, and you should use it always when possible. + +Cheat sheets in the root namespaces cover UNIX/Linux commands. + +Cheat sheets covering programming languages are located in subsections: + + curl cht.sh/go/func + +All cheat sheets in a subsection can be listed using a special query :list : + + curl cht.sh/go/:list + +There are several other special queries. All of them are starting with a colon. +See /:help for the full list of the special queries. + + +## Search + +If a cheat sheet is too large, you can cut the needed part out using an +additional search parameter. In this case, only the paragraph that contains the +search term will be displayed: + + curl cht.sh/tar~extract + +If the name of the cheat sheet is omitted, and only the serch query is specified, +all cheat sheets in the namespace are scanned, and the found occurrencies +are displayed: + + curl cht.sh/~extract + + +## Options + +cheat.sh queries as well as search queries have many options. +They can be specified as a part of the query string in the URL, after ?. +Short single letter options could be written all jointly together, +and long options are separated with &. For example, to switch +syntax highlighting off the T switch is used: + + curl cht.sh/tar?T + +Full list of all available cheat.sh options as well as description of all modes +of operation can be found in /:help, + + curl cht.sh/:help + + +## cht.sh client + +Though it's perfectly possible to access cheat.sh using curl (or any other +HTTP client) alone, there is a special client, that has several advantages +comparing to plain curling: cht.sh. + +To install the client in ~/bin: + + curl https://cht.sh/:cht.sh > ~/bin/cht.sh + chmod +x ~/bin/cht.sh + +Queries look the same, but you can separate words in the query with spaces, +instead of + as when using curl, what looks more natural: + + cht.sh python zip lists + + +## cht.sh shell + +If you always issuing queries about the same programming language, it's can be +more convenient to run the client in the shell mode and specify the queries +context: + + $ cht.sh --shell python + cht.sh/python> zip lists + +Of course, you can start the shell without the context too: + + $ cht.sh --shell + cht.sh> python zip lists + cht.sh> go http query + cht.sh> js iterate list + +If you ue predominantly one language but sometime issuing queries about other, +you may prepend the query with /: + + cht.sh/python> zip lists + cht.sh/python> /go http query + cht.sh/python> /js iterate list + + +## :learn + +If you are just start learning a new programming language, and you have no +distinct queries for the moment, cheat.sh can be a good starting point too. As +you know, it exports cheat sheets from the best cheat sheet repositories, and +one of them is Learn X in Y, a repository of concise documentation devoted +to learning programming languages from scratch (and not only them). + +If you want start learning a new programming language, do (use less -R because +the output could be quite big): + + curl cht.sh/elixir/:learn | less -R + +Or simply :learn with cht.sh (you don't need less -R here, because +cht.sh starts pager if needed automatically): + + cht.sh/elixir> :learn + + +## Programming languages questions + +One of the most important features of cheat.sh is that you can ask it any +questions about programming languages and instantly get answers on them. You +can use both direct HTTP queries or the cht.sh client for that: + + curl cht.sh/python/reverse+list + + cht.sh/python> reverse list + +In the latter case you don't need + to separate the words in the query, you can +do it in a more natural way, with spaces. + +If context in the cht.sh shell is not specified, you have to write the +programming language name as the first word in the query: + + cht.sh> python reverse list + +But if you are using only one programming language and all queries are about +it, it's better to change the current context and + + +## Comments + +Text in the answers is syntactically formatted as comment in the correspondent +programming language + +When using cht.sh, you can copy the result of the last query into the selection +buffer (you may also call it "clibpoard") using C (or c, with text): + + cht.sh/python> reverse list + ... + cht.sh/python> C + 1 lines copied + + +## bash TAB-completion for cht.sh + +One of the advantages of the cht.sh client comparing to plain curl is that you +can use TAB completion when writing its queries in bash +(other supported shells: zsh and fish). + +Install the TAB completion script for that. Assuming you use bash, you have to do: + + mkdir -p ~/.bash.d/ + curl https://cht.sh/:bash_completion > ~/.bash.d/cht.sh + echo 'source ~/.bash.d/cht.sh' >> ~/.bashrc + source ~/.bash.d/cht.sh + + +## Editor + +You can access cheat.sh directly from editors: Vim and Emacs. +It's a very important feature! You should absolutely like it. + +Imagine: +instead of switching to your browser, googling, browsing Stack Overflow +and eventually copying the code snippets you need and later pasting them into +the editor, you can achieve the same instantly and without leaving +the editor at all! + +Here is how it looks like: + +1. In Vim, if you have a question while editing a program, you can just type +your question directly in the buffer and press KK. You will get +the answer to your question in pager. (with KB you'll get the answer +in a separate buffer). + +2. If you like the answer. You can manually paste it from the buffer or +the pager, or if you are lazy you can use KP to paste it under +your question (KR will replace your question). If you want the +answer without the comments, KC replays the last query +toggling them. + +You have to install cheat.sh Vim/Emacs plugins for the editor support. +See /:vim or /:emacs with the detailed installation instructions. + + +## Feature requests, feedback and contribution + +If you want to submit a new community driver repository for cheat.sh please +open a ticket on the project page on GitHub. + +If you want to modify an existing cheat sheet, please check the source of the +cheat sheet (it is always displayed in the cheat sheet bottom line). + +If you want to add a new cheat sheet, add it here: +https://github.com/chubin/cheat.sheets + +If you want to suggest a new feature for cheat.sh, or if you've found a bug, +please open a new issue on github: +https://github.com/chubin/cheat.sh + +If you want to get the major project updates, follow @igor_chubin in Twitter +or this RSS feed: https://twitrss.me/twitter_user_to_rss/?user=igor_chubin diff --git a/tests/results/6 b/tests/results/6 new file mode 100644 index 0000000..4072487 --- /dev/null +++ b/tests/results/6 @@ -0,0 +1,85 @@ +Usage: + + $ curl cheat.sh/TOPIC show cheat sheet on the TOPIC + $ curl cheat.sh/TOPIC/SUB show cheat sheet on the SUB topic in TOPIC + $ curl cheat.sh/~KEYWORD search cheat sheets for KEYWORD + +Options: + + ?OPTIONS + + q quiet mode, don't show github/twitter buttons + T text only, no ANSI sequences + style=STYLE color style + + c do not comment text, do not shift code (QUERY+ only) + C do not comment text, shift code (QUERY+ only) + Q code only, don't show text (QUERY+ only) + +Options can be combined together in this way: + + curl 'cheat.sh/for?qT&style=bw' + +(when using & in shell, don't forget to specify the quotes or escape & with \) + +Special pages: + + :help this page + :list list all cheat sheets + :post how to post new cheat sheet + :cht.sh shell client (cht.sh) + :bash_completion bash function for tab completion + :styles list of color styles + :styles-demo show color styles usage examples + +Shell client: + + $ curl https://cht.sh/:cht.sh > ~/bin/cht.sh + $ chmod +x ~/bin/cht.sh + $ cht.sh python :learn + $ cht.sh --shell + +Tab completion: + + $ mkdir -p ~/.bash.d/ + $ curl cheat.sh/:bash_completion > ~/.bash.d/cht.sh + $ . ~/.bash.d/cht.sh + $ echo '. ~/.bash.d/cht.sh' >> ~/.bashrc + +Editor integration: + + :emacs see the page for the Emacs configuration + :vim see the page for the Vim configuration + +Search: + + /~snapshot look for "snapshot" in the first level cheat sheets + /~ssh~passphrase several keywords can be combined together using ~ + /scala/~closure look for "closure" in scala cheat sheets + /~snapshot/r look for "snapshot" in all cheat sheets recursively + +You can use special search options after the closing slash: + + /~shot/bi case insensitive (i), word boundaries (b) + +List of search options: + + b word boundaries + i case insensitive search + r recursive + +Programming languages topics: + +each programming language topic has the following subptopics: + + hello hello world + how to start the program + :learn big cheat sheet for learning language from scratch + :list list of topics + +Support programming languages: + + go + scala + rust + python + php diff --git a/tests/results/7 b/tests/results/7 new file mode 100644 index 0000000..b1b99fe --- /dev/null +++ b/tests/results/7 @@ -0,0 +1,389 @@ +#!/usr/bin/env bash +# +# [X] open section +# [X] one shot mode +# [X] usage info +# [X] dependencies check +# [X] help +# [X] yank/y/copy/c +# [X] Y/C +# [X] eof problem +# [X] less +# [X] stealth mode +# +# here are several examples for the stealth mode: +# +# zip lists +# list permutation +# random list element +# reverse a list +# read json from file +# append string to a file +# run process in background +# count words in text counter +# group elements list + +__CHTSH_VERSION=4 +__CHTSH_DATETIME="2018-07-08 22:26:46 +0200" + +export LESSSECURE=1 +STEALTH_MAX_SELECTION_LENGTH=5 + +case "$OSTYPE" in + darwin*) is_macos=yes ;; + *) is_macos=no ;; +esac + +get_query_options() +{ + local query="$*" + if [ -n "$CHTSH_QUERY_OPTIONS" ]; then + if [[ $query == *\?* ]]; then + query="$query&${CHTSH_QUERY_OPTIONS}" + else + query="$query?${CHTSH_QUERY_OPTIONS}" + fi + fi + echo "$query" +} + +do_query() +{ + local query="$*" + local b_opts=() + + if [ -e "$HOME/.cht.sh/id" ]; then + b_opts=(-b "$HOME/.cht.sh/id") + fi + + curl "${b_opts[@]}" -s https://cht.sh/"$(get_query_options $query)" > "$TMP1" + + if [ -z "$lines" ] || [ "$(wc -l "$TMP1" | awk '{print $1}')" -lt "$lines" ]; then + cat "$TMP1" + else + less -R "$TMP1" + fi +} + +prepare_query() +{ + local section="$1"; shift + local input="$1"; shift + local arguments="$1"; shift + + local query + if [ -z "$section" ] || [[ "$input" = /* ]]; then + query=$(echo "$input" | sed 's@ @/@; s@ @+@g') + else + query=$(echo "$section/$input" | sed 's@ @+@g') + fi + + [ -n "$arguments" ] && arguments="?$arguments" + echo "$query$arguments" +} + +get_list_of_sections() +{ + curl -s https://cht.sh/:list | grep -v '/.*/' | grep '/$' +} + +if [ -e "$HOME"/.cht.sh/cht.sh.conf ]; then + # shellcheck disable=SC1090,SC2002 + source <( cat "$HOME"/.cht.sh/cht.sh.conf | sed 's/#.*//' | grep -xv '' | sed s/^/CHTSH_/ ) >& /dev/null +fi + +if [ "$1" == --read ]; then + read -r a || a=exit + echo $a + exit 0 +elif [ "$1" == --help ] || [ -z "$1" ]; then + cat <& /dev/null || { echo 'DEPENDENCY: please install "xsel" for "copy"' >&2; } +fi +which rlwrap >& /dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } +which curl >& /dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } + +mkdir -p "$HOME/.cht.sh/" +lines=$(tput lines) + +TMP1=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) +trap 'rm -f $TMP1 $TMP2' EXIT +trap 'true' INT + +if ! [ -e "$HOME/.cht.sh/.hushlogin" ] && [ -z "$this_query" ]; then + 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 + + input=$( + rlwrap -H $HOME/.cht.sh/history -pgreen -C cht.sh -S "$full_prompt" bash "$0" --read | sed 's/ *#.*//' + ) + + case "$input" in + '?'|h|help) + cat < python zip list + cht.sh/python> zip list + cht.sh/go> /python zip list +EOF + continue + ;; + hush) + mkdir -p $HOME/.cht.sh/ && touch $HOME/.cht.sh/.hushlogin && echo "Initial 'use help' message was disabled" + continue + ;; + cd) + section="" + continue + ;; + "cd "*) + new_section=$(echo "$input" | sed 's/cd //; s/ .*//; s@/\+$@@; s@^/\+@@') + if [ "$new_section" = "" ] || [ "$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/^/ /' + continue + else + section="$new_section" + fi + fi + continue + ;; + exit|quit) + break + ;; + copy|yank|c|y) + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + continue + fi + if [ -z "$input" ]; then + echo copy: Make at least one query first. + continue + else + curl -s https://cht.sh/"$(get_query_options "$query"?T)" > "$TMP1" + if [ "$is_macos" != yes ]; then + xsel -i < "$TMP1" + else + cat "$TMP1" | pbcopy + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" + continue + fi + ;; + ccopy|cc|C|Y) + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + continue + fi + if [ -z "$input" ]; then + echo copy: Make at least one query first. + continue + else + curl -s https://cht.sh/"$(get_query_options "$query"?TQ)" > "$TMP1" + if [ "$is_macos" != yes ]; then + xsel -i < "$TMP1" + else + cat "$TMP1" | pbcopy + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" + continue + fi + ;; + id|"id "*) + id_file="$HOME/.cht.sh/id" + + if [ "$input" = id ]; 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" + else + echo "id was not set, so you can't remove it" + fi + continue + fi + if [ -n "$new_id" ] && [ "$new_id" != reset ] && [ "$(echo $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" + continue + 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 + echo $(cat "$id_file" | awk '{if ($6 == "id") print $NF}' | head -1) + continue + else + new_id=reset + fi + fi + if [ "$new_id" = reset ]; then + new_id="$(cat /dev/urandom 2> /dev/null | env LC_CTYPE=C tr -cd 'a-f0-9' 2> /dev/null | head -c 32)" + 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]\+$' "$id_file" 2> /dev/null; then + sed -i 's/\tid\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 + echo "$new_id" + continue + ;; + stealth|"stealth "*) + if [ "$input" != stealth ]; then + arguments=$(echo "$input" | sed 's/stealth //; s/ /\&/') + fi + trap break SIGINT + if [ "$is_macos" == yes ]; then + past=$(pbpaste) + else + past=$(xsel -o) + 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 + if [ $is_macos == yes ]; then + current=$(pbpaste) + else + current=$(xsel -o) + 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 + echo "\033[0;31mstealth:\033[0m selection length is longer than $STEALTH_MAX_SELECTION_LENGTH words; ignoring" + 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 - SIGINT + continue + ;; + update) + [ -w "$0" ] || { echo "The script is readonly; please update manually: curl -s https://cht.sh/:bash | sudo tee $0"; continue; } + TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) + curl -s https://cht.sh/:cht.sh > "$TMP2" + if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then + if grep -q ^__CHTSH_VERSION= "$TMP2"; then + args=(--shell) + [ -n "$section" ] && args=("${args[@]}" "$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 "cht.sh is up to date. No update needed" + fi + rm -f "$TMP2" > /dev/null 2>&1 + continue + ;; + version) + echo "cht.sh version $__CHTSH_VERSION of $__CHTSH_DATETIME; installed at: $(stat -c %y "$0" | sed 's@\..* @ @')" + TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) + if curl -s https://cht.sh/: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 + rm -f "$TMP2" > /dev/null 2>&1 + continue + ;; + "") + continue + ;; + esac + + query=$(prepare_query "$section" "$input") + do_query "$query" +done diff --git a/tests/results/8 b/tests/results/8 new file mode 100644 index 0000000..b6ca4a7 --- /dev/null +++ b/tests/results/8 @@ -0,0 +1,16 @@ +# How do I copy a file in python? +#  +# shutil (http://docs.python.org/2/library/shutil.html) has many methods +# you can use. One of which is: + +from shutil import copyfile + +copyfile(src, dst) + +# Copy the contents of the file named src to a file named dst. The +# destination location must be writable; otherwise, an IOError exception +# will be raised. If dst already exists, it will be replaced. Special +# files such as character or block devices and pipes cannot be copied +# with this function. src and dst are path names given as strings. +#  +# [Swati] [so/q/123198] [cc by-sa 3.0] diff --git a/tests/results/9 b/tests/results/9 new file mode 100644 index 0000000..b6ca4a7 --- /dev/null +++ b/tests/results/9 @@ -0,0 +1,16 @@ +# How do I copy a file in python? +#  +# shutil (http://docs.python.org/2/library/shutil.html) has many methods +# you can use. One of which is: + +from shutil import copyfile + +copyfile(src, dst) + +# Copy the contents of the file named src to a file named dst. The +# destination location must be writable; otherwise, an IOError exception +# will be raised. If dst already exists, it will be replaced. Special +# files such as character or block devices and pipes cannot be copied +# with this function. src and dst are path names given as strings. +#  +# [Swati] [so/q/123198] [cc by-sa 3.0] diff --git a/tests/run-tests.sh b/tests/run-tests.sh new file mode 100644 index 0000000..3ce9701 --- /dev/null +++ b/tests/run-tests.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +TMP=$(mktemp /tmp/cht.sh.tests-XXXXXXXXXXXXXX) +TMP2=$(mktemp /tmp/cht.sh.tests-XXXXXXXXXXXXXX) +trap 'rm -rf $TMP $TMP2' EXIT + + +i=0 +failed=0 +while read -r test_line; do + eval "$test_line" > "$TMP" + diff results/"$i" "$TMP" > "$TMP2" + if [ "$?" != 0 ]; then + echo FAILED: [$i] $test_line + ((failed++)) + fi + ((i++)) +done < tests.txt + +echo TESTS/OK/FAILED "$i/$[i-failed]/$failed" + + diff --git a/tests/tests.txt b/tests/tests.txt new file mode 100644 index 0000000..5187919 --- /dev/null +++ b/tests/tests.txt @@ -0,0 +1,14 @@ +cht.sh python :list +cht.sh ls +cht.sh ls?T +cht.sh btrfs +cht.sh btrfs~volume +cht.sh :intro +cht.sh :help +cht.sh :cht.sh +cht.sh python copy file +cht.sh python/copy+file +cht.sh python/copy+file?Q +cht.sh python/copy+file?QT +cht.sh / +cht.sh // From 9b1fc60a711b26ee2f9e980dbf1a2025ee299e08 Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Fri, 3 Aug 2018 09:13:26 +0000 Subject: [PATCH 13/19] moved POSIX version of cht.sh to share/cht.sh-posix.txt --- share/cht.sh-posix.txt | 428 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100755 share/cht.sh-posix.txt diff --git a/share/cht.sh-posix.txt b/share/cht.sh-posix.txt new file mode 100755 index 0000000..86afd70 --- /dev/null +++ b/share/cht.sh-posix.txt @@ -0,0 +1,428 @@ +#!/bin/sh +# +# [X] open section +# [X] one shot mode +# [X] usage info +# [X] dependencies check +# [X] help +# [X] yank/y/copy/c +# [X] Y/C +# [X] eof problem +# [X] more +# [X] stealth mode +# +# here are several examples for the stealth mode: +# +# zip lists +# list permutation +# random list element +# reverse a list +# read json from file +# append string to a file +# run process in background +# count words in text counter +# group elements list + +__CHTSH_VERSION=4 +__CHTSH_DATETIME="2018-07-08 22:26:46 +0200" + +export LESSSECURE=1 +STEALTH_MAX_SELECTION_LENGTH=5 + +case "$OSTYPE" in + darwin*) is_macos=yes ;; + *) is_macos=no ;; +esac + +# for KSH93 +if ! local foo 2>/dev/null; then + alias local=typeset +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" +} + +do_query() +{ + local query="$*" + local b_opts= + local uri="https://cht.sh/\"\$(get_query_options $query)\"" + + if [ -e "$HOME/.cht.sh/id" ]; then + b_opts="-b \"\$HOME/.cht.sh/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 https://cht.sh/: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 $dev | awk -v ORS='' // + else + cd /tmp + s= + while [ $(echo "$s" | wc -c) -lt $len ]; do + s="$s$(mktemp -u XXXXXXXXXX)" + done + printf %.${len}s "$s" + fi + fi +) + +if [ -e "$HOME"/.cht.sh/cht.sh.conf ]; then + # shellcheck disable=SC1090,SC2002 + . "$HOME"/.cht.sh/cht.sh.conf +fi + +if [ "$1" = --read ]; then + read -r a || a=exit + printf "%s\n" "$a" + exit 0 +elif [ x"$1" = x--help ] || [ -z "$1" ]; then + cat </dev/null || echo 'DEPENDENCY: please install "xsel" for "copy"' >&2 +fi +command -v rlwrap >/dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } +command -v curl >/dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } + +mkdir -p "$HOME/.cht.sh/" +lines=$(tput lines) + +if command -v less >/dev/null; then + defpager="less -R" +elif command -v more >/dev/null; then + defpager=more +else + defpager=cat +fi + +TMP1=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) +trap 'rm -f $TMP1 $TMP2' EXIT +trap 'true' INT + +if ! [ -e "$HOME/.cht.sh/.hushlogin" ] && [ -z "$this_query" ]; then + 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 + + input=$( + rlwrap -H "$HOME/.cht.sh/history" -pgreen -C cht.sh -S "$full_prompt" sh "$0" --read | sed 's/ *#.*//' + ) + + case "$input" in + '?'|h|help) + cat < python zip list + cht.sh/python> zip list + cht.sh/go> /python zip list +EOF + continue + ;; + hush) + mkdir -p $HOME/.cht.sh/ && touch $HOME/.cht.sh/.hushlogin && echo "Initial 'use help' message was disabled" + continue + ;; + cd) + section="" + continue + ;; + "cd "*) + 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/^/ /' + continue + else + section="$new_section" + fi + fi + continue + ;; + exit|quit) + break + ;; + copy|yank|c|y) + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + continue + fi + if [ -z "$input" ]; then + echo copy: Make at least one query first. + continue + else + curl -s https://cht.sh/"$(get_query_options "$query"?T)" > "$TMP1" + if [ "$is_macos" != yes ]; then + xsel -i < "$TMP1" + else + cat "$TMP1" | pbcopy + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" + continue + fi + ;; + ccopy|cc|C|Y) + if [ -z "$DISPLAY" ]; then + echo copy: supported only in the Desktop version + continue + fi + if [ -z "$input" ]; then + echo copy: Make at least one query first. + continue + else + curl -s https://cht.sh/"$(get_query_options "$query"?TQ)" > "$TMP1" + if [ "$is_macos" != yes ]; then + xsel -i < "$TMP1" + else + cat "$TMP1" | pbcopy + fi + echo "copy: $(wc -l "$TMP1" | awk '{print $1}') lines copied to the selection" + continue + fi + ;; + id|"id "*) + id_file="$HOME/.cht.sh/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" + else + echo "id was not set, so you can't remove it" + fi + continue + 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" + continue + 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 + echo $(awk '$6 == "id" {print $NF}' <"$id_file" | tail -n 1) + continue + else + new_id=reset + 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" + fi + printf ".cht.sh\tTRUE\t/\tTRUE\t0\tid\t$new_id\n" >> "$id_file" + fi + echo "$new_id" + continue + ;; + stealth|"stealth "*) + if [ "$input" != stealth ]; then + arguments=$(echo "$input" | sed 's/stealth //; s/ /\&/') + fi + trap break SIGINT + if [ "$is_macos" == yes ]; then + past=$(pbpaste) + else + past=$(xsel -o) + 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 + if [ $is_macos == yes ]; then + current=$(pbpaste) + else + current=$(xsel -o) + 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 + echo "\033[0;31mstealth:\033[0m selection length is longer than $STEALTH_MAX_SELECTION_LENGTH words; ignoring" + 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 - SIGINT + continue + ;; + update) + [ -w "$0" ] || { echo "The script is readonly; please update manually: curl -s https://cht.sh/:bash | sudo tee $0"; continue; } + TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) + curl -s https://cht.sh/: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 "cht.sh is up to date. No update needed" + fi + rm -f "$TMP2" > /dev/null 2>&1 + continue + ;; + 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 https://cht.sh/: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 + rm -f "$TMP2" > /dev/null 2>&1 + continue + ;; + "") + continue + ;; + esac + + query=$(prepare_query "$section" "$input") + do_query "$query" +done From fa89d1a7cae58df50ea1e84bafb65de71ff5915f Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Fri, 3 Aug 2018 09:14:17 +0000 Subject: [PATCH 14/19] reverted a08f130562c6319b02de99ead947bc8424cd4152 (cht.sh posix compatibility) --- share/cht.sh.txt | 135 +++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 87 deletions(-) diff --git a/share/cht.sh.txt b/share/cht.sh.txt index 86afd70..b1b99fe 100755 --- a/share/cht.sh.txt +++ b/share/cht.sh.txt @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # [X] open section # [X] one shot mode @@ -8,7 +8,7 @@ # [X] yank/y/copy/c # [X] Y/C # [X] eof problem -# [X] more +# [X] less # [X] stealth mode # # here are several examples for the stealth mode: @@ -34,39 +34,34 @@ case "$OSTYPE" in *) is_macos=no ;; esac -# for KSH93 -if ! local foo 2>/dev/null; then - alias local=typeset -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 + if [[ $query == *\?* ]]; then + query="$query&${CHTSH_QUERY_OPTIONS}" + else + query="$query?${CHTSH_QUERY_OPTIONS}" + fi fi - printf "%s" "$query" + echo "$query" } do_query() { local query="$*" - local b_opts= - local uri="https://cht.sh/\"\$(get_query_options $query)\"" + local b_opts=() if [ -e "$HOME/.cht.sh/id" ]; then - b_opts="-b \"\$HOME/.cht.sh/id\"" + b_opts=(-b "$HOME/.cht.sh/id") fi - eval curl $b_opts -s $uri > "$TMP1" + curl "${b_opts[@]}" -s https://cht.sh/"$(get_query_options $query)" > "$TMP1" if [ -z "$lines" ] || [ "$(wc -l "$TMP1" | awk '{print $1}')" -lt "$lines" ]; then cat "$TMP1" else - ${PAGER:-$defpager} "$TMP1" + less -R "$TMP1" fi } @@ -74,59 +69,34 @@ prepare_query() { local section="$1"; shift local input="$1"; shift - local arguments="$1" + local arguments="$1"; shift local query - if [ -z "$section" ] || [ x"${input}" != x"${input#/}" ]; then - query=$(printf %s "$input" | sed 's@ @/@; s@ @+@g') + if [ -z "$section" ] || [[ "$input" = /* ]]; then + query=$(echo "$input" | sed 's@ @/@; s@ @+@g') else - query=$(printf %s "$section/$input" | sed 's@ @+@g') + query=$(echo "$section/$input" | sed 's@ @+@g') fi [ -n "$arguments" ] && arguments="?$arguments" - printf %s "$query$arguments" + echo "$query$arguments" } get_list_of_sections() { - curl -s https://cht.sh/:list | grep -v '/.*/' | grep '/$' | xargs + curl -s https://cht.sh/:list | grep -v '/.*/' | grep '/$' } -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 $dev | awk -v ORS='' // - else - cd /tmp - s= - while [ $(echo "$s" | wc -c) -lt $len ]; do - s="$s$(mktemp -u XXXXXXXXXX)" - done - printf %.${len}s "$s" - fi - fi -) - if [ -e "$HOME"/.cht.sh/cht.sh.conf ]; then # shellcheck disable=SC1090,SC2002 - . "$HOME"/.cht.sh/cht.sh.conf + source <( cat "$HOME"/.cht.sh/cht.sh.conf | sed 's/#.*//' | grep -xv '' | sed s/^/CHTSH_/ ) >& /dev/null fi -if [ "$1" = --read ]; then +if [ "$1" == --read ]; then read -r a || a=exit - printf "%s\n" "$a" + echo $a exit 0 -elif [ x"$1" = x--help ] || [ -z "$1" ]; then +elif [ "$1" == --help ] || [ -z "$1" ]; then cat </dev/null || echo 'DEPENDENCY: please install "xsel" for "copy"' >&2 + which xsel >& /dev/null || { echo 'DEPENDENCY: please install "xsel" for "copy"' >&2; } fi -command -v rlwrap >/dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } -command -v curl >/dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } +which rlwrap >& /dev/null || { echo 'DEPENDENCY: install "rlwrap" to use cht.sh in the shell mode' >&2; exit 1; } +which curl >& /dev/null || { echo 'DEPENDENCY: install "curl" to use cht.sh' >&2; exit 1; } mkdir -p "$HOME/.cht.sh/" lines=$(tput lines) -if command -v less >/dev/null; then - defpager="less -R" -elif command -v more >/dev/null; then - defpager=more -else - defpager=cat -fi - TMP1=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) trap 'rm -f $TMP1 $TMP2' EXIT trap 'true' INT @@ -209,7 +171,7 @@ while true; do fi input=$( - rlwrap -H "$HOME/.cht.sh/history" -pgreen -C cht.sh -S "$full_prompt" sh "$0" --read | sed 's/ *#.*//' + rlwrap -H $HOME/.cht.sh/history -pgreen -C cht.sh -S "$full_prompt" bash "$0" --read | sed 's/ *#.*//' ) case "$input" in @@ -242,16 +204,16 @@ EOF continue ;; "cd "*) - new_section=$(echo "$input" | sed 's/cd *//; s@/*$@@; s@^/*@@') - if [ -z "$new_section" ] || [ ".." = "$new_section" ]; then + new_section=$(echo "$input" | sed 's/cd //; s/ .*//; s@/\+$@@; s@^/\+@@') + if [ "$new_section" = "" ] || [ "$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 + 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/^/ /' + echo "${valid_sections[@]}" | xargs printf "%-10s\n" | tr ' ' . | xargs -n 10 | sed 's/\./ /g; s/^/ /' continue else section="$new_section" @@ -303,20 +265,20 @@ EOF id|"id "*) id_file="$HOME/.cht.sh/id" - if [ id = "$input" ]; then + if [ "$input" = id ]; then new_id="" else - new_id=$(echo "$input" | sed 's/id *//; s/ *$//; s/ /+/g') + 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" + rm -f "$id_file" && echo "id is removed" else echo "id was not set, so you can't remove it" fi continue fi - if [ -n "$new_id" ] && [ reset != "$new_id" ] && [ $(/bin/echo -n "$new_id" | wc -c) -lt 16 ]; then + if [ -n "$new_id" ] && [ "$new_id" != reset ] && [ "$(echo $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" continue fi @@ -325,19 +287,19 @@ EOF # if yes, just show it # if not, generate a new id if [ -e "$id_file" ]; then - echo $(awk '$6 == "id" {print $NF}' <"$id_file" | tail -n 1) + echo $(cat "$id_file" | awk '{if ($6 == "id") print $NF}' | head -1) continue else new_id=reset fi fi if [ "$new_id" = reset ]; then - new_id=$(gen_random_str 12) + new_id="$(cat /dev/urandom 2> /dev/null | env LC_CTYPE=C tr -cd 'a-f0-9' 2> /dev/null | head -c 32)" 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" + if [ -e "$id_file" ] && grep -q '\tid\t[^\t]\+$' "$id_file" 2> /dev/null; then + sed -i 's/\tid\t[^\t]\+$/ id '"$new_id"'/' "$id_file" else if ! [ -e "$id_file" ]; then printf '#\n\n' > "$id_file" @@ -392,9 +354,9 @@ EOF curl -s https://cht.sh/: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 + args=(--shell) + [ -n "$section" ] && args=("${args[@]}" "$section") + cp "$TMP2" "$0" && echo "Updated. Restarting..." && rm "$TMP2" && CHEATSH_RESTART=1 exec "$0" "${args[@]}" else echo "Something went wrong. Please update manually" fi @@ -405,8 +367,7 @@ EOF continue ;; 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" + echo "cht.sh version $__CHTSH_VERSION of $__CHTSH_DATETIME; installed at: $(stat -c %y "$0" | sed 's@\..* @ @')" TMP2=$(mktemp /tmp/cht.sh.XXXXXXXXXXXXX) if curl -s https://cht.sh/:cht.sh > "$TMP2"; then if ! cmp "$0" "$TMP2" > /dev/null 2>&1; then From 75c8878956711440182b4760f97a376df1d70a2a Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Sun, 5 Aug 2018 17:14:34 +0000 Subject: [PATCH 15/19] added new section notation: /EDITOR:filetype/ --- lib/cheat_wrapper.py | 4 +-- lib/get_answer.py | 7 +++-- lib/languages_data.py | 69 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 4 deletions(-) diff --git a/lib/cheat_wrapper.py b/lib/cheat_wrapper.py index 60e5a81..6f89b66 100644 --- a/lib/cheat_wrapper.py +++ b/lib/cheat_wrapper.py @@ -21,7 +21,7 @@ MYDIR = os.path.abspath(os.path.join(__file__, '..', '..')) sys.path.append("%s/lib/" % MYDIR) from globals import error, ANSI2HTML, COLOR_STYLES from buttons import TWITTER_BUTTON, GITHUB_BUTTON, GITHUB_BUTTON_FOOTER -from languages_data import LEXER, LANGUAGE_ALIAS +from languages_data import LEXER, get_lexer_name from get_answer import get_topic_type, get_topics_list, get_answer, find_answer_by_keyword from beautifier import code_blocks # import beautifier @@ -94,7 +94,7 @@ def _colorize_ansi_answer(topic, answer, color_style, # pylint: di lexer_class = LEXER['bash'] if '/' in topic: section_name = topic.split('/', 1)[0].lower() - section_name = LANGUAGE_ALIAS.get(section_name, section_name) + section_name = get_lexer_name(section_name) lexer_class = LEXER.get(section_name, lexer_class) if section_name == 'php': answer = "\n" % answer diff --git a/lib/get_answer.py b/lib/get_answer.py index e4363cf..61e4c70 100644 --- a/lib/get_answer.py +++ b/lib/get_answer.py @@ -27,7 +27,7 @@ import time import beautifier from globals import MYDIR, PATH_TLDR_PAGES, PATH_CHEAT_PAGES, PATH_CHEAT_SHEETS, COLOR_STYLES from adapter_learnxiny import get_learnxiny, get_learnxiny_list, is_valid_learnxy -from languages_data import LANGUAGE_ALIAS, SO_NAME +from languages_data import LANGUAGE_ALIAS, SO_NAME, rewrite_editor_section_name from colorize_internal import colorize_internal # pylint: enable=wrong-import-position,wrong-import-order @@ -37,6 +37,7 @@ MAX_SEARCH_LEN = 20 INTERNAL_TOPICS = [ ':cht.sh', + ':cht.sh-posix', ':bash_completion', ':emacs', ':emacs-ivy', @@ -431,8 +432,10 @@ def get_answer(topic, keyword, options="", request_options=None): # pylint: disa return query section_name, rest = query.split('/', 1) + if ':' in section_name: + section_name = rewrite_editor_section_name(section_name) + section_name = SO_NAME.get(section_name, section_name) - print("%s/%s" % (section_name, rest)) return "%s/%s" % (section_name, rest) diff --git a/lib/languages_data.py b/lib/languages_data.py index 5c60e86..16f6c47 100644 --- a/lib/languages_data.py +++ b/lib/languages_data.py @@ -122,3 +122,72 @@ SO_NAME = { 'vb' : 'vba', 'mathematica': 'wolfram-mathematica', } + + +# +# conversion of internal programmin language names +# into canonical cheat.sh names +# + +ATOM_FT_NAME = { +} + +EMACS_FT_NAME = { +} + +SUBLIME_FT_NAME = { +} + +VIM_FT_NAME = { + 'asm': 'assembler', + 'javascript': 'js', +} + +VSCODE_FT_NAME = { +} + +def rewrite_editor_section_name(section_name): + """ + section name cen be specified in form "editor:editor-filetype" + and it will be rewritten into form "filetype" + basing on the editor filetypes names data. + If editor name is unknown, it is just cut off: notepad:js => js + + Known editors: + * atom + * vim + * emacs + * sublime + * vscode + + >>> rewrite_editor_section_name('js') + 'js' + >>> rewrite_editor_section_name('vscode:js') + 'js' + """ + if ':' not in section_name: + return section_name + + editor_name, section_name = section_name.split(':', 1) + editor_name_mapping = { + 'atom': ATOM_FT_NAME, + 'emacs': EMACS_FT_NAME, + 'sublime': SUBLIME_FT_NAME, + 'vim': VIM_FT_NAME, + 'vscode': VSCODE_FT_NAME, + } + if editor_name not in editor_name_mapping: + return section_name + return editor_name_mapping[editor_name].get(section_name, section_name) + +def get_lexer_name(section_name): + """ + Rewrite `section_name` for the further lexer search (for syntax highlighting) + """ + if ':' in section_name: + section_name = rewrite_editor_section_name(section_name) + return LANGUAGE_ALIAS.get(section_name, section_name) + +if __name__ == "__main__": + import doctest + doctest.testmod() From bd7d36cfe2e3a0a5e7d23acdf9defac959369b6d Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Sun, 5 Aug 2018 19:55:43 +0200 Subject: [PATCH 16/19] cheat.sh editors features list --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e428b90..25a4070 100644 --- a/README.md +++ b/README.md @@ -407,7 +407,9 @@ because you know what happens when you do. ## Editors integration -You can use *cheat.sh* directly from the editor (*Vim*, *Emacs* and *Visual Studio Code* are currently supported). +You can use *cheat.sh* directly from the editor +(*Emacs*, *Sublime*, *Vim*, and *Visual Studio Code* are currently supported; +not all features are supported by all plugins though; see below). Instead of opening your browser, googling, browsing Stack Overflow and eventually copying the code snippets you need into the clipboard and later pasting them into the editor, @@ -430,6 +432,19 @@ If you use some static analysis plugin such as *syntastic* (for Vim), you can us its warning and error messages as cheat.sh queries: place the cursor on the problem line and press `KE`: explanation for the warning will be opened in a new buffer. +Features supported by cheat.sh plugins for different editors: + +|Feature |Emacs|Sublime|Vim|VSCode| +|-------------------|-----|-------|---|------| +|Command queries |✓ |✓ |✓ |✓ | +|Queries from buffer| | |✓ |✓ | +|Toggle comments | | |✓ | | +|Prev/next answer | | |✓ | | +|Multiple answers | |✓ | | | +|Warnings as queries| | |✓ | | +|Session id | | |✓ | | +|-------------------|-----|-------|---|------| + ### Vim * [cheat.sh-vim](https://github.com/dbeniamine/cheat.sh-vim) — Vim support From e39cdb965d5b8b29b3ff07414a0fb9dfa34dcd7b Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Sun, 5 Aug 2018 19:56:33 +0200 Subject: [PATCH 17/19] cheat.sh plugins table fixed --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 25a4070..a095875 100644 --- a/README.md +++ b/README.md @@ -443,7 +443,6 @@ Features supported by cheat.sh plugins for different editors: |Multiple answers | |✓ | | | |Warnings as queries| | |✓ | | |Session id | | |✓ | | -|-------------------|-----|-------|---|------| ### Vim From cdadd3c0c9073b3677b0d11dcd2a014e578f3ba1 Mon Sep 17 00:00:00 2001 From: Igor Chubin Date: Sun, 5 Aug 2018 18:56:42 +0000 Subject: [PATCH 18/19] minor fixes after refactoring (#79) --- lib/colorize_internal.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/colorize_internal.py b/lib/colorize_internal.py index 2e7dd41..2d709ac 100644 --- a/lib/colorize_internal.py +++ b/lib/colorize_internal.py @@ -31,17 +31,19 @@ PALETTES = { def _reverse_palette(code): return { 1 : Fore.BLACK + _back_color(code), - 2 : Style.DIM - } + 2 : Style.DIM + } def _back_color(code): - if code == 0 or code.lower()=="white": + if code == 0 or (isinstance(code, str) and code.lower() == "white"): return Back.WHITE - if code == 1 or code.lower()=="cyan": + if code == 1 or (isinstance(code, str) and code.lower() == "cyan"): return Back.CYAN - if code == 2 or code.lower()=="red": + if code == 2 or (isinstance(code, str) and code.lower() == "red"): return Back.RED + return Back.WHITE + def colorize_internal(text, palette_number=1): """ Colorize `text`, use `palette` @@ -58,12 +60,12 @@ def colorize_internal(text, palette_number=1): stripped = text.lstrip('0123456789') return (text, stripped, factor) - def _extract_color_number(text,stripped,factor = 1): + def _extract_color_number(text, stripped, factor=1): return int(text[:len(text)-len(stripped)])*factor def _colorize_curlies_block(text): text, stripped, factor = _process_text(text) - color_number = _extract_color_number(text,stripped,factor) + color_number = _extract_color_number(text, stripped, factor) if stripped.startswith('='): stripped = stripped[1:] From f1633e02750d90487f3fef42a031f09fd8ec66ad Mon Sep 17 00:00:00 2001 From: Brandon Lopez Date: Tue, 7 Aug 2018 12:25:49 -0700 Subject: [PATCH 19/19] Update README.md Added Travis badge to show status of Docker builds --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 94cea95..42691e4 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ What features should it have? Such a thing exists. +[![Build Status](https://travis-ci.org/bglopez/cheat.sh.svg?branch=master)](https://travis-ci.org/bglopez/cheat.sh) + ## Features **cheat.sh**