Procházet zdrojové kódy

feat(desktop): lsp diagnostics displayed

Adam před 2 měsíci
rodič
revize
0c7a297b1d

+ 36 - 0
packages/ui/src/components/message-part.css

@@ -272,3 +272,39 @@
     }
     }
   }
   }
 }
 }
+
+[data-component="diagnostics"] {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+  padding: 8px 12px;
+  background-color: var(--surface-critical-weak);
+  border-top: 1px solid var(--border-critical-base);
+
+  [data-slot="diagnostic"] {
+    display: flex;
+    align-items: baseline;
+    gap: 6px;
+    font-family: var(--font-family-mono);
+    font-size: var(--font-size-small);
+    line-height: var(--line-height-large);
+  }
+
+  [data-slot="diagnostic-label"] {
+    color: var(--text-on-critical-base);
+    font-weight: var(--font-weight-medium);
+    text-transform: uppercase;
+    letter-spacing: -0.5px;
+    flex-shrink: 0;
+  }
+
+  [data-slot="diagnostic-location"] {
+    color: var(--text-on-critical-weak);
+    flex-shrink: 0;
+  }
+
+  [data-slot="diagnostic-message"] {
+    color: var(--text-on-critical-base);
+    word-break: break-word;
+  }
+}

+ 43 - 1
packages/ui/src/components/message-part.tsx

@@ -1,4 +1,4 @@
-import { Component, createMemo, For, Match, Show, Switch } from "solid-js"
+import { Component, createMemo, For, Match, Show, Switch, type JSX } from "solid-js"
 import { Dynamic } from "solid-js/web"
 import { Dynamic } from "solid-js/web"
 import {
 import {
   AssistantMessage,
   AssistantMessage,
@@ -22,6 +22,44 @@ import { Markdown } from "./markdown"
 import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path"
 import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path"
 import { checksum } from "@opencode-ai/util/encode"
 import { checksum } from "@opencode-ai/util/encode"
 
 
+interface Diagnostic {
+  range: {
+    start: { line: number; character: number }
+    end: { line: number; character: number }
+  }
+  message: string
+  severity?: number
+}
+
+function getDiagnostics(
+  diagnosticsByFile: Record<string, Diagnostic[]> | undefined,
+  filePath: string | undefined,
+): Diagnostic[] {
+  if (!diagnosticsByFile || !filePath) return []
+  const diagnostics = diagnosticsByFile[filePath] ?? []
+  return diagnostics.filter((d) => d.severity === 1).slice(0, 3)
+}
+
+function DiagnosticsDisplay(props: { diagnostics: Diagnostic[] }): JSX.Element {
+  return (
+    <Show when={props.diagnostics.length > 0}>
+      <div data-component="diagnostics">
+        <For each={props.diagnostics}>
+          {(diagnostic) => (
+            <div data-slot="diagnostic">
+              <span data-slot="diagnostic-label">Error</span>
+              <span data-slot="diagnostic-location">
+                [{diagnostic.range.start.line + 1}:{diagnostic.range.start.character + 1}]
+              </span>
+              <span data-slot="diagnostic-message">{diagnostic.message}</span>
+            </div>
+          )}
+        </For>
+      </div>
+    </Show>
+  )
+}
+
 export interface MessageProps {
 export interface MessageProps {
   message: MessageType
   message: MessageType
   parts: PartType[]
   parts: PartType[]
@@ -444,6 +482,7 @@ ToolRegistry.register({
   name: "edit",
   name: "edit",
   render(props) {
   render(props) {
     const diffComponent = useDiffComponent()
     const diffComponent = useDiffComponent()
+    const diagnostics = createMemo(() => getDiagnostics(props.metadata.diagnostics, props.input.filePath))
     return (
     return (
       <BasicTool
       <BasicTool
         defaultOpen
         defaultOpen
@@ -482,6 +521,7 @@ ToolRegistry.register({
             />
             />
           </div>
           </div>
         </Show>
         </Show>
+        <DiagnosticsDisplay diagnostics={diagnostics()} />
       </BasicTool>
       </BasicTool>
     )
     )
   },
   },
@@ -491,6 +531,7 @@ ToolRegistry.register({
   name: "write",
   name: "write",
   render(props) {
   render(props) {
     const codeComponent = useCodeComponent()
     const codeComponent = useCodeComponent()
+    const diagnostics = createMemo(() => getDiagnostics(props.metadata.diagnostics, props.input.filePath))
     return (
     return (
       <BasicTool
       <BasicTool
         defaultOpen
         defaultOpen
@@ -523,6 +564,7 @@ ToolRegistry.register({
             />
             />
           </div>
           </div>
         </Show>
         </Show>
+        <DiagnosticsDisplay diagnostics={diagnostics()} />
       </BasicTool>
       </BasicTool>
     )
     )
   },
   },