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),
+  }
+}

Reply via email to