Initial revision
diff --git a/Lib/idlelib/RemoteInterp.py b/Lib/idlelib/RemoteInterp.py
new file mode 100644
index 0000000..724997c
--- /dev/null
+++ b/Lib/idlelib/RemoteInterp.py
@@ -0,0 +1,342 @@
+import select
+import socket
+import struct
+import sys
+import types
+
+VERBOSE = None
+
+class SocketProtocol:
+    """A simple protocol for sending strings across a socket"""
+    BUF_SIZE = 8192
+
+    def __init__(self, sock):
+        self.sock = sock
+        self._buffer = ''
+        self._closed = 0
+
+    def close(self):
+        self._closed = 1
+        self.sock.close()
+
+    def send(self, buf):
+        """Encode buf and write it on the socket"""
+        if VERBOSE:
+            VERBOSE.write('send %d:%s\n' % (len(buf), `buf`))
+        self.sock.send('%d:%s' % (len(buf), buf))
+
+    def receive(self, timeout=0):
+        """Get next complete string from socket or return None
+
+        Raise EOFError on EOF
+        """
+        buf = self._read_from_buffer()
+        if buf is not None:
+            return buf
+        recvbuf = self._read_from_socket(timeout)
+        if recvbuf is None:
+            return None
+        if recvbuf == '' and self._buffer == '':
+            raise EOFError
+        if VERBOSE:
+            VERBOSE.write('recv %s\n' % `recvbuf`)
+        self._buffer = self._buffer + recvbuf
+        r = self._read_from_buffer()
+        return r
+
+    def _read_from_socket(self, timeout):
+        """Does not block"""
+        if self._closed:
+            return ''
+        if timeout is not None:
+            r, w, x = select.select([self.sock], [], [], timeout)
+        if timeout is None or r:
+            return self.sock.recv(self.BUF_SIZE)
+        else:
+            return None
+
+    def _read_from_buffer(self):
+        buf = self._buffer
+        i = buf.find(':')
+        if i == -1:
+            return None
+        buflen = int(buf[:i])
+        enclen = i + 1 + buflen
+        if len(buf) >= enclen:
+            s = buf[i+1:enclen]
+            self._buffer = buf[enclen:]
+            return s
+        else:
+            self._buffer = buf
+        return None
+
+# helpers for registerHandler method below
+
+def get_methods(obj):
+    methods = []
+    for name in dir(obj):
+        attr = getattr(obj, name)
+        if callable(attr):
+            methods.append(name)
+    if type(obj) == types.InstanceType:
+        methods = methods + get_methods(obj.__class__)
+    if type(obj) == types.ClassType:
+        for super in obj.__bases__:
+            methods = methods + get_methods(super)
+    return methods
+
+class CommandProtocol:
+    def __init__(self, sockp):
+        self.sockp = sockp
+        self.seqno = 0
+        self.handlers = {}
+
+    def close(self):
+        self.sockp.close()
+        self.handlers.clear()
+
+    def registerHandler(self, handler):
+        """A Handler is an object with handle_XXX methods"""
+        for methname in get_methods(handler):
+            if methname[:7] == "handle_":
+                name = methname[7:]
+                self.handlers[name] = getattr(handler, methname)
+
+    def send(self, cmd, arg='', seqno=None):
+        if arg:
+            msg = "%s %s" % (cmd, arg)
+        else:
+            msg = cmd
+        if seqno is None:
+            seqno = self.get_seqno()
+        msgbuf = self.encode_seqno(seqno) + msg
+        self.sockp.send(msgbuf)
+        if cmd == "reply":
+            return
+        reply = self.sockp.receive(timeout=None)
+        r_cmd, r_arg, r_seqno = self._decode_msg(reply)
+        assert r_seqno == seqno and r_cmd == "reply", "bad reply"
+        return r_arg
+
+    def _decode_msg(self, msg):
+        seqno = self.decode_seqno(msg[:self.SEQNO_ENC_LEN])
+        msg = msg[self.SEQNO_ENC_LEN:]
+        parts = msg.split(" ", 2)
+        if len(parts) == 1:
+            cmd = msg
+            arg = ''
+        else:
+            cmd = parts[0]
+            arg = parts[1]
+        return cmd, arg, seqno
+
+    def dispatch(self):
+        msg = self.sockp.receive()
+        if msg is None:
+            return
+        cmd, arg, seqno = self._decode_msg(msg)
+        self._current_reply = seqno
+        h = self.handlers.get(cmd, self.default_handler)
+        try:
+            r = h(arg)
+        except TypeError, msg:
+            raise TypeError, "handle_%s: %s" % (cmd, msg)
+        if self._current_reply is None:
+            if r is not None:
+                sys.stderr.write("ignoring %s return value type %s\n" % \
+                                 (cmd, type(r).__name__))
+            return
+        if r is None:
+            r = ''
+        if type(r) != types.StringType:
+            raise ValueError, "invalid return type for %s" % cmd
+        self.send("reply", r, seqno=seqno)
+
+    def reply(self, arg=''):
+        """Send a reply immediately
+
+        otherwise reply will be sent when handler returns
+        """
+        self.send("reply", arg, self._current_reply)
+        self._current_reply = None
+
+    def default_handler(self, arg):
+        sys.stderr.write("WARNING: unhandled message %s\n" % arg)
+        return ''
+
+    SEQNO_ENC_LEN = 4
+
+    def get_seqno(self):
+        seqno = self.seqno
+        self.seqno = seqno + 1
+        return seqno
+
+    def encode_seqno(self, seqno):
+        return struct.pack("I", seqno)
+
+    def decode_seqno(self, buf):
+        return struct.unpack("I", buf)[0]
+
+
+class StdioRedirector:
+    """Redirect sys.std{in,out,err} to a set of file-like objects"""
+
+    def __init__(self, stdin, stdout, stderr):
+        self.stdin = stdin
+        self.stdout = stdout
+        self.stderr = stderr
+
+    def redirect(self):
+        self.save()
+        sys.stdin = self.stdin
+        sys.stdout = self.stdout
+        sys.stderr = self.stderr
+
+    def save(self):
+        self._stdin = sys.stdin
+        self._stdout = sys.stdout
+        self._stderr = sys.stderr
+
+    def restore(self):
+        sys.stdin = self._stdin
+        sys.stdout = self._stdout
+        sys.stderr = self._stderr
+
+class IOWrapper:
+    """Send output from a file-like object across a SocketProtocol
+
+    XXX Should this be more tightly integrated with the CommandProtocol?
+    """
+
+    def __init__(self, name, cmdp):
+        self.name = name
+        self.cmdp = cmdp
+        self.buffer = []
+
+class InputWrapper(IOWrapper):
+    def write(self, buf):
+        # XXX what should this do on Windows?
+        raise IOError, (9, '[Errno 9] Bad file descriptor')
+
+    def read(self, arg=None):
+        if arg is not None:
+            if arg <= 0:
+                return ''
+        else:
+            arg = 0
+        return self.cmdp.send(self.name, "read,%s" % arg)
+
+    def readline(self):
+        return self.cmdp.send(self.name, "readline")
+
+class OutputWrapper(IOWrapper):
+    def write(self, buf):
+        self.cmdp.send(self.name, buf)
+
+    def read(self, arg=None):
+        return ''
+
+class RemoteInterp:
+    def __init__(self, sock):
+        self._sock = SocketProtocol(sock)
+        self._cmd = CommandProtocol(self._sock)
+        self._cmd.registerHandler(self)
+
+    def run(self):
+        try:
+            while 1:
+                self._cmd.dispatch()
+        except EOFError:
+            pass
+
+    def handle_execfile(self, arg):
+        self._cmd.reply()
+        io = StdioRedirector(InputWrapper("stdin", self._cmd),
+                             OutputWrapper("stdout", self._cmd),
+                             OutputWrapper("stderr", self._cmd))
+        io.redirect()
+        execfile(arg, {'__name__':'__main__'})
+        io.restore()
+        self._cmd.send("terminated")
+
+    def handle_quit(self, arg):
+        self._cmd.reply()
+        self._cmd.close()
+
+def startRemoteInterp(id):
+    import os
+    # UNIX domain sockets are simpler for starters
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    sock.bind("/var/tmp/ri.%s" % id)
+    try:
+        sock.listen(1)
+        cli, addr = sock.accept()
+        rinterp = RemoteInterp(cli)
+        rinterp.run()
+    finally:
+        os.unlink("/var/tmp/ri.%s" % id)
+
+class RIClient:
+    """Client of the remote interpreter"""
+    def __init__(self, sock):
+        self._sock = SocketProtocol(sock)
+        self._cmd = CommandProtocol(self._sock)
+        self._cmd.registerHandler(self)
+
+    def execfile(self, file):
+        self._cmd.send("execfile", file)
+
+    def run(self):
+        try:
+            while 1:
+                self._cmd.dispatch()
+        except EOFError:
+            pass
+
+    def handle_stdout(self, buf):
+        sys.stdout.write(buf)
+##        sys.stdout.flush()
+
+    def handle_stderr(self, buf):
+        sys.stderr.write(buf)
+
+    def handle_stdin(self, arg):
+        if arg == "readline":
+            return sys.stdin.readline()
+        i = arg.find(",") + 1
+        bytes = int(arg[i:])
+        if bytes == 0:
+            return sys.stdin.read()
+        else:
+            return sys.stdin.read(bytes)
+
+    def handle_terminated(self, arg):
+        self._cmd.reply()
+        self._cmd.send("quit")
+        self._cmd.close()
+
+def riExec(id, file):
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    sock.connect("/var/tmp/ri.%s" % id)
+    cli = RIClient(sock)
+    cli.execfile(file)
+    cli.run()
+
+if __name__ == "__main__":
+    import sys
+    import getopt
+
+    SERVER = 1
+    opts, args = getopt.getopt(sys.argv[1:], 'cv')
+    for o, v in opts:
+        if o == '-c':
+            SERVER = 0
+        elif o == '-v':
+            VERBOSE = sys.stderr
+    id = args[0]
+
+    if SERVER:
+        startRemoteInterp(id)
+    else:
+        file = args[1]
+        riExec(id, file)
diff --git a/Lib/idlelib/idle b/Lib/idlelib/idle
new file mode 100755
index 0000000..2a85497
--- /dev/null
+++ b/Lib/idlelib/idle
@@ -0,0 +1,12 @@
+#! /usr/bin/env python
+
+import os
+import sys
+from idlelib import IdleConf
+
+idle_dir = os.path.dirname(IdleConf.__file__)
+IdleConf.load(idle_dir)
+
+# defer importing Pyshell until IdleConf is loaded
+from idlelib import PyShell
+PyShell.main()
diff --git a/Lib/idlelib/setup.py b/Lib/idlelib/setup.py
new file mode 100644
index 0000000..73f3a81
--- /dev/null
+++ b/Lib/idlelib/setup.py
@@ -0,0 +1,81 @@
+import os,glob
+from distutils.core import setup
+from distutils.command.build_py import build_py
+from distutils.command.install_lib import install_lib
+import idlever
+
+# name of idle package
+idlelib = "idlelib"
+
+# the normal build_py would not incorporate the .txt files
+txt_files = ['config-unix.txt','config-win.txt','config.txt']
+Icons = glob.glob1("Icons","*.gif")
+class idle_build_py(build_py):
+    def get_plain_outfile(self, build_dir, package, file):
+        # like get_module_outfile, but does not append .py
+        outfile_path = [build_dir] + list(package) + [file]
+        return apply(os.path.join, outfile_path)
+
+    def run(self):
+        # Copies all .py files, then also copies the txt and gif files
+        build_py.run(self)
+        assert self.packages == [idlelib]
+        for name in txt_files:
+            outfile = self.get_plain_outfile(self.build_lib, [idlelib], name)
+            dir = os.path.dirname(outfile)
+            self.mkpath(dir)
+            self.copy_file(name, outfile, preserve_mode = 0)
+        for name in Icons:
+            outfile = self.get_plain_outfile(self.build_lib,
+                                             [idlelib,"Icons"], name)
+            dir = os.path.dirname(outfile)
+            self.mkpath(dir)
+            self.copy_file(os.path.join("Icons",name),
+                           outfile, preserve_mode = 0)
+
+    def get_source_files(self):
+        # returns the .py files, the .txt files, and the icons
+        icons = [os.path.join("Icons",name) for name in Icons]
+        return build_py.get_source_files(self)+txt_files+icons
+
+    def get_outputs(self, include_bytecode=1):
+        # returns the built files
+        outputs = build_py.get_outputs(self, include_bytecode)
+        if not include_bytecode:
+            return outputs
+        for name in txt_files:
+            filename = self.get_plain_outfile(self.build_lib,
+                                              [idlelib], name)
+            outputs.append(filename)
+        for name in Icons:
+            filename = self.get_plain_outfile(self.build_lib,
+                                              [idlelib,"Icons"], name)
+            outputs.append(filename)
+        return outputs
+
+# Arghhh. install_lib thinks that all files returned from build_py's
+# get_outputs are bytecode files
+class idle_install_lib(install_lib):
+    def _bytecode_filenames(self, files):
+        files = [n for n in files if n.endswith('.py')]
+        return install_lib._bytecode_filenames(self,files)
+
+
+setup(name="IDLE",
+      version = idlever.IDLE_VERSION,
+      description = "IDLE, the Python IDE",
+      author = "Guido van Rossum",
+      author_email = "guido@python.org",
+      #url =
+      long_description =
+"""IDLE is a Tkinter based IDE for Python. It is written in 100% pure
+Python and works both on Windows and Unix. It features a multi-window
+text editor with multiple undo, Python colorizing, and many other things,
+as well as a Python shell window and a debugger.""",
+
+      cmdclass = {'build_py':idle_build_py,
+                  'install_lib':idle_install_lib},
+      package_dir = {idlelib:'.'},
+      packages = [idlelib],
+      scripts = ['idle']
+      )