diff --git a/doc/ChangeLog b/doc/ChangeLog index 265acc6..bb582a2 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,17 @@ +2006-04-18 Jörgen Stenarson + * Added more tests for emacsmode + * Made changes in lineeditor + * Added some new commands for move-selection + * primitive logging in tests (both vi and emacs) to show what + functions are tested + * winconstants.py are added to remove dependency on win32all + +2006-04-04 Jörgen Stenarson + * started tests for emacsmode and lineeditor + * assert in lineeditor for point<=len(l_buffer) required changes in vi_mode + * Changes in history_search_forward and history_search_backward, added tests + * Added a few more properties to basemode + 2006-03-31 Jörgen Stenarson * Merged patch from Michael Graz for the vi mode * test directory now have a vi_test, should add more tests diff --git a/pyreadline/clipboard.py b/pyreadline/clipboard.py index 7835460..6a597d3 100644 --- a/pyreadline/clipboard.py +++ b/pyreadline/clipboard.py @@ -34,7 +34,7 @@ ################################################################################### from ctypes import * -from win32con import CF_TEXT, GHND +from winconstants import CF_TEXT, GHND OpenClipboard = windll.user32.OpenClipboard EmptyClipboard = windll.user32.EmptyClipboard diff --git a/pyreadline/configuration/pyreadlineconfig.ini b/pyreadline/configuration/pyreadlineconfig.ini index dacdc27..c55a206 100644 --- a/pyreadline/configuration/pyreadlineconfig.ini +++ b/pyreadline/configuration/pyreadlineconfig.ini @@ -12,13 +12,11 @@ bind_key("Control-b", "backward_char") bind_key("Right", "forward_char") bind_key("Control-f", "forward_char") bind_key("Alt-f", "forward_word") -bind_key("Control-Right", "forward_word") bind_key("Shift-Right", "forward_char_extend_selection") bind_key("Shift-Left", "backward_char_extend_selection") bind_key("Shift-Control-Right", "forward_word_extend_selection") bind_key("Shift-Control-Left", "backward_word_extend_selection") bind_key("Alt-b", "backward_word") -bind_key("Control-Left", "backward_word") bind_key("Clear", "clear_screen") bind_key("Control-l", "clear_screen") bind_key("Control-a", "beginning_of_line") diff --git a/pyreadline/keysyms.py b/pyreadline/keysyms.py index 598f28c..ef298ac 100644 --- a/pyreadline/keysyms.py +++ b/pyreadline/keysyms.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 win32con as c32 +import winconstants as c32 from ctypes import windll import ctypes # table for translating virtual keys to X windows key symbols @@ -135,6 +135,9 @@ def keyname_to_keyinfo(keyname): if lkeyname.startswith('control-'): control = True keyname = keyname[8:] + elif lkeyname.startswith('ctrl-'): + control = True + keyname = keyname[5:] elif lkeyname.startswith('meta-'): meta = True keyname = keyname[5:] diff --git a/pyreadline/lineeditor/lineobj.py b/pyreadline/lineeditor/lineobj.py index 50c2d25..2a05070 100644 --- a/pyreadline/lineeditor/lineobj.py +++ b/pyreadline/lineeditor/lineobj.py @@ -280,7 +280,7 @@ class TextLine(object): stop=key.stop(self) else: stop=key.stop - return TextLine(self.line_buffer[start:stop]) + return TextLine(self.line_buffer[start:stop],point=0) elif isinstance(key,LinePositioner): return self.line_buffer[key(self)] elif isinstance(key,tuple): @@ -290,6 +290,7 @@ class TextLine(object): return self.line_buffer[key] def __delitem__(self,key): + point=self.point if isinstance(key,LineSlice): key=key(self) if isinstance(key,slice): @@ -297,21 +298,26 @@ class TextLine(object): stop=key.stop if isinstance(start,LinePositioner): start=start(self) + elif start is None: + start=0 if isinstance(stop,LinePositioner): stop=stop(self) + elif stop is None: + stop=EndOfLine(self) elif isinstance(key,LinePositioner): start=key(self) stop=start+1 else: start=key stop=key+1 - if self.point>stop: - self.point=self.point-(stop-start) - elif self.point>=start and self.point <=stop: - self.point=start prev=self.line_buffer[:start] rest=self.line_buffer[stop:] self.line_buffer=prev+rest + if point>stop: + self.point=point-(stop-start) + elif point>=start and point <=stop: + self.point=start + def __setitem__(self,key,value): if isinstance(key,LineSlice): @@ -328,7 +334,10 @@ class TextLine(object): start=key stop=key+1 value=TextLine(value).line_buffer - self.line_buffer=prev+value+rest + out=prev+value+rest + if len(out)>=len(self): + self.point=len(self) + self.line_buffer=out def __len__(self): return len(self.line_buffer) @@ -366,6 +375,10 @@ class ReadLineTextBuffer(TextLine): self.selection_mark=-1 self.enable_selection=True + def __repr__(self): + return 'ReadLineTextBuffer("%s",point=%s,mark=%s,selection_mark=%s)'%(self.line_buffer,self.point,self.mark,self.selection_mark) + + def insert_text(self,char): self.delete_selection() self.selection_mark=-1 @@ -393,6 +406,10 @@ class ReadLineTextBuffer(TextLine): self.selection_mark=-1 self.point=NextWordStart + def forward_word_end(self): + self.selection_mark=-1 + self.point=NextWordEnd + def backward_word(self): self.selection_mark=-1 self.point=PrevWordStart @@ -423,6 +440,11 @@ class ReadLineTextBuffer(TextLine): self.selection_mark=self.point self.point=NextWordStart + def forward_word_end_extend_selection(self): + if self.enable_selection and self.selection_mark<0: + self.selection_mark=self.point + self.point=NextWordEnd + def backward_word_extend_selection(self): if self.enable_selection and self.selection_mark<0: self.selection_mark=self.point @@ -431,7 +453,7 @@ class ReadLineTextBuffer(TextLine): ######### delete def delete_selection(self): - if self.enable_selection and self.selection_mark>0: + if self.enable_selection and self.selection_mark>=0: if self.selection_mark0: + if self.l_buffer.enable_selection and self.l_buffer.selection_mark>=0: start=len(self.l_buffer[:self.l_buffer.selection_mark].quoted_text()) stop=len(self.l_buffer[:self.l_buffer.point].quoted_text()) if start>stop: diff --git a/pyreadline/test/common.py b/pyreadline/test/common.py index 5ddf14b..33d41a6 100644 --- a/pyreadline/test/common.py +++ b/pyreadline/test/common.py @@ -8,7 +8,8 @@ from pyreadline.modes.emacs import * from pyreadline import keysyms from pyreadline.lineeditor import lineobj - +from pyreadline.keysyms import key_text_to_keyinfo +import unittest class MockReadline: def __init__ (self): self.l_buffer=lineobj.ReadLineTextBuffer("") @@ -60,3 +61,10 @@ def keytext_to_keyinfo_and_event (keytext): event = Event (chr (keyinfo [3])) return keyinfo, event +#override runTests from from main in unittest to remove sys.exit call +class Tester(unittest.TestProgram): + def runTests(self): + if self.testRunner is None: + self.testRunner = unittest.TextTestRunner(verbosity=self.verbosity) + result = self.testRunner.run(self.test) +# sys.exit(not result.wasSuccessful()) diff --git a/pyreadline/test/emacs_test.py b/pyreadline/test/emacs_test.py index 8f65b29..0eb5cdd 100644 --- a/pyreadline/test/emacs_test.py +++ b/pyreadline/test/emacs_test.py @@ -17,7 +17,9 @@ from pyreadline.lineeditor import lineobj from common import * #---------------------------------------------------------------------- + class EmacsModeTest (EmacsMode): + tested_commands={} def __init__ (self): EmacsMode.__init__ (self, MockReadline()) self.mock_console = MockConsole () @@ -26,7 +28,7 @@ class EmacsModeTest (EmacsMode): self.completer = self.mock_completer self.completer_delims = ' ' self.tabstop = 4 - + def get_mock_console (self): return self.mock_console console = property (get_mock_console) @@ -50,8 +52,11 @@ class EmacsModeTest (EmacsMode): for key in lst_key: keyinfo, event = keytext_to_keyinfo_and_event (key) dispatch_func = self.key_dispatch.get(keyinfo,self.self_insert) + self.tested_commands[dispatch_func.__name__]=dispatch_func +# print key,dispatch_func.__name__ dispatch_func (event) self.previous_func=dispatch_func + def accept_line (self, e): if EmacsMode.accept_line (self, e): # simulate return @@ -63,7 +68,7 @@ class EmacsModeTest (EmacsMode): #---------------------------------------------------------------------- -class Tests (unittest.TestCase): +class TestsKeyinfo (unittest.TestCase): def test_keyinfo (self): keyinfo, event = keytext_to_keyinfo_and_event ('"d"') @@ -76,6 +81,149 @@ class Tests (unittest.TestCase): self.assertEqual ('\x1b', event.char) +class TestsMovement (unittest.TestCase): + def test_cursor (self): + r = EmacsModeTest () + self.assertEqual (r.line, '') + r.input('"First Second Third"') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + r.input('Control-a') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 0) + r.input('Control-e') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + r.input('Home') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 0) + r.input('Right') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 1) + r.input('Ctrl-f') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 2) + r.input('Ctrl-Right') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 5) + r.input('Ctrl-Right') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 12) + r.input('Ctrl-Right') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + r.input('Ctrl-Right') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + r.input('Ctrl-Left') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 13) + r.input('Ctrl-Left') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 6) + r.input('Ctrl-Left') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 0) + r.input('Ctrl-Left') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 0) + + +class TestsDelete (unittest.TestCase): + def test_delete (self): + r = EmacsModeTest () + self.assertEqual (r.line, '') + r.input('"First Second Third"') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + r.input('Delete') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + r.input('Left') + r.input('Left') + r.input('Delete') + self.assertEqual (r.line, 'First Second Thid') + self.assertEqual (r.line_cursor, 16) + r.input('Delete') + self.assertEqual (r.line, 'First Second Thi') + self.assertEqual (r.line_cursor, 16) + r.input('Backspace') + self.assertEqual (r.line, 'First Second Th') + self.assertEqual (r.line_cursor, 15) + r.input('Home') + r.input('Right') + r.input('Right') + self.assertEqual (r.line, 'First Second Th') + self.assertEqual (r.line_cursor, 2) + r.input('Backspace') + self.assertEqual (r.line, 'Frst Second Th') + self.assertEqual (r.line_cursor, 1) + r.input('Backspace') + self.assertEqual (r.line, 'rst Second Th') + self.assertEqual (r.line_cursor, 0) + r.input('Backspace') + self.assertEqual (r.line, 'rst Second Th') + self.assertEqual (r.line_cursor, 0) + r.input('Escape') + self.assertEqual (r.line, '') + self.assertEqual (r.line_cursor, 0) + + + def test_delete_word (self): + r = EmacsModeTest () + self.assertEqual (r.line, '') + r.input('"First Second Third"') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + r.input('Control-Backspace') + self.assertEqual (r.line, 'First Second ') + self.assertEqual (r.line_cursor, 13) + r.input('Backspace') + r.input('Left') + r.input('Left') + self.assertEqual (r.line, 'First Second') + self.assertEqual (r.line_cursor, 10) + r.input('Control-Backspace') + self.assertEqual (r.line, 'First nd') + self.assertEqual (r.line_cursor, 6) + r.input('Escape') + self.assertEqual (r.line, '') + self.assertEqual (r.line_cursor, 0) + + +class TestsSelectionMovement (unittest.TestCase): + def test_cursor (self): + r = EmacsModeTest () + self.assertEqual (r.line, '') + r.input('"First Second Third"') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 18) + self.assertEqual (r.l_buffer.selection_mark, -1) + r.input('Home') + r.input('Shift-Right') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 1) + self.assertEqual (r.l_buffer.selection_mark, 0) + r.input('Shift-Control-Right') + self.assertEqual (r.line, 'First Second Third') + self.assertEqual (r.line_cursor, 5) + self.assertEqual (r.l_buffer.selection_mark, 0) + r.input('"a"') + self.assertEqual (r.line, 'a Second Third') + self.assertEqual (r.line_cursor, 1) + self.assertEqual (r.l_buffer.selection_mark, -1) + r.input('Shift-End') + self.assertEqual (r.line, 'a Second Third') + self.assertEqual (r.line_cursor, 14) + self.assertEqual (r.l_buffer.selection_mark, 1) + r.input('Delete') + self.assertEqual (r.line, 'a') + self.assertEqual (r.line_cursor, 1) + self.assertEqual (r.l_buffer.selection_mark, -1) + + + +class TestsHistory (unittest.TestCase): def test_history_1 (self): r = EmacsModeTest () r.add_history ('aa') @@ -156,5 +304,18 @@ class Tests (unittest.TestCase): #---------------------------------------------------------------------- if __name__ == '__main__': - unittest.main() - + Tester() + tested=EmacsModeTest.tested_commands.keys() + tested.sort() + print " Tested functions ".center(60,"-") + print "\n".join(tested) + print + + all_funcs=dict([(x.__name__,x) for x in EmacsModeTest().key_dispatch.values()]) + all_funcs=all_funcs.keys() + not_tested=[x for x in all_funcs if x not in tested] + not_tested.sort() + print " Not tested functions ".center(60,"-") + print "\n".join(not_tested) + + \ No newline at end of file diff --git a/pyreadline/test/vi_test.py b/pyreadline/test/vi_test.py index 6f04145..cfc12e1 100644 --- a/pyreadline/test/vi_test.py +++ b/pyreadline/test/vi_test.py @@ -16,6 +16,7 @@ from common import * #---------------------------------------------------------------------- class ViModeTest (ViMode): + tested_commands={} def __init__ (self): ViMode.__init__ (self, MockReadline()) self.mock_console = MockConsole () @@ -49,6 +50,7 @@ class ViModeTest (ViMode): for key in lst_key: keyinfo, event = keytext_to_keyinfo_and_event (key) dispatch_func = self.key_dispatch [keyinfo] + self.tested_commands[dispatch_func.__name__]=dispatch_func dispatch_func (event) def vi_accept_line (self, e): @@ -2123,5 +2125,19 @@ class Tests (unittest.TestCase): #---------------------------------------------------------------------- if __name__ == '__main__': - unittest.main() + Tester() + tested=ViModeTest.tested_commands.keys() + tested.sort() + print " Tested functions ".center(60,"-") + print "\n".join(tested) + print + + all_funcs=dict([(x.__name__,x) for x in ViModeTest().key_dispatch.values()]) + all_funcs=all_funcs.keys() + not_tested=[x for x in all_funcs if x not in tested] + not_tested.sort() + print " Not tested functions ".center(60,"-") + print "\n".join(not_tested) + + \ No newline at end of file diff --git a/pyreadline/winconstants.py b/pyreadline/winconstants.py new file mode 100644 index 0000000..5e0ed63 --- /dev/null +++ b/pyreadline/winconstants.py @@ -0,0 +1,171 @@ +#This file contains constants that are normally found in win32all +#But included here to avoid the dependency + +VK_LBUTTON=1 +VK_RBUTTON=2 +VK_CANCEL=3 +VK_MBUTTON=4 +VK_XBUTTON1=5 +VK_XBUTTON2=6 +VK_BACK=8 +VK_TAB=9 +VK_CLEAR=12 +VK_RETURN=13 +VK_SHIFT=16 +VK_CONTROL=17 +VK_MENU=18 +VK_PAUSE=19 +VK_CAPITAL=20 +VK_KANA=0x15 +VK_HANGEUL=0x15 +VK_HANGUL=0x15 +VK_JUNJA=0x17 +VK_FINAL=0x18 +VK_HANJA=0x19 +VK_KANJI=0x19 +VK_ESCAPE=0x1B +VK_CONVERT=0x1C +VK_NONCONVERT=0x1D +VK_ACCEPT=0x1E +VK_MODECHANGE=0x1F +VK_SPACE=32 +VK_PRIOR=33 +VK_NEXT=34 +VK_END=35 +VK_HOME=36 +VK_LEFT=37 +VK_UP=38 +VK_RIGHT=39 +VK_DOWN=40 +VK_SELECT=41 +VK_PRINT=42 +VK_EXECUTE=43 +VK_SNAPSHOT=44 +VK_INSERT=45 +VK_DELETE=46 +VK_HELP=47 +VK_LWIN=0x5B +VK_RWIN=0x5C +VK_APPS=0x5D +VK_SLEEP=0x5F +VK_NUMPAD0=0x60 +VK_NUMPAD1=0x61 +VK_NUMPAD2=0x62 +VK_NUMPAD3=0x63 +VK_NUMPAD4=0x64 +VK_NUMPAD5=0x65 +VK_NUMPAD6=0x66 +VK_NUMPAD7=0x67 +VK_NUMPAD8=0x68 +VK_NUMPAD9=0x69 +VK_MULTIPLY=0x6A +VK_ADD=0x6B +VK_SEPARATOR=0x6C +VK_SUBTRACT=0x6D +VK_DECIMAL=0x6E +VK_DIVIDE=0x6F +VK_F1=0x70 +VK_F2=0x71 +VK_F3=0x72 +VK_F4=0x73 +VK_F5=0x74 +VK_F6=0x75 +VK_F7=0x76 +VK_F8=0x77 +VK_F9=0x78 +VK_F10=0x79 +VK_F11=0x7A +VK_F12=0x7B +VK_F13=0x7C +VK_F14=0x7D +VK_F15=0x7E +VK_F16=0x7F +VK_F17=0x80 +VK_F18=0x81 +VK_F19=0x82 +VK_F20=0x83 +VK_F21=0x84 +VK_F22=0x85 +VK_F23=0x86 +VK_F24=0x87 +VK_NUMLOCK=0x90 +VK_SCROLL=0x91 +VK_LSHIFT=0xA0 +VK_RSHIFT=0xA1 +VK_LCONTROL=0xA2 +VK_RCONTROL=0xA3 +VK_LMENU=0xA4 +VK_RMENU=0xA5 +VK_BROWSER_BACK=0xA6 +VK_BROWSER_FORWARD=0xA7 +VK_BROWSER_REFRESH=0xA8 +VK_BROWSER_STOP=0xA9 +VK_BROWSER_SEARCH=0xAA +VK_BROWSER_FAVORITES=0xAB +VK_BROWSER_HOME=0xAC +VK_VOLUME_MUTE=0xAD +VK_VOLUME_DOWN=0xAE +VK_VOLUME_UP=0xAF +VK_MEDIA_NEXT_TRACK=0xB0 +VK_MEDIA_PREV_TRACK=0xB1 +VK_MEDIA_STOP=0xB2 +VK_MEDIA_PLAY_PAUSE=0xB3 +VK_LAUNCH_MAIL=0xB4 +VK_LAUNCH_MEDIA_SELECT=0xB5 +VK_LAUNCH_APP1=0xB6 +VK_LAUNCH_APP2=0xB7 +VK_OEM_1=0xBA +VK_OEM_PLUS=0xBB +VK_OEM_COMMA=0xBC +VK_OEM_MINUS=0xBD +VK_OEM_PERIOD=0xBE +VK_OEM_2=0xBF +VK_OEM_3=0xC0 +VK_OEM_4=0xDB +VK_OEM_5=0xDC +VK_OEM_6=0xDD +VK_OEM_7=0xDE +VK_OEM_8=0xDF +VK_OEM_102=0xE2 +VK_PROCESSKEY=0xE5 +VK_PACKET=0xE7 +VK_ATTN=0xF6 +VK_CRSEL=0xF7 +VK_EXSEL=0xF8 +VK_EREOF=0xF9 +VK_PLAY=0xFA +VK_ZOOM=0xFB +VK_NONAME=0xFC +VK_PA1=0xFD +VK_OEM_CLEAR=0xFE + +CF_TEXT=1 +CF_BITMAP=2 +CF_METAFILEPICT=3 +CF_SYLK=4 +CF_DIF=5 +CF_TIFF=6 +CF_OEMTEXT=7 +CF_DIB=8 +CF_PALETTE=9 +CF_PENDATA=10 +CF_RIFF=11 +CF_WAVE=12 +CF_UNICODETEXT=13 +CF_ENHMETAFILE=14 +CF_HDROP=15 +CF_LOCALE=16 +CF_MAX=17 +CF_OWNERDISPLAY=128 +CF_DSPTEXT=129 +CF_DSPBITMAP=130 +CF_DSPMETAFILEPICT=131 +CF_DSPENHMETAFILE=142 +CF_PRIVATEFIRST=512 +CF_PRIVATELAST=767 +CF_GDIOBJFIRST=768 +CF_GDIOBJLAST=1023 + + +GPTR=64 +GHND=66