Path: blob/master/elisp/emacs-for-python/rope-dist/ropemacs/__init__.py
990 views
"""ropemacs, an emacs mode for using rope refactoring library"""1import sys23import ropemode.decorators4import ropemode.environment5import ropemode.interface6from Pymacs import lisp7from rope.base import utils8910class LispUtils(ropemode.environment.Environment):1112def ask(self, prompt, default=None, starting=None):13if default is not None:14prompt = prompt + ('[%s] ' % default)15result = lisp.read_from_minibuffer(prompt, starting, None, None,16None, default, None)17if result == '' and default is not None:18return default19return result2021def ask_values(self, prompt, values, default=None, starting=None, exact=True):22if self._emacs_version() < 22:23values = [[value, value] for value in values]24if exact and default is not None:25prompt = prompt + ('[%s] ' % default)26reader = lisp['ropemacs-completing-read-function'].value()27result = reader(prompt, values, None, exact, starting)28if result == '' and exact:29return default30return result3132def ask_completion(self, prompt, values, starting=None):33return self.ask_values(prompt, values, starting=starting, exact=None)3435def ask_directory(self, prompt, default=None, starting=None):36location = starting or default37if location is not None:38prompt = prompt + ('[%s] ' % location)39if lisp.fboundp(lisp['read-directory-name']):40# returns default when starting is entered41result = lisp.read_directory_name(prompt, location, location)42else:43result = lisp.read_file_name(prompt, location, location)44if result == '' and location is not None:45return location46return result4748def message(self, msg):49message(msg)5051def yes_or_no(self, prompt):52return lisp.yes_or_no_p(prompt)5354def y_or_n(self, prompt):55return lisp.y_or_n_p(prompt)5657def get(self, name, default=None):58lispname = 'ropemacs-' + name.replace('_', '-')59if lisp.boundp(lisp[lispname]):60return lisp[lispname].value()61return default6263def get_offset(self):64return lisp.point() - 16566def get_text(self):67end = lisp.buffer_size() + 168old_min = lisp.point_min()69old_max = lisp.point_max()70narrowed = (old_min != 1 or old_max != end)71if narrowed:72lisp.narrow_to_region(1, lisp.buffer_size() + 1)73try:74return lisp.buffer_string()75finally:76if narrowed:77lisp.narrow_to_region(old_min, old_max)7879def get_region(self):80offset1 = self.get_offset()81lisp.exchange_point_and_mark()82offset2 = self.get_offset()83lisp.exchange_point_and_mark()84return min(offset1, offset2), max(offset1, offset2)8586def filename(self):87return lisp.buffer_file_name()8889def is_modified(self):90return lisp.buffer_modified_p()9192def goto_line(self, lineno):93lisp.goto_line(lineno)9495def insert_line(self, line, lineno):96current = lisp.point()97lisp.goto_line(lineno)98lisp.insert(line + '\n')99lisp.goto_char(current + len(line) + 1)100101def insert(self, text):102lisp.insert(text)103104def delete(self, start, end):105lisp.delete_region(start, end)106107def filenames(self):108result = []109for buffer in lisp.buffer_list():110filename = lisp.buffer_file_name(buffer)111if filename:112result.append(filename)113return result114115def save_files(self, filenames):116ask = self.get('confirm_saving')117initial = lisp.current_buffer()118for filename in filenames:119buffer = lisp.find_buffer_visiting(filename)120if buffer:121if lisp.buffer_modified_p(buffer):122if not ask or lisp.y_or_n_p('Save %s buffer?' % filename):123lisp.set_buffer(buffer)124lisp.save_buffer()125lisp.set_buffer(initial)126127def reload_files(self, filenames, moves={}):128if self.filename() in moves:129initial = None130else:131initial = lisp.current_buffer()132for filename in filenames:133buffer = lisp.find_buffer_visiting(filename)134if buffer:135if filename in moves:136lisp.kill_buffer(buffer)137lisp.find_file(moves[filename])138else:139lisp.set_buffer(buffer)140lisp.revert_buffer(False, True)141if initial is not None:142lisp.set_buffer(initial)143144def find_file(self, filename, readonly=False, other=False):145if other:146lisp.find_file_other_window(filename)147elif readonly:148lisp.find_file_read_only(filename)149else:150lisp.find_file(filename)151152def _make_buffer(self, name, contents, empty_goto=True, switch=False,153window='other', modes=[], fit_lines=None):154"""Make an emacs buffer155156`window` can be one of `None`, 'current' or 'other'.157"""158new_buffer = lisp.get_buffer_create(name)159lisp.set_buffer(new_buffer)160lisp.toggle_read_only(-1)161lisp.erase_buffer()162if contents or empty_goto:163lisp.insert(contents)164for mode in modes:165lisp[mode + '-mode']()166lisp.buffer_disable_undo(new_buffer)167lisp.toggle_read_only(1)168if switch:169if window == 'current':170lisp.switch_to_buffer(new_buffer)171else:172lisp.switch_to_buffer_other_window(new_buffer)173lisp.goto_char(lisp.point_min())174elif window == 'other':175new_window = lisp.display_buffer(new_buffer)176lisp.set_window_point(new_window, lisp.point_min())177if fit_lines and lisp.fboundp(lisp['fit-window-to-buffer']):178lisp.fit_window_to_buffer(new_window, fit_lines)179lisp.bury_buffer(new_buffer)180return new_buffer181182def _hide_buffer(self, name, delete=True):183buffer = lisp.get_buffer(name)184if buffer is not None:185window = lisp.get_buffer_window(buffer)186if window is not None:187lisp.bury_buffer(buffer)188if delete:189lisp.delete_window(window)190else:191if lisp.buffer_name(lisp.current_buffer()) == name:192lisp.switch_to_buffer(None)193194def _emacs_version(self):195return int(lisp['emacs-version'].value().split('.')[0])196197def create_progress(self, name):198if lisp.fboundp(lisp['make-progress-reporter']):199progress = _LispProgress(name)200else:201progress = _OldProgress(name)202return progress203204def current_word(self):205return lisp.current_word()206207def push_mark(self):208lisp.push_mark()209210def prefix_value(self, prefix):211return lisp.prefix_numeric_value(prefix)212213def show_occurrences(self, locations):214text = ['List of occurrences:', '']215for location in locations:216line = '%s : %s %s %s' % (location.filename, location.lineno,217location.note, location.offset)218text.append(line)219text = '\n'.join(text) + '\n'220buffer = self._make_buffer('*rope-occurrences*', text, switch=False)221lisp.set_buffer(buffer)222lisp.toggle_read_only(1)223lisp.set(lisp["next-error-function"], lisp.rope_occurrences_next)224lisp.local_set_key('\r', lisp.rope_occurrences_goto)225lisp.local_set_key('q', lisp.delete_window)226227def show_doc(self, docs, altview=False):228use_minibuffer = not altview229if self.get('separate_doc_buffer'):230use_minibuffer = not use_minibuffer231if not use_minibuffer:232fit_lines = self.get('max_doc_buffer_height')233buffer = self._make_buffer('*rope-pydoc*', docs,234empty_goto=False,235fit_lines=fit_lines)236lisp.local_set_key('q', lisp.bury_buffer)237elif docs:238docs = '\n'.join(docs.split('\n')[:7])239self.message(docs)240241def preview_changes(self, diffs):242self._make_buffer('*rope-preview*', diffs, switch=True,243modes=['diff'], window='current')244try:245return self.yes_or_no('Do the changes? ')246finally:247self._hide_buffer('*rope-preview*', delete=False)248249def local_command(self, name, callback, key=None, prefix=False):250globals()[name] = callback251self._set_interaction(callback, prefix)252if self.local_prefix and key:253key = self._key_sequence(self.local_prefix + ' ' + key)254self._bind_local(_lisp_name(name), key)255256def _bind_local(self, name, key):257lisp('(define-key ropemacs-local-keymap "%s" \'%s)' %258(self._key_sequence(key), name))259260def global_command(self, name, callback, key=None, prefix=False):261globals()[name] = callback262self._set_interaction(callback, prefix)263if self.global_prefix and key:264key = self._key_sequence(self.global_prefix + ' ' + key)265lisp.global_set_key(key, lisp[_lisp_name(name)])266267def _key_sequence(self, sequence):268result = []269for key in sequence.split():270if key.startswith('C-'):271number = ord(key[-1].upper()) - ord('A') + 1272result.append(chr(number))273elif key.startswith('M-'):274number = ord(key[-1].upper()) + 0x80275result.append(chr(number))276else:277result.append(key)278return ''.join(result)279280def _set_interaction(self, callback, prefix):281if hasattr(callback, 'im_func'):282callback = callback.im_func283if prefix:284callback.interaction = 'P'285else:286callback.interaction = ''287288def add_hook(self, name, callback, hook):289mapping = {'before_save': 'before-save-hook',290'after_save': 'after-save-hook',291'exit': 'kill-emacs-hook'}292globals()[name] = callback293lisp.add_hook(lisp[mapping[hook]], lisp[_lisp_name(name)])294295def project_opened(self):296'''297This method is called when a new project is opened, it runs298the hooks associated with rope-open-project-hook.299'''300lisp.run_hooks(lisp["rope-open-project-hook"])301302@property303@utils.saveit304def global_prefix(self):305return self.get('global_prefix')306307@property308@utils.saveit309def local_prefix(self):310return self.get('local_prefix')311312313def _lisp_name(name):314return 'rope-' + name.replace('_', '-')315316class _LispProgress(object):317318def __init__(self, name):319self.progress = lisp.make_progress_reporter('%s ... ' % name, 0, 100)320321def update(self, percent):322lisp.progress_reporter_update(self.progress, percent)323324def done(self):325lisp.progress_reporter_done(self.progress)326327class _OldProgress(object):328329def __init__(self, name):330self.name = name331self.update(0)332333def update(self, percent):334if percent != 0:335message('%s ... %s%%%%' % (self.name, percent))336else:337message('%s ... ' % self.name)338339def done(self):340message('%s ... done' % self.name)341342343def message(message):344lisp.message(message.replace('%', '%%'))345346def occurrences_goto():347if lisp.line_number_at_pos() < 3:348lisp.forward_line(3 - lisp.line_number_at_pos())349lisp.end_of_line()350end = lisp.point()351lisp.beginning_of_line()352line = lisp.buffer_substring_no_properties(lisp.point(), end)353tokens = line.split()354if tokens:355filename = tokens[0]356offset = int(tokens[-1])357resource = _interface._get_resource(filename)358LispUtils().find_file(resource.real_path, other=True)359lisp.goto_char(offset + 1)360occurrences_goto.interaction = ''361362def occurrences_next(arg, reset):363lisp.switch_to_buffer_other_window('*rope-occurrences*', True)364if reset:365lisp.goto_char(lisp.point_min())366lisp.forward_line(arg)367if lisp.eobp():368lisp.message("Cycling rope occurences")369lisp.goto_char(lisp.point_min())370occurrences_goto()371occurrences_next.interaction = ''372373374DEFVARS = """\375(defgroup ropemacs nil376"ropemacs, an emacs plugin for rope."377:link '(url-link "http://rope.sourceforge.net/ropemacs.html")378:prefix "rope-")379380(defcustom ropemacs-confirm-saving t381"Shows whether to confirm saving modified buffers before refactorings.382383If non-nil, you have to confirm saving all modified384python files before refactorings; otherwise they are385saved automatically.")386387(defcustom ropemacs-codeassist-maxfixes 1388"The number of errors to fix before code-assist.389390How many errors to fix, at most, when proposing code completions.")391392(defcustom ropemacs-separate-doc-buffer t393"Should `rope-show-doc' use a separate buffer or the minibuffer.")394(defcustom ropemacs-max-doc-buffer-height 22395"The maximum buffer height for `rope-show-doc'.")396397(defcustom ropemacs-enable-autoimport 'nil398"Specifies whether autoimport should be enabled.")399(defcustom ropemacs-autoimport-modules nil400"The name of modules whose global names should be cached.401402The `rope-generate-autoimport-cache' reads this list and fills its403cache.")404(defcustom ropemacs-autoimport-underlineds 'nil405"If set, autoimport will cache names starting with underlines, too.")406407(defcustom ropemacs-completing-read-function (if (and (boundp 'ido-mode)408ido-mode)409'ido-completing-read410'completing-read)411"Function to call when prompting user to choose between a list of options.412This should take the same arguments as `completing-read'.413Possible values are `completing-read' and `ido-completing-read'.414Note that you must set `ido-mode' if using`ido-completing-read'."415:type 'function)416417(make-obsolete-variable418'rope-confirm-saving 'ropemacs-confirm-saving)419(make-obsolete-variable420'rope-code-assist-max-fixes 'ropemacs-codeassist-maxfixes)421422(defcustom ropemacs-local-prefix "C-c r"423"The prefix for ropemacs refactorings.424425Use nil to prevent binding keys.")426427(defcustom ropemacs-global-prefix "C-x p"428"The prefix for ropemacs project commands.429430Use nil to prevent binding keys.")431432(defcustom ropemacs-enable-shortcuts 't433"Shows whether to bind ropemacs shortcuts keys.434435If non-nil it binds:436437================ ============================438Key Command439================ ============================440M-/ rope-code-assist441C-c g rope-goto-definition442C-c d rope-show-doc443C-c f rope-find-occurrences444M-? rope-lucky-assist445================ ============================446")447448(defvar ropemacs-local-keymap (make-sparse-keymap))449450(easy-menu-define ropemacs-mode-menu ropemacs-local-keymap451"`ropemacs' menu"452'("Rope"453["Code assist" rope-code-assist t]454["Lucky assist" rope-lucky-assist t]455["Goto definition" rope-goto-definition t]456["Jump to global" rope-jump-to-global t]457["Show documentation" rope-show-doc t]458["Find Occurrences" rope-find-occurrences t]459["Analyze module" rope-analyze-module t]460("Refactor"461["Inline" rope-inline t]462["Extract Variable" rope-extract-variable t]463["Extract Method" rope-extract-method t]464["Organize Imports" rope-organize-imports t]465["Rename" rope-rename t]466["Move" rope-move t]467["Restructure" rope-restructure t]468["Use Function" rope-use-function t]469["Introduce Factory" rope-introduce-factory t]470("Generate"471["Class" rope-generate-class t]472["Function" rope-generate-function t]473["Module" rope-generate-module t]474["Package" rope-generate-package t]475["Variable" rope-generate-variable t]476)477("Module"478["Module to Package" rope-module-to-package t]479["Rename Module" rope-rename-current-module t]480["Move Module" rope-move-current-module t]481)482"--"483["Undo" rope-undo t]484["Redo" rope-redo t]485)486("Project"487["Open project" rope-open-project t]488["Close project" rope-close-project t]489["Find file" rope-find-file t]490["Open project config" rope-project-config t]491)492("Create"493["Module" rope-create-module t]494["Package" rope-create-package t]495["File" rope-create-file t]496["Directory" rope-create-directory t]497)498))499500(defcustom ropemacs-guess-project 'nil501"Try to guess the project when needed.502503If non-nil, ropemacs tries to guess and open the project that contains504a file on which the rope command is performed when no project is505already opened.")506507(provide 'ropemacs)508"""509510MINOR_MODE = """\511(define-minor-mode ropemacs-mode512"ropemacs, rope in emacs!" nil " Rope" ropemacs-local-keymap513:global nil)514)515"""516517shortcuts = [('M-/', 'rope-code-assist'),518('M-?', 'rope-lucky-assist'),519('C-c g', 'rope-goto-definition'),520('C-c d', 'rope-show-doc'),521('C-c f', 'rope-find-occurrences')]522523524_interface = None525526def _load_ropemacs():527global _interface528ropemode.decorators.logger.message = message529lisp(DEFVARS)530_interface = ropemode.interface.RopeMode(env=LispUtils())531_interface.init()532lisp(MINOR_MODE)533534if LispUtils().get('enable_shortcuts'):535for key, command in shortcuts:536LispUtils()._bind_local(command, key)537538lisp.add_hook(lisp['python-mode-hook'], lisp['ropemacs-mode'])539540def _started_from_pymacs():541import inspect542frame = sys._getframe()543while frame:544# checking frame.f_code.co_name == 'pymacs_load_helper' might545# be very fragile.546if inspect.getfile(frame).rstrip('c').endswith('pymacs.py'):547return True548frame = frame.f_back549550if _started_from_pymacs():551_load_ropemacs()552553554