res-sheets Phase 5: positional copy/cut #6

Open
opened 2026-07-19 02:30:47 +00:00 by agent · 0 comments
Member

Plan: res-sheets Phase 5 — Positional Copy/Cut Translation

Goal

When cells are copied or cut and pasted elsewhere, update formula references according to their absolute/relative markers and whether the operation is copy or cut.

Scope

Repo: git.merith.xyz/residual/extra
Files: extra/lib/sheets/formula_transform.go (new), extra/lib/sheets/tui/model.go

Desired behavior

Copy-paste

  • Relative references inside the copied range shift by the paste offset.
  • Absolute references stay fixed.
  • External references (formulas outside the copied range) are not updated.
  • Example: A1:A5=1..5, B1=SUM(A1:A5). Copy A1:B5 and paste 10 rows down → A11:A15=1..5, B11=SUM(A11:A15).

Cut-paste (move)

  • Relative references inside the moved range shift by the paste offset.
  • Absolute references inside the moved range stay fixed.
  • External absolute references that pointed to cells inside the moved range follow those cells to their new location.
  • External relative references that pointed to cells inside the moved range stay at the original location.

Lua cells

  • =lua{...} cells are skipped. Inline Lua is too complex to rewrite safely.

Implementation

New file: extra/lib/sheets/formula_transform.go

  • TranslateExpr(expr Expr, dCol, dRow int) Expr — deep copy of AST with relative refs shifted; absolute (AbsCol/AbsRow true) unchanged.
  • TranslateFormula(raw string, dCol, dRow int) (string, error) — parse → TranslateExpr → render.
  • RenderExpr(expr Expr) string — pretty-print AST with precedence-aware parens.
  • RenderRange(rng CellRange) stringFrom.String() + ":" + To.String().
  • UpdateRefsForMove(sheet *Sheet, srcTL, srcBR, dstTL CellRef) map[CellRef]string — find every formula cell outside the source rectangle whose formula references a cell inside it; translate by move offset preserving markers; return map cell refs → updated raw formulas.

Changes to extra/lib/sheets/tui/model.go

  • copySelection() already stores Cell.Raw from Phase 1.
  • pasteClipboard(): compute offset dCol = cursor.Col - clip.srcTL.Col, dRow = cursor.Row - clip.srcTL.Row; for each clipboard cell, if raw is a formula translate by offset else write raw as-is; if clip.cut also call UpdateRefsForMove and include external-formula updates in same commit batch; clear clipboard after a cut.

Tests

  • Relative refs translate on copy; absolute refs stay fixed on copy; mixed translate only relative dims; range refs translate (SUM(A1:A5) down 10 → SUM(A11:A15)); cut updates external absolute refs; cut does not update external relative refs; Lua cells paste verbatim.

Verification

cd extra && go build ./... && go test ./... && go vet ./...
# Plan: res-sheets Phase 5 — Positional Copy/Cut Translation ## Goal When cells are copied or cut and pasted elsewhere, update formula references according to their absolute/relative markers and whether the operation is copy or cut. ## Scope Repo: `git.merith.xyz/residual/extra` Files: `extra/lib/sheets/formula_transform.go` (new), `extra/lib/sheets/tui/model.go` ## Desired behavior ### Copy-paste - Relative references inside the copied range shift by the paste offset. - Absolute references stay fixed. - External references (formulas outside the copied range) are not updated. - Example: A1:A5=1..5, B1=`SUM(A1:A5)`. Copy A1:B5 and paste 10 rows down → A11:A15=1..5, B11=`SUM(A11:A15)`. ### Cut-paste (move) - Relative references inside the moved range shift by the paste offset. - Absolute references inside the moved range stay fixed. - External **absolute** references that pointed to cells inside the moved range follow those cells to their new location. - External **relative** references that pointed to cells inside the moved range stay at the original location. ### Lua cells - `=lua{...}` cells are skipped. Inline Lua is too complex to rewrite safely. ## Implementation ### New file: `extra/lib/sheets/formula_transform.go` - `TranslateExpr(expr Expr, dCol, dRow int) Expr` — deep copy of AST with relative refs shifted; absolute (AbsCol/AbsRow true) unchanged. - `TranslateFormula(raw string, dCol, dRow int) (string, error)` — parse → TranslateExpr → render. - `RenderExpr(expr Expr) string` — pretty-print AST with precedence-aware parens. - `RenderRange(rng CellRange) string` — `From.String() + ":" + To.String()`. - `UpdateRefsForMove(sheet *Sheet, srcTL, srcBR, dstTL CellRef) map[CellRef]string` — find every formula cell outside the source rectangle whose formula references a cell inside it; translate by move offset preserving markers; return map cell refs → updated raw formulas. ### Changes to `extra/lib/sheets/tui/model.go` - `copySelection()` already stores `Cell.Raw` from Phase 1. - `pasteClipboard()`: compute offset `dCol = cursor.Col - clip.srcTL.Col`, `dRow = cursor.Row - clip.srcTL.Row`; for each clipboard cell, if raw is a formula translate by offset else write raw as-is; if `clip.cut` also call `UpdateRefsForMove` and include external-formula updates in same `commit` batch; clear clipboard after a cut. ## Tests - Relative refs translate on copy; absolute refs stay fixed on copy; mixed translate only relative dims; range refs translate (`SUM(A1:A5)` down 10 → `SUM(A11:A15)`); cut updates external absolute refs; cut does not update external relative refs; Lua cells paste verbatim. ## Verification ```bash cd extra && go build ./... && go test ./... && go vet ./... ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
residual/.agent#6
No description provided.