'use strict' const vscode = require('vscode') const tools = require('./tools.js') const pcsxRedux = require('./pcsx-redux.js') const templates = require('./templates.js') const os = require('node:os') const taskRunner = require('./taskrunner.js') const util = require('node:util') const openExplorer = util.promisify(require('open-file-explorer')) const terminal = require('./terminal.js') let globalStorageUri class PSXDevPanel { static currentPanel = undefined static createOrShow (extensionUri) { const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined // If we already have a panel, show it. if (PSXDevPanel.currentPanel) { PSXDevPanel.currentPanel._panel.reveal(column) return } // Otherwise, create a new panel. const panel = vscode.window.createWebviewPanel( PSXDevPanel.viewType, 'PSX.Dev', column || vscode.ViewColumn.One, getWebviewOptions(extensionUri) ) PSXDevPanel.currentPanel = new PSXDevPanel(panel, extensionUri) } static revive (panel, extensionUri) { PSXDevPanel.currentPanel = new PSXDevPanel(panel, extensionUri) } constructor (panel, extensionUri) { this._disposables = [] this._panel = panel this._extensionUri = extensionUri // Set the webview's initial html content this._update() // Listen for when the panel is disposed // This happens when the user closes the panel or when the panel is closed programmatically this._panel.onDidDispose(() => this.dispose(), null, this._disposables) // Update the content based on view changes this._panel.onDidChangeViewState( () => { if (this._panel.visible) { this._update() } }, null, this._disposables ) // Handle messages from the webview this._panel.webview.onDidReceiveMessage( (message) => { switch (message.command) { case 'alert': vscode.window.showErrorMessage(message.text) break case 'getTemplates': this._panel.webview.postMessage({ command: 'templates', templates: templates.list, categories: templates.categories }) break case 'refreshTools': tools.refreshAll().then((tools) => { this._panel.webview.postMessage({ command: 'tools', tools }) }) break case 'openUrl': vscode.env.openExternal(vscode.Uri.parse(message.url)) break case 'installTools': tools .install(message.tools, message.force) .then((requiresReboot) => { if (requiresReboot) { this._panel.webview.postMessage({ command: 'requireReboot' }) vscode.window.showInformationMessage( 'Some tools require a reboot to work properly. Please reboot your system before resuming installing more tools.' ) } else { return tools.refreshAll() } }) .then((tools) => { this._panel.webview.postMessage({ command: 'tools', tools }) }) .catch((err) => { this._panel.webview.postMessage({ command: 'tools', tools: tools.list }) vscode.window.showErrorMessage(err.message) }) break case 'launchRedux': launchRedux() break case 'restorePsyq': restorePsyq() break case 'restorePythonEnv': restorePythonEnv() break case 'updateModules': updateModules() break case 'requestHomeDirectory': this._panel.webview.postMessage({ command: 'projectDirectory', path: os.homedir() }) break case 'browseForProjectDirectory': vscode.window .showOpenDialog({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, openLabel: 'Select', title: "Select project's parent directory" }) .then((result) => { if (result) { this._panel.webview.postMessage({ command: 'projectDirectory', path: result[0].fsPath }) } }) break case 'createProjectFromTemplate': templates .createProjectFromTemplate(tools.list, message) .then((fullPath) => { vscode.commands.executeCommand( 'vscode.openFolder', vscode.Uri.file(fullPath) ) }) .catch((err) => { vscode.window.showErrorMessage(err.message) }) break case 'showReduxSettings': showReduxSettings() break } }, null, this._disposables ) } dispose () { PSXDevPanel.currentPanel = undefined // Clean up our resources this._panel.dispose() while (this._disposables.length) { const x = this._disposables.pop() if (x) { x.dispose() } } } _update () { const webview = this._panel.webview webview.html = this._getHtmlForWebview(webview) } _getHtmlForWebview (webview) { const scriptPathOnDisk = vscode.Uri.joinPath( this._extensionUri, 'media', 'main.js' ) const scriptUri = webview.asWebviewUri(scriptPathOnDisk) const nonce = getNonce() return ` PSX.Dev Refresh WELCOME TEMPLATES TOOLS

Welcome to the PSX.Dev VSCode extension

Using this extension, you can install and maintain the necessary tools to develop PS1 software, and create projects based on templates. Click on the tabs above to get started.

You can always use the commands in the Command Palette (Ctrl+Shift+P) to access this panel again. Search for the PSX.Dev: Show Panel command.

You can access more information about PlayStation 1 development on the PSX.Dev website. Please do not hesitate to join the Discord server!

The TEMPLATE panel will let you create a new project based on some provided templates. Each template has a set of required and recommended tools. The required tools are going to be necessary to create and build a project, while the recommended tools will be necessary to launch and debug it.

The TOOLS panel will have the ability to install the tools on the most popular platforms, but there's definitely corner cases when it won't work. When manual installation is required, either look at the homepage provided for each tool, or check the installation instructions provided in the documentation. Additionally, the panel can leverage Linuxbrew to install dependencies on an unsupported Linux platform.

And finally, the Refresh button above will rescan the list of tools installed on your system.


Before debugging a PlayStation 1 application, you'll need to have a target able to run PlayStation 1 code accessible through the gdb protocol. You can connect to a real PlayStation 1, or you can run an emulator with a gdb server. You can click the button below to launch the PCSX-Redux PlayStation 1 emulator in debugger mode.


Open Settings folder Launch PCSX-Redux

After cloning a project that uses Psy-Q libraries or a Python virtual environment, it'll be necessary to restore them. Use the buttons below in order to restore the appropriate dependencies into the current workspace.


Restore Psy-Q Restore Python environment

The templates will create git repositories with submodules. These submodules may update frequently with bug fixes and new features. The updates should not break backward compatibility in general, and should be safe to do. Press the button below to update the submodules in the current workspace.


Update modules

` } } PSXDevPanel.viewType = 'psxDev' exports.activate = (context) => { tools.setExtensionUri(context.extensionUri) tools.setGlobalStorageUri(context.globalStorageUri) templates.setExtensionUri(context.extensionUri) pcsxRedux.setGlobalStorageUri(context.globalStorageUri) globalStorageUri = context.globalStorageUri context.subscriptions.push( vscode.commands.registerCommand('psxDev.showPanel', () => { PSXDevPanel.createOrShow(context.extensionUri) }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.buildDebug', () => { taskRunner.run('Build Debug').catch((err) => { vscode.window.showErrorMessage(err.message) }) }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.buildRelease', () => { taskRunner.run('Build Release').catch((err) => { vscode.window.showErrorMessage(err.message) }) }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.clean', () => { taskRunner.run('Clean').catch((err) => { vscode.window.showErrorMessage(err.message) }) }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.launchRedux', () => { launchRedux() }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.restorePsyq', () => { restorePsyq() }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.restorePythonEnv', () => { restorePythonEnv() }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.updateModules', () => { updateModules() }) ) context.subscriptions.push( vscode.commands.registerCommand('psxDev.showReduxSettings', () => { showReduxSettings() }) ) vscode.window.registerWebviewPanelSerializer(PSXDevPanel.viewType, { async deserializeWebviewPanel (webviewPanel) { webviewPanel.webview.options = getWebviewOptions(context.extensionUri) PSXDevPanel.revive(webviewPanel, context.extensionUri) } }) } function getWebviewOptions (extensionUri) { return { enableScripts: true, localResourceRoots: [ vscode.Uri.joinPath(extensionUri, 'media'), vscode.Uri.joinPath( extensionUri, 'node_modules', '@vscode', 'webview-ui-toolkit', 'dist' ) ] } } function getNonce () { let text = '' const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' for (let i = 0; i < 32; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)) } return text } function launchRedux () { tools .maybeInstall('redux') .then(() => tools.list.redux.launch()) .catch((err) => { vscode.window.showErrorMessage(err.message) }) } function restorePsyq () { if (vscode.workspace.workspaceFolders) { tools .maybeInstall('psyq') .then(() => tools.list.psyq.unpack( vscode.Uri.joinPath( vscode.workspace.workspaceFolders[0].uri, 'third_party', 'psyq' ).fsPath ) ) .catch((err) => { vscode.window.showErrorMessage(err.message) }) } else { vscode.window.showErrorMessage('Please open a project first.') } } function restorePythonEnv () { if (vscode.workspace.workspaceFolders) { templates .createPythonEnv({ path: vscode.workspace.workspaceFolders[0].uri.fsPath, name: 'env', requirementsFiles: [ vscode.Uri.joinPath( vscode.workspace.workspaceFolders[0].uri, 'ps1-bare-metal', 'tools', 'requirements.txt' ).fsPath ] }) .catch((err) => { vscode.window.showErrorMessage(err.message) }) } else { vscode.window.showErrorMessage('Please open a project first.') } } function showReduxSettings () { const pathToOpen = vscode.Uri.joinPath( globalStorageUri, 'pcsx-redux-settings' ).fsPath openExplorer(pathToOpen).catch((err) => { vscode.window.showErrorMessage(err.message) }) } function updateModules () { if (vscode.workspace.workspaceFolders) { tools .maybeInstall('git') .then(() => terminal.run('git', ['submodule', 'update', '--init', '--recursive'], { cwd: vscode.workspace.workspaceFolders[0].uri.fsPath }) ) .catch((err) => { vscode.window.showErrorMessage(err.message) }) } else { vscode.window.showErrorMessage('Please open a project first.') } }