p-doom/crowd-code-dataset-0.2 huggingface dataset:
[content] src/extension.ts (typescript)
// -------------------- Mock Actions (offline/local debug) --------------------
function buildMockPlan(editor: vscode.TextEditor): PlannedAction[] {
	const cursor = editor.selection.active;
	const insertPosition: [number, number] = [cursor.line, cursor.character];
	const selections = [
		{ start: [cursor.line, cursor.character] as [number, number], end: [cursor.line, cursor.character] as [number, number] }
	];
	return [
		{ kind: 'showTextDocument' },
		{ kind: 'setSelections', selections },
		{ kind: 'editInsert', position: insertPosition, text: '// crowd-pilot mock insert
' },
		{ kind: 'terminalShow' },
		{ kind: 'terminalSendText', text: 'echo "[crowd-pilot] mock run"' }
	];
}
[content] src/extension.ts (typescript)
	const testRun = vscode.commands.registerCommand('crowd-pilot.testRun', async () => {
		const editor = vscode.window.activeTextEditor;
		if (!editor) {
			return;
		}
		try {
			const plan = buildMockPlan(editor);
			if (!previewVisible) {
				showPreviewUI(plan);
				return;
			}
			const runPlan = currentPlan ?? plan;
			hidePreviewUI();
			await executePlan(runPlan);
			vscode.window.showInformationMessage('All actions emitted (mock)');
		} catch (err) {
			const errorMessage = err instanceof Error ? err.message : String(err);
			vscode.window.showErrorMessage(`Mock run failed: ${errorMessage}`);
		}
	});

	context.subscriptions.push(hideUi, sglangTest, modelRun, testRun);
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const trimText = (t: string) => {
		const oneLine = t.replace(/
?
/g, '\
');
		return oneLine.length > 80 ? oneLine.slice(0, 77) + '…' : oneLine;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: ` ⟶ insert "${trimText(next.text)}"`,
				color: new vscode.ThemeColor('editorCodeLens.foreground'),
				fontStyle: 'italic',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,0,0,0.12)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			after: {
				contentText: ` ⟶ replace with "${trimText(next.text)}"`,
				color: new vscode.ThemeColor('editorCodeLens.foreground'),
				fontStyle: 'italic'
			}
		});
		editor.setDecorations(decorationReplaceType, [{ range }]);
[content] src/extension.ts (typescript)
let decorationInsertType: vscode.TextEditorDecorationType | undefined;
let decorationDeleteType: vscode.TextEditorDecorationType | undefined;
let decorationReplaceType: vscode.TextEditorDecorationType | undefined;

function disposePreviewDecorations() {
	try { decorationInsertType?.dispose(); } catch {}
	try { decorationDeleteType?.dispose(); } catch {}
	try { decorationReplaceType?.dispose(); } catch {}
	decorationInsertType = undefined;
	decorationDeleteType = undefined;
	decorationReplaceType = undefined;
}
[content] src/extension.ts (typescript)
		if (action.kind === 'editDelete') {
			const range = new vscode.Range(
				new vscode.Position(action.range.start[0], action.range.start[1]),
				new vscode.Position(action.range.end[0], action.range.end[1])
			);
			await editor.edit((e: vscode.TextEditorEdit) => e.delete(range));
			continue;
		}
		if (action.kind === 'editReplace') {
			const range = new vscode.Range(
				new vscode.Position(action.range.start[0], action.range.start[1]),
				new vscode.Position(action.range.end[0], action.range.end[1])
			);
			await editor.edit((e: vscode.TextEditorEdit) => e.replace(range, action.text));
			continue;
		}
[content] src/extension.ts (typescript)
	const items: (vscode.QuickPickItem & { index: number })[] = plan.map((action, index) => {
		switch (action.kind) {
			case 'showTextDocument':
				return { index, label: '$(file) Focus active text document' };
			case 'setSelections':
				{
					const cursors = action.selections.map(s => `(${s.start[0]}, ${s.start[1]})`).join(', ');
					return { index, label: `$(cursor) Move cursor to ${cursors}` };
				}
			case 'editInsert':
				return { index, label: `$(pencil) Insert "${action.text.replace(/
/g, '\
')}" at (${action.position[0]}, ${action.position[1]})` };
			case 'terminalShow':
				return { index, label: '$(terminal) Focus terminal' };
			case 'terminalSendText':
				return { index, label: `$(terminal) Run "${action.text}" in terminal` };
		}
	});
    if (!previewQuickPick) {
        previewQuickPick = vscode.window.createQuickPick<(vscode.QuickPickItem & { index: number })>();
		previewQuickPick.title = 'crowd-pilot: preview';
		previewQuickPick.matchOnDetail = true;
		previewQuickPick.ignoreFocusOut = true;
		previewQuickPick.canSelectMany = false;
        previewQuickPick.onDidAccept(async () => {
            const qp = previewQuickPick!;
            const selected = qp.selectedItems?.[0];
            qp.hide();
            if (selected) {
                await executePlan([plan[selected.index]]);
                vscode.window.showInformationMessage('Action executed');
            }
        });
		previewQuickPick.onDidHide(() => {
			previewVisible = false;
			vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
			try { previewQuickPick?.dispose(); } catch {}
			previewQuickPick = undefined;
		});
[content] src/extension.ts (typescript)
			case 'editDelete': {
				const start = Array.isArray((item as any).range?.start) && (item as any).range.start.length === 2 ? [Number((item as any).range.start[0]) || 0, Number((item as any).range.start[1]) || 0] as [number, number] : [0, 0] as [number, number];
				const end = Array.isArray((item as any).range?.end) && (item as any).range.end.length === 2 ? [Number((item as any).range.end[0]) || 0, Number((item as any).range.end[1]) || 0] as [number, number] : [0, 0] as [number, number];
				result.push({ kind: 'editDelete', range: { start, end } });
				break;
			}
			case 'editReplace': {
				const start = Array.isArray((item as any).range?.start) && (item as any).range.start.length === 2 ? [Number((item as any).range.start[0]) || 0, Number((item as any).range.start[1]) || 0] as [number, number] : [0, 0] as [number, number];
				const end = Array.isArray((item as any).range?.end) && (item as any).range.end.length === 2 ? [Number((item as any).range.end[0]) || 0, Number((item as any).range.end[1]) || 0] as [number, number] : [0, 0] as [number, number];
				const text = typeof (item as any).text === 'string' ? (item as any).text : '';
				result.push({ kind: 'editReplace', range: { start, end }, text });
				break;
			}
[content] src/extension.ts (typescript)
			const action = currentPlan?.[0] ?? getHardcodedNextAction(editor);
			if (!action) {
				hidePreviewUI();
				return;
			}
			hidePreviewUI();
			await executePlan([action]);
			advanceMockStep();
			const next = getHardcodedNextAction(editor);
			if (next) {
				showPreviewUI([next]);
			} else {
				vscode.window.showInformationMessage('All actions emitted (mock)');
			}
[content] src/extension.ts (typescript)
let decorationInsertType: vscode.TextEditorDecorationType | undefined;
let decorationDeleteType: vscode.TextEditorDecorationType | undefined;
let decorationReplaceType: vscode.TextEditorDecorationType | undefined;
let mockStep = 0;

function disposePreviewDecorations() {
	try { decorationInsertType?.dispose(); } catch {}
	try { decorationDeleteType?.dispose(); } catch {}
	try { decorationReplaceType?.dispose(); } catch {}
	decorationInsertType = undefined;
	decorationDeleteType = undefined;
	decorationReplaceType = undefined;
}
[content] src/extension.ts (typescript)
// -------------------- Hardcoded single-step actions --------------------
function getHardcodedNextAction(editor: vscode.TextEditor): PlannedAction | undefined {
	const cursor = editor.selection.active;
	const doc = editor.document;
	const line = doc.lineAt(cursor.line);

	// Step 0: Insert a mock line at cursor
	if (mockStep === 0) {
		return { kind: 'editInsert', position: [cursor.line, cursor.character], text: '// crowd-pilot mock insert
' };
	}
	// Step 1: Replace current line content
	if (mockStep === 1) {
		const range = { start: [line.range.start.line, line.range.start.character] as [number, number], end: [line.range.end.line, line.range.end.character] as [number, number] };
		return { kind: 'editReplace', range, text: `${line.text} // replaced by crowd-pilot` };
	}
	// Step 2: Delete current line content
	if (mockStep === 2) {
		const range = { start: [line.range.start.line, line.range.start.character] as [number, number], end: [line.range.end.line, line.range.end.character] as [number, number] };
		return { kind: 'editDelete', range };
	}
	return undefined;
}

function advanceMockStep(): void {
	mockStep = (mockStep + 1) % 3;
}
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const trimText = (t: string) => {
		const oneLine = t.replace(/
?
/g, '\
');
		return oneLine.length > 80 ? oneLine.slice(0, 77) + '…' : oneLine;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: ` ⟶ insert "${trimText(next.text)}"`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
			after: {
				contentText: ` ⟶ replace with "${trimText(next.text)}"`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600'
			}
		});
		editor.setDecorations(decorationReplaceType, [{ range }]);
[content] src/extension.ts (typescript)
	// Auto-preview listeners
	const onSelChange = vscode.window.onDidChangeTextEditorSelection((e) => {
		if (e.textEditor === vscode.window.activeTextEditor) {
			suppressAutoPreview = false;
			autoShowNextAction();
		}
	});
	const onActiveChange = vscode.window.onDidChangeActiveTextEditor(() => {
		suppressAutoPreview = false;
		autoShowNextAction();
	});
	const onDocChange = vscode.workspace.onDidChangeTextDocument((e) => {
		if (vscode.window.activeTextEditor?.document === e.document) {
			suppressAutoPreview = false;
			autoShowNextAction();
		}
	});

	context.subscriptions.push(hideUi, sglangTest, modelRun, testRun, onSelChange, onActiveChange, onDocChange);
[content] src/extension.ts (typescript)
	if (suppress) {
		suppressAutoPreview = true;
	}
}

// -------------------- Hardcoded single-step actions --------------------
function getHardcodedNextAction(editor: vscode.TextEditor): PlannedAction | undefined {
	const cursor = editor.selection.active;
	const doc = editor.document;
	const line = doc.lineAt(cursor.line);

	// Step 0: Insert a mock line at cursor
	if (mockStep === 0) {
		return { kind: 'editInsert', position: [cursor.line, cursor.character], text: '// crowd-pilot mock insert
' };
	}
	// Step 1: Replace current line content
	if (mockStep === 1) {
		const range = { start: [line.range.start.line, line.range.start.character] as [number, number], end: [line.range.end.line, line.range.end.character] as [number, number] };
		return { kind: 'editReplace', range, text: `${line.text} // replaced by crowd-pilot` };
	}
	// Step 2: Delete current line content
	if (mockStep === 2) {
		const range = { start: [line.range.start.line, line.range.start.character] as [number, number], end: [line.range.end.line, line.range.end.character] as [number, number] };
		return { kind: 'editDelete', range };
	}
	return undefined;
}

function advanceMockStep(): void {
	mockStep = (mockStep + 1) % 3;
}

function autoShowNextAction(): void {
	if (suppressAutoPreview) { return; }
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	const next = getHardcodedNextAction(editor);
	if (next) {
		showPreviewUI([next]);
	} else {
		hidePreviewUI();
	}
[content] src/extension.ts (typescript)
let decorationInsertType: vscode.TextEditorDecorationType | undefined;
let decorationDeleteType: vscode.TextEditorDecorationType | undefined;
let decorationReplaceType: vscode.TextEditorDecorationType | undefined;
let mockStep = 0;
let suppressAutoPreview = false;

function disposePreviewDecorations() {
	try { decorationInsertType?.dispose(); } catch {}
	try { decorationDeleteType?.dispose(); } catch {}
	try { decorationReplaceType?.dispose(); } catch {}
	decorationInsertType = undefined;
	decorationDeleteType = undefined;
	decorationReplaceType = undefined;
}
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const trimText = (t: string) => {
		const oneLine = t.replace(/
?
/g, '\
');
		return oneLine.length > 80 ? oneLine.slice(0, 77) + '…' : oneLine;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
			after: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600'
			}
		});
		editor.setDecorations(decorationReplaceType, [{ range }]);
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const trimText = (t: string) => {
		const oneLine = t.replace(/
?
/g, '\
');
		return oneLine.length > 80 ? oneLine.slice(0, 77) + '…' : oneLine;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			color: new vscode.ThemeColor('disabledForeground'),
			before: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600'
			}
		});
		editor.setDecorations(decorationReplaceType, [{ range }]);
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const trimText = (t: string) => {
		const oneLine = t.replace(/
?
/g, '\
');
		return oneLine.length > 80 ? oneLine.slice(0, 77) + '…' : oneLine;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
			color: new vscode.ThemeColor('disabledForeground'),
			before: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600'
			}
		});
		editor.setDecorations(decorationReplaceType, [{ range }]);
[content] src/extension.ts (typescript)
		const hover = new vscode.MarkdownString();
		hover.appendMarkdown('Replacement:
');
		hover.appendCodeblock(next.text, editor.document.languageId);
		editor.setDecorations(decorationReplaceType, [{ range, hoverMessage: hover }]);
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const trimText = (t: string) => {
		const oneLine = t.replace(/
?
/g, '\
');
		return oneLine.length > 80 ? oneLine.slice(0, 77) + '…' : oneLine;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
			color: new vscode.ThemeColor('disabledForeground'),
[content] src/extension.ts (typescript)
	const items: (vscode.QuickPickItem & { index: number })[] = plan.map((action, index) => {
		switch (action.kind) {
			case 'showTextDocument':
				return { index, label: '$(file) Focus active text document' };
			case 'setSelections':
				{
					const cursors = action.selections.map(s => `(${s.start[0]}, ${s.start[1]})`).join(', ');
					return { index, label: `$(cursor) Move cursor to ${cursors}` };
				}
			case 'editInsert':
				return { index, label: `$(pencil) Insert "${action.text.replace(/
/g, '\
')}" at (${action.position[0]}, ${action.position[1]})` };
			case 'terminalShow':
				return { index, label: '$(terminal) Focus terminal' };
			case 'terminalSendText':
				return { index, label: `$(terminal) Run "${action.text}" in terminal` };
		}
	});
    if (!previewQuickPick) {
        previewQuickPick = vscode.window.createQuickPick<(vscode.QuickPickItem & { index: number })>();
		previewQuickPick.title = 'crowd-pilot: preview';
		previewQuickPick.matchOnDetail = true;
		previewQuickPick.ignoreFocusOut = true;
		previewQuickPick.canSelectMany = false;
        previewQuickPick.onDidAccept(async () => {
            const qp = previewQuickPick!;
            const selected = qp.selectedItems?.[0];
            qp.hide();
            if (selected) {
                await executePlan([plan[selected.index]]);
                vscode.window.showInformationMessage('Action executed');
            }
        });
		previewQuickPick.onDidHide(() => {
			previewVisible = false;
			vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
			try { previewQuickPick?.dispose(); } catch {}
			previewQuickPick = undefined;
[content] src/extension.ts (typescript)
	// Auto-preview listeners
	const onSelChange = vscode.window.onDidChangeTextEditorSelection((e) => {
		if (e.textEditor === vscode.window.activeTextEditor) {
			suppressAutoPreview = false;
			autoShowNextAction();
		}
	});
	const onActiveChange = vscode.window.onDidChangeActiveTextEditor(() => {
		suppressAutoPreview = false;
		autoShowNextAction();
	});
	const onDocChange = vscode.workspace.onDidChangeTextDocument((e) => {
		if (vscode.window.activeTextEditor?.document === e.document) {
			suppressAutoPreview = false;
			autoShowNextAction();
		}
	});

	// CodeLens provider for replace preview popup
	replacePreviewProvider = new ReplacePreviewCodeLensProvider();
	const codelensReg = vscode.languages.registerCodeLensProvider({ pattern: '**/*' }, replacePreviewProvider);

	context.subscriptions.push(hideUi, sglangTest, modelRun, testRun, previewNoop, onSelChange, onActiveChange, onDocChange, codelensReg);
[content] src/extension.ts (typescript)
	if (suppress) {
		suppressAutoPreview = true;
	}
	currentReplacePreview = undefined;
	replacePreviewProvider?.refresh();
}

// -------------------- Hardcoded single-step actions --------------------
function getHardcodedNextAction(editor: vscode.TextEditor): PlannedAction | undefined {
	const cursor = editor.selection.active;
	const doc = editor.document;
	const line = doc.lineAt(cursor.line);

	// Step 0: Insert a mock line at cursor
	if (mockStep === 0) {
		return { kind: 'editInsert', position: [cursor.line, cursor.character], text: '// crowd-pilot mock insert
' };
	}
	// Step 1: Replace current line content
	if (mockStep === 1) {
		const range = { start: [line.range.start.line, line.range.start.character] as [number, number], end: [line.range.end.line, line.range.end.character] as [number, number] };
		return { kind: 'editReplace', range, text: `${line.text} // replaced by crowd-pilot` };
	}
	// Step 2: Delete current line content
	if (mockStep === 2) {
		const range = { start: [line.range.start.line, line.range.start.character] as [number, number], end: [line.range.end.line, line.range.end.character] as [number, number] };
		return { kind: 'editDelete', range };
	}
	return undefined;
}

function advanceMockStep(): void {
	mockStep = (mockStep + 1) % 3;
}

function autoShowNextAction(): void {
	if (suppressAutoPreview) { return; }
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	const next = getHardcodedNextAction(editor);
	if (next) {
		showPreviewUI([next]);
	} else {
		hidePreviewUI();
	}
}

class ReplacePreviewCodeLensProvider implements vscode.CodeLensProvider {
	private emitter = new vscode.EventEmitter<void>();
	public onDidChangeCodeLenses = this.emitter.event;
	refresh(): void { this.emitter.fire(); }
	provideCodeLenses(document: vscode.TextDocument): vscode.ProviderResult<vscode.CodeLens[]> {
		if (!previewVisible || !currentReplacePreview) { return []; }
		if (document.uri.toString() !== currentReplacePreview.uri.toString()) { return []; }
		const startLine = currentReplacePreview.range.start.line;
		const range = new vscode.Range(startLine, 0, startLine, 0);
		const title = currentReplacePreview.text.length > 120
			? currentReplacePreview.text.slice(0, 117).replace(/\s+/g, ' ') + '…'
			: currentReplacePreview.text.replace(/\s+/g, ' ');
		const cmd: vscode.Command = {
			title,
			command: 'crowd-pilot.previewNoop',
			tooltip: 'Replacement preview'
		};
		return [new vscode.CodeLens(range, cmd)];
	}
[content] src/extension.ts (typescript)
		const hover = new vscode.MarkdownString();
		hover.appendMarkdown('Replacement:
');
		hover.appendCodeblock(next.text, editor.document.languageId);
		editor.setDecorations(decorationReplaceType, [{ range, hoverMessage: hover }]);
		currentReplacePreview = { uri: editor.document.uri, range, text: next.text };
		replacePreviewProvider?.refresh();
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const trimText = (t: string) => {
		const oneLine = t.replace(/
?
/g, '\
');
		return oneLine.length > 80 ? oneLine.slice(0, 77) + '…' : oneLine;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${trimText(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
		currentReplacePreview = undefined;
		replacePreviewProvider?.refresh();
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
			color: new vscode.ThemeColor('disabledForeground'),
[content] src/extension.ts (typescript)
let decorationInsertType: vscode.TextEditorDecorationType | undefined;
let decorationDeleteType: vscode.TextEditorDecorationType | undefined;
let decorationReplaceType: vscode.TextEditorDecorationType | undefined;
let mockStep = 0;
let suppressAutoPreview = false;
let replacePreviewProvider: ReplacePreviewCodeLensProvider | undefined;
let currentReplacePreview: { uri: vscode.Uri, range: vscode.Range, text: string } | undefined;

function disposePreviewDecorations() {
	try { decorationInsertType?.dispose(); } catch {}
	try { decorationDeleteType?.dispose(); } catch {}
	try { decorationReplaceType?.dispose(); } catch {}
	decorationInsertType = undefined;
	decorationDeleteType = undefined;
	decorationReplaceType = undefined;
}
[content] src/extension.ts (typescript)
		const hover = new vscode.MarkdownString();
		hover.appendMarkdown('Replacement:
');
		hover.appendCodeblock(next.text, editor.document.languageId);
		editor.setDecorations(decorationReplaceType, [{ range, hoverMessage: hover }]);
		currentReplacePreview = { uri: editor.document.uri, range, text: next.text };
		currentInsertPreview = undefined;
		replacePreviewProvider?.refresh();
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const oneLinePreview = (t: string) => {
		const idx = t.indexOf('
');
		const first = idx === -1 ? t : t.slice(0, idx) + ' …';
		return first.length > 80 ? first.slice(0, 77) + '…' : first;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${oneLinePreview(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
		// For multi-line inserts, show a persistent codelens with full content
		if (next.text.includes('
')) {
			currentInsertPreview = { uri: editor.document.uri, line: pos.line, text: next.text };
		} else {
			currentInsertPreview = undefined;
		}
		currentReplacePreview = undefined;
		replacePreviewProvider?.refresh();
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
		currentReplacePreview = undefined;
		currentInsertPreview = undefined;
		replacePreviewProvider?.refresh();
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
			color: new vscode.ThemeColor('disabledForeground'),
[content] src/extension.ts (typescript)
let decorationInsertType: vscode.TextEditorDecorationType | undefined;
let decorationDeleteType: vscode.TextEditorDecorationType | undefined;
let decorationReplaceType: vscode.TextEditorDecorationType | undefined;
let mockStep = 0;
let suppressAutoPreview = false;
let replacePreviewProvider: ReplacePreviewCodeLensProvider | undefined;
let currentReplacePreview: { uri: vscode.Uri, range: vscode.Range, text: string } | undefined;
let currentInsertPreview: { uri: vscode.Uri, line: number, text: string } | undefined;

function disposePreviewDecorations() {
	try { decorationInsertType?.dispose(); } catch {}
	try { decorationDeleteType?.dispose(); } catch {}
	try { decorationReplaceType?.dispose(); } catch {}
	decorationInsertType = undefined;
	decorationDeleteType = undefined;
	decorationReplaceType = undefined;
}
[content] src/extension.ts (typescript)
	if (suppress) {
		suppressAutoPreview = true;
	}
	currentInsertPreview = undefined;
}

// -------------------- Hardcoded single-step actions --------------------
function getHardcodedNextAction(editor: vscode.TextEditor): PlannedAction | undefined {
	const cursor = editor.selection.active;
	const doc = editor.document;
	const lineCount = doc.lineCount;
	const clamp = (n: number, min: number, max: number) => Math.max(min, Math.min(max, n));

	// Step 0: Insert multiline content two lines below the cursor (start of target line)
	if (mockStep === 0) {
		const targetLine = clamp(cursor.line + 2, 0, Math.max(0, lineCount - 1));
		return {
			kind: 'editInsert',
			position: [targetLine, 0],
			text: '/* crowd-pilot: insert start */
line A
line B
/* crowd-pilot: insert end */
'
		};
	}
	// Step 1: Replace a two-line range three and four lines below the cursor
	if (mockStep === 1) {
		const startLine = clamp(cursor.line + 3, 0, Math.max(0, lineCount - 1));
		const endLine = clamp(startLine + 1, 0, Math.max(0, lineCount - 1));
		const endChar = doc.lineAt(endLine).range.end.character;
		const range = {
			start: [startLine, 0] as [number, number],
			end: [endLine, endChar] as [number, number]
		};
		const replacement = [
			'/* crowd-pilot: replacement */',
			'REPLACED LINE 1',
			'REPLACED LINE 2'
		].join('
');
		return { kind: 'editReplace', range, text: replacement };
	}
	// Step 2: Delete a three-line range six to eight lines below the cursor
	if (mockStep === 2) {
		const startLine = clamp(cursor.line + 6, 0, Math.max(0, lineCount - 1));
		const endLine = clamp(startLine + 2, 0, Math.max(0, lineCount - 1));
		const endChar = doc.lineAt(endLine).range.end.character;
		const range = {
			start: [startLine, 0] as [number, number],
			end: [endLine, endChar] as [number, number]
		};
		return { kind: 'editDelete', range };
	}
	return undefined;
}

function advanceMockStep(): void {
	mockStep = (mockStep + 1) % 3;
}

function autoShowNextAction(): void {
	if (suppressAutoPreview) { return; }
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	const next = getHardcodedNextAction(editor);
	if (next) {
		showPreviewUI([next]);
	} else {
		hidePreviewUI();
	}
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const oneLinePreview = (t: string) => {
		const idx = t.indexOf('
');
		const first = idx === -1 ? t : t.slice(0, idx) + ' …';
		return first.length > 80 ? first.slice(0, 77) + '…' : first;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${oneLinePreview(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
		currentInsertPreview = undefined;
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
		currentInsertPreview = undefined;
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
[content] src/extension.ts (typescript)
let decorationInsertType: vscode.TextEditorDecorationType | undefined;
let decorationDeleteType: vscode.TextEditorDecorationType | undefined;
let decorationReplaceType: vscode.TextEditorDecorationType | undefined;
let mockStep = 0;
let suppressAutoPreview = false;
let currentReplacePreview: undefined;
let currentInsertPreview: undefined;

function disposePreviewDecorations() {
	try { decorationInsertType?.dispose(); } catch {}
	try { decorationDeleteType?.dispose(); } catch {}
	try { decorationReplaceType?.dispose(); } catch {}
	decorationInsertType = undefined;
	decorationDeleteType = undefined;
	decorationReplaceType = undefined;
}
[content] src/extension.ts (typescript)
			await editor.insertSnippet(new vscode.SnippetString(action.text), new vscode.Position(action.position[0], action.position[1]));
			continue;
		}
		if (action.kind === 'editDelete') {
			const range = new vscode.Range(
				new vscode.Position(action.range.start[0], action.range.start[1]),
				new vscode.Position(action.range.end[0], action.range.end[1])
			);
			await editor.edit((e: vscode.TextEditorEdit) => e.delete(range));
			continue;
		}
		if (action.kind === 'editReplace') {
			const range = new vscode.Range(
				new vscode.Position(action.range.start[0], action.range.start[1]),
				new vscode.Position(action.range.end[0], action.range.end[1])
			);
			await editor.insertSnippet(new vscode.SnippetString(action.text), range);
[content] src/extension.ts (typescript)
// -------------------- Hardcoded single-step actions --------------------
function getHardcodedNextAction(editor: vscode.TextEditor): PlannedAction | undefined {
	const cursor = editor.selection.active;
	const doc = editor.document;
	const lineCount = doc.lineCount;
	const clamp = (n: number, min: number, max: number) => Math.max(min, Math.min(max, n));

	// Step 0: Insert multiline content two lines below the cursor (start of target line)
	if (mockStep === 0) {
		const targetLine = clamp(cursor.line + 2, 0, Math.max(0, lineCount - 1));
		return {
			kind: 'editInsert',
			position: [targetLine, 0],
			text: '/* crowd-pilot: insert start */
line A
line B
/* crowd-pilot: insert end */
'
		};
	}
	// Step 1: Replace a two-line range three and four lines below the cursor
	if (mockStep === 1) {
		const startLine = clamp(cursor.line + 3, 0, Math.max(0, lineCount - 1));
		const endLine = clamp(startLine + 1, 0, Math.max(0, lineCount - 1));
		const endChar = doc.lineAt(endLine).range.end.character;
		const range = {
			start: [startLine, 0] as [number, number],
			end: [endLine, endChar] as [number, number]
		};
		const replacement = [
			'/* crowd-pilot: replacement */',
			'REPLACED LINE 1',
			'REPLACED LINE 2'
		].join('
');
		return { kind: 'editReplace', range, text: replacement };
	}
	// Step 2: Delete a three-line range six to eight lines below the cursor
	if (mockStep === 2) {
		const startLine = clamp(cursor.line + 6, 0, Math.max(0, lineCount - 1));
		const endLine = clamp(startLine + 2, 0, Math.max(0, lineCount - 1));
		const endChar = doc.lineAt(endLine).range.end.character;
		const range = {
			start: [startLine, 0] as [number, number],
			end: [endLine, endChar] as [number, number]
		};
		return { kind: 'editDelete', range };
	}
	return undefined;
}

function advanceMockStep(): void {
	mockStep = (mockStep + 1) % 3;
}

function autoShowNextAction(): void {
	if (suppressAutoPreview) { return; }
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	const next = getHardcodedNextAction(editor);
	if (next) {
		showPreviewUI([next]);
	} else {
		hidePreviewUI();
	}
}

// (CodeLens-based previews removed for reliability)
[content] src/extension.ts (typescript)
	const editor = vscode.window.activeTextEditor;
	if (!editor) { return; }
	disposePreviewDecorations();

	// Only preview the next text edit action (insert/delete/replace)
	const next = plan.find(a => a.kind === 'editInsert' || a.kind === 'editDelete' || a.kind === 'editReplace');
	if (!next) {
		previewVisible = false;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		currentPlan = plan;
		return;
	}

	const oneLinePreview = (t: string) => {
		const idx = t.indexOf('
');
		const first = idx === -1 ? t : t.slice(0, idx) + ' …';
		return first.length > 80 ? first.slice(0, 77) + '…' : first;
	};

	if (next.kind === 'editInsert') {
		const pos = new vscode.Position(next.position[0], next.position[1]);
		decorationInsertType = vscode.window.createTextEditorDecorationType({
			after: {
				contentText: `${oneLinePreview(next.text)}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600',
			}
		});
		editor.setDecorations(decorationInsertType, [{ range: new vscode.Range(pos, pos) }]);
		currentInsertPreview = undefined;
	} else if (next.kind === 'editDelete') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationDeleteType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255, 60, 60, 0.18)',
			border: '1px solid rgba(255, 60, 60, 0.35)',
			textDecoration: 'line-through'
		});
		editor.setDecorations(decorationDeleteType, [{ range }]);
		currentInsertPreview = undefined;
	} else if (next.kind === 'editReplace') {
		const range = new vscode.Range(
			new vscode.Position(next.range.start[0], next.range.start[1]),
			new vscode.Position(next.range.end[0], next.range.end[1])
		);
		decorationReplaceType = vscode.window.createTextEditorDecorationType({
			backgroundColor: 'rgba(255,165,0,0.15)',
			border: '1px dashed rgba(255,165,0,0.45)',
		});
		editor.setDecorations(decorationReplaceType, [{ range }]);
		// Show a concise inline preview at the start of the first line
		const previewFirst = next.text.split(/
?
/);
		const firstLineText = previewFirst[0] ?? '';
		const extraCount = previewFirst.length > 1 ? previewFirst.length - 1 : 0;
		const suffix = extraCount > 0 ? ` … (+${extraCount} line${extraCount > 1 ? 's' : ''})` : '';
		const startPos = new vscode.Position(next.range.start[0], next.range.start[1]);
		decorationReplacePreviewTextType = vscode.window.createTextEditorDecorationType({
			before: {
				contentText: `${firstLineText}${suffix}`,
				color: new vscode.ThemeColor('charts.purple'),
				fontStyle: 'italic',
				fontWeight: '600'
			}
		});
		editor.setDecorations(decorationReplacePreviewTextType, [{ range: new vscode.Range(startPos, startPos) }]);
		currentInsertPreview = undefined;
[content] src/extension.ts (typescript)
let decorationInsertType: vscode.TextEditorDecorationType | undefined;
let decorationDeleteType: vscode.TextEditorDecorationType | undefined;
let decorationReplaceType: vscode.TextEditorDecorationType | undefined;
let decorationReplacePreviewTextType: vscode.TextEditorDecorationType | undefined;
let mockStep = 0;
let suppressAutoPreview = false;
let currentReplacePreview: undefined;
let currentInsertPreview: undefined;

function disposePreviewDecorations() {
	try { decorationInsertType?.dispose(); } catch {}
	try { decorationDeleteType?.dispose(); } catch {}
	try { decorationReplaceType?.dispose(); } catch {}
	try { decorationReplacePreviewTextType?.dispose(); } catch {}
	decorationInsertType = undefined;
	decorationDeleteType = undefined;
	decorationReplaceType = undefined;
	decorationReplacePreviewTextType = undefined;
}