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

Pane refactor: separate pane into LeafPane and ParentPane, and make them winrt types #9024

Closed
wants to merge 74 commits into from

Conversation

PankajBhojwani
Copy link
Contributor

@PankajBhojwani PankajBhojwani commented Feb 3, 2021

Summary of the Pull Request

  • Replaces our pane class with LeafPane and ParentPane
  • LeafPane and ParentPane are now winrt types, allowing us to add controls to their xaml files much more easily

There are several todos left:

  • Maximize/Restore (i.e. zoomed leaf panes)
  • Update MRU pane stuff in TerminalTab
    - this requires a bit of discussion on how we want the tab to know about closed leaves so it can update the MRU list
  • Fix entrance animation not working
  • Fix issues with pane splits in startup actions/commandline arguments Turns out these issues also exist in main
  • Fix focus not transferring properly when a pane is closed
  • Code health: LayoutSizeNode does not need to live in ParentPane
  • Code health: Add comments/transfer comments from old pane implementation
  • Various todos marked in the code
  • Delete all the old pane code (leaving this for towards the end just in case something breaks and I want to see how it was done before)
  • Delete all the references to the previous pane type in TerminalTab (most of them have just been commented out for now for the same reason as above
    - this is mostly done, pane.cpp has been removed and references to the old pane type have been gone
    - keeping pane.h around for now because we might want to put some common stuff in there

References

Huge shoutout to @mcpiroman, a lot of the design for this PR was taken from #4068

PR Checklist

  • Closes #xxx
  • CLA signed. If not, go over here and sign the CLA
  • Tests added/passed
  • Documentation updated. If checked, please file a pull request on our docs repo and link it here: #xxx
  • Schema updated.
  • I work here

Validation Steps Performed

For now, opening and closing panes works fine (i.e. it is somewhat functional but I'm sure there are bugs that slipped past me)

@mcpiroman
Copy link
Contributor

O, so because I've got a notification, I'll just let you know some time later I had an idea to wrap the pane node in an union type which would be either pane or leaf, but in the same object. This, AFAIR, would provide a possibility to avoid much of the event rewiring (which I remember fearing), notifying parent, replacement of children, or alike. Something of this kind maybe:

class PaneNode {
    bool isParent;
    union {
        LeafPane asLeaf;
        ParentPane asParent;
    } pane;
    
public:
    LeafPane* AsLeaf() const
    {
        return isParent ? nullptr : &pane.asLeaf;
    }
    
    ParentPane* AsParent() const
    {
        return isParent ? &pane.asParent : nullptr;
    }
}

Dunno how much, if at all, would this actually help though, as this is some vague thought I remember having, and that could be not compatible with WinRT types. I mean, I'm sure this could be achieved on the abi level but I'm more afraid of the ('safe') c++ metaprograming layer.

@zadjii-msft zadjii-msft self-assigned this Feb 4, 2021
@Don-Vito Don-Vito mentioned this pull request Feb 4, 2021
6 tasks
@@ -0,0 +1,12 @@
{
Copy link
Member

Choose a reason for hiding this comment

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

this branch seems to have gotten confused as to who is the merge base and who is the merge target...

Copy link
Member

@DHowett DHowett Apr 7, 2021

Choose a reason for hiding this comment

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

nevermind, i wsa commenting on a merge commit.

@github-actions
Copy link

github-actions bot commented Jun 7, 2021

@check-spelling-bot Report

Unrecognized words, please review:

  • Unsubscribe
  • Unzoom
Previously acknowledged words that are now absent hpcon serializers Tlg
To accept these unrecognized words as correct (and remove the previously acknowledged and now absent words), run the following commands

... in a clone of the git@github.com:microsoft/terminal.git repository
on the dev/pabhoj/pane_refactor branch:

update_files() {
perl -e '
my @expect_files=qw('".github/actions/spelling/expect/alphabet.txt
.github/actions/spelling/expect/expect.txt
.github/actions/spelling/expect/web.txt"');
@ARGV=@expect_files;
my @stale=qw('"$patch_remove"');
my $re=join "|", @stale;
my $suffix=".".time();
my $previous="";
sub maybe_unlink { unlink($_[0]) if $_[0]; }
while (<>) {
if ($ARGV ne $old_argv) { maybe_unlink($previous); $previous="$ARGV$suffix"; rename($ARGV, $previous); open(ARGV_OUT, ">$ARGV"); select(ARGV_OUT); $old_argv = $ARGV; }
next if /^(?:$re)(?:(?:\r|\n)*$| .*)/; print;
}; maybe_unlink($previous);'
perl -e '
my $new_expect_file=".github/actions/spelling/expect/d7f2a39aeb0016bcacaa7ccf1b880d7adedcea46.txt";
use File::Path qw(make_path);
use File::Basename qw(dirname);
make_path (dirname($new_expect_file));
open FILE, q{<}, $new_expect_file; chomp(my @words = <FILE>); close FILE;
my @add=qw('"$patch_add"');
my %items; @items{@words} = @words x (1); @items{@add} = @add x (1);
@words = sort {lc($a)."-".$a cmp lc($b)."-".$b} keys %items;
open FILE, q{>}, $new_expect_file; for my $word (@words) { print FILE "$word\n" if $word =~ /\w/; };
close FILE;
system("git", "add", $new_expect_file);
'
}

comment_json=$(mktemp)
curl -L -s -S \
  --header "Content-Type: application/json" \
  "https://api.github.com/repos/microsoft/terminal/issues/comments/856049709" > "$comment_json"
comment_body=$(mktemp)
jq -r .body < "$comment_json" > $comment_body
rm $comment_json

patch_remove=$(perl -ne 'next unless s{^</summary>(.*)</details>$}{$1}; print' < "$comment_body")
  

patch_add=$(perl -e '$/=undef;
$_=<>;
s{<details>.*}{}s;
s{^#.*}{};
s{\n##.*}{};
s{(?:^|\n)\s*\*}{}g;
s{\s+}{ }g;
print' < "$comment_body")
  
update_files
rm $comment_body
git add -u
✏️ Contributor please read this

By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.

⚠️ The command is written for posix shells. You can copy the contents of each perl command excluding the outer ' marks and dropping any '"/"' quotation mark pairs into a file and then run perl file.pl from the root of the repository to run the code. Alternatively, you can manually insert the items...

If the listed items are:

  • ... misspelled, then please correct them instead of using the command.
  • ... names, please add them to .github/actions/spelling/allow/names.txt.
  • ... APIs, you can add them to a file in .github/actions/spelling/allow/.
  • ... just things you're using, please add them to an appropriate file in .github/actions/spelling/expect/.
  • ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in .github/actions/spelling/patterns/.

See the README.md in each directory for more information.

🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉

🗜️ If you see a bunch of garbage

If it relates to a ...

well-formed pattern

See if there's a pattern that would match it.

If not, try writing one and adding it to a patterns/{file}.txt.

Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

Note that patterns can't match multiline strings.

binary-ish string

Please add a file path to the excludes.txt file instead of just accepting the garbage.

File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

@PankajBhojwani
Copy link
Contributor Author

@Rosefield given your recent work on panes, we wanted your opinion! Do you think there's any merit in splitting panes into 2 distinct types (ParentPane and LeafPane) like in this PR?

@Rosefield
Copy link
Contributor

Rosefield commented Sep 14, 2021

Ideologically I would want to have a separation between "parent" type members and "leaf" type members. However, with #11153 there is a lot of logic that is shared (or with minor changes) between the two kinds so there might be a benefit to having a shared implementation that branches on whether it is a leaf or parent still. That definitely is something to get a feel for while trying to do the refactor though.

I don't know how well it would translate to winrt, but if I was writing something like this in rust I would go with a model like this:

struct LeafState {
  _id: u64,
  _control : Control,
  _profile : Profile,
  ...
}

struct ParentState {
    _firstChild: Box<Pane>, // If you're unfamiliar with rust, a Box is a pointer to a heap allocated object
    _secondChild: Box<Pane>,
    _splitPosition: f32,
    ...
}

enum PaneType {
    Leaf(LeafState),
    Parent(ParentState)
}

struct Pane {
    _isActive : bool,
    _root : Grid,
    _border: Border, // or _firstBorder / _secondBorder with #11153
    _zoomed: bool,
    ... // All of the other shared members
    _type: PaneType // And then have a discriminated union of the type-specific variables
}

impl Pane {
   fn split(...) {...}
   fn focus(...) {...}
   fn resize(...) {...}
   ...
   fn as_leaf(&self) -> Option<&LeafState> {...}
   fn as_parent(&self) -> Option<&ParentState> {...}
   // Functions that work on leaves or parents specifically as needed.
   // The expectation is that you would call as_* and then use that state as a token
   // to call these functions. If the states have private constructors you couldn't
   // get an object of this type unless you called the as_* function.
   // e.g. (if you couldn't just do whatever on the LeafState directly)
   fn do_foo_on_leaf(&self, state: &LeafState) { ... }
}

zadjii-msft added a commit that referenced this pull request Oct 25, 2021
  Fixes #11606

  This is weird, but the infobars would appear totally on top of the
  TerminalPage when `showTabsInTitlebar:false`. This would result in the infobar
  obscuring the tabs.

  Now, the infobars are strictly inserted after the tabs, before the content. So
  when they appear, they will reduce the amount of space usable for the control.
  That is a little annoying, but preferable to the tabs totally not existing.

  Relevant conversation notes from #10798:

  > > If the info bar is not local to the tab, then its location between the tab
  > > bar (when the title bar is hidden) and the terminal panes feels
  > > misleading. Should it instead be above the tab bar or below the terminal
  > > panes?
  >
  > You're... not wrong here. It's maybe not the best place for it, but _on top_
  > of the tabs would look insane, and probably wouldn't even work easily, given
  > the way we reparent the tab row into the titlebar.
  >
  > In the pane itself would make more sense, but that runs abreast of all sorts
  > of things like #9024, #4998, which might make more sense.

  I'm just gonna go with this now, because it's _better_ than before, while we
  work out what's _best_.
ghost pushed a commit that referenced this pull request Oct 26, 2021
…of (#11609)

Fixes #11606

This is weird, but the infobars would appear totally on top of the
TerminalPage when `showTabsInTitlebar:false`. This would result in the infobar
obscuring the tabs.

Now, the infobars are strictly inserted after the tabs, before the content. So
when they appear, they will reduce the amount of space usable for the control.
That is a little annoying, but preferable to the tabs totally not existing.

Relevant conversation notes from #10798:

> > If the info bar is not local to the tab, then its location between the tab
> > bar (when the title bar is hidden) and the terminal panes feels
> > misleading. Should it instead be above the tab bar or below the terminal
> > panes?
>
> You're... not wrong here. It's maybe not the best place for it, but _on top_
> of the tabs would look insane, and probably wouldn't even work easily, given
> the way we reparent the tab row into the titlebar.
>
> In the pane itself would make more sense, but that runs abreast of all sorts
> of things like #9024, #4998, which might make more sense.

I'm just gonna go with this now, because it's _better_ than before, while we
work out what's _best_.

![gh-11606-fix](https://user-images.githubusercontent.com/18356694/138729178-b96b7003-0dd2-4521-8fff-0fd2a5989f22.gif)
DHowett pushed a commit that referenced this pull request Dec 13, 2021
…of (#11609)

Fixes #11606

This is weird, but the infobars would appear totally on top of the
TerminalPage when `showTabsInTitlebar:false`. This would result in the infobar
obscuring the tabs.

Now, the infobars are strictly inserted after the tabs, before the content. So
when they appear, they will reduce the amount of space usable for the control.
That is a little annoying, but preferable to the tabs totally not existing.

Relevant conversation notes from #10798:

> > If the info bar is not local to the tab, then its location between the tab
> > bar (when the title bar is hidden) and the terminal panes feels
> > misleading. Should it instead be above the tab bar or below the terminal
> > panes?
>
> You're... not wrong here. It's maybe not the best place for it, but _on top_
> of the tabs would look insane, and probably wouldn't even work easily, given
> the way we reparent the tab row into the titlebar.
>
> In the pane itself would make more sense, but that runs abreast of all sorts
> of things like #9024, #4998, which might make more sense.

I'm just gonna go with this now, because it's _better_ than before, while we
work out what's _best_.

![gh-11606-fix](https://user-images.githubusercontent.com/18356694/138729178-b96b7003-0dd2-4521-8fff-0fd2a5989f22.gif)

(cherry picked from commit a916a5d)
DHowett pushed a commit that referenced this pull request Dec 13, 2021
…of (#11609)

Fixes #11606

This is weird, but the infobars would appear totally on top of the
TerminalPage when `showTabsInTitlebar:false`. This would result in the infobar
obscuring the tabs.

Now, the infobars are strictly inserted after the tabs, before the content. So
when they appear, they will reduce the amount of space usable for the control.
That is a little annoying, but preferable to the tabs totally not existing.

Relevant conversation notes from #10798:

> > If the info bar is not local to the tab, then its location between the tab
> > bar (when the title bar is hidden) and the terminal panes feels
> > misleading. Should it instead be above the tab bar or below the terminal
> > panes?
>
> You're... not wrong here. It's maybe not the best place for it, but _on top_
> of the tabs would look insane, and probably wouldn't even work easily, given
> the way we reparent the tab row into the titlebar.
>
> In the pane itself would make more sense, but that runs abreast of all sorts
> of things like #9024, #4998, which might make more sense.

I'm just gonna go with this now, because it's _better_ than before, while we
work out what's _best_.

![gh-11606-fix](https://user-images.githubusercontent.com/18356694/138729178-b96b7003-0dd2-4521-8fff-0fd2a5989f22.gif)

(cherry picked from commit a916a5d)
@DHowett
Copy link
Member

DHowett commented Jul 20, 2023

This probably isn't gonna land. @PankajBhojwani, can I delete this branch or is there valuable work on it still?

@DHowett DHowett closed this Jul 20, 2023
@PankajBhojwani
Copy link
Contributor Author

Should be good to delete!

@DHowett DHowett deleted the dev/pabhoj/pane_refactor branch July 20, 2023 22:46
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.

6 participants