orbitalquark / textadept

Textadept is a fast, minimalist, and remarkably extensible cross-platform text editor for programmers.
https://orbitalquark.github.io/textadept
MIT License
653 stars 39 forks source link

Buffer switch behaviour #33

Closed rgieseke closed 3 years ago

rgieseke commented 3 years ago

I'm trying to understand the buffer switch behaviour as the view state restoring is sometimes messed up when using Textredux. E.g. i have wrap_mode set to None in a Textredux buffer, but by word otherwise. When closing a Textredux buffer the wrong wrap_mode is applied to a regular Text buffer.

With

events.connect(events.BUFFER_AFTER_SWITCH, function()
  print(buffer.filename or buffer._type)
end, 1)

in my init.lua and

-- Restore view state.
local function restore_view_state()
  if not buffer._margin_type_n then return end
  print("Restoring", buffer.filename)
  view.view_ws, view.wrap_mode = buffer._view_ws, buffer._wrap_mode
  for i = 1, view.margins do
    view.margin_type_n[i] = buffer._margin_type_n[i]
    view.margin_width_n[i] = buffer._margin_width_n[i]
  end
end
events.connect(events.BUFFER_AFTER_SWITCH, restore_view_state)
events.connect(events.VIEW_AFTER_SWITCH, restore_view_state)

in Textadept's core/ui.lua (just added a print statement) and a similar statement in the save_view_store function it seems, that when I

I suspect that this is the reason for the problem with the view state being applied to the wrong buffer. Any ideas why it switches to the wrong buffer first? Should it save view state also after a buffer_new event?

orbitalquark commented 3 years ago

Textadept switches to the "wrong" buffer first because after buffer:close(), the buffer immediately before it in _BUFFERS is shown/switched to. However, https://github.com/orbitalquark/textadept/blob/cfc696571b49fa0728b19a32671cc6f651181611/core/ui.lua#L442 tries to restore the last visible buffer on buffer:close(), so that is why you're seeing two separate save events. (The duplicate restore event I'm unsure of.)

Do you need save_view_state() to be called immediately on the new buffer to populate those fields? Other than the fields existing, nothing meaningful is saved, which is why I don't do it.

rgieseke commented 3 years ago

Say you have 2 files open:

You go to the first opened init.lua, then you open a new buffer and close the new buffer:

What happens is:

Saving view state   session
Switch to init.lua
Restoring   init.lua
Switch to init.lua
Restoring   init.lua

So if you change wrap mode oder margins in the new buffer (like i do in Textredux) the session file passed by while closing inherits the view state from the new buffer.

The problem seems to be that there is no "after_switch" event fired for the passing-by of the last buffer in _BUFFERS.

orbitalquark commented 3 years ago

Thanks for the concrete example. I'll take a look at this when I have some time.

rgieseke commented 3 years ago

Thanks!

Maybe disconnecting events before the switch to the previous buffer could be a fix.

-- Keeps track of, and switches back to the previous buffer after buffer close.
events.connect(
  events.BUFFER_BEFORE_SWITCH, function() view._prev_buffer = buffer end)
events.connect(events.BUFFER_DELETED, function()
  if _BUFFERS[view._prev_buffer] and buffer ~= view._prev_buffer then
    events.disconnect(events.VIEW_BEFORE_SWITCH, save_view_state)
    events.disconnect(events.BUFFER_BEFORE_SWITCH, save_buffer_state)
    view:goto_buffer(view._prev_buffer)
    events.connect(events.BUFFER_BEFORE_SWITCH, save_view_state)
    events.connect(events.VIEW_BEFORE_SWITCH, save_view_state)
  end
end)

Seems to fix the example scenario above, will check further. Maybe not both need to be disconnected. [Edited to use correct event]

rgieseke commented 3 years ago

The above would likely work with save_view_state only.

Thus, the following also seems to do the trick:

-- Keeps track of, and switches back to the previous buffer after buffer close.
events.connect(
  events.BUFFER_BEFORE_SWITCH, function() view._prev_buffer = buffer end)
events.connect(events.BUFFER_DELETED, function()
  if _BUFFERS[view._prev_buffer] and buffer ~= view._prev_buffer then
    restore_view_state()
    view:goto_buffer(view._prev_buffer)
  end
end)
orbitalquark commented 3 years ago

Thanks for debugging this one. Fixed via https://github.com/orbitalquark/textadept/commit/0ef954ca2030ada323dacf35c41c2d17d3d9731e

rgieseke commented 3 years ago

Awesome, thank you! Next time i'll try to submit a reproducible test case, this is nice :-)