wip: stateful components
This commit is contained in:
parent
5f083a7d01
commit
0255f58964
5 changed files with 99 additions and 130 deletions
|
|
@ -30,6 +30,53 @@ proc addTags() {.compileTime.} =
|
|||
static:
|
||||
addTags()
|
||||
|
||||
template toState(x): untyped = "state" & x
|
||||
proc accessState(sv: string): NimNode {.compileTime.} =
|
||||
newTree(nnkBracketExpr, newIdentNode(sv), newIdentNode("key"))
|
||||
|
||||
proc stateDecl(n: NimNode; names: TableRef[string, bool]; decl, init: NimNode) =
|
||||
case n.kind
|
||||
of nnkVarSection, nnkLetSection:
|
||||
for c in n:
|
||||
expectKind c, nnkIdentDefs
|
||||
let typ = c[^2]
|
||||
let val = c[^1]
|
||||
let usedType = if typ.kind != nnkEmpty: typ else: val
|
||||
if usedType.kind == nnkEmpty:
|
||||
error(c, "cannot determine the variable's type")
|
||||
for i in 0 .. c.len-3:
|
||||
let v = $c[i]
|
||||
let sv = toState v
|
||||
decl.add quote do:
|
||||
var `sv` = newJDict[VKey, `usedType`]()
|
||||
if val.kind != nnkEmpty:
|
||||
init.add newTree(nnkAsgn, accessState(sv), val)
|
||||
names[v] = true
|
||||
of nnkStmtList, nnkStmtListExpr:
|
||||
for x in n: stateDecl(x, names, decl, init)
|
||||
of nnkDo:
|
||||
stateDecl(n.body, names, decl, init)
|
||||
of nnkCommentStmt: discard
|
||||
else:
|
||||
error(n, "invalid 'state' declaration")
|
||||
|
||||
proc doState(n: NimNode; names: TableRef[string, bool]; decl, init: NimNode): NimNode =
|
||||
result = n
|
||||
case n.kind
|
||||
of nnkCallKinds:
|
||||
# handle 'state' declaration and remove it from the AST:
|
||||
if n.len == 2 and repr(n[0]) == "state":
|
||||
stateDecl(n[1], names, decl, init)
|
||||
result = newTree(nnkEmpty)
|
||||
of nnkSym, nnkIdent:
|
||||
let v = $n
|
||||
if v in names:
|
||||
let sv = toState v
|
||||
result = accessState(sv)
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
result[i] = doState(n[i], names, decl, init)
|
||||
|
||||
proc unpack(symbolicType: NimNode; index: int): NimNode {.compileTime.} =
|
||||
#let t = symbolicType.getTypeImpl
|
||||
let t = repr(symbolicType)
|
||||
|
|
|
|||
|
|
@ -75,10 +75,12 @@ proc vnodeToDom(n: VNode): Node =
|
|||
elif n.kind == VNodeKind.vthunk:
|
||||
let x = callThunk(vcomponents[n.text], n)
|
||||
result = vnodeToDom(x)
|
||||
n.key = result.key
|
||||
attach n
|
||||
return result
|
||||
elif n.kind == VNodeKind.dthunk:
|
||||
result = callThunk(dcomponents[n.text], n)
|
||||
n.key = result.key
|
||||
attach n
|
||||
return result
|
||||
else:
|
||||
|
|
@ -114,6 +116,8 @@ proc same(n: VNode, e: Node): bool =
|
|||
var
|
||||
dorender: proc (): VNode {.closure.}
|
||||
currentTree: VNode
|
||||
dirty = newJDict[cstring, bool]()
|
||||
dirtyCount: int
|
||||
|
||||
proc replaceById(id: cstring; newTree: Node) =
|
||||
let x = document.getElementById(id)
|
||||
|
|
@ -145,7 +149,27 @@ proc equalsTree(a, b: VNode): bool =
|
|||
b.calcHash()
|
||||
return a.hash == b.hash
|
||||
else:
|
||||
return eq(a, b)
|
||||
result = eq(a, b)
|
||||
|
||||
proc markDirty*(key: VKey) =
|
||||
dirty[&key] = true
|
||||
inc dirtyCount
|
||||
|
||||
proc updateDirtyElements(parent, current: Node, newNode: VNode) =
|
||||
if newNode.key >= 0 and dirty.contains(&newNode.key):
|
||||
dirty.del(&newNode.key)
|
||||
dec dirtyCount
|
||||
let n = vnodeToDom(newNode)
|
||||
if parent == nil:
|
||||
replaceById("ROOT", n)
|
||||
else:
|
||||
parent.replaceChild(n, current)
|
||||
elif newNode.kind != VNodeKind.text and newNode.kind != VNodeKind.vthunk and
|
||||
newNode.kind != VNodeKind.dthunk:
|
||||
for i in 0..newNode.len-1:
|
||||
updateDirtyElements(current, current[i], newNode[i])
|
||||
# leave early if we know there cannot be anything left to do:
|
||||
#if dirtyCount <= 0: return
|
||||
|
||||
proc updateElement(parent, current: Node, newNode, oldNode: VNode) =
|
||||
if not equalsShallow(newNode, oldNode):
|
||||
|
|
@ -217,6 +241,9 @@ proc dodraw() =
|
|||
let olddom = document.getElementById("ROOT")
|
||||
updateElement(nil, olddom, newtree, currentTree)
|
||||
#assert same(newtree, document.getElementById("ROOT"))
|
||||
if dirtyCount > 0:
|
||||
updateDirtyElements(nil, olddom, newtree)
|
||||
dirtyCount = 0
|
||||
currentTree = newtree
|
||||
# now that it's part of the DOM, give it the focus:
|
||||
if toFocus != nil:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue