feat(ux): unify Ask-Claude-to-Edit on a split-below multi-line webview (#65)

This commit was merged in pull request #65.
This commit is contained in:
2026-06-26 13:50:31 +00:00
parent 56cc9eb6ad
commit 7e42d115c0
7 changed files with 180 additions and 147 deletions
+12 -15
View File
@@ -12,7 +12,6 @@ import { SidecarRouter } from "./sidecarRouter";
import { DiffViewController } from "./diffViewController";
import { TrackChangesPreviewController } from "./trackChangesPreview";
import { LiveProgressUi } from "./liveProgressUi";
import { InlineAskController } from "./inlineAsk";
import { isAuthorable, routeEdit, selectionRejection } from "./workspacePath";
const CHANNEL_NAME = "Cowriting (Cline SDK)";
@@ -26,7 +25,6 @@ export interface CowritingApi {
trackChangesPreviewController: TrackChangesPreviewController;
sidecarRouter: SidecarRouter;
liveProgressUi: LiveProgressUi;
inlineAsk: InlineAskController;
}
export function activate(context: vscode.ExtensionContext): CowritingApi | undefined {
@@ -38,11 +36,6 @@ export function activate(context: vscode.ExtensionContext): CowritingApi | undef
// OutputChannel) for both Ask-Claude entry points.
const liveProgressUi = new LiveProgressUi();
context.subscriptions.push(liveProgressUi);
// The inline "Ask Claude to Edit" prompt — rendered at the selection/cursor via
// the Comments API rather than the top-center QuickInput (see inlineAsk.ts).
// Shared by both Ask-Claude entry points (editSelection + the preview's askClaude).
const inlineAsk = new InlineAskController(context.subscriptions);
context.subscriptions.push(
vscode.commands.registerCommand("cowriting.showClineSdkInfo", async () => {
try {
@@ -119,7 +112,6 @@ export function activate(context: vscode.ExtensionContext): CowritingApi | undef
attributionController,
proposalController,
liveProgressUi,
inlineAsk,
);
context.subscriptions.push(trackChangesPreviewController);
@@ -227,17 +219,23 @@ export function activate(context: vscode.ExtensionContext): CowritingApi | undef
if (!editor) return; // unreachable once reason is null, but narrows the type
const document = editor.document;
const selection = editor.selection; // non-empty (selectionRejection guaranteed it)
// The instruction prompt opens INLINE at the selection (inlineAsk), not the
// top-center QuickInput — anchored to the text Claude will edit.
const instruction = await inlineAsk.prompt(document.uri, selection);
if (!instruction) return;
// Capture the selection text + anchor BEFORE prompting — the inline prompt
// moves the cursor to the document top (where its box anchors), which would
// otherwise collapse the selection we act on (spec §6.5 PUC-1: anchor
// captured pre-turn so mid-turn edits can't skew it).
const selectedText = document.getText(selection);
// Capture the anchor BEFORE the turn (spec §6.5 PUC-1): mid-turn edits
// can't skew it — the proposal renders wherever the target re-resolves.
const fp = buildFingerprint(document.getText(), {
start: document.offsetAt(selection.start),
end: document.offsetAt(selection.end),
});
// The instruction prompt is the multi-line split-below webview box (shared
// with the document case, via the preview controller); the document above
// keeps the selection highlighted while it's open. selectedText/fp were
// captured above, so moving focus to the box doesn't affect what we edit.
const instruction = await trackChangesPreviewController.askEditInstruction(
"Ask Claude to Edit This Selection",
);
if (!instruction) return;
const turnId = `turn-${Date.now().toString(36)}`;
try {
await vscode.window.withProgress(
@@ -344,7 +342,6 @@ export function activate(context: vscode.ExtensionContext): CowritingApi | undef
trackChangesPreviewController,
sidecarRouter,
liveProgressUi,
inlineAsk,
};
}