roku-debug 0.21.18 → 0.21.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/LaunchConfiguration.d.ts +7 -0
  3. package/dist/adapters/DebugProtocolAdapter.d.ts +1 -1
  4. package/dist/adapters/DebugProtocolAdapter.js.map +1 -1
  5. package/dist/adapters/TelnetAdapter.d.ts +2 -0
  6. package/dist/adapters/TelnetAdapter.js +6 -0
  7. package/dist/adapters/TelnetAdapter.js.map +1 -1
  8. package/dist/adapters/customVariables/ifGetMessagePort.js +3 -2
  9. package/dist/adapters/customVariables/ifGetMessagePort.js.map +1 -1
  10. package/dist/adapters/customVariables/ifImageMetadata.js +4 -4
  11. package/dist/adapters/customVariables/ifImageMetadata.js.map +1 -1
  12. package/dist/adapters/customVariables/ifRegion.js +2 -2
  13. package/dist/adapters/customVariables/ifRegion.js.map +1 -1
  14. package/dist/adapters/customVariables/ifSGNodeChildren.js +1 -1
  15. package/dist/adapters/customVariables/ifSGNodeChildren.js.map +1 -1
  16. package/dist/adapters/customVariables/ifSGNodeField.js +1 -1
  17. package/dist/adapters/customVariables/ifSGNodeField.js.map +1 -1
  18. package/dist/adapters/customVariables/ifSGNodeHttpAgentAccess.js +3 -2
  19. package/dist/adapters/customVariables/ifSGNodeHttpAgentAccess.js.map +1 -1
  20. package/dist/adapters/customVariables/ifSGScreen.js +3 -3
  21. package/dist/adapters/customVariables/ifSGScreen.js.map +1 -1
  22. package/dist/adapters/customVariables/ifSocket.js +6 -6
  23. package/dist/adapters/customVariables/ifSocket.js.map +1 -1
  24. package/dist/adapters/customVariables/ifSprite.js +2 -2
  25. package/dist/adapters/customVariables/ifSprite.js.map +1 -1
  26. package/dist/adapters/customVariables/ifVideoPlayer.js +2 -2
  27. package/dist/adapters/customVariables/ifVideoPlayer.js.map +1 -1
  28. package/dist/adapters/customVariables/ifXMLElement.js +4 -4
  29. package/dist/adapters/customVariables/ifXMLElement.js.map +1 -1
  30. package/dist/adapters/customVariables/ifXMLList.js +4 -4
  31. package/dist/adapters/customVariables/ifXMLList.js.map +1 -1
  32. package/dist/bsc/BscProject.d.ts +27 -0
  33. package/dist/bsc/BscProject.js +50 -0
  34. package/dist/bsc/BscProject.js.map +1 -0
  35. package/dist/bsc/BscProjectThreaded.d.ts +45 -0
  36. package/dist/bsc/BscProjectThreaded.js +90 -0
  37. package/dist/bsc/BscProjectThreaded.js.map +1 -0
  38. package/dist/bsc/threading/BscProjectWorkerPool.d.ts +5 -0
  39. package/dist/bsc/threading/BscProjectWorkerPool.js +29 -0
  40. package/dist/bsc/threading/BscProjectWorkerPool.js.map +1 -0
  41. package/dist/bsc/threading/ThreadMessageHandler.d.ts +99 -0
  42. package/dist/bsc/threading/ThreadMessageHandler.js +138 -0
  43. package/dist/bsc/threading/ThreadMessageHandler.js.map +1 -0
  44. package/dist/bsc/threading/ThreadRunner.d.ts +30 -0
  45. package/dist/bsc/threading/ThreadRunner.js +50 -0
  46. package/dist/bsc/threading/ThreadRunner.js.map +1 -0
  47. package/dist/bsc/threading/WorkerPool.d.ts +38 -0
  48. package/dist/bsc/threading/WorkerPool.js +78 -0
  49. package/dist/bsc/threading/WorkerPool.js.map +1 -0
  50. package/dist/debugSession/BrightScriptDebugSession.d.ts +16 -0
  51. package/dist/debugSession/BrightScriptDebugSession.js +342 -23
  52. package/dist/debugSession/BrightScriptDebugSession.js.map +1 -1
  53. package/dist/debugSession/ecpRegistryUtils.d.ts +11 -0
  54. package/dist/debugSession/ecpRegistryUtils.js +168 -0
  55. package/dist/debugSession/ecpRegistryUtils.js.map +1 -0
  56. package/dist/interfaces.d.ts +12 -0
  57. package/dist/managers/BreakpointManager.d.ts +10 -0
  58. package/dist/managers/BreakpointManager.js +15 -5
  59. package/dist/managers/BreakpointManager.js.map +1 -1
  60. package/dist/managers/ProjectManager.d.ts +31 -12
  61. package/dist/managers/ProjectManager.js +61 -9
  62. package/dist/managers/ProjectManager.js.map +1 -1
  63. package/dist/util.d.ts +10 -1
  64. package/dist/util.js +36 -0
  65. package/dist/util.js.map +1 -1
  66. package/package.json +2 -2
  67. package/roku-debug-0.21.20.tgz +0 -0
  68. package/roku-debug-0.21.18.tgz +0 -0
@@ -23,6 +23,10 @@ const logging_1 = require("../logging");
23
23
  const VariablesResponse_1 = require("../debugProtocol/events/responses/VariablesResponse");
24
24
  const brighterscript_1 = require("brighterscript");
25
25
  const debounce_1 = require("debounce");
26
+ const roku_types_1 = require("brighterscript/dist/roku-types");
27
+ const globalCallables_1 = require("brighterscript/dist/globalCallables");
28
+ const BscProjectWorkerPool_1 = require("../bsc/threading/BscProjectWorkerPool");
29
+ const ecpRegistryUtils_1 = require("./ecpRegistryUtils");
26
30
  const diagnosticSource = 'roku-debug';
27
31
  class BrightScriptDebugSession extends debugadapter_1.DebugSession {
28
32
  constructor() {
@@ -73,7 +77,10 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
73
77
  this.breakpointManager = new BreakpointManager_1.BreakpointManager(this.sourceMapManager, this.locationManager);
74
78
  //send newly-verified breakpoints to vscode
75
79
  this.breakpointManager.on('breakpoints-verified', (data) => this.onDeviceBreakpointsChanged('changed', data));
76
- this.projectManager = new ProjectManager_1.ProjectManager(this.breakpointManager, this.locationManager);
80
+ this.projectManager = new ProjectManager_1.ProjectManager({
81
+ breakpointManager: this.breakpointManager,
82
+ locationManager: this.locationManager
83
+ });
77
84
  this.fileLoggingManager = new logging_1.FileLoggingManager();
78
85
  }
79
86
  onDeviceBreakpointsChanged(eventName, data) {
@@ -85,6 +92,8 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
85
92
  column: breakpoint.column,
86
93
  verified: breakpoint.verified,
87
94
  id: breakpoint.id,
95
+ reason: breakpoint.reason,
96
+ message: breakpoint.message,
88
97
  source: {
89
98
  path: breakpoint.srcPath
90
99
  }
@@ -143,6 +152,8 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
143
152
  response.body.supportsHitConditionalBreakpoints = true;
144
153
  // This debug adapter supports log points by interpreting the 'logMessage' attribute of the SourceBreakpoint
145
154
  response.body.supportsLogPoints = true;
155
+ response.body.supportsCompletionsRequest = true;
156
+ response.body.completionTriggerCharacters = ['.', '(', '{', ',', ' '];
146
157
  this.sendResponse(response);
147
158
  //register the debug output log transport writer
148
159
  logging_1.debugServerLogOutputEventTransport.setWriter((message) => {
@@ -245,7 +256,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
245
256
  * @returns
246
257
  */
247
258
  normalizeLaunchConfig(config) {
248
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
259
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
249
260
  (_a = config.cwd) !== null && _a !== void 0 ? _a : (config.cwd = process.cwd());
250
261
  (_b = config.outDir) !== null && _b !== void 0 ? _b : (config.outDir = (0, FileUtils_1.standardizePath) `${config.cwd}/out`);
251
262
  (_c = config.stagingDir) !== null && _c !== void 0 ? _c : (config.stagingDir = (0, FileUtils_1.standardizePath) `${config.outDir}/.roku-deploy-staging`);
@@ -259,14 +270,17 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
259
270
  (_l = config.emitChannelPublishedEvent) !== null && _l !== void 0 ? _l : (config.emitChannelPublishedEvent = true);
260
271
  (_m = config.rewriteDevicePathsInLogs) !== null && _m !== void 0 ? _m : (config.rewriteDevicePathsInLogs = true);
261
272
  (_o = config.autoResolveVirtualVariables) !== null && _o !== void 0 ? _o : (config.autoResolveVirtualVariables = false);
273
+ (_p = config.enhanceREPLCompletions) !== null && _p !== void 0 ? _p : (config.enhanceREPLCompletions = true);
262
274
  return config;
263
275
  }
264
276
  async launchRequest(response, config) {
265
- var _a, _b;
266
- this.logger.log('[launchRequest] begin');
277
+ var _a, _b, _c, _d, _e;
278
+ const logEnd = this.logger.timeStart('log', '[launchRequest] launch');
267
279
  //send the response right away so the UI immediately shows the debugger toolbar
268
280
  this.sendResponse(response);
269
281
  this.launchConfiguration = this.normalizeLaunchConfig(config);
282
+ //prebake some threads for our ProjectManager to use later on (1 for the main project, and 1 for every complib)
283
+ BscProjectWorkerPool_1.bscProjectWorkerPool.preload(1 + ((_c = (_b = (_a = this.launchConfiguration) === null || _a === void 0 ? void 0 : _a.componentLibraries) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0));
270
284
  //set the logLevel provided by the launch config
271
285
  if (this.launchConfiguration.logLevel) {
272
286
  logging_1.logger.logLevel = this.launchConfiguration.logLevel;
@@ -289,7 +303,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
289
303
  return this.shutdown(`Developer mode is not enabled for host '${this.launchConfiguration.host}'.`);
290
304
  }
291
305
  //initialize all file logging (rokuDevice, debugger, etc)
292
- this.fileLoggingManager.activate((_a = this.launchConfiguration) === null || _a === void 0 ? void 0 : _a.fileLogging, this.cwd);
306
+ this.fileLoggingManager.activate((_d = this.launchConfiguration) === null || _d === void 0 ? void 0 : _d.fileLogging, this.cwd);
293
307
  this.projectManager.launchConfiguration = this.launchConfiguration;
294
308
  this.breakpointManager.launchConfiguration = this.launchConfiguration;
295
309
  this.sendEvent(new Events_1.LaunchStartEvent(this.launchConfiguration));
@@ -407,9 +421,10 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
407
421
  util_1.util.log(e === null || e === void 0 ? void 0 : e.stack);
408
422
  this.sendErrorResponse(response, -1, e === null || e === void 0 ? void 0 : e.stack);
409
423
  //send any compile errors to the client
410
- await ((_b = this.rokuAdapter) === null || _b === void 0 ? void 0 : _b.sendErrors());
424
+ await ((_e = this.rokuAdapter) === null || _e === void 0 ? void 0 : _e.sendErrors());
411
425
  }
412
426
  }
427
+ logEnd();
413
428
  //at this point, the project has been deployed. If we need to use a deep link, launch it now.
414
429
  if (this.launchConfiguration.deepLinkUrl) {
415
430
  //wait until the first entry breakpoint has been hit
@@ -739,7 +754,8 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
739
754
  injectRdbOnDeviceComponent: this.launchConfiguration.injectRdbOnDeviceComponent,
740
755
  rdbFilesBasePath: this.launchConfiguration.rdbFilesBasePath,
741
756
  stagingDir: this.launchConfiguration.stagingDir,
742
- packagePath: this.launchConfiguration.packagePath
757
+ packagePath: this.launchConfiguration.packagePath,
758
+ enhanceREPLCompletions: this.launchConfiguration.enhanceREPLCompletions
743
759
  });
744
760
  util_1.util.log('Moving selected files to staging area');
745
761
  await this.projectManager.mainProject.stage();
@@ -810,7 +826,8 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
810
826
  bsConst: componentLibrary.bsConst,
811
827
  injectRaleTrackerTask: componentLibrary.injectRaleTrackerTask,
812
828
  raleTrackerTaskFileLocation: componentLibrary.raleTrackerTaskFileLocation,
813
- libraryIndex: libraryIndex
829
+ libraryIndex: libraryIndex,
830
+ enhanceREPLCompletions: this.launchConfiguration.enhanceREPLCompletions
814
831
  }));
815
832
  }
816
833
  //prepare all of the libraries in parallel
@@ -985,13 +1002,35 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
985
1002
  v.request_seq = response.request_seq;
986
1003
  v.frameId = args.frameId;
987
1004
  }
988
- let scope = new debugadapter_1.Scope('Local', refId, false);
989
- scopes.push(scope);
1005
+ scopes.push({
1006
+ name: 'Local',
1007
+ variablesReference: v.variablesReference,
1008
+ expensive: false,
1009
+ presentationHint: 'locals'
1010
+ });
990
1011
  }
991
1012
  else {
992
1013
  // NOTE: Legacy telnet support
993
- scopes.push(new debugadapter_1.Scope('Local', this.variableHandles.create('local'), false));
1014
+ scopes.push({
1015
+ name: 'Local',
1016
+ variablesReference: this.variableHandles.create('local'),
1017
+ expensive: false,
1018
+ presentationHint: 'locals'
1019
+ });
994
1020
  }
1021
+ let refId = this.getEvaluateRefId('$$registry', Infinity);
1022
+ scopes.push({
1023
+ name: 'Registry',
1024
+ variablesReference: refId,
1025
+ expensive: true
1026
+ });
1027
+ this.variables[refId] = {
1028
+ variablesReference: refId,
1029
+ name: 'Registry',
1030
+ value: '',
1031
+ type: '$$Registry',
1032
+ childVariables: []
1033
+ };
995
1034
  response.body = {
996
1035
  scopes: scopes
997
1036
  };
@@ -1138,6 +1177,13 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1138
1177
  return this.sendResponse(response);
1139
1178
  }
1140
1179
  logger.log('variable', v);
1180
+ if (v.type === '$$Registry' && v.childVariables.length === 0) {
1181
+ // This is a special scope variable used to load registry data via an ECP call
1182
+ const url = `http://${this.launchConfiguration.host}:${this.launchConfiguration.remotePort}/query/registry/dev`;
1183
+ // Send the registry ECP call for the `dev` app as side loaded apps are always `dev`
1184
+ const response = await util_1.util.httpGet(url);
1185
+ await (0, ecpRegistryUtils_1.populateVariableFromRegistryEcp)(response, v, this.variables, this.getEvaluateRefId.bind(this));
1186
+ }
1141
1187
  //query for child vars if we haven't done it yet or DAP is asking to resolve a lazy variable
1142
1188
  if (v.childVariables.length === 0 || v.isResolved) {
1143
1189
  let tempVar;
@@ -1199,8 +1245,10 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1199
1245
  updatedVariables = v.childVariables;
1200
1246
  }
1201
1247
  }
1248
+ // Only send the updated variables if we are not going to trigger an invalidated event.
1249
+ // This is to prevent the UI from updating twice and makes the experience much smoother to the end user.
1202
1250
  response.body = {
1203
- variables: this.filterVariablesUpdates(updatedVariables, args, this.variables[args.variablesReference])
1251
+ variables: sendInvalidatedEvent ? [] : this.filterVariablesUpdates(updatedVariables, args, this.variables[args.variablesReference])
1204
1252
  };
1205
1253
  }
1206
1254
  catch (error) {
@@ -1436,6 +1484,246 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1436
1484
  }
1437
1485
  return results;
1438
1486
  }
1487
+ async completionsRequest(response, args, request) {
1488
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1489
+ this.logger.log('completionsRequest', args, request);
1490
+ // this.sendEvent(new LogOutputEvent(`completionsRequest: ${args.text}`));
1491
+ // this.sendEvent(new OutputEvent(`completionsRequest: ${args.text}\n`, 'stderr'));
1492
+ try {
1493
+ let supplyLocalScopeCompletions = false;
1494
+ let closestCompletionDetails = this.getClosestCompletionDetails(args);
1495
+ if (!closestCompletionDetails) {
1496
+ // If the cursor is not at the end of the line, then we should not supply completions at this time
1497
+ response.body = {
1498
+ targets: []
1499
+ };
1500
+ return this.sendResponse(response);
1501
+ }
1502
+ let completions = new Map();
1503
+ let parentVariablePath = closestCompletionDetails.parentVariablePath;
1504
+ // Get the completions if the variable path was valid
1505
+ if (parentVariablePath) {
1506
+ // If the parent variable path is an empty string, then we are looking up the local scope variables and global functions
1507
+ if (parentVariablePath.length === 1 && parentVariablePath[0] === '') {
1508
+ supplyLocalScopeCompletions = true;
1509
+ }
1510
+ // Look up the parent variable
1511
+ let parentVariable = this.findVariableByPath(Object.values(this.variables), parentVariablePath, args.frameId);
1512
+ if (!parentVariable || parentVariable.childVariables.length === 0) {
1513
+ // We did not find the parent variable, so try to look it up from the device
1514
+ try {
1515
+ let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: parentVariablePath.join('.'), frameId: args.frameId }, parentVariablePath);
1516
+ let result = await this.rokuAdapter.getVariable(evalArgs.expression, args.frameId);
1517
+ parentVariable = await this.getVariableFromResult(result, args.frameId);
1518
+ }
1519
+ catch (error) {
1520
+ this.logger.error('Error looking up parent completions', error, { parentVariablePath });
1521
+ }
1522
+ }
1523
+ // provide completions for the parent variable if one was found
1524
+ if (parentVariable) {
1525
+ let possibleFieldsAndMethods = [];
1526
+ // Filter out virtual variables
1527
+ possibleFieldsAndMethods = parentVariable.childVariables.filter((v) => { var _a; return ((_a = v.presentationHint) === null || _a === void 0 ? void 0 : _a.kind) !== 'virtual'; });
1528
+ for (let v of possibleFieldsAndMethods) {
1529
+ // Default completion type should be variable
1530
+ let completionType = 'variable';
1531
+ if (!supplyLocalScopeCompletions) {
1532
+ // We are not supplying local scope completions, so we need to determine the completion type relative to the parent variable
1533
+ if (parentVariable.type === 'roSGNode' || parentVariable.type === VariablesResponse_1.VariableType.AssociativeArray || parentVariable.type === VariablesResponse_1.VariableType.Object) {
1534
+ completionType = 'field';
1535
+ }
1536
+ switch (v.type) {
1537
+ case VariablesResponse_1.VariableType.Function:
1538
+ case VariablesResponse_1.VariableType.Subroutine:
1539
+ completionType = 'method';
1540
+ break;
1541
+ default:
1542
+ break;
1543
+ }
1544
+ }
1545
+ let label = v.name;
1546
+ if (parentVariable.type === VariablesResponse_1.VariableType.Array ||
1547
+ parentVariable.type === VariablesResponse_1.VariableType.List ||
1548
+ parentVariable.type === 'roXMLList' ||
1549
+ parentVariable.type === 'roByteArray') {
1550
+ label = `[${v.name}]`;
1551
+ }
1552
+ completions.set(`${completionType}-${v.name}`, {
1553
+ label: label,
1554
+ type: completionType,
1555
+ sortText: '000000'
1556
+ });
1557
+ }
1558
+ let parentComponentType = this.debuggerVarTypeToRoType(parentVariable.type).toLowerCase();
1559
+ //assemble a list of all methods on the parent component
1560
+ const methods = [
1561
+ //if the parent variable is an actual interface (if applicable) Ex: `ifString` or `ifArray`
1562
+ ...(_b = (_a = roku_types_1.interfaces[parentComponentType]) === null || _a === void 0 ? void 0 : _a.methods) !== null && _b !== void 0 ? _b : [],
1563
+ //interfaces from component of this name (if applicable) Ex: `roSGNode` or `roDateTime`
1564
+ ...(_d = (_c = roku_types_1.components[parentComponentType]) === null || _c === void 0 ? void 0 : _c.interfaces.map((i) => { var _a; return (_a = roku_types_1.interfaces[i.name.toLowerCase()]) === null || _a === void 0 ? void 0 : _a.methods; })) !== null && _d !== void 0 ? _d : [],
1565
+ // Add parent event function completions (if applicable) Ex: `roSGNodeEvent` or `roDeviceInfoEvent`
1566
+ ...(_f = (_e = roku_types_1.events[parentComponentType]) === null || _e === void 0 ? void 0 : _e.methods) !== null && _f !== void 0 ? _f : []
1567
+ ].flat();
1568
+ // Based on the results of interface, component, and event looks up, add all the methods to the completions
1569
+ for (const method of methods) {
1570
+ completions.set(`method-${method.name}`, {
1571
+ label: method.name,
1572
+ type: 'method',
1573
+ detail: (_g = method.description) !== null && _g !== void 0 ? _g : '',
1574
+ sortText: '000000'
1575
+ });
1576
+ }
1577
+ // Add the global functions to the completions results
1578
+ if (supplyLocalScopeCompletions) {
1579
+ for (let globalCallable of globalCallables_1.globalCallables) {
1580
+ completions.set(`function-${globalCallable.name.toLocaleLowerCase()}`, {
1581
+ label: globalCallable.name,
1582
+ type: 'function',
1583
+ detail: (_j = (_h = globalCallable.shortDescription) !== null && _h !== void 0 ? _h : globalCallable.documentation) !== null && _j !== void 0 ? _j : '',
1584
+ sortText: '000000'
1585
+ });
1586
+ }
1587
+ const frame = this.rokuAdapter.getStackFrameById(args.frameId);
1588
+ let scopeFunctions = await this.projectManager.getScopeFunctionsForFile(frame.filePath);
1589
+ for (let scopeFunction of scopeFunctions) {
1590
+ if (!completions.has(`${scopeFunction.completionItemKind}-${scopeFunction.name.toLocaleLowerCase()}`)) {
1591
+ completions.set(`${scopeFunction.completionItemKind}-${scopeFunction.name.toLocaleLowerCase()}`, {
1592
+ label: scopeFunction.name,
1593
+ type: scopeFunction.completionItemKind,
1594
+ sortText: '000000'
1595
+ });
1596
+ }
1597
+ }
1598
+ }
1599
+ }
1600
+ }
1601
+ // this.sendEvent(new LogOutputEvent(`text: ${args.text} | completions: ${completions.map(v => v.label).join(', ')}`));
1602
+ // this.sendEvent(new OutputEvent(`text: ${args.text} | completions: ${completions.map(v => v.label).join(', ')}\n`, 'stderr'));
1603
+ response.body = {
1604
+ targets: [...completions.values()]
1605
+ };
1606
+ }
1607
+ catch (error) {
1608
+ // this.sendEvent(new LogOutputEvent(`text: ${args.text} | ${error}`));
1609
+ // this.sendEvent(new OutputEvent(`text: ${args.text} | ${error}\n`, 'stderr'));
1610
+ this.logger.error('Error during completionsRequest', error, { args });
1611
+ }
1612
+ this.sendResponse(response);
1613
+ }
1614
+ /**
1615
+ * Gets the closest completion details the incoming completion request.
1616
+ */
1617
+ getClosestCompletionDetails(args) {
1618
+ var _a;
1619
+ const incomingText = args.text;
1620
+ const lines = incomingText.split('\n');
1621
+ let lineNumber = (_a = args.line) !== null && _a !== void 0 ? _a : (this.initRequestArgs.linesStartAt1 ? 1 : 0);
1622
+ let column = args.column;
1623
+ // Make sure to correct the line and column to 0-based
1624
+ // if they are being sent as 1-based from the client
1625
+ if (this.initRequestArgs.linesStartAt1) {
1626
+ lineNumber--;
1627
+ }
1628
+ if (this.initRequestArgs.columnsStartAt1) {
1629
+ column--;
1630
+ }
1631
+ const targetLine = lines[lineNumber];
1632
+ let variablePathString = '';
1633
+ let i = column - 1;
1634
+ const variableChars = /[a-z0-9_\.]/i;
1635
+ // If the character at immediate to the right of the cursor is a variable character, then we are not at the end of the variable path.
1636
+ if (targetLine.length - 1 > i && variableChars.test(targetLine[i + 1])) {
1637
+ return undefined;
1638
+ }
1639
+ // Find the start of the variable path by looking for the first non-alphanumeric or non_underscore character before the cursor
1640
+ while (i >= 0 && (variableChars.test(targetLine[i]))) {
1641
+ i--;
1642
+ }
1643
+ // Pull the variable path string from the line
1644
+ variablePathString = targetLine.slice(i + 1, column);
1645
+ // Attempted dot access something unexpected
1646
+ // Example: `getPerson().name` where `getPerson()` is not a valid variable
1647
+ // and results in `.name` being the variable path string
1648
+ if (variablePathString.startsWith('.')) {
1649
+ return undefined;
1650
+ }
1651
+ // Get the variable path from the text
1652
+ let variablePath = [];
1653
+ if (!variablePathString.trim()) {
1654
+ // The text was empty so assume via '' that we are looking up the local scope variables and global functions
1655
+ variablePath = [''];
1656
+ }
1657
+ else if (variablePathString.endsWith('.')) {
1658
+ // supplied text ends with a period, so strip it off to create a valid variable path
1659
+ variablePath = util_1.util.getVariablePath(variablePathString.slice(0, -1));
1660
+ }
1661
+ else {
1662
+ variablePath = util_1.util.getVariablePath(variablePathString);
1663
+ }
1664
+ // the target string is not a valid variable path
1665
+ if (!variablePath) {
1666
+ return undefined;
1667
+ }
1668
+ let parentVariablePath;
1669
+ // If the last character is a period, then pull completions for the parent variable before the period
1670
+ if (variablePathString.endsWith('.')) {
1671
+ parentVariablePath = variablePath;
1672
+ }
1673
+ else {
1674
+ // Otherwise, pull completions for the parent variable
1675
+ parentVariablePath = variablePath.slice(0, variablePath.length - 1);
1676
+ }
1677
+ // If the parent variable path is empty or an empty string, then we are looking up the local scope variables and global functions
1678
+ if (parentVariablePath.length === 0) {
1679
+ parentVariablePath = [''];
1680
+ }
1681
+ return { parentVariablePath: parentVariablePath };
1682
+ }
1683
+ findVariableByPath(variables, path, frameId) {
1684
+ var _a;
1685
+ let current = null;
1686
+ for (const name of path) {
1687
+ // Find the object matching the current name in the data
1688
+ current = (_a = (Array.isArray(variables) ? variables : current === null || current === void 0 ? void 0 : current.childVariables)) === null || _a === void 0 ? void 0 : _a.find(obj => {
1689
+ return obj.name === name && obj.frameId === frameId;
1690
+ });
1691
+ // If no match is found, return null
1692
+ if (!current) {
1693
+ return null;
1694
+ }
1695
+ // Move to the children for the next iteration
1696
+ variables = current.childVariables;
1697
+ }
1698
+ return current;
1699
+ }
1700
+ debuggerVarTypeToRoType(type) {
1701
+ switch (type) {
1702
+ case VariablesResponse_1.VariableType.Function:
1703
+ case VariablesResponse_1.VariableType.Subroutine:
1704
+ return 'roFunction';
1705
+ case VariablesResponse_1.VariableType.AssociativeArray:
1706
+ return 'roAssociativeArray';
1707
+ case VariablesResponse_1.VariableType.List:
1708
+ return 'roList';
1709
+ case VariablesResponse_1.VariableType.Array:
1710
+ return 'roArray';
1711
+ case VariablesResponse_1.VariableType.Boolean:
1712
+ return 'roBoolean';
1713
+ case VariablesResponse_1.VariableType.Double:
1714
+ return 'roDouble';
1715
+ case VariablesResponse_1.VariableType.Float:
1716
+ return 'roFloat';
1717
+ case VariablesResponse_1.VariableType.Integer:
1718
+ return 'roInteger';
1719
+ case VariablesResponse_1.VariableType.LongInteger:
1720
+ return 'roLongInteger';
1721
+ case VariablesResponse_1.VariableType.String:
1722
+ return 'roString';
1723
+ default:
1724
+ return type;
1725
+ }
1726
+ }
1439
1727
  /**
1440
1728
  * Called when the host stops debugging
1441
1729
  * @param response
@@ -1768,19 +2056,35 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1768
2056
  return this.shutdownPromise;
1769
2057
  }
1770
2058
  async _shutdown(errorMessage, modal = false) {
1771
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
2059
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2060
+ try {
2061
+ (_b = (_a = this.projectManager) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
2062
+ }
2063
+ catch (e) {
2064
+ this.logger.error(e);
2065
+ }
2066
+ try {
2067
+ (_c = this.componentLibraryServer) === null || _c === void 0 ? void 0 : _c.stop();
2068
+ }
2069
+ catch (e) {
2070
+ this.logger.error(e);
2071
+ }
2072
+ try {
2073
+ void ((_e = (_d = this.rendezvousTracker) === null || _d === void 0 ? void 0 : _d.destroy) === null || _e === void 0 ? void 0 : _e.call(_d));
2074
+ }
2075
+ catch (e) {
2076
+ this.logger.error(e);
2077
+ }
2078
+ try {
2079
+ (_g = (_f = this.sourceMapManager) === null || _f === void 0 ? void 0 : _f.destroy) === null || _g === void 0 ? void 0 : _g.call(_f);
2080
+ }
2081
+ catch (e) {
2082
+ this.logger.error(e);
2083
+ }
1772
2084
  try {
1773
- (_a = this.componentLibraryServer) === null || _a === void 0 ? void 0 : _a.stop();
1774
- void ((_c = (_b = this.rendezvousTracker) === null || _b === void 0 ? void 0 : _b.destroy) === null || _c === void 0 ? void 0 : _c.call(_b));
1775
- try {
1776
- (_e = (_d = this.sourceMapManager) === null || _d === void 0 ? void 0 : _d.destroy) === null || _e === void 0 ? void 0 : _e.call(_d);
1777
- }
1778
- catch (e) {
1779
- this.logger.error(e);
1780
- }
1781
2085
  //if configured, delete the staging directory
1782
2086
  if (!this.launchConfiguration.retainStagingFolder) {
1783
- const stagingDirs = (_g = (_f = this.projectManager) === null || _f === void 0 ? void 0 : _f.getStagingDirs()) !== null && _g !== void 0 ? _g : [];
2087
+ const stagingDirs = (_j = (_h = this.projectManager) === null || _h === void 0 ? void 0 : _h.getStagingDirs()) !== null && _j !== void 0 ? _j : [];
1784
2088
  this.logger.info('deleting staging folders', stagingDirs);
1785
2089
  for (let stagingDir of stagingDirs) {
1786
2090
  try {
@@ -1792,13 +2096,23 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1792
2096
  }
1793
2097
  }
1794
2098
  }
2099
+ }
2100
+ catch (e) {
2101
+ this.logger.error(e);
2102
+ }
2103
+ try {
1795
2104
  //if there was an error message, display it to the user
1796
2105
  if (errorMessage) {
1797
2106
  this.logger.error(errorMessage);
1798
2107
  this.showPopupMessage(errorMessage, 'error', modal);
1799
2108
  }
2109
+ }
2110
+ catch (e) {
2111
+ this.logger.error(e);
2112
+ }
2113
+ try {
1800
2114
  this.logger.log('Destroy rokuAdapter');
1801
- await ((_j = (_h = this.rokuAdapter) === null || _h === void 0 ? void 0 : _h.destroy) === null || _j === void 0 ? void 0 : _j.call(_h));
2115
+ await ((_l = (_k = this.rokuAdapter) === null || _k === void 0 ? void 0 : _k.destroy) === null || _l === void 0 ? void 0 : _l.call(_k));
1802
2116
  //press the home button to return to the home screen
1803
2117
  try {
1804
2118
  this.logger.log('Press home button');
@@ -1807,6 +2121,11 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1807
2121
  catch (e) {
1808
2122
  this.logger.error(e);
1809
2123
  }
2124
+ }
2125
+ catch (e) {
2126
+ this.logger.error(e);
2127
+ }
2128
+ try {
1810
2129
  this.logger.log('Send terminated event');
1811
2130
  this.sendEvent(new debugadapter_1.TerminatedEvent());
1812
2131
  //shut down the process