Skip to content

Extract leetcode webview base class & add md settings listener #270

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 9 commits into from
Apr 16, 2019

Conversation

Vigilans
Copy link
Contributor

@Vigilans Vigilans changed the title Extract leetcode webview base class & add md setings listener Extract leetcode webview base class & add md settings listener Apr 14, 2019
}
}

protected showWebviewInternal(): this is { panel: WebviewPanel } {
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain more about this method? The return type is this, but the actual returned value is true

Copy link
Contributor Author

Choose a reason for hiding this comment

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

param is type is a user-defined type guard in typescript's grammar.

It reduced the scope of union type:

function isTypeDefined(obj: Type | undefined): obj is Type {
    return obj !== undefined;
}

let a: Type | undefined;
a.method() // ts error, a may be undefined

if (isTypeDefined(a)) {
    a.method(); // now a's type is only `Type`, `undefined` is reduced
}

this is type is a way to guard a class member's type:
microsoft/TypeScript#26212

this is { panel: WebviewPanel } makes sure this.panel is not undefined.

So the code here do not need to use this.panel!.method() to assert defined:

if (this.showWebviewInternal()) {
    this.panel.title = `${node.name}: Preview`; // now this.panel's undefined type is reduced
    this.panel.reveal(ViewColumn.One);
}

Copy link
Member

Choose a reason for hiding this comment

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

Then why we are not just calling showWebviewInternal() but put it in the if block.

I do not see any benefits to do this.

Copy link
Contributor Author

@Vigilans Vigilans Apr 15, 2019

Choose a reason for hiding this comment

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

You mean the code below?

this.showWebviewInternal();
this.panel!.title = `${node.name}: Preview`; // this.panel's undefined type is not reduced
this.panel!.reveal(ViewColumn.One);

Copy link
Member

Choose a reason for hiding this comment

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

The main problem here is, we should extract the fields in ILeetCodeWebviewOption as the member of the base class. The reason for doing that:

  1. Each web view has its own unique viewType
  2. Each web view has its own location to display - the viewColumn
  3. Each web view has the member title to determine the title of the editor.

So after the extraction, what you need to do is:

  1. Move all the logic about the panel update into showWebviewInternal()
  2. Update the title field when needed.
this.title = xxxx
this.showWebviewInternal();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've brought everything except sideMode in next PR to this PR. It includes the improvement on the webview base class, like mentioned above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you really think there is no relationship? Did you ever test yourself what is the visual effect when the title keeps A so long long long long long name: preview and A so long long long long long name: solution in Column 2? Will the user be able to easily change between the tabs?

Why do you pay more attention to something in the next PR which I haven't given illustration yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just want leetcode tabs in column 2 look like this way:
image

Otherwise, in my small-screen PC, a So long long long a name: Preview just occupies all the room in the Column 2.

Copy link
Member

Choose a reason for hiding this comment

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

Of cause I need to understand what you will do in the next PR since they have some relationship. This will determine whether we need to keep getWebviewOption() or make them as the class member.

The codes written in a good way should not only have good experience but also good at self-explain. This is very important to attract more community contribution. That's why I'm keeping asking you those questions. From the code itself, I cannot get your point. There's no GIF/picture to illustrate that. Then how could I know your point is that the tab is so long that make the experience bad?

Besides, From my understanding, the reason to rename to the title to Description is that you hope the size of the tab is not too big when VS Code has two columns. The real reason actually is having limited resolution, and multiple columns is one of the possible reason to cause the limited resolution.

Take the VS Code embedded Markdown extension as an example, You can see there is no optimization when the tab is too long.
image

Copy link
Member

Choose a reason for hiding this comment

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

I'm not saying that we should not do the optimation. It's acceptable to do it as long as the code logic is easy to understand.

@Vigilans Vigilans force-pushed the vigilans/webview-base branch from 7f1f732 to 9f0999e Compare April 14, 2019 15:58
localResourceRoots: markdownEngine.localResourceRoots,
});
this.panel.onDidDispose(this.onDidDisposeWebview, this, this.context.subscriptions);
this.panel.webview.onDidReceiveMessage(this.onDidReceiveMessage, this, this.context.subscriptions);
Copy link
Member

@jdneo jdneo Apr 15, 2019

Choose a reason for hiding this comment

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

nit: The onDidReceiveMessage can also be disposed in onDidDisposeWebview

Put it into subscriptions is fine though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

another alternative is to pass this.context.subscriptions to workspace.onDidChangeConfiguration, and do not maintain configListener in LeetCodeWebview?

Copy link
Member

Choose a reason for hiding this comment

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

Just my personal opinion: putting into subscriptions is a passive way to clean up the memory:

An array to which disposables can be added. When this extension is deactivated the disposables will be disposed.

It's more suitable for the command, global objects, etc. Since once the command is registered, in most cases you will not remove it during the extension is running.

While here, once the panel is disposed. We need to dispose the listener as well to avoid that multiple listeners are working in the meantime. So disposing them in the onDidDisposeWebview() could be better.

Copy link
Contributor Author

@Vigilans Vigilans Apr 15, 2019

Choose a reason for hiding this comment

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

This way?

private listeners: Disposable[] = [];

//...

this.panel.onDidDispose(this.onDidDisposeWebview, this, this.listeners);
this.panel.webview.onDidReceiveMessage(this.onDidReceiveMessage, this, this.listeners);
workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.listeners);

//...

protected onDidDisposeWebview(): void {
    this.panel = undefined;
    for (const listener of this.listeners) {
        listener.dispose();
    }
    this.listeners = [];
}

In this way, this.context will report never used by tslint. We could make such modification:

public initialize(context: ExtensionContext): void {
    this.context = context;
    this.context.subscriptions.push(this);
}

It separates the intialization code in activate function. Or, we could just move this.context out of webview.

Copy link
Member

Choose a reason for hiding this comment

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

just move this.context out of webview looks good to me.

}
}

protected showWebviewInternal(): this is { panel: WebviewPanel } {
Copy link
Member

Choose a reason for hiding this comment

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

Then why we are not just calling showWebviewInternal() but put it in the if block.

I do not see any benefits to do this.

@Vigilans
Copy link
Contributor Author

illustration about side mode:

Walkthrough:
WalkThrough

ShowProblem command also benefits from it:
ShowProblem

Solution weview always follows the state of preview:
Preview   Solution

What if the title doesn't change (this is on a wide-screen computer):
WhatIf

@Vigilans
Copy link
Contributor Author

My argument for using getWebviewOption() is that it is in parallel with getWebviewContent():

  1. They all provide the function of dynamic updating.
    Now that viewColumn and title's need to be updated dynamiclly is recognized, we can view getWebviewOption() and getWebviewContent() as two decoupled procedures of updating a webview.
    show() is only a stub receiving input parameters, followed with showWebviewInternal().

  2. .title, .viewColumn & .webivew.html should be three equal-level buiding-blocks of a webview.
    If we keep title as a member of base class, then the same applies for .webview.html.

  3. As a class member, .title, .viewColumn & .webivew.html has already been saved in this.panel, we don't need to keep another copy of them.

Copy link
Member

@jdneo jdneo left a comment

Choose a reason for hiding this comment

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

Thank you for the GIFs. Much more clear now.

@jdneo jdneo merged commit 781feb2 into master Apr 16, 2019
@Vigilans Vigilans deleted the vigilans/webview-base branch April 16, 2019 11:54
@jdneo jdneo added this to the 0.13.4 milestone Apr 17, 2019
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