diff options
author | Denis Isidoro <denisidoro@users.noreply.github.com> | 2019-09-22 11:52:10 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-22 11:52:10 -0300 |
commit | 77acda383df96d757df1d3bdaa328b5d15b3a5f6 (patch) | |
tree | 1415d2d9cfd4f18e90978625d098f1729a3b59cc | |
parent | f853181f830e8a8d1792617eb07eb3f644706934 (diff) |
Add option for searching online repositories (#38)v0.8.0
-rw-r--r-- | README.md | 148 | ||||
-rw-r--r-- | cheats/awk.cheat | 6 | ||||
-rw-r--r-- | cheats/network.cheat | 2 | ||||
-rwxr-xr-x | navi | 34 | ||||
-rwxr-xr-x | src/cheat.sh | 4 | ||||
-rw-r--r-- | src/docs.sh | 33 | ||||
-rw-r--r-- | src/health.sh (renamed from src/healthcheck.sh) | 0 | ||||
-rw-r--r-- | src/main.sh | 20 | ||||
-rw-r--r-- | src/opts.sh | 44 | ||||
-rw-r--r-- | src/search.sh | 39 | ||||
-rw-r--r-- | src/str.sh | 4 | ||||
-rw-r--r-- | src/ui.sh | 9 |
12 files changed, 262 insertions, 81 deletions
@@ -6,37 +6,91 @@ An interactive cheatsheet tool for the command-line so that you'll never say the — *Oh, it's not in my bash history*<br> — *Geez, it's almost what I wanted but I need to change some args* -![Demo](https://user-images.githubusercontent.com/3226564/65380182-69431380-dcac-11e9-9af8-0f7b3c869d0f.gif) +![Demo](https://user-images.githubusercontent.com/3226564/65389667-0181dc80-dd2f-11e9-9fac-c875ed7c7b53.gif) **navi** allows you to browse through cheatsheets (that you may write yourself or download from maintainers) and execute commands, prompting for argument values. -## Installation +Table of Contents +----------------- + + * [Installation](#installation) + * [Using Homebrew or Linuxbrew](#using-homebrew-or-linuxbrew) + * [Using git](#using-git) + * [Upgrading](#upgrading) + * [Usage](#usage) + * [Preventing execution](#preventing-execution) + * [Pre-filtering](#pre-filtering) + * [Searching online repositories](#searching-online-repositories) + * [More options](#more-options) + * [Trying out online](#trying-out-online) + * [Motivation](#motivation) + * [Cheatsheets](#cheatsheets) + * [Using your own custom cheatsheets](#using-your-own-custom-cheatsheets) + * [Submitting cheatsheets](#submitting-cheatsheets) + * [Cheatsheet syntax](#cheatsheet-syntax) + * [Syntax overview](#syntax-overview) + * [Variables](#variables) + * [FZF options](#fzf-options) + * [Related projects](#related-projects) + * [Etymology](#etymology) + +Installation +------------ + +### Using Homebrew or Linuxbrew + +You can use [Homebrew](http://brew.sh/) or [Linuxbrew](http://linuxbrew.sh/) +to install **navi**. + +### Using git + +Alternatively, you can `git clone` this repository and run `make`: -**Using [brew](https://brew.sh/):** ```sh -brew install denisidoro/tools/navi -``` - -**Without brew:** -```sh -git clone http://github.com/denisidoro/navi /opt/navi +git clone --depth 1 http://github.com/denisidoro/navi /opt/navi cd /opt/navi sudo make install # install fzf: https://github.com/junegunn/fzf ``` -## Usage +Upgrading +--------- -Simply call: -```sh -navi -``` +**navi** is being actively developed and you might want to upgrade it once in a while. Please follow the instruction below depending on the installation method used: + +- brew: `brew update; brew reinstall navi` +- git: `cd /opt/navi && sudo make update` + +Usage +----- + +By simply running `navi` you will be prompted with the default cheatsheets. + +### Preventing execution + +If you run `navi --print`, the selected command won't be executed. It will be printed to stdout instead. + +### Pre-filtering + +If you run `navi query <cmd>`, the results will be pre-filtered. + +### Searching online repositories + +If you run `navi search <cmd>`, **navi** will try to download cheatsheets from online repositories as well. + +Please note that these cheatsheets aren't curated by **navi**'s maintainers and should be taken with a grain of salt. If you're not sure about executing these commands, make sure to check the preview window or use the `--print` option. + +### More options + +Please refer to `navi --help` for more details. -## Trying it out online +Trying out online +-------------------- -Head to [this playground](https://www.katacoda.com/denisidoro/scenarios/navi) for previewing **navi**. +If you don't have access to bash at the moment and you want to live preview **navi**, head to [this playground](https://www.katacoda.com/denisidoro/scenarios/navi). It'll start a docker container with instructions for you to install and use the tool. Note: login required. -## Motivation +Motivation +---------- The main objectives are: - to increase discoverability, by finding commands given keywords or descriptions; @@ -50,23 +104,31 @@ Or you can launch a browser and search for instructions on Google, but that take **navi**, on the other hand, intends to be a general purpose platform for bookmarking any command at a very low cost. -## Using your own cheatsheets +Cheatsheets +----------- -In this case, you need to pass the directory which contains `.cheat` files as in: +### Using your own custom cheatsheets + +In this case, you need to pass a `:`-separated list of separated directories which contain `.cheat`: ```sh -navi --dir "/folder/with/cheats" +navi --path "/folder/with/cheats" ``` Alternatively, you can set an environment variable in your `.bashrc`-like file: ```sh -export NAVI_DIR="/folder/with/cheats" +export NAVI_PATH="/folder/with/cheats:/another/folder" ``` -## Submitting cheatsheets +### Submitting cheatsheets Feel free to fork this project and open a PR for me to include your contributions. -## .cheat syntax +Cheatsheet syntax +----------------- + +Cheatsheets are describe in `.cheat` files. + +### Syntax overview - lines starting with `%` should contain tags which will be added to any command in a given file; - lines starting with `#` should be descriptions of commands; @@ -83,16 +145,40 @@ git checkout <branch> $ branch: git branch | awk '{print $NF}' ``` -For advanced usage, please refer to the files in [/cheats](https://github.com/denisidoro/navi/tree/master/cheats). +### Variables + +The interface prompts for variable names inside brackets (eg `<branch>`). + +The command for generating possible inputs can refer other variables: +```sh +# If you select 2 for x, the possible values of y will be 12 and 22 +echo <x> <y> + +$ x: echo -e '1\n2\n3' | tr '\n' ' ' +$ y: echo "$((x+10))" "$((x+20))" | tr '\n' ' ' +``` + +### FZF options + +You can make pick a specific column of a selection and set the number of lines considered as headers: + +```sh +# This will pick the 3rd column and use the first line as header +docker rmi <image_id> + +$ image_id: docker images --- --headers 1 --column 3 +``` + +Related projects +---------------- + +There are many similar projects out there ([bro](https://github.com/hubsmoke/bro), [eg](https://github.com/srsudar/eg), [cheat.sh](https://github.com/chubin/cheat.sh), [cmdmenu](https://github.com/amacfie/cmdmenu), [cheat](https://github.com/cheat/cheat), [beavr](https://github.com/denisidoro/beavr), [how2](https://github.com/santinic/how2) and [howdoi](https://github.com/gleitz/howdoi), to name a few). -## Alternatives +Most of them provide excellent cheatsheet repositories, but lack a nice UI. -- [cmdmenu](https://github.com/amacfie/cmdmenu); -- [denisidoro/beavr](https://github.com/denisidoro/beavr); -- [how2](https://github.com/santinic/how2); -- [howdoi](https://github.com/gleitz/howdoi); -- [cheat](https://github.com/cheat/cheat). +In any case, **navi** has the option to [search for some of these repositories](#installation). -## Etymology +Etymology +--------- In [The Legend of Zelda Ocarina of Time](https://zelda.gamepedia.com/Ocarina_of_Time), [navi](https://zelda.gamepedia.com/Navi) is a character that provides [Link](https://zelda.gamepedia.com/Link) with a variety of clues to help him solve puzzles and progress in his quest. diff --git a/cheats/awk.cheat b/cheats/awk.cheat index 984e8c7..080cd88 100644 --- a/cheats/awk.cheat +++ b/cheats/awk.cheat @@ -1,4 +1,4 @@ -% awk, text processing, string +% awk, string -# Print nth column -awk '{print $<n>}
\ No newline at end of file +# Print last column +echo '1 2 3' | awk '{print $NF}'
\ No newline at end of file diff --git a/cheats/network.cheat b/cheats/network.cheat index 1ea7fef..ee52b4d 100644 --- a/cheats/network.cheat +++ b/cheats/network.cheat @@ -10,4 +10,4 @@ netstat -tn 2>/dev/null | grep :<port> | awk '{print $5}' | cut -d: -f1 | sort | dig +short myip.opendns.com @resolver1.opendns.com # Find primary, local IP address -ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
\ No newline at end of file +ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | tail -n1
\ No newline at end of file @@ -5,17 +5,37 @@ export SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" source "${SCRIPT_DIR}/src/main.sh" -##? Command cheatsheet tool +##? An interactive cheatsheet tool for the command-line ##? ##? Usage: -##? cheats [options] +##? cheats [command] [<args>...] [options] +##? +##? Commands: +##? search <cmd> Search for cheatsheets on online repositories +##? query <cmd> Pre-filter results ##? ##? Options: -##? --print Prevent script execution [default: false] -##? --no-interpolation Prevent argument interpolation [default: false] -##? --no-preview Hide command preview window [default: false] +##? --print Prevent script execution +##? --path List of paths to look for cheats +##? --no-interpolation Prevent argument interpolation +##? --no-preview Hide command preview window +##? +##? Examples: +##? cheats +##? cheats --path '/some/folder:/another/folder' +##? cheats search awk +##? cheats search docker --print +##? cheats query git +##? +##? More info: +##? search +##? Queries cheatsheets from http://cheat.sh +##? Please note that these cheatsheets may not work out of the box +##? Always check the preview window before executing commands! +##? full docs +##? Please refer to the README at https://github.com/denisidoro/navi -VERSION="0.7.0" -docs::eval "$@" +VERSION="0.8.0" +opts::eval "$@" main "$@" diff --git a/src/cheat.sh b/src/cheat.sh index f96c8ee..203b8dd 100755 --- a/src/cheat.sh +++ b/src/cheat.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash cheat::find() { - find "${NAVI_DIR:-"${SCRIPT_DIR}/cheats"}" -iname '*.cheat' + for path in $(echo "$NAVI_PATH" | tr ':' '\n'); do + find "$path" -iname '*.cheat' + done } cheat::read_many() { diff --git a/src/docs.sh b/src/docs.sh deleted file mode 100644 index bb3bf4f..0000000 --- a/src/docs.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -docs::extract_help() { - local readonly file="$1" - grep "^##?" "$file" | cut -c 5- -} - -docs::eval() { - local wait_for="" - - entry_point="main" - print=false - interpolation=true - preview=true - - for arg in $@; do - case $wait_for in - dir) NAVI_DIR="$arg"; wait_for="" ;; - command-for) query="$(echo "$arg" | tr "^" " ")"; entry_point="preview"; break ;; - esac - - case $arg in - --print) print=true ;; - --no-interpolation) interpolation=false ;; - --version) echo "${VERSION:-unknown}" && exit 0 ;; - --help) docs::extract_help "$0" && exit 0 ;; - --command-for) wait_for="command-for" ;; - --no-preview) preview=false ;; - -d|--dir) wait_for="dir" ;; - esac - done -} diff --git a/src/healthcheck.sh b/src/health.sh index 90ed69d..90ed69d 100644 --- a/src/healthcheck.sh +++ b/src/health.sh diff --git a/src/main.sh b/src/main.sh index eadc22a..6a23659 100644 --- a/src/main.sh +++ b/src/main.sh @@ -2,9 +2,10 @@ source "${SCRIPT_DIR}/src/arg.sh" source "${SCRIPT_DIR}/src/cheat.sh" -source "${SCRIPT_DIR}/src/docs.sh" -source "${SCRIPT_DIR}/src/healthcheck.sh" +source "${SCRIPT_DIR}/src/health.sh" source "${SCRIPT_DIR}/src/misc.sh" +source "${SCRIPT_DIR}/src/opts.sh" +source "${SCRIPT_DIR}/src/search.sh" source "${SCRIPT_DIR}/src/selection.sh" source "${SCRIPT_DIR}/src/str.sh" source "${SCRIPT_DIR}/src/ui.sh" @@ -51,7 +52,18 @@ handler::preview() { main() { case ${entry_point:-} in - preview) handler::preview "$@" 2>/dev/null || echo "Unable to find command for '${query:-}'" ;; - *) health::fzf && handler::main "$@" ;; + preview) + handler::preview "$@" \ + || echo "Unable to find command for '${query:-}'" + ;; + search) + health::fzf + search::save "$query" || true + handler::main "$@" + ;; + *) + health::fzf + handler::main "$@" + ;; esac }
\ No newline at end of file diff --git a/src/opts.sh b/src/opts.sh new file mode 100644 index 0000000..552406d --- /dev/null +++ b/src/opts.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +opts::extract_help() { + local readonly file="$1" + grep "^##?" "$file" | cut -c 5- +} + +opts::eval() { + local readonly wait_for="" + + entry_point="main" + print=false + interpolation=true + preview=true + + for arg in "$@"; do + case $wait_for in + path) NAVI_PATH="$arg"; wait_for="" ;; + preview) query="$(echo "$arg" | tr "^" " ")"; wait_for=""; break ;; + search) query="$arg"; wait_for=""; export NAVI_PATH="${NAVI_PATH}:$(search::full_path "$query")"; ;; + query) query="$arg"; wait_for="" ;; + esac + + case $arg in + --print) print=true ;; + --no-interpolation) interpolation=false ;; + --version) echo "${VERSION:-unknown}" && exit 0 ;; + help|--help) opts::extract_help "$0" && exit 0 ;; + --command-for) wait_for="command-for" ;; + --no-preview) preview=false ;; + --path) wait_for="path" ;; + search) entry_point="search"; wait_for="search";; + preview) entry_point="preview"; wait_for="preview";; + q|query) wait_for="query";; + esac + done +} + +opts::fallback_path() { + echo "${NAVI_DIR:-${SCRIPT_DIR}/cheats}" +} + +export NAVI_PATH="${NAVI_PATH:-$(opts::fallback_path)}"
\ No newline at end of file diff --git a/src/search.sh b/src/search.sh new file mode 100644 index 0000000..1c2be4b --- /dev/null +++ b/src/search.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +search::cheat() { + local readonly cmd="$(echo "$1" | str::first_word)" + + echo "% ${cmd}, cheatsh" + echo + curl -s "${CHTSH_URL:-http://cht.sh}/${cmd}?T" +} + +search::filename() { + local readonly cmd="$(echo "$1" | str::first_word)" + + echo "${cmd}_cheatsh" \ + | head -n1 \ + | awk '{print $NF}' \ + | xargs \ + | tr ' ' '_' +} + +search::full_path() { + local readonly cmd="$(echo "$1" | str::first_word)" + + echo "/tmp/navi/$(search::filename "$cmd").cheat" +} + +search::save() { + local readonly cmd="$(echo "$1" | str::first_word)" + + local readonly filepath="$(search::full_path "$cmd")" + local readonly filedir="$(dirname "$filepath")" + + if [ -f "$filepath" ]; then + return + fi + + mkdir -p "$filedir" &> /dev/null || true + search::cheat "$cmd" > "$filepath" +}
\ No newline at end of file @@ -25,3 +25,7 @@ str::last_paragraph_line() { awk '(!NF) { exit } { print $0 }' \ | tail -n1 } + +str::first_word() { + awk '{print $1}' +} @@ -7,7 +7,7 @@ ui::pick() { ui::select() { local readonly cheats="$1" local readonly script_path="$(which navi | head -n1 || echo "${SCRIPT_DIR}/navi")" - local readonly preview_cmd="echo {} | tr ' ' '^' | xargs -I% \"${script_path}\" --command-for %" + local readonly preview_cmd="echo \"{}\" | tr ' ' '^' | xargs -I% \"${script_path}\" preview %" local args=() args+=("-i") @@ -16,6 +16,13 @@ ui::select() { args+=("--preview"); args+=("$preview_cmd") args+=("--preview-window"); args+=("up:1") fi + if [ -n "${query:-}" ]; then + args+=("--query=${query} ") + fi + if [ "${entry_point:-}" = "search" ]; then + args+=("--header") + args+=("Displaying online results. Please refer to 'navi --help' for details") + fi echo "$cheats" \ | cheat::read_many \ |