F10: interactive track-changes review in the markdown preview (#29) #30
@@ -2,9 +2,11 @@
|
|||||||
* AttributionController — the thin editor-facing layer for F3 (spec §6.2).
|
* AttributionController — the thin editor-facing layer for F3 (spec §6.2).
|
||||||
* Wires the pure AttributionTracker + PendingEditRegistry + Store/Anchorer to
|
* Wires the pure AttributionTracker + PendingEditRegistry + Store/Anchorer to
|
||||||
* the editor: human typing → human spans, seam edits → agent spans (INV-9),
|
* the editor: human typing → human spans, seam edits → agent spans (INV-9),
|
||||||
* decorations (Claude tint / human gutter border / toggle), save-time
|
* save-time persistence, load/external-change resolve-or-orphan
|
||||||
* persistence, load/external-change resolve-or-orphan (INV-1/INV-6), and the
|
* (INV-1/INV-6), and the orphan status-bar count. The editor carries no
|
||||||
* orphan status-bar count. Sidecar self-write suppression and the shared
|
* in-editor attribution decorations — the rendered preview is the single
|
||||||
|
* review surface (F10/INV-32); spansFor() feeds it the live attribution.
|
||||||
|
* Sidecar self-write suppression and the shared
|
||||||
* FileSystemWatcher live in CoauthorStore / extension.ts (the sidecar is
|
* FileSystemWatcher live in CoauthorStore / extension.ts (the sidecar is
|
||||||
* co-owned with ThreadController).
|
* co-owned with ThreadController).
|
||||||
*/
|
*/
|
||||||
@@ -44,23 +46,10 @@ interface DocAttribution {
|
|||||||
hadAttributions: boolean;
|
hadAttributions: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AGENT_DECO: vscode.DecorationRenderOptions = {
|
|
||||||
backgroundColor: "rgba(99, 102, 241, 0.18)",
|
|
||||||
overviewRulerColor: "rgba(99, 102, 241, 0.8)",
|
|
||||||
overviewRulerLane: vscode.OverviewRulerLane.Right,
|
|
||||||
};
|
|
||||||
const HUMAN_DECO: vscode.DecorationRenderOptions = {
|
|
||||||
borderColor: "rgba(16, 185, 129, 0.8)",
|
|
||||||
borderStyle: "solid",
|
|
||||||
borderWidth: "0 0 0 2px",
|
|
||||||
};
|
|
||||||
|
|
||||||
export class AttributionController implements vscode.Disposable {
|
export class AttributionController implements vscode.Disposable {
|
||||||
private readonly disposables: vscode.Disposable[] = [];
|
private readonly disposables: vscode.Disposable[] = [];
|
||||||
private readonly docs = new Map<string, DocAttribution>();
|
private readonly docs = new Map<string, DocAttribution>();
|
||||||
private readonly pending = new PendingEditRegistry();
|
private readonly pending = new PendingEditRegistry();
|
||||||
private readonly agentType = vscode.window.createTextEditorDecorationType(AGENT_DECO);
|
|
||||||
private readonly humanType = vscode.window.createTextEditorDecorationType(HUMAN_DECO);
|
|
||||||
private readonly statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 90);
|
private readonly statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 90);
|
||||||
private readonly output = vscode.window.createOutputChannel("Cowriting Attribution");
|
private readonly output = vscode.window.createOutputChannel("Cowriting Attribution");
|
||||||
private visible = true;
|
private visible = true;
|
||||||
@@ -79,7 +68,7 @@ export class AttributionController implements vscode.Disposable {
|
|||||||
private readonly rootDir: string | undefined,
|
private readonly rootDir: string | undefined,
|
||||||
private readonly guard: VersionGuard,
|
private readonly guard: VersionGuard,
|
||||||
) {
|
) {
|
||||||
this.disposables.push(this.agentType, this.humanType, this.statusItem, this.output, this.applyEmitter);
|
this.disposables.push(this.statusItem, this.output, this.applyEmitter);
|
||||||
this.disposables.push(
|
this.disposables.push(
|
||||||
vscode.commands.registerCommand("cowriting.toggleAttribution", () => this.toggle()),
|
vscode.commands.registerCommand("cowriting.toggleAttribution", () => this.toggle()),
|
||||||
vscode.workspace.onDidChangeTextDocument((e) => this.onDidChange(e)),
|
vscode.workspace.onDidChangeTextDocument((e) => this.onDidChange(e)),
|
||||||
@@ -354,19 +343,6 @@ export class AttributionController implements vscode.Disposable {
|
|||||||
private render(document: vscode.TextDocument): void {
|
private render(document: vscode.TextDocument): void {
|
||||||
if (!this.isTracked(document)) return;
|
if (!this.isTracked(document)) return;
|
||||||
const s = this.docs.get(this.keyOf(document));
|
const s = this.docs.get(this.keyOf(document));
|
||||||
const spans = this.visible && s ? s.spans : [];
|
|
||||||
const toRange = (sp: LiveSpan) =>
|
|
||||||
new vscode.Range(document.positionAt(sp.start), document.positionAt(sp.end));
|
|
||||||
const agentRanges = spans.filter((x) => x.author.kind === "agent").map(toRange);
|
|
||||||
const humanRanges = spans.filter((x) => x.author.kind === "human").map(toRange);
|
|
||||||
// Apply decorations to ALL visible split-editors showing this document, not
|
|
||||||
// just the first match — each editor pane has its own decoration layer.
|
|
||||||
for (const editor of vscode.window.visibleTextEditors) {
|
|
||||||
if (editor.document === document) {
|
|
||||||
editor.setDecorations(this.agentType, agentRanges);
|
|
||||||
editor.setDecorations(this.humanType, humanRanges);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (document === vscode.window.activeTextEditor?.document) {
|
if (document === vscode.window.activeTextEditor?.document) {
|
||||||
this.renderStatus(s);
|
this.renderStatus(s);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user