summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Isidoro <denisidoro@users.noreply.github.com>2019-09-24 16:13:57 -0300
committerGitHub <noreply@github.com>2019-09-24 16:13:57 -0300
commit36cd52f93d0d7c0dae4d64cc133b4ee35d90cf73 (patch)
tree46632273b543e28f4133cb312ef9f34fdf556d60
parent2ee253a56ecbf4fd8607dc16a1d1cc1f225342b9 (diff)
Minor refactor (#57)v0.9.2
- [x] Define OPTIONS as global in opts::eval - [x] Add script - [x] Minor changes
-rw-r--r--cheats/kubernetes.cheat6
-rwxr-xr-xnavi10
-rwxr-xr-xscripts/docker21
-rwxr-xr-xscripts/install8
-rw-r--r--src/arg.sh10
-rw-r--r--src/dict.sh9
-rw-r--r--src/main.sh20
-rw-r--r--src/opts.sh7
-rw-r--r--src/selection.sh2
-rw-r--r--src/str.sh6
-rw-r--r--test/cheat_test.sh7
-rw-r--r--test/core.sh16
-rw-r--r--test/log.sh102
13 files changed, 187 insertions, 37 deletions
diff --git a/cheats/kubernetes.cheat b/cheats/kubernetes.cheat
index c4584d2..ef14432 100644
--- a/cheats/kubernetes.cheat
+++ b/cheats/kubernetes.cheat
@@ -3,16 +3,16 @@
# Print resource documentation
kubectl explain <resource>
-# Get nodes (add option `-o wide` for details)
+# Get nodes (add option '-o wide' for details)
kubectl get nodes
# Get namespaces
kubectl get namespaces
-# Get pods from namespace (add option `-o wide` for details)
+# Get pods from namespace (add option '-o wide' for details)
kubectl get pods -n <namespace>
-# Get pods from all namespace (add option `-o wide` for details)
+# Get pods from all namespace (add option '-o wide' for details)
kubectl get pods --all-namespaces
# Get services from namespace
diff --git a/navi b/navi
index 4ff8219..fb89a6e 100755
--- a/navi
+++ b/navi
@@ -35,13 +35,7 @@ source "${SCRIPT_DIR}/src/main.sh"
##? full docs
##? Please refer to the README at https://github.com/denisidoro/navi
-VERSION="0.9.1"
+VERSION="0.9.2"
-# workaround while dict::* can't handle newlines
-case "${1:-}" in
- help|--help) opts::extract_help "$0" && exit 0 ;;
-esac
-
-OPTIONS="$(opts::eval "$@")"
-export NAVI_PATH="$(dict::get "$OPTIONS" path)"
+opts::eval "$@"
main "$@"
diff --git a/scripts/docker b/scripts/docker
new file mode 100755
index 0000000..0088b86
--- /dev/null
+++ b/scripts/docker
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+debian="${1:-false}"
+
+if $debian; then
+ docker run \
+ -it \
+ --entrypoint /bin/bash \
+ -v "$(pwd):/navi" \
+ debian \
+ -c 'apt update; apt install -y git curl; git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && yes | ~/.fzf/install; export PATH=$PATH:/navi; bash'
+else
+ docker run \
+ -it \
+ --entrypoint /bin/bash \
+ -v "$(pwd):/navi" \
+ ellerbrock/alpine-bash-git \
+ -c 'git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && yes | ~/.fzf/install; export PATH=$PATH:/navi; bash'
+fi
+
diff --git a/scripts/install b/scripts/install
index 5219540..4aa75b6 100755
--- a/scripts/install
+++ b/scripts/install
@@ -8,6 +8,8 @@ script() {
echo "${SCRIPT_DIR}/navi" '"$@"'
}
-BIN="/usr/local/bin/navi"
-script > "$BIN"
-chmod +x "$BIN" \ No newline at end of file
+folder="${1:-/usr/local/bin}"
+bin="${folder}/navi"
+
+script > "$bin"
+chmod +x "$bin" \ No newline at end of file
diff --git a/src/arg.sh b/src/arg.sh
index d0eb04f..cf0bb38 100644
--- a/src/arg.sh
+++ b/src/arg.sh
@@ -1,11 +1,13 @@
#!/usr/bin/env bash
ARG_REGEX="<[0-9a-zA-Z_]+>"
-ARG_DELIMITER="£"
+ARG_DELIMITER="\f"
arg::dict() {
- local -r fn="$(awk -F'---' '{print $1}')"
- local -r opts="$(awk -F'---' '{print $2}')"
+ local -r input="$(cat)"
+
+ local -r fn="$(echo "$input" | awk -F'---' '{print $1}')"
+ local -r opts="$(echo "$input" | awk -F'---' '{print $2}')"
dict::new fn "$fn" opts "$opts"
}
@@ -34,7 +36,7 @@ arg::deserialize() {
local -r out="$arg"
fi
- echo "$out" | sed "s/${ARG_DELIMITER}/ /g"
+ echo "$out" | tr "${ARG_DELIMITER}" " "
}
# TODO: separation of concerns
diff --git a/src/dict.sh b/src/dict.sh
index 4794425..3fc8ec5 100644
--- a/src/dict.sh
+++ b/src/dict.sh
@@ -1,5 +1,12 @@
#!/usr/bin/env bash
+# for an explanation behind this namespace, please check
+# https://medium.com/@den.isidoro/dictionaries-in-shell-scripts-61d34e1c91c6
+
+# LIMITATIONS:
+# values with non-trivial whitespaces (newlines, subsequent spaces, etc)
+# aren't handled very well
+
DICT_DELIMITER='\f'
dict::_post() {
@@ -64,7 +71,7 @@ dict::get() {
if [ $matches -gt 1 ]; then
echo "$result" | dict::_unescape_value
else
- echo "$result" | sed -E "s/${prefix}//" | dict::_unescape_value
+ echo "$result" | sed -E "s/${prefix}//" | dict::_unescape_value | sed -E 's/^[[:space:]]*//'
fi
}
diff --git a/src/main.sh b/src/main.sh
index c392444..8f667fb 100644
--- a/src/main.sh
+++ b/src/main.sh
@@ -1,5 +1,9 @@
#!/usr/bin/env bash
+if ${NAVI_FORCE_GNU:-false}; then
+ source "${DOTFILES}/scripts/core/main.sh"
+fi
+
source "${SCRIPT_DIR}/src/arg.sh"
source "${SCRIPT_DIR}/src/cheat.sh"
source "${SCRIPT_DIR}/src/dict.sh"
@@ -56,8 +60,12 @@ handler::preview() {
[ -n "$cheat" ] && selection::cmd "$selection" "$cheat"
}
-handler::text() {
- dict::get "$OPTIONS" text
+handler::help() {
+ echo "$TEXT"
+}
+
+handler::version() {
+ echo "${VERSION:-unknown}"
}
main() {
@@ -66,6 +74,7 @@ main() {
local -r query="$(dict::get "$OPTIONS" query)"
handler::preview "$query" \
|| echo "Unable to find command for '$query'"
+ echo "$NAVI_PATH"
;;
search)
health::fzf
@@ -73,8 +82,11 @@ main() {
search::save "$query" || true
handler::main
;;
- text)
- handler::text
+ version)
+ handler::version
+ ;;
+ help)
+ handler::help
;;
*)
health::fzf
diff --git a/src/opts.sh b/src/opts.sh
index 5280a0a..d66e188 100644
--- a/src/opts.sh
+++ b/src/opts.sh
@@ -25,8 +25,8 @@ opts::eval() {
case $arg in
--print) print=true ;;
--no-interpolation) interpolation=false ;;
- --version|version) dict::new entry_point "text" text "${VERSION:-unknown}" && exit 0 ;;
- help|--help) dict::new entry_point "text" text "$(opts::extract_help "$0")" && exit 0 ;;
+ --version|version) entry_point="version" ;;
+ help|--help) entry_point="help"; TEXT="$(opts::extract_help "$0")" ;;
--command-for) wait_for="command-for" ;;
--no-preview) preview=false ;;
--path) wait_for="path" ;;
@@ -36,5 +36,6 @@ opts::eval() {
esac
done
- dict::new entry_point "$entry_point" print "$print" interpolation "$interpolation" preview "$preview" query "${query:-}" path "$path"
+ OPTIONS="$(dict::new entry_point "$entry_point" print "$print" interpolation "$interpolation" preview "$preview" query "${query:-}")"
+ export NAVI_PATH="$path"
}
diff --git a/src/selection.sh b/src/selection.sh
index 6745a47..b11bfb9 100644
--- a/src/selection.sh
+++ b/src/selection.sh
@@ -6,7 +6,7 @@ selection::dict() {
local -r tags="$(echo "$str" | awk -F'[' '{print $NF}' | tr -d ']')"
local -r core="$(echo "$str" | sed -e "s/ \[${tags}\]$//")"
- dict::new core "$core" tags "$tags"
+ dict::new core "$core" tags "$tags" | sed "s/'''/'/g"
}
selection::core_is_comment() {
diff --git a/src/str.sh b/src/str.sh
index f58e962..65e67d2 100644
--- a/src/str.sh
+++ b/src/str.sh
@@ -29,3 +29,9 @@ str::last_paragraph_line() {
str::first_word() {
awk '{print $1}'
}
+
+str::index_last_occurrence() {
+ local -r char="$1"
+
+ awk 'BEGIN{FS=""}{ for(i=1;i<=NF;i++){ if($i=="'"$char"'"){ p=i } }}END{ print p }'
+}
diff --git a/test/cheat_test.sh b/test/cheat_test.sh
index c88e8d1..93c69aa 100644
--- a/test/cheat_test.sh
+++ b/test/cheat_test.sh
@@ -1,4 +1,7 @@
#!/usr/bin/env bash
-test::run "We can find at least one known cheatsheet" \
- 'cheat::find | grep -q "docker.cheat"'
+assert_docker_cheat() {
+ cheat::find | grep -q "docker.cheat"
+}
+
+test::run "We can find at least one known cheatsheet" assert_docker_cheat
diff --git a/test/core.sh b/test/core.sh
index e6718a3..8dd27c0 100644
--- a/test/core.sh
+++ b/test/core.sh
@@ -1,27 +1,27 @@
#!/usr/bin/env bash
source "${SCRIPT_DIR}/src/main.sh"
+source "${SCRIPT_DIR}/test/log.sh"
-OPTIONS="$(opts::eval "$@")"
-export NAVI_PATH="$(dict::get "$OPTIONS" path)"
+opts::eval "$@"
PASSED=0
FAILED=0
test::success() {
PASSED=$((PASSED+1))
- echo "Test passed!"
+ log::success "Test passed!"
}
test::fail() {
FAILED=$((FAILED+1))
- echo "Test failed..."
+ log::error "Test failed..."
return
}
test::run() {
echo
- echo "-> $1"
+ log::note "$1"
shift
eval "$*" && test::success || test::fail
}
@@ -31,7 +31,7 @@ test::equals() {
local -r expected="$(echo "${1:-}" | tr -d '\n' | sed 's/\\n//g')"
if [[ "$actual" != "$expected" ]]; then
- echo "Expected '${expected}' but got '${actual}'"
+ log::success "Expected '${expected}' but got '${actual}'"
return 2
fi
}
@@ -39,10 +39,10 @@ test::equals() {
test::finish() {
echo
if [ $FAILED -gt 0 ]; then
- echo "${PASSED} tests passed but ${FAILED} failed... :("
+ log::error "${PASSED} tests passed but ${FAILED} failed... :("
exit "${FAILED}"
else
- echo "All ${PASSED} tests passed! :)"
+ log::success "All ${PASSED} tests passed! :)"
exit 0
fi
}
diff --git a/test/log.sh b/test/log.sh
new file mode 100644
index 0000000..507c610
--- /dev/null
+++ b/test/log.sh
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+
+_export_colors() {
+ if ! ${DOT_COLORS_EXPORTED:-false}; then
+ if [ -z ${TERM:-} ] || [ $TERM = "dumb" ]; then
+ bold=""
+ underline=""
+ freset=""
+ purple=""
+ red=""
+ green=""
+ tan=""
+ blue=""
+ else
+ bold=$(tput bold)
+ underline=$(tput sgr 0 1)
+ freset=$(tput sgr0)
+ purple=$(tput setaf 171)
+ red=$(tput setaf 1)
+ green=$(tput setaf 76)
+ tan=$(tput setaf 3)
+ blue=$(tput setaf 38)
+ fi
+
+ log_black=30
+ log_red=31
+ log_green=32
+ log_yellow=33
+ log_blue=34
+ log_purple=35
+ log_cyan=36
+ log_white=37
+
+ log_regular=0
+ log_bold=1
+ log_underline=4
+
+ readonly DOT_COLORS_EXPORTED=true
+ fi
+}
+
+log::color() {
+ _export_colors
+ local bg=false
+ case "$@" in
+ *reset*) echo "\e[0m"; exit 0 ;;
+ *black*) color=$log_black ;;
+ *red*) color=$log_red ;;
+ *green*) color=$log_green ;;
+ *yellow*) color=$log_yellow ;;
+ *blue*) color=$log_blue ;;
+ *purple*) color=$log_purple ;;
+ *cyan*) color=$log_cyan ;;
+ *white*) color=$log_white ;;
+ esac
+ case "$@" in
+ *regular*) mod=$log_regular ;;
+ *bold*) mod=$log_bold ;;
+ *underline*) mod=$log_underline ;;
+ esac
+ case "$@" in
+ *background*) bg=true ;;
+ *bg*) bg=true ;;
+ esac
+
+ if $bg; then
+ echo "\e[${color}m"
+ else
+ echo "\e[${mod:-$log_regular};${color}m"
+ fi
+}
+
+if [ -z ${LOG_FILE+x} ]; then
+ readonly LOG_FILE="/tmp/$(basename "$0").log"
+fi
+
+_log() {
+ local template=$1
+ shift
+ if ${log_to_file:-false}; then
+ echo -e $(printf "$template" "$@") | tee -a "$LOG_FILE" >&2
+ else
+ echo -e $(printf "$template" "$@")
+ fi
+}
+
+_header() {
+ local TOTAL_CHARS=60
+ local total=$TOTAL_CHARS-2
+ local size=${#1}
+ local left=$((($total - $size) / 2))
+ local right=$(($total - $size - $left))
+ printf "%${left}s" '' | tr ' ' =
+ printf " $1 "
+ printf "%${right}s" '' | tr ' ' =
+}
+
+log::header() { _export_colors && _log "\n${bold}${purple}$(_header "$1")${freset}\n"; }
+log::success() { _export_colors && _log "${green}✔ %s${freset}\n" "$@"; }
+log::error() { _export_colors && _log "${red}✖ %s${freset}\n" "$@"; }
+log::warning() { _export_colors && _log "${tan}➜ %s${freset}\n" "$@"; }
+log::note() { _export_colors && _log "${blue}➜ %s${freset}\n" "$@"; }