feat(coding-agent): removed vim edit mode and migrated configs to hashline

- Removed vim edit mode and automatically map existing vim configurations to hashline mode.
- Deleted VimTool class, VimEngine implementation, and all vim-specific editing logic (2409 lines).
- Removed vim mode from EditMode union type, edit tool strategies, and configuration schemas.
- Deleted vim parser, command handler, buffer manager, and renderer modules.
- Updated documentation and tests to remove vim mode references and add deprecation mapping.
This commit is contained in:
can1357
2026-05-26 13:16:59 +02:00
parent 7f0208ac83
commit ea2f4b2557
21 changed files with 50 additions and 5726 deletions
+5 -36
View File
@@ -1,6 +1,5 @@
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
import { prompt } from "@oh-my-pi/pi-utils";
import type * as z from "zod/v4";
import {
executeHashlineSingle,
HashlineMismatchError,
@@ -21,9 +20,7 @@ import hashlineDescription from "../prompts/tools/hashline.md" with { type: "tex
import patchDescription from "../prompts/tools/patch.md" with { type: "text" };
import replaceDescription from "../prompts/tools/replace.md" with { type: "text" };
import type { ToolSession } from "../tools";
import { VimTool, vimSchema } from "../tools/vim";
import { type EditMode, normalizeEditMode, resolveEditMode } from "../utils/edit-mode";
import type { VimToolDetails } from "../vim/types";
import { type ApplyPatchParams, applyPatchSchema, expandApplyPatchToEntries } from "./modes/apply-patch";
import applyPatchGrammar from "./modes/apply-patch.lark" with { type: "text" };
import { executePatchSingle, type PatchEditEntry, type PatchParams, patchEditSchema } from "./modes/patch";
@@ -50,12 +47,9 @@ type TInput =
| typeof replaceEditSchema
| typeof patchEditSchema
| typeof hashlineEditParamsSchema
| typeof vimSchema
| typeof applyPatchSchema;
type VimParams = z.infer<typeof vimSchema>;
type EditParams = ReplaceParams | PatchParams | HashlineParams | VimParams | ApplyPatchParams;
type EditToolResultDetails = EditToolDetails | VimToolDetails;
type EditParams = ReplaceParams | PatchParams | HashlineParams | ApplyPatchParams;
type EditModeDefinition = {
description: (session: ToolSession) => string;
@@ -65,8 +59,8 @@ type EditModeDefinition = {
params: EditParams,
signal: AbortSignal | undefined,
batchRequest: LspBatchRequest | undefined,
onUpdate?: (partialResult: AgentToolResult<EditToolResultDetails, TInput>) => void,
) => Promise<AgentToolResult<EditToolResultDetails, TInput>>;
onUpdate?: (partialResult: AgentToolResult<EditToolDetails, TInput>) => void,
) => Promise<AgentToolResult<EditToolDetails, TInput>>;
};
function resolveConfiguredEditMode(rawEditMode: string): EditMode | undefined {
@@ -284,7 +278,6 @@ export class EditTool implements AgentTool<TInput> {
readonly #fuzzyThreshold: number;
readonly #writethrough: WritethroughCallback;
readonly #editMode?: EditMode;
readonly #vimTool: VimTool;
readonly #pendingDeferredFetches = new Map<string, AbortController>();
constructor(private readonly session: ToolSession) {
@@ -298,7 +291,6 @@ export class EditTool implements AgentTool<TInput> {
this.#allowFuzzy = resolveAllowFuzzy(session, editFuzzy);
this.#fuzzyThreshold = resolveFuzzyThreshold(session, editFuzzyThreshold);
this.#writethrough = createEditWritethrough(session);
this.#vimTool = new VimTool(session);
}
get mode(): EditMode {
@@ -341,9 +333,9 @@ export class EditTool implements AgentTool<TInput> {
_toolCallId: string,
params: EditParams,
signal?: AbortSignal,
onUpdate?: AgentToolUpdateCallback<EditToolResultDetails, TInput>,
onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>,
context?: AgentToolContext,
): Promise<AgentToolResult<EditToolResultDetails, TInput>> {
): Promise<AgentToolResult<EditToolDetails, TInput>> {
const modeDefinition = this.#getModeDefinition();
return modeDefinition.execute(this, params, signal, getLspBatchRequest(context?.toolCall), onUpdate);
}
@@ -460,29 +452,6 @@ export class EditTool implements AgentTool<TInput> {
return executeSinglePathEntries(path, runs, batchRequest, onUpdate);
},
},
vim: {
description: () => this.#vimTool.description,
parameters: vimSchema,
execute: async (
tool: EditTool,
params: EditParams,
signal: AbortSignal | undefined,
_batchRequest: LspBatchRequest | undefined,
onUpdate?: (partialResult: AgentToolResult<EditToolResultDetails, TInput>) => void,
) => {
const handleUpdate = onUpdate
? (partialResult: AgentToolResult<VimToolDetails>) => {
onUpdate(partialResult as AgentToolResult<EditToolResultDetails, TInput>);
}
: undefined;
return (await tool.#vimTool.execute(
"edit",
params as VimParams,
signal,
handleUpdate,
)) as AgentToolResult<EditToolResultDetails, TInput>;
},
},
}[this.mode];
}
+1 -41
View File
@@ -25,10 +25,8 @@ import {
shortenPath,
truncateDiffByHunk,
} from "../tools/render-utils";
import { type VimRenderArgs, vimToolRenderer } from "../tools/vim";
import { fileHyperlink, Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
import type { EditMode } from "../utils/edit-mode";
import type { VimToolDetails } from "../vim/types";
import type { DiffError, DiffResult } from "./diff";
import { type ApplyPatchEntry, expandApplyPatchToEntries, expandApplyPatchToPreviewEntries } from "./modes/apply-patch";
import type { Operation } from "./modes/patch";
@@ -127,31 +125,6 @@ interface ApplyPatchRenderSummary {
error?: string;
}
function isVimRenderArgs(args: EditRenderArgs | VimRenderArgs): args is VimRenderArgs {
return (
typeof args === "object" &&
args !== null &&
typeof (args as { file?: unknown }).file === "string" &&
!("path" in args) &&
!("file_path" in args) &&
!("edits" in args)
);
}
function isVimToolDetails(details: unknown): details is VimToolDetails {
if (!details || typeof details !== "object" || Array.isArray(details)) {
return false;
}
const cursor = (details as { cursor?: unknown }).cursor;
const viewportLines = (details as { viewportLines?: unknown }).viewportLines;
return (
typeof (details as { file?: unknown }).file === "string" &&
typeof cursor === "object" &&
cursor !== null &&
Array.isArray(viewportLines)
);
}
/** Extended context for edit tool rendering */
export interface EditRenderContext {
/** Edit mode resolved by the caller; lets the renderer dispatch without shape-sniffing */
@@ -460,16 +433,11 @@ export const editToolRenderer = {
mergeCallAndResult: true,
renderCall(
args: EditRenderArgs | VimRenderArgs,
args: EditRenderArgs,
options: RenderResultOptions & { renderContext?: EditRenderContext },
uiTheme: Theme,
): Component {
const renderContext = options.renderContext;
// Dispatch on the explicit editMode when available; fall back to the
// shape probe for legacy call sites that don't thread renderContext.
if (renderContext?.editMode === "vim" || isVimRenderArgs(args)) {
return vimToolRenderer.renderCall(args as VimRenderArgs, options, uiTheme);
}
const editArgs = args as EditRenderArgs;
const hashlineInputSummary = getHashlineInputRenderSummary(editArgs, renderContext?.editMode);
@@ -514,14 +482,6 @@ export const editToolRenderer = {
uiTheme: Theme,
args?: EditRenderArgs,
): Component {
if (options.renderContext?.editMode === "vim" || isVimToolDetails(result.details)) {
return vimToolRenderer.renderResult(
result as { content: Array<{ type: string; text?: string }>; details?: VimToolDetails; isError?: boolean },
options,
uiTheme,
);
}
const perFileResults = result.details?.perFileResults;
const totalFiles = args?.edits ? countEditFiles(args.edits) : 0;
if (perFileResults && (perFileResults.length > 1 || totalFiles > 1)) {
@@ -523,27 +523,11 @@ const applyPatchStrategy: EditStreamingStrategy<ApplyPatchArgs> = {
return "";
},
};
// Vim streaming preview is handled by the existing vimToolRenderer inside
// edit/renderer.ts. The strategy here is a no-op so the registry is total.
const vimStrategy: EditStreamingStrategy<unknown> = {
extractCompleteEdits(args) {
return args;
},
async computeDiffPreview() {
return null;
},
renderStreamingFallback() {
return "";
},
};
export const EDIT_MODE_STRATEGIES: Record<EditMode, EditStreamingStrategy<unknown>> = {
replace: replaceStrategy as EditStreamingStrategy<unknown>,
patch: patchStrategy as EditStreamingStrategy<unknown>,
hashline: hashlineStrategy as EditStreamingStrategy<unknown>,
apply_patch: applyPatchStrategy as EditStreamingStrategy<unknown>,
vim: vimStrategy,
};
export { resolveEditMode };