0

So, I faced a need to check a type of a window and a buffer when entering a new window so I can do some stuff automatically depending on the types of aforementioned stuff.

For example, when quickfix is opened, I need to know that it is it, the same with command window, help, etc. Putting it in other words - I need to know when the new window opened is a regular window with a regular buffer in it.

The only ways that I wound was a combination of win_gettype() and &buftype options.

First thing I tried was an obvious WinEnter event, which didn't work properly as I couldn't check the type of a buffer.

Then, I tried BufEnter, but that wouldn't catch :split without arguments, apparently in a way similar to BufWinEnter. In addition, that wouldn't catch quickfix when it is opened for the first time and command.

So, coming to the question - is there any reliable way to validate window's and buffer's type automatically when a new window is opened without taking into account the way it was opened in? To summarize - there are two problems - 1) cannot catch a window at all if it is opened with :split without arguments, 2) cannot catch types reliably (see Edit 2).

EDIT 4

Well, with EDIT 3 taken into account, WinEnter works properly and as expected. But this is still a huge workaround. Will leave the question open in case anybody has an adequate solution.

EDIT 3

Well, I cannot see how to check things from EDIT 2 below upon window or buf entrance, but I guess it is possible to check them once again afterwords. I've come up with an idea to catch terminal with TerminalOpen, check command once again with CmdWinEnter, and fixquickfix problem with checking its' filetype with, well, FileType. These are huge workarounds, but I cannot see another way of solving this yet. Unfortunatelly, :split problem is still a thing.

EDIT 2

I've elaborated a bit on the main question and played a bit more with all this stuff. It seems like command line is caught. But terminal behavior is weird. So, behavior of different windows with WinEnter and BufEnter is as follows:

|Window    |WinEnter|BufEnter|
|:---------|:-------|:-------|
|quickfix  |   -    |+, 2    |
|command   |   -    |    +   |
|help      |   -    |    +   |  
|terminal  | +, 1   |+, 1    |

   

1 - but only if another terminal window is opened (the first one is not being caught);

2 - but fails for the first time after Vim startup.

Sorry for the table, it forces me to indent it for some reason, and it breaks all the pretty visuals on the page.

EDIT 1

Adding a snippet of code. The whole idea of what I am trying to do is storing an information about all the windows currently opened that are regular windows with regular buffers. Each time new window is opened or an old window is closed I need this info to be updated automatically. The core code is below:

function HandleNewWindow()
    let winid = win_getid()
    let wi = getwininfo(winid)[0]
    let bufnr = wi.bufnr

    if !CorrectBufAndWinTypes(bufnr, winid)
        return 1
    else
        " add winid to the list of regular windows' IDs
    endif
endfunction

function CorrectBufAndWinTypes(bufnr, winid)
    let wt = win_gettype(a:winid)
    let bt = getbufvar(a:bufnr, "&buftype")
    let wi = getwininfo(a:winid)[0]
    let is_terminal = wi.terminal
    let is_quickfix = wi.quickfix

    echom "WT - " wt "BT - " bt is_terminal is_quickfix

    if wt !=? "" || bt !=? "" || is_terminal || is_quickfix
        return 0
    else
        return 1
    endif
endfunction

" I was trying to handle it with the autocommands below:

" autocmd BufEnter * call HandleNewWindow()
"     cannot detect quickfix window at first try
"   (subsequent tries are positive, though)
"     can detect help, but only via &buftype

" autocmd WimEnter * call HandleNewWindow()
"     cannot detect quickfix at all
"     cannot detect help at all

"     both cannot handle command window (q:)
Anton Tretyakov
  • 303
  • 1
  • 9

2 Answers2

1

You shouldn't have to deal with buffers and thus use :help 'buftype'.

:help win_gettype() tells you if a window is:

  • a popup window
  • a preview window
  • a command-line window

:help getwininfo() tells you if a window is:

  • a quickfix window
  • a terminal window

Having those related informations split between two inconsistently named functions is as ugly as can be but well…

romainl
  • 186,200
  • 21
  • 280
  • 313
  • This language is indeed killing me. Thank you for your advise, but it solves only a half of my problem - I still have all other issues (though replacing `&buftype` is for sure a good thing). – Anton Tretyakov Jun 16 '21 at 15:11
  • By the way, you, kind Sir, seem to be a pundit of the sacred ways of Vim-fu. Could you advise if there is any way to check buf type by its number? – Anton Tretyakov Jun 16 '21 at 15:24
  • You don't have the other issues because you don't have to wonder about the buffer anymore and thus you only need `WinEnter`. – romainl Jun 16 '21 at 15:27
  • 1
    As for your second question: see `:help getbufvar()`. – romainl Jun 16 '21 at 15:29
  • As for `WinEnter` - it seems like right after this event Vim knows about the id of the window but doesn't know anything about it's type, as it cannot determine the window is a `quickfix` in a autocommand fired on the event. `BufEnter`, as I wrote in the question, seems to be catching it, but only at the second and subsequent attempts. – Anton Tretyakov Jun 16 '21 at 15:42
  • It would help to know what you are trying to do. – romainl Jun 16 '21 at 15:51
  • I am sorry for the delay in answer. Please find the updated info in the question text. – Anton Tretyakov Jun 16 '21 at 19:45
  • Do you really need that information in real time, e.g. "I want to play a sound whenever a normal window is created"/"I want the number of normal windows displayed in the status line"? – romainl Jun 16 '21 at 20:25
  • I don't know how weird that sounds, but kinda yes, in the most real time possible. – Anton Tretyakov Jun 17 '21 at 10:44
  • I guess I can catch `command line` buffer by its name, but I still cannot see how to do it timely. – Anton Tretyakov Jun 17 '21 at 11:08
  • Yes, it sounds weird, especially given the lack of explicit justification. The only reason to want real time, here, would be if you wanted to have a side-effect happen in real time too. If you don't, then there is no need for real time and you can simply query the current state _when needed_. – romainl Jun 17 '21 at 11:16
  • Side-effect description is accurate. In general, every time the window is opened I need to display a certain info related to it, given the window is a regular window with a regular buffer. – Anton Tretyakov Jun 17 '21 at 11:27
  • Tested it a bit more and added the new info into a post, if you would find it interesting to find out what is happening. – Anton Tretyakov Jun 17 '21 at 15:22
1

You can check out :h :buffers which shows all buffers.

:buffers[!] [flags] where [flags] restricts the buffers to be listed. For example

" Show all active buffers
buffers! a

" Show regular active buffers
buffers a

" Show special(unlisted) active buffers
buffers au

You can also :filter buffers by displayed buffer name

filter /\.vim/ buffers a

Another way to get all buffers is getbufinfo() which provides more details.

leaf
  • 1,624
  • 11
  • 16
  • Hey! Thanks for spending time on this question! Though this is a good point, I cannot yet see how this answers my question or how I can apply it to solve the problem. – Anton Tretyakov Jun 17 '21 at 10:52
  • I mean, I can see the buffers that are unmodifaible to catch `quickfix`, `help` and `terminal`, but the open question is still when exactly to do it to catch the type timely and in a reliable fashion. – Anton Tretyakov Jun 17 '21 at 11:04
  • Tested it a bit more and added the new info into a post, if you would find it interesting to find out what is happening. – Anton Tretyakov Jun 17 '21 at 15:22
  • 1
    There are a number of events on buf change. I see you mentioned `BufEnter, WinEnter`. I'm not sure, maybe a combination of them and `BufWinEnter` as well as `BufNew, BufAdd` can cover most cases. – leaf Jun 18 '21 at 05:44
  • `BufWinEnter` doesn't solve the problem, unfortunately. But, you got me thinking in a way of using some other events to catch the rebellious windows and buffers after `BufEnter` and co somehow, and I come up with the idea to catch `terminal` with `TerminalOpen`, check `command` once again with `CmdWinEnter`, and fix`quickfix` problem with checking its' `filetype` with, well, `FileType`. These are huge workarounds, but I cannot se another way of solving this yet. Unfortunatelly, `:split` problem is still a thing. – Anton Tretyakov Jun 19 '21 at 13:05
  • Ok, with the above taken into account, `WinEnter` seem to work fine with `:split`. I guess the problem is solved. – Anton Tretyakov Jun 19 '21 at 13:16