|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -o pipefail |
| 4 | + |
| 5 | +# tmux requires unrecognized OSC sequences to be wrapped with DCS tmux; |
| 6 | +# <sequence> ST, and for all ESCs in <sequence> to be replaced with ESC ESC. It |
| 7 | +# only accepts ESC backslash for ST. We use TERM instead of TMUX because TERM |
| 8 | +# gets passed through ssh. |
| 9 | +function print_osc() { |
| 10 | + if [[ $TERM == screen* || $TERM == tmux* ]]; then |
| 11 | + printf "\033Ptmux;\033\033]" |
| 12 | + else |
| 13 | + printf "\033]" |
| 14 | + fi |
| 15 | +} |
| 16 | + |
| 17 | +# More of the tmux workaround described above. |
| 18 | +function print_st() { |
| 19 | + if [[ $TERM == screen* || $TERM == tmux* ]]; then |
| 20 | + printf "\a\033\\" |
| 21 | + else |
| 22 | + printf "\a" |
| 23 | + fi |
| 24 | +} |
| 25 | + |
| 26 | +function load_version() { |
| 27 | + if [ -z ${IT2CAT_BASE64_VERSION+x} ]; then |
| 28 | + IT2CAT_BASE64_VERSION=$(base64 --version 2>&1) |
| 29 | + export IT2CAT_BASE64_VERSION |
| 30 | + fi |
| 31 | +} |
| 32 | + |
| 33 | +function b64_encode() { |
| 34 | + load_version |
| 35 | + if [[ $IT2CAT_BASE64_VERSION =~ GNU ]]; then |
| 36 | + # Disable line wrap |
| 37 | + base64 -w0 |
| 38 | + else |
| 39 | + base64 |
| 40 | + fi |
| 41 | +} |
| 42 | + |
| 43 | +function b64_decode() { |
| 44 | + load_version |
| 45 | + if [[ $IT2CAT_BASE64_VERSION =~ fourmilab ]]; then |
| 46 | + BASE64ARG=-d |
| 47 | + elif [[ $IT2CAT_BASE64_VERSION =~ GNU ]]; then |
| 48 | + BASE64ARG=-di |
| 49 | + else |
| 50 | + BASE64ARG=-D |
| 51 | + fi |
| 52 | + base64 $BASE64ARG |
| 53 | +} |
| 54 | + |
| 55 | +# print_file filename base64contents type mode |
| 56 | +# filename: Filename to convey to client |
| 57 | +# base64contents: Base64-encoded contents |
| 58 | +# type: type hint |
| 59 | +# mode: wide or regular |
| 60 | +function print_file() { |
| 61 | + print_osc |
| 62 | + printf "1337;File=inline=1" |
| 63 | + printf ";size=%d" $(printf "%s" "$2" | b64_decode | wc -c) |
| 64 | + [ -n "$1" ] && printf ";name=%s" "$(printf "%s" "$1" | b64_encode)" |
| 65 | + [ -n "$3" ] && printf ";type=%s" "$3" |
| 66 | + [ -n "$4" ] && printf ";mode=%s" "$4" |
| 67 | + printf ":%s" "$2" |
| 68 | + print_st |
| 69 | + printf '\n' |
| 70 | + did_print=t |
| 71 | +} |
| 72 | + |
| 73 | +function error() { |
| 74 | + errcho "ERROR: $*" |
| 75 | +} |
| 76 | + |
| 77 | +function errcho() { |
| 78 | + echo "$@" >&2 |
| 79 | +} |
| 80 | + |
| 81 | +function show_help() { |
| 82 | + errcho |
| 83 | + errcho "Usage: it2cat [-w] [-t file-type] [-u] [-f] filename ..." |
| 84 | + errcho " cat filename | it2cat [-w] [-t file-type]" |
| 85 | + errcho |
| 86 | + errcho "Display a text file with native rendering." |
| 87 | + errcho |
| 88 | + errcho "Options:" |
| 89 | + errcho |
| 90 | + errcho " -h, --help Display help message" |
| 91 | + errcho " -u, --url Interpret following filename arguments as remote URLs" |
| 92 | + errcho " -f, --file Interpret following filename arguments as regular Files" |
| 93 | + errcho " -t, --type file-type Provides a type hint" |
| 94 | + errcho " -w, --wide Render in wide mode with a horizontal scrollbar" |
| 95 | + errcho |
| 96 | + errcho " If a type is provided, it is used as a hint to disambiguate." |
| 97 | + errcho " The file type can be a mime type like text/markdown, a language name like Java, or a file extension like .c" |
| 98 | + errcho " The file type can usually be inferred from the extension or its contents. -t is most useful when" |
| 99 | + errcho " a filename is not available, such as whe input comes from a pipe." |
| 100 | + errcho |
| 101 | + errcho "Examples:" |
| 102 | + errcho |
| 103 | + errcho " $ it2cat file.txt" |
| 104 | + errcho " $ cat graph.png | it2cat" |
| 105 | + errcho " $ it2cat -u http://example.com/path/to/file.txt -f otherfile.txt" |
| 106 | + errcho " $ cat url_list.txt | xargs it2cat -u" |
| 107 | + errcho " $ it2cat -w -t application/json config.json" |
| 108 | + errcho |
| 109 | +} |
| 110 | + |
| 111 | +function check_dependency() { |
| 112 | + if ! (builtin command -V "$1" >/dev/null 2>&1); then |
| 113 | + error "missing dependency: can't find $1" |
| 114 | + exit 1 |
| 115 | + fi |
| 116 | +} |
| 117 | + |
| 118 | +## Main |
| 119 | + |
| 120 | +if [ -t 0 ]; then |
| 121 | + has_stdin=f |
| 122 | +else |
| 123 | + has_stdin=t |
| 124 | +fi |
| 125 | + |
| 126 | +# Show help if no arguments and no stdin. |
| 127 | +if [ $has_stdin = f ] && [ $# -eq 0 ]; then |
| 128 | + show_help |
| 129 | + exit |
| 130 | +fi |
| 131 | + |
| 132 | +check_dependency base64 |
| 133 | +check_dependency wc |
| 134 | +file_type="" |
| 135 | +mode=regular |
| 136 | + |
| 137 | +# Look for command line flags. |
| 138 | +while [ $# -gt 0 ]; do |
| 139 | + case "$1" in |
| 140 | + -h | --h | --help) |
| 141 | + show_help |
| 142 | + exit |
| 143 | + ;; |
| 144 | + -w | --w | --wide) |
| 145 | + mode=wide |
| 146 | + ;; |
| 147 | + -f | --f | --file) |
| 148 | + has_stdin=f |
| 149 | + is_url=f |
| 150 | + ;; |
| 151 | + -u | --u | --url) |
| 152 | + check_dependency curl |
| 153 | + has_stdin=f |
| 154 | + is_url=t |
| 155 | + ;; |
| 156 | + -t | --t | --type) |
| 157 | + file_type="$2" |
| 158 | + shift |
| 159 | + ;; |
| 160 | + -*) |
| 161 | + error "Unknown option flag: $1" |
| 162 | + show_help |
| 163 | + exit 1 |
| 164 | + ;; |
| 165 | + *) |
| 166 | + if [ "$is_url" == "t" ]; then |
| 167 | + encoded_file=$(curl -fs "$1" | b64_encode) || { |
| 168 | + error "Could not retrieve file from URL $1, error_code: $?" |
| 169 | + exit 2 |
| 170 | + } |
| 171 | + elif [ -r "$1" ]; then |
| 172 | + encoded_file=$(cat "$1" | b64_encode) |
| 173 | + else |
| 174 | + error "it2cat: $1: No such file or directory" |
| 175 | + exit 2 |
| 176 | + fi |
| 177 | + has_stdin=f |
| 178 | + print_file "$1" "$encoded_file" "$file_type" "$mode" |
| 179 | + ;; |
| 180 | + esac |
| 181 | + shift |
| 182 | +done |
| 183 | + |
| 184 | +# Read and print stdin |
| 185 | +if [ $has_stdin = t ]; then |
| 186 | + print_file "" "$(cat | b64_encode)" "$file_type" "$mode" |
| 187 | +fi |
| 188 | + |
| 189 | +if [ "$did_print" != "t" ]; then |
| 190 | + error "No file provided. Check command line options." |
| 191 | + show_help |
| 192 | + exit 1 |
| 193 | +fi |
| 194 | + |
| 195 | +exit 0 |
0 commit comments