-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathreact.py
101 lines (73 loc) · 2.58 KB
/
react.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#coding=utf8
import os
import random
import urwid
_APP = None
_ROOT_EL = None
_UPDATE_PIPE = None
def _update_screen():
os.write(_UPDATE_PIPE, b'1')
class Component:
def __init__(self, **props):
self.props = props
self.state = {}
def set_state(self, m,
disable_render=False):
for k, v in m.items():
self.state[k] = v
if not disable_render:
# TODO: just render self
# self.contents = self.render()
if _APP is not None:
self.mount(_APP.render())
# for async update
_update_screen()
def mount(self, el):
# TODO: use loop.widget = el
# https://github.com/zulip/zulip-terminal/blob/master/zulipterminal/core.py#L107
_ROOT_EL.contents = el
def component_did_mount(self):
pass
def render(self):
pass
class React:
instances = {}
n_element = 0
def create_element(type, instance_name, return_instance=False, **props):
random.seed(React.n_element)
React.n_element += 1
obj = React.instances.get(instance_name)
if obj is not None:
obj.props = props
el = obj.render()
else:
obj = type(**props)
if _APP is not None:
el = obj.render()
obj.component_did_mount()
else:
# TODO: move component_did_mount to after render
# now component_did_mount have to call before render,
# or state in component_did_mount can't take effects
obj.component_did_mount()
el = obj.render()
React.instances[instance_name] = obj
return (obj, el) if return_instance else el
def _unhandled(key):
if key == 'ctrl c' or key in ('q', 'Q'):
raise urwid.ExitMainLoop()
class ReactConsole:
def render(app, root_el, palette=None):
global _APP, _ROOT_EL, _UPDATE_PIPE
# reset for dev in repl
React.instances = {}
_ROOT_EL = root_el
_APP, el = app
_APP.mount(el)
loop = urwid.MainLoop(_ROOT_EL, palette=palette, unhandled_input=_unhandled)
# for async update
# see main in https://github.com/zulip/zulip-terminal/blob/master/zulipterminal/core.py
# http://urwid.org/reference/main_loop.html#selecteventloop
# https://github.com/urwid/urwid/commit/83b64fee60fd77bc80f3dda307c74b53b35f6581
_UPDATE_PIPE = loop.watch_pipe(lambda *x, **xs: loop.draw_screen())
loop.run()