import Foundation import RastrilloApple @MainActor extension SheetModel { @discardableResult func write(_ writes: [CellWrite], retrying: Bool = false) async -> Bool { guard failedWrites.isEmpty || retrying else { error = "Retry or discard the pending edits before making another change." return false } guard mayWrite && !busy else { return false } guard writes.allSatisfy({ $0.raw.utf8.count <= 8192 }) else { error = "A cell exceeds the input size limit. Nothing was changed." return false } if writes.isEmpty { return true } busy = true defer { busy = false } var offset = 0 do { while offset < writes.count { let batch = try await wire.encode(writes, startingAt: offset) let count = batch.count let data = batch.data let (bytes, status) = try await client.response( grid + "/cells/batch", method: "POST", body: data, maxBytes: 64 << 20) guard (200..<300).contains(status) else { throw NativeClientError.message("The server did not confirm the edit.") } let response = try await wire.decode(bytes) await accept(response) offset += count } failedWrites = [] error = "" notice = "Saved" if showTable { await loadTable() } return true } catch { failedWrites = Array(writes.dropFirst(offset)) self.error = "\(offset) cells confirmed; \(failedWrites.count) still need saving. " + error.localizedDescription return false } } func retryWrites() async { let pending = failedWrites if await write(pending, retrying: true), pending.count == 1, let value = pending.first, value.r == selection.start.r, value.c == selection.start.c, value.raw == draft { originalDraft = draft } } }