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:
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user