diff -r 000000000000 -r ca70ae20a155 src/extras/pyrepl/commands.py --- /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")