88import sys
99import re
1010import json
11+ import multiprocessing
1112from .utils import (
1213 message , PY2 , error , pymode_input , pymode_inputlist , pymode_y_n )
1314
1920from rope .base import project , libutils , exceptions , change # noqa
2021from rope .base .fscommands import FileSystemCommands # noqa
2122from rope .contrib import autoimport , codeassist , findit # noqa
22- from rope .refactor import ModuleToPackage , ImportOrganizer , rename , extract , inline , usefunction # noqa
23+ from rope .refactor import ModuleToPackage , ImportOrganizer , rename , extract , inline , usefunction , move # noqa
2324from rope .base .taskhandle import TaskHandle # noqa
2425
2526
@@ -85,15 +86,15 @@ def completions():
8586 vim .command ("return %s" % json .dumps (proposals ))
8687
8788
88- def complete ():
89+ def complete (dot = False ):
8990 """ Ctrl+Space completion.
9091
9192 :return bool: success
9293
9394 """
9495 row , column = vim .current .window .cursor
9596 source , offset = get_assist_params ((row , column ))
96- proposals = get_proporsals (source , offset )
97+ proposals = get_proporsals (source , offset , dot = dot )
9798 if not proposals :
9899 return False
99100
@@ -116,7 +117,7 @@ def complete():
116117 return True
117118
118119
119- def get_proporsals (source , offset , base = '' ):
120+ def get_proporsals (source , offset , base = '' , dot = False ):
120121 """ Code assist.
121122
122123 :return str:
@@ -136,7 +137,7 @@ def get_proporsals(source, offset, base=''):
136137 proposals = sorted (proposals , key = _sort_proporsals )
137138
138139 out = []
139- preview = 'preview' in ctx .completeopt
140+ preview = 'preview' in ctx .options . get ( ' completeopt' )
140141 for p in proposals :
141142 out .append (dict (
142143 word = p .name ,
@@ -145,6 +146,8 @@ def get_proporsals(source, offset, base=''):
145146 info = p .get_doc () or "No docs." if preview else "" ,
146147 ))
147148
149+ out = _get_autoimport_proposals (out , ctx , source , offset , dot = dot )
150+
148151 return out
149152
150153
@@ -334,17 +337,22 @@ def __init__(self, path, project_path):
334337 update_python_path (self .project .prefs .get ('python_path' , []))
335338
336339 self .resource = None
337- self .completeopt = vim .eval ('&completeopt' )
338340 self .options = dict (
339- goto_definition_cmd = vim .eval ('g:pymode_rope_goto_definition_cmd' )
341+ completeopt = vim .eval ('&completeopt' ),
342+ autoimport = vim .eval ('g:pymode_rope_autoimport' ),
343+ autoimport_modules = vim .eval ('g:pymode_rope_autoimport_modules' ),
344+ goto_definition_cmd = vim .eval ('g:pymode_rope_goto_definition_cmd' ),
340345 )
341- self .encoding = vim .eval ('&encoding' )
342346
343347 if os .path .exists ("%s/__init__.py" % project_path ):
344348 sys .path .append (project_path )
345349
350+ if self .options .get ('autoimport' ) == '1' :
351+ self .generate_autoimport_cache ()
352+
346353 def __enter__ (self ):
347354 self .project .validate (self .project .root )
355+ self .options ['encoding' ] = vim .eval ('&encoding' )
348356 self .resource = libutils .path_to_resource (
349357 self .project , vim .current .buffer .name , 'file' )
350358 return self
@@ -353,11 +361,19 @@ def __exit__(self, t, value, traceback):
353361 if t is None :
354362 self .project .close ()
355363
356- def generate_modules_cache (self , modules ):
357- """ Generate modules cache. """
358- message ("Generate Modules cache ..." )
359- self .importer .generate_modules_cache (modules )
360- self .project .sync ()
364+ def generate_autoimport_cache (self ):
365+ """ Update autoimport cache. """
366+
367+ def _update_cache (importer , modules = None ):
368+
369+ importer .generate_cache ()
370+ if modules :
371+ importer .generate_modules_cache (modules )
372+ importer .project .sync ()
373+
374+ process = multiprocessing .Process (target = _update_cache , args = (
375+ self .importer , self .options .get ('autoimport_modules' )))
376+ process .start ()
361377
362378
363379class ProgressHandler (object ):
@@ -397,6 +413,7 @@ def run(self):
397413
398414 with RopeContext () as ctx :
399415 try :
416+ message (self .__doc__ )
400417 refactor = self .get_refactor (ctx )
401418 input_str = self .get_input_str (refactor , ctx )
402419 if not input_str :
@@ -435,15 +452,24 @@ def get_refactor(ctx):
435452
436453 @staticmethod
437454 def get_input_str (refactor , ctx ):
438- """ Get user input. """
455+ """ Get user input. Skip by default.
439456
440- raise NotImplementedError
457+ :return bool: True
458+
459+ """
460+
461+ return True
441462
442463 @staticmethod
443- def get_changes (refactor , ctx ):
444- """ Get changes. """
464+ def get_changes (refactor , input_str ):
465+ """ Get changes.
445466
446- raise NotImplementedError
467+ :return Changes:
468+
469+ """
470+ progress = ProgressHandler ('Calculate changes ...' )
471+ return refactor .get_changes (
472+ input_str , task_handle = progress .handle )
447473
448474
449475class RenameRefactoring (Refactoring ):
@@ -480,18 +506,6 @@ def get_input_str(self, refactor, ctx):
480506
481507 return newname
482508
483- @staticmethod
484- def get_changes (refactor , input_str ):
485- """ Get changes.
486-
487- :return Changes:
488-
489- """
490-
491- progress = ProgressHandler ('Calculate changes ...' )
492- return refactor .get_changes (
493- input_str , task_handle = progress .handle )
494-
495509
496510class ExtractMethodRefactoring (Refactoring ):
497511
@@ -567,12 +581,6 @@ class InlineRefactoring(Refactoring):
567581
568582 """ Inline variable/method. """
569583
570- @staticmethod
571- def get_input_str (refactor , ctx ):
572- """ Return user input. """
573-
574- return True
575-
576584 @staticmethod
577585 def get_refactor (ctx ):
578586 """ Function description.
@@ -598,12 +606,6 @@ class UseFunctionRefactoring(Refactoring):
598606
599607 """ Use selected function as possible. """
600608
601- @staticmethod
602- def get_input_str (refactor , ctx ):
603- """ Return user input. """
604-
605- return True
606-
607609 @staticmethod
608610 def get_refactor (ctx ):
609611 """ Function description.
@@ -630,12 +632,6 @@ class ModuleToPackageRefactoring(Refactoring):
630632
631633 """ Convert module to package. """
632634
633- @staticmethod
634- def get_input_str (refactor , ctx ):
635- """ Return user input. """
636-
637- return True
638-
639635 @staticmethod
640636 def get_refactor (ctx ):
641637 """ Function description.
@@ -655,6 +651,33 @@ def get_changes(refactor, input_str):
655651 return refactor .get_changes ()
656652
657653
654+ class MoveRefactoring (Refactoring ):
655+
656+ """ Move method/module to other class/global. """
657+
658+ @staticmethod
659+ def get_input_str (refactor , ctx ):
660+ """ Get destination.
661+
662+ :return str:
663+
664+ """
665+
666+ return pymode_input ('Enter destination:' )
667+
668+ @staticmethod
669+ def get_refactor (ctx ):
670+ """ Function description.
671+
672+ :return Rename:
673+
674+ """
675+ _ , offset = get_assist_params ()
676+ if offset == 0 :
677+ offset = None
678+ return move .create_move (ctx .project , ctx .resource , offset )
679+
680+
658681def reload_changes (changes ):
659682 """ Reload changed buffers. """
660683
@@ -693,3 +716,31 @@ def _get_moved_resources(changes):
693716 moved [changes .resource ] = changes .new_resource
694717
695718 return moved
719+
720+
721+ def _get_autoimport_proposals (out , ctx , source , offset , dot = False ):
722+
723+ if not ctx .options .get ('autoimport' ) or dot :
724+ return out
725+
726+ if '.' in codeassist .starting_expression (source , offset ):
727+ return out
728+
729+ current_offset = offset - 1
730+ while current_offset >= 0 and (
731+ source [current_offset ].isalnum () or source [current_offset ] == '_' ):
732+ current_offset -= 1
733+ starting = source [current_offset :offset ]
734+ starting = starting .strip ()
735+
736+ if not starting :
737+ return out
738+
739+ for assist in ctx .importer .import_assist (starting ):
740+ out .append (dict (
741+ abbr = ' : ' .join (assist ),
742+ word = assist [0 ],
743+ kind = 'autoimport:' ,
744+ ))
745+
746+ return out
0 commit comments