eric6/Plugins/PluginSyntaxChecker.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7199
c71bd6f21748
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2007 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the Syntax Checker plugin.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13
14 from PyQt5.QtCore import QObject
15
16 from E5Gui.E5Action import E5Action
17 from E5Gui.E5Application import e5App
18 from eric6config import getConfig
19
20 from Project.ProjectBrowserModel import ProjectBrowserFileItem
21
22 import Preferences
23 import UI.Info
24
25 # Start-Of-Header
26 name = "Syntax Checker Plugin"
27 author = "Detlev Offenbach <detlev@die-offenbachs.de>"
28 autoactivate = True
29 deactivateable = True
30 version = UI.Info.VersionOnly
31 className = "SyntaxCheckerPlugin"
32 packageName = "__core__"
33 shortDescription = "Show the Syntax Checker dialog."
34 longDescription = """This plugin implements the Syntax Checker dialog.""" \
35 """ Syntax Checker is used to check Python source files for correct""" \
36 """ syntax."""
37 pyqtApi = 2
38 python2Compatible = True
39 # End-Of-Header
40
41 error = ""
42
43
44 class SyntaxCheckerPlugin(QObject):
45 """
46 Class implementing the Syntax Checker plugin.
47 """
48 def __init__(self, ui):
49 """
50 Constructor
51
52 @param ui reference to the user interface object (UI.UserInterface)
53 """
54 super(SyntaxCheckerPlugin, self).__init__(ui)
55 self.__ui = ui
56 self.__initialize()
57
58 from Plugins.CheckerPlugins.SyntaxChecker.SyntaxCheckService import \
59 SyntaxCheckService
60 self.syntaxCheckService = SyntaxCheckService()
61 e5App().registerObject("SyntaxCheckService", self.syntaxCheckService)
62
63 ericPath = getConfig('ericDir')
64 path = os.path.join(ericPath, 'Plugins', 'CheckerPlugins',
65 'SyntaxChecker')
66
67 self.syntaxCheckService.addLanguage(
68 'Python2', 'Python2', path, 'SyntaxCheck',
69 self.__getPythonOptions,
70 lambda: Preferences.getPython("PythonExtensions"),
71 self.__translateSyntaxCheck,
72 self.syntaxCheckService.serviceErrorPy2)
73
74 self.syntaxCheckService.addLanguage(
75 'Python3', 'Python3', path, 'SyntaxCheck',
76 self.__getPythonOptions,
77 lambda: Preferences.getPython("Python3Extensions"),
78 self.__translateSyntaxCheck,
79 self.syntaxCheckService.serviceErrorPy3)
80
81 # Jasy isn't yet compatible to Python2
82 self.syntaxCheckService.addLanguage(
83 'JavaScript', 'Python3', path,
84 'jsCheckSyntax',
85 lambda: [], # No options
86 lambda: ['.js'],
87 lambda fn, problems:
88 self.syntaxCheckService.syntaxChecked.emit(fn, problems),
89 self.syntaxCheckService.serviceErrorJavaScript)
90
91 def __initialize(self):
92 """
93 Private slot to (re)initialize the plugin.
94 """
95 self.__projectAct = None
96 self.__projectSyntaxCheckerDialog = None
97
98 self.__projectBrowserAct = None
99 self.__projectBrowserMenu = None
100 self.__projectBrowserSyntaxCheckerDialog = None
101
102 self.__editors = []
103 self.__editorAct = None
104 self.__editorSyntaxCheckerDialog = None
105
106 def __getPythonOptions(self):
107 """
108 Private methode to determine the syntax check options.
109
110 @return state of checkFlakes and ignoreStarImportWarnings (bool, bool)
111 """
112 checkFlakes = Preferences.getFlakes("IncludeInSyntaxCheck")
113 ignoreStarImportWarnings = Preferences.getFlakes(
114 "IgnoreStarImportWarnings")
115 return checkFlakes, ignoreStarImportWarnings
116
117 def __translateSyntaxCheck(self, fn, problems):
118 """
119 Private slot to translate the resulting messages.
120
121 If checkFlakes is True, warnings contains a list of strings containing
122 the warnings (marker, file name, line number, message)
123 The values are only valid, if nok is False.
124
125 @param fn filename of the checked file (str)
126 @param problems dictionary with the keys 'error' and 'warnings' which
127 hold a list containing details about the error/ warnings
128 (file name, line number, column, codestring (only at syntax
129 errors), the message, a list with arguments for the message)
130 """
131 from CheckerPlugins.SyntaxChecker.pyflakes.translations import \
132 getTranslatedFlakesMessage
133 warnings = problems.get('warnings', [])
134 for warning in warnings:
135 # Translate messages
136 msg_args = warning.pop()
137 warning[4] = getTranslatedFlakesMessage(warning[4], msg_args)
138
139 problems['warnings'] = warnings
140 self.syntaxCheckService.syntaxChecked.emit(fn, problems)
141
142 def activate(self):
143 """
144 Public method to activate this plugin.
145
146 @return tuple of None and activation status (boolean)
147 """
148 menu = e5App().getObject("Project").getMenu("Checks")
149 if menu:
150 self.__projectAct = E5Action(
151 self.tr('Check Syntax'),
152 self.tr('&Syntax...'), 0, 0,
153 self, 'project_check_syntax')
154 self.__projectAct.setStatusTip(
155 self.tr('Check syntax.'))
156 self.__projectAct.setWhatsThis(self.tr(
157 """<b>Check Syntax...</b>"""
158 """<p>This checks Python files for syntax errors.</p>"""
159 ))
160 self.__projectAct.triggered.connect(self.__projectSyntaxCheck)
161 e5App().getObject("Project").addE5Actions([self.__projectAct])
162 menu.addAction(self.__projectAct)
163
164 self.__editorAct = E5Action(
165 self.tr('Check Syntax'),
166 self.tr('&Syntax...'), 0, 0,
167 self, "")
168 self.__editorAct.setWhatsThis(self.tr(
169 """<b>Check Syntax...</b>"""
170 """<p>This checks Python files for syntax errors.</p>"""
171 ))
172 self.__editorAct.triggered.connect(self.__editorSyntaxCheck)
173
174 e5App().getObject("Project").showMenu.connect(self.__projectShowMenu)
175 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\
176 .showMenu.connect(self.__projectBrowserShowMenu)
177 e5App().getObject("ViewManager").editorOpenedEd.connect(
178 self.__editorOpened)
179 e5App().getObject("ViewManager").editorClosedEd.connect(
180 self.__editorClosed)
181
182 for editor in e5App().getObject("ViewManager").getOpenEditors():
183 self.__editorOpened(editor)
184
185 return None, True
186
187 def deactivate(self):
188 """
189 Public method to deactivate this plugin.
190 """
191 e5App().getObject("Project").showMenu.disconnect(
192 self.__projectShowMenu)
193 e5App().getObject("ProjectBrowser").getProjectBrowser("sources")\
194 .showMenu.disconnect(self.__projectBrowserShowMenu)
195 e5App().getObject("ViewManager").editorOpenedEd.disconnect(
196 self.__editorOpened)
197 e5App().getObject("ViewManager").editorClosedEd.disconnect(
198 self.__editorClosed)
199
200 menu = e5App().getObject("Project").getMenu("Checks")
201 if menu:
202 menu.removeAction(self.__projectAct)
203
204 if self.__projectBrowserMenu:
205 if self.__projectBrowserAct:
206 self.__projectBrowserMenu.removeAction(
207 self.__projectBrowserAct)
208
209 for editor in self.__editors:
210 editor.showMenu.disconnect(self.__editorShowMenu)
211 menu = editor.getMenu("Checks")
212 if menu is not None:
213 menu.removeAction(self.__editorAct)
214
215 self.__initialize()
216
217 def __projectShowMenu(self, menuName, menu):
218 """
219 Private slot called, when the the project menu or a submenu is
220 about to be shown.
221
222 @param menuName name of the menu to be shown (string)
223 @param menu reference to the menu (QMenu)
224 """
225 if menuName == "Checks" and self.__projectAct is not None:
226 self.__projectAct.setEnabled(
227 e5App().getObject("Project").getProjectLanguage() in
228 self.syntaxCheckService.getLanguages())
229
230 def __projectBrowserShowMenu(self, menuName, menu):
231 """
232 Private slot called, when the the project browser menu or a submenu is
233 about to be shown.
234
235 @param menuName name of the menu to be shown (string)
236 @param menu reference to the menu (QMenu)
237 """
238 if menuName == "Checks" and \
239 e5App().getObject("Project").getProjectLanguage() in \
240 self.syntaxCheckService.getLanguages():
241 self.__projectBrowserMenu = menu
242 if self.__projectBrowserAct is None:
243 self.__projectBrowserAct = E5Action(
244 self.tr('Check Syntax'),
245 self.tr('&Syntax...'), 0, 0,
246 self, "")
247 self.__projectBrowserAct.setWhatsThis(self.tr(
248 """<b>Check Syntax...</b>"""
249 """<p>This checks Python files for syntax errors.</p>"""
250 ))
251 self.__projectBrowserAct.triggered.connect(
252 self.__projectBrowserSyntaxCheck)
253 if self.__projectBrowserAct not in menu.actions():
254 menu.addAction(self.__projectBrowserAct)
255
256 def __projectSyntaxCheck(self):
257 """
258 Private slot used to check the project files for syntax errors.
259 """
260 project = e5App().getObject("Project")
261 project.saveAllScripts()
262 ppath = project.getProjectPath()
263 extensions = tuple(self.syntaxCheckService.getExtensions())
264 files = [os.path.join(ppath, file)
265 for file in project.pdata["SOURCES"]
266 if file.endswith(extensions)]
267
268 from CheckerPlugins.SyntaxChecker.SyntaxCheckerDialog import \
269 SyntaxCheckerDialog
270 self.__projectSyntaxCheckerDialog = SyntaxCheckerDialog()
271 self.__projectSyntaxCheckerDialog.show()
272 self.__projectSyntaxCheckerDialog.prepare(files, project)
273
274 def __projectBrowserSyntaxCheck(self):
275 """
276 Private method to handle the syntax check context menu action of the
277 project sources browser.
278 """
279 browser = e5App().getObject("ProjectBrowser").getProjectBrowser(
280 "sources")
281 if browser.getSelectedItemsCount([ProjectBrowserFileItem]) > 1:
282 fn = []
283 for itm in browser.getSelectedItems([ProjectBrowserFileItem]):
284 fn.append(itm.fileName())
285 else:
286 itm = browser.model().item(browser.currentIndex())
287 try:
288 fn = itm.fileName()
289 except AttributeError:
290 fn = itm.dirName()
291
292 from CheckerPlugins.SyntaxChecker.SyntaxCheckerDialog import \
293 SyntaxCheckerDialog
294 self.__projectBrowserSyntaxCheckerDialog = SyntaxCheckerDialog()
295 self.__projectBrowserSyntaxCheckerDialog.show()
296 self.__projectBrowserSyntaxCheckerDialog.start(fn)
297
298 def __editorOpened(self, editor):
299 """
300 Private slot called, when a new editor was opened.
301
302 @param editor reference to the new editor (QScintilla.Editor)
303 """
304 menu = editor.getMenu("Checks")
305 if menu is not None:
306 menu.addAction(self.__editorAct)
307 editor.showMenu.connect(self.__editorShowMenu)
308 self.__editors.append(editor)
309
310 def __editorClosed(self, editor):
311 """
312 Private slot called, when an editor was closed.
313
314 @param editor reference to the editor (QScintilla.Editor)
315 """
316 try:
317 self.__editors.remove(editor)
318 except ValueError:
319 pass
320
321 def __editorShowMenu(self, menuName, menu, editor):
322 """
323 Private slot called, when the the editor context menu or a submenu is
324 about to be shown.
325
326 @param menuName name of the menu to be shown (string)
327 @param menu reference to the menu (QMenu)
328 @param editor reference to the editor
329 """
330 if menuName == "Checks":
331 if self.__editorAct not in menu.actions():
332 menu.addAction(self.__editorAct)
333 self.__editorAct.setEnabled(
334 editor.getLanguage() in self.syntaxCheckService.getLanguages())
335
336 def __editorSyntaxCheck(self):
337 """
338 Private slot to handle the syntax check context menu action of the
339 editors.
340 """
341 editor = e5App().getObject("ViewManager").activeWindow()
342 if editor is not None:
343 from CheckerPlugins.SyntaxChecker.SyntaxCheckerDialog import \
344 SyntaxCheckerDialog
345 self.__editorSyntaxCheckerDialog = SyntaxCheckerDialog()
346 self.__editorSyntaxCheckerDialog.show()
347 if editor.isJavascriptFile():
348 unnamed = "Unnamed.js"
349 else:
350 unnamed = "Unnamed.py"
351 self.__editorSyntaxCheckerDialog.start(
352 editor.getFileName() or unnamed, editor.text())

eric ide

mercurial