diff --git a/src/extension.ts b/src/extension.ts index 0d034e6..6cd2a82 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,37 +1,67 @@ import * as vscode from 'vscode'; import {createPanel} from './panel'; import { Parser } from './parser'; +import { Tree } from './types/tree'; + +let tree: Parser | undefined = undefined; +let panel: vscode.WebviewPanel | undefined = undefined + // This method is called when your extension is activated // Your extension is activated the very first time the command is executed - function activate(context: vscode.ExtensionContext) { - let disposable = vscode.commands.registerCommand('react-labyrinth.helloWorld', function () { - vscode.window.showInformationMessage('Hello World from React Labyrinth!'); - }); + // This is the column where Webview will be revealed to + const columnToShowIn : vscode.ViewColumn | undefined = vscode.window.activeTextEditor + ? vscode.window.activeTextEditor.viewColumn + : undefined; + + + // Command that allows for User to select the root file of their React application. + const pickFile: vscode.Disposable = vscode.commands.registerCommand('myExtension.pickFile', async () => { + - // pass in the command we want to register (refer to package.json) - // let result = vscode.commands.registerCommand('myExtension.showPanel', () => { - // // call helper func - // createPanel(context); - // }); + // Check if there is an existing webview panel, if so display it. + if(panel) { + panel.reveal(columnToShowIn) + } - vscode.commands.registerCommand('myExtension.pickFile', async () => { - const fileArray = await vscode.window.showOpenDialog({ canSelectFolders: false, canSelectFiles: true, canSelectMany: false }); + + // Opens window for the User to select the root file of React application + const fileArray: vscode.Uri[] = await vscode.window.showOpenDialog({ canSelectFolders: false, canSelectFiles: true, canSelectMany: false }); + + // Throw error message if no file was selected if (!fileArray || fileArray.length === 0) { vscode.window.showErrorMessage('No file selected'); return; } - - const tree = new Parser(fileArray[0].path); + + + // Create Tree to be inserted into returned HTML + tree = new Parser(fileArray[0].path); tree.parse(); - const data = tree.getTree(); - console.log('Data sent back: \n', data); - createPanel(context, data); + const data: Tree = tree.getTree(); + + + // Check if panel currently has a webview, if it does dispose of it and create another with updated root file selected. + // Otherwise create a new webview to display root file selected. + if(!panel) { + panel = createPanel(context, data, columnToShowIn); + } else { + panel.dispose() + panel = createPanel(context, data, columnToShowIn); + } }); - context.subscriptions.push(disposable); + + + // Command to show panel if it is hidden + const showPanel: vscode.Disposable = vscode.commands.registerCommand('myExtension.showPanel', () => { + panel.reveal(columnToShowIn) + }); + + + context.subscriptions.push(pickFile, showPanel); } // This method is called when your extension is deactivated diff --git a/src/panel.ts b/src/panel.ts index 606db1e..f06678a 100644 --- a/src/panel.ts +++ b/src/panel.ts @@ -2,13 +2,15 @@ import * as vscode from 'vscode'; import { getNonce } from './getNonce'; import { Tree } from './types/tree'; -export function createPanel(context: vscode.ExtensionContext, data: Tree) { - // if the current panel exists, then reveal the column, else make one? +let panel: vscode.WebviewPanel | undefined = undefined + +export function createPanel(context: vscode.ExtensionContext, data: Tree, columnToShowIn: vscode.ViewColumn) { // utilize method on vscode.window object to create webview - const panel = vscode.window.createWebviewPanel( + panel = vscode.window.createWebviewPanel( 'reactLabyrinth', 'React Labyrinth', + // create one new tab vscode.ViewColumn.One, { @@ -16,26 +18,42 @@ export function createPanel(context: vscode.ExtensionContext, data: Tree) { retainContextWhenHidden: true } ); + + // Set the icon logo of extension webview panel.iconPath = vscode.Uri.joinPath(context.extensionUri, 'media', 'favicon.ico'); + + + // Set URI to be the path to bundle + const bundlePath: vscode.Uri = vscode.Uri.joinPath(context.extensionUri, 'build', 'bundle.js'); - const bundlePath = vscode.Uri.joinPath(context.extensionUri, 'build', 'bundle.js'); // set webview URI to pass into html script - const bundleURI = panel.webview.asWebviewUri(bundlePath); + const bundleURI: vscode.Uri = panel.webview.asWebviewUri(bundlePath); + // render html of webview here panel.webview.html = createWebviewHTML(bundleURI, data); - // will need to use onDidDispose to clear cached data and reset tree when the webview and/or application is closed + // Listens for when webview is closed and disposes of webview resources + panel.onDidDispose( + () => { + panel = undefined; + }, + null, + context.subscriptions + ); + + + // Sends data to Flow.tsx to be displayed after parsed data is received panel.webview.onDidReceiveMessage( async (msg: any) => { switch (msg.type) { case 'onData': if (!msg.value) break; context.workspaceState.update('reactLabyrinth', msg.value); - // console.log('msg.value from panel.js: ', msg.value); + panel.webview.postMessage( { type: 'parsed-data', @@ -49,13 +67,18 @@ export function createPanel(context: vscode.ExtensionContext, data: Tree) { undefined, context.subscriptions ); + + return panel }; + + // getNonce generates a new random string each time ext is used to prevent external injection of foreign code into the html -const nonce = getNonce(); +const nonce: string = getNonce(); + // function to create the HTML page for webview -function createWebviewHTML(URI: vscode.Uri, initialData: Tree) { +function createWebviewHTML(URI: vscode.Uri, initialData: Tree) : string { return ( `