From e897ca7848acaf42bd8ae80ea54612d71cf09772 Mon Sep 17 00:00:00 2001 From: Eric Rumsey Date: Fri, 23 May 2025 17:37:51 -0500 Subject: [PATCH] Begin re-write in proper functional style --- src/lib/painter/canvas.ts | 102 ++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/src/lib/painter/canvas.ts b/src/lib/painter/canvas.ts index 40b8e0a..7df02bf 100644 --- a/src/lib/painter/canvas.ts +++ b/src/lib/painter/canvas.ts @@ -1,47 +1,63 @@ -import { tryCatch } from '@maxmorozoff/try-catch-tuple'; -import type { CursorPosition } from '../util/terminal'; +import { type CursorPos } from 'node:readline' -const setInitialEnd = (pos: { - origin: CursorPosition; - end?: CursorPosition; - lines?: number; -}) => { - if (!pos.end || !pos.lines) - throw TypeError("One of 'end' or 'lines' must be set"); - if (Object.keys(pos).includes('end') || Object.keys(pos).includes('end')) - throw TypeError("Cannot set both 'end' and 'lines'"); - if (pos.end) return pos.end; - return { - row: pos.origin.row + pos.lines, - col: pos.origin.col, - }; -}; +// Cursor stuffs +interface CursorPosX { + readonly _tag: 'X' + readonly value: number +} -export const createCanvas = ( - pos: { origin: CursorPosition; end?: CursorPosition; lines?: number }, - paint: () => Promise, - cleanup?: () => Promise -) => { - let currentOrigin = pos.origin; +interface CursorPosY { + readonly _tag: 'Y' + readonly value: number +} - let currentEnd; - const [endVal, endError] = tryCatch(() => setInitialEnd(pos)); - if (endError) throw endError; - currentEnd = endVal; +const cursorPosX = (x: number): CursorPosX => ({_tag: 'X', value: x}) - paint(); - // - // Paint function - // - // Restore origin position - // Clear to cursor end position - // - // API - // --- - // get origin - // get end - // move end - // get line count - // clear canvas - return [1]; -}; +const cursorPosY = (x: number): CursorPosY => ({_tag: 'Y', value: x}) + +type IsCursorPos = + (x: 'X' | 'Y') => (y: CursorPosX | CursorPosY) => boolean +const isCursorPos: IsCursorPos = x => y => y._tag === x + +// Tagged types +interface CanvasOrigin { + readonly _tag: 'Origin' + readonly value: CursorPos +} + +interface CanvasEnd { + readonly _tag: 'End' + readonly value: CursorPos +} + +// Canvas type using tagged positions +type Canvas = { + origin: CanvasOrigin, + end: CanvasEnd, +} + +// Cursor Position +// const cursorPos: CursorPos = () + +// Constructor helpers +const origin = (pos: CursorPos): CanvasOrigin => ({ + _tag: 'Origin', + value: pos, +}) + +const end = (pos: CursorPos): CanvasEnd => ({ + _tag: 'End', + value: pos, +}) + +// Curried canvas creator with type safety +const canvas = + (origin: CanvasOrigin) => (end: CanvasEnd): Canvas => ({ + origin, + end, + }) + +// Usage with proper type safety +const myCanvas = canvas(origin({rows: 3, cols: 1}))( + end({rows: 8, cols: 1}), +)