[shpy-commit] r2873 - in shpy/trunk/dist/shpy: . net
arigo@codespeak.net
arigo@codespeak.net
Wed, 21 Jan 2004 16:33:36 +0100 (MET)
Author: arigo
Date: Wed Jan 21 16:33:35 2004
New Revision: 2873
Added:
shpy/trunk/dist/shpy/net/inputoutput.py
Modified:
shpy/trunk/dist/shpy/net/gateway.py
shpy/trunk/dist/shpy/net/register.py
shpy/trunk/dist/shpy/net/shell.py
shpy/trunk/dist/shpy/ui_pygame.py
Log:
Introduced execution server. You must run a startserver.py process
locally; pressing ALT-ENTER in a cell executes its content in that
process.
Rearranged net/ a bit.
Modified: shpy/trunk/dist/shpy/net/gateway.py
==============================================================================
--- shpy/trunk/dist/shpy/net/gateway.py (original)
+++ shpy/trunk/dist/shpy/net/gateway.py Wed Jan 21 16:33:35 2004
@@ -2,33 +2,6 @@
from unittest2.tool import dyncode
-class SocketIO:
- def __init__(self, sock):
- self.sock = sock
- try:
- sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
- sock.setsockopt(socket.SOL_IP, socket.IP_TOS, 0x10) # IPTOS_LOWDELAY
- except socket.error, e:
- print "Cannot set socket option:", str(e)
-
- def read(self, bytes):
- "Read exactly 'bytes' bytes from the socket."
- buf = ""
- while len(buf) < bytes:
- t = self.sock.recv(bytes - len(buf))
- print 'recv -->', len(t)
- if not t:
- raise EOFError
- buf += t
- return buf
-
- def write(self, data):
- self.sock.sendall(data)
-
- def close(self):
- self.sock.shutdown(2)
-
-
class Gateway:
def __init__(self, io, ns = None):
if ns is None:
Added: shpy/trunk/dist/shpy/net/inputoutput.py
==============================================================================
--- (empty file)
+++ shpy/trunk/dist/shpy/net/inputoutput.py Wed Jan 21 16:33:35 2004
@@ -0,0 +1,39 @@
+import socket
+
+def connect(addr):
+ if isinstance(addr, str):
+ host, port = addr.split(':')
+ port = int(port)
+ addr = (host, port)
+ assert len(addr) == 2
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect(addr)
+ return SocketIO(sock)
+
+class SocketIO:
+ def __init__(self, sock):
+ self.sock = sock
+ try:
+ sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
+ sock.setsockopt(socket.SOL_IP, socket.IP_TOS, 0x10) # IPTOS_LOWDELAY
+ except socket.error, e:
+ print "Cannot set socket option:", str(e)
+
+ def read(self, bytes):
+ "Read exactly 'bytes' bytes from the socket."
+ buf = ""
+ while len(buf) < bytes:
+ t = self.sock.recv(bytes - len(buf))
+ print 'recv -->', len(t)
+ if not t:
+ raise EOFError
+ buf += t
+ return buf
+
+ def write(self, data):
+ self.sock.sendall(data)
+
+ def close(self):
+ self.sock.shutdown(2)
+
+
Modified: shpy/trunk/dist/shpy/net/register.py
==============================================================================
--- shpy/trunk/dist/shpy/net/register.py (original)
+++ shpy/trunk/dist/shpy/net/register.py Wed Jan 21 16:33:35 2004
@@ -1,34 +1,19 @@
import autopath, os
import inspect, socket, pickle, thread
-from shpy.net import gateway, structure
+from shpy.net import gateway, structure, inputoutput
-class ServerGateway(gateway.Gateway):
-
- def __init__(self, hostport = ':8888', ns = None):
- if isinstance(hostport, str):
- host, port = hostport.split(':')
- hostport = (host, int(port))
-
- source = [inspect.getsource(gateway)]
+class InstallableGateway(gateway.Gateway):
+ def __init__(self, addr, ns = None):
+ source = [inspect.getsource(inputoutput),
+ inspect.getsource(gateway),
+ ]
source.append('thread = Gateway(SocketIO(clientsock))')
- source.append('pickler.dump("ok")')
source = "\n".join(source)
-
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.connect(hostport)
- sockfile = sock.makefile('wb',0)
- p = pickle.Pickler(sockfile, bin=True)
- p.dump(source)
- sockfile.close()
- sockfile = sock.makefile('rb',0)
- u = pickle.Unpickler(sockfile)
- res = u.load()
- sockfile.close()
- assert res=='ok', ("could not establish server gateway %r" %
- hostport)
- gateway.Gateway.__init__(self, gateway.SocketIO(sock), ns)
+ sockio = inputoutput.connect(addr)
+ sockio.write(pickle.dumps(source, bin=True))
+ gateway.Gateway.__init__(self, sockio, ns)
def import_remote(self, filename, modname, reload=False):
filename = os.path.join(autopath.thisdir, filename)
@@ -49,6 +34,8 @@
""")
self.exec_remote("".join(l) % locals())
+
+class ServerGateway(InstallableGateway):
def registerclient(self, reload=False):
self.ns['getstructure'] = structure.getstructure
self.import_remote('shared.py', 'shared', reload)
@@ -72,3 +59,71 @@
if 'root' in l:
self.root = l['root']
self.waiting_for_root.release()
+
+ def notifychanges(self, *structures):
+ lines = [structure.representstructure(s) for s in structures]
+ lines.append('''if 1:
+ for c in shared.getclientlist():
+ if c is not gateway:
+ try:
+ rerepresent = c.ns['representstructure']
+ relines = []
+ for structid in %r:
+ obj = getstructure(structid)
+ relines.append(rerepresent(obj))
+ relines.append("terminal.postrepaintevent()")
+ c.exec_remote('\\n'.join(relines))
+ except:
+ import traceback
+ traceback.print_exc()
+ ''' % [structure.getstructureid(s) for s in structures])
+ self.exec_remote('\n'.join(lines))
+
+
+class ExecGateway(InstallableGateway):
+ def userexec_remote(self, lines, callback):
+ # hack: turn the content of the cell into
+ #
+ # if 1:
+ # line1
+ # line2
+ # ...
+ #
+ lines = [' ' + line for line in lines]
+ lines.insert(0, 'if 1:')
+ lines.append('')
+ sourcecode = '\n'.join(lines)
+ try:
+ callbacks = self.callbacks
+ except AttributeError:
+ callbacks = self.callbacks = {}
+ answerid = id(callback)
+ self.callbacks[answerid] = callback
+
+ self.exec_remote('''
+ import sys, StringIO
+ try:
+ execns
+ except:
+ execns = {}
+ oldout, olderr = sys.stdout, sys.stderr
+ try:
+ buffer = StringIO.StringIO()
+ sys.stdout = sys.stderr = buffer
+ try:
+ exec compile(%(sourcecode)r, '<remote stdin>', 'single') in execns
+ except:
+ import traceback
+ traceback.print_exc()
+ finally:
+ sys.stdout=oldout
+ sys.stderr=olderr
+ # fiddle us (the caller) into executing the callback on remote answers
+ gateway.exec_remote(
+ "gateway.invoke_callback(%(answerid)r, %%r)" %% buffer.getvalue())
+ ''' % locals())
+
+ def invoke_callback(self, answerid, value):
+ callback = self.callbacks[answerid]
+ del self.callbacks[answerid]
+ callback(value)
Modified: shpy/trunk/dist/shpy/net/shell.py
==============================================================================
--- shpy/trunk/dist/shpy/net/shell.py (original)
+++ shpy/trunk/dist/shpy/net/shell.py Wed Jan 21 16:33:35 2004
@@ -67,7 +67,7 @@
try:
exec compile(line + '\n','<remote stdin>', 'single')
except:
- print print_exc()
+ print_exc()
finally:
sys.stdout=oldout
sys.stderr=olderr
Modified: shpy/trunk/dist/shpy/ui_pygame.py
==============================================================================
--- shpy/trunk/dist/shpy/ui_pygame.py (original)
+++ shpy/trunk/dist/shpy/ui_pygame.py Wed Jan 21 16:33:35 2004
@@ -7,8 +7,8 @@
from shpy.net.structure import Structure, representstructure, getstructureid
from shpy import info
-#RESOLUTION = (768, 512)
-RESOLUTION = (300, 300)
+RESOLUTION = (768, 512)
+#RESOLUTION = (300, 300)
#FONT = 'lucon.ttf'
FONT = None
HEIGHT = 24
@@ -19,8 +19,7 @@
KEYMAP = {}
for name, value in pygame.locals.__dict__.items():
if name.startswith('K_'):
- KEYMAP[(value, False)] = name
- KEYMAP[(value, True)] = 'CTRL_' + name
+ KEYMAP[value] = name
##LINECACHE = {}
##def rendertext(font, text, fgcolor, bgcolor=(255,255,255,255)):
@@ -34,9 +33,11 @@
class Terminal:
- def __init__(self, hostport):
+ def __init__(self, sharedserver, execserver):
ns = {'terminal': self}
- self.servergateway = shpy.net.register.ServerGateway(hostport, ns)
+ self.servergateway = shpy.net.register.ServerGateway(sharedserver, ns)
+ self.execgateway = shpy.net.register.ExecGateway(execserver)
+
pygame.init()
pygame.key.set_repeat(500,30)
self.screen = pygame.display.set_mode(RESOLUTION, RESIZABLE)
@@ -51,9 +52,8 @@
self.cursor = Structure(x=0, color=info.getcolor())
setattr(self.root.users, username, self.cursor)
#print self.root.users.__dict__
- self.celllist = self.root.cells.list
- if not hasattr(self.cursor, 'cell') or self.cursor.cell not in self.celllist:
- self.cursor.cell = self.celllist[-1]
+ if not hasattr(self.cursor, 'cell') or self.cursor.cell not in self.root.cells.list:
+ self.cursor.cell = self.root.cells.list[-1]
if not hasattr(self.cursor, 'line') or self.cursor.line not in self.cursor.cell.lines:
self.cursor.line = self.cursor.cell.lines[-1]
self.lastline_cell = self.cursor.cell
@@ -70,8 +70,8 @@
lines = self.lastline_cell.lines[:index+1]
ypos = self.drawlinesbackwards(lines)
if ypos > 0:
- index = self.celllist.index(self.lastline_cell)
- remainingcells = self.celllist[:index]
+ index = self.root.cells.list.index(self.lastline_cell)
+ remainingcells = self.root.cells.list[:index]
while remainingcells and ypos > 0:
cell = remainingcells.pop()
ypos = self.drawspacing(ypos)
@@ -124,8 +124,8 @@
cursorindex = self.cursor.cell.lines.index(self.cursor.line)
lastlineindex = self.lastline_cell.lines.index(self.lastline)
else:
- cursorindex = self.celllist.index(self.cursor.cell)
- lastlineindex = self.celllist.index(self.lastline_cell)
+ cursorindex = self.root.cells.list.index(self.cursor.cell)
+ lastlineindex = self.root.cells.list.index(self.lastline_cell)
if cursorindex < lastlineindex:
self.lastline, self.lastline_cell = self.previousline(self.lastline, self.lastline_cell)
else:
@@ -137,9 +137,9 @@
return cell.lines[index-1], cell
else:
# XXX this changes if we have output cells ...
- index = self.celllist.index(cell)
+ index = self.root.cells.list.index(cell)
if index > 0:
- cell = self.celllist[index-1]
+ cell = self.root.cells.list[index-1]
return cell.lines[-1], cell
return line, cell
@@ -149,9 +149,9 @@
return cell.lines[index+1], cell
else:
# XXX this changes if we have output cells ...
- index = self.celllist.index(cell)
- if index + 1 < len(self.celllist):
- cell = self.celllist[index+1]
+ index = self.root.cells.list.index(cell)
+ if index + 1 < len(self.root.cells.list):
+ cell = self.root.cells.list[index+1]
return cell.lines[0], cell
return line, cell
@@ -255,11 +255,33 @@
self.changed[line] = 1
self.changed[newline] = 1
+ def ALT_K_RETURN(self, event):
+ inputcell = self.cursor.cell
+ lines = [line.content for line in inputcell.lines]
+ outputcell = getattr(inputcell, 'outputcell', None)
+ if outputcell is None:
+ outputcell = Structure()
+ inputcell.outputcell = outputcell
+ index = self.root.cells.list.index(inputcell)
+ self.root.cells.list.insert(index+1, outputcell)
+ self.changed[inputcell] = 1
+ self.changed[self.root.cells] = 1
+ outputcell.lines = [Structure(content="")]
+ self.changed[outputcell] = 1
+ self.changed[outputcell.lines[0]] = 1
+ def fill_output_cell(value):
+ lines = value.split('\n')
+ outputcell.lines = [Structure(content=line) for line in lines]
+ self.changed[outputcell] = 1
+ for s in outputcell.lines:
+ self.changed[s] = 1
+ self.execgateway.userexec_remote(lines, fill_output_cell)
+
def run(self):
self.invalid = True
while 1:
if self.changed:
- self.notifychanges(*self.changed.keys())
+ self.servergateway.notifychanges(*self.changed.keys())
self.changed.clear()
self.invalid = True
if self.invalid:
@@ -269,9 +291,13 @@
print event
if event.type == KEYDOWN:
keynames = []
- k = (event.key, bool(event.mod&KMOD_CTRL))
- if k in KEYMAP:
- keynames.append(KEYMAP[k])
+ if event.key in KEYMAP:
+ keyname = KEYMAP[event.key]
+ if event.mod & KMOD_ALT:
+ keyname = 'ALT_' + keyname
+ if event.mod & KMOD_CTRL:
+ keyname = 'CTRL_' + keyname
+ keynames.append(keyname)
if event.unicode:
keynames.append("PRINTABLE_KEY")
for keyname in keynames:
@@ -296,28 +322,14 @@
self.invalid = True
pygame.event.post(pygame.event.Event(WAKEUPEVENT))
- def notifychanges(self, *structures):
- lines = [representstructure(structure) for structure in structures]
- lines.append('''if 1:
- for c in shared.getclientlist():
- if c is not gateway:
- try:
- rerepresent = c.ns['representstructure']
- relines = []
- for structid in %r:
- obj = getstructure(structid)
- relines.append(rerepresent(obj))
- relines.append("terminal.postrepaintevent()")
- c.exec_remote('\\n'.join(relines))
- except:
- import traceback
- traceback.print_exc()
- ''' % [getstructureid(struct) for struct in structures])
- self.servergateway.exec_remote('\n'.join(lines))
-
if __name__ == '__main__':
- t = Terminal(sys.argv[1])
+ sharedserver = sys.argv[1]
+ if len(sys.argv) > 2:
+ execserver = sys.argv[2]
+ else:
+ execserver = 'localhost:8888'
+ t = Terminal(sharedserver, execserver)
try:
t.run()
finally: