Search code examples
visual-studio-codevscode-extensions

how to open a webview to the side in vscode extension?


I am trying to open a webview to the side (a new tab in a new group) of the current editor like this markdown extension does, however it opens in the same group of tabs.

Basically I need that the user see the current editor and the webview at same time.

I've tried many combinations of viewColumn and preserveFocus but didn't work:


 vscode.window.createWebviewPanel(
  'foo',
  `foooooo`,
 {
   viewColumn: ViewColumn.two,
   preserveFocus: true
 },
  {
    enableScripts: true,
  },
);


Solution

  • A flexible solution requires a combination of editor group creation and the view column option. In my app I have a webview provider that contains this:

        protected createPanel(placement?: string): Promise<boolean> {
            return new Promise((resolve) => {
                void this.prepareEditorGroup(placement).then((viewColumn) => {
                    this.panel = window.createWebviewPanel(
                        "my-webview",
                        this.#caption,
                        { viewColumn, preserveFocus: true },
                        {
                            enableScripts: true,
                            retainContextWhenHidden: true,
                        });
    
                    this.panel.onDidDispose(() => { this.handleDispose(); });
                    this.panel.iconPath = {
                        dark: Uri.file(path.join(__dirname, "..", "images", "dark", "mysql.svg")),
                        light: Uri.file(path.join(__dirname, "..", "images", "light", "mysql.svg")),
                    };
    
                    this.panel.webview.onDidReceiveMessage((message: IEmbeddedMessage) => {
                        if (message.source === "app") {
                            this.requisitions?.handleRemoteMessage(message);
                        }
                    });
    
                    if (this.onStateChange) {
                        this.panel.onDidChangeViewState((event) => {
                            this.onStateChange?.(this, event.webviewPanel.active);
                        });
                    }
    
                    // A method which generates the standard content of my webviews.
                    prepareWebviewContent(this.panel, this.url);
                });
    
            });
        }
    
        private prepareEditorGroup = async (placement?: string): Promise<ViewColumn> => {
            let viewColumn = (!placement || placement === "Active") ? ViewColumn.Active : ViewColumn.Beside;
            if (placement === "Beside Bottom") {
                viewColumn = ViewColumn.Active;
                await commands.executeCommand("workbench.action.editorLayoutTwoRows");
                await commands.executeCommand("workbench.action.focusSecondEditorGroup");
            }
    
            return viewColumn;
        };
    

    The parameter placement is a string I store as an extension setting. It can be one of these values: Active, Beside Right, Beside Bottom.

    To open a new editor (group) to the bottom, you have to adjust the editor layout first, which is what the two command executions do. Otherwise use ViewColumn.Beside for opening a new editor to the right.