textEditor scrolling. only rendering the lines that are in the viewport. smooth. better prettyPrinting of match inside lambda

master
Dustin Swan 15 hours ago
parent f54b8ca65e
commit 3267d5bc39
Signed by: dustinswan
GPG Key ID: 30D46587E2100467

@ -252,9 +252,12 @@ export function prettyPrint(ast: AST, indent = 0): string {
case 'match': case 'match':
const expr = prettyPrint(ast.expr, indent); const expr = prettyPrint(ast.expr, indent);
const cases = ast.cases const cases = ast.cases
.map(c => `${i}| ${prettyPrintPattern(c.pattern)} \\ ${prettyPrint(c.result, indent + 1)}`) .map(c => {
.join('\n'); const result = prettyPrint(c.result, indent + 1);
return `${expr}\n${cases}`; const needsParens = c.result.kind === 'match' || c.result.kind === 'let';
return `${i}| ${prettyPrintPattern(c.pattern)} \\ ${needsParens ? '(' : ''}${result}${needsParens ? ')' : ''}`;
}).join('\n');
return `${i}${expr}\n${cases}`;
case 'rebind': case 'rebind':
return `${prettyPrint(ast.target, indent)} := ${prettyPrint(ast.value, indent)}`; return `${prettyPrint(ast.target, indent)} := ${prettyPrint(ast.value, indent)}`;

@ -85,9 +85,6 @@ textEditor = name \
newLines = updateAt state.cursorRow (_ \ before) state.lines; newLines = updateAt state.cursorRow (_ \ before) state.lines;
newLines2 = insertAt (state.cursorRow + 1) after newLines; newLines2 = insertAt (state.cursorRow + 1) after newLines;
_ = debug! "enter" { before = before, after = after, newLines2 = newLines2, newRow =
state.cursorRow + 1 };
{ state = state.{ lines = newLines2, cursorCol = 0, cursorRow = state.cursorRow + 1 }, emit = [] }; { state = state.{ lines = newLines2, cursorCol = 0, cursorRow = state.cursorRow + 1 }, emit = [] };
clampCursor = state \ clampCursor = state \
@ -103,157 +100,184 @@ textEditor = name \
state.{ cursorRow = newRow2, cursorCol = newCol2 }; state.{ cursorRow = newRow2, cursorCol = newCol2 };
upArrow = state \ ( upArrow = state \
newState = clampCursor state.{ cursorRow = state.cursorRow - 1 }; newState = clampCursor state.{ cursorRow = state.cursorRow - 1 };
{ state = newState, emit = [] }); { state = newState, emit = [] };
downArrow = state \ ( downArrow = state \
newState = clampCursor state.{ cursorRow = state.cursorRow + 1 }; newState = clampCursor state.{ cursorRow = state.cursorRow + 1 };
{ state = newState, emit = [] }); { state = newState, emit = [] };
leftArrow = state \ ( leftArrow = state \
newState = clampCursor state.{ cursorCol = state.cursorCol - 1 }; newState = clampCursor state.{ cursorCol = state.cursorCol - 1 };
{ state = newState, emit = [] }); { state = newState, emit = [] };
rightArrow = state \ ( rightArrow = state \
newState = clampCursor state.{ cursorCol = state.cursorCol + 1 }; newState = clampCursor state.{ cursorCol = state.cursorCol + 1 };
{ state = newState, emit = [] }); { state = newState, emit = [] };
# todo: scrollHalfDown = state \ ();
# todo: scrollHalfUp = state \ ();
{ {
view = ctx \ ui.stateful { view = ctx \
focusable = True,
autoFocus = True,
key = "textEditor-" & name,
init = {
lines = lines,
cursorRow = 0,
cursorCol = 0,
scrollX = 0,
scrollY = 0,
undoStack = [],
redoStack = [],
mode = Normal # Normal | Insert | Visual
},
update = state event \ event scale = 2;
| Scrolled delta \ ( charH = 12;
newY = max 0 (state.scrollY + delta.deltaY); charW = 5;
newX = max 0 (state.scrollX + delta.deltaX); lineGap = 1;
{ state = state.{ scrollY = newY, scrollX = newX }, emit = [] }) charGap = 2;
lineH = charH * scale + lineGap;
| Key { key = "ArrowDown" } \ downArrow state
| Key { key = "j" } \ (state.mode
| Insert \ insertChar "j" state
| Normal \ downArrow state)
| Key { key = "ArrowUp" } \ upArrow state
| Key { key = "k" } \ (state.mode
| Insert \ insertChar "k" state
| Normal \ upArrow state)
| Key { key = "ArrowLeft" } \ leftArrow state
| Key { key = "h" } \ (state.mode
| Insert \ insertChar "h" state
| Normal \ leftArrow state)
| Key { key = "ArrowRight" } \ rightArrow state
| Key { key = "l" } \ (state.mode
| Insert \ insertChar "l" state
| Normal \ rightArrow state)
| Key { key = "i" } \ (state.mode
| Insert \ insertChar "i" state
| Normal \ insertMode state)
| Key { key = "u" } \ (state.mode
| Insert \ insertChar "u" state
| Normal \ undo state)
| Key { key = "r", ctrl = True } \ (state.mode
| Insert \ { state = state, emit = [] }
| Normal \ redo state)
| Key { key = "W", shift = True } \ (state.mode
| Insert \ insertChar "W" state
| Normal \ write state)
| Key { key = "W", shift = True } \ (state.mode
| Insert \ insertChar "W" state
| Normal \ write state)
| Key { key = "A", shift = True } \ (state.mode
| Insert \ insertChar "A" state
| Normal \ apply state)
| Key { key = "Escape" } \ escape state
| Key { key = "Backspace" } \ (state.mode
| Insert \ backspace state
| _ \ { state = state, emit = [] })
| Key { key = "Enter" } \ (state.mode
| Insert \ enter state
| _ \ { state = state, emit = [] })
# any other key
| Key { key = key, printable = True } \ (state.mode
| Insert \ insertChar key state
| _ \ { state = state, emit = [] })
| _ \ { state = state, emit = [] },
view = state emit \
scale = 2;
charH = 12;
charW = 5;
lineGap = 1;
charGap = 2;
lineH = charH * scale + lineGap;
autoScroll = state \
cursorY = state.cursorRow * lineH; cursorY = state.cursorRow * lineH;
scrollY = (cursorY < state.scrollY newScrollY = (cursorY < state.scrollY
| True \ cursorY | True \ cursorY
| False \ (cursorY + lineH > state.scrollY + ctx.h | False \ (cursorY + lineH > state.scrollY + ctx.h
| True \ cursorY + lineH - ctx.h | True \ cursorY + lineH - ctx.h
| False \ state.scrollY)); | False \ state.scrollY));
cursorX = state.cursorCol * charW * scale + charGap * state.cursorCol; cursorX = state.cursorCol * charW * scale + charGap * state.cursorCol;
scrollX = (cursorX < state.scrollX newScrollX = (cursorX < state.scrollX
| True \ cursorX | True \ cursorX
| False \ (cursorX + charW * scale > state.scrollX + ctx.w | False \ (cursorX + charW * scale > state.scrollX + ctx.w
| True \ cursorX + charW * scale - ctx.w | True \ cursorX + charW * scale - ctx.w
| False \ state.scrollX)); | False \ state.scrollX));
state.{ scrollY = newScrollY, cursorY = cursorY, scrollX = newScrollX, cursorX = cursorX };
buffer = map (l \ text l) state.lines;
withScroll = result \
cursor = ui.positioned { { state = autoScroll result.state, emit = result.emit };
x = cursorX,
y = cursorY, ui.stateful {
child = ui.rect { w = charW * scale, h = charH * scale, color = "rgba(255,255,255,0.5)" } focusable = True,
}; autoFocus = True,
maxLineLen = fold (acc line \ max acc (len line)) 0 state.lines; key = "textEditor-" & name,
totalWidth = maxLineLen * charW * scale + maxLineLen * charGap;
totalHeight = len state.lines * lineH; init = {
lines = lines,
scrollable { cursorRow = 0,
w = ctx.w, cursorCol = 0,
h = ctx.h, scrollX = 0,
totalWidth = totalWidth, scrollY = 0,
totalHeight = totalHeight, undoStack = [],
scrollX = scrollX, redoStack = [],
scrollY = scrollY, mode = Normal # Normal | Insert | Visual
child = ui.stack { },
children = [
ui.column { update = state event \ event
gap = 1, | Scrolled delta \ (
children = buffer maxLineLen = fold (acc line \ max acc (len line)) 0 state.lines;
}, totalW = maxLineLen * charW * scale + maxLineLen * charGap;
cursor totalH = len state.lines * lineH;
] newX = max 0 (min (totalW - ctx.w) (state.scrollX + delta.deltaX));
newY = max 0 (min (totalH - ctx.h) (state.scrollY + delta.deltaY));
{ state = state.{ scrollY = newY, scrollX = newX }, emit = [] })
| Key { key = "ArrowDown" } \ withScroll (downArrow state)
| Key { key = "j" } \ (state.mode
| Insert \ insertChar "j" state
| Normal \ withScroll (downArrow state))
| Key { key = "ArrowUp" } \ withScroll (upArrow state)
| Key { key = "k" } \ (state.mode
| Insert \ insertChar "k" state
| Normal \ withScroll(upArrow state))
| Key { key = "ArrowLeft" } \ withScroll (leftArrow state)
| Key { key = "h" } \ (state.mode
| Insert \ insertChar "h" state
| Normal \ withScroll(leftArrow state))
| Key { key = "ArrowRight" } \ withScroll (rightArrow state)
| Key { key = "l" } \ (state.mode
| Insert \ insertChar "l" state
| Normal \ withScroll(rightArrow state))
| Key { key = "i" } \ (state.mode
| Insert \ insertChar "i" state
| Normal \ insertMode state)
| Key { key = "u" } \ (state.mode
| Insert \ insertChar "u" state
| Normal \ undo state)
| Key { key = "r", ctrl = True } \ (state.mode
| Insert \ { state = state, emit = [] }
| Normal \ redo state)
| Key { key = "W", shift = True } \ (state.mode
| Insert \ insertChar "W" state
| Normal \ write state)
| Key { key = "W", ctrl = True, shift = True } \ (state.mode
| Insert \ insertChar "W" state
| Normal \ write state)
| Key { key = "A", ctrl = True, shift = True } \ (state.mode
| Insert \ insertChar "A" state
| Normal \ apply state)
| Key { key = "d", ctrl = True } \ scrollHalfDown state
| Key { key = "u", ctrl = True } \ scrollHalfUp state
| Key { key = "Escape" } \ escape state
| Key { key = "Backspace" } \ (state.mode
| Insert \ backspace state
| _ \ { state = state, emit = [] })
| Key { key = "Enter" } \ (state.mode
| Insert \ enter state
| _ \ { state = state, emit = [] })
# any other key
| Key { key = key, printable = True } \ (state.mode
| Insert \ insertChar key state
| _ \ { state = state, emit = [] })
| _ \ { state = state, emit = [] },
view = state emit \
_ = debug! "here" state;
cursor = ui.positioned {
x = state.cursorX,
y = state.cursorY,
child = ui.rect { w = charW * scale, h = charH * scale, color = "rgba(255,255,255,0.5)" }
};
maxLineLen = fold (acc line \ max acc (len line)) 0 state.lines;
totalWidth = maxLineLen * charW * scale + maxLineLen * charGap;
totalHeight = len state.lines * lineH;
# buffer = map (l \ text l) state.lines;
# only render visible lines
startLine = max 0 (floor (state.scrollY / lineH));
visibleCount = floor (ctx.h / lineH) + 2;
endLine = min (len state.lines) (startLine + visibleCount);
visibleLines = slice state.lines startLine endLine;
buffer = mapWithIndex (l i \
ui.positioned {
x = 0,
y = (startLine + i) * lineH,
child = text l
}
) visibleLines;
scrollable {
w = ctx.w,
h = ctx.h,
totalWidth = totalWidth,
totalHeight = totalHeight,
scrollX = state.scrollX,
scrollY = state.scrollY,
onScroll = delta \ emit (Scrolled delta),
child = ui.stack {
children = [
...buffer,
cursor
]
}
} }
} }
}
}; };

Loading…
Cancel
Save