diff --git a/README.md b/README.md index 57b4679..6c5147a 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Here's a list of the most interesting ones, along with what they do and where th - [repren](https://github.com/jlevy/repren) - A good bulk file renaming tool. - [goldilocks](http://unix.stackexchange.com/a/124460/64687) - A script that displays all of the possible terminal colours. - [catimg](https://github.com/posva/catimg) - A cool script to display images in the terminal. Useful when you're sshing into servers. - - [tldr](https://github.com/raylee/tldr) - A bash client for + - [tldr](http://github.com/pepa65/tldr-bash-client) - A bash client for [tldr-pages](https://github.com/tldr-pages/tldr). - [git ignore](https://gitignore.io/) - A really useful subcommand for git that allows you to generate ignore files automagically. - organise-photos - A small bash script I wrote that organises the photos in a directory by year & month. diff --git a/tldr b/tldr index 2b294c0..7934924 100755 --- a/tldr +++ b/tldr @@ -1,246 +1,419 @@ #!/bin/bash -# tldr client by Ray Lee, http://github.com/raylee/tldr -# a Sunday afternoon's project, I'm sure there's room for improvement. PRs welcome! +set +vx -o pipefail +[[ $- = *i* ]] && echo "Don't source this script!" && return 1 +version='0.3' +# tldr-bash-client version 0.3 +# Bash client for tldr: community driven man-by-example +# - forked from Ray Lee, http://github.com/raylee/tldr +# - modified and expanded by pepa65: http://github.com/pepa65/tldr-bash-client +# Requiring: coreutils, less, grep, unzip, curl/wget -set -uf -o pipefail +# The 5 elements in TLDR markup that can be styled with these colors and +# backgrounds (last one specified will be used) and modes (more can apply): +# Colors: Black, Red, Green, Yellow, Blue, Magenta, Cyan, White +# BG: BlackBG, RedBG, GreenBG, YellowBG, BlueBG, MagentaBG, CyanBG, WhiteBG +# Modes: Bold, Underline, Italic, Inverse +# 'Newline' can be added to the style list to add a newline before the element +# and 'Space' to add a space at the start of the line +# (style items are separated by space, lower/uppercase mixed allowed) +: "${TLDR_TITLE_STYLE:= Newline Space Bold Yellow }" +: "${TLDR_DESCRIPTION_STYLE:= Space Yellow }" +: "${TLDR_EXAMPLE_STYLE:= Newline Space Bold Green }" +: "${TLDR_CODE_STYLE:= Space Bold Blue }" +: "${TLDR_VALUE_ISTYLE:= Space Bold Cyan }" +# The Value style (above) is an Inline style: doesn't take Newline or Space +# Inline styles for help text: default, URL, option, platform, command, header +: "${TLDR_DEFAULT_ISTYLE:= White }" +: "${TLDR_URL_ISTYLE:= Yellow }" +: "${TLDR_HEADER_ISTYLE:= Bold }" +: "${TLDR_OPTION_ISTYLE:= Bold Yellow }" +: "${TLDR_PLATFORM_ISTYLE:= Bold Blue }" +: "${TLDR_COMMAND_ISTYLE:= Bold Cyan }" +: "${TLDR_FILE_ISTYLE:= Bold Magenta }" +# Color/BG (Newline and Space also allowed) for error and info messages +: "${TLDR_ERROR_COLOR:= Newline Space Red }" +: "${TLDR_INFO_COLOR:= Newline Space Green }" -# initialize globals, sanity check the environment, etc. -config() { - init_term_cmds +# How many days before freshly downloading a potentially stale page +: "${TLDR_EXPIRY:= 60 }" - if [ -z $(which curl) ]; then - echo "${red}tldr requires \`curl\` installed in your path$reset" - exit 1 - fi +# Alternative location of pages cache +: "${TLDR_CACHE:= }" - configdir=~/.tldr - [ -d ~/.config ] && configdir=~/.config/tldr +# $1: [optional] exit code; Uses: version cachedir +Usage(){ + Out "$(cat <<-EOF + $HHE $version - platform=$(get_platform) - base_url="https://raw.githubusercontent.com/tldr-pages/tldr/master/pages" - index_url="http://tldr-pages.github.io/assets/index.json" - index="$configdir/index.json" - cache_days=14 - force_update='' + $HDE USAGE: $HHE$(basename "$0")$XHHE [${HOP}option$XHOP] [${HPL}platform$XHPL/]${HCO}command$XHCO - #check if config folder exists, otherwise create it - [ -d "$configdir" ] || mkdir -p "$configdir" + $HDE [${HPL}platform$XHPL/]${HCO}command$XHCO: Show page for$HCO command$XHCO (from$HPL platform$XHPL) - [ ! -f $index ] && update_index - auto_update_index + $HPL platform$XHPL is optionally one of:$HPL common$XHPL,$HPL linux$XHPL,$HPL osx$XHPL,$HPL sunos$XHPL + + $HOP option$XHOP is optionally one of: + $HOP-l$XHOP,$HOP --list$XHOP [${HPL}platform$XHPL]: Show all available pages (from$HPL platform$XHPL) + $HOP-r$XHOP,$HOP --render$XHOP ${HFI}file$XHFI: Render a local$HFI file$XHFI as tldr markdown + $HOP-m$XHOP,$HOP --markdown$XHOP ${HCO}command$XHCO: Show the markdown source for$HCO command$XHCO + $HOP-c$XHOP,$HOP --cache$XHOP: Cache all pages by downloading archive from repo + $HOP-u$XHOP,$HOP --update$XHOP: Re-download index file from repo + $HOP-v$XHOP,$HOP --version$XHOP: Version number and repo location + $HDE[$HOP-h$XHOP,$HOP -?$XHOP,$HOP --help$XHOP]: This help overview + + $HDE Element styling:$XHDE$T Title$XT$D Description$XD$E Example$XD$C Code$XC$V Value$XV + $HDE All pages and the index are cached locally under $HUR$cachedir$XHUR. + $HDE By default, the cached copies will be freshly downloaded after $HUR${TLDR_EXPIRY// /}$XHUR days. + EOF + )" + exit "${1:-0}" } -update_index() { - curl -sf -o "$index" "$index_url" - res=$? - if [ $res -eq 22 ]; then - echo "Could not download index from $index_url" - exit 1 - fi +# $1: keep output; Uses/Sets: stdout +Out(){ stdout+=$1$N;} + +# $1: keep error messages +Err(){ Out "$ERRNL$ERRSP$ERR$B$1$XB$XERR";} + +# $1: keep info messages +Inf(){ Out "$INFNL$INFSP$INF$B$1$XB$XINF";} + +# $1: Style specification; Uses: color xcolor bg xbg mode xmode +Style(){ + local -l style + STYLES='' XSTYLES='' COLOR='' XCOLOR='' NL='' SP='' + for style in $1 + do + [[ $style = newline ]] && NL=$N + [[ $style = space ]] && SP=' ' + COLOR+=${color[$style]:-}${bg[$style]:-} + XCOLOR=${xbg[$style]:-}${xcolor[$style]:-}$XCOLOR + STYLES+=${color[$style]:-}${bg[$style]:-}${mode[$style]:-} + XSTYLES=${xmode[$style]:-}${xbg[$style]:-}${xcolor[$style]:-}$XSTYLES + done +} + +# Sets: color xcolor bg xbg mode xmode +Init_term(){ + [[ -t 2 ]] && { # only if interactive session (stderr open) + B=$'\e[1m' # $(tput bold || tput md) # Start bold + XB=$'\e[0m' # End bold (no tput code...) + U=$'\e[4m' # $(tput smul || tput us) # Start underline + XU=$'\e[24m' # $(tput rmul || tput ue) # End underline + I=$'\e[3m' # $(tput sitm || tput ZH) # Start italic + XI=$'\e[23m' # $(tput ritm || tput ZR) # End italic + R=$'\e[7m' # $(tput smso || tput so) # Start reverse + XR=$'\e[27m' # $(tput rmso || tput se) # End reverse + #X=$'\e[0m' # $(tput sgr0 || tput me) # End all + + [[ $TERM != *-m ]] && { + BLA=$'\e[30m' # $(tput setaf 0 || tput AF 0) + RED=$'\e[31m' # $(tput setaf 1 || tput AF 1) + GRE=$'\e[32m' # $(tput setaf 2 || tput AF 2) + YEL=$'\e[33m' # $(tput setaf 3 || tput AF 3) + BLU=$'\e[34m' # $(tput setaf 4 || tput AF 4) + MAG=$'\e[35m' # $(tput setaf 5 || tput AF 5) + CYA=$'\e[36m' # $(tput setaf 6 || tput AF 6) + WHI=$'\e[37m' # $(tput setaf 7 || tput AF 7) + DEF=$'\e[39m' # $(tput op) + BLAB=$'\e[40m' # $(tput setab 0 || tput AB 0) + REDB=$'\e[41m' # $(tput setab 1 || tput AB 1) + GREB=$'\e[42m' # $(tput setab 2 || tput AB 2) + YELB=$'\e[43m' # $(tput setab 3 || tput AB 3) + BLUB=$'\e[44m' # $(tput setab 4 || tput AB 4) + MAGB=$'\e[45m' # $(tput setab 5 || tput AB 5) + CYAB=$'\e[46m' # $(tput setab 6 || tput AB 6) + WHIB=$'\e[47m' # $(tput setab 7 || tput AB 7) + DEFB=$'\e[49m' # $(tput op) + } + } + + declare -A color=(['black']=$BLA ['red']=$RED ['green']=$GRE ['yellow']=$YEL \ + ['blue']=$BLU ['magenta']=$MAG ['cyan']=$CYA ['white']=$WHI) + declare -A xcolor=(['black']=$DEF ['red']=$DEF ['green']=$DEF ['yellow']=$DEF \ + ['blue']=$DEF ['magenta']=$DEF ['cyan']=$DEF ['white']=$DEF) + declare -A bg=(['blackbg']=$BLAB ['redbg']=$REDB ['greenbg']=$GREB ['yellowbg']=$YELB \ + ['bluebg']=$BLUB ['magentabg']=$MAGB ['cyanbg']=$CYAB ['whitebg']=$WHIB) + declare -A xbg=(['blackbg']=$DEFB ['redbg']=$DEFB ['greenbg']=$DEFB ['yellowbg']=$DEFB \ + ['bluebg']=$DEFB ['magentabg']=$DEFB ['cyanbg']=$DEFB ['whitebg']=$DEFB) + declare -A mode=(['bold']=$B ['underline']=$U ['italic']=$I ['inverse']=$R) + declare -A xmode=(['bold']=$XB ['underline']=$XU ['italic']=$XI ['inverse']=$XR) + + # the 5 main tldr page styles and error message colors + Style "$TLDR_TITLE_STYLE" + T=$STYLES XT=$XSTYLES TNL=$NL TSP=$SP + Style "$TLDR_DESCRIPTION_STYLE" + D=$STYLES XD=$XSTYLES DNL=$NL DSP=$SP + Style "$TLDR_EXAMPLE_STYLE" + E=$STYLES XE=$XSTYLES ENL=$NL ESP=$SP + Style "$TLDR_CODE_STYLE" + C=$STYLES XC=$XSTYLES CNL=$NL CSP=$SP + Style "$TLDR_VALUE_ISTYLE" + V=$STYLES XV=$XSTYLES + Style "$TLDR_DEFAULT_ISTYLE" + HDE=$STYLES XHDE=$XSTYLES + Style "$TLDR_URL_ISTYLE" + URL=$STYLES XURL=$XSTYLES + HUR=$XHDE$STYLES XHUR=$XSTYLES$HDE + Style "$TLDR_OPTION_ISTYLE" + HOP=$XHDE$STYLES XHOP=$XSTYLES$HDE + Style "$TLDR_PLATFORM_ISTYLE" + HPL=$XHDE$STYLES XHPL=$XSTYLES$HDE + Style "$TLDR_COMMAND_ISTYLE" + HCO=$XHDE$STYLES XHCO=$XSTYLES$HDE + Style "$TLDR_FILE_ISTYLE" + HFI=$XHDE$STYLES XHFI=$XSTYLES$HDE + Style "$TLDR_HEADER_ISTYLE" + HHE=$XHDE$STYLES XHHE=$XSTYLES$HDE + Style "$TLDR_ERROR_COLOR" + ERR=$COLOR XERR=$XCOLOR ERRNL=$NL ERRSP=$SP + Style "$TLDR_INFO_COLOR" + INF=$COLOR XINF=$XCOLOR INFNL=$NL INFSP=$SP } -# if the file exists and is more recent than $cache_days old -recent() { - exists=$(find "$1" -mtime -$cache_days 2>/dev/null) - [ -n "$exists" -a -z "$force_update" ] +# $1: page +Recent(){ find "$1" -mtime -"${TLDR_EXPIRY// /}" >/dev/null 2>&1;} + +# Download index.json; Uses: index index_url base_url zip_url dl +Update_index(){ + $dl "$index" "$index_url" && Inf "Index file $I$index$XI freshly downloaded" || { + Err "Could not download index from $I$index_url$XI" + exit 2 + } } -auto_update_index() { - recent "$index" || update_index +# Initialize globals, check the environment; Uses: config cachedir version +# Sets: stdout os version dl +Config(){ + os=common stdout='' Q='"' N=$'\n' + case "$(uname -s)" in + Darwin) os='osx' ;; + Linux) os='linux' ;; + SunOS) os='sunos' ;; + esac + Init_term + trap 'less -~RXQFP"Browse up/down, press Q to exit " <<<"$stdout"' EXIT + + version="tldr-bash-client version $version $XB$URL http://github.com/pepa65/tldr-bash-client$XURL" + + # Select download method + dl="$(type -p curl) -sfo" || { + dl="$(type -p wget) -qNO" || { + Err "tldr requires$I curl$XI or$I wget $XI installed in your path" + exit 3 + } + } + + base_url='https://raw.githubusercontent.com/tldr-pages/tldr/master/pages' + zip_url='http://tldr-pages.github.io/assets/tldr.zip' + index_url='http://tldr-pages.github.io/assets/index.json' + + read cachedir <<<$TLDR_CACHE + [[ $cachedir ]] || { + [[ $XDG_DATA_HOME ]] && cachedir=$XDG_DATA_HOME/tldr \ + || cachedir=$HOME/.local/share/tldr + } + [[ -d "$cachedir" ]] || mkdir -p "$cachedir" || { + Err "Can't create the pages cache location $cachedir" + exit 4 + } + index=$cachedir/index.json + # update if the file doesn't exists, or if it's older than $TLDR_EXPIRY + [[ -f $index ]] && Recent "$index" || Update_index } -# function contents via http://mywiki.wooledge.org/BashFAQ/037 -init_term_cmds() { - # only set if we're on an interactive session - [[ -t 2 ]] && { - reset=$( tput sgr0 || tput me ) # Reset cursor - bold=$( tput bold || tput md ) # Start bold - under=$( tput smul || tput us ) # Start underline - italic=$( tput sitm || tput ZH ) # Start italic - eitalic=$( tput ritm || tput ZH ) # End italic - default=$( tput op ) - back=$'\b' - - [[ $TERM != *-m ]] && { - black=$( tput setaf 0 || tput AF 0 ) - red=$( tput setaf 1 || tput AF 1 ) - green=$( tput setaf 2 || tput AF 2 ) - yellow=$( tput setaf 3 || tput AF 3 ) - blue=$( tput setaf 4 || tput AF 4 ) - magenta=$( tput setaf 5 || tput AF 5 ) - cyan=$( tput setaf 6 || tput AF 6 ) - white=$( tput setaf 7 || tput AF 7 ) - - onblue=$( tput setab 4 || tput AB 4 ) - ongrey=$( tput setab 7 || tput AB 7 ) - } - } 2>/dev/null ||: - - # osx's termcap doesn't have italics. The below adds support for iTerm2 - # and is harmless on Terminal.app - [ "$(get_platform)" = "osx" ] && { - italic=$(echo -e "\033[3m") - eitalic=$(echo -e "\033[23m") - } +# $1: error message; Uses: md line ln +Unlinted(){ + Err "Page $I$md$XI not properly linted!$N${ERRSP}${ERR}Line $I$ln$XI [$XERR$U$line$XU$ERR]$N$ERRSP$ERR$1" + exit 4 } -heading() { - local line="$*" - echo "$bold$red${line:2}$reset" +# $1: page; Uses: index index_url cachedir base_url platform os dl cached md +# Sets: cached md +Get_tldr(){ + local desc err notfound + # convert the local platform name to tldr's version + # extract the platform key from index.json, return preferred subpath to page + desc=$(tr '{' '\n' <$index |grep "\"name\":\"$1\"") + # results in, eg, "name":"netstat","platform":["linux","osx"]}, + + [[ $desc ]] || return # just not found + + err=0 + if [[ $platform ]] + then # platform given on commandline + [[ ! $desc =~ \"$platform\" ]] && notfound=$I$platform$XI && err=1 || md=$platform/$1.md + else # check common + [[ $desc =~ \"common\" ]] && md=common/$1.md || { # not in common either + [[ $notfound ]] && notfound+=" or " + notfound+=${I}common$XI + } + fi + # if no page found yet, try the system platform + [[ $md ]] || [[ $platform = "$os" ]] || { + [[ $desc =~ \"$os\" ]] && md=$os/$1.md + } || { + notfound+=" or $I$os$XI" + err=1 + } + # if still no page found, get the first entry in index + [[ $md ]] || md=$(cut -d "$Q" -f 8 <<<"$desc")/"$1.md" + ((err)) && Err "tldr page $I$1$XI not found in $notfound, from platform $U${md%/*}$XU instead" + + # return the local cached copy of the tldrpage, or retrieve and cache from github + cached=$cachedir/$md + Recent "$cached" || { + mkdir -p "${cached%/*}" + $dl "$cached" "$base_url/$md" || Err "Could not download page $I$cached$XI from index $U$index_url$XU" + } } -quotation() { - local line="$*" - echo "$under${line:2}$reset" +# $1: text; Uses: page stdout; Sets: ln line +Display_tldr(){ + local newfmt len val + ln=0 line='' + [[ $md ]] || md=$1 + # Read full lines, and process even when no newline at the end + while read -r line || [[ $line ]] + do + ((++ln)) + ((ln==1)) && { + [[ ${line:0:1} = '#' ]] && newfmt=0 || newfmt=1 + ((newfmt)) && { + [[ $line ]] || Unlinted "No title" + Out "$TNL$TSP$T$line$XT" + len=${#line} + read -r; ((++ln)) + [[ $line =~ [^=] ]] && Unlinted "Title underline must be equal signs" + ((len!=${#line})) && Unlinted "Underline length not equal to title's" + read -r; ((++ln)) + } + } + case "${line:0:1}" in # first character + '#') ((newfmt)) && Unlinted "Bad first character" + ((${#line} <= 2)) && Unlinted "No title" + [[ ! ${line:1:1} = ' ' ]] && Unlinted "2nd character no space" + Out "$TNL$TSP$T${line:2}$XT" ;; + '>') ((${#line} <= 3)) && Unlinted "No valid desciption" + [[ ! ${line:1:1} = ' ' ]] && Unlinted "2nd character no space" + [[ ! ${line: -1} = '.' ]] && Unlinted "Description doesn't end in full stop" + Out "$DNL$DSP$D${line:2}$XD" + DNL='' ;; + '-') ((newfmt)) && Unlinted "Bad first character" + ((${#line} <= 2)) && Unlinted "No example content" + [[ ! ${line:1:1} = ' ' ]] && Unlinted "2nd character no space" + Out "$ENL$ESP$E${line:2}$XE" ;; + ' ') ((newfmt)) || Unlinted "Bad first character" + ((${#line} <= 4)) && Unlinted "No valid code content" + [[ ${line:0:4} = ' ' ]] || Unlinted "No four spaces before code" + val=${line:4} + # Value: convert {{value}} + val=${val//\{\{/$CX$V} + val=${val//\}\}/$XV$C} + Out "$CNL$CSP$C$val$XC" ;; + '`') ((newfmt)) && Unlinted "Bad first character" + ((${#line} <= 2)) && Unlinted "No valid code content" + [[ ! ${line: -1} = '`' ]] && Unlinted "Code doesn't end in backtick" + val=${line:1:-1} + # Value: convert {{value}} + val=${val//\{\{/$CX$V} + val=${val//\}\}/$XV$C} + Out "$CNL$CSP$C$val$XC" ;; + '') continue ;; + *) ((newfmt)) || Unlinted "Bad first character" + [[ -z $line ]] && Unlinted "No example content" + Out "$ENL$EPS$E$line$XE" ;; + esac + done <"$1" + trap 'less +Gg -~RXQFP"%pB\% tldr $I$page$XI - browse up/down, press Q to exit" <<<"$stdout"' EXIT } -list_item() { - local line="$*" - echo "$line$reset" +# $1: exit code; Uses: platform index +List_pages(){ + local platformtext c1 c2 c3 + [[ $platform ]] && platformtext=" from platform $I$platform$XI" + Inf "Known tldr pages$platformtext:" + Out "$(while read -r c1 c2 c3; do printf "%-19s %-19s %-19s %-19s$N" $c1 $c2 $c3; done \ + <<<$(tr '{' '\n' <$index |grep "$platform" |cut -d "$Q" -f4))" + exit "$1" } -code() { - local line="$*" - # I'm sure there's a better way to strip the first and last characters. - line="${line:1}" - line="${line%\`}" - # convert {{variable}} to italics - line=${line//\{\{/$italic} - line=${line//\}\}/$eitalic} - - echo "$bold$line$reset" +# $1: exit code; Uses: dl cachedir zip_url +Cache_fill(){ + local tmp unzip + tmp=$(mktemp -d) + $dl "$tmp/pages.zip" "$zip_url" || { + rm -- "$tmp" + Err "Could not download pages archive from $U$zip_url$XU" + exit 6 + } + unzip="$(type -p unzip) -q" || { + rm -- "$tmp" + Err "Unzip is necessary to fill the cache" + exit 7 + } + $unzip "$tmp/pages.zip" -d "$tmp" 'pages/*' + rm -rf -- "${cachedir:?}/"* + mv -- "$tmp/pages/"* "${cachedir:?}/" + rm -rf -- "$tmp" + Inf "Pages cached in $U$cachedir$XU" + exit "$1" } -text() { - local line="$*" - echo "$line" +# $@: commandline parameters; Uses: version cached; Sets: platform page +Main(){ + local markdown err + Config + markdown=0 err=0 + case "$1" in + -l|--list) [[ $2 ]] && { + platform=$2 + [[ ,common,linux,osx,sunos, = *,$platform,* ]] || { + Err "Unknown platform $I$platform$XI" + Usage 8 + } + [[ $3 ]] && Err "No more command line arguments allowed" && err=9 + } + List_pages "$err" ;; + -c|--cache) [[ $2 ]] && Err "No more command line arguments allowed" && err=10 + Cache_fill "$err" ;; + -v|--version) [[ $2 ]] && Err "No more command line arguments allowed" && err=11 + Inf "$version" + exit "$err" ;; + -u|--update) [[ $2 ]] && Err "No more command line arguments allowed" && err=12 + Update_index + exit "$err" ;; + -r|--render) [[ -z $2 ]] && Err "Specify a file to render" && Usage 13 + [[ $3 ]] && Err "No more command line arguments allowed" && err=14 + [[ -f "$2" ]] && { + Display_tldr "$2" && exit "$err" + Err "A file error occured" + exit 15 + } || Err "No file:$I $2$XI" && exit 16 ;; + -m|--markdown) shift + page=$* + [[ -z $page ]] && Err "Specify a page to display" && Usage 17 + [[ -f "$page" && ${page: -3:3} = .md ]] && Out "$(cat "$page")" && exit 0 + markdown=1 ;; + ''|-h|-\?|--help) [[ $2 ]] && Err "No more command line arguments allowed" && err=18 + Usage "$err" ;; + -*) Err "Unrecognized option $I$1$XI"; Usage 19 ;; + *) page=$* ;; + esac + + [[ -z $page ]] && Err "No command specified" && Usage 20 + [[ $page =~ ' -' || ${page:0:1} = '-' ]] && Err "Only one option allowed" && Usage 21 + [[ $page = */* ]] && platform=${page%/*} && page=${page##*/} + [[ $platform && ,common,linux,osx,sunos, != *,$platform,* ]] && { + Err "Unknown platform $I$platform$XI" + Usage 22 + } + + Get_tldr "${page// /-}" + [[ ! -s $cached ]] && Err "tldr page for command $I$page$XI not found" \ + && Inf "Contribute new pages at:$XB$URL https://github.com/tldr-pages/tldr$XURL" && exit 23 + ((markdown)) && Out "$(cat "$cached")" || Display_tldr "$cached" } -# an idiot-level recognition of tldr's markdown. Needs improvement, or -# subcontracting out to a markdown -> ANSI formatting command -display_tldr() { - # read one line at a time, don't strip whitespace ('IFS='), and process - # last line even if it doesn't have a newline at the end - while IFS= read -r line || [[ -n "$line" ]]; do - start=${line:0:1} # get the first character - case "$start" in - '#') heading "$line" - ;; - '>') quotation "$line" - ;; - '-') list_item "$line" - ;; - '`') code "$line" - ;; - *) text "$line" - ;; - esac - done -} - -# convert the local platorm name to tldr's version -get_platform() { - case `uname -s` in - Darwin) echo "osx" ;; - Linux) echo "linux" ;; - SunOS) echo "sunos" ;; - *) echo "common" ;; - esac -} - -# extract the platform key from index.json, return preferred subpath to tldrpage -path_for_cmd() { - local desc=$(tr '{' '\n' < $index | grep "\"name\":\"$1\"") - # results in, eg, "name":"netstat","platform":["linux","osx"]}, - - [ -z "$desc" ] && return - - # use the platform specific version of the tldr first - if [[ $desc =~ \"$platform\" ]]; then - echo "$platform/$1.md" - elif [[ $desc =~ \"common\" ]]; then - echo "common/$1.md" - else - # take the first one so we can show something, but warn the user - local p=$(echo "$desc" | cut -d '"' -f 8) - >&2 echo -e "${red}tldr page $1 not found in $platform or common, using page from platform $p instead$reset\n" - echo "$p/$1.md" - fi -} - -# return the local cached copy of the tldrpage, or retrieve and cache from github -get_tldr() { - local p="$(path_for_cmd $1)" - cached="$configdir/$p" - recent "$cached" || { - mkdir -p $(dirname $cached) - curl -sf -o "$cached" "$base_url/$p" - } - # if the curl failed for some reason, keep cat from whinging - cat "$cached" 2>/dev/null -} - - -config - -usage() { - cmd=$(basename $0) - cat < - -[options] - -l, --list: show all available pages - -p, --platform: show page from specific platform rather than autodetecting - -u, --update: update, force retrieving latest copies of locally cached files - -h, -?, --help: this help overview - - - Show examples for this command - -The client caches a copy of all pages and the index locally under -$configdir. By default, the cached copies will expire in $cache_days days. - -EOF +Main "$@" +# The error trap will output the accumulated stdout exit 0 -} - -while [ $# -gt 0 ] -do - case "$1" in - -l|--list) - >&2 echo -e "Known tldr pages: \n" - tr '{' '\n' < "$configdir/index.json" | cut -d '"' -f4 | column - exit 0 - ;; - -u|--update) - force_update=yes - update_index - ;; - -h|-\?|--help) - usage - ;; - -p|--platform) - shift - platform=$1 - ;; - -*) - usage - ;; - *) - page=${1:-''} - ;; - esac - shift -done - -[ -z ${page:-} ] && usage - -tldr="$(get_tldr $page)" - -if [ -z "$tldr" ]; then - echo "tldr page for command $page not found" - exit 1 -fi - -display_tldr <<< "$tldr" -echo