Skip to content
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

Ready to make pull request #8

Merged
merged 1 commit into from
Dec 18, 2021
Merged

Ready to make pull request #8

merged 1 commit into from
Dec 18, 2021

Conversation

kwkarlwang
Copy link
Owner

This pull request brings two new functionality, resize_open and resize_close.

Problem

The problems I would like to solve is the following.

Normally, if you close window D in the below configuration, the height of window D goes to A and C.

Actual behavior
---------------          ---------------
|      |      |          |      |      |
|      |  B   |          |      |  B   |
|  A   |------|          |  A   |------|
|      |  C   |    ->    |      |  C   |
|      |      |          |      |      |
---------------          |      |      |
|      D      |          |      |      |
---------------          ---------------

This, at least to me, is strange as I would expect the the height and to be evenly distributed as between B and C

Expected Behavior
---------------          ---------------
|      |      |          |      |      |
|      |  B   |          |      |  B   |
|  A   |------|          |  A   |      |
|      |  C   |    ->    |      |------|
|      |      |          |      |      |
---------------          |      |  C   |
|      D      |          |      |      |
---------------          ---------------

The same goes for opening a new window. For example, if you open toggleterm in vertical direction (windows D in the below figure), the initial windows will go out of proportion.

Actual Behavior
---------------         ---------------
|      |      |         |      | |    |
|      |  B   |         |      |B|    |
|  A   |      |         |  A   | |    |
|      |------|   ->    |      |-| D  |
|      |      |         |      | |    |
|      |  C   |         |      |C|    |
|      |      |         |      | |    |
---------------         ---------------

I expected the width of A and B/C to have the same width as their width proportion was the same before toggling the new windows.

Expected Behavior
---------------         ---------------
|      |      |         |    |   |    |
|      |  B   |         |    | B |    |
|  A   |      |         |  A |   |    |
|      |------|   ->    |    |---| D  |
|      |      |         |    |   |    |
|      |  C   |         |    | C |    |
|      |      |         |    |   |    |
---------------         ---------------

I first notice this phenomena when using toggleterm as shown below.

without_bufresize.mov

Solution

Initially, I was planning to make a new extension to solve this problem. However, I found out that it shares a lot of codebase with bufresize.nvim, thus I am adding this functionality in this plugin.

The two new functions are resize_open and resize_close. Below is the configuration to solve the problem above.

opts = { noremap = true, silent = true }
map = vim.api.nvim_set_keymap
ToggleTerm = function(direction)
    local command = "ToggleTerm"
    if direction == "horizontal" then
        command = command .. " direction=horizontal"
    elseif direction == "vertical" then
        command = command .. " direction=vertical"
    end
    if vim.bo.filetype == "toggleterm" then
        require("bufresize").block_register()
        vim.api.nvim_command(command)
        require("bufresize").resize_close()
    else
        require("bufresize").block_register()
        vim.api.nvim_command(command)
        require("bufresize").resize_open()
        cmd([[execute "normal! i"]])
    end
end
map("n", "<C-s>", ":lua ToggleTerm()<cr>", opts)
map("n", "<leader>ot", [[:lua ToggleTerm("horizontal")<cr>]], opts)
map("n", "<leader>ol", [[:lua ToggleTerm("vertical")<cr>]], opts)
map("i", "<C-s>", "<esc>:lua ToggleTerm()<cr>", opts)
map("t", "<C-s>", "<C-\\><C-n>:lua ToggleTerm()<cr>", opts)
  • resize_open: find the newly opened window that is in the current state but not in the registered state, adjust the proportion of registered windows accordingly, then apply resize to the registered windows. Should be use with block_register to prevent race condition
  • resize_close: find the newly closed window that is not in the registered state but not in the current state, adjust the proportion of registered windows accordingly, then apply resize to the registered windows. Should be use with block_register to prevent race condition

A complete list of functions are listed in the README.

With this setup, below is the new behavior.

with_bufresize.mov

@kwkarlwang kwkarlwang merged commit a0b96b6 into master Dec 18, 2021
@kwkarlwang kwkarlwang deleted the resize_open_close branch December 18, 2021 19:47
@serranomorante
Copy link

serranomorante commented Aug 26, 2023

Hi! I got this working with neo-tree's event_handlers config option. I just wanted to confirm if the following code snippet is a good implementation? I mean it works, but I think I don't fully understand when block_register should be called and why? I just assumed it should be on neo_tree_window_before_open event but I'm not 100% sure.

Considering these neo-tree events:

  • "neo_tree_window_before_open" Fired before opening a new Neo-tree window.

  • "neo_tree_window_after_open" Fired after opening a new Neo-tree window.

  • "neo_tree_window_before_close" Fired before closing a Neo-tree window.

  • "neo_tree_window_after_close" Fired after closing a Neo-tree window.

I implemented this working solution:

...
event_handlers = {
	-- See https://github.com/kwkarlwang/bufresize.nvim/pull/8
	{
		event = "neo_tree_window_before_open",
		handler = function()
			require("bufresize").block_register()
		end,
	},
	{
		event = "neo_tree_window_after_open",
		handler = function()
			require("bufresize").resize_open()
		end,
	},
        {
	        event = "neo_tree_window_before_close",
	        handler = function()
		        require("bufresize").block_register()
	        end,
        },
	{
		event = "neo_tree_window_after_close",
		handler = function()
			require("bufresize").resize_close()
		end,
	},
},
...

Here's the before and after in that order:

t-rec_8

@kwkarlwang
Copy link
Owner Author

Hi! I got this working with neo-tree's event_handlers config option. I just wanted to confirm if the following code snippet is a good implementation? I mean it works, but I think I don't fully understand when block_register should be called and why? I just assumed it should be on neo_tree_window_before_open event but I'm not 100% sure.

Considering these neo-tree events:

  • "neo_tree_window_before_open" Fired before opening a new Neo-tree window.
  • "neo_tree_window_after_open" Fired after opening a new Neo-tree window.
  • "neo_tree_window_before_close" Fired before closing a Neo-tree window.
  • "neo_tree_window_after_close" Fired after closing a Neo-tree window.

I implemented this working solution:

...
event_handlers = {
	-- See https://github.com/kwkarlwang/bufresize.nvim/pull/8
	{
		event = "neo_tree_window_before_open",
		handler = function()
			require("bufresize").block_register()
		end,
	},
	{
		event = "neo_tree_window_after_open",
		handler = function()
			require("bufresize").resize_open()
		end,
	},
        {
	        event = "neo_tree_window_before_close",
	        handler = function()
		        require("bufresize").block_register()
	        end,
        },
	{
		event = "neo_tree_window_after_close",
		handler = function()
			require("bufresize").resize_close()
		end,
	},
},
...

Here's the before and after in that order:

t-rec_8

Hi @serranomorante, glad to see you got it working! Let me explain why block_register is necessary. First of all, we have state, state contains all the visible opened windows info (widths and heights). Using the default configuration, a state is registered on the events of WinEnter and BufWinEnter, essentially when you enter or open a new window.

So what block_register does is to prevent the state from being registered, even when WinEnter or BufWinEnter happens.
Below is a high level diagram demonstrating the what happens with or without block register. With block register, opening neotree will prevent
not trigger a state register. So when applying resize, the plugin knows that both A and B should occupy half of the space. After resize_open,
unblock_register is called and a new state will be registered (hence the state = neotree: 20%, A: 40%, B:40%).

Without block_regisiter
---------------         ---------------
|      |      |         |n |   |      |
|      |      |         |e |   |      |
|  A   |  B   |         |o | A |  B   |
|      |      |   ->    |t |   |      |
|      |      |         |r |   |      |
|      |      |         |e |   |      |
|      |      |         |e |   |      |
---------------         ---------------

before opening neotree:
state = A: 50%, B: 50% 

after opening neotree (a new state is registered):
state = neotree: 20%, A: 30%, B:50%

after resize_open:
state = neotree: 20%, A: 30%, B:50%

With block_regisiter
---------------         ---------------
|      |      |         |n |     |    |
|      |      |         |e |     |    |
|  A   |  B   |         |o |  A  |  B |
|      |      |   ->    |t |     |    |
|      |      |         |r |     |    |
|      |      |         |e |     |    |
|      |      |         |e |     |    |
---------------         ---------------

before opening neotree:
state = A: 50%, B: 50% 

after block_register:
state = A: 50%, B: 50% 

after opening neotree (state stays the same as before as block register is on):
state = A: 50%, B:50%

after resize_open:
state = neotree: 20%, A: 40%, B:40%

Hope this help!

@serranomorante
Copy link

Thank you so much 😭!! That make things more clear.

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.

2 participants