The Wayback Machine - https://web.archive.org/web/20200915122403/https://github.com/LeetCode-OpenSource/vscode-leetcode/pull/270
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

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

Merged
merged 9 commits into from Apr 16, 2019

Conversation

@Vigilans
Copy link
Contributor

Vigilans commented Apr 14, 2019

  • A webview base class
  • webview listener for #260
@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 } {

This comment has been minimized.

@jdneo

jdneo Apr 14, 2019

Member

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

This comment has been minimized.

@Vigilans

Vigilans Apr 14, 2019

Author Contributor

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);
}

This comment has been minimized.

@jdneo

jdneo Apr 15, 2019

Member

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

I do not see any benefits to do this.

This comment has been minimized.

@Vigilans

Vigilans Apr 15, 2019

Author Contributor

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);

This comment has been minimized.

@jdneo

jdneo Apr 15, 2019

Member

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();

This comment has been minimized.

@Vigilans

Vigilans Apr 16, 2019

Author Contributor

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

This comment has been minimized.

@Vigilans

Vigilans Apr 16, 2019

Author Contributor

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?

This comment has been minimized.

@Vigilans

Vigilans Apr 16, 2019

Author Contributor

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.

This comment has been minimized.

@jdneo

jdneo Apr 16, 2019

Member

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

This comment has been minimized.

@jdneo

jdneo Apr 16, 2019

Member

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.

src/webview/leetCodePreviewProvider.ts Outdated Show resolved Hide resolved
src/webview/leetCodeSolutionProvider.ts Outdated Show resolved Hide resolved
src/webview/LeetCodeWebview.ts Outdated Show resolved Hide resolved
@Vigilans Vigilans force-pushed the vigilans/webview-base branch from 7f1f732 to 9f0999e Apr 14, 2019
src/webview/LeetCodeWebview.ts Outdated Show resolved Hide resolved
localResourceRoots: markdownEngine.localResourceRoots,
});
this.panel.onDidDispose(this.onDidDisposeWebview, this, this.context.subscriptions);
this.panel.webview.onDidReceiveMessage(this.onDidReceiveMessage, this, this.context.subscriptions);

This comment has been minimized.

@jdneo

jdneo Apr 15, 2019

Member

nit: The onDidReceiveMessage can also be disposed in onDidDisposeWebview

Put it into subscriptions is fine though.

This comment has been minimized.

@Vigilans

Vigilans Apr 15, 2019

Author Contributor

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

This comment has been minimized.

@jdneo

jdneo Apr 15, 2019

Member

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.

This comment has been minimized.

@Vigilans

Vigilans Apr 15, 2019

Author Contributor

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.

This comment has been minimized.

@jdneo

jdneo Apr 16, 2019

Member

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

}
}

protected showWebviewInternal(): this is { panel: WebviewPanel } {

This comment has been minimized.

@jdneo

jdneo Apr 15, 2019

Member

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

Vigilans commented Apr 16, 2019

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

Vigilans commented Apr 16, 2019

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.

@jdneo
jdneo approved these changes Apr 16, 2019
Copy link
Member

jdneo left a comment

Thank you for the GIFs. Much more clear now.

@jdneo jdneo merged commit 781feb2 into master Apr 16, 2019
3 checks passed
3 checks passed
LGTM analysis: JavaScript No new or fixed alerts
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details
@Vigilans Vigilans deleted the vigilans/webview-base branch Apr 16, 2019
@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
2 participants
You can’t perform that action at this time.