spreadsheet_autosum.ts 새로 만듦 — 위 또는 왼쪽 연속 숫자 범위를 찾아 =SUM() 식을 활성 칸에 넣음(엑셀 규칙), 여러 칸을 고른 채면 그 안에서만 찾음. 계약 안 건드림 · 엔진 A·격자 C 안 건드림 — 실제 단축키·Σ 단추 이음은 sub7 몫(머리 주석에 적음). 시험 resources/tester/spreadsheet/test_stage3_autosum.ts 6개 통과. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EUypcnp5d1gU2aeKh9F2H7
71 lines
3.1 KiB
TypeScript
71 lines
3.1 KiB
TypeScript
/* =============================================================================
|
|
* spreadsheet_autosum.ts (3단계 · 주인 sub_laptop_4)
|
|
* 자동 합계(Alt+= · 도구 단추 Σ) — 엑셀 규칙: 활성 칸 바로 위가 숫자면 그 위 연속 숫자 칸을
|
|
* 위로 죽 잡고, 아니면 바로 왼쪽이 숫자면 왼쪽으로 죽 잡음. 여러 칸을 고른 채면 그 고름
|
|
* 안에서(활성 칸 위 또는 왼쪽만) 잡음. 아무것도 못 찾으면 빈 `=SUM()`.
|
|
*
|
|
* 잇는 법(D · E · sub7 — 지금은 하나도 안 이어짐):
|
|
* 1) `spreadsheet_keys.ts` 에 Alt+= 를 매핑해 `applyAutoSum(ctx)` 를 부름.
|
|
* 2) `spreadsheet_toolbar.ts` 에 Σ 단추를 두고 눌리면 `applyAutoSum(ctx)` 를 부름.
|
|
* 3) 지금은 칸에 식 글만 바로 넣음(편집기를 안 거침) — 사용자가 범위를 눈으로 고쳐 잡게 하려면
|
|
* `ctx.editor.begin("=SUM(...)")` 로 편집 상태로 열고 커밋은 사용자가 Enter.
|
|
* ========================================================================== */
|
|
|
|
import { rangeToA1, toA1 } from "./spreadsheet_address";
|
|
import { isFrac } from "./spreadsheet_functions_math";
|
|
import type { CellRange } from "./spreadsheet_types";
|
|
import type { SpreadsheetContext } from "./spreadsheet_view_types";
|
|
|
|
function isNumericCell(ctx: SpreadsheetContext, sheet: string, r: number, c: number): boolean {
|
|
if (r < 0 || c < 0) return false;
|
|
return isFrac(ctx.engine.value(sheet, r, c));
|
|
}
|
|
|
|
function verticalRun(
|
|
ctx: SpreadsheetContext,
|
|
sheet: string,
|
|
r: number,
|
|
c: number,
|
|
top: number,
|
|
): CellRange | null {
|
|
if (r - 1 < top || !isNumericCell(ctx, sheet, r - 1, c)) return null;
|
|
let start = r - 1;
|
|
while (start - 1 >= top && isNumericCell(ctx, sheet, start - 1, c)) start--;
|
|
return { r0: start, c0: c, r1: r - 1, c1: c };
|
|
}
|
|
|
|
function horizontalRun(
|
|
ctx: SpreadsheetContext,
|
|
sheet: string,
|
|
r: number,
|
|
c: number,
|
|
left: number,
|
|
): CellRange | null {
|
|
if (c - 1 < left || !isNumericCell(ctx, sheet, r, c - 1)) return null;
|
|
let start = c - 1;
|
|
while (start - 1 >= left && isNumericCell(ctx, sheet, r, start - 1)) start--;
|
|
return { r0: r, c0: start, r1: r, c1: c - 1 };
|
|
}
|
|
|
|
/** 활성 칸 기준 합산 범위를 찾음 — 없으면 null(빈 `=SUM()`). */
|
|
export function autoSumRange(ctx: SpreadsheetContext): CellRange | null {
|
|
const sheet = ctx.selection.시트;
|
|
const { r, c } = ctx.selection.활성;
|
|
const sel = ctx.selection.범위[0];
|
|
|
|
if (sel && (sel.r1 > sel.r0 || sel.c1 > sel.c0)) {
|
|
if (r > sel.r0) return { r0: sel.r0, c0: c, r1: r - 1, c1: c };
|
|
if (c > sel.c0) return { r0: r, c0: sel.c0, r1: r, c1: c - 1 };
|
|
}
|
|
|
|
return verticalRun(ctx, sheet, r, c, 0) ?? horizontalRun(ctx, sheet, r, c, 0);
|
|
}
|
|
|
|
/** 활성 칸에 `=SUM(...)` 을 바로 넣음(칸 명령 — 편집기를 안 거침). */
|
|
export function applyAutoSum(ctx: SpreadsheetContext): void {
|
|
const range = autoSumRange(ctx);
|
|
const { r, c } = ctx.selection.활성;
|
|
const 식 = range ? `SUM(${rangeToA1(range)})` : "SUM()";
|
|
ctx.dispatch({ 종류: "칸", 시트: ctx.selection.시트, 칸: { [toA1(r, c)]: { 식 } } });
|
|
}
|