Skip to content

Commit af9986a

Browse files
committed
feat(js): browser (karax) repl
1 parent c41c3b5 commit af9986a

File tree

3 files changed

+70
-30
lines changed

3 files changed

+70
-30
lines changed

Python/cpython.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import ../Parser/[lexer, parser]
1212
import ../Objects/bundle
1313
import ../Utils/[utils, compat, getplatform]
1414

15-
proc getVersionString(verbose=false): string =
15+
proc getVersionString*(verbose=false): string =
1616
result = "NPython "
1717
if not verbose:
1818
result.add Version

Python/karaxpython.nim

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
{.used.}
22

33
import 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-
94
import ./cpython
105

116
import ../Utils/compat
@@ -14,6 +9,11 @@ import ./lifecycle
149
import ../Objects/frameobject
1510
import ../Parser/[lexer, parser]
1611
pyInit(@[])
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

1818
var finished = true
1919
var 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

3131
include karax/prelude
3232
import 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

3471
proc 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

60101
setRenderer createDom

Utils/compat.nim

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ when defined(js):
88
when dKarax:
99
include karax/prelude
1010
var stream*: seq[(kstring, kstring)]
11-
proc log*(prompt, info: cstring) {. importc .}
12-
11+
1312
import std/jsffi
1413

1514
when defined(nodejs):

0 commit comments

Comments
 (0)