Commits

Anonymous committed 6f7f6a0

Repeat last action; C-x z
Yank; M-y

Comments (0)

Files changed (17)

docs/dev/done.txt

 ===========
 
 
+- Yanking ``M-y`` : March 13, 2007
+
+
+- Repeating last command; ``C-x z`` : March 13, 2007
+
+
 - Adding 'rename when unsure' option : March 13, 2007
 
 

docs/dev/issues.txt

 * Returning a `Generator` for functions with unknown return type;
 * Changing `callinfo` to match not exactly the same but similar args
 * Using `sqlite3` to prevent holding information in memory? mocks?
+* Saving `AbstractXxx`
+
+
+Separating 'none' From 'unknown'
+--------------------------------
+
+
+
+Invalidating Information
+------------------------
+
+When do we need to recalculate the information?
+
+
+Using A Real Database
+---------------------
+
+We need to save information for future use.  We can use a strategy
+object for saving information.
 
 
 Better Concluded Data

docs/dev/stories.txt

 * Basic code formatting; correcting blank lines
 
 
-* Repeating last command; ``C-x z``
-
-
 * Analyzing function decorators
 
 
 * Lambdas as functions; consider their parameters
 
 
-* Having multiple clipboards; ``M-y``
-
-
 * Renaming textual matches
 
 

docs/dev/workingon.txt

-'Rename When Unsure' Option
-===========================
+Small Stories
+=============
 
-- Binding next/prev page keys in show pydoc
-- Adding `UnboundPyName`
-
-* Is throwing `IsBeingInferredException` a good thing?  Can't we
-  return `get_unknown()` instead?
+* Adding a test showing that `None`\s and unknowns are the same
 * Evaluate function parameter defaults in staticoi?
 
 
   ``Exception exceptions.SystemError: 'error return without exception set'
     in <generator object at 0xb7173aec> ignored``
 * Only saving diffs in `ChangeContents`
-* Undoing `RemoveResource`; It's not used by refactorings
 * Importing star and removing self imports; stack overflow
 * `PyClass.superclasses` should be concluded data
 * Handling `AssList` for inline variable and encapsulate field

docs/user/overview.txt

 copy region                 M-w            C-c
 swap mark and insert        C-x C-x
 paste                       C-y            C-v
+yank                        M-y
 undo editing                C-x u          C-z
 redo editing                C-x r          C-y
+repeat last action          C-x z
 --------------------------  -------------  -------------
 Execute Command             M-x
 Edit ~/.rope                C-x c

rope/base/builtins.py

 
 
 for name in dir(__builtin__):
-    if name not in builtins:
+    if name not in builtins and name not in ['None']:
         obj = getattr(__builtin__, name)
         if inspect.isclass(obj):
             builtins[name] = BuiltinName(BuiltinClass(obj, {}))

rope/base/change.py

 
     # TODO: Undoing remove operations
     def undo(self):
-        pass
+        raise NotImplementedError(
+            'Undoing `RemoveResource` is not implemented yet.')
 
     def __str__(self):
         return 'Remove <%s>' % (self.resource.path)

rope/refactor/functionutils.py

                 args.append(primary)
             current = self.word_finder._find_last_non_space_char(current - 1)
         if self.is_called_as_a_method():
-            args.append(self.word_finder.get_primary_at(
-                        self.call.rindex('.', 0, self.first_parens) - 1))
+            args.append(self.call[:self.call.rindex('.', 0, self.first_parens)].strip())
         args.reverse()
         keywords.reverse()
         return args, keywords

rope/refactor/move.py

         if dest.is_folder():
             raise exceptions.RefactoringError(
                 'Move destination for non-modules should not be folders.')
+        if self.source == dest:
+            raise exceptions.RefactoringError(
+                'Moving global elements to the same module.')
         changes = ChangeSet('Moving global <%s>' % self.old_name)
         self._change_destination_module(changes, dest)
         self._change_source_module(changes, dest)
         self.rebound_keys = {}
         self.actions = []
         self.prefs = prefs.Prefs()
+        self.last_action = None
 
     def _load_actions(self):
         """Load extension modules.
         def callback(event=None):
             try:
                 action.do(ActionContext(self))
+                if action.get_name() != 'repeat_last_action':
+                    self.last_action = action
             except RopeError, e:
                 self._report_error(e)
             if event:
     def perform_action(self, action):
         self._make_callback(action)()
 
+    def repeat_last_action(self):
+        if self.last_action is not None:
+            self.perform_action(self.last_action)
+
     def _report_error(self, e):
         toplevel = Toplevel()
         toplevel.title('RopeError Was Raised')

rope/ui/dot_rope.py

     core.rebind_action('copy', 'C-c')
     core.rebind_action('cut', 'C-x')
     core.rebind_action('paste', 'C-v')
+    core.rebind_action('yank', None)
     core.rebind_action('goto_line', 'C-l')
     core.rebind_action('goto_last_edit_location', 'C-q')
     core.rebind_action('swap_mark_and_insert', None)
     core.rebind_action('undo', 'C-z')
     core.rebind_action('redo', 'C-y')
+    core.rebind_action('repeat_last_action', 'C-x z')
     core.rebind_action('undo_project', 'C-Z')
     core.rebind_action('redo_project', 'C-Y')
     core.rebind_action('project_history', None)

rope/ui/editactions.py

     if context.get_active_editor():
         context.get_active_editor().get_editor().paste()
 
+
+class Yank(object):
+
+    _yank_count = 0
+
+    def __call__(self, context):
+        last_command = context.core.last_action
+        if last_command is None or last_command.get_name() not in ['paste', 'yank']:
+            return
+        if last_command.get_name() == 'paste':
+            self._yank_count = 1
+        if last_command.get_name() == 'yank':
+            self._yank_count += 1
+        if context.get_active_editor():
+            context.get_active_editor().get_editor().yank(self._yank_count)
+
+
 def undo_editing(context):
     if context.get_active_editor():
         context.get_active_editor().get_editor().undo()
     editor_manager = context.get_core().get_editor_manager()
     editor_manager.get_resource_editor(resource, mode='python')
 
+def repeat_last_action(context):
+    if context.get_active_editor():
+        context.core.repeat_last_action()
+
 
 class FindCommandHandle(uihelpers.FindItemHandle):
 
                             MenuAddress(['Edit', 'Cut'], 't'), ['all']))
 actions.append(SimpleAction('paste', paste, 'C-y',
                             MenuAddress(['Edit', 'Paste'], 'p'), ['all']))
+actions.append(SimpleAction('yank', Yank(), 'M-y',
+                            MenuAddress(['Edit', 'Yank'], 'y'), ['all']))
 actions.append(SimpleAction('goto_line', goto_line, 'C-x g',
                             MenuAddress(['Edit', 'Goto Line'], 'g'), ['all']))
 actions.append(SimpleAction('goto_last_edit_location', goto_last_edit_location, 'C-x C-q',
                             MenuAddress(['Edit', 'Undo Editing'], 'u', 1), ['all']))
 actions.append(SimpleAction('redo', redo_editing, 'C-x r',
                             MenuAddress(['Edit', 'Redo Editing'], 'r', 1), ['all']))
+actions.append(SimpleAction('repeat_last_action', repeat_last_action, 'C-x z',
+                            MenuAddress(['Edit', 'Repeat Last Action'], 'l', 1), ['all']))
 actions.append(
     SimpleAction('undo_project',
                  ConfirmEditorsAreSaved(undo_project), 'C-x p u',

rope/ui/editor.py

 import os
 
+import ScrolledText
 import tkFont
-import ScrolledText
-from Tkinter import END, TclError, SEL_FIRST, SEL, SEL_LAST, INSERT
+from Tkinter import END, TclError, SEL_FIRST, SEL, SEL_LAST, INSERT, Toplevel, Text
 
 import rope.ide.codeassist
 import rope.ui.editingtools
                 font = tkFont.Font(family='Typewriter', size=14)
             else:
                 font = tkFont.Font(family='Courier', size=13)
-        self.text = ScrolledText.ScrolledText(parent, bg='white', font=font,
-                                 undo=True, maxundo=100, highlightcolor='#99A')
+        self.text = ScrolledText.ScrolledText(
+            parent, bg='white', font=font, undo=True,
+            maxundo=100, highlightcolor='#99A')
         self.change_inspector = _TextChangeInspector(self, self._text_changed)
         self.searcher = rope.ui.searcher.Searcher(self)
         self._set_editingcontexts(editorcontext)
         self.modification_observers = []
         self.change_observers = []
         self.modified_flag = False
+        self.kill_ring = KillRingManager()
         self.text.bind('<<Modified>>', self._editor_modified)
         self.text.edit_modified(False)
 
 
     def copy_region(self):
         try:
+            self._add_yank()
             self._select_region()
             self.text.event_generate('<<Copy>>')
             self.text.tag_remove(SEL, '1.0', END)
 
     def cut_region(self):
         try:
+            self._add_yank()
             self._select_region()
             self.text.event_generate('<<Cut>>')
             self.text.see(INSERT)
         except TclError, e:
             pass
 
+    def _add_yank(self):
+        start, end = self._get_region_index()
+        selected = self.text.get(start, end)
+        self.kill_ring.killed(selected)
+
+    def yank(self, count):
+        result = self.kill_ring.yank(count)
+        if result is not None:
+            old = self.kill_ring.yank(count - 1)
+            self.text.delete('insert -%dc' % len(old), INSERT)
+            self.text.insert(INSERT, result)
+
     def paste(self):
         self.text.event_generate('<<Paste>>')
         self.text.see(INSERT)
 
     def insert_to_line(self, line_number, text):
         self.editor.text.insert('%d.0' % line_number, text)
+
+
+class KillRingManager(object):
+
+    def __init__(self, limit=20):
+        self.ring = []
+        self.limit = limit
+
+    def yank(self, count):
+        if self.ring:
+            return self.ring[count % len(self.ring)]
+
+    def killed(self, killed):
+        self.ring.insert(0, killed)
+        if len(self.ring) > self.limit:
+            del self.ring[-1]

rope/ui/refactor.py

 import rope.refactor.move
 import rope.refactor.rename
 import rope.ui.core
+from rope.base import exceptions
 from rope.refactor import ImportOrganizer
 from rope.ui.actionhelpers import ConfirmEditorsAreSaved
 from rope.ui.extension import SimpleAction
 
 class RefactoringDialog(object):
 
-    def __init__(self, project, title):
-        self.project = project
+    def __init__(self, context, title):
+        self.core = context.core
+        self.project = context.project
         self.title = title
 
     def show(self):
         frame.grid(row=0, columnspan=3)
 
     def _ok(self, event=None):
-        PreviewAndCommitChanges(self.project, self._get_changes()).commit()
+        try:
+            PreviewAndCommitChanges(self.project, self._get_changes()).commit()
+        except exceptions.RopeError, e:
+            self.core._report_error(e)
         self.toplevel.destroy()
 
     def _preview(self, event=None):
-        PreviewAndCommitChanges(self.project, self._get_changes()).preview()
+        try:
+            PreviewAndCommitChanges(self.project, self._get_changes()).preview()
+        except exceptions.RopeError, e:
+            self.core._report_error(e)
         self.toplevel.destroy()
 
     def _cancel(self, event=None):
     def __init__(self, context, title, is_local=False, current_module=False):
         resource = context.resource
         editor = context.get_active_editor().get_editor()
-        super(RenameDialog, self).__init__(context.project, title)
+        super(RenameDialog, self).__init__(context, title)
         self.is_local = is_local
         offset = editor.get_current_offset()
         if current_module:
 
     def __init__(self, context, do_extract, kind):
         editor = context.get_active_editor().get_editor()
-        super(ExtractDialog, self).__init__(context.project,
-                                            'Extract ' + kind)
+        super(ExtractDialog, self).__init__(context, 'Extract ' + kind)
         self.do_extract = do_extract
         self.kind = kind
 
         resource = context.get_active_editor().get_file()
         editor = context.get_active_editor().get_editor()
         super(IntroduceFactoryDialog, self).__init__(
-            context.project, 'Introduce Factory Method Refactoring')
+            context, 'Introduce Factory Method Refactoring')
         self.introducer = rope.refactor.introduce_factory.IntroduceFactoryRefactoring(
             context.project, resource, editor.get_current_offset())
 
         resource = context.get_active_editor().get_file()
         editor = context.get_active_editor().get_editor()
         self.project = context.get_core().get_open_project()
-        super(MoveDialog, self).__init__(context.project,
-                                         'Move Refactoring')
+        super(MoveDialog, self).__init__(context, 'Move Refactoring')
         offset = editor.get_current_offset()
         if current_module:
             offset = None
             tree_view = TreeView(toplevel, tree_handle, title='Destination Module')
             for folder in self.project.get_pycore().get_source_folders():
                 tree_view.add_entry(folder)
-            tree_view.list.focus_set()
             toplevel.grab_set()
 
         self._bind_keys(self.destination_entry)
         editor = context.get_active_editor().get_editor()
         self.project = context.get_core().get_open_project()
         super(ChangeMethodSignatureDialog, self).__init__(
-            context.project, 'Change Method Signature Refactoring')
+            context, 'Change Method Signature Refactoring')
         self.signature = rope.refactor.change_signature.ChangeSignature(
             context.project, resource, editor.get_current_offset())
         self.definition_info = self.signature.get_definition_info()
         editor = context.get_active_editor().get_editor()
         self.project = context.get_core().get_open_project()
         super(InlineArgumentDefaultDialog, self).__init__(
-            context.project, 'Inline Argument Default')
+            context, 'Inline Argument Default')
         self.signature = rope.refactor.change_signature.ChangeSignature(
             context.project, resource, editor.get_current_offset())
         self.definition_info = self.signature.get_definition_info()
 
     def __init__(self, context, title):
         editor = context.get_active_editor().get_editor()
-        super(IntroduceParameterDialog, self).__init__(context.project, title)
+        super(IntroduceParameterDialog, self).__init__(context, title)
         self.renamer = rope.refactor.introduce_parameter.IntroduceParameter(
             context.project, context.resource, editor.get_current_offset())
 
 
     def __init__(self, context):
         editor = context.get_active_editor().get_editor()
-        super(MethodObjectDialog, self).__init__(
-            context.project, 'Replace Method With Method Object Refactoring')
+        super(MethodObjectDialog, self).__init__(context, 'Replace Method With Method Object Refactoring')
         self.renamer = rope.refactor.method_object.MethodObject(
             context.project, context.resource, editor.get_current_offset())
 
     def __init__(self, context):
         resource = context.resource
         editor = context.get_active_editor().get_editor()
-        super(ChangeOccurrencesDialog, self).__init__(context.project,
+        super(ChangeOccurrencesDialog, self).__init__(context,
                                                       'Change Occurrences')
         offset = editor.get_current_offset()
         self.renamer = rope.refactor.rename.ChangeOccurrences(

ropetest/refactor/change_signature_test.py

             'c = C()\n',
             self.mod.read())
 
+    def test_changing_signature_for_constructors_when_using_super(self):
+        self.mod.write(
+            'class A(object):\n    def __init__(self, p):\n        pass\n'
+            'class B(A):\n    '
+            'def __init__(self, p):\n        super(B, self).__init__(p)\n')
+        signature = ChangeSignature(self.project, self.mod,
+                                    self.mod.read().index('__init__') + 1)
+        signature.apply_changers([change_signature.ArgumentRemover(1)]).do()
+        self.assertEquals(
+            'class A(object):\n    def __init__(self):\n        pass\n'
+            'class B(A):\n    '
+            'def __init__(self, p):\n        super(B, self).__init__()\n',
+            self.mod.read())
+
 
 if __name__ == '__main__':
     unittest.main()

ropetest/refactor/movetest.py

         self._move(self.mod1, self.mod1.read().index('AClass') + 1,
                    self.mod2)
 
+    @testutils.assert_raises(exceptions.RefactoringError)
+    def test_raising_exception_for_moving_global_elements_to_the_same_module(self):
+        self.mod1.write('def a_func():\n    pass\n')
+        self._move(self.mod1, self.mod1.read().index('a_func'), self.mod1)
+
     def test_moving_used_imports_to_destination_module(self):
         self.mod3.write('a_var = 10')
         self.mod1.write('import mod3\nfrom mod3 import a_var\n' \
             '    def new_method(self):\n        return 1\n',
             self.mod2.read())
 
-    def test_moving_methods_getting_getting_changes_for_goal_class(self):
+    def test_moving_methods_getting_getting_changes_for_goal_class2(self):
         code = 'class B(object):\n    var = 1\n\n' \
                'class A(object):\n    attr = B()\n' \
                '    def a_method(self):\n        return 1\n'
             '    def new_method(self):\n        return sys.version\n',
             self.mod2.read())
 
-    def test_moving_methods_getting_getting_changes_for_goal_class(self):
+    def test_moving_methods_getting_getting_changes_for_goal_class3(self):
         self.mod2.write('class B(object):\n    pass\n')
         code = 'import mod2\n\nclass A(object):\n    attr = mod2.B()\n' \
                '    def a_method(self):\n        return 1\n'

ropetest/ui/editortest.py

 from ropetest.ui.mockeditortest import (GraphicalEditorFactory,
                                         get_sample_editingcontext)
 from rope.ui.indenter import PythonCodeIndenter
+from rope.ui import editor
 
 
 class GraphicalEditorTest(unittest.TestCase):
-    '''This class only tests features that are specific to GraphicalEditor; see mockeditortest'''
+    """This class only tests features that are specific to GraphicalEditor;
+    see mockeditortest
+    """
 
     __factory = GraphicalEditorFactory(Tkinter.Frame())
 
         self.editor.goto_line(2)
         self.assertEquals(2, self.editor.get_current_line_number())
 
+    def test_yanking(self):
+        self.editor.next_word()
+        self.editor.set_mark()
+        self.editor.goto_end()
+        self.editor.copy_region()
+        self.editor.goto_start()
+        self.editor.paste()
+        self.assertEquals(' textsample text', self.editor.get_text())
+
+
 class TextChangeInspectorTest(unittest.TestCase):
 
     __factory = GraphicalEditorFactory(Tkinter.Frame())
         self.assertEquals(('1.1', '1.4'), self.change_inspector.get_changed_region())
 
 
+class KillRingManagerTest(unittest.TestCase):
+
+    def setUp(self):
+        super(KillRingManagerTest, self).setUp()
+        self.ring = editor.KillRingManager()
+
+    def tearDown(self):
+        super(KillRingManagerTest, self).tearDown()
+
+    def test_empty_ring(self):
+        self.assertTrue(self.ring.yank(1) is None)
+
+    def test_trivial_yanking(self):
+        self.ring.killed('x')
+        self.ring.killed('y')
+        self.assertEquals('x', self.ring.yank(1))
+
+    def test_yanking_direction(self):
+        self.ring.killed('x')
+        self.ring.killed('y')
+        self.ring.killed('z')
+        self.assertEquals('y', self.ring.yank(1))
+        self.assertEquals('x', self.ring.yank(2))
+        self.assertEquals('z', self.ring.yank(3))
+
+    def test_yanking_the_last_element(self):
+        self.ring.killed('x')
+        self.ring.killed('y')
+        self.assertEquals('y', self.ring.yank(2))
+
+    def test_only_one_entry(self):
+        self.ring.killed('x')
+        self.assertEquals('x', self.ring.yank(1))
+
+    def test_unclear_conditions2(self):
+        ring = editor.KillRingManager(limit=2)
+        ring.killed('1')
+        ring.killed('2')
+        ring.killed('3')
+        self.assertEquals('3', ring.yank(2))
+
+
 def suite():
     result = unittest.TestSuite()
     result.addTests(unittest.makeSuite(GraphicalEditorTest))
     result.addTests(unittest.makeSuite(TextChangeInspectorTest))
+    result.addTests(unittest.makeSuite(KillRingManagerTest))
     return result
 
 
 if __name__ == '__main__':
     unittest.main()
-