eric6/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheckService.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7164
6da6a0a5a448
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheckService.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2013 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+# pylint: disable=C0103
+
+"""
+Module implementing an interface to add different languages to do a syntax
+check.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import QObject, pyqtSignal
+
+from E5Gui.E5Application import e5App
+from Utilities import determinePythonVersion
+
+
+class SyntaxCheckService(QObject):
+    """
+    Implement the syntax check service.
+    
+    Plugins can add other languages to the syntax check by calling addLanguage
+    and support of an extra checker module on the client side which has to
+    connect directly to the background service.
+    
+    @signal syntaxChecked(str, dict) emitted when the syntax check was done for
+        one file
+    @signal batchFinished() emitted when a syntax check batch is done
+    @signal error(str, str) emitted in case of an error
+    """
+    syntaxChecked = pyqtSignal(str, dict)
+    batchFinished = pyqtSignal()
+    error = pyqtSignal(str, str)
+    
+    def __init__(self):
+        """
+        Constructor
+        """
+        super(SyntaxCheckService, self).__init__()
+        self.backgroundService = e5App().getObject("BackgroundService")
+        self.__supportedLanguages = {}
+        
+        self.queuedBatches = []
+        self.batchesFinished = True
+
+    def __determineLanguage(self, filename, source):
+        """
+        Private methode to determine the language of the file.
+        
+        @param filename of the sourcefile (str)
+        @param source code of the file (str)
+        @return language of the file or None if not found (str or None)
+        """
+        pyVer = determinePythonVersion(filename, source)
+        if pyVer:
+            return 'Python{0}'.format(pyVer)
+        
+        for lang, (_env, _getArgs, getExt) in \
+                self.__supportedLanguages.items():
+            if filename.endswith(tuple(getExt())):
+                return lang
+        
+        return None
+
+    def addLanguage(
+            self, lang, env, path, module, getArgs, getExt, callback, onError):
+        """
+        Public method to register a new language to the supported languages.
+        
+        @param lang new language to check syntax (str)
+        @param env the environment in which the checker is implemented (str)
+        @param path full path to the module (str)
+        @param module name to import (str)
+        @param getArgs function to collect the required arguments to call the
+            syntax checker on client side (function)
+        @param getExt function that returns the supported file extensions of
+            the syntax checker (function)
+        @param callback function on service response (function)
+        @param onError callback function if client or service isn't available
+            (function)
+        """
+        self.__supportedLanguages[lang] = env, getArgs, getExt
+        # Connect to the background service
+        self.backgroundService.serviceConnect(
+            '{0}Syntax'.format(lang), env, path, module, callback, onError,
+            onBatchDone=self.batchJobDone)
+
+    def getLanguages(self):
+        """
+        Public method to return the supported language names.
+        
+        @return list of languanges supported (list of str)
+        """
+        return list(self.__supportedLanguages.keys())
+
+    def removeLanguage(self, lang):
+        """
+        Public method to remove the language from syntax check.
+        
+        @param lang language to remove (str)
+        """
+        self.__supportedLanguages.pop(lang, None)
+        self.backgroundService.serviceDisconnect(
+            '{0}Syntax'.format(lang), lang)
+
+    def getExtensions(self):
+        """
+        Public method to return all supported file extensions for the
+        syntax checker dialog.
+        
+        @return set of all supported file extensions (set of str)
+        """
+        extensions = set()
+        for _env, _getArgs, getExt in self.__supportedLanguages.values():
+            for ext in getExt():
+                extensions.add(ext)
+        return extensions
+
+    def syntaxCheck(self, lang, filename, source):
+        """
+        Public method to prepare a syntax check of one source file.
+        
+        @param lang language of the file or None to determine by internal
+            algorithm (str or None)
+        @param filename source filename (string)
+        @param source string containing the code to check (string)
+        """
+        if not lang:
+            lang = self.__determineLanguage(filename, source)
+        if lang not in self.getLanguages():
+            return
+        data = [source]
+        # Call the getArgs function to get the required arguments
+        env, args, getExt = self.__supportedLanguages[lang]
+        data.extend(args())
+        self.backgroundService.enqueueRequest(
+            '{0}Syntax'.format(lang), env, filename, data)
+    
+    def syntaxBatchCheck(self, argumentsList):
+        """
+        Public method to prepare a syntax check on multiple source files.
+        
+        @param argumentsList list of arguments tuples with each tuple
+            containing filename and source (string, string)
+        """
+        data = {
+        }
+        for lang in self.getLanguages():
+            data[lang] = []
+        
+        for filename, source in argumentsList:
+            lang = self.__determineLanguage(filename, source)
+            if lang not in self.getLanguages():
+                continue
+            else:
+                jobData = [source]
+                # Call the getArgs function to get the required arguments
+                args = self.__supportedLanguages[lang][1]
+                jobData.extend(args())
+                data[lang].append((filename, jobData))
+        
+        self.queuedBatches = []
+        for lang in self.getLanguages():
+            if data[lang]:
+                self.queuedBatches.append(lang)
+                env = self.__supportedLanguages[lang][0]
+                self.backgroundService.enqueueRequest(
+                    'batch_{0}Syntax'.format(lang), env, "", data[lang])
+                self.batchesFinished = False
+    
+    def cancelSyntaxBatchCheck(self):
+        """
+        Public method to cancel all batch jobs.
+        """
+        for lang in self.getLanguages():
+            env = self.__supportedLanguages[lang][0]
+            self.backgroundService.requestCancel(
+                'batch_{0}Syntax'.format(lang), env)
+    
+    def __serviceError(self, fn, msg):
+        """
+        Private slot handling service errors.
+        
+        @param fn file name (string)
+        @param msg message text (string)
+        """
+        self.error.emit(fn, msg)
+    
+    def serviceErrorPy2(self, fx, lang, fn, msg):
+        """
+        Public method handling service errors for Python 2.
+        
+        @param fx service name (string)
+        @param lang language (string)
+        @param fn file name (string)
+        @param msg message text (string)
+        """
+        if fx in ['Python2Syntax', 'batch_Python2Syntax']:
+            if fx == 'Python2Syntax':
+                self.__serviceError(fn, msg)
+            else:
+                self.__serviceError(self.tr("Python 2 batch check"), msg)
+                self.batchJobDone(fx, lang)
+    
+    def serviceErrorPy3(self, fx, lang, fn, msg):
+        """
+        Public method handling service errors for Python 2.
+        
+        @param fx service name (string)
+        @param lang language (string)
+        @param fn file name (string)
+        @param msg message text (string)
+        """
+        if fx in ['Python3Syntax', 'batch_Python3Syntax']:
+            if fx == 'Python3Syntax':
+                self.__serviceError(fn, msg)
+            else:
+                self.__serviceError(self.tr("Python 3 batch check"), msg)
+                self.batchJobDone(fx, lang)
+    
+    def serviceErrorJavaScript(self, fx, lang, fn, msg):
+        """
+        Public method handling service errors for JavaScript.
+        
+        @param fx service name (string)
+        @param lang language (string)
+        @param fn file name (string)
+        @param msg message text (string)
+        """
+        if fx in ['JavaScriptSyntax', 'batch_JavaScriptSyntax']:
+            if fx == 'JavaScriptSyntax':
+                self.__serviceError(fn, msg)
+            else:
+                self.__serviceError(self.tr("JavaScript batch check"), msg)
+                self.batchJobDone(fx, lang)
+    
+    def batchJobDone(self, fx, lang):
+        """
+        Public slot handling the completion of a batch job.
+        
+        @param fx service name (string)
+        @param lang language (string)
+        """
+        if fx in ['Python2Syntax', 'batch_Python2Syntax',
+                  'Python3Syntax', 'batch_Python3Syntax',
+                  'JavaScriptSyntax', 'batch_JavaScriptSyntax']:
+            if lang in self.queuedBatches:
+                self.queuedBatches.remove(lang)
+            # prevent sending the signal multiple times
+            if len(self.queuedBatches) == 0 and not self.batchesFinished:
+                self.batchFinished.emit()
+                self.batchesFinished = True

eric ide

mercurial