Using VIM as a logfile-viewer - vim

I'd like to use VIM as a logfile-viewer. Is it possible to reload the current file in a regular time interval (~1s)?

use :set autoread

See this VIM tip. It offers tailing (like tail -f) together with log line numbering

I like it short and without a lot of hacking or external scripts.
You can run this oneliner from ex (whithin vim) when needed (or put each command in vimrc, for when log-files are opened.)
:set autoread | au CursorHold * checktime | call feedkeys("lh")
(if you would want to jump (nearly) to the end of the file, just use "G" instead of "lh" with feedkeys)
Explanation:
autoread: reads the file when changed from the outside (but it doesnt work on its own, there is no internal timer or something like that. It will only read the file when vim does an action, like a command in ex :!
CursorHold * checktime: when the cursor isn't moved by the user for the time specified in updatetime (which is 4000 miliseconds by default) checktime is executed, which checks for changes from outside the file
call feedkeys("lh"): the cursor is moved once, right and back left. and then nothing happens (... which means, that CursorHold is triggered, which means we have a loop)
To stop the scrolling when using call feedkeys("G"), execute :set noautoread - now vim will tell, that the file was change ans ask if one wants to read the changes or not)
I like the idea to watch logfiles in vim (instead of tail -f), e.g. when you are working in an ssh session without screen/tmux. Additionally you can copy directly from the logfile, if needed, or save the output directly or ... whatever you can do with vim :)
*from this answer (refering to an answer by PhanHaiQuang and a comment by flukus)

With the timers in Vim 8 this can now much simpler and less of a kludge. For example:
:set autoread
:function! Tailf(id)
: checkt
: $
:endfunc
:let timer_id = timer_start(4000, 'Tailf', {"repeat":-1})
This has vim rereading the whole log every 4 seconds. For many purposes that's fine, but would not be for large, say several GB, log files. There's other capabilities, like jobs and channels, that could be used for more sophisticated log reading.

asyncrun.vim lets you run programs and see live output in the quickfix (essentially JohnLittle's answer, but with setqflist() instead of Tailf()). You can use it with tail (I'm on Windows and my tail comes from my git install):
AsyncRun tail -f C:\logs\plugin-info.log
It has the additional benefit of using 'errorformat' to parse filenames out of the logs.

Related

How to :bufdo only on modifiable buffers in vim?

Sometimes I need to substitute across multiple buffers. For the purpose I use :bufdo %s/old/new/gec. Recently I noticed that the command fails when there is non-modifiable buffer in the buffer list (in my case it's opened file explorer/netrw). After running the command vim leaves me with E21: Cannot make changes, 'modifiable' is off and opened Netrw window.
Are the ways to :bufdo only on modifiable buffers? I've already tried :bufdo!, but the behaviour was the same (just without showing the error).
UPDATE
I find the line of .vimrc that poses this problematic behaviour:
let g:netrw_liststyle=3
I don't know what the magic here, but when I set this option neither of the suggested solutions/commands work for me. Now, the question is how to keep this line and make the :bufdo behaviour skip the buffer created by Netrw.
Well, if :bufdo sil! :%s/old/new/gec does not work for you (this silently ignores errors). you need to wrap the command into an if statement. Something like this:
:bufdo if &ma | :%s/old/new/gec | endif
which checks for each buffer, if it is modifiable and only then attempts to replace old by new.
Note: You might also want to check for the 'readonly' option in addition to the 'modifiable' setting.

Best way to view multiple logs at once?

I am currently running zookeeper processes and multiple internal processes and they all print out to their own log files as text. I am pretty green to linux but I was wondering if viewing multiple log file in a single screen without switching between emacs windows or vim windows is an issue for other. What is the best way to view say 3, four or more log files at once? Would it involve the CAT or | commands?
If you are viewing live logs you can use tail with multiple files, or just tail an entire directory using the wildcard operator.
If you are digging though logs you can use Terminator, it is in the Debian repos, to open multiple terminal sessions in one window.
If you are feeling more adventurous your can use tmux to split your terminal window, the great thing about tmux is that is works in textmode, so you can do it over ssh. Here is a pretty decent tmux split pane tutorial http://lukaszwrobel.pl/blog/tmux-tutorial-split-terminal-windows-easily
i like multitail as an optional but nice way to monitor multiple files whithout a lot of hacking around. After installing (e.g. apt-get install multitail) run multitail file1.log file2.log file3.log. the 'f1' key gives you inline help which keys to press.
But, if you want to stay in vim you can use this answer:
One can run this oneliner from ex (whithin vim) when needed (or put each command in vimrc, for when log-files are opened.)
:set autoread | au CursorHold * checktime | call feedkeys("lh")
Explanation:
- autoread: reads the file when changed from the outside (but it doesnt work on its own, there is no internal timer or something like that. It will only read the file when vim does an action, like a command in ex :!
- CursorHold * checktime: when the cursor isn't moved by the user for the time specified in 'updatetime' (which is 4000 miliseconds by default) checktime is executed, which checks for changes from outside the file
- call feedkeys("lh"): the cursor is moved once, right and back left. and then nothing happens (... which means, that CursorHold is triggered, which means we have a loop)
It hit me out of nowhere... I should just import the log folder directory into an empty project in eclipse, then I can swiftly explore and inspect logs and split the screens as needed across multiple monitors. All of Leon's answer is good stuff too, but since I am already using Eclipse heavily I might as well take advantage of that locality.

vim run make through screen

Due to some complicated environmental variables required, I have chosen to run Make through GNU screen. Using the screen vim plugin, I have the following setup in my .vimrc:
map <Leader>mm :call ScreenShellSend("cd ".expand("%:p:h")." && make 2>&1 | tee /path/to/errorfile") <CR>
Roughly translated, this will run make in the current working directory through an existing screen session with all of the required environment variables preset. I can then see the output of that command in a separate terminal window.
My question is, assuming I output the results of make to a text file, how do I tell automate the vim make process to:
A.) set make to use a vimscript function, i.e. call SreenShellSend() instead of an external program.
B.) set errorfile to /path/to/errorfile
Unfortunately, you cannot set 'makeprg' to a Vim function or command, it has to be a shell program. (I wish for an enhancement that treats commands starting with a colon as Vim commands, similar to the :help exception in 'keywordprg', but haven't come around to implementing this.)
There are workarounds, though. One is to use vim --remote-send as 'makeprg' and use this other temporary Vim instance to call back into the original Vim. What I do though is overriding the :make command through the cmdalias.vim plugin for those buffers. That alias then simply :calls my function.
Once you're able to invoke a Vim function, setting the 'errorfile' is just a matter of putting a function wrapper around ScreenShellSend() and setting it in there.

How to set fileformat=unix for all files opend in vim?

I want change fileformat of all the files.
So I open them use vim *.
Then I want to know if there is any simple way to do this, rather than typing :set fileformat=unix and :wfor each file one by one.
argdo is what you want, not bufdo, since you want to do it on every argument and you don't (necessarily) want to open every file first.
:argdo set ff=unix | update
should do the trick.
Maybe you need bufdo?
:help bufdo
bufdo[!] {cmd} Execute {cmd} in each buffer in the buffer list.
It works like doing this:
:bfirst
:{cmd}
:bnext
:{cmd}
etc.
Sure, you can do this using vim record and play feature. Follow these steps
1. Open all files using vim *
2. Press "qq" to start recording
3. :set ff=unix
4. :wn
5. Press again "q" to stop recording
6. Execute like "100#q"
Here 100 is the approximate number of files, but don't worry if you gave more number also. It'll stop when it finishes all buffer saying "E165: Cannot go beyond last file". You can get the number of file is by doing "ls | wc -l" before you open.

tail like functionality for gvim

I want to use gvim to view a log file which is being updated continuously, such that I always see the last updated line, much like tail command in unix. Is it possible?
Open logfile and
:setlocal autoread
There is a plugin (Tail Bundle) on the vim site.
I like it short and without a lot of hacking or external scripts.
You can run this oneliner from ex (whithin vim) when needed (or put each command in vimrc, for when log-files are opened.)
:set autoread | au CursorHold * checktime | call feedkeys("lh")
and additionally you can :set syntax=logtalk to color the log
(if you would want to jump (nearly) to the end of the file, just use "G" instead of "lh" with feedkeys)
Explanation:
autoread: reads the file when changed from the outside (but it doesnt work on its own, there is no internal timer or something like that. It will only read the file when vim does an action, like a command in ex :!
CursorHold * checktime: when the cursor isn't moved by the user for the time specified in updatetime (which is 4000 miliseconds by default) checktime is executed, which checks for changes from outside the file
call feedkeys("lh"): the cursor is moved once, right and back left. and then nothing happens (... which means, that CursorHold is triggered, which means we have a loop)
To stop the scrolling when using call feedkeys("G"), execute :set noautoread - now vim will tell, that the file was change ans ask if one wants to read the changes or not)
*from this answer (refering to an answer by PhanHaiQuang and a comment by flukus)
Or a less elegant solution on a vim 7.x would be just do :e! whenever you need the update .

Resources