mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-31 16:33:34 +08:00
Replaces the bare 'LSP {state} . N diagnostics' span in the file preview header with the existing LspStatusIndicator component, which was already authored, tested, and shipped on main but had no parent rendering it.
What you now get on the workspace file preview header:
- Spinning loader for starting/idle, green check for ready, red alert with N error count when ready+errors, red retry button when unavailable
- Click the pill to open a diagnostics dropdown listing path:line:col plus truncated message; Enter on a row opens that file in the preview
- Retry button round-trips POST /api/sessions/:id/lsp/restart and re-reads state, since LspManager keeps unavailable workspaces sticky until an explicit restart
Type bridge:
- The server wire shape (WorkspaceLspState: idle/starting/ready/unavailable with an error string) does not carry LspUnavailableReason, but LspStatusIndicator was authored against the legacy four-state shape with reason+errorCount
- New pure adapter desktop/src/lib/lspStateMap.ts maps the two shapes: idle-as-starting, ready threads errorCount derived from severity=error diagnostics, unavailable collapses to init-failed (Retry path)
Tested:
- bunx vitest src/lib/lspStateMap.test.ts (8 cases — all four state transitions plus diagnostic severity counting)
- bunx vitest LspStatusIndicator + workspacePanelStore — 53/53 pass
- bun run lint (tsc --noEmit) clean
Not-tested: live-LSP retry round-trip (covered by lspManager server tests separately)
Confidence: high
Scope-risk: narrow
Co-authored-by: 你的姓名 <you@example.com>
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import type {
|
|
LspDiagnostic,
|
|
LegacyWorkspaceLspState,
|
|
WorkspaceLspState,
|
|
} from '../types/lsp'
|
|
|
|
/**
|
|
* Map the server-side {@link WorkspaceLspState} (one shape, four states
|
|
* including `idle`) onto the legacy four-state shape that
|
|
* {@link LspStatusIndicator} consumes.
|
|
*
|
|
* The indicator was authored against an earlier wire shape that exposed an
|
|
* `LspUnavailableReason`. The current server response only carries an `error`
|
|
* string, so unavailable states collapse to `init-failed` (Retry button) and
|
|
* never trigger the prereq-missing path. That is acceptable because the
|
|
* desktop's prereq UX lives in `PluginPrerequisitesModal`, reached from the
|
|
* Plugins page, not the workspace pill.
|
|
*/
|
|
export function toLegacyLspState(
|
|
state: WorkspaceLspState | undefined,
|
|
errorCount: number,
|
|
workspaceId: string,
|
|
): LegacyWorkspaceLspState {
|
|
// No state yet (loading, or never queried) — present as `starting` so the
|
|
// pill spins instead of flashing "unavailable".
|
|
if (!state || state.state === 'idle' || state.state === 'starting') {
|
|
return { state: 'starting', workspaceId, errorCount: 0 }
|
|
}
|
|
if (state.state === 'ready') {
|
|
return { state: 'ready', workspaceId, errorCount }
|
|
}
|
|
return {
|
|
state: 'unavailable',
|
|
workspaceId,
|
|
reason: 'init-failed',
|
|
errorCount: 0,
|
|
...(state.error ? { lastStderrTail: state.error } : {}),
|
|
}
|
|
}
|
|
|
|
/** Count how many diagnostics in a list are errors (not warnings/info/hints). */
|
|
export function errorCountFromDiagnostics(
|
|
diagnostics: readonly LspDiagnostic[] | undefined,
|
|
): number {
|
|
if (!diagnostics || diagnostics.length === 0) return 0
|
|
let count = 0
|
|
for (const d of diagnostics) {
|
|
if (d.severity === 'error') count += 1
|
|
}
|
|
return count
|
|
}
|