/* ============================================================================= * 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 }; }