I am working on a vim plugin and as part of that I am testing various things like "auto-groups" and events where I can hook bits and pieces in general. While things are running I am using functions that output various debug messages using the echom command. The problem is once I want to have a look at the output, I need to type :message and then keep hitting a key until the end of the messages appear, so I can see what was the last message.
Is there a workaround for this? Like, is there a plugin that would help me see the messages stream in realtime inside a separate buffer?
Thanks.
(OSX, MacVim)
Instead of using :echom directly, write a little s:Log(message) function. It should switch to your log buffer, then append a:message at the bottom (or the top, if you like). Switch back to the current buffer and :execute "echom" a:message.
If you also want to see regular messages in your log buffer, you could use :redir to capture the messages, then append them to your log buffer on a CursorHold event. This is more complicated, and it would tie up one of your named buffers.
:help :wincmd
:help :put
:help append()
:help :redir
:help CursorHold
For me, :echomsg and :messages is fine most of the time. If you need something more elaborate, have a look at the Decho - Vim script internal debugger plugin. It can capture log messages in a separate window.
For hairy parts, no amount of log output will be enough; you can then launch the built-in interactive debugging; see :help debug-scripts.
Related
To source vimrc in all buffers in the current window I do :bufdo so~/.vimrc ,to source vimrc in the ACTIVE buffers in all windows I do :windo so~/.vimrc. How to source vimrc in all buffers in all windows?
for some reason if I do:bufdo so~/.vimrc | :windo so~/.vimrc the active buffer in the non-active window changes.
example: if I set set number in my .vimrc, I want all buffers in all windows affect the change.
the solution might be something like this:
for window in windowlist
execute 'bufdo so~/.vimrc'
I use vim 8.2 .
PLEASE NOTE: I did try all of the commands you guys suggested but it seems that things aren't clear enough. all of the commands that includes :tabdo :windo :bufdo or combination of them doesn't work properly for what I want. please note that this is the same as changing vimrc and sourcing it with chain of these commands like :tabdo bufdo so~/.vimrc. for example :windo bufdo set number does set number to all buffers(active or hidden) in the active window but on non-active windows only does set number for the active buffer(buffer that is shown in the window) or :tabdo windo set number only does set number in active buffers in every window meaning that hidden buffers won't get line numbers.
I even made a reddit post about this problem on r/vim and made a video about it but I don't know why nobody gets what I say. honestly don't think this problem will be solved by someone else but me even though its a simple one.
The :bufdo command will consume | as part of the command to execute, so in effect you're running the :windo command for each buffer that you have active!
See :help :bar, which documents this behavior.
That help section also mentions a way to work around this behavior, by using the :execute command to run the first command from a string, which allows you to delimit the first command. Like so:
:execute 'bufdo so ~/.vimrc' | windo so ~/.vimrc
Please note that sourcing your vimrc file "in all buffers" or "in all windows" doesn't make much sense... The vimrc file typically has global commands that usually need to be sourced only once, and usually if you modify your vimrc, sourcing it again only once should be enough...
This might make sense with a separate *.vim script that affects local settings and is meant to act on a single buffer. The ftplugin, indent and syntax scripts come to mind. But also with those, they're normally run per buffer, not per window... It's not completely inconceivable that you'd have scripts that you want to run on every buffer and window, but it surely seems odd...
.vimrc shall only contain global definitions. That the way it's supposed to be used. Sourcing it in several buffers makes no sense.
I wonder if you're fighting with local settings for which the best tool to use is either ftplugin (when the setting are filetype driven), or a local_vimrc plugin for project driven settings.
To apply in all buffers and all windows:
:windo bufdo set number
If you have tabs, from :tabe, :tabf, :tab and friends. Just add tabdo like this:
:tabdo windo bufdo set number
I would advise not to source your vimrc like this. If you want a quick setting, just use the set command and friends.
:help tabdo
:help windo
:help bufdo
:help source
While I agree with most answers on sourcing your vimrc. I do believe there are uses of the source command. Particularly batch fixing. I've never tried using
:windo with this, I mostly use :argdo and :cdo. As I have more fine-grained control on what files I need to apply.
Batch fixing is particularly useful on a large codebase. You do your fixes with :g, :v, :s for example, and save them in a file called fix.vim. This is so useful, you could even pair macros with those commands (:g and :v) via :norm command.
:help norm
Then update your argslist via :args *.js or similar commands (like backtick expression) and finally do the :argdo source fix.vim
I often use the command :Explore to switch to another file. I also use a lot the command :buffer to switch between previously opened files, but it is not always convenient when a lot of files are opened.
Is there a way to display a list of all opened files (buffers) in the current window, in a "explore" way, without using plugin?
:help :ls is the closest you can get with basic built-in tools.
I would recommend creating a normal map like this in your ~/vimrc file.
" list buffers and jump to a chosen one
nnoremap <Leader>b :ls<CR>:b<Space>
It triggers your <Leader> plus b to execute two commands at once, first it shows all open buffers, then it allows you to type the buffer number to open it. It wort reading :h leader.
I often like to complete more just a Vim keyword. For example, I want to complete an arbitrary pathname or something like self.logger.debug("...") which I already have somewhere in my text file.
C-n and C-p use the 'iskeyword' option and thus only complete Vim keywords.
What is the best way to implement a space-separated word completion?
inoremap <C-m> ???
My only idea is to change 'iskeyword', use normal word completion, and reset 'iskeyword' it after that.
Both #Ingo Karkat and #Luc Hermitte provide excellent solutions. However if you want to do this natively then Vim provides some solutions which might help you. Typically completion uses plain <c-n>/<c-p> however there is an completion submode accessed via <c-x>.
Filename completion
Use <c-x><c-f> to start completing a filename. You can use <c-n>/<c-p> just like you normally would after you have started completion to move between options. If the completion ends in a directory (e.g. /usr/bin/) then just execute <c-x><c-f> to start completion into that directory.
Whole line completion
If you are commonly using the same line, but it isn't worth making a snippet or an abbreviation, then type the start of the line you wish then <c-x><c-l> to start line completion. Then just use <c-n>/<c-p> as you normally would.
Multi-word completion
You can use <c-x><c-n>/<c-x><c-p> to complete another word that follows the current word. This one is sort of tough to explain without just trying it.
Let's say you have the following text:
self.logger.debug("foo")
Let's say you would like another self.logger.debug somewhere else.
So type: sel then use <c-p> to as you normally would complete to self
Then use <c-x><c-p> to complete to self.logger (may need to do some <c-p>/<c-n> to get to .logger).
Once self.logger is completed then use <c-x><c-p> again for the .debugger part.
Note: this does use iskeyword so it may not complete exactly as you want, but should be pretty close.
For more help
:h ins-completion
:h compl-whole-line
:h compl-current
:h compl-filename
:h 'complete'
IMO, snippets are the best way to proceed in your case -- as you certainly don't want to change 'iskeyword' option (it'd trigger too many undesired side-effects, and as you said you'd need to restore it afterward, which is not trivial if possible at all). You could use abbreviations or mappings, but then you'd loose the "completion" feeling/feature you'd get with snippet plugins.
There exist plenty different snippet plugins. I'm quite sure there are plenty answers here on SO, or on vi.SE which describe the existing plugins.
For pathnames, you have i_CTRL-X_CTRL-f, but indeed it stops at each directory. In that case you could may be override i_CTRL-X_CTRL-f to alter &isk (and key sequences that valid/abort completion), trigger the completion, and then restore &isk and the mappings when you validate/abort the completion. This restoration at the end of completion is what some snippet plugins do. That's what I do in the core functions used in mu-template to take care of the completion. (Explanations of how this works on vi.SE)
I have written a plugin that is powered by my CompleteHelper plugin that does just that:
The WORDComplete plugin finds matches for WORDs that start with the non-blank characters in front of the cursor and end at the next whitespace. By default, it is triggered in insert mode with <C-x><C-w>. Like the built-in completions, the source buffers it considers can be configured.
Clarification: A "window-local buffer" in this context just means a buffer once loaded into a specific window, any other buffer not ever loaded into that window is not a "window-local buffer".
I had some ruminations on ways managing buffers earlier and I think having a "window-local" buffer list would provide an extra way managing buffers. By saying that, I'm not interested in ways managing buffers already provided by Vim.
And it seems the solution is straightforward by recording "window-local" buffers manually like autocmd BufWinEnter * call add(w:buffers, expand('%')) and providing corresponding interfaces to the "window-local" buffer list w:buffers.
Do you find this useful? And any suggestion would be appreciated.
To list all open buffers use this:
:buffers
To open buffer #5 use this:
:buffer 5
You can use the following mapping to combine the two commands:
:nnoremap <F5> :buffers<CR>:buffer<Space>
How to use this convenient mapping:
press F5
enter a buffer number
press <Enter>
More reading here. (search for "switching by number")
The buffer list is global. You can have a window-local argument list (with :arglocal), and then use commands like :next to navigate through them.
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.