Documentation
¶
Overview ¶
Package edit implements symbol editing tools: replace body, insert before/after, rename, safe delete, and post-edit diagnostic verification.
Index ¶
- Constants
- func ClassifyEditError(err error) string
- func InsertAfter(ctx context.Context, lease *lspool.WorkerLease, uri string, symbolName string, ...) error
- func InsertAfterWithPlan(ctx context.Context, lease *lspool.WorkerLease, plan *EditPlan) error
- func InsertBefore(ctx context.Context, lease *lspool.WorkerLease, uri string, symbolName string, ...) error
- func InsertBeforeWithPlan(ctx context.Context, lease *lspool.WorkerLease, plan *EditPlan) error
- func RegisterTools(server *mcp.SerenaMCPServer, k *kernel.Kernel, extractor *BodyExtractor, ...)
- func ReplaceBody(ctx context.Context, lease *lspool.WorkerLease, extractor *BodyExtractor, ...) error
- type BodyExtractor
- type DeleteResult
- type DiagnosticSummary
- type EditPlan
- type FuzzyMatchInfo
- type InsertAfterArgs
- type InsertBeforeArgs
- type RenameOverrider
- type RenameResult
- type RenameStrategy
- type RenameSymbolArgs
- type ReplaceBodyArgs
- type RustAnalyzerRenameOverride
- type SafeDeleteArgs
- type SymbolEditingSkill
- type VerifyEditArgs
- type VerifyResult
Constants ¶
const ( EditTypeReplaceBody = "replace_body" EditTypeInsertBefore = "insert_before" EditTypeInsertAfter = "insert_after" EditTypeRename = "rename" EditTypeDelete = "delete" )
EditType enumerates the kinds of edits the planner can produce.
Variables ¶
This section is empty.
Functions ¶
func ClassifyEditError ¶
ClassifyEditError maps an edit/fileops handler error to one of the closed helix_edit_outcome_total "outcome" values (Phase 53 D-10).
Source-of-truth bucketing (RESEARCH §"Edit-Tool Outcome Map"):
- fuzzy.ErrAmbiguous → "ambiguous_match"
- fuzzy.ErrNoMatch → "no_match"
- serr.NoWorkspace → "internal" (no_workspace is a setup error, not an edit-domain bucket)
- all other errors → "internal"
Q-3 (RESOLVED 2026-04-30): missing-required-field errors and other serr.InvalidArgs results that are NOT fuzzy ambiguity / no-match map to "internal" — preserves the locked D-10 6-value enum; classified as a known under-classification scheduled for v1.3 typed-error work.
"ls_error" classification is BEST-EFFORT in v1.2: without typed "LS-failure" sentinels in internal/kernel/edit, every LS adapter failure currently flows as serr.Internal-wrapped errors that look identical to file-I/O errors. The bucket exists in the closed enum per D-10, but in v1.2 it is only emitted via direct outcome assignment at known LS call sites (e.g. didChange notify, apply rename edits) — not via this classifier. v1.3 will add LS-error sentinels and bridge them here.
"validation_failed" is similarly NOT classified by this helper — it is flipped at the end of a happy-path handler when the post-edit verifier reports VerifyResult.HasErrors (see appendVerifyInfoWithStatus).
Exported as ClassifyEditError so internal/kernel/fileops/ can reuse the helper without duplicating the bucket map (DRY: single source of truth for the D-10 outcome classifier).
func InsertAfter ¶
func InsertAfter(ctx context.Context, lease *lspool.WorkerLease, uri string, symbolName string, content string) error
InsertAfter inserts content immediately after a symbol's range end. Per D-13: LSP-first, DocumentSymbol range boundaries are sufficient.
func InsertAfterWithPlan ¶
InsertAfterWithPlan executes an insert-after using a pre-computed plan.
func InsertBefore ¶
func InsertBefore(ctx context.Context, lease *lspool.WorkerLease, uri string, symbolName string, content string) error
InsertBefore inserts content immediately before a symbol's range start. Per D-13: LSP-first, DocumentSymbol range boundaries are sufficient.
func InsertBeforeWithPlan ¶
InsertBeforeWithPlan executes an insert-before using a pre-computed plan.
func RegisterTools ¶
func RegisterTools(server *mcp.SerenaMCPServer, k *kernel.Kernel, extractor *BodyExtractor, diagStore *diag.DiagnosticStore, wsKeyFn func() workspace.WorkspaceKey)
RegisterTools registers all 6 symbol editing tools with the MCP server. Each handler is wrapped with kernel.WrapToolSpan to produce kernel.tool.{name} sub-spans under the TelemetryMiddleware span (Phase 12, TRACE-03).
func ReplaceBody ¶
func ReplaceBody(ctx context.Context, lease *lspool.WorkerLease, extractor *BodyExtractor, uri string, symbolName string, newBody string, lang string) error
ReplaceBody replaces a symbol's body using tree-sitter for precise body extraction. Per D-14: tree-sitter-first for body surgery, LSP-assisted for discovery. Per D-15: falls back to full symbol range replacement when tree-sitter unavailable.
Types ¶
type BodyExtractor ¶
type BodyExtractor struct {
// contains filtered or unexported fields
}
BodyExtractor uses tree-sitter to precisely extract symbol body byte ranges. Per D-14: tree-sitter-first for replace-body operations.
func NewBodyExtractor ¶
func NewBodyExtractor(registry *treesitter.GrammarRegistry) *BodyExtractor
NewBodyExtractor creates a BodyExtractor using the shared grammar registry.
func (*BodyExtractor) ExtractBody ¶
func (be *BodyExtractor) ExtractBody(source []byte, lang string, symbolName string, symbolRange gen.Range) (startByte, endByte uint, err error)
ExtractBody parses source with the language grammar and returns the byte range of the body of the declaration that matches symbolName and overlaps symbolRange. Per D-14: tree-sitter-first for precise body surgery.
func (*BodyExtractor) SupportsLanguage ¶
func (be *BodyExtractor) SupportsLanguage(lang string) bool
SupportsLanguage returns true if the extractor has a grammar for the given language.
type DeleteResult ¶
type DeleteResult struct {
Deleted bool
References int // number of remaining references (if not deleted)
RefLocations []symbols.SymbolLocation // where the refs are
}
DeleteResult summarizes the outcome of a delete operation.
func SafeDelete ¶
func SafeDelete(ctx context.Context, lease *lspool.WorkerLease, uri string, symbolName string, force bool) (*DeleteResult, error)
SafeDelete deletes a symbol from a file after checking for references. EDT-05: Unless force=true, checks FindReferences before deleting.
func SafeDeleteWithPlan ¶
func SafeDeleteWithPlan(ctx context.Context, readLease, writeLease *lspool.WorkerLease, plan *EditPlan, force bool) (*DeleteResult, error)
SafeDeleteWithPlan executes a safe delete using a pre-computed plan. readLease is used for reference lookups (can be clean/shared), writeLease for file mutation.
type DiagnosticSummary ¶
DiagnosticSummary is a simplified diagnostic for reporting.
type EditPlan ¶
type EditPlan struct {
URI string
SymbolName string
EditType string // one of EditType* constants
Range gen.Range // computed edit range (full symbol extent)
SelectionRange gen.Range // identifier range (for cursor positioning)
NewContent string // content to insert/replace
}
EditPlan describes a resolved edit ready for execution.
func PlanEdit ¶
func PlanEdit(ctx context.Context, lease *lspool.WorkerLease, uri string, symbolName string, editType string, content string) (*EditPlan, error)
PlanEdit resolves a symbol via documentSymbol and produces an EditPlan. Should be called on a warm (indexed) lease for accurate symbol ranges.
type FuzzyMatchInfo ¶
FuzzyMatchInfo carries fuzzy match metadata back to the tool handler for response formatting (D-07).
func ReplaceBodyWithPlan ¶
func ReplaceBodyWithPlan(ctx context.Context, lease *lspool.WorkerLease, extractor *BodyExtractor, plan *EditPlan, lang string, searchBody string) (*FuzzyMatchInfo, error)
ReplaceBodyWithPlan executes a body replacement using a pre-computed plan. When searchBody is non-empty, the replacement is scoped to the fuzzy-matched sub-region within the tree-sitter/range-extracted body (FUZZ-05). Returns FuzzyMatchInfo when fuzzy matching was used, nil otherwise.
type InsertAfterArgs ¶
type InsertAfterArgs struct {
Path string `json:"path" jsonschema:"File path"`
SymbolName string `json:"symbol_name" jsonschema:"Name of the symbol to insert after"`
Content string `json:"content" jsonschema:"Content to insert"`
}
InsertAfterArgs is the input schema for the insert_after_symbol tool.
type InsertBeforeArgs ¶
type InsertBeforeArgs struct {
Path string `json:"path" jsonschema:"File path"`
SymbolName string `json:"symbol_name" jsonschema:"Name of the symbol to insert before"`
Content string `json:"content" jsonschema:"Content to insert"`
}
InsertBeforeArgs is the input schema for the insert_before_symbol tool.
type RenameOverrider ¶
type RenameOverrider interface {
RenameOverride(
ctx context.Context,
lease *lspool.WorkerLease,
uri string,
line, col int,
newName string,
) (*RenameResult, error)
}
RenameOverrider is an optional interface that lspool.QuirkAdapter implementations may satisfy (directly or via a wrapper in package edit) to bypass textDocument/rename. Called by edit.RenameSymbol when the native rename attempt fails.
Semantic-accuracy note: overrides are NOT required to match native LSP rename fidelity (cross-crate trait-impl discovery, macro expansion). Implementations MUST document their limits in their doc comment AND in USAGE.md. See BUG-DEFER-02.
On success returns (*RenameResult, nil); the caller sets Strategy. On failure returns (nil, serr.*); the caller wraps in serr.Unsupported per D-06 if the native path also failed.
type RenameResult ¶
type RenameResult struct {
FilesChanged int
EditsApplied int
Files []string
// Strategy tags which dispatch path produced this result (D-07).
// Populated by RenameSymbol on every nil-error return.
Strategy RenameStrategy
}
RenameResult summarizes the outcome of a rename operation.
func RenameSymbol ¶
func RenameSymbol(ctx context.Context, lease *lspool.WorkerLease, uri string, line, col int, newName string) (*RenameResult, error)
RenameSymbol dispatches a rename request. It first attempts the native LSP path (textDocument/prepareRename + textDocument/rename); on failure, if the underlying LS adapter exposes a RenameOverrider (directly or via the rust-analyzer wrapper), it delegates to the override. On success the result carries a Strategy tag. If both paths fail, returns serr.Unsupported with a message pointing agents at fuzzy_edit, replace_symbol_body, or search_in_files (D-06).
func RustClientSideRename ¶
func RustClientSideRename( ctx context.Context, lease *lspool.WorkerLease, uri string, line, col int, newName string, ) (*RenameResult, error)
RustClientSideRename implements the references-driven fallback used by RustAnalyzerRenameOverride. Kept in package edit to avoid the lspool -> edit import cycle (applyTextEdits is package-private here).
Contract assumptions (rust-analyzer only — DO NOT generalize):
- textDocument/references (includeDeclaration=true) returns ranges that exactly span the identifier to be renamed.
- The symbol has at least one reference (including the declaration).
Failure modes:
- zero references -> serr.NotFound
- references RPC error -> serr.Internal (wrap)
- text-edit apply error -> serr.Internal (wrap, with file URI detail)
type RenameStrategy ¶
type RenameStrategy string
RenameStrategy enumerates the path a successful rename took. String values are a public contract: they appear in rename_symbol tool responses AND in the helix_rename_strategy_total metric label set. MUST NOT change without a coordinated telemetry-schema update.
const ( // StrategyLSPNative indicates textDocument/rename succeeded via the LS. StrategyLSPNative RenameStrategy = "lsp-native" // StrategyRustClientSide indicates the rust-analyzer quirk override was // used: references were gathered via textDocument/references and text // edits were applied client-side. See BUG-DEFER-02 for semantic limits. StrategyRustClientSide RenameStrategy = "rust-client-side" )
type RenameSymbolArgs ¶
type RenameSymbolArgs struct {
Path string `json:"path" jsonschema:"File path where symbol is defined"`
Line int `json:"line" jsonschema:"Line number of symbol (1-indexed)"`
Col int `json:"column" jsonschema:"Column number of symbol (1-indexed)"`
NewName string `json:"new_name" jsonschema:"New name for the symbol"`
}
RenameSymbolArgs is the input schema for the rename_symbol tool.
type ReplaceBodyArgs ¶
type ReplaceBodyArgs struct {
Path string `json:"path" jsonschema:"File path"`
SymbolName string `json:"symbol_name" jsonschema:"Name of the symbol whose body to replace"`
NewBody string `json:"new_body" jsonschema:"New body content to replace with"`
SearchBody string `` /* 153-byte string literal not displayed */
}
ReplaceBodyArgs is the input schema for the replace_symbol_body tool.
type RustAnalyzerRenameOverride ¶
type RustAnalyzerRenameOverride struct {
Inner *lspool.RustAnalyzerAdapter
}
RustAnalyzerRenameOverride wraps a *lspool.RustAnalyzerAdapter with a RenameOverrider implementation. Lives in package edit so the method can return *RenameResult without forcing lspool -> edit import (RESEARCH Pitfall 1 resolution). The dispatcher in rename.go constructs this wrapper inline after type-asserting the adapter for *lspool.RustAnalyzerAdapter.
Semantic-accuracy note (D-05, BUG-DEFER-02): the references-driven fallback does NOT match native rust-analyzer rename fidelity on cross-crate trait-impl discovery, macro-expansion sites, or re-exports that rename at the re-export site. See USAGE.md Troubleshooting.
func (*RustAnalyzerRenameOverride) RenameOverride ¶
func (w *RustAnalyzerRenameOverride) RenameOverride( ctx context.Context, lease *lspool.WorkerLease, uri string, line, col int, newName string, ) (*RenameResult, error)
RenameOverride satisfies the RenameOverrider interface. Best-effort waits for rust-analyzer quiescence (readiness is an optimization; the references-driven fallback works even when the server is not yet quiescent because textDocument/references succeeds at the failing position per RCA §1).
type SafeDeleteArgs ¶
type SafeDeleteArgs struct {
Path string `json:"path" jsonschema:"File path"`
SymbolName string `json:"symbol_name" jsonschema:"Name of the symbol to delete"`
Force bool `json:"force,omitempty" jsonschema:"Delete even if references exist (default: false)"`
}
SafeDeleteArgs is the input schema for the safe_delete_symbol tool.
type SymbolEditingSkill ¶
type SymbolEditingSkill struct{}
SymbolEditingSkill is a ToolProvider adapter that exposes the 6 symbol editing tools through the skill interface for daemon discovery.
func (*SymbolEditingSkill) Description ¶
func (s *SymbolEditingSkill) Description() string
Description returns a human-readable description of this skill.
func (*SymbolEditingSkill) Init ¶
func (s *SymbolEditingSkill) Init(deps skill.SkillDeps) error
Init is a no-op; kernel tools get their dependencies from the daemon, not SkillDeps.
func (*SymbolEditingSkill) Name ¶
func (s *SymbolEditingSkill) Name() string
Name returns the unique skill identifier.
func (*SymbolEditingSkill) Tools ¶
func (s *SymbolEditingSkill) Tools() []*mcp.ToolDef
Tools returns the 6 ToolDefs for symbol editing. RegisterFn is nil because the daemon owns MCP registration (D-01).
type VerifyEditArgs ¶
type VerifyEditArgs struct {
Path string `json:"path" jsonschema:"File path to verify after editing"`
}
VerifyEditArgs is the input schema for the verify_edit tool.
type VerifyResult ¶
type VerifyResult struct {
HasErrors bool
ErrorCount int
Errors []DiagnosticSummary
}
VerifyResult holds the outcome of post-edit diagnostic verification.
func VerifyEdit ¶
func VerifyEdit(ctx context.Context, diagStore *diag.DiagnosticStore, uri string) (*VerifyResult, error)
VerifyEdit checks for compilation errors after an edit. EDT-06: Post-edit diagnostic verification via WaitForDiagnostics.