atlas-engineer / nyxt

Nyxt - the hacker's browser.
https://nyxt-browser.com/
9.9k stars 412 forks source link

Buffer splitting/tiling #55

Open dunkyp opened 6 years ago

dunkyp commented 6 years ago

Is anyone else interested in splitting windows emacs style. I've implemented a super simple prototype in the cocoa version (splitting window in half horizonally and manually updating the window url from the repl) and it seems to work nicely. Does anyone else like this idea. I've included a screenshot of the hack in action, just want to gather opinions on whether it's worth implementing this fully (horizonal and vertical splitting, resizing window switching etc.)

screenshot

jmercouris commented 6 years ago

I for one am SUPER interested in this. How do you update the active buffer when splitting the window? Did you make a callback into the next package to set the active buffer?

Any more information on this would be greatly interested. Thank you so much! I have literally been dreaming about this feature for months.

dunkyp commented 6 years ago

Well, that's great news I have a weekend project sorted ;). The implementation is just the simplest possible but I'll push changes once I have them to a fork which I'll create now.

jmercouris commented 6 years ago

Ok great, I'm so happy to hear this, you have no idea :)

jmercouris commented 6 years ago

@dunkyp Could you please post the code you did to split the screen? Regardless of how incomplete it may be. I'm quite curious to see!

shanemhansen commented 5 years ago

@dunkyp Interested in the split screen as well.

jmercouris commented 5 years ago

I'm afraid the implementation has changed so much since this RFC, that it is at the moment entirely impossible. We have to change a lot of things in the port architecture to support this. I would like window splitting myself as well. I don't like to say it, but this is probably something that will most likely have to wait for version 2.0.

Ambrevar commented 5 years ago

Hmm... Maybe not. I gave this some thoughts and I think we might even be able to roll out a fully-flexible window management without breaking backward compatibility.

There are more pressing issues at the moment, but I might work on this not to far in the future.

jmercouris commented 5 years ago

If you can think of a simple way to do this, I would be very happy as this is one feature I really would love to have!

I can't ever wrap my head around the tree structures and how to implement things though (with regards to tiling window managers) :\

Ambrevar commented 4 years ago

We are very close to being able to have a vertical minibuffer. A few FFI functions would be enough.

That said, it would be more interesting to implement full-fledged window-manager à-la Emacs. Then the vertical minibuffer would come for free.

Maybe have a look at Lem / StumpWM to avoid reinventing the wheel.

shaunsingh commented 1 year ago

Ran into this bug today, which i quite like 20230302_13h34m15s_grim

As https://github.com/atlas-engineer/nyxt/issues/1604 has been fixed, is this possible to implement now? I'd be happy to work on it

aadcg commented 1 year ago

Offtopic: That's a seriously customized status-buffer! Glad to see it :)

shaunsingh commented 1 year ago

Glad to see it :)

Thank you for making it to easy to configure :)

Anyways, had a go at trying to implement a hacky version using the current panel-buffer functionality

20230303_01h37m53s_grim

From what I understand, the renderer has assigned containers for the panel buffers and prompt buffer. The hsplit code below doesn't work currently, but you could probably implement it using the prompt-buffers container.

https://github.com/atlas-engineer/nyxt/blob/0a288c573e40b8b7ac12264782e095ca08d9f507/source/renderer/gtk.lisp#L68

I think the way to go is give prompt-buffer, status-buffer, and message-buffer their own containers, since those are always going to be static on the page (assuming you have one status/message/prompt for the whole window, which is what I prefer)

Then we should be able to spawn new containers for each buffer. This will deprecate the need for panel buffers, and will allow us to create multiple regular buffers of various sizes, enabling emacs/stumpwm-like manipulation and management of windows.

After that its just a matter of modifying the code to take multiple buffers into account, and respond better to mouse actions (e.g. resizing windows). A lot of this is already semi-implemented with panel-buffer's, so shouldn't be too bad

Of course I'd be more than happy to just limit it to one horizontal split and one vertical split, definining static containers for each, but I think it would be much more powerful to enable infinite buffers.

Code for the "poor mans split" below (my enable-modes code clearly doesn't work, although I believe it should?)

(defun open-split (type panel-buffer)
  "a poor mans split"
  (let* ((url (quri:render-uri (url (current-buffer))))
         (modes (mapcar #'serapeum:class-name-of
                  (modes (current-buffer)))))
    (cond 
      ((string= type "horizontal")
       (setf (ffi-width panel-buffer) (ffi-width (current-window)))
       (setf (ffi-height panel-buffer) (round (/ (ffi-height (current-window)) 2))))
      ((string= type "vertical")
       (setf (ffi-width panel-buffer) (round (/ (ffi-width (current-window)) 2)))))
    (buffer-load (quri:uri url) :buffer panel-buffer)
    (enable-modes* modes (buffer panel-buffer))))

(define-panel-command-global vsplit ()
    (panel-buffer "*vsplit*" :right)
  "open current buffer with modes in a knockoff vertical split"
  (open-split "vertical" panel-buffer))

(define-panel-command-global hsplit ()
    (panel-buffer "*split*")
  "open current buffer with modes in a knockoff horizontal split"
  (open-split "horizontal" panel-buffer))

(define-command-global split ()
  "alias to `hsplit`"
  (hsplit))
jmercouris commented 1 year ago

I think the way to go is give prompt-buffer, status-buffer, and message-buffer their own containers, since those are always going to be static on the page (assuming you have one status/message/prompt for the whole window, which is what I prefer)

(define-class gtk-window ()
  ((gtk-object)
   (handler-ids
    :documentation "See `gtk-buffer' slot of the same name.")
   (root-box-layout)
   (horizontal-box-layout)
   (panel-buffer-container-left)
   (panel-buffer-container-right)
   (panel-buffers-left)
   (panel-buffers-right)
   (main-buffer-container)
   (prompt-buffer-container)
   (prompt-buffer-view
    :documentation "Shared web view between all prompt buffers of this window.")
   (status-container)
   (message-container)
   (message-view)
   (key-string-buffer))
  (:export-class-name-p t)
  (:export-accessor-names-p t)          ; TODO: Unexport?
  (:accessor-name-transformer (class*:make-name-transformer name)))

Very close :-). So the prompt-buffer has a container, the message buffer has a container (message-container), and the status buffer has a container (status-container). The reason for this inconsistent naming is because we actually refer to them as the "status area" and "message area".

I too would like infinite buffers tiling. I have thought about how to do this. From what I have figured it would look like this.

We have a root container, it doesn't matter what this is. With a single buffer it looks like this:

Root -> Horizontal Box -> Webview

if the user splits vertically, we will get:

Root -> Horizontal Box -> Horizontal Box -> Webview, Horizontal Box -> Webview

if the user splits horizontally we will get:

Root -> Vertical Box -> Horizontal Box -> Webview, Horizontal Box -> Webview

so we always wrap a Webview in a container that we can then swap out for a horizontal or vertical container. It would be even easier if we can dynamically assign box layouts to being horizontal or vertical.

In any case, after a lot of consideration and deliberation, I think the best way to do this would be to only allow vertical splits, and then implement horizontal scrolling. This will be the easiest way to present lots of information, and the aspect ratio of all monitors these days is basically wide screen.

If you are interested in implementing this idea, I will champion it to completion :-D

jmercouris commented 1 year ago

I think it also fits well with people's mental model of "tabs".

aartaka commented 1 year ago

Anyways, had a go at trying to implement a hacky version using the current panel-buffer functionality

Yeah, I had one too :D

shaunsingh commented 1 year ago

Your config inspired me to have a go at this issue in the first place :p

In any case, after a lot of consideration and deliberation, I think the best way to do this would be to only allow vertical splits, and then implement horizontal scrolling. This will be the easiest way to present lots of information, and the aspect ratio of all monitors these days is basically wide screen.

I actually use a vertical monitor, so I primarily use horizontal splits in vim/emacs, and I'd like to add it sometime. I agree that starting off with horizontal splits for now is a good idea.

If you are interested in implementing this idea, I will champion it to completion :-D

Sure! I'm not the best at CL, I'm only proficient in fennel which is quite a different implementation, so I apologize in advance if it might take a while

Regarding the status-buffer/message-buffer/prompt-buffer, are we having one of each "globally" for the window? Or are we aiming it to handle it like emacs, with one status per split.

I feel like web-pages are generally a lot bigger than text, and our status-buffer is quite crowded already, so we should stick with one globally

aartaka commented 1 year ago

Regarding the status-buffer/message-buffer/prompt-buffer, are we having one of each "globally" for the window? Or are we aiming it to handle it like emacs, with one status per split.

I feel like web-pages are generally a lot bigger than text, and our status-buffer is quite crowded already, so we should stick with one globally

Yes, that'd be my intuition too!

jmercouris commented 1 year ago

Yes, we can stick with one globally that updates when you select different buffers.

tekakutli commented 1 year ago

This would be cool, that said:

I did this too, but it wasnt intentional, it has happened a couple of times and I dont know what I did or how to fix it other than by restarting nyxt https://files.catbox.moe/df07y0.png do anyone knows how to close it?

jmercouris commented 1 year ago

I have no idea how you did that. Presumably two views got added to the current buffer view and it stacked them on top. Perhaps some race condition?

shaunsingh commented 1 year ago

Indeed, sometimes the view bugs out and puts a web buffer in place of the prompt buffer.

I've been quite busy with personal and work projects, but I still plan to work on this soon-ish :tm:

MaxGyver83 commented 1 year ago

Today (running the master branch's version), I also ran into an unintentional split:

2023-09-30 10 48 02 2560x1412 Window

I tried Ctrl-Alt-h (jump-to-heading-buffers) and browsed through the result list and then aborted with Esc.

shaunsingh commented 1 year ago

A small update to the above: I did have a badly broken but slightly functional PoC with gtk, but had to switch back to macOS for work and, despite my best efforts, couldn't compile webkitGTK using nix. In the meantime, I'd be happy to work on the electron port (https://github.com/atlas-engineer/nyxt/issues/2989) and attack this in the future

cc @aartaka

aartaka commented 1 year ago

No worries, we're not hurrying with it anyway (I myself in particular — I already have what I need with the panel buffer hack 😅)

jjba23 commented 4 months ago

@MaxGyver83 I have also run into this strange vertical split thing unintentionally! Seems like Nyxt wants to have Emacs like buffer management hahah