ropemacs-0.6c2/0000755000175000017500000000000011026635424011514 5ustar alialiropemacs-0.6c2/PKG-INFO0000644000175000017500000000311211026635424012606 0ustar alialiMetadata-Version: 1.0 Name: ropemacs Version: 0.6c2 Summary: An emacs mode for using rope python refactoring library Home-page: http://rope.sf.net/ropemacs.html Author: Ali Gholami Rudi Author-email: aligrudi@users.sourceforge.net License: GNU GPL Description: ========================= ropemacs, rope in emacs ========================= Ropemacs is an emacs mode that uses rope_ library to provide features like python refactorings and code-assists. You should install rope_ library and pymacs_ before using ropemacs. .. _rope: http://rope.sf.net/ .. _pymacs: http://pymacs.progiciels-bpi.ca/pymacs.html New Features ============ * added ``ropemacs-guess-project`` variable * added ``rope-run-module`` command * showing line-number in occurrences buffer * fixed go to occurrence in xemacs * fixed error messages that contain percent sign * fixed ask directory and entering default directory Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Operating System :: OS Independent Classifier: Environment :: X11 Applications Classifier: Environment :: Win32 (MS Windows) Classifier: Environment :: MacOS X Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Natural Language :: English Classifier: Programming Language :: Python Classifier: Topic :: Text Editors :: Emacs Classifier: Topic :: Software Development ropemacs-0.6c2/setup.py0000644000175000017500000000204611026633070013223 0ustar alialifrom distutils.core import setup classifiers=[ 'Development Status :: 4 - Beta', 'Operating System :: OS Independent', 'Environment :: X11 Applications', 'Environment :: Win32 (MS Windows)', 'Environment :: MacOS X', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Natural Language :: English', 'Programming Language :: Python', 'Topic :: Text Editors :: Emacs', 'Topic :: Software Development'] def get_long_description(): lines = open('README.txt').read().splitlines(False) end = lines.index('Setting Up') return '\n' + '\n'.join(lines[:end]) + '\n' setup(name='ropemacs', version='0.6c2', description='An emacs mode for using rope python refactoring library', long_description=get_long_description(), packages=['ropemode', 'ropemacs'], author='Ali Gholami Rudi', author_email='aligrudi@users.sourceforge.net', url='http://rope.sf.net/ropemacs.html', license='GNU GPL', classifiers=classifiers) ropemacs-0.6c2/README.txt0000644000175000017500000003047211026635412013215 0ustar aliali========================= ropemacs, rope in emacs ========================= Ropemacs is an emacs mode that uses rope_ library to provide features like python refactorings and code-assists. You should install rope_ library and pymacs_ before using ropemacs. .. _rope: http://rope.sf.net/ .. _pymacs: http://pymacs.progiciels-bpi.ca/pymacs.html New Features ============ * added ``ropemacs-guess-project`` variable * added ``rope-run-module`` command * showing line-number in occurrences buffer * fixed go to occurrence in xemacs * fixed error messages that contain percent sign * fixed ask directory and entering default directory Setting Up ========== After installing pymacs, add these lines to your ``~/.emacs`` file:: (require 'pymacs) (pymacs-load "ropemacs" "rope-") Note that rope and ropemacs should be in your ``PYTHONPATH`` for this to work. Loading Lazily -------------- If you want to load ropemacs only when you really need it, you can use a function like this in your ``~/.emacs``:: (defun load-ropemacs () "Load pymacs and ropemacs" (interactive) (require 'pymacs) (pymacs-load "ropemacs" "rope-") ;; Automatically save project python buffers before refactorings (setq ropemacs-confirm-saving 'nil) ) (global-set-key "\C-xpl" 'load-ropemacs) And execute ``load-ropemacs`` (or use ``C-x p l``) whenever you want to use ropemacs. Not Installing -------------- If you don't want to install rope library and ropemacs you can extract them somewhere and add these lines to your ``.emacs``:: ;; Add this before loading pymacs if you haven't installed rope and ropemacs (setq pymacs-load-path '("/path/to/rope" "/path/to/ropemacs")) Multiple Python Versions ------------------------ Rope needs at least Python2.5. If you have older versions of Python you can use ``PYMACS_PYTHON`` environment variable. You can add:: (setenv "PYMACS_PYTHON" "python2.5") to force pymacs to use Python2.5. Ropemacs Minor Mode ------------------- Ropemacs registers its local keys when ``ropemacs-mode`` is enabled. By default it is enabled using ``python-mode`` hook (this hook is available if you are using Emacs' ``python.el`` or XEmacs' ``python-mode.el``). If you want to enable it in other major modes either execute ``ropemacs-mode`` manually or call it in some other hook. Getting Started =============== Refactoring Dialog ------------------ Ropemacs refactorings use a special kind of dialog. When you start a refactoring, you'll be asked to confirm saving modified python buffers; you can change it by using ``ropemacs-confirm-saving`` variable. Adding ``(setq ropemacs-confirm-saving 'nil)`` to your ``.emacs`` file, will make emacs save them without asking. After that depending on the refactoring, you'll be asked about the essential information a refactoring needs to know (like the new name in rename refactoring). You can skip it by prefixing the refactoring; this can be useful when using batchset command (described later). Next you'll see the base prompt of a refactoring dialog that shows something like "Choose what to do". By entering the name of a refactoring option you can set its value. After setting each option you'll be returned back to the base prompt. Finally, you can ask rope to perform, preview or cancel the refactoring. See keybinding_ section and try the refactorings yourself. Finding Files ------------- By using ``rope-find-file`` (``C-x p f`` by default), you can search for files in your project. When you complete the minibuffer you'll see all files in the project; files are shown as their reversed paths. For instance ``projectroot/docs/todo.txt`` is shown like ``todo.txt Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ropemacs-0.6c2/CONTRIBUTORS0000644000175000017500000000022311026633070013364 0ustar aliali======================= Ropemacs Contributors ======================= * Sebastjan Trepca * Stefan Reichoer ropemacs-0.6c2/ropemode/0000755000175000017500000000000011026635424013326 5ustar alialiropemacs-0.6c2/ropemode/refactor.py0000644000175000017500000003656411026633100015510 0ustar alialiimport re import rope.base.change import rope.contrib.generate import rope.refactor.change_signature import rope.refactor.extract import rope.refactor.inline import rope.refactor.introduce_factory import rope.refactor.method_object import rope.refactor.move import rope.refactor.rename import rope.refactor.restructure import rope.refactor.usefunction from rope.base import taskhandle from ropemode import dialog, filter class Refactoring(object): key = None confs = {} optionals = {} saveall = True def __init__(self, interface, env): self.interface = interface self.env = env def show(self, initial_asking=True): self.interface._check_project() self.interface._save_buffers(only_current=not self.saveall) self._create_refactoring() action, result = dialog.show_dialog( self.interface._askdata, ['perform', 'preview', 'cancel'], self._get_confs(), self._get_optionals(), initial_asking=initial_asking) if action == 'cancel': self.env.message('Cancelled!') return def calculate(handle): return self._calculate_changes(result, handle) name = 'Calculating %s changes' % self.name changes = runtask(self.env, calculate, name=name) if action == 'perform': self._perform(changes) if action == 'preview': if changes is not None: diffs = str(changes.get_description()) if self.env.preview_changes(diffs): self._perform(changes) else: self.env.message('Thrown away!') else: self.env.message('No changes!') @property def project(self): return self.interface.project @property def resource(self): return self.interface._get_resource() @property def offset(self): return self.env.get_offset() @property def region(self): return self.env.get_region() @property def name(self): return refactoring_name(self.__class__) def _calculate_changes(self, option_values, task_handle): pass def _create_refactoring(self): pass def _done(self): pass def _perform(self, changes): if changes is None: self.env.message('No changes!') return def perform(handle, self=self, changes=changes): self.project.do(changes, task_handle=handle) self.interface._reload_buffers(changes) self._done() runtask(self.env, perform, 'Making %s changes' % self.name, interrupts=False) self.env.message(str(changes.description) + ' finished') def _get_confs(self): return self.confs def _get_optionals(self): return self.optionals @property def resources_option(self): return dialog.Data('Files to apply this refactoring on: ', decode=self._decode_resources) def _decode_resources(self, value): return _resources(self.project, value) class Rename(Refactoring): key = 'r' saveall = True def _create_refactoring(self): self.renamer = rope.refactor.rename.Rename( self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): return self.renamer.get_changes(task_handle=task_handle, **values) def _get_optionals(self): opts = {} opts['docs'] = dialog.Boolean('Search comments and docs: ', True) if self.renamer.is_method(): opts['in_hierarchy'] = dialog.Boolean('Rename methods in ' 'class hierarchy: ') opts['resources'] = self.resources_option opts['unsure'] = dialog.Data('Unsure occurrences: ', decode=self._decode_unsure, values=['ignore', 'match'], default='ignore') return opts def _get_confs(self): oldname = str(self.renamer.get_old_name()) return {'new_name': dialog.Data('New name: ', default=oldname)} def _decode_unsure(self, value): unsure = value == 'match' return lambda occurrence: unsure class RenameCurrentModule(Rename): key = '1 r' offset = None class Restructure(Refactoring): key = 'x' confs = {'pattern': dialog.Data('Restructuring pattern: '), 'goal': dialog.Data('Restructuring goal: ')} def _calculate_changes(self, values, task_handle): restructuring = rope.refactor.restructure.Restructure( self.project, values['pattern'], values['goal'], args=values['args'], imports=values['imports']) return restructuring.get_changes(resources=values['resources'], task_handle=task_handle) def _get_optionals(self): return { 'args': dialog.Data('Arguments: ', decode=self._decode_args), 'imports': dialog.Data('Imports: ', decode=self._decode_imports), 'resources': self.resources_option} def _decode_args(self, value): if value: args = {} for raw_check in value.split('\n'): if raw_check: key, value = raw_check.split(':', 1) args[key.strip()] = value.strip() return args def _decode_imports(self, value): if value: return [line.strip() for line in value.split('\n')] class UseFunction(Refactoring): key = 'u' def _create_refactoring(self): self.user = rope.refactor.usefunction.UseFunction( self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): return self.user.get_changes(task_handle=task_handle, **values) def _get_optionals(self): return {'resources': self.resources_option} class Move(Refactoring): key = 'v' def _create_refactoring(self): self.mover = rope.refactor.move.create_move(self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): destination = values['destination'] resources = values.get('resources', None) if isinstance(self.mover, rope.refactor.move.MoveGlobal): return self._move_global(destination, resources, task_handle) if isinstance(self.mover, rope.refactor.move.MoveModule): return self._move_module(destination, resources, task_handle) if isinstance(self.mover, rope.refactor.move.MoveMethod): return self._move_method(destination, resources, task_handle) def _move_global(self, dest, resources, handle): destination = self.project.pycore.find_module(dest) return self.mover.get_changes( destination, resources=resources, task_handle=handle) def _move_method(self, dest, resources, handle): return self.mover.get_changes( dest, self.mover.get_method_name(), resources=resources, task_handle=handle) def _move_module(self, dest, resources, handle): destination = self.project.pycore.find_module(dest) return self.mover.get_changes( destination, resources=resources, task_handle=handle) def _get_confs(self): if isinstance(self.mover, rope.refactor.move.MoveGlobal): prompt = 'Destination module: ' if isinstance(self.mover, rope.refactor.move.MoveModule): prompt = 'Destination package: ' if isinstance(self.mover, rope.refactor.move.MoveMethod): prompt = 'Destination attribute: ' return {'destination': dialog.Data(prompt)} def _get_optionals(self): return {'resources': self.resources_option} class MoveCurrentModule(Move): key = '1 v' offset = None class ModuleToPackage(Refactoring): key = '1 p' saveall = False def _create_refactoring(self): self.packager = rope.refactor.ModuleToPackage( self.project, self.resource) def _calculate_changes(self, values, task_handle): return self.packager.get_changes() class Inline(Refactoring): key = 'i' def _create_refactoring(self): self.inliner = rope.refactor.inline.create_inline( self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): return self.inliner.get_changes(task_handle=task_handle, **values) def _get_optionals(self): opts = {'resources': self.resources_option} if self.inliner.get_kind() == 'parameter': opts['in_hierarchy'] = dialog.Boolean( 'Apply on all matching methods in class hierarchy: ', False) else: opts['remove'] = dialog.Boolean('Remove the definition: ', True) opts['only_current'] = dialog.Boolean('Inline this ' 'occurrence only: ') return opts class _Extract(Refactoring): saveall = False optionals = {'similar': dialog.Boolean('Extract similar pieces: ', True), 'global_': dialog.Boolean('Make global: ')} kind = None constructor = None def _create_refactoring(self): start, end = self.region self.extractor = self.constructor(self.project, self.resource, start, end) def _calculate_changes(self, values, task_handle): similar = values.get('similar') global_ = values.get('global_') return self.extractor.get_changes(values['name'], similar=similar, global_=global_) def _get_confs(self): return {'name': dialog.Data('Extracted %s name: ' % self.kind)} class ExtractVariable(_Extract): key = 'l' kind = 'variable' constructor = rope.refactor.extract.ExtractVariable class ExtractMethod(_Extract): key = 'm' kind = 'method' constructor = rope.refactor.extract.ExtractMethod class OrganizeImports(Refactoring): key = 'o' saveall = False def _create_refactoring(self): self.organizer = rope.refactor.ImportOrganizer(self.project) def _calculate_changes(self, values, task_handle): return self.organizer.organize_imports(self.resource) class MethodObject(Refactoring): saveall = False confs = {'classname': dialog.Data('New class name: ', default='_ExtractedClass')} def _create_refactoring(self): self.objecter = rope.refactor.method_object.MethodObject( self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): classname = values.get('classname') return self.objecter.get_changes(classname) class IntroduceFactory(Refactoring): saveall = True key = 'f' def _create_refactoring(self): self.factory = rope.refactor.introduce_factory.IntroduceFactory( self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): return self.factory.get_changes(task_handle=task_handle, **values) def _get_confs(self): default = 'create_%s' % self.factory.old_name.lower() return {'factory_name': dialog.Data('Factory name: ', default)} def _get_optionals(self): return {'global_factory': dialog.Boolean('Make global: ', True), 'resources': self.resources_option} class ChangeSignature(Refactoring): saveall = True key = 's' def _create_refactoring(self): self.changer = rope.refactor.change_signature.ChangeSignature( self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): signature = values.get('signature') args = re.sub(r'[\s\(\)]+', '', signature).split(',') olds = [arg[0] for arg in self._get_args()] changers = [] for arg in list(olds): if arg in args: continue changers.append(rope.refactor.change_signature. ArgumentRemover(olds.index(arg))) olds.remove(arg) order = [] for index, arg in enumerate(args): if arg not in olds: changers.append(rope.refactor.change_signature. ArgumentAdder(index, arg)) olds.insert(index, arg) order.append(olds.index(arg)) changers.append(rope.refactor.change_signature. ArgumentReorderer(order, autodef='None')) del values['signature'] return self.changer.get_changes(changers, task_handle=task_handle, **values) def _get_args(self): if hasattr(self.changer, 'get_args'): return self.changer.get_args() return self.changer.get_definition_info().args_with_defaults def _get_confs(self): args = [] for arg, default in self._get_args(): args.append(arg) signature = '(' + ', '.join(args) + ')' return {'signature': dialog.Data('Change the signature: ', default=signature)} def _get_optionals(self): opts = {'resources': self.resources_option} if self.changer.is_method(): opts['in_hierarchy'] = dialog.Boolean('Rename methods in ' 'class hierarchy: ') return opts class _GenerateElement(Refactoring): def _create_refactoring(self): kind = self.name.split('_')[-1] self.generator = rope.contrib.generate.create_generate( kind, self.project, self.resource, self.offset) def _calculate_changes(self, values, task_handle): return self.generator.get_changes() def _done(self): resource, lineno = self.generator.get_location() self.interface._goto_location(resource, lineno) class GenerateVariable(_GenerateElement): key = 'n v' class GenerateFunction(_GenerateElement): key = 'n f' class GenerateClass(_GenerateElement): key = 'n c' class GenerateModule(_GenerateElement): key = 'n m' class GeneratePackage(_GenerateElement): key = 'n p' def refactoring_name(refactoring): classname = refactoring.__name__ result = [] for c in classname: if result and c.isupper(): result.append('_') result.append(c.lower()) name = ''.join(result) return name def _resources(project, text): if text is None or text.strip() == '': return None return filter.resources(project, text) def runtask(env, command, name, interrupts=True): return RunTask(env, command, name, interrupts)() class RunTask(object): def __init__(self, env, task, name, interrupts=True): self.env = env self.task = task self.name = name self.interrupts = interrupts def __call__(self): handle = taskhandle.TaskHandle(name=self.name) progress = self.env.create_progress(self.name) def update_progress(): jobset = handle.current_jobset() if jobset: percent = jobset.get_percent_done() if percent is not None: progress.update(percent) handle.add_observer(update_progress) result = self.task(handle) progress.done() return result ropemacs-0.6c2/ropemode/interface.py0000644000175000017500000005517011026633101015636 0ustar alialiimport os import rope.base.change from rope.base import libutils from rope.contrib import codeassist, generate, autoimport, findit from ropemode import refactor, decorators, dialog class RopeMode(object): def __init__(self, env): self.project = None self.old_content = None self.env = env self._prepare_refactorings() self.autoimport = None self._init_mode() def init(self): """Initialize rope mode""" def _init_mode(self): for attrname in dir(self): attr = getattr(self, attrname) if not callable(attr): continue kind = getattr(attr, 'kind', None) if kind == 'local': key = getattr(attr, 'local_key', None) prefix = getattr(attr, 'prefix', None) self.env.local_command(attrname, attr, key, prefix) if kind == 'global': key = getattr(attr, 'global_key', None) prefix = getattr(attr, 'prefix', None) self.env.global_command(attrname, attr, key, prefix) if kind == 'hook': hook = getattr(attr, 'hook', None) self.env.add_hook(attrname, attr, hook) def _prepare_refactorings(self): for name in dir(refactor): if not name.startswith('_') and name != 'Refactoring': attr = getattr(refactor, name) if isinstance(attr, type) and \ issubclass(attr, refactor.Refactoring): refname = self._refactoring_name(attr) @decorators.local_command(attr.key, 'P', None, refname) def do_refactor(prefix, self=self, refactoring=attr): initial_asking = prefix is None refactoring(self, self.env).show(initial_asking=initial_asking) setattr(self, refname, do_refactor) def _refactoring_name(self, refactoring): return refactor.refactoring_name(refactoring) @decorators.rope_hook('before_save') def before_save_actions(self): if self.project is not None: if not self._is_python_file(self.env.filename()): return resource = self._get_resource() if resource.exists(): self.old_content = resource.read() else: self.old_content = '' @decorators.rope_hook('after_save') def after_save_actions(self): if self.project is not None and self.old_content is not None: libutils.report_change(self.project, self.env.filename(), self.old_content) self.old_content = None @decorators.rope_hook('exit') def exiting_actions(self): if self.project is not None: self.close_project() @decorators.global_command('o') def open_project(self, root=None): if not root: root = self.env.ask_directory('Rope project root folder: ') if self.project is not None: self.close_project() progress = self.env.create_progress('Opening [%s] project' % root) self.project = rope.base.project.Project(root) if self.env.get('enable_autoimport'): underlined = self.env.get('autoimport_underlineds') self.autoimport = autoimport.AutoImport(self.project, underlined=underlined) progress.done() @decorators.global_command('k') def close_project(self): if self.project is not None: progress = self.env.create_progress('Closing [%s] project' % self.project.address) self.project.close() self.project = None progress.done() @decorators.global_command() def write_project(self): if self.project is not None: progress = self.env.create_progress( 'Writing [%s] project data to disk' % self.project.address) self.project.sync() progress.done() @decorators.global_command('u') def undo(self): self._check_project() change = self.project.history.tobe_undone if change is None: self.env.message('Nothing to undo!') return if self.env.y_or_n('Undo [%s]? ' % str(change)): def undo(handle): for changes in self.project.history.undo(task_handle=handle): self._reload_buffers(changes, undo=True) refactor.runtask(self.env, undo, 'Undo refactoring', interrupts=False) @decorators.global_command('r') def redo(self): self._check_project() change = self.project.history.tobe_redone if change is None: self.env.message('Nothing to redo!') return if self.env.y_or_n('Redo [%s]? ' % str(change)): def redo(handle): for changes in self.project.history.redo(task_handle=handle): self._reload_buffers(changes) refactor.runtask(self.env, redo, 'Redo refactoring', interrupts=False) @decorators.local_command('a g', shortcut='C-c g') def goto_definition(self): self._check_project() resource, offset = self._get_location() maxfixes = self.env.get('codeassist_maxfixes') definition = codeassist.get_definition_location( self.project, self._get_text(), offset, resource, maxfixes) if tuple(definition) != (None, None): self.env.push_mark() self._goto_location(definition[0], definition[1]) else: self.env.message('Cannot find the definition!') @decorators.local_command('a d', 'P', 'C-c d') def show_doc(self, prefix): self._check_project() self._base_show_doc(prefix, codeassist.get_doc) @decorators.local_command('a c', 'P') def show_calltip(self, prefix): self._check_project() def _get_doc(project, text, offset, *args, **kwds): try: offset = text.rindex('(', 0, offset) - 1 except ValueError: return None return codeassist.get_calltip(project, text, offset, *args, **kwds) self._base_show_doc(prefix, _get_doc) def _base_show_doc(self, prefix, get_doc): maxfixes = self.env.get('codeassist_maxfixes') text = self._get_text() offset = self.env.get_offset() docs = get_doc(self.project, text, offset, self._get_resource(), maxfixes) self.env.show_doc(docs, prefix) if docs is None: self.env.message('No docs avilable!') def _get_text(self): if not self.env.is_modified(): return self._get_resource().read() return self.env.get_text() def _base_findit(self, do_find, optionals, get_kwds): self._check_project() self._save_buffers() resource, offset = self._get_location() action, values = dialog.show_dialog( self._askdata, ['search', 'cancel'], optionals=optionals) if action == 'search': kwds = get_kwds(values) def calculate(handle): resources = refactor._resources(self.project, values.get('resources')) return do_find(self.project, resource, offset, resources=resources, task_handle=handle, **kwds) result = refactor.runtask(self.env, calculate, 'Find Occurrences') locations = [Location(location) for location in result] self.env.show_occurrences(locations) @decorators.local_command('a f', shortcut='C-c f') def find_occurrences(self): optionals = { 'unsure': dialog.Data('Find uncertain occurrences: ', default='no', values=['yes', 'no']), 'resources': dialog.Data('Files to search: '), 'in_hierarchy': dialog.Data( 'Rename methods in class hierarchy: ', default='no', values=['yes', 'no'])} def get_kwds(values): return {'unsure': values.get('unsure') == 'yes', 'in_hierarchy': values.get('in_hierarchy') == 'yes'} self._base_findit(findit.find_occurrences, optionals, get_kwds) @decorators.local_command('a i') def find_implementations(self): optionals = {'resources': dialog.Data('Files to search: ')} def get_kwds(values): return {} self._base_findit(findit.find_implementations, optionals, get_kwds) @decorators.local_command('a /', 'P', 'M-/') def code_assist(self, prefix): _CodeAssist(self, self.env).code_assist(prefix) @decorators.local_command('a ?', 'P', 'M-?') def lucky_assist(self, prefix): _CodeAssist(self, self.env).lucky_assist(prefix) @decorators.local_command() def auto_import(self): _CodeAssist(self, self.env).auto_import() def _check_autoimport(self): self._check_project() if self.autoimport is None: self.env.message('autoimport is disabled; ' 'see `enable_autoimport\' variable') return False return True @decorators.global_command() def generate_autoimport_cache(self): if not self._check_autoimport(): return modules = self.env.get('autoimport_modules') modnames = [] if modules: for i in range(len(modules)): modname = modules[i] if not isinstance(modname, basestring): modname = modname.value() modnames.append(modname) def generate(handle): self.autoimport.generate_cache(task_handle=handle) self.autoimport.generate_modules_cache(modules, task_handle=handle) refactor.runtask(self.env, generate, 'Generate autoimport cache') @decorators.global_command('f', 'P') def find_file(self, prefix): file = self._base_find_file(prefix) if file is not None: self.env.find_file(file.real_path) @decorators.global_command('4 f', 'P') def find_file_other_window(self, prefix): file = self._base_find_file(prefix) if file is not None: self.env.find_file(file.real_path, other=True) def _base_find_file(self, prefix): self._check_project() if prefix: files = self.project.pycore.get_python_files() else: files = self.project.get_files() return self._ask_file(files) def _ask_file(self, files): names = [] for file in files: names.append('<'.join(reversed(file.path.split('/')))) result = self.env.ask_values('Rope Find File: ', names) if result is not None: path = '/'.join(reversed(result.split('<'))) file = self.project.get_file(path) return file self.env.message('No file selected') @decorators.local_command('a j') def jump_to_global(self): if not self._check_autoimport(): return all_names = list(self.autoimport.get_all_names()) name = self.env.ask_values('Global name: ', all_names) result = dict(self.autoimport.get_name_locations(name)) if len(result) == 1: resource = list(result.keys())[0] else: resource = self._ask_file(result.keys()) if resource: self._goto_location(resource, result[resource]) @decorators.global_command('c') def project_config(self): self._check_project() if self.project.ropefolder is not None: config = self.project.ropefolder.get_child('config.py') self.env.find_file(config.real_path) else: self.env.message('No rope project folder found') @decorators.global_command('n m') def create_module(self): def callback(sourcefolder, name): return generate.create_module(self.project, name, sourcefolder) self._create('module', callback) @decorators.global_command('n p') def create_package(self): def callback(sourcefolder, name): folder = generate.create_package(self.project, name, sourcefolder) return folder.get_child('__init__.py') self._create('package', callback) @decorators.global_command('n f') def create_file(self): def callback(parent, name): return parent.create_file(name) self._create('file', callback, 'parent') @decorators.global_command('n d') def create_directory(self): def callback(parent, name): parent.create_folder(name) self._create('directory', callback, 'parent') @decorators.local_command() def analyze_module(self): """Perform static object analysis on this module""" self._check_project() resource = self._get_resource() self.project.pycore.analyze_module(resource) @decorators.global_command() def analyze_modules(self): """Perform static object analysis on all project modules""" self._check_project() def _analyze_modules(handle): libutils.analyze_modules(self.project, task_handle=handle) refactor.runtask(self.env, _analyze_modules, 'Analyze project modules') @decorators.local_command() def run_module(self): """Run and perform dynamic object analysis on this module""" self._check_project() resource = self._get_resource() process = self.project.pycore.run_module(resource) try: process.wait_process() finally: process.kill_process() def _create(self, name, callback, parentname='source'): self._check_project() confs = {'name': dialog.Data(name.title() + ' name: ')} parentname = parentname + 'folder' optionals = {parentname: dialog.Data( parentname.title() + ' Folder: ', default=self.project.address, kind='directory')} action, values = dialog.show_dialog( self._askdata, ['perform', 'cancel'], confs, optionals) if action == 'perform': parent = libutils.path_to_resource( self.project, values.get(parentname, self.project.address)) resource = callback(parent, values['name']) if resource: self.env.find_file(resource.real_path) def _goto_location(self, resource, lineno): if resource: self.env.find_file(str(resource.real_path), resource.project != self.project) if lineno: self.env.goto_line(lineno) def _get_location(self): resource = self._get_resource() offset = self.env.get_offset() return resource, offset def _get_resource(self, filename=None): if filename is None: filename = self.env.filename() if filename is None: return resource = libutils.path_to_resource(self.project, filename, 'file') return resource def _check_project(self): if self.project is None: if self.env.get('guess_project'): self.open_project(self._guess_project()) else: self.open_project() else: self.project.validate(self.project.root) def _guess_project(self): cwd = self.env.filename() if cwd is not None: while True: ropefolder = os.path.join(cwd, '.ropeproject') if os.path.exists(ropefolder) and os.path.isdir(ropefolder): return cwd newcwd = os.path.dirname(cwd) if newcwd == cwd: break cwd = newcwd def _reload_buffers(self, changes, undo=False): self._reload_buffers_for_changes( changes.get_changed_resources(), self._get_moved_resources(changes, undo)) def _reload_buffers_for_changes(self, changed, moved={}): filenames = [resource.real_path for resource in changed] moved = dict([(resource.real_path, moved[resource].real_path) for resource in moved]) self.env.reload_files(filenames, moved) def _get_moved_resources(self, changes, undo=False): result = {} if isinstance(changes, rope.base.change.ChangeSet): for change in changes.changes: result.update(self._get_moved_resources(change)) if isinstance(changes, rope.base.change.MoveResource): result[changes.resource] = changes.new_resource if undo: return dict([(value, key) for key, value in result.items()]) return result def _save_buffers(self, only_current=False): if only_current: filenames = [self.env.filename()] else: filenames = self.env.filenames() pythons = [] for filename in filenames: if self._is_python_file(filename): pythons.append(filename) self.env.save_files(pythons) def _is_python_file(self, path): resource = self._get_resource(path) return (resource is not None and resource.project == self.project and self.project.pycore.is_python_file(resource)) def _askdata(self, data, starting=None): ask_func = self.env.ask ask_args = {'prompt': data.prompt, 'starting': starting, 'default': data.default} if data.values: ask_func = self.env.ask_values ask_args['values'] = data.values elif data.kind == 'directory': ask_func = self.env.ask_directory return ask_func(**ask_args) class Location(object): def __init__(self, location): self.location = location self.filename = location.resource.real_path self.offset = location.offset self.note = '' if location.unsure: self.note = '?' @property def lineno(self): if hasattr(self.location, 'lineno'): return self.location.lineno return self.location.resource.read().count('\n', 0, self.offset) + 1 class _CodeAssist(object): def __init__(self, interface, env): self.interface = interface self.autoimport = interface.autoimport self.env = env self._source = None self._offset = None self._starting_offset = None self._starting = None self._expression = None def code_assist(self, prefix): names = self._calculate_proposals() if prefix is not None: arg = self.env.prefix_value(prefix) if arg == 0: arg = len(names) common_start = self._calculate_prefix(names[:arg]) self.env.insert(common_start[self.offset - self.starting_offset:]) self._starting = common_start self._offset = self.starting_offset + len(common_start) prompt = 'Completion for %s: ' % self.expression result = self.env.ask_completion(prompt, names, self.starting) if result is not None: self._apply_assist(result) def lucky_assist(self, prefix): names = self._calculate_proposals() selected = 0 if prefix is not None: selected = self.env.prefix_value(prefix) if 0 <= selected < len(names): result = names[selected] else: self.env.message('Not enough proposals!') return self._apply_assist(result) def auto_import(self): if not self.interface._check_autoimport(): return name = self.env.current_word() modules = self.autoimport.get_modules(name) if modules: if len(modules) == 1: module = modules[0] else: module = self.env.ask_values( 'Which module to import: ', modules) self._insert_import(name, module) else: self.env.message('Global name %s not found!' % name) def _apply_assist(self, assist): if ' : ' in assist: name, module = assist.rsplit(' : ', 1) self.env.delete(self.starting_offset + 1, self.offset + 1) self.env.insert(name) self._insert_import(name, module) else: self.env.delete(self.starting_offset + 1, self.offset + 1) self.env.insert(assist) def _calculate_proposals(self): self.interface._check_project() resource = self.interface._get_resource() maxfixes = self.env.get('codeassist_maxfixes') proposals = codeassist.code_assist( self.interface.project, self.source, self.offset, resource, maxfixes=maxfixes) proposals = codeassist.sorted_proposals(proposals) names = [proposal.name for proposal in proposals] if self.autoimport is not None: if self.starting.strip() and '.' not in self.expression: import_assists = self.autoimport.import_assist(self.starting) names.extend(x[0] + ' : ' + x[1] for x in import_assists) return names def _insert_import(self, name, module): lineno = self.autoimport.find_insertion_line(self.source) line = 'from %s import %s' % (module, name) self.env.insert_line(line, lineno) def _calculate_prefix(self, names): if not names: return '' prefix = names[0] for name in names: common = 0 for c1, c2 in zip(prefix, name): if c1 != c2 or ' ' in (c1, c2): break common += 1 prefix = prefix[:common] return prefix @property def offset(self): if self._offset is None: self._offset = self.env.get_offset() return self._offset @property def source(self): if self._source is None: self._source = self.interface._get_text() return self._source @property def starting_offset(self): if self._starting_offset is None: self._starting_offset = codeassist.starting_offset(self.source, self.offset) return self._starting_offset @property def starting(self): if self._starting is None: self._starting = self.source[self.starting_offset:self.offset] return self._starting @property def expression(self): if self._expression is None: self._expression = codeassist.starting_expression(self.source, self.offset) return self._expression ropemacs-0.6c2/ropemode/filter.py0000644000175000017500000000225511026633100015156 0ustar alialifrom rope.base import exceptions def resources(project, rules): """Find python files in the `project` matching `rules` `rules` is a multi-line `str`; each line starts with either a '+' or '-'. Each '+' means include the file (or its children if it's a folder) that comes after it. '-' has the same meaning for exclusion. """ all = set(project.pycore.get_python_files()) files = None for line in rules.splitlines(): if not line.strip(): continue first, path = (line[0], line[1:]) if first not in '+-': continue try: resource = project.get_resource(path.strip()) except exceptions.ResourceNotFoundError: continue if resource.is_folder(): matches = set(filter(lambda item: resource.contains(item), all)) else: matches = set([resource]) if first == '+': if files is None: files = set() files.update(matches) if first == '-': if files is None: files = set(all) files -= matches if files is None: return all return files ropemacs-0.6c2/ropemode/environment.py0000644000175000017500000000327411026633101016240 0ustar alialiclass Environment(object): def ask(self, prompt, default=None, starting=None): pass def ask_values(self, prompt, values, default=None, starting=None): pass def ask_directory(self, prompt, default=None, starting=None): pass def ask_completion(self, prompt, values, starting=None): pass def message(self, message): pass def yes_or_no(self, prompt): pass def y_or_n(self, prompt): pass def get(self, name, default=None): pass def get_offset(self): pass def get_text(self): pass def get_region(self): pass def filename(self): pass def is_modified(self): pass def goto_line(self, lineno): pass def insert_line(self, line, lineno): pass def insert(self, text): pass def delete(self, start, end): pass def filenames(self): pass def save_files(self, filenames): pass def reload_files(self, filenames, moves={}): pass def find_file(self, filename, readonly=False, other=False): pass def create_progress(self, name): pass def current_word(self): pass def push_mark(self): pass def prefix_value(self, prefix): pass def show_occurrences(self, locations): pass def show_doc(self, docs, altview=False): pass def preview_changes(self, diffs): pass def local_command(self, name, callback, key=None, prefix=False): pass def global_command(self, name, callback, key=None, prefix=False): pass def add_hook(self, name, callback, hook): pass ropemacs-0.6c2/ropemode/dialog.py0000644000175000017500000000564511026633100015136 0ustar alialiclass Data(object): def __init__(self, prompt=None, default=None, values=None, kind=None, decode=None): self.prompt = prompt self.default = default self.values = values self.kind = kind self._decode = decode def decode(self, value): if self._decode: return self._decode(value) return value class Boolean(Data): def __init__(self, prompt=None, default=False): Data.__init__(self, prompt, self._encode(default), [self._encode(True), self._encode(False)]) def _encode(self, value): if value: return 'yes' return 'no' def decode(self, value): if value.lower() in ('yes', '1', 'true'): return True return False def show_dialog(askdata, actions, confs={}, optionals={}, initial_asking=True): result = {} if initial_asking: for name, conf in confs.items(): result[name] = askdata(conf) actions.append('batchset') names = list(actions) names.extend(optionals.keys()) names.extend(confs.keys()) base_question = Data('Choose what to do: ', default=actions[0], values=names) batchset_question = Data('Batch sets: ') while True: response = askdata(base_question) if response == '': response = base_question.default elif response == 'batchset': sets = askdata(batchset_question) for key, value in _parse_batchset(sets).items(): if key.endswith(':'): key = key[:-1] if key in names: conf = confs.get(key, optionals.get(key)) result[key] = value elif response in actions: break else: if response in confs: conf = confs[response] else: conf = optionals[response] oldvalue = result.get(response, None) result[response] = askdata(conf, starting=oldvalue) decoded = {} all_confs = dict(confs) all_confs.update(optionals) for key in all_confs: conf = all_confs.get(key) if key in result: decoded[key] = conf.decode(result[key]) else: decoded[key] = conf.decode(conf.default) return response, decoded def _parse_batchset(sets): result = [] multiline = False for line in sets.splitlines(True): if line[0].isspace(): if multiline: result[-1][1] += line[1:] else: if not line.strip(): continue multiline= False tokens = line.split(None, 1) value = '' if len(tokens) > 1: result.append([tokens[0], tokens[1].rstrip('\r\n')]) else: multiline = True result.append([tokens[0], '']) return dict(result) ropemacs-0.6c2/ropemode/decorators.py0000644000175000017500000000465011026633101016040 0ustar alialiimport traceback from rope.base import exceptions class Logger(object): message = None only_short = False def __call__(self, message, short=None): if short is None or not self.only_short: self._show(message) if short is not None: self._show(short) def _show(self, message): if message is None: print message else: self.message(message) logger = Logger() def lisphook(func): def newfunc(*args, **kwds): try: func(*args, **kwds) except Exception, e: trace = str(traceback.format_exc()) short = 'Ignored an exception in ropemode hook: %s' % \ _exception_message(e) logger(trace, short) newfunc.lisp = None newfunc.__name__ = func.__name__ newfunc.__doc__ = func.__doc__ return newfunc def lispfunction(func): func.lisp = None return func input_exceptions = (exceptions.RefactoringError, exceptions.ModuleSyntaxError, exceptions.BadIdentifierError) def _exception_handler(func): def newfunc(*args, **kwds): try: func(*args, **kwds) except exceptions.RopeError, e: short = None if isinstance(e, input_exceptions): short = _exception_message(e) logger(str(traceback.format_exc()), short) newfunc.__name__ = func.__name__ newfunc.__doc__ = func.__doc__ return newfunc def _exception_message(e): return '%s: %s' % (e.__class__.__name__, str(e)) def rope_hook(hook): def decorator(func): func = lisphook(func) func.name = func.__name__ func.kind = 'hook' func.hook = hook return func return decorator def local_command(key=None, prefix=False, shortcut=None, name=None): def decorator(func, name=name): func = _exception_handler(func) func.kind = 'local' func.prefix = prefix func.local_key = key func.shortcut_key = shortcut if name is None: name = func.__name__ func.name = name return func return decorator def global_command(key=None, prefix=False): def decorator(func): func = _exception_handler(func) func.kind = 'global' func.prefix = prefix func.global_key = key func.name = func.__name__ return func return decorator ropemacs-0.6c2/ropemode/__init__.py0000644000175000017500000000113311026633100015422 0ustar aliali"""ropemode, a helper for using rope refactoring library in IDEs""" COPYRIGHT = """\ Copyright (C) 2007-2008 Ali Gholami Rudi This program is free software; you can redistribute it and/or modify it under the terms of GNU General Public License as published by the Free Software Foundation; either version 2 of the license, or (at your opinion) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.""" ropemacs-0.6c2/ropemacs/0000755000175000017500000000000011026635424013325 5ustar alialiropemacs-0.6c2/ropemacs/__init__.py0000644000175000017500000004313511026633070015437 0ustar aliali"""ropemacs, an emacs mode for using rope refactoring library""" import ropemode.decorators import ropemode.environment import ropemode.interface from Pymacs import lisp from rope.base import utils class LispUtils(ropemode.environment.Environment): def ask(self, prompt, default=None, starting=None): if default is not None: prompt = prompt + ('[%s] ' % default) result = lisp.read_from_minibuffer(prompt, starting, None, None, None, default, None) if result == '' and default is not None: return default return result def ask_values(self, prompt, values, default=None, starting=None, exact=True): if self._emacs_version() < 22: values = [[value, value] for value in values] if exact and default is not None: prompt = prompt + ('[%s] ' % default) reader = lisp['ropemacs-completing-read-function'].value() result = reader(prompt, values, None, exact, starting) if result == '' and exact: return default return result def ask_completion(self, prompt, values, starting=None): return self.ask_values(prompt, values, starting=starting, exact=None) def ask_directory(self, prompt, default=None, starting=None): location = starting or default if location is not None: prompt = prompt + ('[%s] ' % location) if lisp.fboundp(lisp['read-directory-name']): # returns default when starting is entered result = lisp.read_directory_name(prompt, location, location) else: result = lisp.read_file_name(prompt, location, location) if result == '' and location is not None: return location return result def message(self, msg): message(msg) def yes_or_no(self, prompt): return lisp.yes_or_no_p(prompt) def y_or_n(self, prompt): return lisp.y_or_n_p(prompt) def get(self, name, default=None): lispname = 'ropemacs-' + name.replace('_', '-') if lisp.boundp(lisp[lispname]): return lisp[lispname].value() return default def get_offset(self): return lisp.point() - 1 def get_text(self): end = lisp.buffer_size() + 1 old_min = lisp.point_min() old_max = lisp.point_max() narrowed = (old_min != 1 or old_max != end) if narrowed: lisp.narrow_to_region(1, lisp.buffer_size() + 1) try: return lisp.buffer_string() finally: if narrowed: lisp.narrow_to_region(old_min, old_max) def get_region(self): offset1 = self.get_offset() lisp.exchange_point_and_mark() offset2 = self.get_offset() lisp.exchange_point_and_mark() return min(offset1, offset2), max(offset1, offset2) def filename(self): return lisp.buffer_file_name() def is_modified(self): return lisp.buffer_modified_p() def goto_line(self, lineno): lisp.goto_line(lineno) def insert_line(self, line, lineno): current = lisp.point() lisp.goto_line(lineno) lisp.insert(line + '\n') lisp.goto_char(current + len(line) + 1) def insert(self, text): lisp.insert(text) def delete(self, start, end): lisp.delete_region(start, end) def filenames(self): result = [] for buffer in lisp.buffer_list(): filename = lisp.buffer_file_name(buffer) if filename: result.append(filename) return result def save_files(self, filenames): ask = self.get('confirm_saving') initial = lisp.current_buffer() for filename in filenames: buffer = lisp.find_buffer_visiting(filename) if buffer: if lisp.buffer_modified_p(buffer): if not ask or lisp.y_or_n_p('Save %s buffer?' % filename): lisp.set_buffer(buffer) lisp.save_buffer() lisp.set_buffer(initial) def reload_files(self, filenames, moves={}): if self.filename() in moves: initial = None else: initial = lisp.current_buffer() for filename in filenames: buffer = lisp.find_buffer_visiting(filename) if buffer: if filename in moves: lisp.kill_buffer(buffer) lisp.find_file(moves[filename]) else: lisp.set_buffer(buffer) lisp.revert_buffer(False, True) if initial is not None: lisp.set_buffer(initial) def find_file(self, filename, readonly=False, other=False): if other: lisp.find_file_other_window(filename) elif readonly: lisp.find_file_read_only(filename) else: lisp.find_file(filename) def _make_buffer(self, name, contents, empty_goto=True, switch=False, window='other', modes=[], fit_lines=None): """Make an emacs buffer `window` can be one of `None`, 'current' or 'other'. """ new_buffer = lisp.get_buffer_create(name) lisp.set_buffer(new_buffer) lisp.toggle_read_only(-1) lisp.erase_buffer() if contents or empty_goto: lisp.insert(contents) for mode in modes: lisp[mode + '-mode']() lisp.buffer_disable_undo(new_buffer) lisp.toggle_read_only(1) if switch: if window == 'current': lisp.switch_to_buffer(new_buffer) else: lisp.switch_to_buffer_other_window(new_buffer) lisp.goto_char(lisp.point_min()) elif window == 'other': new_window = lisp.display_buffer(new_buffer) lisp.set_window_point(new_window, lisp.point_min()) if fit_lines and lisp.fboundp(lisp['fit-window-to-buffer']): lisp.fit_window_to_buffer(new_window, fit_lines) lisp.bury_buffer(new_buffer) return new_buffer def _hide_buffer(self, name, delete=True): buffer = lisp.get_buffer(name) if buffer is not None: window = lisp.get_buffer_window(buffer) if window is not None: lisp.bury_buffer(buffer) if delete: lisp.delete_window(window) else: if lisp.buffer_name(lisp.current_buffer()) == name: lisp.switch_to_buffer(None) def _emacs_version(self): return int(lisp['emacs-version'].value().split('.')[0]) def create_progress(self, name): if lisp.fboundp(lisp['make-progress-reporter']): progress = _LispProgress(name) else: progress = _OldProgress(name) return progress def current_word(self): return lisp.current_word() def push_mark(self): lisp.push_mark() def prefix_value(self, prefix): return lisp.prefix_numeric_value(prefix) def show_occurrences(self, locations): text = [] for location in locations: line = '%s : %s %s %s' % (location.filename, location.lineno, location.note, location.offset) text.append(line) text = '\n'.join(text) + '\n' buffer = self._make_buffer('*rope-occurrences*', text, switch=True) lisp.set_buffer(buffer) lisp.local_set_key('\r', lisp.rope_occurrences_goto_occurrence) lisp.local_set_key('q', lisp.delete_window) def show_doc(self, docs, altview=False): use_minibuffer = not altview if self.get('separate_doc_buffer'): use_minibuffer = not use_minibuffer if not use_minibuffer: fit_lines = self.get('max_doc_buffer_height') buffer = self._make_buffer('*rope-pydoc*', docs, empty_goto=False, fit_lines=fit_lines) lisp.local_set_key('q', lisp.bury_buffer) elif docs: docs = '\n'.join(docs.split('\n')[:7]) self.message(docs) def preview_changes(self, diffs): self._make_buffer('*rope-preview*', diffs, switch=True, modes=['diff'], window='current') try: return self.yes_or_no('Do the changes? ') finally: self._hide_buffer('*rope-preview*', delete=False) def local_command(self, name, callback, key=None, prefix=False): globals()[name] = callback self._set_interaction(callback, prefix) if self.local_prefix and key: key = self._key_sequence(self.local_prefix + ' ' + key) self._bind_local(_lisp_name(name), key) def _bind_local(self, name, key): lisp('(define-key ropemacs-local-keymap "%s" \'%s)' % (self._key_sequence(key), name)) def global_command(self, name, callback, key=None, prefix=False): globals()[name] = callback self._set_interaction(callback, prefix) if self.global_prefix and key: key = self._key_sequence(self.global_prefix + ' ' + key) lisp.global_set_key(key, lisp[_lisp_name(name)]) def _key_sequence(self, sequence): result = [] for key in sequence.split(): if key.startswith('C-'): number = ord(key[-1].upper()) - ord('A') + 1 result.append(chr(number)) elif key.startswith('M-'): number = ord(key[-1].upper()) + 0x80 result.append(chr(number)) else: result.append(key) return ''.join(result) def _set_interaction(self, callback, prefix): if hasattr(callback, 'im_func'): callback = callback.im_func if prefix: callback.interaction = 'P' else: callback.interaction = '' def add_hook(self, name, callback, hook): mapping = {'before_save': 'before-save-hook', 'after_save': 'after-save-hook', 'exit': 'kill-emacs-hook'} globals()[name] = callback lisp.add_hook(lisp[mapping[hook]], lisp[_lisp_name(name)]) @property @utils.cacheit def global_prefix(self): return self.get('global_prefix') @property @utils.cacheit def local_prefix(self): return self.get('local_prefix') def _lisp_name(name): return 'rope-' + name.replace('_', '-') class _LispProgress(object): def __init__(self, name): self.progress = lisp.make_progress_reporter('%s ... ' % name, 0, 100) def update(self, percent): lisp.progress_reporter_update(self.progress, percent) def done(self): lisp.progress_reporter_done(self.progress) class _OldProgress(object): def __init__(self, name): self.name = name self.update(0) def update(self, percent): if percent != 0: message('%s ... %s%%%%' % (self.name, percent)) else: message('%s ... ' % self.name) def done(self): message('%s ... done' % self.name) def message(message): lisp.message(message.replace('%', '%%')) def occurrences_goto_occurrence(): lisp.end_of_line() end = lisp.point() lisp.beginning_of_line() start = lisp.point() line = lisp.buffer_substring_no_properties(start, end) tokens = line.split() if tokens: filename = tokens[0] offset = int(tokens[-1]) resource = _interface._get_resource(filename) LispUtils().find_file(resource.real_path, other=True) lisp.goto_char(offset + 1) lisp.switch_to_buffer_other_window('*rope-occurrences*') occurrences_goto_occurrence.interaction = '' DEFVARS = """\ (defgroup ropemacs nil "ropemacs, an emacs plugin for rope." :link '(url-link "http://rope.sourceforge.net/ropemacs.html") :prefix "rope-") (defcustom ropemacs-confirm-saving t "Shows whether to confirm saving modified buffers before refactorings. If non-nil, you have to confirm saving all modified python files before refactorings; otherwise they are saved automatically.") (defcustom ropemacs-codeassist-maxfixes 1 "The number of errors to fix before code-assist. How many errors to fix, at most, when proposing code completions.") (defcustom ropemacs-separate-doc-buffer t "Should `rope-show-doc' use a separate buffer or the minibuffer.") (defcustom ropemacs-max-doc-buffer-height 22 "The maximum buffer height for `rope-show-doc'.") (defcustom ropemacs-enable-autoimport 'nil "Specifies whether autoimport should be enabled.") (defcustom ropemacs-autoimport-modules nil "The name of modules whose global names should be cached. The `rope-generate-autoimport-cache' reads this list and fills its cache.") (defcustom ropemacs-autoimport-underlineds 'nil "If set, autoimport will cache names starting with underlines, too.") (defcustom ropemacs-completing-read-function (if (and (boundp 'ido-mode) ido-mode) 'ido-completing-read 'completing-read) "Function to call when prompting user to choose between a list of options. This should take the same arguments as `completing-read'. Possible values are `completing-read' and `ido-completing-read'. Note that you must set `ido-mode' if using`ido-completing-read'." :type 'function) (make-obsolete-variable 'rope-confirm-saving 'ropemacs-confirm-saving) (make-obsolete-variable 'rope-code-assist-max-fixes 'ropemacs-codeassist-maxfixes) (defcustom ropemacs-local-prefix "C-c r" "The prefix for ropemacs refactorings. Use nil to prevent binding keys.") (defcustom ropemacs-global-prefix "C-x p" "The prefix for ropemacs project commands. Use nil to prevent binding keys.") (defcustom ropemacs-enable-shortcuts 't "Shows whether to bind ropemacs shortcuts keys. If non-nil it binds: ================ ============================ Key Command ================ ============================ M-/ rope-code-assist C-c g rope-goto-definition C-c d rope-show-doc C-c f rope-find-occurrences M-? rope-lucky-assist ================ ============================ ") (defvar ropemacs-local-keymap (make-sparse-keymap)) (easy-menu-define ropemacs-mode-menu ropemacs-local-keymap "`ropemacs' menu" '("Rope" ["Code assist" rope-code-assist t] ["Lucky assist" rope-lucky-assist t] ["Goto definition" rope-goto-definition t] ["Jump to global" rope-jump-to-global t] ["Show documentation" rope-show-doc t] ["Find Occurrences" rope-find-occurrences t] ["Analyze module" rope-analyze-module t] ("Refactor" ["Inline" rope-inline t] ["Extract Variable" rope-extract-variable t] ["Extract Method" rope-extract-method t] ["Organize Imports" rope-organize-imports t] ["Rename" rope-rename t] ["Move" rope-move t] ["Restructure" rope-restructure t] ["Use Function" rope-use-function t] ["Introduce Factory" rope-introduce-factory t] ("Generate" ["Class" rope-generate-class t] ["Function" rope-generate-function t] ["Module" rope-generate-module t] ["Package" rope-generate-package t] ["Variable" rope-generate-variable t] ) ("Module" ["Module to Package" rope-module-to-package t] ["Rename Module" rope-rename-current-module t] ["Move Module" rope-move-current-module t] ) "--" ["Undo" rope-undo t] ["Redo" rope-redo t] ) ("Project" ["Open project" rope-open-project t] ["Close project" rope-close-project t] ["Find file" rope-find-file t] ["Open project config" rope-project-config t] ) ("Create" ["Module" rope-create-module t] ["Package" rope-create-package t] ["File" rope-create-file t] ["Directory" rope-create-directory t] ) )) (defcustom ropemacs-guess-project 'nil "Try to guess the project when needed. If non-nil, ropemacs tries to guess and open the project that contains a file on which the rope command is performed when no project is already opened.") (provide 'ropemacs) """ MINOR_MODE = """\ (define-minor-mode ropemacs-mode "ropemacs, rope in emacs!" nil " Rope" ropemacs-local-keymap :global nil) ) """ shortcuts = [('M-/', 'rope-code-assist'), ('M-?', 'rope-lucky-assist'), ('C-c g', 'rope-goto-definition'), ('C-c d', 'rope-show-doc'), ('C-c f', 'rope-find-occurrences')] ropemode.decorators.logger.message = message lisp(DEFVARS) _interface = ropemode.interface.RopeMode(env=LispUtils()) _interface.init() lisp(MINOR_MODE) for key, command in shortcuts: LispUtils()._bind_local(command, key) lisp.add_hook(lisp['python-mode-hook'], lisp['ropemacs-mode']) ropemacs-0.6c2/docs/0000755000175000017500000000000011026635424012444 5ustar alialiropemacs-0.6c2/docs/todo.txt0000644000175000017500000000027511026633070014151 0ustar alialiTODO ==== > Public Release 1.0 > Public Release 0.6 * saving the old values of refactoring configs * showing proposal type in code-assist * something like grep mode for find occurrences ropemacs-0.6c2/docs/ropemacs.txt0000644000175000017500000000353011026633070015012 0ustar aliali========================= ropemacs, rope in emacs ========================= Ropemacs is a plugin for performing python refactorings in emacs. It uses rope_ library and pymacs_. You should install `rope`_ library and pymacs_ before using ropemacs. You can download ropemacs from `project download page`_. .. _rope: http://rope.sf.net/ Features ======== * Supports many of the refactorings that are supported by rope_ library: * Rename * Extract method/local variable * Move class/function/module/package/method * Inline method/local variable/parameter * Restructuring * Change signature * ... * Other refactoring-related features * Previewing refactorings * Undo/redo refactorings * Showing refactoring progress * Code-assists * Code-completion * Goto definition * Show pydoc * Find occurrences * Organize imports (remove unused and duplicate imports and sort them) * Generating python elements Source Repository ================= The repository version needs ropemode (which was once part of ropemacs); in order to use the repository version of ropemacs you need to put ropemode in your ``PYTHONPATH``. Note that ropemode is included in released packages. Ropemacs: * repo url: http://rope.sf.net/hg/ropemacs * snapshot: http://rope.sf.net/hg/ropemacs/archive/tip.tar.gz Ropemode: * repo url: http://rope.sf.net/hg/ropemode * snapshot: http://rope.sf.net/hg/ropemode/archive/tip.tar.gz Feedback ======== Send your bug reports, feature requests and patches to `rope-dev (at) googlegroups.com`_. License ======= Ropemacs is under the terms of GNU GPL (GNU General Public License). .. _project download page: http://sf.net/projects/rope/files .. _`rope-dev (at) googlegroups.com`: http://groups.google.com/group/rope-dev .. _pymacs: http://pymacs.progiciels-bpi.ca/pymacs.html .. _Mercurial: http://selenic.com/mercurial ropemacs-0.6c2/docs/done.txt0000644000175000017500000001041011026633070014121 0ustar aliali====== Done ====== > Public Release 0.6c2 : June 20, 2008 - fixed go to occurrence in xemacs : June 20, 2008 - added ropemacs-guess-project variable : June 18, 2008 - fixed error messages that contain percent sign : June 18, 2008 - fixed ask directory and entering default directory : June 9, 2008 - added rope-run-module command : May 24, 2008 - showing line-number in occurrences buffer : May 19, 2008 > Public Release 0.6c1 : May 10, 2008 - supporting inlining parameters : May 10, 2008 - added rope-change-signature : May 9, 2008 - added ropemacs-autoimport-underlineds variable : May 7, 2008 - added rope-find-implementations : April 28, 2008 - added rope-show-calltip : April 12, 2008 - added rope-analyze-modules : April 12, 2008 > Public Release 0.5 : April 5, 2008 - better input error reporting : March 27, 2008 - added ropemacs-completing-read-function variable : March 17, 2008 - added rope-jump-to-global : March 17, 2008 > Public Release 0.5c6 : March 15, 2008 - added rope-analyze-module command : March 15, 2008 - supporting in_hierarchy option of find_occurrences : March 10, 2008 - added ropemacs-max-doc-buffer-height variable : March 7, 2008 - added ropemacs menu : March 7, 2008 - added rope-show-call-doc command : March 6, 2008 - added ropemacs-separate-doc-buffer variable : March 6, 2008 - supporting maxfixes option of rope-goto-definition : March 6, 2008 - supporting maxfixes option of rope-show-doc : March 6, 2008 - added ropemacs minor mode : March 1, 2008 > Public Release 0.5c5 : March 1, 2008 - filtering resources : February 29, 2008 - added support for introduce factory refactoring : February 25, 2008 > Public Release 0.5c4 : February 16, 2008 - compatibility with pymacs : February 14, 2008 - faster code-assists : February 7, 2008 - prefixing rope-find-file shows only python files : February 2, 2008 - merged rope-complete-and-import with code-assist : January 28, 2008 > Public Release 0.5c3 : January 28, 2008 - added support for autoimport : January 26, 2008 - added introduce method object refactoring : January 25, 2008 - added use function refactoring : January 25, 2008 > Public Release 0.5c2 : January 17, 2008 - showing change description in undo/redo : January 8, 2008 - added rope-find-file-other-window : January 4, 2008 - added ropemacs-enable-shortcuts variable : January 3, 2008 > Public Release 0.5c1 : January 3, 2008 - deprecated rope-code-assist-max-fixes : December 28, 2007 - deprecated rope-confirm-saving : December 28, 2007 - added ropemacs-local-prefix and ropemacs-global-prefix : December 28, 2007 - handling narrowed regions : December 21, 2007 > Public Release 0.4 : December 19, 2007 - supporting emacs 21 : December 18, 2007 - added ``rope-code-assist-max-fixes`` variable : December 17, 2007 - printing traceback when task runner gets interrupted : December 14, 2007 - supporting ``only_current`` option for inline refactoring : December 13, 2007 - supporting ``global_`` option for extract refactorings : December 13, 2007 - not raising exceptions in hooks : December 5, 2007 > Public Release 0.3 : December 5, 2007 - setting many configs using batchset in dialogs : December 1, 2007 - updating buffers with moved files : December 1, 2007 - showing the old value of a field in dialogs : November 30, 2007 - new file/directory/module/package; ``C-x p n [fdmp]`` : November 30, 2007 - lucky-assist; ``M-?`` : November 29, 2007 - find occurrences; ``C-c f`` : November 29, 2007 - edit project config; ``C-x p c`` : November 28, 2007 > Public Release 0.2 : November 28, 2007 - previewing changes : November 27, 2007 - specifying refactoring options : November 26, 2007 - restructuring support : November 26, 2007 - added ``rope-confirm-saving`` variable : November 26, 2007 - only activating local keys in python mode : November 26, 2007 - find file and advanced matching : November 25, 2007 - generate python element; ``C-c n [vfcmp]`` : November 23, 2007 - rope find file; ``C-c p f`` : November 23, 2007 - code-assist; ``M-/`` : November 23, 2007 > Public Release 0.1 : September 9, 2007 - moving elements, methods and modules : October 30, 2007 - undoing refactorings : October 29, 2007 - inline refactoring : October 29, 2007 - extract method and local variable : October 29, 2007 - goto definition : October 29, 2007 - rename refactoring : October 29, 2007