"=============================================================================
" FILE: less.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:manager = vimshell#util#get_vital().import('Vim.Buffer')
let s:command = {
\ 'name' : 'less',
\ 'kind' : 'execute',
\ 'description' : 'less [{option}...] {command}',
\}
function! s:command.execute(commands, context) abort "{{{
" Execute command in background.
if empty(a:commands)
return
endif
let commands = a:commands
let [commands[0].args, options] = vimshell#parser#getopt(commands[0].args, {
\ 'arg=' : ['--encoding', '--syntax', '--split'],
\ }, {
\ '--encoding' : vimshell#interactive#get_default_encoding(a:commands),
\ '--syntax' : 'vimshell-less',
\ '--split' : g:vimshell_split_command,
\ })
if empty(commands[0].args)
return
endif
if !executable(commands[0].args[0])
return vimshell#helpers#execute_internal_command(
\ 'view', commands[0].args, a:context)
endif
" Background execute.
if exists('b:interactive') && get(b:interactive.process, 'is_valid')
" Delete zombie process.
call vimshell#interactive#force_exit()
endif
" Encoding conversion.
if options['--encoding'] != '' && options['--encoding'] != &encoding
for command in commands
call map(command.args,
\ 'vimproc#util#iconv(v:val, &encoding, options["--encoding"])')
endfor
endif
" Set variables.
let interactive = {
\ 'type' : 'less',
\ 'syntax' : options['--syntax'],
\ 'fd' : a:context.fd,
\ 'encoding' : options['--encoding'],
\ 'is_pty' : 0,
\ 'echoback_linenr' : 0,
\ 'command' : commands[0].args[0],
\ 'cmdline' : join(commands[0].args),
\ 'stdout_cache' : '',
\ 'stderr_cache' : '',
\ 'width' : vimshell#helpers#get_winwidth(),
\ 'height' : g:vimshell_scrollback_limit,
\}
return s:init(a:commands, a:context, options, interactive)
endfunction"}}}
function! s:command.complete(args) abort "{{{
return vimshell#complete#helper#command_args(a:args)
endfunction"}}}
function! vimshell#commands#less#define() abort
return s:command
endfunction
function! s:init(commands, context, options, interactive) abort "{{{
" Save current directiory.
let cwd = getcwd()
let [new_pos, old_pos] = vimshell#helpers#split(a:options['--split'])
" Set environment variables.
let environments_save = vimshell#util#set_variables({
\ '$TERM' : g:vimshell_environment_term,
\ '$TERMCAP' : 'COLUMNS=' . vimshell#helpers#get_winwidth(),
\ '$VIMSHELL' : 1,
\ '$COLUMNS' : vimshell#helpers#get_winwidth(),
\ '$LINES' : g:vimshell_scrollback_limit,
\ '$VIMSHELL_TERM' : 'less',
\ '$EDITOR' : vimshell#helpers#get_editor_name(),
\ '$GIT_EDITOR' : vimshell#helpers#get_editor_name(),
\ '$PAGER' : g:vimshell_cat_command,
\ '$GIT_PAGER' : g:vimshell_cat_command,
\})
" Initialize.
let a:interactive.process = vimproc#plineopen2(a:commands)
" Restore environment variables.
call vimshell#util#restore_variables(environments_save)
" Input from stdin.
if a:interactive.fd.stdin != ''
call a:interactive.process.stdin.write(
\ vimshell#interactive#read(a:context.fd))
endif
call a:interactive.process.stdin.close()
let a:interactive.width = vimshell#helpers#get_winwidth()
let a:interactive.height = g:vimshell_scrollback_limit
let args = ''
for command in a:commands
let args .= join(command.args)
endfor
let loaded = s:manager.open('less-'.substitute(args,
\ '[<>|]', '_', 'g') .'@'.(bufnr('$')+1), 'silent edit')
if !loaded
call vimshell#echo_error(
\ '[vimshell] Failed to open Buffer.')
return
endif
let [new_pos[2], new_pos[3]] = [bufnr('%'), getpos('.')]
" Common.
setlocal nolist
setlocal buftype=nofile
setlocal noswapfile
setlocal tabstop=8
setlocal foldcolumn=0
setlocal foldmethod=manual
if has('conceal')
setlocal conceallevel=3
setlocal concealcursor=n
endif
" For less.
setlocal nomodifiable
setlocal filetype=vimshell-less
let &syntax = a:options['--syntax']
let b:interactive = a:interactive
call vimshell#cd(cwd)
" Set syntax.
syn region InteractiveError
\ start=+!!!+ end=+!!!+ contains=InteractiveErrorHidden oneline
if v:version >= 703
" Supported conceal features.
syn match InteractiveErrorHidden '!!!' contained conceal
else
syn match InteractiveErrorHidden '!!!' contained
endif
hi def link InteractiveErrorHidden Error
augroup vimshell
autocmd BufDelete,VimLeavePre <buffer>
\ call vimshell#interactive#hang_up(expand('<afile>'))
augroup END
nnoremap <buffer><silent> <Plug>(vimshell_less_execute_line)
\ :<C-u>call <SID>on_execute()<CR>
nnoremap <buffer><silent> <Plug>(vimshell_less_interrupt)
\ :<C-u>call vimshell#interactive#hang_up(bufname('%'))<CR>
nnoremap <buffer><silent> <Plug>(vimshell_less_exit)
\ :<C-u>call vimshell#interactive#quit_buffer()<CR>
nnoremap <buffer><silent> <Plug>(vimshell_less_next_line)
\ :<C-u>call <SID>next_line()<CR>
nnoremap <buffer><silent> <Plug>(vimshell_less_next_screen)
\ :<C-u>call <SID>next_screen()<CR>
nnoremap <buffer><silent> <Plug>(vimshell_less_next_half_screen)
\ :<C-u>call <SID>next_half_screen()<CR>
nnoremap <buffer><silent> <Plug>(vimshell_less_last_screen)
\ :<C-u>call <SID>last_screen()<CR>
nmap <buffer><CR> <Plug>(vimshell_less_execute_line)
nmap <buffer><C-c> <Plug>(vimshell_less_interrupt)
nmap <buffer>q <Plug>(vimshell_less_exit)
nmap <buffer>j <Plug>(vimshell_less_next_line)
nmap <buffer>f <Plug>(vimshell_less_next_screen)
nmap <buffer><C-f> <Plug>(vimshell_less_next_screen)
nmap <buffer>d <Plug>(vimshell_less_next_half_screen)
nmap <buffer><C-d> <Plug>(vimshell_less_next_half_screen)
nmap <buffer>G <Plug>(vimshell_less_last_screen)
nmap <buffer><Space> <Plug>(vimshell_less_next_screen)
nnoremap <buffer>b <C-b>
nnoremap <buffer>u <C-u>
call s:print_output(winheight(0))
noautocmd call vimshell#helpers#restore_pos(old_pos)
if get(a:context, 'is_single_command', 0)
call vimshell#next_prompt(a:context, 0)
noautocmd call vimshell#helpers#restore_pos(new_pos)
stopinsert
endif
endfunction"}}}
function! s:next_line() abort "{{{
if line('.') == line('$')
call s:print_output(2)
endif
call cursor(line('.')+1, 0)
endfunction "}}}
function! s:next_screen() abort "{{{
if line('.') == line('$')
call s:print_output(winheight(0))
else
execute "normal! \<C-f>"
endif
endfunction "}}}
function! s:next_half_screen() abort "{{{
if line('.') == line('$')
call s:print_output(winheight(0)/2)
else
execute "normal! \<C-d>"
endif
endfunction "}}}
function! s:last_screen() abort "{{{
call s:print_output(-1)
endfunction "}}}
function! s:print_output(line_num) abort "{{{
setlocal modifiable
call cursor(line('$'), 0)
call cursor(0, col('$'))
if b:interactive.stdout_cache == ''
if b:interactive.process.stdout.eof
call vimshell#interactive#exit()
endif
if !b:interactive.process.is_valid
setlocal nomodifiable
return
endif
endif
" Check cache.
let cnt = len(split(b:interactive.stdout_cache, '\n', 1))
if !b:interactive.process.stdout.eof
\ && (a:line_num < 0 || cnt < a:line_num)
echo 'Running command.'
while !b:interactive.process.stdout.eof
\ && (a:line_num < 0 || cnt < a:line_num)
let b:interactive.stdout_cache .=
\ b:interactive.process.stdout.read(100, 40)
if a:line_num >= 0
let cnt = len(split(b:interactive.stdout_cache, '\n', 1))
endif
endwhile
redraw
echo ''
endif
let match = -1
if a:line_num >= 0
if cnt > a:line_num
let cnt = a:line_num
endif
let match = match(b:interactive.stdout_cache, '\n', 0, cnt)
endif
if a:line_num < 0 || match <= 0
let output = b:interactive.stdout_cache
let b:interactive.stdout_cache = ''
else
let output = b:interactive.stdout_cache[: match-1]
let b:interactive.stdout_cache = b:interactive.stdout_cache[match :]
endif
call vimshell#interactive#print_buffer(b:interactive.fd, output)
setlocal nomodifiable
if b:interactive.stdout_cache == ''
\ && b:interactive.process.stdout.eof
call vimshell#interactive#exit()
endif
endfunction"}}}