1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
import getopt
import sys
from collections import namedtuple
from rope.base.project import Project
from rope.contrib import codeassist
from rope.contrib import autoimport
import os, re
import pkg_resources
from distutils.version import LooseVersion as V
BUILDER_EXTENSION = '.ui'
ROPE_VERSION = ''
CompletionItem = namedtuple('CompletionItem', 'name info type scope location')
def new_completion_item(**i):
return CompletionItem('_','_','_','_','_')._replace(**i)
class BuilderComplete(object):
def __init__(self, project_path, resource_path, source_code, code_point, project_files):
self.code_point = code_point
self.src_dir = os.path.join(project_path, os.path.dirname(resource_path))
self.source_code = source_code
#grab all of the ui files from the project source files
self.builder_files = [f for f in project_files if f.endswith(BUILDER_EXTENSION) and os.path.exists(f)]
#suggest completions whenever someone types get_object(' in some form
self.should_autocompelte_re = re.compile(r'get_object\s*\(\s*[\'"](\w*)$')
def get_proposals(self, skip_verify=False):
""" return possible completions based on objects in ui files.
skip_verify=False will check to make sure preceeding the
current cursor position is something of the form 'get_object("' """
starting_word = ""
if skip_verify is False:
curr_line = self.source_code[:self.code_point].split('\n')[-1]
reg_search = self.should_autocompelte_re.search(curr_line)
if not reg_search:
return []
starting_word = reg_search.groups()[0]
possible_completions = self.get_all_builder_objects(self.builder_files)
#return only the ones with valid start
return [item for item in possible_completions if item.name.startswith(starting_word)]
def get_all_builder_objects(self, file_list):
""" go through every file in file_list and extract all <object/>
tags and return their ids """
from xml.dom import minidom
ret = []
for f in file_list:
md = minidom.parse(f)
for e in md.getElementsByTagName('object'):
item = new_completion_item(name=e.getAttribute('id'), scope='external', location=f, type='builder_object')
ret.append(item)
return ret
class RopeComplete(object):
def __init__(self, project_path, source_code, resource_path, code_point):
self.project = Project(project_path)
self.project.pycore._init_python_files()
self.resource = self.project.get_resource(resource_path)
self.source_code = source_code
self.code_point = code_point
def __del__(self):
self.project.close()
def get_proposals(self):
ret = []
proposals = codeassist.code_assist(self.project, self.source_code, self.code_point, resource=self.resource, maxfixes=10)
proposals = codeassist.sorted_proposals(proposals)
if V(ROPE_VERSION) <= V('0.9.2'):
for proposal in proposals:
ret.append(new_completion_item(name=proposal.name, scope=proposal.kind, type=proposal.type))
else:
for proposal in proposals:
ret.append(new_completion_item(name=proposal.name, scope=proposal.scope, type=proposal.type))
return ret
def get_calltip(self):
calltip = codeassist.get_doc(self.project, self.source_code, self.code_point, resource=self.resource, maxfixes=10)
return calltip
def parse_arguments(args):
""" Returns a dictionary containing all the parsed args
and a string containing the source_code """
ret = {}
options, remainder = getopt.getopt(args, 'o:p:s:r:f:b:')
for opt, arg in options:
if opt in ('-o', '--option'):
option_arg = arg
elif opt in ('-p', '--project'):
project_arg = arg
elif opt == '-s':
source_code_arg = arg
elif opt == '-r':
res_arg = arg
elif opt == '-f':
offset_arg = arg
elif opt == '-b':
builder_files_arg = arg
ret['option'] = option_arg;
ret['project_path'] = str.replace(project_arg, 'file://', '') if project_arg.startswith('file://') else project_arg
ret['resource_path'] = os.path.relpath(res_arg, ret['project_path'])
if ret['option'] != 'calltip':
ret['project_files'] = builder_files_arg.split('|')
ret['position'] = int(offset_arg)
input = open(source_code_arg, 'r')
ret['source_code'] = input.read()
return ret
if __name__ == '__main__':
try:
ROPE_VERSION = pkg_resources.get_distribution('rope').version
except:
print '|Missing python-rope module!|.|.|.|.|'
sys.exit(1)
try:
args = parse_arguments(sys.argv[1:])
suggestions = []
calltip = ''
if args['option'] == 'autocomplete':
#get any completions Rope offers us
comp = RopeComplete(args['project_path'], args['source_code'], args['resource_path'], args['position'])
suggestions.extend(comp.get_proposals())
#see if we've typed get_object(' and if so, offer completions based upon the builder ui files in the project
comp = BuilderComplete(args['project_path'], args['resource_path'], args['source_code'], args['position'], args['project_files'])
suggestions.extend(comp.get_proposals())
elif args['option'] == 'calltip':
calltip_obj = RopeComplete(args['project_path'], args['source_code'], args['resource_path'], args['position'])
calltip = calltip_obj.get_calltip()
for s in suggestions:
print "|{0}|{1}|{2}|{3}|{4}|".format(s.name, s.scope, s.type, s.location, s.info)
print calltip
except:
pass
|