- 계약 더함: Command 「정렬」(차례를 박음 → 다시 하기가 같음) · 「필터」(걸러짐 행을 박음) · AutoFilter · Sheet.필터 · RowInfo.걸러짐 · 파일 목록 - spreadsheet_sortfilter.ts(A 엔진) — 수 < 글 < 참거짓 < 오류 · 빈 칸 늘 맨 뒤 · 같은 값 원래 차례 · 대소문자 옵션 · 현재 영역 · 정렬 옮김 = 범위 열만 · 식은 상대 참조만 복사처럼 · 범위 밖 식 그대로 · 서식 · 메모 따라감 · 걸러진 행 제자리 · 병합 걸치면 막음 · 자동 필터 엔진(값 목록 · 걸러짐 셈 · 적용 · 행열 넣기 · 지우기 때 필터 따라감) · 되돌림 짝 = 시트통째 - spreadsheet_sort_dialog.ts — 정렬 대화 상자(범위 · 머리 행 짐작 · 기준 더하기 · 오름 · 내림) · 빠른 정렬 sortSelection - spreadsheet_commands_sheet.ts — 시트 명령을 떼어 냄(commands 700 줄 안쪽) - 시험 test_spreadsheet_sortfilter.py 엑셀 규칙표 4 묶음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TULoa94ZFL26KU6ZqVpjkF
70 lines
3.4 KiB
TypeScript
70 lines
3.4 KiB
TypeScript
/* =============================================================================
|
|
* spreadsheet_commands_sheet.ts (주인 A)
|
|
* 시트 명령 — 더하기 · 지우기 · 이름 · 옮기기 · 통째 바꿔 넣기. 들머리는 `applyCommand`(commands).
|
|
* ========================================================================== */
|
|
|
|
import { clone, CommandError, restoreChanged, rewriteAll, sheetOf } from "./spreadsheet_commands";
|
|
import type { Of } from "./spreadsheet_commands";
|
|
import type { Command, CommandEffect, Workbook } from "./spreadsheet_types";
|
|
|
|
function checkSheetName(book: Workbook, name: string, self?: string) {
|
|
if (!name.trim() || name.length > 31) throw new CommandError("시트 이름은 1~31 글자");
|
|
if (/[[\]:*?/\\]/.test(name) || name.startsWith("'") || name.endsWith("'"))
|
|
throw new CommandError("시트 이름에 못 쓰는 글자: [ ] : * ? / \\ 와 앞뒤 '");
|
|
if (book.시트.some((s) => s.id !== self && s.이름.toLowerCase() === name.toLowerCase()))
|
|
throw new CommandError(`같은 이름 시트가 있음: ${name}`);
|
|
}
|
|
|
|
export function addSheet(book: Workbook, cmd: Of<"시트더하기">): CommandEffect {
|
|
if (book.시트.some((s) => s.id === cmd.시트.id))
|
|
throw new CommandError(`같은 id 시트가 있음: ${cmd.시트.id}`);
|
|
checkSheetName(book, cmd.시트.이름);
|
|
book.시트.splice(Math.max(0, Math.min(cmd.자리, book.시트.length)), 0, clone(cmd.시트));
|
|
return { undo: { 종류: "시트지우기", 시트: cmd.시트.id }, cells: [], rebuild: true };
|
|
}
|
|
|
|
export function removeSheet(book: Workbook, cmd: Of<"시트지우기">): CommandEffect {
|
|
const s = sheetOf(book, cmd.시트);
|
|
if (book.시트.length === 1) throw new CommandError("마지막 시트는 못 지움");
|
|
const at = book.시트.indexOf(s);
|
|
const old = book.시트.map(clone);
|
|
rewriteAll(book, cmd);
|
|
book.시트.splice(at, 1);
|
|
if (book.활성 === s.id) book.활성 = book.시트[Math.min(at, book.시트.length - 1)].id;
|
|
const undo: Command[] = [
|
|
{ 종류: "시트더하기", 시트: old[at], 자리: at },
|
|
...restoreChanged(book, old),
|
|
];
|
|
return { undo: { 종류: "묶음", 명령: undo }, cells: [], rebuild: true };
|
|
}
|
|
|
|
export function renameSheet(book: Workbook, cmd: Of<"시트이름">): CommandEffect {
|
|
const s = sheetOf(book, cmd.시트);
|
|
checkSheetName(book, cmd.이름, s.id);
|
|
const prev = s.이름;
|
|
rewriteAll(book, cmd);
|
|
s.이름 = cmd.이름;
|
|
return { undo: { 종류: "시트이름", 시트: s.id, 이름: prev }, cells: [], rebuild: true };
|
|
}
|
|
|
|
export function moveSheet(book: Workbook, cmd: Of<"시트옮기기">): CommandEffect {
|
|
const s = sheetOf(book, cmd.시트);
|
|
const from = book.시트.indexOf(s);
|
|
book.시트.splice(from, 1);
|
|
book.시트.splice(Math.max(0, Math.min(cmd.자리, book.시트.length)), 0, s);
|
|
return { undo: { 종류: "시트옮기기", 시트: s.id, 자리: from }, cells: [], rebuild: false };
|
|
}
|
|
|
|
export function replaceSheet(book: Workbook, cmd: Of<"시트통째">): CommandEffect {
|
|
const at = book.시트.findIndex((x) => x.id === cmd.시트.id);
|
|
if (at < 0) throw new CommandError(`없는 시트: ${cmd.시트.id}`);
|
|
const prev = book.시트[at];
|
|
book.시트[at] = clone(cmd.시트);
|
|
const undo: Of<"시트통째"> = { 종류: "시트통째", 시트: prev };
|
|
if (cmd.서식) {
|
|
undo.서식 = book.서식;
|
|
book.서식 = clone(cmd.서식);
|
|
}
|
|
return { undo, cells: [], rebuild: true };
|
|
}
|