├── .gitignore ├── README.md ├── autoload └── autoread.vim ├── doc └── autoread.txt └── plugin └── autoread.vim /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore swapfile 2 | *.swp 3 | *.swo 4 | *.swn 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-autoread 2 | ============ 3 | > A plugin to automatically re-read your buffers, when they change 4 | 5 | This plugin uses Vim 8 async jobs to append new buffer content. Internally, it 6 | works by running tail -f on a file and the output will be appended to the 7 | buffer, which displays this buffer. 8 | 9 | ## Installation 10 | --- 11 | 12 | Use the plugin manager of your choice. 13 | 14 | Alternatively, since Vim 8 includes a package manager by default, clone this repository below 15 | `~/.vim/pack/dist/start/` 16 | 17 | You should have a directory `~/.vim/pack/dist/start/vim-autoread` 18 | That directory will be loaded automatically by Vim. 19 | 20 | ## Usage 21 | --- 22 | Once installed, take a look at the help at `:h vim-autoread`. 23 | 24 | Here is a short overview of the functionality provided by the plugin: 25 | 26 | ### Ex commands: 27 | 28 | :AutoRead - starts a async job and will append new buffer content 29 | to the current buffer once it is noticed. 30 | :AutoRead! - stop autoreading 31 | 32 | ## License & Copyright 33 | ------- 34 | 35 | Developed by Christian Brabandt. 36 | The Vim License applies. See `:h license` 37 | 38 | © 2009-2016 by Christian Brabandt 39 | 40 | __NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK__ 41 | -------------------------------------------------------------------------------- /autoload/autoread.vim: -------------------------------------------------------------------------------- 1 | let s:jobs = {} 2 | 3 | function! s:autoread_on_exit(channel) dict abort "{{{1 4 | " Remove from s:jobs 5 | call remove(s:jobs, self.file) 6 | endfunction 7 | 8 | function! s:autoread_cb(channel, msg) dict abort "{{{1 9 | let switch_buffer = 0 10 | if bufnr('%') != self.buffer 11 | " switch to buffer 12 | let bufinfo = getbufinfo(self.buffer) 13 | if len(bufinfo[0].windows) == 0 14 | return 15 | endif 16 | let winfo = getwininfo(bufinfo[0].windows[0]) 17 | let winnr = winfo[0].winnr 18 | let tabnr = winfo[0].tabnr 19 | let curtabnr = tabpagenr() 20 | let curwinnr = winnr() 21 | if tabnr != curtabnr 22 | exe "noa ". tabnr. "tabnext" 23 | endif 24 | if winnr != curwinnr 25 | exe "noa ". winnr. "wincmd w" 26 | endif 27 | let switch_buffer = 1 28 | if bufnr('%') != self.buffer 29 | " shouldn't happen 30 | exe "noa :". self.buffer. "b" 31 | endif 32 | endif 33 | let fsize = getfsize(self.file) 34 | if fsize < get(b:, 'autoread_fsize', 0) 35 | call s:StoreMessage('Truncating Buffer, as file seemed to have changed', 'error') 36 | sil! %d 37 | endif 38 | let b:autoread_fsize = fsize 39 | if line('$') == 1 && empty(getline(1)) 40 | call setline(1, a:msg) 41 | else 42 | call append('$', a:msg) 43 | endif 44 | norm! G 45 | if switch_buffer 46 | exe "noa ". curtabnr. "tabnext" 47 | exe "noa ". curwinnr. "wincmd w" 48 | endif 49 | call s:OutputMessage() 50 | endfunction 51 | 52 | function! s:autoread_on_error(channel, msg) dict abort "{{{1 53 | call s:StoreMessage(a:msg, 'error') 54 | echohl ErrorMsg 55 | echom a:msg 56 | echohl None 57 | endfunction 58 | 59 | function! s:ReadOutputAsync(cmd, file, buffer) "{{{1 60 | if has("win32") || has("win64") 61 | let cmd = a:cmd 62 | else 63 | let cmd = ['sh', '-c', a:cmd] 64 | endif 65 | 66 | let options = {'file': a:file, 'cmd': a:cmd, 'buffer': a:buffer} 67 | if has_key(s:jobs, a:file) && job_status(get(s:jobs, a:file)) == 'run' 68 | call s:StoreMessage("Job still running", 'error') 69 | return 70 | endif 71 | call s:StoreMessage(printf("Starting Job for file %s buffer %d", a:file, a:buffer), 'warning') 72 | let id = job_start(cmd, { 73 | \ 'out_io': 'buffer', 74 | \ 'out_cb': function('s:autoread_cb', options), 75 | \ 'close_cb': function('s:autoread_on_exit', options), 76 | \ 'err_cb': function('s:autoread_on_error', options)}) 77 | let s:jobs[a:file] = id 78 | endfu 79 | 80 | function! s:StoreMessage(msg, type) "{{{1 81 | if !exists("s:msg_{a:type}") 82 | let s:msg_{a:type} = [] 83 | endif 84 | call add(s:msg_{a:type}, a:msg) 85 | endfu 86 | 87 | function! s:OutputMessage() "{{{1 88 | for type in ['warning', 'error'] 89 | if !exists("s:msg_{type}") 90 | continue 91 | endif 92 | let msg=s:msg_{type} 93 | if empty(msg) 94 | continue 95 | endif 96 | " Always store messages in history 97 | if get(g:, 'autoread_debug', 0) || type ==# 'error' 98 | let i=0 99 | for line in msg 100 | echom (i == 0 ? ('vim-autoread:'.toupper(type[0]).':') : ''). line 101 | let i += 1 102 | endfor 103 | " Add last message to error message 104 | if type ==# 'error' 105 | let v:errmsg = line 106 | endif 107 | endif 108 | unlet! s:msg_{type} 109 | endfor 110 | endfu 111 | 112 | function! autoread#AutoRead(bang, file) "{{{1 113 | let file=fnamemodify(a:file, ':p') 114 | let buff=bufnr('%') 115 | let agroup='vim-autoread-'.buff 116 | let agroup_cmd='augroup '.agroup 117 | if !empty(a:bang) 118 | if has_key(s:jobs, file) 119 | call job_stop(s:jobs[file]) 120 | endif 121 | exe agroup_cmd 122 | au! 123 | augroup end 124 | exe "augroup!" agroup 125 | return 126 | endif 127 | if !executable('tail') 128 | call s:StoreMessage('tail not found', 'error') 129 | return 130 | elseif empty(file) 131 | call s:StoreMessage(printf('Filename "%s" not given', file), 'error') 132 | return 133 | elseif !filereadable(file) 134 | call s:StoreMessage(printf('File "%s" not readable', a:file), 'error') 135 | return 136 | endif 137 | let cmd=printf('tail -n0 -F -- %s', file) 138 | if !exists("#".agroup."#FileChangedShell") 139 | exe agroup_cmd 140 | au! FileChangedShell :let v:fcs_choice='reload' 141 | augroup end 142 | endif 143 | call s:ReadOutputAsync(cmd, file, bufnr('')) 144 | endfunction 145 | 146 | " Modeline {{{1 147 | " vim: ts=2 sts=2 sw=2 et fdm=marker com+=l\:\" 148 | -------------------------------------------------------------------------------- /doc/autoread.txt: -------------------------------------------------------------------------------- 1 | *autoread.txt* Automatically update a buffer as it is changed 2 | 3 | Author: Christian Brabandt 4 | Version: 0.2 5 | Copyright: (c) 2016-2017 by Christian Brabandt 6 | The VIM LICENSE applies to the autoread plugin 7 | (see |copyright|) except use autoread instead of "Vim". 8 | NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK. 9 | 10 | ============================================================================== 11 | *vim-autoread* 12 | 13 | Vim-autoread is a plugin to automatically re-read your buffers, as it changes. 14 | 15 | It uses Vim 8 feature of async jobs to append new buffer content as it appears. 16 | Internally, it works by running tail -f on a file and the output will be appended 17 | to the buffer, which displays this file. 18 | Note: this needs the command tail in your path (so probably won't work on 19 | Windows). 20 | 21 | Since it relies heavily on the |job| feature of Vim, it needs at least Vim 22 | Version 8 to work. 23 | 24 | *:AutoRead* 25 | :AutoRead[!] Starts a new async job and will append output to the current 26 | buffer as it appears in the background. The buffer will be 27 | scrolled automatically. 28 | If ! is given, stop auto-reading. 29 | 30 | ============================================================================== 31 | vim:tw=78:ts=8:ft=help:et:fdm=marker:fdl=0:norl 32 | -------------------------------------------------------------------------------- /plugin/autoread.vim: -------------------------------------------------------------------------------- 1 | " vim-autoread - Read a buffer periodically 2 | " ------------------------------------------------------------- 3 | " Version: 0.2 4 | " Maintainer: Christian Brabandt 5 | " Copyright: (c) 2009-2017 by Christian Brabandt 6 | " The VIM LICENSE applies to vim-autoread 7 | " (see |copyright|) except use "vim-autoread" 8 | " instead of "Vim". 9 | " No warranty, express or implied. 10 | " *** *** Use At-Your-Own-Risk! *** *** 11 | " Init: {{{1 12 | let s:cpo= &cpo 13 | if exists("g:loaded_autoread") || &cp 14 | finish 15 | elseif has("nvim") 16 | " disabled for neovim, because it uses a different API 17 | finish 18 | elseif !has('job') 19 | echohl WarningMsg 20 | echomsg "The vim-autoread Plugin needs at least a Vim version 8 (with +job feature)" 21 | echohl Normal 22 | finish 23 | endif 24 | set cpo&vim 25 | let g:loaded_autoread = 1 26 | 27 | " Commands: {{{1 28 | com! -bang AutoRead :call autoread#AutoRead(, expand('%')) 29 | 30 | " Reset cpo 31 | let &cpo=s:cpo 32 | 33 | " vim: ts=2 sts=2 sw=2 et fdm=marker com+=l\:\" 34 | --------------------------------------------------------------------------------