Cleaning up UI primitives. fixing parser bugs. still struggling to make a command palette lol
This commit is contained in:
parent
2d687b5d38
commit
da97f53729
10 changed files with 66 additions and 23 deletions
|
|
@ -468,7 +468,8 @@ export const builtins: { [name: string]: Value } = {
|
|||
name: 'debug',
|
||||
arity: 2,
|
||||
fn: (label, value) => {
|
||||
expectString(label, 'debug');
|
||||
const str = expectString(label, 'debug');
|
||||
console.log(str, value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { Env } from './env'
|
||||
import type { Value } from './types'
|
||||
import { evaluate } from './interpreter'
|
||||
import { tokenize } from './lexer'
|
||||
import { Parser } from './parser'
|
||||
|
|
|
|||
36
src/os.cg
36
src/os.cg
|
|
@ -1,7 +1,6 @@
|
|||
osState = {
|
||||
query = "",
|
||||
debug = "DEBUG",
|
||||
selectedPaletteIndex = 0
|
||||
focusedPaletteIndex = 0
|
||||
};
|
||||
|
||||
init = {
|
||||
|
|
@ -11,7 +10,23 @@ init = {
|
|||
update = state event \ event
|
||||
| _ \ state;
|
||||
|
||||
listRow = child selected \
|
||||
Clickable {
|
||||
event = osState.query := "",
|
||||
child = Stack {
|
||||
children = [
|
||||
Rect { w = 300, h = 40, strokeWidth = 2, strokeColor = "black", color = "pink" }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
# listRow = child selected \
|
||||
# pre = (selected | True \ "*" | _ \ "");
|
||||
# Text { content = pre & " " & child };
|
||||
|
||||
view = state viewport \
|
||||
_ = debug "focusedPalletIndex" osState.focusedPaletteIndex;
|
||||
|
||||
Positioned {
|
||||
x = 30,
|
||||
y = 30,
|
||||
|
|
@ -26,13 +41,18 @@ view = state viewport \
|
|||
h = 40,
|
||||
onChange = text \ osState.query := text,
|
||||
onKeyDown = key \ key
|
||||
| ArrowUp \ osState.selectedPaletteIndex := max 0 (osState.selectedPaletteIndex + 1)
|
||||
| ArrowDown \ osState.selectedPaletteIndex := osState.selectedPaletteIndex - 1
|
||||
| ArrowUp \ osState.focusedPaletteIndex := max 0 (osState.focusedPaletteIndex - 1)
|
||||
| ArrowDown \ osState.focusedPaletteIndex := (osState.focusedPaletteIndex + 1)
|
||||
| _ \ NoOp
|
||||
},
|
||||
Text { content = osState.debug, x = 8, y = 16 },
|
||||
Column {
|
||||
gap = 10,
|
||||
children = map (t \ Text { content = t, x = 8, y = 16 }) (storeSearch osState.query)
|
||||
Clip {
|
||||
w = 300,
|
||||
h = 300,
|
||||
child = Column {
|
||||
gap = 10,
|
||||
# children = mapWithIndex (t i \ Text { content = str i & " " & t }) (storeSearch osState.query)
|
||||
children = mapWithIndex (t i \ listRow t (osState.focusedPaletteIndex == i)) (storeSearch osState.query)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ export class Parser {
|
|||
if (this.current().kind == 'colon-equals') {
|
||||
const token = this.current();
|
||||
this.advance();
|
||||
const value = this.parseExpression();
|
||||
const value = this.parseExpressionNoMatch();
|
||||
return { kind: 'rebind', target: expr, value, ...this.getPos(token) };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,6 +154,10 @@ export function runApp(app: App, canvas: HTMLCanvasElement, source: string, env:
|
|||
view: ui.view
|
||||
};
|
||||
componentInstances.set(fullKey, instance);
|
||||
} else {
|
||||
// refresh closures, pick up new values
|
||||
instance.update = ui.update;
|
||||
instance.view = ui.view;
|
||||
}
|
||||
|
||||
if (instance.view.kind !== 'closure')
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ map = f list \ list
|
|||
| [] \ []
|
||||
| [x, ...xs] \ [f x, ...map f xs];
|
||||
|
||||
# mapWithIndex : (a \ Number \ b) \ List a \ List b
|
||||
mapWithIndex = f list \
|
||||
init = { i = 0, result = [] };
|
||||
f2 = acc x \ { i = acc.i + 1, result = [...acc.result, f x acc.i] };
|
||||
(fold f2 init list).result;
|
||||
|
||||
# filter : (a \ Bool) \ List a \ List a
|
||||
filter = f list \ list
|
||||
| [] \ []
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ export type NativeFunction = {
|
|||
}
|
||||
|
||||
export type UIValue =
|
||||
| { kind: 'rect', w: number, h: number, color: string, radius?: number }
|
||||
| { kind: 'text', content: string, x: number, y: number }
|
||||
| { kind: 'rect', w: number, h: number, color?: string, strokeColor?: string, strokeWidth?: number, radius?: number }
|
||||
| { kind: 'text', content: string }
|
||||
| { kind: 'row', children: UIValue[], gap: number }
|
||||
| { kind: 'column', children: UIValue[], gap: number }
|
||||
| { kind: 'clickable', child: UIValue, event: Value }
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ textInput = config \ Stateful {
|
|||
Positioned {
|
||||
x = 8 - state.scrollOffset,
|
||||
y = 8,
|
||||
child = Text { content = state.text, x = 0, y = 17 }
|
||||
child = Positioned { x = 0, y = 17, child = Text { content = state.text } }
|
||||
},
|
||||
|
||||
(state.focused
|
||||
|
|
|
|||
17
src/ui.ts
17
src/ui.ts
|
|
@ -27,7 +27,7 @@ export function render(ui: UIValue, canvas: HTMLCanvasElement) {
|
|||
function renderUI(ui: UIValue, ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
switch (ui.kind) {
|
||||
case 'rect': {
|
||||
ctx.fillStyle = ui.color;
|
||||
ctx.fillStyle = ui.color || 'transparent';
|
||||
|
||||
if (ui.radius && ui.radius > 0) {
|
||||
const r = Math.min(ui.radius, ui.w / 2, ui.h / 2);
|
||||
|
|
@ -43,8 +43,21 @@ function renderUI(ui: UIValue, ctx: CanvasRenderingContext2D, x: number, y: numb
|
|||
ctx.arcTo(x, y, x + r, y, r);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
if (ui.strokeColor && ui.strokeWidth) {
|
||||
ctx.strokeStyle = ui.strokeColor;
|
||||
ctx.lineWidth = ui.strokeWidth;
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
} else {
|
||||
ctx.fillRect(x, y, ui.w, ui.h);
|
||||
|
||||
if (ui.strokeColor && ui.strokeWidth) {
|
||||
ctx.strokeStyle = ui.strokeColor;
|
||||
ctx.lineWidth = ui.strokeWidth;
|
||||
ctx.strokeRect(x, y, ui.w, ui.h);;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -53,7 +66,7 @@ function renderUI(ui: UIValue, ctx: CanvasRenderingContext2D, x: number, y: numb
|
|||
case 'text':
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.font = '16px "SF Mono", "Monaco", "Menlo", "Consolas", "Courier New", monospace';
|
||||
ctx.fillText(ui.content, x + ui.x, y + ui.y);
|
||||
ctx.fillText(ui.content, x, y);
|
||||
break;
|
||||
|
||||
case 'row': {
|
||||
|
|
|
|||
|
|
@ -12,29 +12,29 @@ export function valueToUI(value: Value): UIValue {
|
|||
|
||||
switch (value.name) {
|
||||
case 'Rect': {
|
||||
const { w, h, color, radius } = fields;
|
||||
const { w, h, color, radius, strokeColor, strokeWidth } = fields;
|
||||
|
||||
if (w.kind !== 'int' || h.kind !== 'int' || color.kind !== 'string')
|
||||
if (w.kind !== 'int' || h.kind !== 'int')
|
||||
throw new Error('Invalid Rect fields');
|
||||
|
||||
return {
|
||||
kind: 'rect',
|
||||
w: w.value,
|
||||
h: h.value,
|
||||
color: color.value,
|
||||
color: color && color.kind === 'string' ? color.value : undefined,
|
||||
strokeColor: strokeColor && strokeColor.kind === 'string' ? strokeColor.value : undefined,
|
||||
strokeWidth: strokeWidth && strokeWidth.kind === 'int' ? strokeWidth.value : undefined,
|
||||
radius: radius && radius.kind === 'int' ? radius.value : 0
|
||||
};
|
||||
}
|
||||
|
||||
case 'Text': {
|
||||
const x = fields.x;
|
||||
const y = fields.y;
|
||||
const content = fields.content;
|
||||
|
||||
if (content.kind !== 'string' || x.kind !== 'int' || y.kind !== 'int')
|
||||
if (content.kind !== 'string')
|
||||
throw new Error('Invalid Text fields');
|
||||
|
||||
return { kind: 'text', x: x.value, y: y.value, content: content.value };
|
||||
return { kind: 'text', content: content.value };
|
||||
}
|
||||
|
||||
case 'Column': {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue