This is an automated email from the ASF dual-hosted git repository.
jw3 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil-vscode.git
The following commit(s) were added to refs/heads/main by this push:
new fb39b93 Create launch.json config wizard:
fb39b93 is described below
commit fb39b93adf405417ddaeaef86ef328341e7d0229
Author: Shane Dell <[email protected]>
AuthorDate: Thu Nov 4 12:41:08 2021 -0400
Create launch.json config wizard:
- Create new command called launch.config
- When command is ran the user will go through a selection process to set
all variables for the launch.json
- Add an icon for running the new command to the toolbar (gear icon)
- Once all items are selected by the user the .vscode/launch.json will be
created
- Created default profile that lives inside of the Settings of VSCode.
- Updated code to use default config options if launch.json does not exist
- Create launch-wizard file that is used for creating a WebView for getting
the settings desired for a launch.json item
- Create launch-wizard.js which is what grabs the settings from the WebView
and sends them to the backend to be written to the file.
Closes #38
---
package.json | 96 +++++++-
src/adapter/activateDaffodilDebug.ts | 83 +++----
src/launchWizard/launchWizard.js | 146 ++++++++++++
src/launchWizard/launchWizard.ts | 435 +++++++++++++++++++++++++++++++++++
src/launchWizard/styles.css | 145 ++++++++++++
src/utils.ts | 57 +++++
6 files changed, 907 insertions(+), 55 deletions(-)
diff --git a/package.json b/package.json
index 1edfc3c..dca9e9a 100644
--- a/package.json
+++ b/package.json
@@ -72,7 +72,8 @@
"onCommand:extension.dfdl-debug.getProgramName",
"onCommand:extension.dfdl-debug.getDataName",
"onCommand:extension.dfdl-debug.runEditorContents",
- "onCommand:extension.dfdl-debug.debugEditorContents"
+ "onCommand:extension.dfdl-debug.debugEditorContents",
+ "onCommand:launch.config"
],
"workspaceTrust": {
"request": "never"
@@ -87,19 +88,23 @@
"menus": {
"editor/title": [
{
+ "command": "launch.config",
+ "group": "navigation@1"
+ },
+ {
"command": "hexview.display",
"when": "resourceLangId == xml",
- "group": "navigation@3"
+ "group": "navigation@4"
},
{
"command": "infoset.display",
"when": "resourceLangId == xml",
- "group": "navigation@1"
+ "group": "navigation@2"
},
{
"command": "infoset.diff",
"when": "resourceLangId == xml",
- "group": "navigation@2"
+ "group": "navigation@3"
}
],
"editor/title/run": [
@@ -176,6 +181,13 @@
"title": "Save the current infoset",
"category": "Daffodil Debug",
"enablement": "inDebugMode"
+ },
+ {
+ "command": "launch.config",
+ "title": "Configure launch.json",
+ "category": "Daffodil Debug",
+ "enablement": "!inDebugMode",
+ "icon": "$(debug-configure)"
}
],
"breakpoints": [
@@ -227,6 +239,11 @@
"description": "Enable logging of the Debug Adapter Protocol.",
"default": true
},
+ "debugServer": {
+ "type": "integer",
+ "description": "Port debug server running on",
+ "default": 4711
+ },
"useExistingServer": {
"type": "boolean",
"description": "Enable connection to running DAP Server",
@@ -295,6 +312,77 @@
"AskForDataName": "extension.dfdl-debug.getDataName"
}
}
+ ],
+ "configuration": [
+ {
+ "title": "Daffodil Debugger Global",
+ "properties": {
+ "type": {
+ "type": "string",
+ "default": "dfdl"
+ },
+ "program": {
+ "type": "string",
+ "description": "Absolute path to the DFDL schema file.",
+ "default": "${command:AskForProgramName}"
+ },
+ "data": {
+ "type": "string",
+ "description": "Absolute path to the input data file.",
+ "default": "${command:AskForDataName}"
+ },
+ "infosetOutputType": {
+ "type": "string",
+ "description": "Destination for final Infoset (file | 'console' |
'none')",
+ "enum": [
+ "file",
+ "console",
+ "none"
+ ],
+ "default": "none"
+ },
+ "infosetOutputFilePath": {
+ "type": "string",
+ "description": "Path to output for Infoset file (req:
infosetOutput=file)",
+ "default": "${workspaceFolder}/infoset.xml"
+ },
+ "stopOnEntry": {
+ "type": "boolean",
+ "description": "Automatically stop after launch.",
+ "default": true
+ },
+ "trace": {
+ "type": "boolean",
+ "description": "Enable logging of the Debug Adapter Protocol.",
+ "default": true
+ },
+ "useExistingServer": {
+ "type": "boolean",
+ "description": "Enable connection to running DAP Server",
+ "default": false
+ },
+ "debugServer": {
+ "type": "integer",
+ "description": "Port debug server running on",
+ "default": 4711
+ },
+ "openHexView": {
+ "type": "boolean",
+ "description": "Open hexview on debug start",
+ "default": false
+ },
+ "openInfosetView": {
+ "type": "boolean",
+ "description": "Open hexview on debug start",
+ "default": false
+ },
+ "openInfosetDiffView": {
+ "type": "boolean",
+ "description": "Open hexview on debug start",
+ "default": false
+ }
+ }
+ }
]
}
}
diff --git a/src/adapter/activateDaffodilDebug.ts
b/src/adapter/activateDaffodilDebug.ts
index ba13144..700a8e9 100644
--- a/src/adapter/activateDaffodilDebug.ts
+++ b/src/adapter/activateDaffodilDebug.ts
@@ -19,6 +19,8 @@ import { getDebugger, getDataFileFromFolder } from
'../daffodilDebugger'
import { FileAccessor } from './daffodilRuntime'
import * as fs from 'fs'
import * as infoset from '../infoset'
+import { getConfig } from '../utils'
+import * as launchWizard from '../launchWizard/launchWizard'
// Function for setting up the commands for Run and Debug file
function createDebugRunFileConfigs(resource: vscode.Uri, runOrDebug: String) {
@@ -32,21 +34,19 @@ function createDebugRunFileConfigs(resource: vscode.Uri,
runOrDebug: String) {
let infosetFile = `${
path.basename(targetResource.fsPath).split('.')[0]
}-infoset.xml`
+ vscode.window.showInformationMessage(infosetFile)
vscode.debug.startDebugging(
undefined,
- {
- type: 'dfdl',
- name: 'Run File',
- request: 'launch',
- program: targetResource.fsPath,
- data: '${command:AskForDataName}',
- debugServer: 4711,
- infosetOutput: {
- type: 'file',
- path: infosetFile,
- },
- },
+ getConfig(
+ 'Run File',
+ 'launch',
+ 'dfdl',
+ targetResource.fsPath,
+ false,
+ false,
+ { type: 'file', path: '${workspaceFolder}/' + infosetFile }
+ ),
{ noDebug: noDebug }
)
@@ -160,18 +160,15 @@ export function activateDaffodilDebug(
): ProviderResult<DebugConfiguration[]> {
if (!vscode.workspace.workspaceFolders) {
return [
- {
- name: 'Daffodil Launch',
- request: 'launch',
- type: 'dfdl',
- program: '${file}',
- data: '${command:AskForDataName}',
- debugServer: 4711,
- infosetOutput: {
- type: 'file',
- path: '${file}-infoset.xml',
- },
- },
+ getConfig(
+ 'Daffodil Launch',
+ 'launch',
+ 'dfdl',
+ '${file}',
+ false,
+ false,
+ { type: 'file', path: '${file}-infoset.xml' }
+ ),
]
}
@@ -183,18 +180,15 @@ export function activateDaffodilDebug(
}-infoset.xml`
return [
- {
- name: 'Daffodil Launch',
- request: 'launch',
- type: 'dfdl',
- program: '${file}',
- data: '${command:AskForDataName}',
- debugServer: 4711,
- infosetOutput: {
- type: 'file',
- path: infosetFile,
- },
- },
+ getConfig(
+ 'Daffodil Launch',
+ 'launch',
+ 'dfdl',
+ '${file}',
+ false,
+ false,
+ { type: 'file', path: '${workspaceFolder}/' + infosetFile }
+ ),
]
},
},
@@ -269,6 +263,7 @@ export function activateDaffodilDebug(
)
infoset.activate(context)
+ launchWizard.activate(context)
}
class DaffodilConfigurationProvider
@@ -291,21 +286,7 @@ class DaffodilConfigurationProvider
): ProviderResult<DebugConfiguration> {
// if launch.json is missing or empty
if (!config.type && !config.request && !config.name) {
- const editor = vscode.window.activeTextEditor
- if (editor && editor.document.languageId === 'xml') {
- config.type = 'dfdl'
- config.name = 'Launch'
- config.request = 'launch'
- config.program = '${file}'
- config.data = '${command:AskForDataName}'
- config.stopOnEntry = true
- config.useExistingServer = false
- config.infosetOutput = {
- type: 'file',
- path: '${file}-infoset.xml',
- }
- config.debugServer = 4711
- }
+ config = getConfig('Launch', 'launch', 'dfdl')
}
if (!config.program) {
diff --git a/src/launchWizard/launchWizard.js b/src/launchWizard/launchWizard.js
new file mode 100644
index 0000000..547a3fd
--- /dev/null
+++ b/src/launchWizard/launchWizard.js
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Retrieve vscode api - Doing this multiple times causes issues with the
scripts
+const vscode = acquireVsCodeApi();
+
+// Function to call extension to open file picker
+function filePicker(id, description) {
+ vscode.postMessage({
+ command: 'openFilePicker', id: id, description: description
+ })
+}
+
+// Function to update select infoset output type
+function updateInfosetOutputType() {
+ var infosetSelectionBox = document.getElementById("infosetOutputType")
+ var infosetSelectedValue =
infosetSelectionBox.options[infosetSelectionBox.selectedIndex].value
+
+ if (infosetSelectedValue === 'file') {
+ document.getElementById("infosetOutputFilePathLabel").style =
"margin-top: 10px; visibility: visible;"
+ } else {
+ document.getElementById("infosetOutputFilePathLabel").style =
"visibility: hidden;"
+ }
+}
+
+// Function to update config selected, also display name input box if 'New
Config' selected
+function updateSelectedConfig() {
+ var configSelectionBox = document.getElementById("configSelected")
+ var configSelectedValue =
configSelectionBox.options[configSelectionBox.selectedIndex].value
+
+ if (configSelectedValue === 'New Config') {
+ document.getElementById("nameLabel").style = "margin-top: 10px;
visibility: visible;"
+ } else {
+ document.getElementById("nameLabel").style = "visibility: hidden;"
+ }
+
+ let configIndex = configSelectedValue === 'New Config' ? -1 :
configSelectionBox.selectedIndex
+
+ vscode.postMessage({
+ command: 'updateConfigValue', configIndex: configIndex
+ })
+}
+
+// Function for checking/unchecking a checkbox element
+function check(elementId) {
+ const element = document.getElementById(elementId)
+ element.checked = element.checked ? false : true
+}
+
+// Function for saving the settings to a launch.json
+function save() {
+ var configSelectionBox = document.getElementById("configSelected")
+ var configSelectedValue =
configSelectionBox.options[configSelectionBox.selectedIndex].value
+ var updateOrCreate = configSelectedValue === 'New Config' ? 'create' :
'update'
+ const name = configSelectedValue === 'New Config' ?
document.getElementById('name').value : configSelectedValue
+ const data = document.getElementById('data').value
+ const debugServer = parseInt(document.getElementById('debugServer').value)
+ const infosetOutputFilePath =
document.getElementById('infosetOutputFilePath').value
+ const infosetOutputType =
document.getElementById('infosetOutputType').value
+ const openHexView = document.getElementById('openHexView').checked
+ const openInfosetDiffView =
document.getElementById('openInfosetDiffView').checked
+ const openInfosetView = document.getElementById('openInfosetView').checked
+ const program = document.getElementById('program').value
+ const stopOnEntry = document.getElementById('stopOnEntry').checked
+ const trace = document.getElementById('trace').checked
+ const useExistingServer =
document.getElementById('useExistingServer').checked
+
+ var obj = {
+ version: '0.2.0',
+ configurations: [
+ {
+ request: 'launch',
+ type: 'dfdl',
+ name: name,
+ program: program,
+ data: data,
+ debugServer: debugServer,
+ infosetOutput: {
+ "type": infosetOutputType,
+ "path": infosetOutputFilePath,
+ },
+ trace: trace,
+ stopOnEntry: stopOnEntry,
+ useExistingServer: useExistingServer,
+ openHexView: openHexView,
+ openInfosetView: openInfosetView,
+ openInfosetDiffView: openInfosetDiffView
+ }
+ ]
+ }
+
+ vscode.postMessage({
+ command: 'saveConfig', data: JSON.stringify(obj, null, 4),
updateOrCreate: updateOrCreate
+ })
+}
+
+// Function to update config values in the webview
+function updateConfigValues(config) {
+ document.getElementById('name').value = config.name
+ document.getElementById('data').value = config.data
+ document.getElementById('debugServer').value = parseInt(config.debugServer)
+ document.getElementById('infosetOutputFilePath').value =
config.infosetOutput['path'] ? config.infosetOutput['path'] :
config.infosetOutputFilePath
+ document.getElementById('infosetOutputType').value =
config.infosetOutput['type'] ? config.infosetOutput['type'] :
config.infosetOutputType
+ document.getElementById('openHexView').checked = config.openHexView
+ document.getElementById('openInfosetDiffView').checked =
config.openInfosetDiffView
+ document.getElementById('openInfosetView').checked = config.openInfosetView
+ document.getElementById('program').value = config.program
+ document.getElementById('stopOnEntry').checked = config.stopOnEntry
+ document.getElementById('trace').checked = config.trace
+ document.getElementById('useExistingServer').checked =
config.useExistingServer
+ updateInfosetOutputType()
+}
+
+// Function that gets called by default to create and update the hex web view
+(function main() {
+ // Listener for getting messages/data from the extension
+ window.addEventListener('message', event => {
+ const message = event.data
+
+ switch (message.command) {
+ case 'updateConfValues':
+ updateConfigValues(message.configValues)
+ break
+ case 'dataUpdate':
+ document.getElementById('data').value = message.value
+ break
+ case 'programUpdate':
+ document.getElementById('program').value = message.value
+ break
+ }
+ })
+} ());
diff --git a/src/launchWizard/launchWizard.ts b/src/launchWizard/launchWizard.ts
new file mode 100644
index 0000000..e81d09f
--- /dev/null
+++ b/src/launchWizard/launchWizard.ts
@@ -0,0 +1,435 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as vscode from 'vscode'
+import * as fs from 'fs'
+import { getConfig } from '../utils'
+
+const defaultConf = getConfig('Wizard Config', 'launch', 'dfdl')
+
+// Function that will activate/open the launch config wizard
+export async function activate(ctx: vscode.ExtensionContext) {
+ ctx.subscriptions.push(
+ vscode.commands.registerCommand('launch.config', async () => {
+ await createWizard(ctx)
+ })
+ )
+}
+
+// Function to get config values
+function getConfigValues(data, configIndex) {
+ return data && configIndex !== -1
+ ? data.configurations[configIndex]
+ : defaultConf
+}
+
+/**
+ * Function used for:
+ * Creating the launch.json with the desired config settings
+ * Updating the launch.json configs to have the desired config settings
+ * Updating an already avaiable config inside of launch.json
+ */
+async function createUpdateConfigFile(data, updateOrCreate) {
+ let rootPath = vscode.workspace.workspaceFolders
+ ? vscode.workspace.workspaceFolders[0].uri.fsPath
+ : vscode.Uri.parse('').fsPath
+
+ if (!fs.existsSync(`${rootPath}/.vscode`)) {
+ fs.mkdirSync(`${rootPath}/.vscode`)
+ }
+
+ // Create launch.json if it doesn't exist already
+ if (!fs.existsSync(`${rootPath}/.vscode/launch.json`)) {
+ fs.writeFileSync(`${rootPath}/.vscode/launch.json`, data)
+ vscode.window.showTextDocument(
+ vscode.Uri.parse(`${rootPath}/.vscode/launch.json`)
+ )
+ return
+ }
+
+ let newConf = JSON.parse(data).configurations[0]
+ let fileData = JSON.parse(
+ fs.readFileSync(`${rootPath}/.vscode/launch.json`).toString()
+ )
+
+ if (updateOrCreate.toLowerCase() === 'create') {
+ let alreadyExists = false
+
+ fileData.configurations.forEach((element) => {
+ if (element.name === newConf.name) {
+ alreadyExists = true
+ }
+ })
+
+ if (alreadyExists) {
+ // Config wanted to create already exists in launch.json
+ vscode.window.showWarningMessage(
+ 'The conf trying to be saved already exists in the launch.json'
+ )
+ return
+ }
+
+ // Add new config to launch.json
+ fileData.configurations.push(newConf)
+ fs.writeFileSync(
+ `${rootPath}/.vscode/launch.json`,
+ JSON.stringify(fileData, null, 4)
+ )
+ } else if (updateOrCreate.toLowerCase() === 'update') {
+ // Update selected config in launch.json
+ let configIndex = -1
+
+ for (var i = 0; i < fileData.configurations.length; i++) {
+ if (fileData.configurations[i].name === newConf.name) {
+ configIndex = i
+ break
+ }
+ }
+
+ // Error handling to make sure a proper config specified
+ if (configIndex !== -1) {
+ fileData.configurations[configIndex] = newConf
+ fs.writeFileSync(
+ `${rootPath}/.vscode/launch.json`,
+ JSON.stringify(fileData, null, 4)
+ )
+ } else {
+ vscode.window.showErrorMessage('Invalid Config Selected!')
+ }
+ }
+
+ vscode.window.showTextDocument(
+ vscode.Uri.parse(`${rootPath}/.vscode/launch.json`)
+ )
+}
+
+// Function to update the config values in the webview panel
+async function updateWebViewConfigValues(configIndex) {
+ let rootPath = vscode.workspace.workspaceFolders
+ ? vscode.workspace.workspaceFolders[0].uri.fsPath
+ : vscode.Uri.parse('').fsPath
+
+ let fileData =
+ configIndex === -1
+ ? null
+ : JSON.parse(
+ fs.readFileSync(`${rootPath}/.vscode/launch.json`).toString()
+ )
+
+ return getConfigValues(fileData, configIndex)
+}
+
+// Function to create file picker for wizard
+async function openFilePicker(description) {
+ let rootPath = vscode.workspace.workspaceFolders
+ ? vscode.workspace.workspaceFolders[0].uri.fsPath
+ : vscode.Uri.parse('').fsPath
+
+ let chosenFile = await vscode.window
+ .showOpenDialog({
+ canSelectMany: false,
+ openLabel: description,
+ canSelectFiles: true,
+ canSelectFolders: false,
+ title: description,
+ })
+ .then((fileUri) => {
+ if (fileUri && fileUri[0]) {
+ return fileUri[0].fsPath
+ }
+
+ return ''
+ })
+
+ if (chosenFile.includes(rootPath)) {
+ chosenFile = '${workspaceFolder}/' + chosenFile.split('/').pop()
+ }
+
+ return chosenFile
+}
+
+// Function that will create webview
+async function createWizard(ctx: vscode.ExtensionContext) {
+ let launchWizard = new LaunchWizard(ctx)
+ let panel = launchWizard.getPanel()
+ panel.webview.html = launchWizard.getWebViewContent()
+
+ panel.webview.onDidReceiveMessage(
+ async (message) => {
+ switch (message.command) {
+ case 'saveConfig':
+ await createUpdateConfigFile(message.data, message.updateOrCreate)
+ panel.dispose()
+ return
+ case 'updateConfigValue':
+ let configValues = await updateWebViewConfigValues(
+ message.configIndex
+ )
+
+ panel.webview.postMessage({
+ command: 'updateConfValues',
+ configValues: configValues,
+ })
+ return
+ case 'openFilePicker':
+ let result = await openFilePicker(message.description)
+ panel.webview.postMessage({
+ command: `${message.id}Update`,
+ value: result,
+ })
+ return
+ }
+ },
+ undefined,
+ ctx.subscriptions
+ )
+}
+
+// Class for creating launch wizard webview
+class LaunchWizard {
+ ctx: vscode.ExtensionContext
+ panel: vscode.WebviewPanel | undefined = undefined
+ extensionUri: vscode.Uri = vscode.Uri.parse('')
+
+ constructor(ctx: vscode.ExtensionContext) {
+ this.ctx = ctx
+
+ if (vscode.workspace.workspaceFolders) {
+ this.extensionUri = vscode.workspace.workspaceFolders[0].uri
+ }
+ }
+
+ // Method to create/get the webview panel
+ getPanel() {
+ if (!this.panel) {
+ this.panel = vscode.window.createWebviewPanel(
+ 'launchWizard',
+ 'Launch Config Wizard',
+ vscode.ViewColumn.Active,
+ this.getWebViewOptions(this.extensionUri)
+ )
+
+ this.panel.onDidDispose(
+ () => {
+ this.panel = undefined
+ },
+ null,
+ this.ctx.subscriptions
+ )
+ }
+
+ return this.panel
+ }
+
+ // Method for creating web view option that allow our custom script to run
+ getWebViewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions {
+ return {
+ enableScripts: true,
+ localResourceRoots: [
+ vscode.Uri.parse(this.ctx.asAbsolutePath('./src/launchWizard')),
+ ],
+ }
+ }
+
+ // Method to set html for the hex view
+ getWebViewContent() {
+ const scriptUri = vscode.Uri.parse(
+ this.ctx.asAbsolutePath('./src/launchWizard/launchWizard.js')
+ ).with({ scheme: 'vscode-resource' })
+ const styleUri = vscode.Uri.parse(
+ this.ctx.asAbsolutePath('./src/launchWizard/styles.css')
+ ).with({ scheme: 'vscode-resource' })
+ const nonce = this.getNonce()
+
+ let rootPath = vscode.workspace.workspaceFolders
+ ? vscode.workspace.workspaceFolders[0].uri.fsPath
+ : vscode.Uri.parse('').fsPath
+
+ let configSelect = ''
+ let newConfig = fs.existsSync(`${rootPath}/.vscode/launch.json`)
+ ? false
+ : true
+ let configIndex = fs.existsSync(`${rootPath}/.vscode/launch.json`) ? 0 : -1
+ let fileData = JSON.parse('{}')
+
+ if (fs.existsSync(`${rootPath}/.vscode/launch.json`)) {
+ fileData = JSON.parse(
+ fs.readFileSync(`${rootPath}/.vscode/launch.json`).toString()
+ )
+
+ fileData.configurations.forEach((element) => {
+ configSelect += `<option
value="${element.name}">${element.name}</option>`
+ })
+ }
+
+ let defaultValues = getConfigValues(fileData, configIndex)
+
+ let nameVisOrHiddenStyle = newConfig
+ ? 'margin-top: 10px; visibility: visible;'
+ : 'visibility: hidden;'
+
+ configSelect += `<option value="New Config">New Config</option>`
+
+ let openHexView = defaultValues.openHexView ? 'checked' : ''
+ let openInfosetDiffView = defaultValues.openInfosetDiffView ? 'checked' :
''
+ let openInfosetView = defaultValues.openInfosetView ? 'checked' : ''
+ let stopOnEntry = defaultValues.stopOnEntry ? 'checked' : ''
+ let trace = defaultValues.trace ? 'checked' : ''
+ let useExistingServer = defaultValues.useExistingServer ? 'checked' : ''
+
+ let infosetOutputTypeSelect = ''
+ let infosetOutputTypes = ['none', 'console', 'file']
+ let infosetOutputType = defaultValues.infosetOutput['type']
+ ? defaultValues.infosetOutput['type']
+ : defaultValues.infosetOutputType
+ let infosetOutputPath = defaultValues.infosetOutput['path']
+ ? defaultValues.infosetOutput['path']
+ : defaultValues.infosetOutputFilePath
+ let infosetPathVisOrHiddenStyle =
+ infosetOutputType === 'file'
+ ? 'margin-top: 10px; visibility: visible;'
+ : 'visibility: hidden;'
+
+ infosetOutputTypes.forEach((type) => {
+ if (type === infosetOutputType) {
+ infosetOutputTypeSelect += `<option selected
value="${type}">${type}</option>`
+ } else {
+ infosetOutputTypeSelect += `<option value="${type}">${type}</option>`
+ }
+ })
+
+ return `
+ <!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content=width=device-width, initial-scale=1.0">
+ <title>Launch Config Wizard</title>
+ </head>
+ <body>
+ <link rel="stylesheet" type="text/css" href="${styleUri}">
+ <script nonce="${nonce}" src="${scriptUri}"></script>
+ <h2 style="color: white;">Daffodil Debugger Config Settings</h2>
+
+ <div id="configSelectionDropDown" class="setting-div">
+ <p>Launch Config:</p>
+ <p class="setting-description">Launch config to be updated in the
launch.json. 'New Config' will allow for a new one to be made.</p>
+ <select onChange="updateSelectedConfig()" class="file-input"
style="width: 200px;" id="configSelected">
+ ${configSelect}
+ </select>
+
+ <p style="${nameVisOrHiddenStyle}" id="nameLabel"
class="setting-description">
+ New Config Name: <input class="file-input"
value="${defaultValues.name}" id="name"/>
+ </p>
+ </div>
+
+ <div id="dataDiv" class="setting-div">
+ <p>Data:</p>
+ <p class="setting-description">Absolute path to the input data
file.</p>
+ <input class="file-input" value="${defaultValues.data}" id="data"/>
+ <button id="dataBrowse" class="browse-button" type="button"
onclick="filePicker('data', 'Select input data file to debug')">Browse</button>
+ </div>
+
+ <div id="debugServerDiv" class="setting-div">
+ <p>Debug Server:</p>
+ <p class="setting-description">Port debug server running on.</p>
+ <input class="file-input" value="${defaultValues.debugServer}"
id="debugServer"/>
+ </div>
+
+ <div id="infosetOutputTypeDiv" class="setting-div">
+ <p>Infoset Output Type:</p>
+ <p class="setting-description">Destination for final Infoset (file |
'console' | 'none')</p>
+ <select onChange="updateInfosetOutputType()" class="file-input"
style="width: 200px;" id="infosetOutputType">
+ ${infosetOutputTypeSelect}
+ </select>
+
+ <p id="infosetOutputFilePathLabel"
style="${infosetPathVisOrHiddenStyle}" class="setting-description">
+ Output Infoset Path: <input class="file-input"
value="${infosetOutputPath}" id="infosetOutputFilePath"/>
+ </p>
+ </div>
+
+ <div id="openHexViewDiv" class="setting-div"
onclick="check('openHexView')">
+ <p>Open Hex View:</p>
+ <label class="container">Open hexview on debug start.
+ <input type="checkbox" id="openHexView" ${openHexView}>
+ <span class="checkmark"></span>
+ </label>
+ </div>
+
+ <div id="openInfosetDiffViewDiv" class="setting-div"
onclick="check('openInfosetDiffView')">
+ <p>Open Infoset Diff View:</p>
+ <label class="container">Open hexview on debug start.
+ <input type="checkbox" id="openInfosetDiffView"
${openInfosetDiffView}>
+ <span class="checkmark"></span>
+ </label>
+ </div>
+
+ <div id="openInfosetViewDiv" class="setting-div"
onclick="check('openInfosetView')">
+ <p>Open Infoset View:</p>
+ <label class="container">Open hexview on debug start.
+ <input type="checkbox" id="openInfosetView" ${openInfosetView}>
+ <span class="checkmark"></span>
+ </label>
+ </div>
+
+ <div id="programDiv" class="setting-div">
+ <p>Program:</p>
+ <p class="setting-description">Absolute path to the DFDL schema
file.</p>
+ <input class="file-input" value="${defaultValues.program}"
id="program"/>
+ <button id="programBrowse" class="browse-button" type="button"
onclick="filePicker('program', 'Select DFDL schema to debug')">Browse</button>
+ </div>
+
+ <div id="stopOnEntryDiv" class="setting-div"
onclick="check('stopOnEntry')">
+ <p>Stop On Entry:</p>
+ <label class="container">Automatically stop after launch.
+ <input type="checkbox" id="stopOnEntry" ${stopOnEntry}>
+ <span class="checkmark"></span>
+ </label>
+ </div>
+
+ <div id="traceDiv" class="setting-div" onclick="check('trace')">
+ <p>Trace:</p>
+ <label class="container">Enable logging of the Debug Adapter Protocol.
+ <input type="checkbox" id="trace" ${trace}>
+ <span class="checkmark"></span>
+ </label>
+ </div>
+
+ <div id="useExistingServerDiv" class="setting-div"
onclick="check('useExistingServer')">
+ <p>Use Existing Server:</p>
+ <label class="container">Enable connection to running DAP Server.
+ <input type="checkbox" id="useExistingServer" ${useExistingServer}>
+ <span class="checkmark"></span>
+ </label>
+ </div>
+
+ <button class="save-button" type="button" onclick="save()">Save</button>
+ </body>
+ </html>`
+ }
+
+ // Method to get nonce, helps with running custom script
+ getNonce() {
+ let text = ''
+ const possible =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
+ for (let i = 0; i < 32; i++) {
+ text += possible.charAt(Math.floor(Math.random() * possible.length))
+ }
+ return text
+ }
+}
diff --git a/src/launchWizard/styles.css b/src/launchWizard/styles.css
new file mode 100644
index 0000000..20a1f80
--- /dev/null
+++ b/src/launchWizard/styles.css
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ .container {
+ display: block;
+ position: relative;
+ margin: 0px;
+ margin-top: -10px;
+ padding-left: 35px;
+ margin-bottom: 25px;
+ cursor: pointer;
+ font-size: 14px;
+ font-style: italic;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.file-input {
+ color: white;
+ cursor: pointer;
+ background-color: rgb(80, 78, 78);
+ width: 350px;
+ height: 25px;
+ font-size: 12px;
+ border: none;
+ border-radius: 12px;
+ padding-left: 7px;
+ margin: 0px;
+ margin-top: 5px;
+ margin-left: 10px;
+}
+
+/* Hide the browser's default checkbox */
+.container input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+ height: 0;
+ width: 0;
+}
+
+/* Create a custom checkbox */
+.checkmark {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 15px;
+ width: 15px;
+ background-color: grey;
+ margin-left: 10px;
+}
+
+/* On mouse-over, add a grey background color */
+.container:hover input ~ .checkmark {
+ background-color: #aaa;
+}
+
+/* When the checkbox is checked, add a blue background */
+.container input:checked ~ .checkmark {
+ background-color: grey;
+}
+
+/* Create the checkmark/indicator (hidden when not checked) */
+.checkmark:after {
+ content: "";
+ position: absolute;
+ display: none;
+}
+
+/* Show the checkmark when checked */
+.container input:checked ~ .checkmark:after {
+ display: block;
+}
+
+/* Style the checkmark/indicator */
+.container .checkmark:after {
+ left: 4px;
+ top: 0px;
+ width: 5px;
+ height: 10px;
+ border: solid black;
+ border-width: 0 3px 3px 0;
+ -webkit-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ transform: rotate(45deg);
+}
+
+.setting-div {
+ color: white;
+ font-size: 16px;
+ cursor: pointer;
+}
+
+.save-button {
+ background-color: #4CAF50;
+ border: none;
+ border-radius: 12px;
+ color: white;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ font-size: 16px;
+ cursor: pointer;
+ width: 150px;
+ height: 35px;
+ margin-top: -10px;
+}
+
+.browse-button {
+ background-color: lightgray;
+ border: none;
+ border-radius: 12px;
+ color: black;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ font-size: 12px;
+ cursor: pointer;
+ width: 75px;
+ height: 25px;
+}
+
+.setting-description {
+ font-size: 14px;
+ margin: 0px;
+ margin-top: -10px;
+ font-style: italic;
+ margin-left: 10px;
+}
diff --git a/src/utils.ts b/src/utils.ts
index 65ba465..dfcb90d 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -17,6 +17,8 @@
import * as vscode from 'vscode'
+const defaultConf = vscode.workspace.getConfiguration()
+
// Function to run vscode command and catch the error to not cause other issues
export function runCommand(command: string) {
vscode.commands.executeCommand(command).then(undefined, (err) => {
@@ -60,3 +62,58 @@ export async function onDebugStartDisplay(viewsToCheck:
string[]) {
}
})
}
+
+// Method for retrieving the config when launch.json does not exist
+export function getConfig(
+ name,
+ request,
+ type,
+ program: string = '',
+ data = false,
+ debugServer = false,
+ infosetOutput: object | null = null,
+ stopOnEntry = false,
+ useExistingServer = false,
+ trace = false,
+ openHexView = false,
+ openInfosetView = false,
+ openInfosetDiffView = false
+) {
+ return {
+ name: name,
+ request: request,
+ type: type,
+ program: program
+ ? program
+ : defaultConf.get('program', '${command:AskForProgramName}'),
+ data: data ? data : defaultConf.get('data', '${command:AskForDataName}'),
+ debugServer: debugServer
+ ? debugServer
+ : defaultConf.get('debugServer', 4711),
+ infosetOutput: infosetOutput
+ ? infosetOutput
+ : {
+ type: defaultConf.get('infosetOutputType', 'none'),
+ path: defaultConf.get(
+ 'infosetOutputFilePath',
+ '${workspaceFolder}/infoset.xml'
+ ),
+ },
+ stopOnEntry: stopOnEntry
+ ? stopOnEntry
+ : defaultConf.get('stopOnEntry', true),
+ useExistingServer: useExistingServer
+ ? useExistingServer
+ : defaultConf.get('useExistingServer', false),
+ trace: trace ? trace : defaultConf.get('trace', true),
+ openHexView: openHexView
+ ? openHexView
+ : defaultConf.get('openHexView', false),
+ openInfosetView: openInfosetView
+ ? openInfosetView
+ : defaultConf.get('openInfosetView', false),
+ openInfosetDiffView: openInfosetDiffView
+ ? openInfosetDiffView
+ : defaultConf.get('openInfosetDiffView', false),
+ }
+}