Skip to content

add multi window support #419

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 31 commits into from
Closed

Conversation

xzbdmw
Copy link

@xzbdmw xzbdmw commented Mar 19, 2024

This will track a global map that map winid to {bufnr,gut_bufnr, context_bufnr,gutter_winid,context_winid} and dynamically clean up and add new one, I'm new to lua so thanks for your advice. Currently WinScroll autocmd seems don't adjust context window position and I can't figure out why.

@xzbdmw
Copy link
Author

xzbdmw commented Mar 19, 2024

Oh why the formatting is changed

Copy link
Collaborator

@romgrk romgrk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested yet but overall the approach & feature looks good to me.

Comment on lines 132 to 136
autocmd({ 'WinScrolled' }, function()
for winid, bufnr_map in pairs(require('treesitter-context.render').get_bufnr_maps()) do
update(bufnr_map.bufnr, winid)
end
end)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we updating all the windows on scroll? Shouldn't we be only updating the scrolled one?

Copy link
Author

@xzbdmw xzbdmw Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commands such as split will trigger winscroll, and every window width should be adjusted to new width, how should we differentiate scroll and resizing? Should I use winresized instead? Ideally if user create a new split, I’d like to close all of them and reopen again to avoid position flashing, will try again.

@xzbdmw
Copy link
Author

xzbdmw commented Mar 20, 2024

There is one thing I can't understand
in neovide, resizing works perfect:

iShot_2024-03-20_12.35.51.mp4

but in kitty(as well as wezterm), when new window created, the position becomes wrong(if I focus the window again, position will be correct):

iShot_2024-03-20_12.37.36.mp4

Can you help with me what causes the difference?
note: I checked the else branch in display_window, It indeed changed context's window width after resize, but the real effect don't show up.

@xzbdmw
Copy link
Author

xzbdmw commented Mar 21, 2024

@romgrk @lewis6991 Hello could you test this? The only issue remains is the attached[buf] I'm not sure how to change it, since now we have multiple windows.

Edit: I found

local update = throttle(function()
  local bufnr = api.nvim_get_current_buf()
  local winid = api.nvim_get_current_win()

these two lines have race conditions that nvim_get_current_buf sometimes returns the old bufnr which is not the one in nvim_get_current_win's buf, add a 1ms delay calling update fix that(vim.schedule also works). Not sure why it is inconsistent.

  autocmd({ 'WinScrolled', 'BufEnter', 'WinEnter', 'VimResized' }, function()
    vim.defer_fn(function()
      update()
    end, 1)
  end)

@romgrk
Copy link
Collaborator

romgrk commented Mar 22, 2024

For your issue, I don't like adding an async delay there, even if just 1ms. You should retrieve the buf/win ID during the event handler via the usual mechanism (<amatch> and friends) and pass it as an argument to update(), maybe an optional param would be good. Though I don't see the defer_fn in this PR, lmk when it's ready for review.

do
for _, window_id in pairs(window_ids) do
if stored_winid == window_id then
throttle(function()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work for anonymous functions since it is only ever called once.

Copy link
Author

@xzbdmw xzbdmw Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe no need for throttle? Just directly calling
open() to update state, and the same for WinEnter, since some plugin may open many windows in a short time , we should instantly trigger open().

Copy link
Member

@lewis6991 lewis6991 Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling throttle like this (throttle(...)()) doesn't work. It needs to be.

local f = throttle(...)
f()
f() -- throttled

Not:

throttle(...)()
throttle(...)() -- not throttled!

return buf
--- @param winid integer?
local function win_close(winid)
vim.schedule(function()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code doesn't show why this is needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I move win_close to top since store_context needs to call close if underline buffer changed

@@ -155,7 +198,18 @@ function M.enable()

autocmd({ 'BufLeave', 'WinLeave' }, close)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe bufleave and winleave is no longer needed, winleave can be replaced by winclosed, and bufleave's close behavior is expressed in store_contest's win_close call.

relative = 'win',
width = width,
height = height,
row = 0,
col = col,
})
end
return winid
return float_winid
end

--- @param winid integer
Copy link
Author

@xzbdmw xzbdmw Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

textoff is inconsistent too. In my case it will return 4 and after next update time it will return 8, cause window position to flash(mark the wrong line number, two lines below)

@xzbdmw
Copy link
Author

xzbdmw commented Apr 8, 2024

@romgrk hello do you have time to review?
According to this suggestion
https://www.reddit.com/r/neovim/comments/10eu7go/comment/j4uaxpe/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
I'm wrapping WinEnter in a vim.schedule now to get new bufnr. It should be ready to merge, after 3 weeks of use I see no problem.
But I have not find a reliable way to get buffer information after WinEnter is triggered, the solution above is not perfect if you open many windows at the same time, since vim.schedule's execute time is uncertain, as the origin comment says. But it is still a improvement since there would not be some file buffer unrelated windows to show previous buf's context.

if window_ctx.bufnr == bufnr then
return window_ctx
else
-- Unserline buffer have changed, close it
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo?

Copy link
Collaborator

@romgrk romgrk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I'll run the PR in my config to test it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wrapping WinEnter in a vim.schedule now to get new bufnr. It should be ready to merge, after 3 weeks of use I see no problem.
But I have not find a reliable way to get buffer information after WinEnter is triggered, the solution above is not perfect if you open many windows at the same time, since vim.schedule's execute time is uncertain, as the origin comment says. But it is still a improvement since there would not be some file buffer unrelated windows to show previous buf's context.

Yeah sometimes events are ugly. Maybe this would be better fixed in neovim directly, if it's unreliable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I remove WinEnter since it is not reliable, and indeed there are no need for that autocmd

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wdym by not needed? I'm observing a few cases where the context doesn't show up, wondering if it's connected?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think BufEnter is more general than WinEnter, since there must be a loaded buffer to show context, which case context don't show up? Could you try to add WinEnter to see if it still doesn't show up?

Copy link
Collaborator

@romgrk romgrk Apr 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you observed similar behavior? Can you do the changes on this PR? Could you also explain why it was needed to change the events we listen to?

Also I've been using for 2 weeks and I love how much less flickering there is from the context window opening/closing on every window change.

Copy link
Author

@xzbdmw xzbdmw Apr 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you observed similar behavior

No, but I have context window opened in none-file buffers if I just keep WinEnter unchanged as is.
截屏2024-04-19 21 08 03
I have a keymap that first enter right "reference list", then immediately move focus to the preview window, and a workaround is wrapping callback in vim.schedule to get the right buffer number(but it is not always right theoretically that's why I delete it), If you prefer keep WinEnter I'll add it back.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a preference, whatever works is best, I'm just wondering if changing the events might have caused the few cases I saw where the window wasn't appearing. I'm always very confused with autocmds so I couldn't tell you which combination of BufEnter/WinEnter/BufWinEnter is right for our use-case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, have added it back.

WinEnter may mess up windows and there is no need for that I think
@xzbdmw
Copy link
Author

xzbdmw commented May 3, 2024

@romgrk @lewis6991 Hello any chance this get merged?

@romgrk
Copy link
Collaborator

romgrk commented May 7, 2024

Code-wise the PR looks good, but I've been running it for a while and I keep seeing cases where the context window(s) don't get opened. It doesn't bother me much personally but I don't have enough confidence in it to give it a green light, and I also haven't had time to debug the code.

Have you seen any such cases?

@xzbdmw
Copy link
Author

xzbdmw commented May 7, 2024

Hmm no problem for me so far, works seamless( I mainly use nightly), if users encounter the same problem, they may provide some information and we can fix it. I think whenever you move cursor, context will open if it didn't open before.

@xzbdmw xzbdmw closed this Jul 9, 2024
@apollo1321
Copy link
Contributor

apollo1321 commented Aug 21, 2024

@romgrk @lewis6991 Hi, could you please clarify the reason this PR was closed?

I have developed my own implementation of multi-window support a couple of months ago, and I have been using it extensively since then. My experience has been very positive; it has performed flawlessly without any issues related to multiple windows or resizing.

Additionally, I have conducted performance testing using flamegraphs, and I have observed that treesitter-context consumes approximately 7% of processing time, which appears to be within a reasonable range.

I believe that multi-window support is a highly valuable feature, especially for working with large codebases efficiently. I think it would greatly benefit other users as well.

If it would be helpful, I am more than happy to share my implementation and potentially create a new PR.

@xzbdmw
Copy link
Author

xzbdmw commented Aug 21, 2024

Because I tried to rebase but there are too many commits behind 😄 I planned to open a new pr but forgot it, it will be awesome if you are happy to create a pr.

@romgrk
Copy link
Collaborator

romgrk commented Aug 21, 2024

Not enough time to review/debug the few minor issues that appeared at the time. I'd be happy to see this feature, I just don't have much time to put into FOSS right now, and @lewis6991 also needs to sign off on it as he's the more active maintainer at the moment. But please open a PR if you have one that's production ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants