11{.used .}
22
33import std/ strutils
4- proc subsNonbreakingSpace (s: var string ) =
5- # # The leading space, if with following spaces, in on contenteditable element
6- # # will become `U+00A0` (whose utf-8 encoding is c2a0)
7- s = s.replace (" \xc2\xa0 " , " " )
8-
94import ./ cpython
105
116import ../ Utils / compat
@@ -14,6 +9,11 @@ import ./lifecycle
149import ../ Objects / frameobject
1510import ../ Parser / [lexer, parser]
1611pyInit (@ [])
12+ proc subsNonbreakingSpace (s: var string ) =
13+ # # The leading space, if with following spaces, in on contenteditable element
14+ # # will become `U+00A0` (whose utf-8 encoding is c2a0)
15+ s = s.replace (" \xc2\xa0 " , " " )
16+
1717
1818var finished = true
1919var rootCst: ParseNode
@@ -26,35 +26,76 @@ proc interactivePython(input: string): bool {. exportc, discardable .} =
2626 lexerInst.clearIndent
2727 return parseCompileEval (input, lexerInst, rootCst, prevF, finished)
2828
29- const prompt = " >>> "
29+ let info = getVersionString (verbose = true )
3030
3131include karax/ prelude
3232import karax/ kdom
33+ import karax/ vstyles
34+
35+ var prompt: kstring
36+
37+ let
38+ suitHeight = (StyleAttr .height, kstring " wrap-content" ) # XXX: still too height
39+ preserveSpaces = (whiteSpace, kstring " pre" ) # ensure spaces remained
40+ monospace = (StyleAttr .font_family, kstring " monospace" )
41+ template oneReplLineNode (editable: static [bool ]; promptExpr, editExpr): VNode {.dirty .} =
42+ buildHtml:
43+ tdiv (class= " line" , style= style (
44+ (display, kstring " flex" ), # make children within one line
45+ suitHeight,
46+ )):
47+ p (class= " prompt" , style= style (
48+ suitHeight, monospace, preserveSpaces,
49+ )):
50+ promptExpr
51+
52+ p (class= " edit" , contenteditable= editable, style= style (
53+ (flex, kstring " 1" ), # without this, it becomes uneditable
54+ (border, kstring " none" ),
55+ (outline, kstring " none" ),
56+ suitHeight, monospace, preserveSpaces,
57+ )):
58+ editExpr
59+ # TODO : arrow-up / arrow-down for history
60+ const historyContainerId = " history-container"
61+ proc pushHistory (prompt: kstring, exp: string ) =
62+ stream.add (prompt, kstring exp)
63+
64+ # auto scroll down when the inputing line is to go down the view
65+ let historyNode = document.getElementById (historyContainerId)
66+ let last = historyNode.lastChild
67+ if last.isNil: return
68+ last.scrollIntoView (ScrollIntoViewOptions (
69+ `block`: " start" , inline: " start" , behavior: " instant" ))
3370
3471proc createDom (): VNode =
3572 result = buildHtml (tdiv):
36- tdiv (class= " stream" ):
37- echo stream.len
73+ tdiv (class= " header" ):
74+ p (class= " info" ):
75+ text info
76+ tdiv (class= " stream" , id= historyContainerId):
3877 for line in stream:
3978 let (prompt, content) = line
40- tdiv (class= " line" ):
41- p (class= " prompt" ):
42- if prompt.len == 0 :
43- text kstring " "
44- else :
45- text prompt
46- p:
47- text content
48- tdiv (class= " line editline" ):
49- p (class= " prompt" ):
50- text prompt
51- p (class= " edit" , contenteditable= " true" ):
52- proc onKeydown (ev: Event , n: VNode ) =
53- if KeyboardEvent (ev).keyCode == 13 :
54- var input = $ n.dom.textContent
55- input.subsNonbreakingSpace
56- interactivePython (input)
57- n.dom.innerHTML = kstring " "
58- ev.preventDefault
79+ tdiv (class= " history" ):
80+ oneReplLineNode (false ,
81+ text prompt, text content
82+ )
83+ oneReplLineNode (true , block :
84+ prompt = if finished:
85+ kstring " >>> "
86+ else :
87+ kstring " ... "
88+ text prompt
89+ ,
90+ block :
91+ proc onKeydown (ev: Event , n: VNode ) =
92+ if KeyboardEvent (ev).keyCode == 13 :
93+ var input = $ n.dom.textContent
94+ input.subsNonbreakingSpace
95+ pushHistory (prompt, input)
96+ interactivePython (input)
97+ n.dom.innerHTML = kstring " "
98+ ev.preventDefault
99+ )
59100
60101setRenderer createDom
0 commit comments