-
Notifications
You must be signed in to change notification settings - Fork 8.7k
Add support for multiple panes in the same window #825
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
Merged
Merged
Changes from 30 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
606dd57
Start working on adding support for panes
zadjii-msft 91dc273
Add basic pane splitting
zadjii-msft a600b20
This works for nesting panes
zadjii-msft faaba47
Switching tabs keeps focus on the last active pane now
zadjii-msft 9b792d3
Reload settings for the panes.
zadjii-msft 7ca3e8d
Get titles working again
zadjii-msft db7523a
Update the icon too
zadjii-msft 7258a71
Pull these two guys into helpers
zadjii-msft 29464ea
Merge remote-tracking branch 'origin/master' into dev/migrie/f/panes
zadjii-msft 377aa4f
Hook up the terminal's closing to the pane's to the tab's
zadjii-msft 23930b5
This is me trying to mess with the tab closing, but I think it's prob…
zadjii-msft a4fbc53
Revert "This is me trying to mess with the tab closing, but I think i…
zadjii-msft b353e89
TONS of polish. Doc comments, etc.
zadjii-msft dc3f522
Correctly close a pane when one of it's children has children
zadjii-msft d45a9aa
Correctly move focus to a child with children when the focused pane i…
zadjii-msft 0a96ed4
doc comments for days
zadjii-msft a754474
Merge remote-tracking branch 'origin/master' into dev/migrie/f/panes
zadjii-msft ff21bd2
This is most all of the PR feedback
zadjii-msft ba805e8
Update doc/cascadia/Panes.md
zadjii-msft 3d1c4ca
Mostly just PR nits
zadjii-msft 013cefa
Merge remote-tracking branch 'origin/master' into dev/migrie/f/panes
zadjii-msft 7c5c222
Fix some bugs with closing a leaf _after_ it was a parent.
zadjii-msft cd75b1d
Merge remote-tracking branch 'origin/master' into dev/migrie/f/panes
zadjii-msft d5060b3
Merge branch 'master' into dev/migrie/f/panes
zadjii-msft 6d847dc
Merge remote-tracking branch 'origin/master' into dev/migrie/f/panes
zadjii-msft 0f848e7
Remove the default keybinding.
zadjii-msft bbed9ed
switch to in-class initializers
zadjii-msft 704f6cc
Update doc/cascadia/Panes.md
zadjii-msft d016d5c
Merge remote-tracking branch 'origin/master' into dev/migrie/f/panes
zadjii-msft 40c5600
Apply suggestions from code review
zadjii-msft 890fb3a
Add a NOTICES file.
DHowett 0ea8b85
move the NOTICE to the right branch...
DHowett 80036e2
Much of the easier PR feedback
zadjii-msft 9165d02
Lock up the panes when they're getting opened/closed
zadjii-msft 7f50a0f
A little bit of cleanup on the comments here
zadjii-msft b5d954e
Refactor the code for actually doing a split
zadjii-msft c6311f7
Clean up some typos
zadjii-msft a76db18
Merge remote-tracking branch 'origin/master' into dev/migrie/f/panes
zadjii-msft c265317
Fixed build error
carlos-zamora 14f3ffa
Apply suggestions from code review
zadjii-msft f945c18
Apply suggestions from code review
zadjii-msft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
--- | ||
author: "Mike Griese @zadjii-msft" | ||
created on: 2019-May-16 | ||
--- | ||
|
||
# Panes in the Windows Terminal | ||
|
||
## Abstract | ||
|
||
Panes are an abstraction by which the terminal can display multiple terminal | ||
instances simultaneously in a single terminal window. While tabs allow for a | ||
single terminal window to have many terminal sessions running simultaneously | ||
within a single window, only one tab can be visible at a time. Panes, on the | ||
other hand, allow a user to have many different terminal sessions visible to the | ||
user within the context of a single window at the same time. This can enable | ||
greater productivity from the user, as they can see the output of one terminal | ||
window while working in another. | ||
|
||
This spec will help outline the design of the implementation of panes in the | ||
Windows Terminal. | ||
|
||
## Inspirations | ||
|
||
Panes within the context of a single terminal window are not a new idea. The | ||
design of the panes for the Windows Terminal was heavily inspired by the | ||
application `tmux`, which is a commandline application which acts as a "terminal | ||
multiplexer", allowing for the easy managment of many terminal sessions from a | ||
single application. | ||
|
||
Other applications that include pane-like functionality include (but are not | ||
limited to): | ||
|
||
* screen | ||
* terminator | ||
* emacs & vim | ||
* Iterm2 | ||
|
||
## Design | ||
|
||
The architecture of the Windows Terminal can be broken into two main pieces: | ||
Tabs and Panes. The Windows Terminal supports _top-level_ tabs, with nested | ||
panes inside the tabs. This means that there's a single strip of tabs along the | ||
application, and each tab has a set of panes that are visible within the context | ||
of that tab. | ||
|
||
Panes are implemented as a binary tree of panes. A Pane can either be a leaf | ||
pane, with it's own terminal control that it displays, or it could be a parent | ||
pane, where it has two children, each with their own terminal control. | ||
|
||
When a pane is a parent, its two children are either split vertically or | ||
horizontally. Parent nodes don't have a terminal of their own, the merely | ||
display the terminals of their children. | ||
|
||
* If a Pane is split vertically, the two panes are seperated by a vertical | ||
split, as to appear side-by-side. Think `[|]` | ||
* If a Pane is split horizontally, the two panes are split by a horizontal | ||
separator, and appear above/below one another. Think `[-]`. | ||
|
||
As additional panes are created, panes will continue to subdivide the space of | ||
their parent. It's up to the parent pane to control the sizing and display of | ||
it's children. | ||
|
||
### Example | ||
|
||
We'll start by taking the terminal and creating a single vertical split. There | ||
are now two panes in the terminal, side by side. The original terminal is `A`, | ||
and the newly created one is `B`. The terminal now looks like this: | ||
|
||
``` | ||
+---------------+ | ||
| | | 1: parent [|] | ||
| | | ├── 2: A | ||
| | | └── 3: B | ||
| A | B | | ||
| | | | ||
| | | | ||
| | | | ||
+---------------+ | ||
``` | ||
|
||
Here, there are actually 3 nodes: 1 is the parent of both 2 and 3. 2 is the node | ||
containing the `A` terminal, and 3 is the node with the `B` terminal. | ||
|
||
|
||
We could now split `B` in two horizontally, creating a third terminal pane `C`. | ||
|
||
``` | ||
+---------------+ | ||
| | | 1: parent [|] | ||
| | B | ├── 2: A | ||
| | | └── 3: parent [-] | ||
| A +-------+ ├── 4: B | ||
| | | └── 5: C | ||
| | C | | ||
| | | | ||
+---------------+ | ||
``` | ||
|
||
Node 3 is now a parent node, and the terminal `B` has moved into a new node as a | ||
sibling of the new terminal `C`. | ||
|
||
We could also split `A` in horizontally, creating a fourth terminal pane `D`. | ||
|
||
``` | ||
+---------------+ | ||
| | | 1: parent [|] | ||
| A | B | ├── 2: parent [-] | ||
| | | | ├── 4: A | ||
+-------+-------+ | └── 5: D | ||
| | | └── 3: parent [-] | ||
| D | C | ├── 4: B | ||
| | | └── 5: C | ||
+---------------+ | ||
``` | ||
|
||
While it may appear that there's a single horizonal separator and a single | ||
vertical separator here, that's not actually the case. Due to the tree-like | ||
structure of the pane splitting, the horizontal splits exist only between the | ||
two panes they're splitting. So, the user could move each of the horizontal | ||
splits independently, without affecting the other set of panes. As an example: | ||
|
||
``` | ||
+---------------+ | ||
| | | | ||
| A | | | ||
+-------+ B | | ||
| | | | ||
| D | | | ||
| +-------+ | ||
| | C | | ||
+---------------+ | ||
``` | ||
|
||
### Creating a pane | ||
|
||
In the basic use case, the user will decide to split the currently focused pane. | ||
The currently focused pane is always a leaf, because as parent's can't be | ||
focused (they don't have their own terminal). When a user decides to add a new | ||
pane, the child will: | ||
|
||
1. Convert into a parent | ||
2. Move its terminal into it's first child | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
3. Split its UI in half, and display each child in one half. | ||
|
||
It's up to the app hosting the panes to tell the pane what kind of terminal in | ||
wants created in the new pane. By default, the new pane will be created with the | ||
default settings profile. | ||
|
||
### While panes are open | ||
|
||
When a tab has multiple panes open, only one is the "active" pane. This is the | ||
pane that was last focused in the tab. If the tab is the currently open tab, | ||
then this is the pane with the currectly focused terminal control. When the user | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
brings the tab into focus, the last focused pane is the pane that should become | ||
focused again. | ||
|
||
The Tab's state will be updated to reflect the state of it's focused pane. The | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
title text and icon of the tab will reflect that of the focused pane. Should the | ||
focus switch from one pane to another, the tab's text and icon should update to | ||
reflect the newly focused control. Any additional state that the tab would | ||
display for a single pane should also be reflected in the tab for a tab with | ||
multiple panes. | ||
|
||
While panes are open, the user should be able to move any split between panes. | ||
In moving the split, the sizes of the terminal controls should be resized to | ||
match. | ||
|
||
### Closing a pane | ||
|
||
A pane can either be close by the user manually, or when the terminal it's | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
attached to raises it's ConnectionClosed event. When this happens, we should | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
remove this pane from the tree. The parent of the closing pane will have to | ||
remove the pane as one of it's children. If the sibling of the closing pane is a | ||
leaf, then the parent should just take all of the state from the remaining pane. | ||
This will cause the remaining pane's content to expand to take the entire | ||
boundaries of the parent's pane. If the remaining child was a parent itself, | ||
then the parent will take both the children of the remaining pane, and make them | ||
the parent's children, as if the parent node was taken from the tree and | ||
replaced by the remaining child. | ||
|
||
## Future considerations | ||
|
||
The Pane implementation isn't complete in it's current form. There are many | ||
additional things that could be done to improve the user experience. This is by | ||
no means a comprehensive list. | ||
|
||
* [ ] Panes should be resizable with the mouse. The user should be able to drag | ||
the separator for a pair of panes, and have the content between them resize as | ||
the separator moves. | ||
* [ ] There's no keyboard shortcut for "ClosePane" | ||
* [ ] The user should be able to configure what profile is used for splitting a | ||
pane. Currently, the default profile is used, but it's possible a user might | ||
want to create a new pane with the parent pane's profile. | ||
* [ ] There should be some sort of UI to indicate that a particular pane is | ||
focused, more than just the blinking cursor. `tmux` accomplishes this by | ||
colorizing the separators adjacent to the active pane. Another idea is | ||
displaying a small outline around the focused pane (like when tabbing through | ||
controls on a webpage). | ||
* [ ] The user should be able to navigate the focus of panes with the keyboard, | ||
instead of requiring the mouse. | ||
* [ ] The user should be able to zoom a pane, to make the pane take the entire | ||
size of the terminal window temporarily. | ||
* [ ] A pane doesn't necessarily need to host a terminal. It could potentially | ||
host another UIElement. One could imagine enabling a user to quickly open up a | ||
Browser pane to search for a particular string without needing to leave the | ||
terminal. | ||
|
||
## Footnotes | ||
|
||
### Why not top-Level Panes, and nested tabs? | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
If each pane were to have it's own set of tabs, then each pane would need to | ||
reserve screen real estate for a row of tabs. As a user continued to split the | ||
window, more and more of the screen would be dedicated to just displaying a row | ||
of tabs, which isn't really the important part of the application, the terminal | ||
is. | ||
|
||
Additionally, if there were top-level panes, once the root was split, it would | ||
not be possible to move a single pane to be the full size of the window. The | ||
user would need to somehow close the other panes, to be able to make the split | ||
the size of the dull window. | ||
|
||
One con of this design is that if a control is hosted in a pane, the current | ||
design makes it hard to move out of a pane into it's own tab, or into another | ||
pane. This could be solved a number of ways. There could be keyboard shortcuts | ||
for swapping the positions of tabs, or a shortcut for both "zooming" a tab | ||
(temporarily making it the full size) or even popping a pane out to it's own | ||
tab. Additionally, a right-click menu option could be added to do the | ||
aformentioned actions. Discoverability of these two actions is not as high as | ||
just dragging a tab from one pane to another; however, it's believed that panes | ||
are more of a power-user scenario, and power users will not neccessarily be | ||
turned off by the feature's discoverability. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.