#!/bin/sh
#!/usr/bin/env vim
#! This is a bash script that executes itself as a vimscript to do its work
#! Based on _v by Magnus Woldrich: https://github.com/trapd00r/utils/blob/master/_v

: if 0
  # Just pass through if not on a tty
  if [ ! -t 1 ]; then
    exec cat "${@}"
  fi
# try to find a better shell, especially on Solaris

  PATH=$PATH:/usr/local/bin:/opt/csw/bin:/opt/local/bin:/usr/dt/bin:/usr/xpg4/bin:/usr/bin:/bin

  if [ -z "$IN_BASH" ] && command -v bash >/dev/null; then
    IN_BASH=1
    export IN_BASH
    exec bash "$0" "$@"
  elif [ -z "$IN_BASH" ] && [ -z "$IN_KSH" ]; then
    if command -v dtksh >/dev/null; then
      IN_KSH=1
      export IN_KSH
      exec dtksh "$0" "$@"
    elif [ -x /usr/xpg4/bin/sh ]; then
      IN_KSH=1
      export IN_KSH
      exec /usr/xpg4/bin/sh "$0" "$@"
    elif command -v ksh93 >/dev/null; then
      IN_KSH=1
      export IN_KSH
      exec ksh93 "$0" "$@"
    elif command -v ksh >/dev/null; then
      IN_KSH=1
      export IN_KSH
      exec ksh "$0" "$@"
    else
      echo "$0 requires either bash or ksh" >&2
      exit
    fi
  fi

  # hopefully we're now POSIX

  tmp_dir=/tmp/vimcat_${$}
  mkdir -m 700 ${tmp_dir} || {
    echo Could not create temporary directory ${tmp_dir} >&2
    exit 1
  }
  trap "rm -rf ${tmp_dir}" HUP INT QUIT ILL TRAP KILL BUS TERM
  tmp_file=${tmp_dir}/vimcat

  script=$(command -v ${0})

  # check for arguments to pass to vim
  while [ $# -gt 0 ] ; do
    case "${1}" in
      "-c") shift; extra_c="${1}"; shift ;;
        -*) echo "bad option '${1}'" ; exit 1 ;;
         *) break ;;
    esac
  done

  files=("${@}")

  if [ "${#}" -eq 0 ]; then
    files[1]="-"
  fi

  for file in "${files[@]}"
  do
    if [ "${#files[@]}" -ge 2 ]; then
      echo "==> ${file} <=="
    fi

    if [ -f ~/.vimcatrc ]; then
        vimcatrc_arg="-u ~/.vimcatrc"
    else
        vimcatrc_arg=""
    fi

    if [ "${file}" = "-" ]; then
      cat - >${tmp_file}
      file=${tmp_file}
    fi

    # Check that the file exists
    if test -r "${file}" -a -f "${file}"; then
      if test -s "${file}"; then
        vim -E -X -R -i NONE $vimcatrc_arg -c "source ${script} | ${extra_c} | visual | call AnsiHighlight(\"${tmp_file}\") | q" "${file}" </dev/tty >/dev/null 2>&1
        cat ${tmp_file}
        echo
      fi
    else
      echo "$0: Cannot read file: ${file}" >&2
    fi
  done

  rm -rf "${tmp_dir}"

  exit

: endfor
: endwhile
: endif
: endif
: endif
: endif
: endif

" AnsiHighlight: Allows for marking up a file, using ANSI color escapes when
" the syntax changes colors, for easy, faithful reproduction.
" Author: Matthew Wozniski (mjw@drexel.edu)
" Date: Fri, 01 Aug 2008 05:22:55 -0400
" Version: 1.0 FIXME
" History: FIXME see :help marklines-history
" License: BSD. Completely open source, but I would like to be
" credited if you use some of this code elsewhere.

" Copyright (c) 2008, Matthew J. Wozniski {{{1
" All rights reserved.
"
" Redistribution and use in source and binary forms, with or without
" modification, are permitted provided that the following conditions are met:
" * Redistributions of source code must retain the above copyright
" notice, this list of conditions and the following disclaimer.
" * Redistributions in binary form must reproduce the above copyright
" notice, this list of conditions and the following disclaimer in the
" documentation and/or other materials provided with the distribution.
" * The names of the contributors may not be used to endorse or promote
" products derived from this software without specific prior written
" permission.
"
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY
" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

" Turn off vi-compatible mode, unless it's already off {{{1
if &cp
  set nocp
endif

let s:type = 'cterm'
if &t_Co == 0
  let s:type = 'term'
endif

" Converts info for a highlight group to a string of ANSI color escapes {{{1
function! s:GroupToAnsi(groupnum)
  if ! exists("s:ansicache")
    let s:ansicache = {}
  endif

  let groupnum = a:groupnum

  if groupnum == 0
    let groupnum = hlID('Normal')
  endif

  if has_key(s:ansicache, groupnum)
    return s:ansicache[groupnum]
  endif

  let fg = synIDattr(groupnum, 'fg', s:type)
  let bg = synIDattr(groupnum, 'bg', s:type)
  let rv = synIDattr(groupnum, 'reverse', s:type)
  let bd = synIDattr(groupnum, 'bold', s:type)

  " FIXME other attributes?

  if rv == "" || rv == -1
    let rv = 0
  endif

  if bd == "" || bd == -1
    let bd = 0
  endif

  if rv
    let temp = bg
    let bg = fg
    let fg = temp
  endif

  if fg == "" || fg == -1
    unlet fg
  endif

  if !exists('fg') && !groupnum == hlID('Normal')
    let fg = synIDattr(hlID('Normal'), 'fg', s:type)
    if fg == "" || fg == -1
      unlet fg
    endif
  endif

  if bg == "" || bg == -1
    unlet bg
  endif

  if !exists('bg')
    let bg = synIDattr(hlID('Normal'), 'bg', s:type)
    if bg == "" || bg == -1
      unlet bg
    endif
  endif

  let retv = "\<Esc>[22;24;25;27;28"

  if bd
    let retv .= ";1"
  endif

  if exists('fg') && fg < 8
    let retv .= ";3" . fg
  elseif exists('fg')  && fg < 16    "use aixterm codes
    let retv .= ";9" . (fg - 8)
  elseif exists('fg')                "use xterm256 codes
    let retv .= ";38;5;" . fg
  else
    let retv .= ";39"
  endif

  if exists('bg') && bg < 8
    let retv .= ";4" . bg
  elseif exists('bg') && bg < 16     "use aixterm codes
    let retv .= ";10" . (bg - 8)
  elseif exists('bg')                "use xterm256 codes
    let retv .= ";48;5;" . bg
  else
    let retv .= ";49"
  endif

  let retv .= "m"

  let s:ansicache[groupnum] = retv

  return retv
endfunction

function! AnsiHighlight(output_file)
  let retv = []

  for lnum in range(1, line('$'))
    let last = hlID('Normal')
    let output = s:GroupToAnsi(last) . "\<Esc>[K" " Clear to right

        " Hopefully fix highlighting sync issues
    exe "norm! " . lnum . "G$"

    let line = getline(lnum)

    for cnum in range(1, col('.'))
      if synIDtrans(synID(lnum, cnum, 1)) != last
        let last = synIDtrans(synID(lnum, cnum, 1))
        let output .= s:GroupToAnsi(last)
      endif

      let output .= matchstr(line, '\%(\zs.\)\{'.cnum.'}')
      "let line = substitute(line, '.', '', '')
            "let line = matchstr(line, '^\@<!.*')
    endfor
    let retv += [output]
  endfor
  " Reset the colors to default after displaying the file
  let retv[-1] .= "\<Esc>[0m"

  return writefile(retv, a:output_file)
endfunction

" See copyright in the vimscript above.
"
" The list of contributors is at the bottom of the vimpager script in this
" project.
"
" vim: sw=2 sts=2 et ft=vim
