Continued implementing support for EditorConfig.

Fri, 02 Feb 2018 19:42:01 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 02 Feb 2018 19:42:01 +0100
changeset 6101
b854a825d483
parent 6100
63d6350f3a34
child 6102
a5b9f6a38faf

Continued implementing support for EditorConfig.

QScintilla/Editor.py file | annotate | diff | comparison | revisions
QScintilla/MiniEditor.py file | annotate | diff | comparison | revisions
eric6_browser.py file | annotate | diff | comparison | revisions
eric6_configure.py file | annotate | diff | comparison | revisions
eric6_editor.py file | annotate | diff | comparison | revisions
eric6_webbrowser.py file | annotate | diff | comparison | revisions
--- a/QScintilla/Editor.py	Thu Feb 01 19:32:19 2018 +0100
+++ b/QScintilla/Editor.py	Fri Feb 02 19:42:01 2018 +0100
@@ -3037,6 +3037,10 @@
         @param backup flag indicating to save a backup (boolean)
         @return flag indicating success (boolean)
         """
+        # TODO: editorconfig: apply end_of_line, trim_trailing_whitespace,
+        #       insert_final_newline
+        config = self.__loadEditorConfigObject(fn)
+        
         # TODO: editorconfig: trim_trailing_whitespace
         if Preferences.getEditor("StripTrailingWhitespace"):
             self.__removeTrailingWhitespace()
@@ -3079,7 +3083,7 @@
         # now write text to the file fn
         try:
             editorConfigEncoding = self.__getEditorConfig(
-                "DefaultEncoding", nodefault=True)
+                "DefaultEncoding", nodefault=True, config=config)
             self.encoding = Utilities.writeEncodedFile(
                 fn, txt, self.encoding, forcedEncoding=editorConfigEncoding)
             if createBackup and perms_valid:
@@ -8057,22 +8061,34 @@
         if not fileName:
             fileName = self.fileName
         
+        self.__editorConfig = self.__loadEditorConfigObject(fileName)
+    
+    def __loadEditorConfigObject(self, fileName):
+        """
+        Private method to load the EditorConfig properties for the given
+        file name.
+        
+        @param fileName name of the file
+        @type str
+        @return EditorConfig dictionary
+        @rtype dict
+        """
+        editorConfig = {}
+        
         if fileName:
             try:
-                self.__editorConfig = \
-                    editorconfig.get_properties(fileName)
+                editorConfig = editorconfig.get_properties(fileName)
             except editorconfig.EditorConfigError:
                 E5MessageBox.warning(
                     self,
                     self.tr("EditorConfig Properties"),
                     self.tr("""<p>The EditorConfig properties for file"""
                             """ <b>{0}</b> could not be loaded.</p>""")
-                    .format(self.fileName))
-                self.__editorConfig = {}
-        else:
-            self.__editorConfig = {}
-    
-    def __getEditorConfig(self, option, nodefault=False):
+                    .format(fileName))
+        
+        return editorConfig
+    
+    def __getEditorConfig(self, option, nodefault=False, config=None):
         """
         Private method to get the requested option via EditorConfig.
         
@@ -8086,11 +8102,16 @@
         @param nodefault flag indicating to not get the default value from
             Preferences but return None instead
         @type bool
+        @param config reference to an EditorConfig object or None
+        @type dict
         @return value of requested setting or None if nothing was found and
             nodefault parameter was True
         @rtype any
         """
-        if not self.__editorConfig:
+        if config is None:
+            config = self.__editorConfig
+        
+        if not config:
             if nodefault:
                 return None
             else:
@@ -8098,7 +8119,7 @@
         
         try:
             if option == "EOLMode":
-                value = self.__editorConfig["end_of_line"]
+                value = config["end_of_line"]
                 if value == "lf":
                     value = QsciScintilla.EolUnix
                 elif value == "crlf":
@@ -8108,7 +8129,7 @@
                 else:
                     value = None
             elif option == "DefaultEncoding":
-                value = self.__editorConfig["charset"]
+                value = config["charset"]
         except KeyError:
             value = None
         
--- a/QScintilla/MiniEditor.py	Thu Feb 01 19:32:19 2018 +0100
+++ b/QScintilla/MiniEditor.py	Fri Feb 02 19:42:01 2018 +0100
@@ -34,6 +34,8 @@
 import Utilities
 import Preferences
 
+from ThirdParty.EditorConfig import editorconfig
+
 
 class MiniScintilla(QsciScintillaCompat):
     """
@@ -120,7 +122,7 @@
         self.__textEdit.clearSearchIndicators = self.clearSearchIndicators
         self.__textEdit.setSearchIndicator = self.setSearchIndicator
         self.__textEdit.setUtf8(True)
-        self.encoding = Preferences.getEditor("DefaultEncoding")
+        
         
         self.srHistory = {
             "search": [],
@@ -184,9 +186,11 @@
         self.__textEdit.selectionChanged.connect(
             self.__replaceWidget.selectionChanged)
         
-        self.__setCurrentFile("")
         if filename:
             self.__loadFile(filename, filetype)
+        else:
+            self.__setCurrentFile("")
+            self.encoding = self.__getEditorConfig("DefaultEncoding")
         
         self.__checkActions()
 
@@ -252,25 +256,8 @@
         fileName = E5FileDialog.getSaveFileName(self)
         if not fileName:
             return
-    
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        txt = self.__textEdit.text()
-        try:
-            self.encoding = Utilities.writeEncodedFile(
-                fileName, txt, self.encoding)
-        except (IOError, Utilities.CodingError, UnicodeError) as why:
-            E5MessageBox.critical(
-                self, self.tr('Save File'),
-                self.tr('<p>The file <b>{0}</b> could not be saved.<br/>'
-                        'Reason: {1}</p>')
-                .format(fileName, str(why)))
-            QApplication.restoreOverrideCursor()
-            return
         
-        QApplication.restoreOverrideCursor()
-        self.__statusBar.showMessage(self.tr("File saved"), 2000)
-        
-        return
+        self.__writeFile(fileName)
     
     def __about(self):
         """
@@ -2304,10 +2291,18 @@
         @param fileName name of the file to load (string)
         @param filetype type of the source file (string)
         """
+        self.__loadEditorConfig(fileName=fileName)
+        
         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
         
         try:
-            txt, self.encoding = Utilities.readEncodedFile(fileName)
+            encoding = self.__getEditorConfig("DefaultEncoding",
+                                              nodefault=True)
+            if encoding:
+                txt, self.encoding = Utilities.readEncodedFileWithEncoding(
+                    fileName, encoding)
+            else:
+                txt, self.encoding = Utilities.readEncodedFile(fileName)
         except (UnicodeDecodeError, IOError) as why:
             QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
@@ -2328,6 +2323,7 @@
         self.__setCurrentFile(fileName)
         
         fileEol = self.__textEdit.detectEolString(txt)
+        # TODO: editorconfig: end_of_line
         self.__textEdit.setEolModeByEolString(fileEol)
         
         self.__statusBar.showMessage(self.tr("File loaded"), 2000)
@@ -2336,36 +2332,57 @@
         """
         Private method to save to the given file.
         
-        @param fileName name of the file to save to (string)
-        @return flag indicating success (boolean)
+        @param fileName name of the file to save to
+        @type str
+        @return flag indicating success
+        @rtype bool
         """
+        res = self.__writeFile(fileName)
+        
+        if res:
+            self.editorSaved.emit()
+            self.__setCurrentFile(fileName)
+        
+        self.__checkActions()
+        
+        return res
+    
+    def __writeFile(self, fileName):
+        """
+        Private method to write the current editor text to a file.
+        
+        @param fileName name of the file to be written to
+        @type str
+        @return flag indicating success
+        @rtype bool
+        """
+        # TODO: editorconfig: apply end_of_line, trim_trailing_whitespace,
+        #       insert_final_newline
+        config = self.__loadEditorConfigObject(fileName)
+        
         QApplication.setOverrideCursor(Qt.WaitCursor)
         txt = self.__textEdit.text()
+        # TODO: editorconfig: insert_final_newline
         try:
+            editorConfigEncoding = self.__getEditorConfig(
+                "DefaultEncoding", nodefault=True, config=config)
             self.encoding = Utilities.writeEncodedFile(
-                fileName, txt, self.encoding)
+                fileName, txt, self.encoding,
+                forcedEncoding=editorConfigEncoding)
         except (IOError, Utilities.CodingError, UnicodeError) as why:
+            QApplication.restoreOverrideCursor()
             E5MessageBox.critical(
                 self, self.tr('Save File'),
                 self.tr('<p>The file <b>{0}</b> could not be saved.<br/>'
                         'Reason: {1}</p>')
                 .format(fileName, str(why)))
-            QApplication.restoreOverrideCursor()
-        
-            self.__checkActions()
-            
             return False
         
         QApplication.restoreOverrideCursor()
-        self.editorSaved.emit()
-        
-        self.__setCurrentFile(fileName)
         self.__statusBar.showMessage(self.tr("File saved"), 2000)
         
-        self.__checkActions()
-        
         return True
-
+    
     def __setCurrentFile(self, fileName):
         """
         Private method to register the file name of the current file.
@@ -2386,6 +2403,8 @@
         self.setWindowModified(False)
         
         self.setLanguage(self.__bindName(self.__textEdit.text(0)))
+        
+        self.__loadEditorConfig()
 
     def getFileName(self):
         """
@@ -2506,9 +2525,14 @@
         """
         Private method to configure the text display.
         """
+        # TODO: editorconfig: move these to separate method called, when
+        #   EditorConfig has been loaded
+        # TODO: editorconfig: tab_width
         self.__textEdit.setTabWidth(Preferences.getEditor("TabWidth"))
+        # TODO: editorconfig: indent_size
         self.__textEdit.setIndentationWidth(
             Preferences.getEditor("IndentWidth"))
+        # TODO: editorconfig: indent_style
         if self.lexer_ and self.lexer_.alwaysKeepTabs():
             self.__textEdit.setIndentationsUseTabs(True)
         else:
@@ -2610,6 +2634,7 @@
         """
         Private method to configure the eol mode of the editor.
         """
+        # TODO: editorconfig: end_of_line
         eolMode = Preferences.getEditor("EOLMode")
         eolMode = QsciScintilla.EolMode(eolMode)
         self.__textEdit.setEolMode(eolMode)
@@ -3239,7 +3264,100 @@
         else:
             self.filetype = filetype
         
+        # TODO: editorconfig: end_of_line
         fileEol = self.__textEdit.detectEolString(txt)
         self.__textEdit.setEolModeByEolString(fileEol)
         
         self.__textEdit.setModified(False)
+    
+    #######################################################################
+    ## Methods implementing the interface to EditorConfig
+    #######################################################################
+    
+    def __loadEditorConfig(self, fileName=""):
+        """
+        Private method to load the EditorConfig properties.
+        
+        @param fileName name of the file
+        @type str
+        """
+        if not fileName:
+            fileName = self.__curFile
+        
+        self.__editorConfig = self.__loadEditorConfigObject(fileName)
+    
+    def __loadEditorConfigObject(self, fileName):
+        """
+        Private method to load the EditorConfig properties for the given
+        file name.
+        
+        @param fileName name of the file
+        @type str
+        @return EditorConfig dictionary
+        @rtype dict
+        """
+        editorConfig = {}
+        
+        if fileName:
+            try:
+                editorConfig = editorconfig.get_properties(fileName)
+            except editorconfig.EditorConfigError:
+                E5MessageBox.warning(
+                    self,
+                    self.tr("EditorConfig Properties"),
+                    self.tr("""<p>The EditorConfig properties for file"""
+                            """ <b>{0}</b> could not be loaded.</p>""")
+                    .format(fileName))
+        
+        return editorConfig
+    
+    def __getEditorConfig(self, option, nodefault=False, config=None):
+        """
+        Private method to get the requested option via EditorConfig.
+        
+        If there is no EditorConfig defined, the equivalent built-in option
+        will be used (Preferences.getEditor(). The option must be given as the
+        Preferences option key. The mapping to the EditorConfig option name
+        will be done within this method.
+        
+        @param option Preferences option key
+        @type str
+        @param nodefault flag indicating to not get the default value from
+            Preferences but return None instead
+        @type bool
+        @param config reference to an EditorConfig object or None
+        @type dict
+        @return value of requested setting or None if nothing was found and
+            nodefault parameter was True
+        @rtype any
+        """
+        if config is None:
+            config = self.__editorConfig
+        
+        if not config:
+            if nodefault:
+                return None
+            else:
+                return Preferences.getEditor(option)
+        
+        try:
+            if option == "EOLMode":
+                value = config["end_of_line"]
+                if value == "lf":
+                    value = QsciScintilla.EolUnix
+                elif value == "crlf":
+                    value = QsciScintilla.EolWindows
+                elif value == "cr":
+                    value = QsciScintilla.EolMac
+                else:
+                    value = None
+            elif option == "DefaultEncoding":
+                value = config["charset"]
+        except KeyError:
+            value = None
+        
+        if value is None and not nodefault:
+            # use Preferences in case of error
+            value = Preferences.getEditor(option)
+        
+        return value
--- a/eric6_browser.py	Thu Feb 01 19:32:19 2018 +0100
+++ b/eric6_browser.py	Fri Feb 02 19:42:01 2018 +0100
@@ -66,6 +66,8 @@
 # make ThirdParty package available as a packages repository
 sys.path.insert(2, os.path.join(os.path.dirname(__file__),
                                 "ThirdParty", "Pygments"))
+sys.path.insert(2, os.path.join(os.path.dirname(__file__),
+                                "ThirdParty", "EditorConfig"))
 
 try:
     from PyQt5 import QtWebEngineWidgets    # __IGNORE_WARNING__
--- a/eric6_configure.py	Thu Feb 01 19:32:19 2018 +0100
+++ b/eric6_configure.py	Fri Feb 02 19:42:01 2018 +0100
@@ -50,6 +50,8 @@
 # make ThirdParty package available as a packages repository
 sys.path.insert(2, os.path.join(os.path.dirname(__file__),
                                 "ThirdParty", "Pygments"))
+sys.path.insert(2, os.path.join(os.path.dirname(__file__),
+                                "ThirdParty", "EditorConfig"))
 
 from Globals import AppInfo
 
--- a/eric6_editor.py	Thu Feb 01 19:32:19 2018 +0100
+++ b/eric6_editor.py	Fri Feb 02 19:42:01 2018 +0100
@@ -42,6 +42,8 @@
 # make ThirdParty package available as a packages repository
 sys.path.insert(2, os.path.join(os.path.dirname(__file__),
                                 "ThirdParty", "Pygments"))
+sys.path.insert(2, os.path.join(os.path.dirname(__file__),
+                                "ThirdParty", "EditorConfig"))
 
 from Globals import AppInfo
 
--- a/eric6_webbrowser.py	Thu Feb 01 19:32:19 2018 +0100
+++ b/eric6_webbrowser.py	Fri Feb 02 19:42:01 2018 +0100
@@ -64,6 +64,8 @@
 # make ThirdParty package available as a packages repository
 sys.path.insert(2, os.path.join(os.path.dirname(__file__),
                                 "ThirdParty", "Pygments"))
+sys.path.insert(2, os.path.join(os.path.dirname(__file__),
+                                "ThirdParty", "EditorConfig"))
 
 import Globals
 from Globals import AppInfo

eric ide

mercurial