/lib_pypy/pyrepl/commands.py
Python | 384 lines | 308 code | 43 blank | 33 comment | 54 complexity | 15b4b5c8a923c618e6b48fa9b5adcb2a MD5 | raw file
- # Copyright 2000-2010 Michael Hudson-Doyle <micahel@gmail.com>
- # Antonio Cuni
- # Armin Rigo
- #
- # All Rights Reserved
- #
- #
- # 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 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, cmd):
- self.reader = reader
- self.event_name, self.event = cmd
- 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 c.isspace():
- 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):
- import signal
- r = self.reader
- p = r.pos
- r.console.finish()
- os.kill(os.getpid(), signal.SIGSTOP)
- ## this should probably be done
- ## in a handler for SIGCONT?
- r.console.prepare()
- r.pos = p
- r.posxy = 0, 0
- r.dirty = 1
- r.console.screen = []
- class up(MotionCommand):
- def do(self):
- r = self.reader
- for i in range(r.get_arg()):
- bol1 = r.bol()
- if bol1 == 0:
- if r.historyi > 0:
- r.select_item(r.historyi - 1)
- return
- 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):
- if r.historyi < len(r.history):
- r.select_item(r.historyi + 1)
- r.pos = r.eol(0)
- return
- 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.update_screen()
- 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())