Copilot commented on code in PR #1726:
URL: https://github.com/apache/daffodil-vscode/pull/1726#discussion_r3440057404


##########
src/dataEditor/omegaEditDataEditor.ts:
##########
@@ -0,0 +1,347 @@
+/*
+ * 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 path from 'path'
+import * as vscode from 'vscode'
+import {
+  DaffodilData,
+  dataEvent,
+  extractDaffodilEvent,
+} from '../daffodilDebugger/daffodil'
+import { substituteVSCodeEnvVariables } from '../utils'
+
+export const DATA_EDITOR_COMMAND = 'extension.data.edit'
+export const OMEGA_EDIT_EXTENSION_ID = 'ctc-oss.omega-edit-data-editor'
+export const OMEGA_EDIT_EXTENSION_API_VERSION = 1
+export const DAFFODIL_CURRENT_DATA_HIGHLIGHT_ID =
+  'apache-daffodil.current-data-byte'
+
+export type OmegaEditExternalHighlightKind =
+  | 'current'
+  | 'parsed'
+  | 'error'
+  | 'warning'
+  | 'breakpoint'
+  | 'secondary'
+
+export interface OmegaEditExternalHighlight {
+  id: string
+  offset: number
+  length: number
+  kind: OmegaEditExternalHighlightKind
+  label: string
+  source?: string
+}
+
+export interface OmegaEditEditorState {
+  uri: string
+  filePath: string
+  fileSize: number
+  externalHighlights: OmegaEditExternalHighlight[]
+}
+
+export interface OmegaEditEditorSelector {
+  uri?: vscode.Uri | string
+}
+
+export interface OmegaEditOpenOptions {
+  offset?: number
+}
+
+export interface OmegaEditExternalHighlightRequest
+  extends OmegaEditEditorSelector {
+  highlights: OmegaEditExternalHighlight[]
+  reveal?: boolean
+}
+
+export interface OmegaEditExtensionApi {
+  readonly extensionId: typeof OMEGA_EDIT_EXTENSION_ID
+  readonly version: typeof OMEGA_EDIT_EXTENSION_API_VERSION
+  readonly onDidChangeEditorState: vscode.Event<OmegaEditEditorState>
+  open(
+    uri: vscode.Uri,
+    options?: OmegaEditOpenOptions
+  ): Promise<OmegaEditEditorState | undefined>
+  getEditorState(
+    options?: vscode.Uri | string | OmegaEditEditorSelector
+  ): OmegaEditEditorState | undefined
+  setExternalHighlights(
+    request: OmegaEditExternalHighlightRequest
+  ): Promise<OmegaEditEditorState | undefined>
+  clearExternalHighlights(
+    options?: vscode.Uri | string | OmegaEditEditorSelector
+  ): OmegaEditEditorState | undefined
+}
+
+const openDataEditorUris = new Map<string, vscode.Uri>()
+let omegaEditApiPromise: Promise<OmegaEditExtensionApi> | undefined
+
+export function activate(ctx: vscode.ExtensionContext): void {
+  ctx.subscriptions.push(
+    vscode.commands.registerCommand(
+      DATA_EDITOR_COMMAND,
+      async (fileToEdit: string | vscode.Uri = '') =>
+        await openDataEditor(fileToEdit)
+    ),
+    vscode.debug.onDidReceiveDebugSessionCustomEvent((event) => {
+      void handleDaffodilDebugEvent(event)
+    }),
+    vscode.debug.onDidTerminateDebugSession(() => {
+      void clearDaffodilDataHighlights()
+    })

Review Comment:
   The `onDidTerminateDebugSession` subscription currently clears Data Editor 
highlights when *any* debug session ends (including non-DFDL sessions). This 
should be scoped to Daffodil debug sessions (type `dfdl`) so unrelated 
debugging doesn’t unexpectedly clear highlights.



##########
src/tests/runTest.ts:
##########
@@ -68,4 +77,26 @@ async function main() {
   }
 }
 
+function installOmegaEditDataEditorFixture(extensionsDir: string): string {
+  const source = path.resolve(
+    __dirname,
+    '../../src/tests/fixtures/omega-edit-data-editor'
+  )
+  const extensionFolderPrefix = 'ctc-oss.omega-edit-data-editor'
+  const destination = path.join(extensionsDir, 
`${extensionFolderPrefix}-0.0.0`)
+

Review Comment:
   The OmegaEdit fixture’s `package.json` version is `0.0.0-test`, but the 
folder name uses `-0.0.0`. While VS Code doesn’t strictly require these to 
match for a dev extension, keeping them consistent reduces confusion when 
inspecting the test extensions directory.



##########
src/dataEditor/omegaEditDataEditor.ts:
##########
@@ -0,0 +1,347 @@
+/*
+ * 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 path from 'path'
+import * as vscode from 'vscode'
+import {
+  DaffodilData,
+  dataEvent,
+  extractDaffodilEvent,
+} from '../daffodilDebugger/daffodil'
+import { substituteVSCodeEnvVariables } from '../utils'
+
+export const DATA_EDITOR_COMMAND = 'extension.data.edit'
+export const OMEGA_EDIT_EXTENSION_ID = 'ctc-oss.omega-edit-data-editor'
+export const OMEGA_EDIT_EXTENSION_API_VERSION = 1
+export const DAFFODIL_CURRENT_DATA_HIGHLIGHT_ID =
+  'apache-daffodil.current-data-byte'
+
+export type OmegaEditExternalHighlightKind =
+  | 'current'
+  | 'parsed'
+  | 'error'
+  | 'warning'
+  | 'breakpoint'
+  | 'secondary'
+
+export interface OmegaEditExternalHighlight {
+  id: string
+  offset: number
+  length: number
+  kind: OmegaEditExternalHighlightKind
+  label: string
+  source?: string
+}
+
+export interface OmegaEditEditorState {
+  uri: string
+  filePath: string
+  fileSize: number
+  externalHighlights: OmegaEditExternalHighlight[]
+}
+
+export interface OmegaEditEditorSelector {
+  uri?: vscode.Uri | string
+}
+
+export interface OmegaEditOpenOptions {
+  offset?: number
+}
+
+export interface OmegaEditExternalHighlightRequest
+  extends OmegaEditEditorSelector {
+  highlights: OmegaEditExternalHighlight[]
+  reveal?: boolean
+}
+
+export interface OmegaEditExtensionApi {
+  readonly extensionId: typeof OMEGA_EDIT_EXTENSION_ID
+  readonly version: typeof OMEGA_EDIT_EXTENSION_API_VERSION
+  readonly onDidChangeEditorState: vscode.Event<OmegaEditEditorState>
+  open(
+    uri: vscode.Uri,
+    options?: OmegaEditOpenOptions
+  ): Promise<OmegaEditEditorState | undefined>
+  getEditorState(
+    options?: vscode.Uri | string | OmegaEditEditorSelector
+  ): OmegaEditEditorState | undefined
+  setExternalHighlights(
+    request: OmegaEditExternalHighlightRequest
+  ): Promise<OmegaEditEditorState | undefined>
+  clearExternalHighlights(
+    options?: vscode.Uri | string | OmegaEditEditorSelector
+  ): OmegaEditEditorState | undefined
+}
+
+const openDataEditorUris = new Map<string, vscode.Uri>()
+let omegaEditApiPromise: Promise<OmegaEditExtensionApi> | undefined
+
+export function activate(ctx: vscode.ExtensionContext): void {
+  ctx.subscriptions.push(
+    vscode.commands.registerCommand(
+      DATA_EDITOR_COMMAND,
+      async (fileToEdit: string | vscode.Uri = '') =>
+        await openDataEditor(fileToEdit)
+    ),
+    vscode.debug.onDidReceiveDebugSessionCustomEvent((event) => {
+      void handleDaffodilDebugEvent(event)
+    }),
+    vscode.debug.onDidTerminateDebugSession(() => {
+      void clearDaffodilDataHighlights()
+    })
+  )
+}
+
+export async function openDataEditor(
+  fileToEdit: string | vscode.Uri = ''
+): Promise<OmegaEditEditorState | undefined> {
+  const dataUri = await resolveDataFileUri(fileToEdit)
+  if (!dataUri) return undefined
+
+  const api = await getOmegaEditApiForUserAction()
+  if (!api) return undefined
+
+  const state = await api.open(dataUri)
+  if (state) {
+    openDataEditorUris.set(dataUri.toString(), dataUri)
+  }
+  return state
+}
+
+export async function resolveDataFileUri(
+  fileToEdit: string | vscode.Uri = ''
+): Promise<vscode.Uri | undefined> {
+  if (fileToEdit instanceof vscode.Uri) {
+    return fileToEdit
+  }
+
+  const dataPath = fileToEdit.trim()
+  if (dataPath.length === 0) {
+    const fileUri = await vscode.window.showOpenDialog({
+      canSelectMany: false,
+      openLabel: 'Select',
+      canSelectFiles: true,
+      canSelectFolders: false,
+      title: 'Select Data File',
+    })
+
+    if (!fileUri || !fileUri[0]) {
+      vscode.window.showInformationMessage(
+        'Data Editor file opening cancelled.'
+      )
+      return undefined
+    }
+
+    return fileUri[0]
+  }
+
+  const uri = dataPathLooksLikeUri(dataPath)
+    ? vscode.Uri.parse(dataPath)
+    : vscode.Uri.file(resolveDataPath(dataPath))
+
+  try {
+    const stat = await vscode.workspace.fs.stat(uri)
+    if ((stat.type & vscode.FileType.File) === 0) {
+      vscode.window.showErrorMessage(
+        `Data Editor can only open files: ${uri.fsPath || uri.toString()}`
+      )
+      return undefined
+    }
+  } catch {
+    vscode.window.showErrorMessage(
+      `Data Editor file does not exist: ${uri.fsPath || uri.toString()}`
+    )
+    return undefined
+  }
+
+  return uri
+}
+
+export function buildDaffodilDataHighlight(
+  bytePos1b: number,
+  fileSize: number
+): OmegaEditExternalHighlight | undefined {
+  if (
+    !Number.isFinite(bytePos1b) ||
+    !Number.isInteger(bytePos1b) ||
+    bytePos1b < 1 ||
+    !Number.isFinite(fileSize) ||
+    fileSize < 1
+  ) {
+    return undefined
+  }
+
+  const offset = Math.min(bytePos1b - 1, fileSize - 1)
+  return {
+    id: DAFFODIL_CURRENT_DATA_HIGHLIGHT_ID,
+    offset,
+    length: 1,
+    kind: 'current',
+    label: `Daffodil parser byte ${bytePos1b}`,
+    source: 'Apache Daffodil',
+  }
+}
+
+async function handleDaffodilDebugEvent(
+  event: vscode.DebugSessionCustomEvent
+): Promise<void> {
+  if (openDataEditorUris.size === 0) return
+
+  const daffodilEvent = extractDaffodilEvent(event)
+  if (daffodilEvent?.event !== dataEvent) return
+
+  const body = daffodilEvent.body as DaffodilData
+  let api: OmegaEditExtensionApi
+  try {
+    api = await getOmegaEditApi()
+  } catch {
+    return
+  }
+
+  for (const [key, uri] of openDataEditorUris) {
+    const editorState = api.getEditorState(uri)
+    if (!editorState) {
+      openDataEditorUris.delete(key)
+      continue
+    }
+
+    const highlight = buildDaffodilDataHighlight(
+      body.bytePos1b,
+      editorState.fileSize
+    )
+    if (!highlight) continue
+
+    await api.setExternalHighlights({
+      uri,
+      highlights: [highlight],
+      reveal: true,
+    })
+  }

Review Comment:
   `handleDaffodilDebugEvent()` is invoked from an event handler via `void ...` 
and this loop contains awaited calls that can throw/reject (e.g. editor closed, 
OmegaEdit API errors). As written, a rejection here becomes an unhandled 
promise rejection. Wrap the per-URI work in a try/catch and drop the URI (or 
otherwise swallow/log) on failures so the extension remains stable during 
debugging.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to