├── .gitignore ├── MANIFEST.in ├── CONTRIBUTORS ├── ftplugin └── python_ropevim.vim ├── ChangeLog ├── setup.py ├── rope_omni.py ├── doc └── ropevim.txt ├── COPYING ├── README.rst └── ropevim.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.*~ 3 | *.egg-info 4 | .ropeproject/ 5 | doc/build/ 6 | doc/tags 7 | build/ 8 | dist/ 9 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst COPYING setup.py MANIFEST.in 2 | include ropevim.py ropevim.vim 3 | recursive-include ropemode *.py 4 | recursive-include docs *.rst 5 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | ====================== 2 | Ropevim Contributors 3 | ====================== 4 | 5 | * Alon Levy 6 | * Matthieu Tanguay-Carel 7 | * Jesse Zhang 8 | * Ben Davis 9 | * Anton Gritsay 10 | -------------------------------------------------------------------------------- /ftplugin/python_ropevim.vim: -------------------------------------------------------------------------------- 1 | " Save the opportunity for some other Python interpreters (pypy?) 2 | if has("python3") 3 | command! -buffer -nargs=+ PythonCmd python3 4 | else 5 | finish 6 | endif 7 | 8 | function! LoadRope() 9 | PythonCmd << EOF 10 | import ropevim 11 | from rope_omni import RopeOmniCompleter 12 | EOF 13 | endfunction 14 | 15 | call LoadRope() 16 | 17 | " The code below is an omni-completer for python using rope and ropevim. 18 | " Created by Ryan Wooden (rygwdn@gmail.com) 19 | 20 | function! RopeCompleteFunc(findstart, base) 21 | " A completefunc for python code using rope 22 | if (a:findstart) 23 | PythonCmd ropecompleter = RopeOmniCompleter(vim.eval("a:base")) 24 | PythonCmd vim.command("return %s" % ropecompleter.start) 25 | else 26 | PythonCmd vim.command("return %s" % ropecompleter.complete(vim.eval("a:base"))) 27 | endif 28 | endfunction 29 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | ====== 2 | Done 3 | ====== 4 | 5 | > Public Release 0.8.1 : January 24, 2021 6 | 7 | * Mostly cleanups 8 | * Closes #83. Change :map -> :noremap 9 | * Remove incorrect reference to fugitive from docs 10 | 11 | > Public Release 0.8 : February 3, 2020 12 | 13 | * too many changes since 0.3 to list 14 | * for this release it is switch to Python 3 as the only supported Python 15 | interpreter (for now). Python 2 is gone. 16 | 17 | > Public Release 0.3 : February 5, 2010 18 | 19 | * ropemode is not the part of distribution : February 5, 2010 20 | * implemented `extended complete` feature : January 26, 2010 21 | * improved support of multibyte sources : June 24, 2009 22 | 23 | > Public Release 0.2 : October 3, 2008 24 | 25 | * fixed quickfix error format : August 18, 2008 26 | * ropevim_guess_project variable : June 18, 2008 27 | 28 | > Public Release 0.2c1 : June 12, 2008 29 | 30 | * not showing python traceback for bad inputs : May 23, 2008 31 | * interrupting refactorings : May 22, 2008 32 | 33 | > Public Release 0.1 : May 22, 2008 34 | 35 | * ropveim menu : May 21, 2008 36 | * code-assist in insert mode : May 21, 2008 37 | * using vim quickfix for showing occurrences : May 20, 2008 38 | * better dialogs : May 19, 2008 39 | * implementing basic ropemode commands : May 15, 2008 40 | * project started! : May 12, 2008 41 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | extra_kwargs = {} 2 | try: 3 | from setuptools import setup 4 | extra_kwargs['install_requires'] = ['rope >= 0.9.3', 'ropemode'] 5 | extra_kwargs['zip_safe'] = False 6 | except ImportError: 7 | from distutils.core import setup 8 | 9 | 10 | classifiers = [ 11 | 'Development Status :: 6 - Mature', 12 | 'Programming Language :: Python', 13 | 'Programming Language :: Python :: 3', 14 | 'Programming Language :: Python :: 3.7', 15 | 'Programming Language :: Python :: 3.8', 16 | 'Programming Language :: Python :: 3.9', 17 | 'Programming Language :: Python :: 3.10', 18 | 'Operating System :: OS Independent', 19 | 'Environment :: X11 Applications', 20 | 'Environment :: Win32 (MS Windows)', 21 | # Have not been tested on MacOS 22 | 'Environment :: MacOS X', 23 | 'Intended Audience :: Developers', 24 | 'License :: OSI Approved :: GNU General Public License (GPL)', 25 | 'Natural Language :: English', 26 | 'Topic :: Software Development'] 27 | 28 | 29 | def get_long_description(): 30 | lines = open('README.rst').read().splitlines(False) 31 | end = lines.index('Installation') 32 | return '\n' + '\n'.join(lines[:end]) + '\n' 33 | 34 | setup(name='ropevim', 35 | version='0.8.1', 36 | description='A vim plugin for using rope python refactoring library', 37 | long_description=get_long_description(), 38 | py_modules=['ropevim', 'rope_omni'], 39 | maintainer='Matej Cepl', 40 | maintainer_email='mcepl@cepl.eu', 41 | author='Ali Gholami Rudi', 42 | author_email='aligrudi@users.sourceforge.net', 43 | url='https://github.com/python-rope/ropevim', 44 | license='GNU GPL', 45 | classifiers=classifiers, 46 | requires=['ropemode'], 47 | **extra_kwargs 48 | ) 49 | -------------------------------------------------------------------------------- /rope_omni.py: -------------------------------------------------------------------------------- 1 | import vim 2 | import ropevim 3 | import ropemode.interface 4 | 5 | 6 | class RopeOmniCompleter(object): 7 | """ The class used to complete python code. """ 8 | 9 | def __init__(self, base=""): 10 | self.assist = None 11 | self.start = self.get_start(base) 12 | 13 | def vim_string(self, inp): 14 | """ Creates a vim-friendly string from a group of 15 | dicts, lists and strings. 16 | """ 17 | def conv(obj): 18 | if isinstance(obj, list): 19 | return u'[' + u",".join([conv(o) for o in obj]) + u']' 20 | elif isinstance(obj, dict): 21 | return u'{' + u','.join([ 22 | u"%s:%s" % (conv(key), conv(value)) 23 | for key, value in obj.items()]) + u'}' 24 | else: 25 | return u'"%s"' % str(obj).replace(u'"', u'\\"') 26 | return conv(inp) 27 | 28 | def _get_dict(self, prop): 29 | ci = vim.eval(ropevim._env._extended_completion(prop)) 30 | ci['info'] = prop.get_doc() or " " 31 | return ci 32 | 33 | def complete(self, base): 34 | """ Gets a completion list using a given base string. """ 35 | if vim.eval("complete_check()") != "0": 36 | return [] 37 | 38 | try: 39 | proposals = self.assist._calculate_proposals() 40 | except Exception: # a bunch of rope stuff 41 | return [] 42 | 43 | ps = [self._get_dict(p) for p in proposals] 44 | return self.vim_string(ps) 45 | 46 | def get_start(self, base): 47 | """ Gets the starting column for vim completion. """ 48 | try: 49 | inf = ropevim._interface 50 | self.assist = ropemode.interface._CodeAssist(inf, inf.env) 51 | 52 | base_len = self.assist.offset - self.assist.starting_offset 53 | return int(vim.eval("col('.')")) - base_len - 1 54 | 55 | except Exception: 56 | return -1 57 | -------------------------------------------------------------------------------- /doc/ropevim.txt: -------------------------------------------------------------------------------- 1 | *ropevim.rst* *Ropevim* Rope in VIM 2 | 3 | Note: this documentation is pulled from different project and perhaps we 4 | haven’t find all issues yet. Please, if you see something wrong, file a ticket 5 | to https://github.com/python-rope/ropevim/issues issue tracker. Thank you! 6 | 7 | ============================================================================== 8 | CONTENTS *Rope contents* 9 | 10 | 1.Refactoring Dialog......................|RopeRefactoringDialog| 11 | 2.Finding Files...........................|RopeFindingFiles| 12 | 3.Code Assist.............................|RopeCodeAssist| 13 | 4.Enabling Autoimport.....................|RopeEnablingAutoimport| 14 | 5.Filtering Resources.....................|RopeFilteringResources| 15 | 6.Finding Occurrences.....................|RopeFindOccurrences| 16 | 7.Dialog Batchset Command.................|RopeDialogBatchsetCommand| 17 | 8.Variables...............................|RopeVariables| 18 | 9.Keybindings.............................|RopeKeys| 19 | 20 | 21 | ============================================================================== 22 | 1. Refactoring Dialog ~ 23 | *RopeRefactoringDialog* 24 | 25 | Ropevim refactorings use a special kind of dialog. Depending on the 26 | refactoring, you'll be asked about the essential information a 27 | refactoring needs to know (like the new name in rename refactoring). 28 | 29 | Next you'll see the base prompt of a refactoring dialog that shows 30 | something like "Choose what to do". By entering the name of a 31 | refactoring option you can set its value. After setting each option 32 | you'll be returned back to the base prompt. Finally, you can ask rope 33 | to perform, preview or cancel the refactoring. 34 | 35 | See |RopeKeys| section and try the refactorings yourself. 36 | 37 | 38 | ============================================================================== 39 | 2. Finding Files ~ 40 | *RopeFindingFiles* 41 | *:RopeFindFile* 42 | *:RopeFindFileOtherWindow* 43 | 44 | By using |:RopeFindFile| (" p f" by default), you can search for 45 | files in your project. When you complete the minibuffer you'll see 46 | all files in the project; files are shown as their reversed paths. 47 | For instance ``projectroot/docs/todo.txt`` is shown like 48 | ``todo.txt p 4 f") opens the 50 | file in the other window. 51 | 52 | 53 | ============================================================================== 54 | 3. Code Assist ~ 55 | *RopeCodeAssist* 56 | *:RopeCodeAssist* 57 | *:RopeLuckyAssist* 58 | *'ropevim_vim_completion'* 59 | *'ropevim_extended_complete'* 60 | 61 | |:RopeCodeAssist| command () will let you select from a list 62 | of completions. |:RopeLuckyAssist| command () does not ask 63 | anything; instead, it inserts the first proposal. 64 | 65 | You can tell ropevim to use vim's complete function in insert mode; 66 | Add: > 67 | 68 | let ropevim_vim_completion=1 69 | < 70 | to your '~/.vimrc' file. 71 | 72 | Note: 73 | That when this variable is set, autoimport completions no longer 74 | work since they need to insert an import to the top of the module, 75 | too. 76 | 77 | By default autocomplete feature will use plain list of proposed completion 78 | items. You can enable showing extended information about completion 79 | proposals by setting : > 80 | 81 | let ropevim_extended_complete=1 82 | < 83 | Completion menu list will show the proposed name itself, one letter which 84 | shows where this proposal came from (it can be "L" for locals, "G" for 85 | globals, "B" for builtins, or empty string if such scope definition is not 86 | applicable), a short object type description (such as "func", "param", 87 | "meth" and so forth) and a first line of proposed object's docstring (if it 88 | has one). For function's keyword parameters the last field shows "*" symbol 89 | if this param is required or "= " if it is not. 90 | 91 | 92 | ============================================================================== 93 | 4. Enabling Autoimport ~ 94 | *RopeEnablingAutoimport* 95 | *:RopeAutoImport* 96 | *:RopeGenerateAutoimportCache* 97 | 98 | Rope can propose and automatically import global names in other 99 | modules. Rope maintains a cache of global names for each project. It 100 | updates the cache only when modules are changed; if you want to cache 101 | all your modules at once, use |:RopeGenerateAutoimportCache|. It 102 | will cache all of the modules inside the project plus those whose 103 | names are listed in |'ropevim_autoimport_modules'| list: > 104 | 105 | " add the name of modules you want to autoimport 106 | let g:ropevim_autoimport_modules = ["os", "shutil"] 107 | < 108 | Now if you are in a buffer that contains: > 109 | 110 | rmtree 111 | < 112 | 113 | and you execute |:RopeAutoImport| you'll end up with: > 114 | 115 | from shutil import rmtree 116 | rmtree 117 | < 118 | Also |:RopeCodeAssist| and |:RopeLuckyAssist| propose auto-imported 119 | names by using "name : module" style. Selecting them will import 120 | the module automatically. 121 | 122 | 123 | ============================================================================== 124 | 5. Filtering Resources ~ 125 | *RopeFilteringResources* 126 | 127 | Some refactorings, restructuring and find occurrences take an option 128 | called resources. This option can be used to limit the resources on 129 | which a refactoring should be applied. 130 | 131 | It uses a simple format: each line starts with either '+' or '-'. 132 | Each '+' means include the file (or its children if it's a folder) 133 | that comes after it. '-' has the same meaning for exclusion. So 134 | using: > 135 | 136 | +rope 137 | +ropetest 138 | -rope/contrib 139 | < 140 | means include all python files inside ``rope`` and ``ropetest`` 141 | folders and their subfolder, but those that are in ``rope/contrib``. 142 | Or: > 143 | 144 | -ropetest 145 | -setup.py 146 | < 147 | means include all python files inside the project but ``setup.py`` and 148 | those under ``ropetest`` folder. 149 | 150 | 151 | ============================================================================== 152 | 6. Finding Occurrences ~ 153 | *RopeFindOccurrences* 154 | 155 | The find occurrences command (" f" by default) can be used to 156 | find the occurrences of a python name. If ``unsure`` option is 157 | ``yes``, it will also show unsure occurrences; unsure occurrences are 158 | indicated with a ``?`` mark in the end. 159 | 160 | Note: 161 | That ropevim uses the quickfix feature of vim for 162 | marking occurrence locations. 163 | 164 | 165 | ============================================================================== 166 | 7. Dialog Batchset Command ~ 167 | *RopeDialogBatchsetCommand* 168 | 169 | When you use ropevim dialogs there is a command called ``batchset``. 170 | It can set many options at the same time. After selecting this 171 | command from dialog base prompt, you are asked to enter a string. 172 | 173 | ``batchset`` strings can set the value of configs in two ways. The 174 | single line form is like this: > 175 | 176 | name1 value1 177 | name2 value2 178 | < 179 | 180 | That is the name of config is followed its value. For multi-line 181 | values you can use: > 182 | 183 | name1 184 | line1 185 | line2 186 | 187 | name2 188 | line3 189 | < 190 | Each line of the definition should start with a space or a tab. 191 | Note: 192 | That blank lines before the name of config definitions are ignored. 193 | 194 | ``batchset`` command is useful when performing refactorings with long 195 | configs, like restructurings: > 196 | 197 | pattern ${pycore}.create_module(${project}.root, ${name}) 198 | 199 | goal generate.create_module(${project}, ${name}) 200 | 201 | imports 202 | from rope.contrib import generate 203 | 204 | args 205 | pycore: type=rope.base.pycore.PyCore 206 | project: type=rope.base.project.Project 207 | < 208 | .. ignore the two-space indents 209 | 210 | This is a valid ``batchset`` string for restructurings. 211 | 212 | Just for the sake of completeness, the reverse of the above 213 | restructuring can be: > 214 | 215 | pattern ${create_module}(${project}, ${name}) 216 | 217 | goal ${project}.pycore.create_module(${project}.root, ${name}) 218 | 219 | args 220 | create_module: name=rope.contrib.generate.create_module 221 | project: type=rope.base.project.Project 222 | < 223 | 224 | ============================================================================== 225 | 8. Variables ~ 226 | *RopeVariables* 227 | 228 | *'ropevim_codeassist_maxfixes'* The maximum number of syntax errors 229 | to fix for code assists. 230 | The default value is `1`. 231 | 232 | *'ropevim_local_prefix'* The prefix for ropevim refactorings. 233 | Defaults to ` r`. 234 | 235 | *'ropevim_global_prefix'* The prefix for ropevim project commands 236 | Defaults to ` p`. 237 | 238 | *'ropevim_enable_shortcuts'* Shows whether to bind ropevim shortcuts keys. 239 | Defaults to `1`. 240 | 241 | *'ropevim_guess_project'* If non-zero, ropevim tries to guess and 242 | open the project that contains the file on which 243 | a ropevim command is performed when no project 244 | is already open. 245 | 246 | *'ropevim_enable_autoimport'* Shows whether to enable autoimport. 247 | 248 | *'ropevim_autoimport_modules'* The name of modules whose global names should 249 | be cached. |:RopeGenerateAutoimportCache| reads 250 | this list and fills its cache. 251 | 252 | *'ropevim_autoimport_underlineds'* If set, autoimport will cache names starting 253 | with underlines, too. 254 | 255 | *'ropevim_goto_def_newwin'* If set, ropevim will open a new buffer 256 | for "go to definition" result if the definition 257 | found is located in another file. By default the 258 | file is open in the same buffer. 259 | Values: '' -- same buffer, 'new' -- 260 | horizontally split, 'vnew' -- 261 | vertically split 262 | 263 | *'ropevim_open_files_in_tabs'* If non-zero, ropevim will open files in tabs. 264 | This is disabled by default, and it is now 265 | *deprecated* in favor of 266 | 'ropevim_goto_def_newwin' set to 'tabnew'. 267 | 268 | 269 | 270 | ============================================================================== 271 | 9. Keybinding ~ 272 | *RopeKeys* 273 | 274 | Uses almost the same keybinding as ropemacs. 275 | Note: 276 | That global commands have a ` p` prefix and local commands 277 | have a `` r`` prefix. 278 | You can change that (see |RopeVariables| section). 279 | 280 | 281 | ================ ============================ 282 | Key Command 283 | ================ ============================ 284 | C-x p o |:RopeOpenProject| 285 | C-x p k |:RopeCloseProject| 286 | C-x p f |:RopeFindFile| 287 | C-x p 4 f |:RopeFindFileOtherWindow| 288 | C-x p u |:RopeUndo| 289 | C-x p r |:RopeRedo| 290 | C-x p c |:RopeProjectConfig| 291 | C-x p n [mpfd] |:RopeCreate|(Module|Package|File|Directory) 292 | |:RopeWriteProject| 293 | 294 | C-c r r |:RopeRename| 295 | C-c r l |:RopeExtractVariable| 296 | C-c r m |:RopeExtractMethod| 297 | C-c r i |:RopeInline| 298 | C-c r v |:RopeMove| 299 | C-c r x |:RopeRestructure| 300 | C-c r u |:RopeUseFunction| 301 | C-c r f |:RopeIntroduceFactory| 302 | C-c r s |:RopeChangeSignature| 303 | C-c r 1 r |:RopeRenameCurrentModule| 304 | C-c r 1 v |:RopeMoveCurrentModule| 305 | C-c r 1 p |:RopeModuleToPackage| 306 | 307 | C-c r o |:RopeOrganizeImports| 308 | C-c r n [vfcmp] |:RopeGenerate|(Variable|Function|Class|Module|Package) 309 | 310 | C-c r a / |:RopeCodeAssist| 311 | C-c r a g |:RopeGotoDefinition| 312 | C-c r a d |:RopeShowDoc| 313 | C-c r a f |:RopeFindOccurrences| 314 | C-c r a ? |:RopeLuckyAssist| 315 | C-c r a j |:RopeJumpToGlobal| 316 | C-c r a c |:RopeShowCalltip| 317 | |:RopeAnalyzeModule| 318 | 319 | |:RopeAutoImport| 320 | |:RopeGenerateAutoimportCache| 321 | =============== ============================ 322 | 323 | 324 | ============================================================================== 325 | 10. Shortcuts ~ 326 | *RopeShortcuts* 327 | 328 | Some commands are used very frequently; specially the commands in 329 | code-assist group. You can define your own shortcuts like this: > 330 | 331 | :noremap g :call RopeGotoDefinition() 332 | 333 | < 334 | 335 | ================ ============================ 336 | Key Command 337 | ================ ============================ 338 | |:RopeCodeAssist| 339 | |:RopeLuckyAssist| 340 | g |:RopeGotoDefinition| 341 | d |:RopeShowDoc| 342 | f |:RopeFindOccurrences| 343 | ================ ============================ 344 | 345 | ------------------------------------------------------------------------------ 346 | 347 | vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl: 348 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | ropevim, rope in vim 3 | ====================== 4 | 5 | .. csv-table:: 6 | 7 | "❗If you are using ropevim, consider using `pylsp-rope`_ in Vim. Also see, `setup guide for pylsp-rope in Vim`_." 8 | 9 | .. _pylsp-rope: https://github.com/python-rope/pylsp-rope 10 | .. _setup guide for pylsp-rope in Vim: https://github.com/python-rope/rope/wiki/Rope-in-Vim-or-Neovim 11 | 12 | Overview 13 | ======== 14 | 15 | Ropevim is a vim mode that uses rope_ library to provide features like 16 | python refactorings and code-assists. You should install rope_ 17 | library before using ropevim. 18 | 19 | .. _rope: https://github.com/python-rope/rope 20 | 21 | 22 | New Features 23 | ============ 24 | 25 | * works only with python3 ATM (python2 is not supported anymore) 26 | * improved support of multibyte sources 27 | * implemented `extended complete` feature (disabled by default) 28 | * ropemode is not part of the distribution now 29 | 30 | 31 | Installation 32 | ============ 33 | 34 | Using Minpac 35 | ------------ 36 | 37 | .. code:: vim 38 | 39 | filetype plugin on 40 | call minpac#add('python-rope/ropevim') 41 | 42 | .. code:: bash 43 | 44 | $ pip install ropevim 45 | 46 | If you're using **Neovim**, you will also need to 47 | `install neovim python providers`_ using ``pip install pynvim``. 48 | 49 | Using Packer 50 | -------------- 51 | 52 | .. code:: lua 53 | 54 | use({ 55 | 'python-rope/ropevim', 56 | ft = "python" 57 | }) 58 | 59 | .. code:: bash 60 | 61 | $ pip install ropevim 62 | 63 | If you're using **Neovim**, you will also need to 64 | `install neovim python providers`_ using ``pip install pynvim``. 65 | 66 | Using Vim-Plug 67 | -------------- 68 | 69 | .. code:: vim 70 | 71 | filetype plugin on 72 | Plug 'python-rope/ropevim' 73 | 74 | .. code:: bash 75 | 76 | $ pip install ropevim 77 | 78 | If you're using **Neovim**, you will also need to 79 | `install neovim python providers`_ using ``pip install pynvim``. 80 | 81 | Using Vundle 82 | ------------ 83 | 84 | .. code:: vim 85 | 86 | filetype plugin on 87 | Plugin 'python-rope/ropevim' 88 | 89 | .. code:: bash 90 | 91 | $ pip install ropevim 92 | 93 | If you're using **Neovim**, you will also need to 94 | `install neovim python providers`_ using ``pip install pynvim``. 95 | 96 | Basic Installation 97 | ------------------ 98 | 99 | A simple way to download and install, which does just uses native 100 | packaging system (requires Vim 8): 101 | 102 | .. code:: bash 103 | 104 | $ mkdir -p ~/.vim/pack/plugins/start/ 105 | $ git clone https://github.com/python-rope/ropevim.git ~/.vim/pack/plugins/start/ropevim 106 | $ pip install ropevim 107 | 108 | Or on older Vim: 109 | 110 | .. code:: bash 111 | 112 | $ sudo pip3 install ropevim 113 | $ wget -P ~/.vim/ https://raw.githubusercontent.com/python-rope/ropevim/master/ftplugin/python_ropevim.vim 114 | $ echo "source ~/.vim/python_ropevim.vim" >> ~/.vimrc 115 | $ pip install ropevim 116 | 117 | (rope, ropemode and ropevim are pure python libraries which do 118 | not need to talk to vim directly, they are installed by pip into 119 | the usual Python path. Only python_ropevim.vim needs to be seen 120 | by vim, and it handles loading the pure python modules.) 121 | 122 | If you're using **Neovim**, you will also need to 123 | `install neovim python providers`_ using ``pip install pynvim``. 124 | 125 | Installation with pathogen 126 | -------------------------- 127 | 128 | If using pathogen.vim, and then simply copy and paste: 129 | 130 | .. code:: bash 131 | 132 | $ cd ~/.vim/bundle 133 | $ git clone https://github.com/python-rope/ropevim.git 134 | $ pip install ropevim 135 | 136 | (or even add this repo as a submodule to ``~/.vim/bundle`` git repo if 137 | you have setup ``~/.vim/bundle`` in this way and you should) 138 | 139 | Once help tags have been generated, you can view the manual with ``:help 140 | ropevim.`` 141 | 142 | If you're using **Neovim**, you will also need to 143 | `install neovim python providers`_ using ``pip install pynvim``. 144 | 145 | Installation of repo version 146 | ---------------------------- 147 | 148 | For using the repository version of rope, see ``docs/ropevim.rst`` (or 149 | vim command ``:help ropevim``) 150 | 151 | .. _install neovim python providers: https://neovim.io/doc/user/provider.html 152 | 153 | Getting Started 154 | =============== 155 | 156 | Refactoring Dialog 157 | ------------------ 158 | 159 | Ropevim refactorings use a special kind of dialog. Depending on the 160 | refactoring, you'll be asked about the essential information a 161 | refactoring needs to know (like the new name in rename refactoring). 162 | 163 | Next you'll see the base prompt of a refactoring dialog that shows 164 | something like "Choose what to do". By entering the name of a 165 | refactoring option you can set its value. After setting each option 166 | you'll be returned back to the base prompt. Finally, you can ask rope 167 | to perform, preview or cancel the refactoring. 168 | 169 | See keybinding_ section and try the refactorings yourself. 170 | 171 | 172 | Finding Files 173 | ------------- 174 | 175 | By using ``RopeFindFile`` (``C-x p f`` by default), you can search for 176 | files in your project. When you complete the minibuffer you'll see 177 | all files in the project; files are shown as their reversed paths. 178 | For instance ``projectroot/docs/todo.txt`` is shown like 179 | ``todo.txt" if it is not. 214 | 215 | Note that you'll need rope r1558:0d76aa9d0614 or later and ropemode 216 | r35:bd77ca42b04d or later for extended complete feature to work. 217 | 218 | 219 | Enabling Autoimport 220 | ------------------- 221 | 222 | Rope can propose and automatically import global names in other 223 | modules. Rope maintains a cache of global names for each project. It 224 | updates the cache only when modules are changed; if you want to cache 225 | all your modules at once, use ``RopeGenerateAutoimportCache``. It 226 | will cache all of the modules inside the project plus those whose 227 | names are listed in ``ropevim_autoimport_modules`` list:: 228 | 229 | # add the name of modules you want to autoimport 230 | let g:ropevim_autoimport_modules = ["os", "shutil"] 231 | 232 | Now if you are in a buffer that contains:: 233 | 234 | rmtree 235 | 236 | and you execute ``RopeAutoImport`` you'll end up with:: 237 | 238 | from shutil import rmtree 239 | rmtree 240 | 241 | Also ``RopeCodeAssist`` and ``RopeLuckyAssist`` propose auto-imported 242 | names by using ``name : module`` style. Selecting them will import 243 | the module automatically. 244 | 245 | 246 | Filtering Resources 247 | ------------------- 248 | 249 | Some refactorings, restructuring and find occurrences take an option 250 | called resources. This option can be used to limit the resources on 251 | which a refactoring should be applied. 252 | 253 | It uses a simple format: each line starts with either '+' or '-'. 254 | Each '+' means include the file (or its children if it's a folder) 255 | that comes after it. '-' has the same meaning for exclusion. So 256 | using:: 257 | 258 | +rope 259 | +ropetest 260 | -rope/contrib 261 | 262 | means include all python files inside ``rope`` and ``ropetest`` 263 | folders and their subfolder, but those that are in ``rope/contrib``. 264 | Or:: 265 | 266 | -ropetest 267 | -setup.py 268 | 269 | means include all python files inside the project but ``setup.py`` and 270 | those under ``ropetest`` folder. 271 | 272 | 273 | Finding Occurrences 274 | ------------------- 275 | 276 | The find occurrences command (``C-c f`` by default) can be used to 277 | find the occurrences of a python name. If ``unsure`` option is 278 | ``yes``, it will also show unsure occurrences; unsure occurrences are 279 | indicated with a ``?`` mark in the end. Note that ropevim uses the 280 | quickfix feature of vim for marking occurrence locations. 281 | 282 | 283 | Dialog ``batchset`` Command 284 | --------------------------- 285 | 286 | When you use ropevim dialogs there is a command called ``batchset``. 287 | It can set many options at the same time. After selecting this 288 | command from dialog base prompt, you are asked to enter a string. 289 | 290 | ``batchset`` strings can set the value of configs in two ways. The 291 | single line form is like this:: 292 | 293 | name1 value1 294 | name2 value2 295 | 296 | That is the name of config is followed its value. For multi-line 297 | values you can use:: 298 | 299 | name1 300 | line1 301 | line2 302 | 303 | name2 304 | line3 305 | 306 | Each line of the definition should start with a space or a tab. Note 307 | that blank lines before the name of config definitions are ignored. 308 | 309 | ``batchset`` command is useful when performing refactorings with long 310 | configs, like restructurings:: 311 | 312 | pattern ${pycore}.create_module(${project}.root, ${name}) 313 | 314 | goal generate.create_module(${project}, ${name}) 315 | 316 | imports 317 | from rope.contrib import generate 318 | 319 | args 320 | pycore: type=rope.base.pycore.PyCore 321 | project: type=rope.base.project.Project 322 | 323 | .. ignore the two-space indents 324 | 325 | This is a valid ``batchset`` string for restructurings. 326 | 327 | Just for the sake of completeness, the reverse of the above 328 | restructuring can be:: 329 | 330 | pattern ${create_module}(${project}, ${name}) 331 | 332 | goal ${project}.pycore.create_module(${project}.root, ${name}) 333 | 334 | args 335 | create_module: name=rope.contrib.generate.create_module 336 | project: type=rope.base.project.Project 337 | 338 | 339 | Variables 340 | ========= 341 | 342 | * ``ropevim_codeassist_maxfixes``: The maximum number of syntax errors 343 | to fix for code assists. The default value is ``1``. 344 | * ``ropevim_local_prefix``: The prefix for ropevim refactorings. 345 | Defaults to ``C-c r``. 346 | * ``ropevim_global_prefix``: The prefix for ropevim project commands 347 | Defaults to ``C-x p``. 348 | * ``ropevim_enable_shortcuts``: Shows whether to bind ropevim 349 | shortcuts keys. Defaults to ``1``. 350 | * ``ropevim_guess_project``: If non-zero, ropevim tries to guess and 351 | open the project that contains the file on which a ropevim command 352 | is performed when no project is already open. 353 | 354 | * ``ropevim_enable_autoimport``: Shows whether to enable autoimport. 355 | * ``ropevim_autoimport_modules``: The name of modules whose global 356 | names should be cached. `RopeGenerateAutoimportCache` reads this 357 | list and fills its cache. 358 | * ``ropevim_autoimport_underlineds``: If set, autoimport will cache 359 | names starting with underlines, too. 360 | 361 | * ``ropevim_goto_def_newwin``: If set, ropevim will open a new buffer 362 | for "go to definition" result if the definition found is located 363 | in another file. By default the file is open in the same buffer. 364 | 365 | * ``g:ropevim_open_files_in_tabs``: If non-zero, ropevim will open files 366 | in tabs. This is disabled by default, and it is now *deprecated* in 367 | favor of ``g:ropevim_goto_def_newwin`` set to ``"tabnew"``. 368 | 369 | Keybinding 370 | ========== 371 | 372 | Uses almost the same keybinding as ropemacs. Note that global 373 | commands have a ``C-x p`` prefix and local commands have a ``C-c r`` 374 | prefix. You can change that (see variables_ section). 375 | 376 | +-----------------+-------------------------------------------------------+ 377 | |Key | Command | 378 | +=================+=======================================================+ 379 | |C-x p o | RopeOpenProject | 380 | +-----------------+-------------------------------------------------------+ 381 | |C-x p k | RopeCloseProject | 382 | +-----------------+-------------------------------------------------------+ 383 | |C-x p f | RopeFindFile | 384 | +-----------------+-------------------------------------------------------+ 385 | |C-x p 4 f | RopeFindFileOtherWindow | 386 | +-----------------+-------------------------------------------------------+ 387 | |C-x p u | RopeUndo | 388 | +-----------------+-------------------------------------------------------+ 389 | |C-x p r | RopeRedo | 390 | +-----------------+-------------------------------------------------------+ 391 | |C-x p c | RopeProjectConfig | 392 | +-----------------+-------------------------------------------------------+ 393 | |C-x p n [mpfd] | RopeCreate(Module|Package|File|Directory) | 394 | +-----------------+-------------------------------------------------------+ 395 | | | RopeWriteProject | 396 | +-----------------+-------------------------------------------------------+ 397 | | | | 398 | +-----------------+-------------------------------------------------------+ 399 | |C-c r r | RopeRename | 400 | +-----------------+-------------------------------------------------------+ 401 | |C-c r l | RopeExtractVariable | 402 | +-----------------+-------------------------------------------------------+ 403 | |C-c r m | RopeExtractMethod | 404 | +-----------------+-------------------------------------------------------+ 405 | |C-c r i | RopeInline | 406 | +-----------------+-------------------------------------------------------+ 407 | |C-c r v | RopeMove | 408 | +-----------------+-------------------------------------------------------+ 409 | |C-c r x | RopeRestructure | 410 | +-----------------+-------------------------------------------------------+ 411 | |C-c r u | RopeUseFunction | 412 | +-----------------+-------------------------------------------------------+ 413 | |C-c r f | RopeIntroduceFactory | 414 | +-----------------+-------------------------------------------------------+ 415 | |C-c r s | RopeChangeSignature | 416 | +-----------------+-------------------------------------------------------+ 417 | |C-c r 1 r | RopeRenameCurrentModule | 418 | +-----------------+-------------------------------------------------------+ 419 | |C-c r 1 v | RopeMoveCurrentModule | 420 | +-----------------+-------------------------------------------------------+ 421 | |C-c r 1 p | RopeModuleToPackage | 422 | +-----------------+-------------------------------------------------------+ 423 | | | | 424 | +-----------------+-------------------------------------------------------+ 425 | |C-c r o | RopeOrganizeImports | 426 | +-----------------+-------------------------------------------------------+ 427 | |C-c r n [vfcmp] | RopeGenerate(Variable|Function|Class|Module|Package) | 428 | +-----------------+-------------------------------------------------------+ 429 | | | | 430 | +-----------------+-------------------------------------------------------+ 431 | |C-c r a / | RopeCodeAssist | 432 | +-----------------+-------------------------------------------------------+ 433 | |C-c r a g | RopeGotoDefinition | 434 | +-----------------+-------------------------------------------------------+ 435 | |C-c r a d | RopeShowDoc | 436 | +-----------------+-------------------------------------------------------+ 437 | |C-c r a f | RopeFindOccurrences | 438 | +-----------------+-------------------------------------------------------+ 439 | |C-c r a ? | RopeLuckyAssist | 440 | +-----------------+-------------------------------------------------------+ 441 | |C-c r a j | RopeJumpToGlobal | 442 | +-----------------+-------------------------------------------------------+ 443 | |C-c r a c | RopeShowCalltip | 444 | +-----------------+-------------------------------------------------------+ 445 | | | RopeAnalyzeModule | 446 | +-----------------+-------------------------------------------------------+ 447 | | | RopeAutoImport | 448 | +-----------------+-------------------------------------------------------+ 449 | | | RopeGenerateAutoimportCache | 450 | +-----------------+-------------------------------------------------------+ 451 | 452 | 453 | Shortcuts 454 | --------- 455 | 456 | Some commands are used very frequently; specially the commands in 457 | code-assist group. You can define your own shortcuts like this:: 458 | 459 | :noremap g :call RopeGotoDefinition() 460 | 461 | Ropevim itself comes with a few shortcuts. These shortcuts will be 462 | used only when ``ropevim_enable_shortcuts`` is set. 463 | 464 | ================ ============================ 465 | Key Command 466 | ================ ============================ 467 | M-/ RopeCodeAssist 468 | M-? RopeLuckyAssist 469 | C-c g RopeGotoDefinition 470 | C-c d RopeShowDoc 471 | C-c f RopeFindOccurrences 472 | ================ ============================ 473 | 474 | 475 | Support for Omni completion 476 | --------------------------- 477 | 478 | You can enable using Rope as providing for Omni completion by setting 479 | omnifunc variable to ``RopeCompleteFunc``. E.g., by putting something 480 | like this in your ``~/.vimrc``:: 481 | 482 | autocmd FileType python setlocal omnifunc=RopeCompleteFunc 483 | 484 | 485 | Contributing 486 | ============ 487 | 488 | Send your bug reports, feature requests and patches to `ropevim Github 489 | Issue Tracker`_ or `rope Github Discussions`_. 490 | 491 | .. _`ropevim Github Issue Tracker`: https://github.com/python-rope/ropevim/issues 492 | .. _`rope Github Discussions`: https://github.com/python-rope/rope/discussions 493 | 494 | 495 | License 496 | ======= 497 | 498 | This program is under the terms of GPL (GNU General Public License). 499 | Have a look at ``COPYING`` file for more information. 500 | -------------------------------------------------------------------------------- /ropevim.py: -------------------------------------------------------------------------------- 1 | """ropevim, a vim mode for using rope refactoring library""" 2 | from __future__ import print_function 3 | 4 | import os 5 | import re 6 | import sys 7 | import tempfile 8 | 9 | import ropemode.decorators 10 | import ropemode.environment 11 | import ropemode.interface 12 | 13 | import vim 14 | 15 | # Save the opportunity for some other Python interpreters (pypy?) 16 | python_cmd = 'python3' 17 | 18 | 19 | class VimUtils(ropemode.environment.Environment): 20 | 21 | def ask(self, prompt, default=None, starting=None): 22 | if starting is None: 23 | starting = '' 24 | if default is not None: 25 | prompt = prompt + ('[%s] ' % default) 26 | result = call('input("%s", "%s")' % (prompt, starting)) 27 | if default is not None and result == '': 28 | return default 29 | return result 30 | 31 | def ask_values(self, prompt, values, default=None, 32 | starting=None, show_values=None): 33 | if show_values or (show_values is None and len(values) < 14): 34 | self._print_values(values) 35 | if default is not None: 36 | prompt = prompt + ('[%s] ' % default) 37 | starting = starting or '' 38 | _completer.values = values 39 | answer = call('input("%s", "%s", "customlist,RopeValueCompleter")' % 40 | (prompt, starting)) 41 | if answer is None: 42 | if 'cancel' in values: 43 | return 'cancel' 44 | return 45 | if default is not None and not answer: 46 | return default 47 | if answer.isdigit() and 0 <= int(answer) < len(values): 48 | return values[int(answer)] 49 | return answer 50 | 51 | def _print_values(self, values): 52 | numbered = [] 53 | for index, value in enumerate(values): 54 | numbered.append('%s. %s' % (index, str(value))) 55 | echo('\n'.join(numbered) + '\n') 56 | 57 | def ask_directory(self, prompt, default=None, starting=None): 58 | return call('input("%s", ".", "dir")' % prompt) 59 | 60 | def ask_completion(self, prompt, values, starting=None): 61 | if self.get('vim_completion') and 'i' in call('mode()'): 62 | if not self.get('extended_complete', False): 63 | proposals = u','.join(u"'%s'" % self._completion_text(proposal) 64 | for proposal in values) 65 | else: 66 | proposals = u','.join(self._extended_completion(proposal) 67 | for proposal in values) 68 | 69 | col = int(call('col(".")')) 70 | if starting: 71 | col -= len(starting) 72 | command = u'call complete(%s, [%s])' % (col, proposals) 73 | vim.command(command.encode(self._get_encoding())) 74 | return None 75 | return self.ask_values(prompt, values, starting=starting, 76 | show_values=False) 77 | 78 | def message(self, message): 79 | echo(message) 80 | 81 | def yes_or_no(self, prompt): 82 | return self.ask_values(prompt, ['yes', 'y', 'no', 'n']).lower() \ 83 | in ['yes', 'y'] 84 | 85 | def y_or_n(self, prompt): 86 | return self.yes_or_no(prompt) 87 | 88 | def get(self, name, default=None): 89 | vimname = 'g:ropevim_%s' % name 90 | if str(vim.eval('exists("%s")' % vimname)) == '0': 91 | return default 92 | result = vim.eval(vimname) 93 | if isinstance(result, str) and result.isdigit(): 94 | return int(result) 95 | return result 96 | 97 | def get_offset(self): 98 | result = self._position_to_offset(*self.cursor) 99 | return result 100 | 101 | def _get_encoding(self): 102 | return vim.eval('&encoding') 103 | 104 | def _encode_line(self, line): 105 | return line.encode(self._get_encoding()) 106 | 107 | def _decode_line(self, line): 108 | if hasattr(line, 'decode'): 109 | return line.decode(self._get_encoding()) 110 | else: 111 | return line 112 | 113 | def _position_to_offset(self, lineno, colno): 114 | result = min(colno, len(self.buffer[lineno - 1]) + 1) 115 | for line in self.buffer[:lineno-1]: 116 | line = self._decode_line(line) 117 | result += len(line) + 1 118 | return result 119 | 120 | def get_text(self): 121 | return self._decode_line('\n'.join(self.buffer)) + u'\n' 122 | 123 | def get_region(self): 124 | beg_mark = self.buffer.mark('<') 125 | end_mark = self.buffer.mark('>') 126 | if beg_mark and end_mark: 127 | start = self._position_to_offset(*beg_mark) 128 | end = self._position_to_offset(*end_mark) + 1 129 | return start, end 130 | else: 131 | return 0, 0 132 | 133 | @property 134 | def buffer(self): 135 | return vim.current.buffer 136 | 137 | def _get_cursor(self): 138 | lineno, col = vim.current.window.cursor 139 | line = self._decode_line(vim.current.line[:col]) 140 | col = len(line) 141 | return (lineno, col) 142 | 143 | def _set_cursor(self, cursor): 144 | lineno, col = cursor 145 | line = self._decode_line(vim.current.line) 146 | line = self._encode_line(line[:col]) 147 | col = len(line) 148 | vim.current.window.cursor = (lineno, col) 149 | 150 | cursor = property(_get_cursor, _set_cursor) 151 | 152 | def filename(self): 153 | return self.buffer.name 154 | 155 | def is_modified(self): 156 | return vim.eval('&modified') 157 | 158 | def goto_line(self, lineno): 159 | self.cursor = (lineno, 0) 160 | 161 | def insert_line(self, line, lineno): 162 | self.buffer[lineno - 1:lineno - 1] = [line] 163 | 164 | def insert(self, text): 165 | lineno, colno = self.cursor 166 | line = self.buffer[lineno - 1] 167 | self.buffer[lineno - 1] = line[:colno] + text + line[colno:] 168 | self.cursor = (lineno, colno + len(text)) 169 | 170 | def delete(self, start, end): 171 | lineno1, colno1 = self._offset_to_position(start - 1) 172 | lineno2, colno2 = self._offset_to_position(end - 1) 173 | lineno, colno = self.cursor 174 | if lineno1 == lineno2: 175 | line = self.buffer[lineno1 - 1] 176 | self.buffer[lineno1 - 1] = line[:colno1] + line[colno2:] 177 | if lineno == lineno1 and colno >= colno1: 178 | diff = colno2 - colno1 179 | self.cursor = (lineno, max(0, colno - diff)) 180 | 181 | def _offset_to_position(self, offset): 182 | text = self.get_text() 183 | lineno = text.count('\n', 0, offset) + 1 184 | try: 185 | colno = offset - text.rindex('\n', 0, offset) - 1 186 | except ValueError: 187 | colno = offset 188 | return lineno, colno 189 | 190 | def filenames(self): 191 | result = [] 192 | for buffer in vim.buffers: 193 | if buffer.name: 194 | result.append(buffer.name) 195 | return result 196 | 197 | def save_files(self, filenames): 198 | vim.command('wall') 199 | 200 | def reload_files(self, filenames, moves={}): 201 | initial = self.filename() 202 | for filename in filenames: 203 | self.find_file(moves.get(filename, filename), force=True) 204 | if initial: 205 | self.find_file(initial) 206 | 207 | def _open_file(self, filename, new=False): 208 | # TODO deprecated ... for now it is just an equivalent to 209 | # g:ropevim_goto_def_newwin == 'tabnew' 210 | if int(vim.eval('g:ropevim_open_files_in_tabs')): 211 | new = 'tabnew' 212 | 213 | if new in ('new', 'vnew', 'tabnew'): 214 | vim.command(new) 215 | vim.command('edit! %s' % filename) 216 | 217 | @staticmethod 218 | def _samefile(file1, file2): 219 | # Breaks under Jython and other platforms, but I guess it should 220 | # be enough. 221 | if os.name == "posix" and os.path.exists(file1) and os.path.exists(file2): 222 | return os.path.samefile(file1, file2) 223 | else: 224 | # it is a way more complicated, the following does not deal 225 | # with hard links on Windows 226 | # for better discussion see 227 | # http://stackoverflow.com/q/8892831/164233 228 | return os.path.normcase(os.path.normpath(file1)) == \ 229 | os.path.normcase(os.path.normpath(file2)) 230 | 231 | def find_file(self, filename, readonly=False, other=False, force=False): 232 | """ 233 | Originally coming from Emacs, so the definition is the same as 234 | the Emacs Lisp function find-file ... " 235 | 236 | (find-file FILENAME &optional WILDCARDS) 237 | 238 | Edit file FILENAME. 239 | Switch to a buffer visiting file FILENAME, 240 | creating one if none already exists. 241 | """ 242 | if filename not in self.filenames() or force: 243 | self._open_file(filename, new=other) 244 | else: 245 | found = False 246 | for tab in vim.tabpages: 247 | for win in tab.windows: 248 | if self._samefile(win.buffer.name, filename): 249 | vim.current.tabpage = tab 250 | vim.current.window = win 251 | vim.current.buffer = win.buffer 252 | found = True 253 | break 254 | if not found: 255 | self._open_file(filename, new=other) 256 | 257 | if readonly: 258 | vim.command('set nomodifiable') 259 | 260 | def create_progress(self, name): 261 | return VimProgress(name) 262 | 263 | def current_word(self): 264 | return vim.eval('expand("")') 265 | 266 | def push_mark(self): 267 | vim.command('mark `') 268 | 269 | def prefix_value(self, prefix): 270 | return prefix 271 | 272 | def show_occurrences(self, locations): 273 | self._quickfixdefs(locations) 274 | 275 | def _quickfixdefs(self, locations): 276 | filename = os.path.join(tempfile.gettempdir(), tempfile.mktemp()) 277 | try: 278 | self._writedefs(locations, filename) 279 | vim.command('let old_errorfile = &errorfile') 280 | vim.command('let old_errorformat = &errorformat') 281 | vim.command('set errorformat=%f:%l:\ %m') 282 | vim.command('cfile ' + filename) 283 | vim.command('let &errorformat = old_errorformat') 284 | vim.command('let &errorfile = old_errorfile') 285 | finally: 286 | os.remove(filename) 287 | 288 | def _writedefs(self, locations, filename): 289 | tofile = open(filename, 'w') 290 | try: 291 | for location in locations: 292 | # FIXME seems suspicious lineno = location.lineno 293 | err = '%s:%d: %s %s\n' % ( 294 | os.path.relpath(location.filename), location.lineno, 295 | location.note, location.line_content) 296 | echo(err) 297 | tofile.write(err) 298 | finally: 299 | tofile.close() 300 | 301 | def show_doc(self, docs, altview=False): 302 | if docs: 303 | echo(docs) 304 | 305 | def preview_changes(self, diffs): 306 | echo(diffs) 307 | return self.y_or_n('Do the changes? ') 308 | 309 | def local_command(self, name, callback, key=None, prefix=False): 310 | self._add_command(name, callback, key, prefix, 311 | prekey=self.get('local_prefix')) 312 | 313 | def global_command(self, name, callback, key=None, prefix=False): 314 | self._add_command(name, callback, key, prefix, 315 | prekey=self.get('global_prefix')) 316 | 317 | def add_hook(self, name, callback, hook): 318 | mapping = {'before_save': 'FileWritePre,BufWritePre', 319 | 'after_save': 'FileWritePost,BufWritePost', 320 | 'exit': 'VimLeave'} 321 | self._add_function(name, callback) 322 | vim.command('autocmd %s *.py call %s()' % 323 | (mapping[hook], _vim_name(name))) 324 | 325 | def _add_command(self, name, callback, key, prefix, prekey): 326 | self._add_function(name, callback, prefix) 327 | vim.command('command! -range %s call %s()' % 328 | (_vim_name(name), _vim_name(name))) 329 | if key is not None: 330 | key = prekey + key.replace(' ', '') 331 | vim.command('noremap %s :call %s()' % (key, _vim_name(name))) 332 | 333 | def _add_function(self, name, callback, prefix=False): 334 | globals()[name] = callback 335 | arg = 'None' if prefix else '' 336 | vim.command('function! %s() range\n' % _vim_name(name) + 337 | '%s ropevim.%s(%s)\n' % (python_cmd, name, arg) + 338 | 'endfunction\n') 339 | 340 | def _completion_data(self, proposal): 341 | return proposal 342 | 343 | _docstring_re = re.compile('^[\s\t\n]*([^\n]*)') 344 | 345 | def _extended_completion(self, proposal): 346 | # we are using extended complete and return dicts instead of strings. 347 | # `ci` means "completion item". see `:help complete-items` 348 | ci = {'word': proposal.name} 349 | 350 | scope = proposal.scope[0].upper() 351 | type_ = proposal.type 352 | info = None 353 | 354 | if proposal.scope == 'parameter_keyword': 355 | scope = ' ' 356 | type_ = 'param' 357 | if not hasattr(proposal, 'get_default'): 358 | # old version of rope 359 | pass 360 | else: 361 | default = proposal.get_default() 362 | if default is None: 363 | info = '*' 364 | else: 365 | info = '= %s' % default 366 | 367 | elif proposal.scope == 'keyword': 368 | scope = ' ' 369 | type_ = 'keywd' 370 | 371 | elif proposal.scope == 'attribute': 372 | scope = 'M' 373 | if proposal.type == 'function': 374 | type_ = 'meth' 375 | elif proposal.type == 'instance': 376 | type_ = 'prop' 377 | 378 | elif proposal.type == 'function': 379 | type_ = 'func' 380 | 381 | elif proposal.type == 'instance': 382 | type_ = 'inst' 383 | 384 | elif proposal.type == 'module': 385 | type_ = 'mod' 386 | 387 | if info is None: 388 | obj_doc = proposal.get_doc() 389 | if obj_doc: 390 | info = self._docstring_re.match(obj_doc).group(1) 391 | else: 392 | info = '' 393 | 394 | if type_ is None: 395 | type_ = ' ' 396 | else: 397 | type_ = type_.ljust(5)[:5] 398 | ci['menu'] = ' '.join((scope, type_, info)) 399 | ret = u'{%s}' % \ 400 | u','.join(u'"%s":"%s"' % 401 | (key, value.replace('"', '\\"')) 402 | for (key, value) in ci.items()) 403 | return ret 404 | 405 | 406 | def _vim_name(name): 407 | tokens = name.split('_') 408 | newtokens = ['Rope'] + [token.title() for token in tokens] 409 | return ''.join(newtokens) 410 | 411 | 412 | class VimProgress(object): 413 | 414 | def __init__(self, name): 415 | self.name = name 416 | self.last = 0 417 | echo('%s ... ' % self.name) 418 | 419 | def update(self, percent): 420 | try: 421 | vim.eval('getchar(0)') 422 | except vim.error: 423 | raise KeyboardInterrupt('Task %s was interrupted!' % self.name) 424 | if percent > self.last + 4: 425 | echo('%s ... %s%%%%' % (self.name, percent)) 426 | self.last = percent 427 | 428 | def done(self): 429 | echo('%s ... done' % self.name) 430 | 431 | 432 | def echo(message): 433 | print(message) 434 | 435 | 436 | def call(command): 437 | return vim.eval(command) 438 | 439 | 440 | class _ValueCompleter(object): 441 | 442 | def __init__(self): 443 | self.values = [] 444 | vim.command('%s import vim' % python_cmd) 445 | vim.command('function! RopeValueCompleter(A, L, P)\n' 446 | '%s args = [vim.eval("a:" + p) for p in "ALP"]\n' 447 | '%s ropevim._completer(*args)\n' 448 | 'return s:completions\n' 449 | 'endfunction\n' % (python_cmd, python_cmd)) 450 | 451 | def __call__(self, arg_lead, cmd_line, cursor_pos): 452 | # don't know if self.values can be empty but better safe then sorry 453 | if self.values: 454 | if not isinstance(self.values[0], basestring): 455 | result = [proposal.name for proposal in self.values 456 | if proposal.name.startswith(arg_lead)] 457 | else: 458 | result = [proposal for proposal in self.values 459 | if proposal.startswith(arg_lead)] 460 | vim.command('let s:completions = %s' % result) 461 | 462 | 463 | variables = {'ropevim_enable_autoimport': 1, 464 | 'ropevim_autoimport_underlineds': 0, 465 | 'ropevim_codeassist_maxfixes': 1, 466 | 'ropevim_enable_shortcuts': 1, 467 | 'ropevim_open_files_in_tabs': 0, 468 | 'ropevim_autoimport_modules': '[]', 469 | 'ropevim_confirm_saving': 0, 470 | 'ropevim_local_prefix': '"r"', 471 | 'ropevim_global_prefix': '"p"', 472 | 'ropevim_vim_completion': 0, 473 | 'ropevim_guess_project': 0} 474 | 475 | shortcuts = {'code_assist': '', 476 | 'lucky_assist': '', 477 | 'goto_definition': 'g', 478 | 'show_doc': 'd', 479 | 'find_occurrences': 'f'} 480 | 481 | insert_shortcuts = {'code_assist': '', 482 | 'lucky_assist': ''} 483 | 484 | menu_structure = ( 485 | 'open_project', 486 | 'close_project', 487 | 'find_file', 488 | 'undo', 489 | 'redo', 490 | None, # separator 491 | 'rename', 492 | 'extract_variable', 493 | 'extract_method', 494 | 'inline', 495 | 'move', 496 | 'restructure', 497 | 'use_function', 498 | 'introduce_factory', 499 | 'change_signature', 500 | 'rename_current_module', 501 | 'move_current_module', 502 | 'module_to_package', 503 | None, # separator 504 | 'code_assist', 505 | 'goto_definition', 506 | 'show_doc', 507 | 'find_occurrences', 508 | 'lucky_assist', 509 | 'jump_to_global', 510 | 'show_calltip', 511 | ) 512 | 513 | 514 | def _init_variables(): 515 | for variable, default in variables.items(): 516 | vim.command('if !exists("g:%s")\n' % variable + 517 | ' let g:%s = %s\n' % (variable, default)) 518 | 519 | 520 | def _enable_shortcuts(env): 521 | if env.get('enable_shortcuts'): 522 | for command, shortcut in shortcuts.items(): 523 | vim.command('noremap %s :call %s()' % 524 | (shortcut, _vim_name(command))) 525 | for command, shortcut in insert_shortcuts.items(): 526 | command_name = _vim_name(command) + 'InsertMode' 527 | vim.command('func! %s()\n' % command_name + 528 | 'call %s()\n' % _vim_name(command) + 529 | 'return ""\n' 530 | 'endfunc') 531 | vim.command('imap %s =%s()' % (shortcut, command_name)) 532 | 533 | 534 | def _add_menu(env, root_node='&Ropevim'): 535 | cmd_tmpl = '%s %s.%s :call %s()' 536 | 537 | vim.command('silent! aunmenu %s' % root_node) 538 | 539 | for i, cb in enumerate(menu_structure): 540 | if cb is None: 541 | vim.command('amenu %s.-SEP%s- :' % (root_node, i)) 542 | continue 543 | 544 | # use_function -> Use\ Function 545 | name = cb.replace('_', '\ ').title() 546 | 547 | for cmd in ('amenu', 'vmenu'): 548 | vim.command(cmd_tmpl % (cmd, root_node, name, _vim_name(cb))) 549 | 550 | 551 | ropemode.decorators.logger.message = echo 552 | ropemode.decorators.logger.only_short = True 553 | _completer = _ValueCompleter() 554 | 555 | _init_variables() 556 | _env = VimUtils() 557 | _interface = ropemode.interface.RopeMode(env=_env) 558 | _interface.init() 559 | _enable_shortcuts(_env) 560 | 561 | _add_menu(_env) 562 | _add_menu(_env, 'PopUp.&Ropevim') # menu weight can also be added 563 | --------------------------------------------------------------------------------