diff --git a/pyreadline/clipboard/__init__.py b/pyreadline/clipboard/__init__.py index 4b54c3d..6c76046 100644 --- a/pyreadline/clipboard/__init__.py +++ b/pyreadline/clipboard/__init__.py @@ -1,15 +1,19 @@ +import sys success=False +in_ironpython=sys.version.startswith("IronPython") -try: - from clipboard import GetClipboardText,SetClipboardText - success=True -except ImportError: +if in_ironpython: try: from ironpython_clipboard import GetClipboardText,SetClipboardText success=True except ImportError: pass - +else: + try: + from clipboard import GetClipboardText,SetClipboardText + success=True + except ImportError: + pass diff --git a/pyreadline/console/__init__.py b/pyreadline/console/__init__.py index bb79204..f9a14cc 100644 --- a/pyreadline/console/__init__.py +++ b/pyreadline/console/__init__.py @@ -1,15 +1,18 @@ -import glob +import glob,sys success=False +in_ironpython=sys.version.startswith("IronPython") -try: - from console import * - success=True -except ImportError: - +if in_ironpython: try: from ironpython_console import * success=True + except ImportError: + raise +else: + try: + from console import * + success=True except ImportError: pass diff --git a/pyreadline/console/console.py b/pyreadline/console/console.py index 411c484..b944254 100644 --- a/pyreadline/console/console.py +++ b/pyreadline/console/console.py @@ -209,6 +209,14 @@ class Console(object): self.SetConsoleMode(self.hin, self.inmode) self.FreeConsole() + def _get_top_bot(self): + info = CONSOLE_SCREEN_BUFFER_INFO() + self.GetConsoleScreenBufferInfo(self.hout, byref(info)) + rect = info.srWindow + top = rect.Top + bot = rect.Bottom + return top,bot + def fixcoord(self, x, y): '''Return a long with x and y packed inside, also handle negative x and y.''' if x < 0 or y < 0: @@ -279,7 +287,6 @@ class Console(object): x, y = self.pos() w, h = self.size() scroll = 0 # the result - # split the string into ordinary characters and funny characters chunks = self.motion_char_re.split(text) for chunk in chunks: @@ -344,12 +351,9 @@ class Console(object): return n def write_color(self, text, attr=None): - log_sock(text) - log_sock("%s"%attr) n,res= self.ansiwriter.write_color(text,attr) junk = c_int(0) for attr,chunk in res: - log_sock("%s:%s"%(attr,chunk)) log(str(attr)) log(str(chunk)) self.SetConsoleTextAttribute(self.hout, attr.winattr) @@ -409,8 +413,17 @@ class Console(object): self.WriteConsoleOutputCharacterA(self.hout, text, len(text), pos, byref(n)) self.FillConsoleOutputAttribute(self.hout, attr, n, pos, byref(n)) + def clear_to_end_of_window(self): + top,bot=self._get_top_bot() + pos=self.pos() + w,h=self.size() + self.rectangle( (pos[0],pos[1],w,pos[1]+1)) + if pos[1]>4] + except TypeError: + fg=attr + for chunk in chunks: m = self.escape_parts.match(chunk) if m: log(m.group(1)) attr=ansicolor.get(m.group(1),self.attr) n += len(chunk) - log('attr=%s' % attr) - System.Console.ForegroundColor=attr + System.Console.ForegroundColor=fg + System.Console.BackgroundColor=bg #self.WriteConsoleA(self.hout, chunk, len(chunk), byref(junk), None) System.Console.Write(chunk) return n @@ -215,9 +262,21 @@ class Console(object): self.pos(x,y) self.write_color(text,attr) + def clear_to_end_of_window(self): + oldtop=self.WindowTop + lastline=self.WindowTop+System.Console.WindowHeight + pos=self.pos() + w,h=self.size() + length=w-pos[0]+min((lastline-pos[1]-1),5)*w-1 + self.write_color(length*" ") + self.pos(*pos) + self.WindowTop=oldtop + def rectangle(self, rect, attr=None, fill=' '): '''Fill Rectangle.''' pass + oldtop=self.WindowTop + oldpos=self.pos() #raise NotImplementedError x0, y0, x1, y1 = rect if attr is None: @@ -229,6 +288,7 @@ class Console(object): for y in range(y0, y1): System.Console.SetCursorPosition(x0,y) self.write_color(rowfill,attr) + self.pos(*oldpos) def scroll(self, rect, dx, dy, attr=None, fill=' '): '''Scroll a rectangle.''' @@ -237,23 +297,28 @@ class Console(object): def scroll_window(self, lines): '''Scroll the window by the indicated number of lines.''' - top=System.Console.WindowTop+lines + top=self.WindowTop+lines if top<0: top=0 if top+System.Console.WindowHeight>System.Console.BufferHeight: top=System.Console.BufferHeight - System.Console.WindowTop=top + self.WindowTop=top def getkeypress(self): '''Return next key press event from the queue, ignoring others.''' ck=System.ConsoleKey while 1: - e = System.Console.ReadKey(True) + try: + e = System.Console.ReadKey(True) + except KeyboardInterrupt: + return CTRL_C_EVENT if e.Key == System.ConsoleKey.PageDown: #PageDown self.scroll_window(12) elif e.Key == System.ConsoleKey.PageUp:#PageUp self.scroll_window(-12) elif str(e.KeyChar)=="\000":#Drop deadkeys + log_sock("Deadkey: %s"%e) + return event(self,e) pass else: return event(self,e) @@ -268,10 +333,17 @@ class Console(object): def size(self, width=None, height=None): '''Set/get window size.''' sc=System.Console + + + if width is not None and height is not None: + sc.BufferWidth,sc.BufferHeight=width,height + else: + return sc.BufferWidth,sc.BufferHeight + if width is not None and height is not None: sc.WindowWidth,sc.WindowHeight=width,height else: - return sc.WindowWidth,sc.WindowHeight + return sc.WindowWidth-1,sc.WindowHeight-1 def cursor(self, visible=True, size=None): '''Set cursor on or off.''' @@ -298,12 +370,25 @@ class event(Event): self.char = str(input.KeyChar) self.keycode = input.Key self.state = input.Modifiers - + log_sock("%s,%s,%s"%(input.Modifiers,input.Key,input.KeyChar),"console") self.type="KeyRelease" - self.keysym = make_keysym(self.keycode) self.keyinfo = make_KeyPress(self.char, self.state, self.keycode) +def make_event_from_keydescr(keydescr): + def input(): + return 1 + input.KeyChar="a" + input.Key=System.ConsoleKey.A + input.Modifiers=System.ConsoleModifiers.Shift + input.next_serial=input + e=event(input,input) + del input.next_serial + keyinfo=make_KeyPress_from_keydescr(keydescr) + e.keyinfo=keyinfo + return e + +CTRL_C_EVENT=make_event_from_keydescr("Control-c") def install_readline(hook): class IronPythonWrapper(IronPythonConsole.IConsole): @@ -343,4 +428,4 @@ if __name__ == '__main__': print e.Key,chr(e.KeyChar),ord(e.KeyChar),e.Modifiers del c -System.Console.Clear() + System.Console.Clear() diff --git a/pyreadline/keysyms/ironpython_keysyms.py b/pyreadline/keysyms/ironpython_keysyms.py index d5626bb..b856ad7 100644 --- a/pyreadline/keysyms/ironpython_keysyms.py +++ b/pyreadline/keysyms/ironpython_keysyms.py @@ -8,7 +8,7 @@ #***************************************************************************** import System from common import validkey,KeyPress,make_KeyPress_from_keydescr - +from pyreadline.logger import log_sock c32=System.ConsoleKey Shift=System.ConsoleModifiers.Shift Control=System.ConsoleModifiers.Control @@ -196,7 +196,11 @@ def make_KeyPress(char,state,keycode): control=bool(int(state)&int(Control)) meta=bool(int(state)&int(Alt)) keyname=code2sym_map.get(keycode,"").lower() - if control: + log_sock("make key %s %s %s %s"%(shift,control,meta,keycode),"keysyms") + if control and meta: #equivalent to altgr so clear flags + control=False + meta=False + elif control: char=str(keycode) return KeyPress(char,shift,control,meta,keyname) diff --git a/pyreadline/lineeditor/history.py b/pyreadline/lineeditor/history.py index fd1bccf..4b91e06 100644 --- a/pyreadline/lineeditor/history.py +++ b/pyreadline/lineeditor/history.py @@ -58,7 +58,7 @@ class LineHistory(object): if filename is None: filename=self.history_filename try: - for line in open(filename, 'rt'): + for line in open(filename, 'r'): self.add_history(lineobj.ReadLineTextBuffer(line.rstrip())) except IOError: self.history = [] @@ -179,33 +179,38 @@ class LineHistory(object): return self._non_i_search(1,current) def _search(self, direction, partial): - if (self.lastcommand != self.history_search_forward and - self.lastcommand != self.history_search_backward): - self.query = ''.join(partial[0:partial.point].get_line_text()) - hcstart=max(self.history_cursor,0) - hc = self.history_cursor + direction - while (direction < 0 and hc >= 0) or (direction > 0 and hc < len(self.history)): - h = self.history[hc] - if not self.query: - self.history_cursor = hc - result=lineobj.ReadLineTextBuffer(h,point=len(h.get_line_text())) - return result - elif h.get_line_text().startswith(self.query) and h != partial.get_line_text(): - self.history_cursor = hc - result=lineobj.ReadLineTextBuffer(h,point=partial.point) - return result - hc += direction - else: - if len(self.history)==0: - pass - elif hc>=len(self.history) and not self.query: - self.history_cursor=len(self.history) - return lineobj.ReadLineTextBuffer("",point=0) - elif self.history[hcstart].get_line_text().startswith(self.query) and self.query: - return lineobj.ReadLineTextBuffer(self.history[hcstart],point=partial.point) - else: - return lineobj.ReadLineTextBuffer(partial,point=partial.point) - return lineobj.ReadLineTextBuffer(self.query,point=min(len(self.query),partial.point)) + try: + if (self.lastcommand != self.history_search_forward and + self.lastcommand != self.history_search_backward): + self.query = ''.join(partial[0:partial.point].get_line_text()) + hcstart=max(self.history_cursor,0) + log_sock("hcstart %s"%hcstart) + hc = self.history_cursor + direction + while (direction < 0 and hc >= 0) or (direction > 0 and hc < len(self.history)): + h = self.history[hc] + if not self.query: + self.history_cursor = hc + result=lineobj.ReadLineTextBuffer(h,point=len(h.get_line_text())) + return result + elif h.get_line_text().startswith(self.query) and h != partial.get_line_text(): + self.history_cursor = hc + result=lineobj.ReadLineTextBuffer(h,point=partial.point) + return result + hc += direction + else: + if len(self.history)==0: + pass + elif hc>=len(self.history) and not self.query: + self.history_cursor=len(self.history) + return lineobj.ReadLineTextBuffer("",point=0) + elif self.history[max(min(hcstart,len(self.history)-1),0)].get_line_text().startswith(self.query) and self.query: + return lineobj.ReadLineTextBuffer(self.history[max(min(hcstart,len(self.history)-1),0)],point=partial.point) + else: + return lineobj.ReadLineTextBuffer(partial,point=partial.point) + return lineobj.ReadLineTextBuffer(self.query,point=min(len(self.query),partial.point)) + except IndexError: + log_sock("hcstart:%s %s"%(hcstart,len(self.history))) + raise def history_search_forward(self,partial): # () '''Search forward through the history for the string of characters @@ -218,6 +223,7 @@ class LineHistory(object): '''Search backward through the history for the string of characters between the start of the current line and the point. This is a non-incremental search. By default, this command is unbound.''' + q= self._search(-1,partial) return q diff --git a/pyreadline/logger.py b/pyreadline/logger.py index d82c549..539b042 100644 --- a/pyreadline/logger.py +++ b/pyreadline/logger.py @@ -26,10 +26,10 @@ host="localhost" port=8081 logsocket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) -show_event=["keypress","bound_function","bind_key"] +show_event=["keypress","bound_function","bind_key","console"] show_event=["bound_function"] -sock_silent=False +sock_silent=True def log_sock(s,event_type=None): if sock_silent: @@ -43,4 +43,3 @@ def log_sock(s,event_type=None): pass -log_sock("Starting pyreadline") \ No newline at end of file diff --git a/pyreadline/modes/basemode.py b/pyreadline/modes/basemode.py index 1683187..3689de7 100644 --- a/pyreadline/modes/basemode.py +++ b/pyreadline/modes/basemode.py @@ -6,7 +6,7 @@ # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #***************************************************************************** -import os,re,math,glob +import os,re,math,glob,sys import pyreadline.logger as logger from pyreadline.logger import log from pyreadline.keysyms.common import make_KeyPress_from_keydescr @@ -14,6 +14,7 @@ import pyreadline.lineeditor.lineobj as lineobj import pyreadline.lineeditor.history as history import pyreadline.clipboard as clipboard from pyreadline.error import ReadlineError,GetSetError +in_ironpython=sys.version.startswith("IronPython") class BaseMode(object): mode="base" @@ -173,6 +174,8 @@ class BaseMode(object): if i < len(completions): self.console.write(completions[i].ljust(wmax+1)) self.console.write('\n') + if in_ironpython: + self.prompt=sys.ps1 self._print_prompt() def complete(self, e): # (TAB) diff --git a/pyreadline/modes/emacs.py b/pyreadline/modes/emacs.py index bebb006..9231302 100644 --- a/pyreadline/modes/emacs.py +++ b/pyreadline/modes/emacs.py @@ -6,7 +6,7 @@ # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #***************************************************************************** -import os +import os,sys import pyreadline.logger as logger from pyreadline.logger import log,log_sock from pyreadline.lineeditor.lineobj import Point @@ -21,6 +21,8 @@ def format(keyinfo): k=keyinfo+(ord(keyinfo[-1]),) return "(%s,%s,%s,%s,%x)"%k +in_ironpython=sys.version.startswith("IronPython") + class EmacsMode(basemode.BaseMode): mode="emacs" @@ -28,7 +30,7 @@ class EmacsMode(basemode.BaseMode): super(EmacsMode,self).__init__(rlobj) self._keylog=(lambda x,y: None) self.previous_func=None - self.prompt="" + self.prompt=">>>" def __repr__(self): return "" @@ -105,7 +107,13 @@ class EmacsMode(basemode.BaseMode): self.paste_line_buffer=self.paste_line_buffer[1:] c.write('\r\n') else: - self._readline_from_keyboard() + try: + self._readline_from_keyboard() + except EOFError: + if in_ironpython: + return None + else: + raise c.write('\r\n') self.add_history(self.l_buffer.copy()) diff --git a/pyreadline/rlmain.py b/pyreadline/rlmain.py index 3b394cc..52716e6 100644 --- a/pyreadline/rlmain.py +++ b/pyreadline/rlmain.py @@ -29,6 +29,14 @@ import release from modes import editingmodes +in_ironpython=sys.version.startswith("IronPython") +if in_ironpython:#ironpython does not provide a prompt string to readline + import System + default_prompt=">>> " +else: + default_prompt="" + + def quote_char(c): if ord(c)>0: return c @@ -47,7 +55,7 @@ class Readline(object): self.size = self.console.size() self.prompt_color = None self.command_color = None - self.selection_color =0x00f0 + self.selection_color = self.console.saveattr<<4 self.key_dispatch = {} self.previous_func = None self.first_prompt = True @@ -270,7 +278,7 @@ class Readline(object): c = self.console x, y = c.pos() w, h = c.size() - c.rectangle((x, y, w, y+1)) + c.rectangle((x, y, w+1, y+1)) c.rectangle((0, y+1, w, min(y+3,h))) def _set_cursor(self): @@ -278,15 +286,15 @@ class Readline(object): xc, yc = self.prompt_end_pos w, h = c.size() xc += self.l_buffer.visible_line_width() - while(xc > w): + while(xc >= w): xc -= w yc += 1 c.pos(xc, yc) def _print_prompt(self): c = self.console - log('prompt="%s"' % repr(self.prompt)) x, y = c.pos() + n = c.write_scrolling(self.prompt, self.prompt_color) self.prompt_begin_pos = (x, y - n) self.prompt_end_pos = c.pos() @@ -313,9 +321,11 @@ class Readline(object): n = c.write_scrolling(ltext[stop:], self.command_color) else: n = c.write_scrolling(ltext, self.command_color) - self._update_prompt_pos(n) - self._clear_after() + if hasattr(c,"clear_to_end_of_window"): #Work around function for ironpython due + c.clear_to_end_of_window() #to System.Console's lack of FillFunction + else: + self._clear_after() self._set_cursor() def readline(self, prompt=''): @@ -329,9 +339,7 @@ class Readline(object): self.mode=modes[name] def bind_key(key,name): log("bind %s %s"%(key,name)) - log_sock("bindkey: %s %s"%(key,name),"bind_key") if hasattr(modes[mode],name): - # print "can bind",key,name modes[mode]._bind_key(key,getattr(modes[mode],name)) else: print "Trying to bind unknown command '%s' to key '%s'"%(name,key) diff --git a/pyreadline/test/emacs_test.py b/pyreadline/test/emacs_test.py index 337c16f..18a4d0a 100644 --- a/pyreadline/test/emacs_test.py +++ b/pyreadline/test/emacs_test.py @@ -304,6 +304,19 @@ class TestsHistory (unittest.TestCase): r.input ('Up') self.assert_line(r,'ako',3) + def test_history_3 (self): + r = EmacsModeTest () + r.add_history ('aaaa') + r.add_history ('aaba') + r.add_history ('aaca') + r.add_history ('akca') + r.add_history ('bbb') + r.add_history ('ako') + self.assert_line(r,'',0) + r.input ('k') + r.input ('Up') + self.assert_line(r,'k',1) + def assert_line(self,r,line,cursor):