├── .gitignore ├── .hgignore ├── .hgtags ├── CONTRIBUTORS ├── COPYING ├── MANIFEST.in ├── README.rst ├── docs ├── done.rst ├── pymacs_signalrecursion.patch ├── ropemacs.rst └── todo.rst ├── ropemacs └── __init__.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.*~ 3 | *.egg-info 4 | .ropeproject/ 5 | doc/build/ 6 | build/ 7 | dist/ 8 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | \.pyc$ 2 | ^\.ropeproject$ 3 | ~$ 4 | -------------------------------------------------------------------------------- /.hgtags: -------------------------------------------------------------------------------- 1 | 7f7bd066834e2605d505bae11742d4a667d64c67 0.2 2 | df95cd65aff8fc2f60e6249d1b1507692bb8458a 0.3 3 | 353004207d3ad38b7da5abe52801b8049e4ff6c7 0.4 4 | 57422412927e2814664594c51714bca83a105f46 0.5c1 5 | 5ebeec2551e785bab085e83ce012b1e53d223c34 0.5c2 6 | 43142f39704c78d0f9711a6dc3334a69a68a3f9e 0.5c3 7 | 807232de1b787c8b950bf778aa6d8cfe00702c00 0.5c4 8 | ebdcc7bdc0e9748b743f3c5cdb207ff4bdbf5809 0.5c5 9 | 0abbd016038f56195d0697293b2558b10a402054 0.5c6 10 | 019a727a041282b6f3a54d61eb5fc9cdbaf6dba1 0.5 11 | be19b7e35aebea755961f7a5ac3f9e055f65764d 0.6c1 12 | 895b1eddffc8ae978d2447e13156aefec4b39c33 0.6c2 13 | 8b277a188d00a11eb561687587ac9bd6f331155b 0.6 14 | 93721bd03667897d712c5f5bcd8976a00e565dca 0.7 15 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | ======================= 2 | Ropemacs Contributors 3 | ======================= 4 | 5 | * Sebastjan Trepca 6 | * Stefan Reichoer 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst COPYING setup.py MANIFEST.in CONTRIBUTORS 2 | recursive-include ropemacs *.py 3 | recursive-include ropemode *.py 4 | recursive-include docs *.rst 5 | recursive-include docs *.patch 6 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. csv-table:: 2 | 3 | "❗If you are using ropemacs, consider using `pylsp-rope`_ in Emacs." 4 | 5 | .. _pylsp-rope: https://github.com/python-rope/pylsp-rope 6 | 7 | **This project is quite definitively free for adoption. Anybody who actually cares for Emacs, please, take this over from my hands. Thank you!** 8 | 9 | 10 | ========================= 11 | ropemacs, rope in emacs 12 | ========================= 13 | 14 | Ropemacs is an emacs mode that uses rope_ library to provide features 15 | like python refactorings and code-assists. You should install pymacs_ before using ropemacs. 16 | 17 | .. _rope: https://github.com/python-rope/rope/ 18 | .. _pymacs: https://github.com/dgentry/Pymacs 19 | 20 | 21 | New Features 22 | ============ 23 | 24 | ``rope-find-occurrences`` sets ``next-error-function``. That means 25 | compilation mode keys like ``C-x \``` work for occurrences buffer, 26 | too. 27 | 28 | Also there is a bug in pymacs 23 and 24-beta1 that makes python reach 29 | maximum recursion after interrupting a pymacs command; a patch is 30 | included in the docs folder. 31 | 32 | 33 | Setting Up 34 | ========== 35 | 36 | Install latest version of ropemacs:: 37 | 38 | python -m pip install --user --editable "git+https://github.com/python-rope/ropemacs.git#egg=ropemacs" 39 | 40 | After installing pymacs, add these lines to your ``~/.emacs`` file:: 41 | 42 | (require 'pymacs) 43 | (pymacs-load "ropemacs" "rope-") 44 | 45 | Also note that ropemacs may redefine some standard Emacs and your custom key 46 | bindings. To prevent this, put the following example lines to your 47 | ``~/.emacs`` *before* the lines presented above:: 48 | 49 | (setq ropemacs-enable-shortcuts nil) 50 | (setq ropemacs-local-prefix "C-c C-p") 51 | 52 | See keybinding_ and variables_ sections for more details. 53 | 54 | Loading Lazily 55 | -------------- 56 | 57 | If you want to load ropemacs only when you really need it, you can use 58 | a function like this in your ``~/.emacs``:: 59 | 60 | (defun load-ropemacs () 61 | "Load pymacs and ropemacs" 62 | (interactive) 63 | (require 'pymacs) 64 | (pymacs-load "ropemacs" "rope-") 65 | ;; Automatically save project python buffers before refactorings 66 | (setq ropemacs-confirm-saving 'nil) 67 | ) 68 | (global-set-key "\C-xpl" 'load-ropemacs) 69 | 70 | And execute ``load-ropemacs`` (or use ``C-x p l``) whenever you want 71 | to use ropemacs. 72 | 73 | 74 | Not Installing 75 | -------------- 76 | 77 | If you don't want to install rope library and ropemacs you can extract 78 | them somewhere and add these lines to your ``.emacs``:: 79 | 80 | ;; Add this before loading pymacs if you haven't installed rope and ropemacs 81 | (setq pymacs-load-path '("/path/to/rope" 82 | "/path/to/ropemacs")) 83 | 84 | 85 | Multiple Python Versions 86 | ------------------------ 87 | 88 | Rope needs at least Python2.5. If you have older versions of Python 89 | you can use ``PYMACS_PYTHON`` environment variable. You can add:: 90 | 91 | (setenv "PYMACS_PYTHON" "python2.5") 92 | 93 | to force pymacs to use Python2.5. 94 | 95 | 96 | Ropemacs Minor Mode 97 | ------------------- 98 | 99 | Ropemacs registers its local keys when ``ropemacs-mode`` is enabled. 100 | By default it is enabled using ``python-mode`` hook (this hook is 101 | available if you are using Emacs' ``python.el`` or XEmacs' 102 | ``python-mode.el``). If you want to enable it in other major modes 103 | either execute ``ropemacs-mode`` manually or call it in some other 104 | hook. 105 | 106 | 107 | Getting Started 108 | =============== 109 | 110 | Refactoring Dialog 111 | ------------------ 112 | 113 | Ropemacs refactorings use a special kind of dialog. When you start a 114 | refactoring, you'll be asked to confirm saving modified python 115 | buffers; you can change it by using ``ropemacs-confirm-saving`` 116 | variable. Adding ``(setq ropemacs-confirm-saving 'nil)`` to your 117 | ``.emacs`` file, will make emacs save them without asking. 118 | 119 | After that depending on the refactoring, you'll be asked about the 120 | essential information a refactoring needs to know (like the new name 121 | in rename refactoring). You can skip it by prefixing the refactoring; 122 | this can be useful when using batchset command (described later). 123 | 124 | Next you'll see the base prompt of a refactoring dialog that shows 125 | something like "Choose what to do". By entering the name of a 126 | refactoring option you can set its value. After setting each option 127 | you'll be returned back to the base prompt. Finally, you can ask rope 128 | to perform, preview or cancel the refactoring. 129 | 130 | See keybinding_ section and try the refactorings yourself. 131 | 132 | 133 | Finding Files 134 | ------------- 135 | 136 | By using ``rope-find-file`` (``C-x p f`` by default), you can search 137 | for files in your project. When you complete the minibuffer you'll 138 | see all files in the project; files are shown as their reversed paths. 139 | For instance ``projectroot/docs/todo.txt`` is shown like 140 | ``todo.txt Public Release 0.6 : October 3, 2008 6 | 7 | - include a patch for pymacs signal bug : October 3, 2008 8 | - set next-error-function : July 16, 2008 9 | 10 | > Public Release 0.6c2 : June 20, 2008 11 | 12 | - fixed go to occurrence in xemacs : June 20, 2008 13 | - added ropemacs-guess-project variable : June 18, 2008 14 | - fixed error messages that contain percent sign : June 18, 2008 15 | - fixed ask directory and entering default directory : June 9, 2008 16 | - added rope-run-module command : May 24, 2008 17 | - showing line-number in occurrences buffer : May 19, 2008 18 | 19 | > Public Release 0.6c1 : May 10, 2008 20 | 21 | - supporting inlining parameters : May 10, 2008 22 | - added rope-change-signature : May 9, 2008 23 | - added ropemacs-autoimport-underlineds variable : May 7, 2008 24 | - added rope-find-implementations : April 28, 2008 25 | - added rope-show-calltip : April 12, 2008 26 | - added rope-analyze-modules : April 12, 2008 27 | 28 | > Public Release 0.5 : April 5, 2008 29 | 30 | - better input error reporting : March 27, 2008 31 | - added ropemacs-completing-read-function variable : March 17, 2008 32 | - added rope-jump-to-global : March 17, 2008 33 | 34 | > Public Release 0.5c6 : March 15, 2008 35 | 36 | - added rope-analyze-module command : March 15, 2008 37 | - supporting in_hierarchy option of find_occurrences : March 10, 2008 38 | - added ropemacs-max-doc-buffer-height variable : March 7, 2008 39 | - added ropemacs menu : March 7, 2008 40 | - added rope-show-call-doc command : March 6, 2008 41 | - added ropemacs-separate-doc-buffer variable : March 6, 2008 42 | - supporting maxfixes option of rope-goto-definition : March 6, 2008 43 | - supporting maxfixes option of rope-show-doc : March 6, 2008 44 | - added ropemacs minor mode : March 1, 2008 45 | 46 | > Public Release 0.5c5 : March 1, 2008 47 | 48 | - filtering resources : February 29, 2008 49 | - added support for introduce factory refactoring : February 25, 2008 50 | 51 | > Public Release 0.5c4 : February 16, 2008 52 | 53 | - compatibility with pymacs : February 14, 2008 54 | - faster code-assists : February 7, 2008 55 | - prefixing rope-find-file shows only python files : February 2, 2008 56 | - merged rope-complete-and-import with code-assist : January 28, 2008 57 | 58 | > Public Release 0.5c3 : January 28, 2008 59 | 60 | - added support for autoimport : January 26, 2008 61 | - added introduce method object refactoring : January 25, 2008 62 | - added use function refactoring : January 25, 2008 63 | 64 | > Public Release 0.5c2 : January 17, 2008 65 | 66 | - showing change description in undo/redo : January 8, 2008 67 | - added rope-find-file-other-window : January 4, 2008 68 | - added ropemacs-enable-shortcuts variable : January 3, 2008 69 | 70 | > Public Release 0.5c1 : January 3, 2008 71 | 72 | - deprecated rope-code-assist-max-fixes : December 28, 2007 73 | - deprecated rope-confirm-saving : December 28, 2007 74 | - added ropemacs-local-prefix and ropemacs-global-prefix : December 28, 2007 75 | - handling narrowed regions : December 21, 2007 76 | 77 | > Public Release 0.4 : December 19, 2007 78 | 79 | - supporting emacs 21 : December 18, 2007 80 | - added ``rope-code-assist-max-fixes`` variable : December 17, 2007 81 | - printing traceback when task runner gets interrupted : December 14, 2007 82 | - supporting ``only_current`` option for inline refactoring : December 13, 2007 83 | - supporting ``global_`` option for extract refactorings : December 13, 2007 84 | - not raising exceptions in hooks : December 5, 2007 85 | 86 | > Public Release 0.3 : December 5, 2007 87 | 88 | - setting many configs using batchset in dialogs : December 1, 2007 89 | - updating buffers with moved files : December 1, 2007 90 | - showing the old value of a field in dialogs : November 30, 2007 91 | - new file/directory/module/package; ``C-x p n [fdmp]`` : November 30, 2007 92 | - lucky-assist; ``M-?`` : November 29, 2007 93 | - find occurrences; ``C-c f`` : November 29, 2007 94 | - edit project config; ``C-x p c`` : November 28, 2007 95 | 96 | > Public Release 0.2 : November 28, 2007 97 | 98 | - previewing changes : November 27, 2007 99 | - specifying refactoring options : November 26, 2007 100 | - restructuring support : November 26, 2007 101 | - added ``rope-confirm-saving`` variable : November 26, 2007 102 | - only activating local keys in python mode : November 26, 2007 103 | - find file and advanced matching : November 25, 2007 104 | - generate python element; ``C-c n [vfcmp]`` : November 23, 2007 105 | - rope find file; ``C-c p f`` : November 23, 2007 106 | - code-assist; ``M-/`` : November 23, 2007 107 | 108 | > Public Release 0.1 : September 9, 2007 109 | 110 | - moving elements, methods and modules : October 30, 2007 111 | - undoing refactorings : October 29, 2007 112 | - inline refactoring : October 29, 2007 113 | - extract method and local variable : October 29, 2007 114 | - goto definition : October 29, 2007 115 | - rename refactoring : October 29, 2007 116 | -------------------------------------------------------------------------------- /docs/pymacs_signalrecursion.patch: -------------------------------------------------------------------------------- 1 | # It can be applied on Pymacs 0.23 or 0.24-beta1. The problem is 2 | # signal.signal() is called twice for signal.SIGINT. You can use 3 | # ``patch -p1 < signal_recursion.patch`` in the extracted directory. 4 | 5 | --- a/Pymacs/pymacs.py 6 | +++ b/Pymacs/pymacs.py 7 | @@ -69,20 +69,6 @@ 8 | import signal 9 | self.original_handler = signal.signal( 10 | signal.SIGINT, self.interrupt_handler) 11 | - for counter in range(1, signal.NSIG): 12 | - if counter == signal.SIGINT: 13 | - self.original_handler = signal.signal(counter, 14 | - self.interrupt_handler) 15 | - 16 | - # The following few lines of code are reported to create IO 17 | - # problems within the Pymacs helper itself, so I merely comment 18 | - # them for now, until we know better. 19 | - 20 | - #else: 21 | - # try: 22 | - # signal.signal(counter, self.generic_handler) 23 | - # except RuntimeError: 24 | - # pass 25 | self.inhibit_quit = True 26 | # Start protocol and services. 27 | from Pymacs import __version__ 28 | -------------------------------------------------------------------------------- /docs/ropemacs.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | ropemacs, rope in emacs 3 | ========================= 4 | 5 | Ropemacs is a plugin for performing python refactorings in emacs. It 6 | uses rope_ library and pymacs_. 7 | 8 | You should install `rope`_ library and pymacs_ before using ropemacs. 9 | You can download ropemacs from `project download page`_. 10 | 11 | .. _rope: http://rope.sf.net/ 12 | 13 | 14 | Features 15 | ======== 16 | 17 | * Supports many of the refactorings that are supported by rope_ 18 | library: 19 | 20 | * Rename 21 | * Extract method/local variable 22 | * Move class/function/module/package/method 23 | * Inline method/local variable/parameter 24 | * Restructuring 25 | * Change signature 26 | * ... 27 | 28 | * Other refactoring-related features 29 | 30 | * Previewing refactorings 31 | * Undo/redo refactorings 32 | * Showing refactoring progress 33 | 34 | * Code-assists 35 | 36 | * Code completion 37 | * Goto definition 38 | * Show pydoc 39 | * Find occurrences 40 | * Organize imports (remove unused and duplicate imports and sort them) 41 | * Generating python elements 42 | 43 | 44 | Source Repository 45 | ================= 46 | 47 | The repository version needs ropemode (which was once part of 48 | ropemacs); in order to use the repository version of ropemacs you need 49 | to put ropemode in your ``PYTHONPATH``. Note that ropemode is 50 | included in released packages. 51 | 52 | Ropemacs: 53 | 54 | * repo url: http://bitbucket.org/agr/ropemacs 55 | * snapshot: http://bitbucket.org/agr/ropemacs/get/tip.gz 56 | 57 | Ropemode: 58 | 59 | * repo url: http://bitbucket.org/agr/ropemode 60 | * snapshot: http://bitbucket.org/agr/ropemode/get/tip.gz 61 | 62 | 63 | Feedback 64 | ======== 65 | 66 | Send your bug reports, feature requests and patches to `rope-dev (at) 67 | googlegroups.com`_. 68 | 69 | 70 | License 71 | ======= 72 | 73 | Ropemacs is under the terms of GNU GPL (GNU General Public License). 74 | 75 | .. _project download page: http://sf.net/projects/rope/files 76 | .. _`rope-dev (at) googlegroups.com`: http://groups.google.com/group/rope-dev 77 | .. _pymacs: http://pymacs.progiciels-bpi.ca/pymacs.html 78 | .. _Mercurial: http://selenic.com/mercurial 79 | -------------------------------------------------------------------------------- /docs/todo.rst: -------------------------------------------------------------------------------- 1 | TODO 2 | ==== 3 | 4 | > Public Release 1.0 5 | 6 | > Public Release 0.6 7 | 8 | * saving the old values of refactoring configs 9 | * showing proposal type in code-assist 10 | -------------------------------------------------------------------------------- /ropemacs/__init__.py: -------------------------------------------------------------------------------- 1 | """ropemacs, an emacs mode for using rope refactoring library""" 2 | import sys 3 | from os.path import join 4 | 5 | import ropemode.decorators 6 | import ropemode.environment 7 | import ropemode.interface 8 | from Pymacs import lisp 9 | from rope.base import utils 10 | 11 | 12 | class LispUtils(ropemode.environment.Environment): 13 | 14 | def ask(self, prompt, default=None, starting=None): 15 | if default is not None: 16 | prompt = prompt + ('[%s] ' % default) 17 | result = lisp.read_from_minibuffer(prompt, starting, None, None, 18 | None, default, None) 19 | if result == '' and default is not None: 20 | return default 21 | return result 22 | 23 | def ask_values(self, prompt, values, default=None, starting=None, exact=True): 24 | if self._emacs_version() < 22: 25 | values = [[value, value] for value in values] 26 | if exact and default is not None: 27 | prompt = prompt + ('[%s] ' % default) 28 | reader = lisp['ropemacs-completing-read-function'].value() 29 | result = reader(prompt, values, None, exact, starting) 30 | if result == '' and exact: 31 | return default 32 | return result 33 | 34 | def ask_completion(self, prompt, values, starting=None): 35 | return self.ask_values(prompt, values, starting=starting, exact=None) 36 | 37 | def ask_directory(self, prompt, default=None, starting=None): 38 | location = starting or default 39 | if location is not None: 40 | prompt = prompt + ('[%s] ' % location) 41 | if lisp.fboundp(lisp['read-directory-name']): 42 | # returns default when starting is entered 43 | result = lisp.read_directory_name(prompt, location, location) 44 | else: 45 | result = lisp.read_file_name(prompt, location, location) 46 | if result == '' and location is not None: 47 | return self.path_on_python_host(location) 48 | return self.path_on_python_host(result) 49 | 50 | def path_on_python_host(self, path_on_lisp_host): 51 | path_on_python_host = None 52 | if path_on_lisp_host: 53 | path_on_python_host = lisp.file_remote_p(path_on_lisp_host, lisp.localname) 54 | return path_on_python_host or path_on_lisp_host 55 | 56 | def message(self, msg): 57 | message(msg) 58 | 59 | def yes_or_no(self, prompt): 60 | return lisp.yes_or_no_p(prompt) 61 | 62 | def y_or_n(self, prompt): 63 | return lisp.y_or_n_p(prompt) 64 | 65 | def get(self, name, default=None): 66 | lispname = 'ropemacs-' + name.replace('_', '-') 67 | if lisp.boundp(lisp[lispname]): 68 | return lisp[lispname].value() 69 | return default 70 | 71 | def get_offset(self): 72 | return lisp.point() - 1 73 | 74 | def get_text(self): 75 | end = lisp.buffer_size() + 1 76 | old_min = lisp.point_min() 77 | old_max = lisp.point_max() 78 | narrowed = (old_min != 1 or old_max != end) 79 | if narrowed: 80 | lisp.narrow_to_region(1, lisp.buffer_size() + 1) 81 | try: 82 | return lisp.buffer_string() 83 | finally: 84 | if narrowed: 85 | lisp.narrow_to_region(old_min, old_max) 86 | 87 | def get_region(self): 88 | offset1 = self.get_offset() 89 | lisp.exchange_point_and_mark() 90 | offset2 = self.get_offset() 91 | lisp.exchange_point_and_mark() 92 | return min(offset1, offset2), max(offset1, offset2) 93 | 94 | def filename(self): 95 | filename = lisp.buffer_file_name() 96 | return self.path_on_python_host(filename) 97 | 98 | def is_modified(self): 99 | return lisp.buffer_modified_p() 100 | 101 | def goto_line(self, lineno): 102 | lisp.goto_line(lineno) 103 | 104 | def insert_line(self, line, lineno): 105 | current = lisp.point() 106 | lisp.goto_line(lineno) 107 | lisp.insert(line + '\n') 108 | lisp.goto_char(current + len(line) + 1) 109 | 110 | def insert(self, text): 111 | lisp.insert(text) 112 | 113 | def delete(self, start, end): 114 | lisp.delete_region(start, end) 115 | 116 | def filenames(self): 117 | result = [] 118 | for buffer in lisp.buffer_list(): 119 | filename = lisp.buffer_file_name(buffer) 120 | if filename: 121 | result.append(filename) 122 | return result 123 | 124 | def save_files(self, filenames): 125 | ask = self.get('confirm_saving') 126 | initial = lisp.current_buffer() 127 | for filename in filenames: 128 | buffer = lisp.find_buffer_visiting(filename) 129 | if buffer: 130 | if lisp.buffer_modified_p(buffer): 131 | if not ask or lisp.y_or_n_p('Save %s buffer?' % filename): 132 | lisp.set_buffer(buffer) 133 | lisp.save_buffer() 134 | lisp.set_buffer(initial) 135 | 136 | def reload_files(self, filenames, moves={}): 137 | if self.filename() in moves: 138 | initial = None 139 | else: 140 | initial = lisp.current_buffer() 141 | for filename in filenames: 142 | buffer = lisp.find_buffer_visiting(self.path_on_lisp_host(filename)) 143 | if buffer: 144 | if filename in moves: 145 | lisp.kill_buffer(buffer) 146 | lisp.find_file(moves[filename]) 147 | else: 148 | lisp.set_buffer(buffer) 149 | lisp.revert_buffer(False, True) 150 | if initial is not None: 151 | lisp.set_buffer(initial) 152 | 153 | def path_on_lisp_host(self, path_on_python_host): 154 | default_directory = lisp['default-directory'].value() 155 | path = lisp.file_remote_p(default_directory) 156 | return join((path or default_directory) , path_on_python_host) 157 | 158 | def find_file(self, filename, readonly=False, other=False): 159 | filename = self.path_on_lisp_host(filename) 160 | if other: 161 | lisp.find_file_other_window(filename) 162 | elif readonly: 163 | lisp.find_file_read_only(filename) 164 | else: 165 | lisp.find_file(filename) 166 | 167 | def _make_buffer(self, name, contents, empty_goto=True, switch=False, 168 | window='other', modes=[], fit_lines=None): 169 | """Make an emacs buffer 170 | 171 | `window` can be one of `None`, 'current' or 'other'. 172 | """ 173 | new_buffer = lisp.get_buffer_create(name) 174 | lisp.set_buffer(new_buffer) 175 | lisp.toggle_read_only(-1) 176 | lisp.erase_buffer() 177 | if contents or empty_goto: 178 | lisp.insert(contents) 179 | for mode in modes: 180 | lisp[mode + '-mode']() 181 | lisp.buffer_disable_undo(new_buffer) 182 | lisp.toggle_read_only(1) 183 | if switch: 184 | if window == 'current': 185 | lisp.switch_to_buffer(new_buffer) 186 | else: 187 | lisp.switch_to_buffer_other_window(new_buffer) 188 | lisp.goto_char(lisp.point_min()) 189 | elif window == 'other': 190 | if self.get("use_pop_to_buffer"): 191 | lisp.pop_to_buffer(new_buffer) 192 | lisp.goto_char(lisp.point_min()) 193 | else: 194 | new_window = lisp.display_buffer(new_buffer) 195 | lisp.set_window_point(new_window, lisp.point_min()) 196 | if (fit_lines 197 | and lisp.fboundp(lisp['fit-window-to-buffer'])): 198 | lisp.fit_window_to_buffer(new_window, fit_lines) 199 | lisp.bury_buffer(new_buffer) 200 | return new_buffer 201 | 202 | def _hide_buffer(self, name, delete=True): 203 | buffer = lisp.get_buffer(name) 204 | if buffer is not None: 205 | window = lisp.get_buffer_window(buffer) 206 | if window is not None: 207 | lisp.bury_buffer(buffer) 208 | if delete: 209 | lisp.delete_window(window) 210 | else: 211 | if lisp.buffer_name(lisp.current_buffer()) == name: 212 | lisp.switch_to_buffer(None) 213 | 214 | def _emacs_version(self): 215 | return int(lisp['emacs-version'].value().split('.')[0]) 216 | 217 | def create_progress(self, name): 218 | if lisp.fboundp(lisp['make-progress-reporter']): 219 | progress = _LispProgress(name) 220 | else: 221 | progress = _OldProgress(name) 222 | return progress 223 | 224 | def current_word(self): 225 | return lisp.current_word() 226 | 227 | def push_mark(self): 228 | marker_ring = self.get('marker_ring') 229 | marker = lisp.point_marker() 230 | lisp.ring_insert(marker_ring, marker) 231 | 232 | def pop_mark(self): 233 | marker_ring = self.get('marker_ring') 234 | if lisp.ring_empty_p(marker_ring): 235 | self.message("There are no more marked buffers in \ 236 | the rope-marker-ring") 237 | else: 238 | oldbuf = lisp.current_buffer() 239 | marker = lisp.ring_remove(marker_ring, 0) 240 | marker_buffer = lisp.marker_buffer(marker) 241 | if marker_buffer is None: 242 | lisp.message("The marked buffer has been deleted") 243 | return 244 | marker_point = lisp.marker_position(marker) 245 | lisp.set_buffer(marker_buffer) 246 | lisp.goto_char(marker_point) 247 | #Kill that marker so it doesn't slow down editing. 248 | lisp.set_marker(marker, None, None) 249 | if not lisp.eq(oldbuf, marker_buffer): 250 | lisp.switch_to_buffer(marker_buffer) 251 | 252 | def prefix_value(self, prefix): 253 | return lisp.prefix_numeric_value(prefix) 254 | 255 | def read_line_from_file(self, filename, lineno): 256 | with open(filename) as f: 257 | for i, line in enumerate(f): 258 | if i+1 == lineno: 259 | return line 260 | 261 | return "" # If lineno goes beyond the end of the file 262 | 263 | def show_occurrences(self, locations): 264 | buffer = self._make_buffer('*rope-occurrences*', "", switch=False) 265 | lisp.set_buffer(buffer) 266 | lisp.toggle_read_only(0) 267 | 268 | trunc_length = len(lisp.rope_get_project_root()) 269 | 270 | lisp.insert('List of occurrences:\n') 271 | for location in locations: 272 | code_line = self.read_line_from_file(location.filename, location.lineno).rstrip() 273 | filename = location.filename[trunc_length:] 274 | lineno = str(location.lineno) 275 | offset = str(location.offset) 276 | 277 | lisp.insert(filename + ":" + lineno + ":" + code_line + " " + offset) 278 | 279 | beginning = lisp.line_beginning_position() 280 | end = beginning + len(filename) 281 | 282 | lisp.add_text_properties(beginning, end, [lisp.face, lisp.button]) 283 | lisp.add_text_properties(beginning, end, [lisp.mouse_face, lisp.highlight, 284 | lisp.help_echo, "mouse-2: visit this file in other window"]) 285 | 286 | lisp.insert("\n") 287 | 288 | lisp.toggle_read_only(1) 289 | 290 | lisp.set(lisp["next-error-function"], lisp.rope_occurrences_next) 291 | lisp.local_set_key('\r', lisp.rope_occurrences_goto) 292 | lisp.local_set_key((lisp.mouse_1,), lisp.rope_occurrences_goto) 293 | lisp.local_set_key('q', lisp.delete_window) 294 | 295 | 296 | def show_doc(self, docs, altview=False): 297 | use_minibuffer = not altview 298 | if self.get('separate_doc_buffer'): 299 | use_minibuffer = not use_minibuffer 300 | if not use_minibuffer: 301 | fit_lines = self.get('max_doc_buffer_height') 302 | buffer = self._make_buffer('*rope-pydoc*', docs, 303 | empty_goto=False, 304 | fit_lines=fit_lines) 305 | lisp.local_set_key('q', lisp.bury_buffer) 306 | elif docs: 307 | docs = '\n'.join(docs.split('\n')[:7]) 308 | self.message(docs) 309 | 310 | def preview_changes(self, diffs): 311 | self._make_buffer('*rope-preview*', diffs, switch=True, 312 | modes=['diff'], window='current') 313 | try: 314 | return self.yes_or_no('Do the changes? ') 315 | finally: 316 | self._hide_buffer('*rope-preview*', delete=False) 317 | 318 | def local_command(self, name, callback, key=None, prefix=False): 319 | globals()[name] = callback 320 | self._set_interaction(callback, prefix) 321 | if self.local_prefix and key: 322 | key = self._key_sequence(self.local_prefix + ' ' + key) 323 | self._bind_local(_lisp_name(name), key) 324 | 325 | def _bind_local(self, name, key): 326 | lisp('(define-key ropemacs-local-keymap "%s" \'%s)' % 327 | (self._key_sequence(key), name)) 328 | 329 | def global_command(self, name, callback, key=None, prefix=False): 330 | globals()[name] = callback 331 | self._set_interaction(callback, prefix) 332 | if self.global_prefix and key: 333 | key = self._key_sequence(self.global_prefix + ' ' + key) 334 | lisp.global_set_key(key, lisp[_lisp_name(name)]) 335 | 336 | def _key_sequence(self, sequence): 337 | result = [] 338 | for key in sequence.split(): 339 | if key.startswith('C-'): 340 | number = ord(key[-1].upper()) - ord('A') + 1 341 | result.append(chr(number)) 342 | elif key.startswith('M-'): 343 | number = ord(key[-1].upper()) + 0x80 344 | result.append(chr(number)) 345 | else: 346 | result.append(key) 347 | return ''.join(result) 348 | 349 | def _set_interaction(self, callback, prefix): 350 | if hasattr(callback, '__func__'): 351 | callback = callback.__func__ 352 | if prefix: 353 | callback_interaction = 'P' 354 | else: 355 | callback_interaction = '' 356 | 357 | try: 358 | callback.interaction = callback_interaction 359 | except AttributeError: 360 | callback.__func__.interaction = callback_interaction 361 | 362 | def add_hook(self, name, callback, hook): 363 | mapping = {'before_save': 'before-save-hook', 364 | 'after_save': 'after-save-hook', 365 | 'exit': 'kill-emacs-hook'} 366 | globals()[name] = callback 367 | lisp.add_hook(lisp[mapping[hook]], lisp[_lisp_name(name)]) 368 | 369 | @property 370 | @utils.saveit 371 | def global_prefix(self): 372 | return self.get('global_prefix') 373 | 374 | @property 375 | @utils.saveit 376 | def local_prefix(self): 377 | return self.get('local_prefix') 378 | 379 | 380 | def _lisp_name(name): 381 | return 'rope-' + name.replace('_', '-') 382 | 383 | class _LispProgress(object): 384 | 385 | def __init__(self, name): 386 | self.progress = lisp.make_progress_reporter('%s ... ' % name, 0, 100) 387 | 388 | def update(self, percent): 389 | lisp.progress_reporter_update(self.progress, percent) 390 | 391 | def done(self): 392 | lisp.progress_reporter_done(self.progress) 393 | 394 | class _OldProgress(object): 395 | 396 | def __init__(self, name): 397 | self.name = name 398 | self.update(0) 399 | 400 | def update(self, percent): 401 | if percent != 0: 402 | message('%s ... %s%%%%' % (self.name, percent)) 403 | else: 404 | message('%s ... ' % self.name) 405 | 406 | def done(self): 407 | message('%s ... done' % self.name) 408 | 409 | 410 | def message(message): 411 | lisp.message(message.replace('%', '%%')) 412 | 413 | def occurrences_goto(): 414 | if lisp.line_number_at_pos() < 1: 415 | lisp.forward_line(1 - lisp.line_number_at_pos()) 416 | lisp.end_of_line() 417 | end = lisp.point() 418 | lisp.beginning_of_line() 419 | line = lisp.buffer_substring_no_properties(lisp.point(), end) 420 | tokens = line.split() 421 | semicolon_tokens = line.split(":") 422 | 423 | project_root = lisp.rope_get_project_root() 424 | if tokens and semicolon_tokens: 425 | # Mark this line with an arrow 426 | lisp(''' 427 | (remove-overlays (point-min) (point-max)) 428 | (overlay-put (make-overlay (line-beginning-position) (line-end-position)) 429 | 'before-string 430 | (propertize "A" 'display '(left-fringe right-triangle))) 431 | ''') 432 | 433 | 434 | filename = project_root + "/" + semicolon_tokens[0] 435 | offset = int(tokens[-1]) 436 | resource = _interface._get_resource(filename) 437 | LispUtils().find_file(resource.real_path, other=True) 438 | lisp.goto_char(offset + 1) 439 | occurrences_goto.interaction = '' 440 | 441 | def occurrences_next(arg, reset): 442 | lisp.switch_to_buffer_other_window('*rope-occurrences*', True) 443 | if reset: 444 | lisp.goto_char(lisp.point_min()) 445 | lisp.forward_line(arg) 446 | if lisp.eobp(): 447 | lisp.message("Cycling rope occurrences") 448 | lisp.goto_char(lisp.point_min()) 449 | occurrences_goto() 450 | occurrences_next.interaction = '' 451 | 452 | 453 | DEFVARS = """\ 454 | (defgroup ropemacs nil 455 | "ropemacs, an emacs plugin for rope." 456 | :link '(url-link "http://rope.sourceforge.net/ropemacs.html") 457 | :prefix "rope-") 458 | 459 | (defcustom ropemacs-confirm-saving t 460 | "Shows whether to confirm saving modified buffers before refactorings. 461 | 462 | If non-nil, you have to confirm saving all modified 463 | python files before refactorings; otherwise they are 464 | saved automatically.") 465 | 466 | (defcustom ropemacs-codeassist-maxfixes 1 467 | "The number of errors to fix before code-assist. 468 | 469 | How many errors to fix, at most, when proposing code completions.") 470 | 471 | (defcustom ropemacs-separate-doc-buffer t 472 | "Should `rope-show-doc' use a separate buffer or the minibuffer.") 473 | (defcustom ropemacs-max-doc-buffer-height 22 474 | "The maximum buffer height for `rope-show-doc'.") 475 | 476 | (defcustom ropemacs-use-pop-to-buffer nil 477 | "Use native `pop-to-buffer' to show new buffer. 478 | 479 | This affect all ropemacs function including `rope-show-doc'.") 480 | 481 | (defcustom ropemacs-enable-autoimport 'nil 482 | "Specifies whether autoimport should be enabled.") 483 | (defcustom ropemacs-autoimport-modules nil 484 | "The name of modules whose global names should be cached. 485 | 486 | The `rope-generate-autoimport-cache' reads this list and fills its 487 | cache.") 488 | (defcustom ropemacs-autoimport-underlineds 'nil 489 | "If set, autoimport will cache names starting with underlines, too.") 490 | 491 | (defcustom ropemacs-completing-read-function (if (and (boundp 'ido-mode) 492 | ido-mode) 493 | 'ido-completing-read 494 | 'completing-read) 495 | "Function to call when prompting user to choose between a list of options. 496 | This should take the same arguments as `completing-read'. 497 | Possible values are `completing-read' and `ido-completing-read'. 498 | Note that you must set `ido-mode' if using`ido-completing-read'." 499 | :type 'function) 500 | 501 | (make-obsolete-variable 502 | 'rope-confirm-saving 'ropemacs-confirm-saving "27.1") 503 | (make-obsolete-variable 504 | 'rope-code-assist-max-fixes 'ropemacs-codeassist-maxfixes "27.1") 505 | 506 | (defcustom ropemacs-local-prefix "C-c r" 507 | "The prefix for ropemacs refactorings. 508 | 509 | Use nil to prevent binding keys.") 510 | 511 | (defcustom ropemacs-global-prefix "C-x p" 512 | "The prefix for ropemacs project commands. 513 | 514 | Use nil to prevent binding keys.") 515 | 516 | (defcustom ropemacs-marker-ring-length 16 517 | "Length of the rope marker ring.") 518 | 519 | (defcustom ropemacs-marker-ring (make-ring ropemacs-marker-ring-length) 520 | "Ring of markers which are locations from which goto-definition was invoked.") 521 | 522 | (defcustom ropemacs-enable-shortcuts 't 523 | "Shows whether to bind ropemacs shortcuts keys. 524 | 525 | If non-nil it binds: 526 | 527 | ================ ============================ 528 | Key Command 529 | ================ ============================ 530 | M-/ rope-code-assist 531 | C-c g rope-goto-definition 532 | C-c u rope-pop-mark 533 | C-c d rope-show-doc 534 | C-c f rope-find-occurrences 535 | M-? rope-lucky-assist 536 | ================ ============================ 537 | ") 538 | 539 | (defvar ropemacs-local-keymap (make-sparse-keymap)) 540 | 541 | (easy-menu-define ropemacs-mode-menu ropemacs-local-keymap 542 | "`ropemacs' menu" 543 | '("Rope" 544 | ["Code assist" rope-code-assist t] 545 | ["Lucky assist" rope-lucky-assist t] 546 | ["Goto definition" rope-goto-definition t] 547 | ["Pop mark" rope-pop-mark t] 548 | ["Jump to global" rope-jump-to-global t] 549 | ["Show documentation" rope-show-doc t] 550 | ["Find Occurrences" rope-find-occurrences t] 551 | ["Analyze module" rope-analyze-module t] 552 | ("Refactor" 553 | ["Inline" rope-inline t] 554 | ["Extract Variable" rope-extract-variable t] 555 | ["Extract Method" rope-extract-method t] 556 | ["Organize Imports" rope-organize-imports t] 557 | ["Rename" rope-rename t] 558 | ["Move" rope-move t] 559 | ["Restructure" rope-restructure t] 560 | ["Use Function" rope-use-function t] 561 | ["Introduce Factory" rope-introduce-factory t] 562 | ("Generate" 563 | ["Class" rope-generate-class t] 564 | ["Function" rope-generate-function t] 565 | ["Module" rope-generate-module t] 566 | ["Package" rope-generate-package t] 567 | ["Variable" rope-generate-variable t] 568 | ) 569 | ("Module" 570 | ["Module to Package" rope-module-to-package t] 571 | ["Rename Module" rope-rename-current-module t] 572 | ["Move Module" rope-move-current-module t] 573 | ) 574 | "--" 575 | ["Undo" rope-undo t] 576 | ["Redo" rope-redo t] 577 | ) 578 | ("Project" 579 | ["Open project" rope-open-project t] 580 | ["Close project" rope-close-project t] 581 | ["Find file" rope-find-file t] 582 | ["Open project config" rope-project-config t] 583 | ) 584 | ("Create" 585 | ["Module" rope-create-module t] 586 | ["Package" rope-create-package t] 587 | ["File" rope-create-file t] 588 | ["Directory" rope-create-directory t] 589 | ) 590 | )) 591 | 592 | (defcustom ropemacs-guess-project 'nil 593 | "Try to guess the project when needed. 594 | 595 | If non-nil, ropemacs tries to guess and open the project that contains 596 | a file on which the rope command is performed when no project is 597 | already opened.") 598 | 599 | (provide 'ropemacs) 600 | """ 601 | 602 | MINOR_MODE = """\ 603 | (require 'thingatpt) 604 | 605 | (define-minor-mode ropemacs-mode 606 | "ropemacs, rope in emacs!" nil " Rope" ropemacs-local-keymap 607 | (if ropemacs-mode 608 | (add-hook 'completion-at-point-functions 'ropemacs-completion-at-point nil t) 609 | (remove-hook 'completion-at-point-functions 'ropemacs-completion-at-point t))) 610 | 611 | (defun ropemacs-completion-at-point () 612 | (unless (nth 8 (syntax-ppss)) 613 | (let ((bounds (or (bounds-of-thing-at-point 'symbol) 614 | (cons (point) (point))))) 615 | (list (car bounds) 616 | (cdr bounds) 617 | 'ropemacs--completion-table 618 | :company-doc-buffer 'ropemacs--completion-doc-buffer 619 | :company-location 'ropemacs--completion-location)))) 620 | 621 | (defalias 'ropemacs--completion-table 622 | (if (fboundp 'completion-table-with-cache) 623 | (completion-table-with-cache #'ropemacs--completion-candidates) 624 | (completion-table-dynamic #'ropemacs--completion-candidates))) 625 | 626 | (defun ropemacs--completion-candidates (prefix) 627 | (mapcar (lambda (element) (concat prefix element)) 628 | (rope-completions))) 629 | 630 | (defun ropemacs--with-inserted (candidate fn) 631 | (let ((inhibit-modification-hooks t) 632 | (inhibit-point-motion-hooks t) 633 | (modified-p (buffer-modified-p)) 634 | (beg (or (car (bounds-of-thing-at-point 'symbol)) (point))) 635 | (pt (point))) 636 | (insert (substring candidate (- pt beg))) 637 | (unwind-protect 638 | (funcall fn) 639 | (delete-region pt (point)) 640 | (set-buffer-modified-p modified-p)))) 641 | 642 | (defun ropemacs--completion-doc-buffer (candidate) 643 | (let ((doc (ropemacs--with-inserted candidate #'rope-get-doc))) 644 | (when doc 645 | (with-current-buffer (get-buffer-create "*ropemacs-completion-doc*") 646 | (erase-buffer) 647 | (insert doc) 648 | (goto-char (point-min)) 649 | (current-buffer))))) 650 | 651 | (defun ropemacs--completion-location (candidate) 652 | (let ((location (ropemacs--with-inserted 653 | candidate #'rope-definition-location))) 654 | (when location 655 | (cons (elt location 0) (elt location 1))))) 656 | """ 657 | 658 | shortcuts = [('M-/', 'rope-code-assist'), 659 | ('M-?', 'rope-lucky-assist'), 660 | ('C-c g', 'rope-goto-definition'), 661 | ('C-c u', 'rope-pop-mark'), 662 | ('C-c d', 'rope-show-doc'), 663 | ('C-c f', 'rope-find-occurrences')] 664 | 665 | 666 | _interface = None 667 | 668 | def _load_ropemacs(): 669 | global _interface 670 | ropemode.decorators.logger.message = message 671 | lisp(DEFVARS) 672 | _interface = ropemode.interface.RopeMode(env=LispUtils()) 673 | _interface.init() 674 | lisp(MINOR_MODE) 675 | 676 | if LispUtils().get('enable_shortcuts'): 677 | for key, command in shortcuts: 678 | LispUtils()._bind_local(command, key) 679 | 680 | lisp.add_hook(lisp['python-mode-hook'], lisp['ropemacs-mode']) 681 | 682 | def _started_from_pymacs(): 683 | import inspect 684 | frame = sys._getframe() 685 | while frame: 686 | # checking frame.f_code.co_name == 'pymacs_load_helper' might 687 | # be very fragile. 688 | filename = inspect.getfile(frame).rstrip('c') 689 | if filename.endswith(('Pymacs.py', 'pymacs.py')): 690 | return True 691 | frame = frame.f_back 692 | 693 | if _started_from_pymacs(): 694 | _load_ropemacs() 695 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | extra_kwargs = {} 2 | try: 3 | from setuptools import setup 4 | extra_kwargs['install_requires'] = ['rope >= 0.9.4', 'ropemode >= 0.2'] 5 | except ImportError: 6 | from distutils.core import setup 7 | 8 | 9 | classifiers = [ 10 | 'Development Status :: 4 - Beta', 11 | 'Operating System :: OS Independent', 12 | 'Environment :: X11 Applications', 13 | 'Environment :: Win32 (MS Windows)', 14 | 'Environment :: MacOS X', 15 | 'Intended Audience :: Developers', 16 | 'License :: OSI Approved :: GNU General Public License (GPL)', 17 | 'Natural Language :: English', 18 | 'Programming Language :: Python', 19 | 'Topic :: Text Editors :: Emacs', 20 | 'Topic :: Software Development'] 21 | 22 | 23 | def get_long_description(): 24 | lines = open('README.rst').read().splitlines(False) 25 | end = lines.index('Setting Up') 26 | return '\n' + '\n'.join(lines[:end]) + '\n' 27 | 28 | setup(name='ropemacs', 29 | version='0.8', 30 | description='An emacs mode for using rope python refactoring library', 31 | long_description=get_long_description(), 32 | packages=['ropemacs'], 33 | author='Ali Gholami Rudi', 34 | author_email='aligrudi@users.sourceforge.net', 35 | url='http://rope.sf.net/ropemacs.html', 36 | license='GNU GPL', 37 | classifiers=classifiers, 38 | requires=['ropemode'], 39 | **extra_kwargs) 40 | --------------------------------------------------------------------------------