RefactoringRope/Refactoring.py

branch
server_client_variant
changeset 166
6fc202183b3b
parent 165
ea41742015af
child 167
3c8e875d0326
equal deleted inserted replaced
165:ea41742015af 166:6fc202183b3b
56 self.__ui = parent 56 self.__ui = parent
57 self.__e5project = e5App().getObject("Project") 57 self.__e5project = e5App().getObject("Project")
58 self.__projectpath = '' 58 self.__projectpath = ''
59 self.__projectLanguage = "" 59 self.__projectLanguage = ""
60 self.__projectopen = False 60 self.__projectopen = False
61 self.__ropeConfig = {}
61 62
62 self.__mainMenu = None 63 self.__mainMenu = None
63 self.__helpDialog = None 64 self.__helpDialog = None
64 self.__progressDialog = None 65 self.__progressDialog = None
65 66
909 """ 910 """
910 Private method to handle a rope error. 911 Private method to handle a rope error.
911 912
912 @param result dictionary containing the error information 913 @param result dictionary containing the error information
913 @type dict 914 @type dict
914 """ 915 @return flag indicating, that the error is to be ignored
916 @rtype bool
917 """
918 if "Error" not in result:
919 return True
920
915 if result["Error"] == 'ModuleSyntaxError': 921 if result["Error"] == 'ModuleSyntaxError':
916 res = E5MessageBox.warning( 922 res = E5MessageBox.warning(
917 self.__ui, result["Title"], 923 self.__ui, result["Title"],
918 self.tr("Rope error: {0}").format( 924 self.tr("Rope error: {0}").format(
919 result["ErrorString"]), 925 result["ErrorString"]),
921 if res == E5MessageBox.Open: 927 if res == E5MessageBox.Open:
922 e5App().getObject("ViewManager").openSourceFile( 928 e5App().getObject("ViewManager").openSourceFile(
923 os.path.join(self.__e5project.getProjectPath(), 929 os.path.join(self.__e5project.getProjectPath(),
924 result["ErrorFile"]), 930 result["ErrorFile"]),
925 result["ErrorLine"]) 931 result["ErrorLine"])
932 elif result["Error"] == "InterruptedTaskError":
933 return True
926 else: 934 else:
927 E5MessageBox.warning( 935 E5MessageBox.warning(
928 self.__ui, result["Title"], 936 self.__ui, result["Title"],
929 self.tr("Rope error: {0}").format( 937 self.tr("Rope error: {0}").format(
930 result["ErrorString"]) 938 result["ErrorString"])
931 ) 939 )
940
941 return False
932 942
933 def __getOffset(self, editor, line, index): 943 def __getOffset(self, editor, line, index):
934 r""" 944 r"""
935 Private method to get the offset into the text treating CRLF as ONE 945 Private method to get the offset into the text treating CRLF as ONE
936 character. 946 character.
1916 the client. 1926 the client.
1917 1927
1918 @param result dictionary containing the result data 1928 @param result dictionary containing the result data
1919 @type dict 1929 @type dict
1920 """ 1930 """
1921 if "Error" in result: 1931 if self.__handleRopeError(result):
1922 self.__handleRopeError(result)
1923 else:
1924 title = result["Title"] 1932 title = result["Title"]
1925 if result["EntriesCount"] > 0: 1933 if result["EntriesCount"] > 0:
1926 from MatchesDialog import MatchesDialog 1934 from MatchesDialog import MatchesDialog
1927 self.dlg = MatchesDialog(self.__ui, True) 1935 self.dlg = MatchesDialog(self.__ui, True)
1928 self.dlg.show() 1936 self.dlg.show()
1929 for occurrence in result["Entries"]: 1937 for occurrence in result["Entries"]:
1930 self.dlg.addEntry( 1938 self.dlg.addEntry(
1931 # resource, lineno, unsure 1939 # file name, lineno, unsure
1932 occurrence[0], occurrence[1], occurrence[2]) 1940 occurrence[0], occurrence[1], occurrence[2])
1933 else: 1941 else:
1934 E5MessageBox.warning( 1942 E5MessageBox.warning(
1935 self.__ui, title, 1943 self.__ui, title,
1936 self.tr("No occurrences found.")) 1944 self.tr("No occurrences found."))
1942 aw = e5App().getObject("ViewManager").activeWindow() 1950 aw = e5App().getObject("ViewManager").activeWindow()
1943 1951
1944 if aw is None: 1952 if aw is None:
1945 return 1953 return
1946 1954
1947 title = self.tr("Find &Definition") 1955 title = self.tr("Find Definition")
1948 1956
1949 if not self.confirmAllBuffersSaved(): 1957 if not self.confirmAllBuffersSaved():
1950 return 1958 return
1951 1959
1952 filename = aw.getFileName() 1960 filename = aw.getFileName()
1953 line, index = aw.getCursorPosition() 1961 line, index = aw.getCursorPosition()
1954 offset = self.__getOffset(aw, line, index) 1962 offset = self.__getOffset(aw, line, index)
1955 1963
1956 import rope.contrib.findit 1964 self.sendJson("QueryDefinition", {
1957 resource = rope.base.libutils.path_to_resource( 1965 "Title": title,
1958 self.__project, filename) 1966 "FileName": filename,
1959 try: 1967 "Offset": offset,
1960 location = rope.contrib.findit.find_definition( 1968 "Source": aw.text(),
1961 self.__project, aw.text(), offset, resource) 1969 "Subcommand": "Query",
1962 except Exception as err: 1970 })
1963 self.handleRopeError(err, title)
1964 return
1965
1966 if location is not None:
1967 from MatchesDialog import MatchesDialog
1968 self.dlg = MatchesDialog(self.__ui, False)
1969 self.dlg.show()
1970 self.dlg.addEntry(location.resource, location.lineno)
1971 else:
1972 E5MessageBox.warning(
1973 self.__ui, title,
1974 self.tr("No matching definition found."))
1975 1971
1976 def gotoDefinition(self, editor): 1972 def gotoDefinition(self, editor):
1977 """ 1973 """
1978 Public slot to find the definition for the word at the cursor position 1974 Public slot to find the definition for the word at the cursor position
1979 and go to it. 1975 and go to it.
1984 """ 1980 """
1985 filename = editor.getFileName() 1981 filename = editor.getFileName()
1986 line, index = editor.getCursorPosition() 1982 line, index = editor.getCursorPosition()
1987 offset = self.__getOffset(editor, line, index) 1983 offset = self.__getOffset(editor, line, index)
1988 1984
1989 import rope.contrib.findit 1985 self.sendJson("QueryDefinition", {
1990 resource = rope.base.libutils.path_to_resource( 1986 "Title": "",
1991 self.__project, filename) 1987 "FileName": filename,
1992 try: 1988 "Offset": offset,
1993 location = rope.contrib.findit.find_definition( 1989 "Source": editor.text(),
1994 self.__project, editor.text(), offset, resource) 1990 "Subcommand": "Goto",
1995 except Exception: 1991 })
1996 # simply ignore them 1992
1997 return 1993 def __queryDefinitionResult(self, result):
1998 1994 """
1999 if location is not None: 1995 Private method to handle the "Query Definition" result sent by
2000 try: 1996 the client.
2001 e5App().getObject("ViewManager").openSourceFile( 1997
2002 location.resource.real_path, location.lineno, addNext=True) 1998 @param result dictionary containing the result data
2003 except TypeError: 1999 @type dict
2004 # backward compatibility; <= 17.03 2000 """
2005 e5App().getObject("ViewManager").openSourceFile( 2001 if result["Subcommand"] == "Query":
2006 location.resource.real_path, location.lineno, next=True) 2002 if self.__handleRopeError(result):
2007 else: 2003 title = result["Title"]
2008 e5App().getObject("UserInterface").statusBar().showMessage( 2004 if "Location" in result:
2009 self.tr('No definition found'), 5000) 2005 location = result["Location"]
2006
2007 from MatchesDialog import MatchesDialog
2008 self.dlg = MatchesDialog(self.__ui, False)
2009 self.dlg.show()
2010 self.dlg.addEntry(location[0], location[1])
2011 # file name, lineno
2012 else:
2013 E5MessageBox.warning(
2014 self.__ui, title,
2015 self.tr("No matching definition found."))
2016 elif result["Subcommand"] == "Goto":
2017 if "Error" not in result:
2018 # ignore errors silently
2019 if "Location" in result:
2020 location = result["Location"]
2021 try:
2022 e5App().getObject("ViewManager").openSourceFile(
2023 location[0], location[1], addNext=True)
2024 except TypeError:
2025 # backward compatibility; <= 17.03
2026 e5App().getObject("ViewManager").openSourceFile(
2027 location[0], location[1], next=True)
2028 else:
2029 e5App().getObject("UserInterface").statusBar().showMessage(
2030 self.tr('No definition found'), 5000)
2010 2031
2011 def __queryImplementations(self): 2032 def __queryImplementations(self):
2012 """ 2033 """
2013 Private slot to handle the Find Implementations action. 2034 Private slot to handle the Find Implementations action.
2014 """ 2035 """
2024 2045
2025 filename = aw.getFileName() 2046 filename = aw.getFileName()
2026 line, index = aw.getCursorPosition() 2047 line, index = aw.getCursorPosition()
2027 offset = self.__getOffset(aw, line, index) 2048 offset = self.__getOffset(aw, line, index)
2028 2049
2029 import rope.contrib.findit 2050 self.sendJson("QueryImplementations", {
2030 from ProgressHandle import ProgressHandle 2051 "Title": title,
2031 resource = rope.base.libutils.path_to_resource( 2052 "FileName": filename,
2032 self.__project, filename) 2053 "Offset": offset,
2033 handle = ProgressHandle(title, True, self.__ui) 2054 })
2034 handle.show() 2055
2035 QApplication.processEvents() 2056 def __queryImplementationsResult(self, result):
2036 try: 2057 """
2037 occurrences = rope.contrib.findit.find_implementations( 2058 Private method to handle the "Query Implementations" result sent by
2038 self.__project, resource, offset, task_handle=handle) 2059 the client.
2039 except Exception as err: 2060
2040 self.handleRopeError(err, title, handle) 2061 @param result dictionary containing the result data
2041 return 2062 @type dict
2042 handle.reset() 2063 """
2043 2064 if self.__handleRopeError(result):
2044 if occurrences: 2065 title = result["Title"]
2045 from MatchesDialog import MatchesDialog 2066 if result["EntriesCount"] > 0:
2046 self.dlg = MatchesDialog(self.__ui, True) 2067 from MatchesDialog import MatchesDialog
2047 self.dlg.show() 2068 self.dlg = MatchesDialog(self.__ui, True)
2048 for occurrence in occurrences: 2069 self.dlg.show()
2049 self.dlg.addEntry( 2070 for occurrence in result["Entries"]:
2050 occurrence.resource, occurrence.lineno, occurrence.unsure) 2071 self.dlg.addEntry(
2051 else: 2072 # file name, lineno, unsure
2052 E5MessageBox.warning( 2073 occurrence[0], occurrence[1], occurrence[2])
2053 self.__ui, title, self.tr("No occurrences found.")) 2074 else:
2075 E5MessageBox.warning(
2076 self.__ui, title, self.tr("No implementations found."))
2054 2077
2055 ##################################################### 2078 #####################################################
2056 ## Various actions 2079 ## Various actions
2057 ##################################################### 2080 #####################################################
2058 2081
2059 def __editConfig(self): 2082 def __editConfig(self):
2060 """ 2083 """
2061 Private slot to open the rope configuration file in an editor. 2084 Private slot to open the rope configuration file in an editor.
2062 """ 2085 """
2063 ropedir = self.__project.ropefolder 2086 ropedir = self.__ropeConfig["RopeFolderName"]
2064 configfile = "" 2087 configfile = ""
2065 if ropedir is not None: 2088 if ropedir and os.path.exists(ropedir):
2066 configfile = os.path.join(ropedir.real_path, "config.py") 2089 configfile = os.path.join(ropedir, "config.py")
2067 if os.path.exists(configfile): 2090 if os.path.exists(configfile):
2068 from QScintilla.MiniEditor import MiniEditor 2091 from QScintilla.MiniEditor import MiniEditor
2069 self.__editor = MiniEditor(configfile) 2092 self.__editor = MiniEditor(configfile)
2070 self.__editor.show() 2093 self.__editor.show()
2071 self.__editor.editorSaved.connect(self.__configChanged) 2094 self.__editor.editorSaved.connect(self.__configChanged)
2112 """ 2135 """
2113 Private slot to show help about the refactorings offered by Rope. 2136 Private slot to show help about the refactorings offered by Rope.
2114 """ 2137 """
2115 if self.__helpDialog is None: 2138 if self.__helpDialog is None:
2116 from HelpDialog import HelpDialog 2139 from HelpDialog import HelpDialog
2117 if sys.version_info[0] >= 3:
2118 directory = 'rope_py3'
2119 else:
2120 directory = 'rope_py2'
2121 helpfile = os.path.join(os.path.dirname(__file__),
2122 directory, "rope", "docs", "overview.txt")
2123 self.__helpDialog = \ 2140 self.__helpDialog = \
2124 HelpDialog(self.tr("Help about rope refactorings"), 2141 HelpDialog(self.tr("Help about rope refactorings"),
2125 helpfile) 2142 self.__ropeConfig["RopeHelpFile"])
2126 self.__helpDialog.show() 2143 self.__helpDialog.show()
2127 2144
2128 def __performSOA(self): 2145 def __performSOA(self):
2129 """ 2146 """
2130 Private slot to perform SOA on all modules. 2147 Private slot to perform SOA on all modules.
2134 self.__ui, 2151 self.__ui,
2135 title, 2152 title,
2136 self.tr("""This action might take some time. """ 2153 self.tr("""This action might take some time. """
2137 """Do you really want to perform SOA?""")) 2154 """Do you really want to perform SOA?"""))
2138 if res: 2155 if res:
2139 from ProgressHandle import ProgressHandle 2156
2140 handle = ProgressHandle(title, True, self.__ui) 2157 self.sendJson("PerformSoa", {
2141 handle.show() 2158 "Title": title,
2142 QApplication.processEvents() 2159 })
2143 try: 2160
2144 rope.base.libutils.analyze_modules( 2161 def __soaFinished(self, result):
2145 self.__project, task_handle=handle) 2162 """
2146 handle.reset() 2163 Private method to handle the "Soa Finished" result sent by
2147 E5MessageBox.information( 2164 the client.
2148 self.__ui, 2165
2149 title, 2166 @param result dictionary containing the result data
2150 self.tr("""Static object analysis (SOA) done. """ 2167 @type dict
2151 """SOA database updated.""")) 2168 """
2152 except Exception as err: 2169 if self.__handleRopeError(result):
2153 self.handleRopeError(err, title, handle) 2170 title = result["Title"]
2171
2172 E5MessageBox.information(
2173 self.__ui,
2174 title,
2175 self.tr("""Static object analysis (SOA) done. """
2176 """SOA database updated."""))
2154 2177
2155 ################################################################## 2178 ##################################################################
2156 ## methods below are private utility methods 2179 ## methods below are private utility methods
2157 ################################################################## 2180 ##################################################################
2158 2181
2161 Private method to get the name of the rope configuration file. 2184 Private method to get the name of the rope configuration file.
2162 2185
2163 @return name of the rope configuration file (string) 2186 @return name of the rope configuration file (string)
2164 """ 2187 """
2165 configfile = None 2188 configfile = None
2166 if self.__project is not None: 2189 if self.__ropeConfig:
2167 ropedir = self.__project.ropefolder 2190 ropedir = self.__ropeConfig["RopeFolderName"]
2168 if ropedir is not None: 2191 if ropedir:
2169 configfile = os.path.join(ropedir.real_path, "config.py") 2192 configfile = os.path.join(ropedir, "config.py")
2170 if not os.path.exists(configfile): 2193 if not os.path.exists(configfile):
2171 configfile = None 2194 configfile = None
2172 return configfile 2195 return configfile
2173 2196
2174 def __configChanged(self): 2197 def __configChanged(self):
2175 """ 2198 """
2176 Private slot called, when the rope config file has changed. 2199 Private slot called, when the rope config file has changed.
2177 """ 2200 """
2178 import rope.base.project 2201 self.sendJson("ConfigChanged", {})
2179 self.__project.close()
2180 self.__project = rope.base.project.Project(
2181 self.__projectpath, fscommands=self.__fsCommands)
2182 2202
2183 def __defaultConfig(self): 2203 def __defaultConfig(self):
2184 """ 2204 """
2185 Private slot to return the contents of rope's default configuration. 2205 Private slot to return the contents of rope's default configuration.
2186 2206
2187 @return string containing the source of rope's default 2207 @return string containing the source of rope's default
2188 configuration (string) 2208 configuration (string)
2189 """ 2209 """
2190 if self.__project is not None: 2210 if self.__ropeConfig and "DefaultConfig" in self.__ropeConfig:
2191 return self.__project._default_config() 2211 return self.__ropeConfig["DefaultConfig"]
2192 else: 2212 else:
2193 return "" 2213 return ""
2194 2214
2195 ################################################################## 2215 ##################################################################
2196 ## methods below are public utility methods 2216 ## methods below are public utility methods
2250 self.stopClient() 2270 self.stopClient()
2251 2271
2252 self.__projectopen = False 2272 self.__projectopen = False
2253 self.__projectpath = '' 2273 self.__projectpath = ''
2254 self.__projectLanguage = "" 2274 self.__projectLanguage = ""
2275 self.__ropeConfig = {}
2255 2276
2256 # TODO: delete this or move to client 2277 # TODO: delete this or move to client
2257 ## def getProject(self): 2278 ## def getProject(self):
2258 ## """ 2279 ## """
2259 ## Public method to get a reference to the rope project object. 2280 ## Public method to get a reference to the rope project object.
2283 """ 2304 """
2284 res = e5App().getObject("ViewManager").checkAllDirty() 2305 res = e5App().getObject("ViewManager").checkAllDirty()
2285 self.sendJson("Validate", {}) 2306 self.sendJson("Validate", {})
2286 return res 2307 return res
2287 2308
2309 # TODO: port this
2288 def refreshEditors(self, changes): 2310 def refreshEditors(self, changes):
2289 """ 2311 """
2290 Public method to refresh modified editors. 2312 Public method to refresh modified editors.
2291 2313
2292 @param changes reference to the ChangeSet object 2314 @param changes reference to the ChangeSet object
2293 (rope.base.change.ChangeSet) 2315 (rope.base.change.ChangeSet)
2294 """ 2316 """
2295 vm = e5App().getObject("ViewManager") 2317 vm = e5App().getObject("ViewManager")
2296 2318
2297 changedFiles = [] 2319 changedFiles = []
2298 for resource in changes.get_changed_resources(): 2320 # for resource in changes.get_changed_resources():
2299 if not resource.is_folder(): 2321 # if not resource.is_folder():
2300 changedFiles.append(resource.real_path) 2322 # changedFiles.append(resource.real_path)
2301 2323
2302 openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()] 2324 openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()]
2303 2325
2304 for file in changedFiles: 2326 for file in changedFiles:
2305 normfile = Utilities.normcasepath(file) 2327 normfile = Utilities.normcasepath(file)
2318 Public slot to report some changed sources. 2340 Public slot to report some changed sources.
2319 2341
2320 @param filename file name of the changed source (string) 2342 @param filename file name of the changed source (string)
2321 @param oldSource source code before the change (string) 2343 @param oldSource source code before the change (string)
2322 """ 2344 """
2323 if self.__project and self.__e5project.isProjectFile(filename): 2345 if self.__e5project.isOpen() and \
2324 try: 2346 self.__e5project.isProjectFile(filename):
2325 rope.base.libutils.report_change( 2347 self.sendJson("ReportChanged", {
2326 self.__project, filename, oldSource) 2348 "FileName": filename,
2327 except RuntimeError: 2349 "OldSource": oldSource,
2328 # this could come from trying to do PyQt4/PyQt5 mixed stuff 2350 })
2329 # simply ignore it
2330 pass
2331 2351
2332 ####################################################################### 2352 #######################################################################
2333 ## Methods below handle the network connection 2353 ## Methods below handle the network connection
2334 ####################################################################### 2354 #######################################################################
2335 2355
2343 @param method requested method name 2363 @param method requested method name
2344 @type str 2364 @type str
2345 @param params dictionary with method specific parameters 2365 @param params dictionary with method specific parameters
2346 @type dict 2366 @type dict
2347 """ 2367 """
2348 if method == "pong": 2368 if method == "Config":
2349 pass 2369 self.__ropeConfig = params
2370 # keys: RopeFolderName, DefaultConfig
2350 2371
2351 elif method == "ClientException": 2372 elif method == "ClientException":
2352 if params["ExceptionType"] == "ProtocolError": 2373 if params["ExceptionType"] == "ProtocolError":
2353 E5MessageBox.critical( 2374 E5MessageBox.critical(
2354 None, 2375 None,
2399 if self.__progressDialog is not None: 2420 if self.__progressDialog is not None:
2400 self.__progressDialog.reset() 2421 self.__progressDialog.reset()
2401 2422
2402 elif method == "QueryReferencesResult": 2423 elif method == "QueryReferencesResult":
2403 self.__queryReferencesResult(params) 2424 self.__queryReferencesResult(params)
2425
2426 elif method == "QueryDefinitionResult":
2427 self.__queryDefinitionResult(params)
2428
2429 elif method == "QueryImplementationsResult":
2430 self.__queryImplementationsResult(params)
2431
2432 elif method == "SoaFinished":
2433 self.__soaFinished(params)
2404 2434
2405 def __startRefactoringClient(self, interpreter): 2435 def __startRefactoringClient(self, interpreter):
2406 """ 2436 """
2407 Private method to start the refactoring client. 2437 Private method to start the refactoring client.
2408 2438

eric ide

mercurial