src/extras/pyrepl/commands.py
changeset 0 ca70ae20a155
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/extras/pyrepl/commands.py	Tue Feb 16 10:07:05 2010 +0530
@@ -0,0 +1,371 @@
+#   Copyright 2000-2004 Michael Hudson mwh@python.net
+#
+#                        All Rights Reserved
+#
+# Portions Copyright (c) 2005 Nokia Corporation 
+#
+# Permission to use, copy, modify, and distribute this software and
+# its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appear in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation.
+#
+# THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO
+# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+# INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import ascii
+import sys, os
+
+# Catgories of actions:
+#  killing
+#  yanking
+#  motion
+#  editing
+#  history
+#  finishing
+# [completion]
+
+class Command(object):
+    finish = 0
+    kills_digit_arg = 1
+    def __init__(self, reader, (event_name, event)):
+        self.reader = reader
+        self.event = event
+        self.event_name = event_name
+    def do(self):
+        pass
+
+class KillCommand(Command):
+    def kill_range(self, start, end):
+        if start == end:
+            return
+        r = self.reader
+        b = r.buffer
+        text = b[start:end]
+        del b[start:end]
+        if is_kill(r.last_command):
+            if start < r.pos:
+                r.kill_ring[-1] = text + r.kill_ring[-1]
+            else:
+                r.kill_ring[-1] = r.kill_ring[-1] + text
+        else:
+            r.kill_ring.append(text)
+        r.pos = start
+        r.dirty = 1
+
+class YankCommand(Command):
+    pass
+
+class MotionCommand(Command):
+    pass
+
+class EditCommand(Command):
+    pass
+
+class FinishCommand(Command):
+    finish = 1
+    pass
+
+def is_kill(command):
+    return command and issubclass(command, KillCommand)
+
+def is_yank(command):
+    return command and issubclass(command, YankCommand)
+
+# etc
+
+class digit_arg(Command):
+    kills_digit_arg = 0
+    def do(self):
+        r = self.reader
+        c = self.event[-1]
+        if c == "-":
+            if r.arg is not None:
+                r.arg = -r.arg
+            else:
+                r.arg = -1
+        else:
+            d = int(c)
+            if r.arg is None:
+                r.arg = d
+            else:
+                if r.arg < 0:
+                    r.arg = 10*r.arg - d
+                else:
+                    r.arg = 10*r.arg + d
+        r.dirty = 1
+
+class clear_screen(Command):
+    def do(self):
+        r = self.reader
+        r.console.clear()
+        r.dirty = 1
+
+class refresh(Command):
+    def do(self):
+        self.reader.dirty = 1
+
+class repaint(Command):
+    def do(self):
+        self.reader.dirty = 1
+        self.reader.console.repaint_prep()
+
+class kill_line(KillCommand):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        eol = r.eol()
+        for c in b[r.pos:eol]:
+            if not ascii.isspace(c):
+                self.kill_range(r.pos, eol)
+                return
+        else:
+            self.kill_range(r.pos, eol+1)
+
+class unix_line_discard(KillCommand):
+    def do(self):
+        r = self.reader
+        self.kill_range(r.bol(), r.pos)
+
+# XXX unix_word_rubout and backward_kill_word should actually
+# do different things...
+
+class unix_word_rubout(KillCommand):
+    def do(self):
+        r = self.reader
+        for i in range(r.get_arg()):
+            self.kill_range(r.bow(), r.pos)
+
+class kill_word(KillCommand):
+    def do(self):
+        r = self.reader
+        for i in range(r.get_arg()):
+            self.kill_range(r.pos, r.eow())
+
+class backward_kill_word(KillCommand):
+    def do(self):
+        r = self.reader
+        for i in range(r.get_arg()):
+            self.kill_range(r.bow(), r.pos)
+
+class yank(YankCommand):
+    def do(self):
+        r = self.reader
+        if not r.kill_ring:
+            r.error("nothing to yank")
+            return
+        r.insert(r.kill_ring[-1])
+
+class yank_pop(YankCommand):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        if not r.kill_ring:
+            r.error("nothing to yank")
+            return
+        if not is_yank(r.last_command):
+            r.error("previous command was not a yank")
+            return
+        repl = len(r.kill_ring[-1])
+        r.kill_ring.insert(0, r.kill_ring.pop())
+        t = r.kill_ring[-1]
+        b[r.pos - repl:r.pos] = t
+        r.pos = r.pos - repl + len(t)
+        r.dirty = 1
+
+class interrupt(FinishCommand):
+    def do(self):
+        #import signal
+        self.reader.console.finish()
+        #os.kill(os.getpid(), signal.SIGINT)
+
+class suspend(Command):
+    def do(self):
+        raise "suspend not implemented"
+
+class up(MotionCommand):
+    def do(self):
+        r = self.reader
+        for i in range(r.get_arg()):
+            bol1 = r.bol()
+            if bol1 == 0:
+                r.pos = 0
+                r.error("start of buffer")
+                return
+            bol2 = r.bol(bol1-1)
+            line_pos = r.pos - bol1
+            if line_pos > bol1 - bol2 - 1:
+                r.sticky_y = line_pos
+                r.pos = bol1 - 1
+            else:
+                r.pos = bol2 + line_pos
+
+class down(MotionCommand):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        for i in range(r.get_arg()):
+            bol1 = r.bol()
+            eol1 = r.eol()
+            if eol1 == len(b):
+                r.pos = len(b)
+                r.error("end of buffer")
+                return
+            eol2 = r.eol(eol1+1)
+            if r.pos - bol1 > eol2 - eol1 - 1:
+                r.pos = eol2
+            else:
+                r.pos = eol1 + (r.pos - bol1) + 1
+
+class left(MotionCommand):
+    def do(self):
+        r = self.reader
+        for i in range(r.get_arg()):        
+            p = r.pos - 1
+            if p >= 0:
+                r.pos = p
+            else:
+                self.reader.error("start of buffer")
+
+class right(MotionCommand):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        for i in range(r.get_arg()):
+            p = r.pos + 1
+            if p <= len(b):
+                r.pos = p
+            else:
+                self.reader.error("end of buffer")
+
+class beginning_of_line(MotionCommand):
+    def do(self):
+        self.reader.pos = self.reader.bol()
+
+class end_of_line(MotionCommand):
+    def do(self):
+        r = self.reader
+        self.reader.pos = self.reader.eol()
+
+class home(MotionCommand):
+    def do(self):
+        self.reader.pos = 0
+        
+class end(MotionCommand):
+    def do(self):
+        self.reader.pos = len(self.reader.buffer)
+        
+class forward_word(MotionCommand):
+    def do(self):
+        r = self.reader
+        for i in range(r.get_arg()):
+            r.pos = r.eow()
+    
+class backward_word(MotionCommand):
+    def do(self):
+        r = self.reader
+        for i in range(r.get_arg()):
+            r.pos = r.bow()
+
+class self_insert(EditCommand):
+    def do(self):
+        r = self.reader
+        r.insert(self.event * r.get_arg())
+
+class insert_nl(EditCommand):
+    def do(self):
+        r = self.reader
+        r.insert("\n" * r.get_arg())
+
+class transpose_characters(EditCommand):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        s = r.pos - 1
+        if s < 0:
+            r.error("cannot transpose at start of buffer")
+        else:
+            if s == len(b):
+                s -= 1
+            t = min(s + r.get_arg(), len(b) - 1)
+            c = b[s]
+            del b[s]
+            b.insert(t, c)
+            r.pos = t
+            r.dirty = 1
+
+class backspace(EditCommand):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        for i in range(r.get_arg()):
+            if r.pos > 0:
+                r.pos -= 1
+                del b[r.pos]
+                r.dirty = 1
+            else:
+                self.reader.error("can't backspace at start")
+
+class delete(EditCommand):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        if  ( r.pos == 0 and len(b) == 0 # this is something of a hack
+              and self.event[-1] == "\004"):
+            r.console.finish()
+            raise EOFError
+        for i in range(r.get_arg()):
+            if r.pos != len(b):
+                del b[r.pos]
+                r.dirty = 1
+            else:
+                self.reader.error("end of buffer")
+
+class accept(FinishCommand):
+    def do(self):
+        pass
+
+class help(Command):
+    def do(self):
+        self.reader.msg = self.reader.help_text
+        self.reader.dirty = 1
+
+class invalid_key(Command):
+    def do(self):
+        pending = self.reader.console.getpending()
+        s = ''.join(self.event) + pending.data
+        self.reader.error("`%r' not bound"%s)
+
+class invalid_command(Command):
+    def do(self):
+        s = self.event_name
+        self.reader.error("command `%s' not known"%s)
+
+class qIHelp(Command):
+    def do(self):
+        r = self.reader
+        r.insert((self.event + r.console.getpending().data) * r.get_arg())
+        r.pop_input_trans()
+
+from pyrepl import input
+
+class QITrans(object):
+    def push(self, evt):
+        self.evt = evt
+    def get(self):
+        return ('qIHelp', self.evt.raw)
+
+class quoted_insert(Command):
+    kills_digit_arg = 0
+    def do(self):
+        self.reader.push_input_trans(QITrans())
+
+class save_history(Command):
+    def do(self):
+        self.reader.save_history()
+        self.reader.message("history saved to file")