Thu, 28 Jan 2021 18:29:00 +0100
Implemented the JSON based highlighting styles files.
--- a/eric6.e4p Thu Jan 28 16:36:29 2021 +0100 +++ b/eric6.e4p Thu Jan 28 18:29:00 2021 +0100 @@ -771,12 +771,14 @@ <Source>eric6/Preferences/ConfigurationPages/WebBrowserSpellCheckingPage.py</Source> <Source>eric6/Preferences/ConfigurationPages/WebBrowserVirusTotalPage.py</Source> <Source>eric6/Preferences/ConfigurationPages/__init__.py</Source> + <Source>eric6/Preferences/HighlightingStylesFile.py</Source> <Source>eric6/Preferences/MouseClickDialog.py</Source> <Source>eric6/Preferences/PreferencesLexer.py</Source> <Source>eric6/Preferences/ProgramsDialog.py</Source> <Source>eric6/Preferences/ShortcutDialog.py</Source> <Source>eric6/Preferences/Shortcuts.py</Source> <Source>eric6/Preferences/ShortcutsDialog.py</Source> + <Source>eric6/Preferences/ShortcutsFile.py</Source> <Source>eric6/Preferences/SubstyleDefinitionDialog.py</Source> <Source>eric6/Preferences/ToolConfigurationDialog.py</Source> <Source>eric6/Preferences/ToolGroupConfigurationDialog.py</Source>
--- a/eric6/E5XML/HighlightingStylesReader.py Thu Jan 28 16:36:29 2021 +0100 +++ b/eric6/E5XML/HighlightingStylesReader.py Thu Jan 28 18:29:00 2021 +0100 @@ -25,7 +25,8 @@ Constructor @param device reference to the I/O device to read from (QIODevice) - @param lexers list of lexer objects for which to export the styles + @param lexers dictionary of lexer objects for which to import the + styles """ XMLStreamReaderBase.__init__(self, device)
--- a/eric6/Preferences/ConfigurationPages/EditorHighlightingStylesPage.py Thu Jan 28 16:36:29 2021 +0100 +++ b/eric6/Preferences/ConfigurationPages/EditorHighlightingStylesPage.py Thu Jan 28 18:29:00 2021 +0100 @@ -7,6 +7,8 @@ Module implementing the Editor Highlighting Styles configuration page. """ +import os + from PyQt5.QtCore import pyqtSlot, Qt, QFileInfo, QFile, QIODevice from PyQt5.QtGui import QPalette, QFont from PyQt5.QtWidgets import ( @@ -28,6 +30,7 @@ NoFontsOption = QFontDialog.FontDialogOptions(0) +# TODO: add capability to export a list of selected highlighter styles class EditorHighlightingStylesPage(ConfigurationPageBase, Ui_EditorHighlightingStylesPage): """ @@ -517,12 +520,12 @@ """ self.__exportStyles(list(self.lexers.values())) - # TODO: do the JSON styles def __exportStyles(self, lexers): """ Private method to export the styles of the given lexers. @param lexers list of lexer objects for which to export the styles + @type list of PreferencesLexer """ from eric6config import getConfig stylesDir = getConfig("ericStylesDir") @@ -531,7 +534,8 @@ self, self.tr("Export Highlighting Styles"), stylesDir, - self.tr("Highlighting styles file (*.e6h)"), + self.tr("Highlighting Styles File (*.ehj);;" + "XML Highlighting Styles File (*.e6h)"), "", E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) @@ -544,22 +548,39 @@ if ex: fn += ex - f = QFile(fn) - if f.open(QIODevice.WriteOnly): - from E5XML.HighlightingStylesWriter import HighlightingStylesWriter - HighlightingStylesWriter(f, lexers).writeXML() - f.close() - else: - E5MessageBox.critical( + if os.path.exists(fn): + ok = E5MessageBox.yesNo( self, self.tr("Export Highlighting Styles"), - self.tr( - """<p>The highlighting styles could not be exported""" - """ to file <b>{0}</b>.</p><p>Reason: {1}</p>""") - .format(fn, f.errorString()) - ) + self.tr("""<p>The highlighting styles file <b>{0}</b> exists""" + """ already. Overwrite it?</p>""").format(fn)) + else: + ok = True + + if ok: + if fn.endswith(".ehj"): + from Preferences.HighlightingStylesFile import ( + HighlightingStylesFile + ) + highlightingStylesFile = HighlightingStylesFile() + highlightingStylesFile.writeFile(fn, lexers) + else: + f = QFile(fn) + if f.open(QIODevice.WriteOnly): + from E5XML.HighlightingStylesWriter import ( + HighlightingStylesWriter + ) + HighlightingStylesWriter(f, lexers).writeXML() + f.close() + else: + E5MessageBox.critical( + self, + self.tr("Export Highlighting Styles"), + self.tr("<p>The highlighting styles file <b>{0}</b>" + " could not be written.</p><p>Reason: {1}</p>") + .format(fn, f.errorString()) + ) - # TODO: do the JSON styles def __importStyles(self, lexers): """ Private method to import the styles of the given lexers. @@ -574,27 +595,41 @@ self, self.tr("Import Highlighting Styles"), stylesDir, - self.tr("Highlighting styles file (*.e6h *.e4h)")) + self.tr("Highlighting Styles File (*.ehj);;" + "XML Highlighting Styles File (*.e6h *.e4h)")) if not fn: return - f = QFile(fn) - if f.open(QIODevice.ReadOnly): - from E5XML.HighlightingStylesReader import HighlightingStylesReader - reader = HighlightingStylesReader(f, lexers) - reader.readXML() - f.close() + if fn.endswith(".ehj"): + # new JSON based file + from Preferences.HighlightingStylesFile import ( + HighlightingStylesFile + ) + highlightingStylesFile = HighlightingStylesFile() + res = highlightingStylesFile.readFile(fn, lexers) + if not res: + return else: - E5MessageBox.critical( - self, - self.tr("Import Highlighting Styles"), - self.tr( - """<p>The highlighting styles could not be read""" - """ from file <b>{0}</b>.</p><p>Reason: {1}</p>""") - .format(fn, f.errorString()) - ) - return + # old XML based file + f = QFile(fn) + if f.open(QIODevice.ReadOnly): + from E5XML.HighlightingStylesReader import ( + HighlightingStylesReader + ) + reader = HighlightingStylesReader(f, lexers) + reader.readXML() + f.close() + else: + E5MessageBox.critical( + self, + self.tr("Import Highlighting Styles"), + self.tr( + "<p>The highlighting styles file <b>{0}</b> could not" + " be read.</p><p>Reason: {1}</p>" + ).format(fn, f.errorString()) + ) + return self.on_lexerLanguageComboBox_activated( self.lexerLanguageComboBox.currentText())
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric6/Preferences/HighlightingStylesFile.py Thu Jan 28 18:29:00 2021 +0100 @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a class representing the highlighting styles JSON file. +""" + +import json +import time + +from PyQt5.QtCore import QObject +from PyQt5.QtGui import QColor, QFont + +from E5Gui import E5MessageBox +from E5Gui.E5OverrideCursor import E5OverridenCursor + +import Preferences + + +class HighlightingStylesFile(QObject): + """ + Class representing the highlighting styles JSON file. + """ + def __init__(self, parent: QObject = None): + """ + Constructor + + @param parent reference to the parent object (defaults to None) + @type QObject (optional) + """ + super(HighlightingStylesFile, self).__init__(parent) + + def writeFile(self, filename: str, lexers: list) -> bool: + """ + Public method to write the highlighting styles data to a highlighting + styles JSON file. + + @param filename name of the highlighting styles file + @type str + @param lexers list of lexers for which to export the styles + @type list of PreferencesLexer + @return flag indicating a successful write + @rtype bool + """ + stylesDict = {} + # step 0: header + stylesDict["header"] = { + "comment": "eric highlighting styles file", + "saved": time.strftime('%Y-%m-%d, %H:%M:%S'), + "author": Preferences.getUser("Email"), + } + + # step 1: add the lexer style data + stylesDict["lexers"] = [] + for lexer in lexers: + lexerDict = { + "name": lexer.language(), + "styles": [], + } + for description, style, substyle in lexer.getStyles(): + lexerDict["styles"].append({ + "description": description, + "style": style, + "substyle": substyle, + "color": lexer.color(style, substyle).name(), + "paper": lexer.paper(style, substyle).name(), + "font": lexer.font(style, substyle).toString(), + "eolfill": lexer.eolFill(style, substyle), + "words": lexer.words(style, substyle).strip(), + }) + stylesDict["lexers"].append(lexerDict) + + try: + jsonString = json.dumps(stylesDict, indent=2) + with open(filename, "w") as f: + f.write(jsonString) + except (TypeError, EnvironmentError) as err: + with E5OverridenCursor(): + E5MessageBox.critical( + None, + self.tr("Export Highlighting Styles"), + self.tr( + "<p>The highlighting styles file <b>{0}</b> could not" + " be written.</p><p>Reason: {1}</p>" + ).format(filename, str(err)) + ) + return False + + return True + + def readFile(self, filename: str, lexers: dict) -> bool: + """ + Public method to read the highlighting styles data from a highlighting + styles JSON file. + + @param filename name of the highlighting styles file + @type str + @param lexers dictionary of lexer objects for which to import the + styles + @type dict of {str: PreferencesLexer} + @return flag indicating a successful read + @rtype bool + """ + try: + with open(filename, "r") as f: + jsonString = f.read() + stylesDict = json.loads(jsonString) + except (EnvironmentError, json.JSONDecodeError) as err: + E5MessageBox.critical( + None, + self.tr("Import Highlighting Styles"), + self.tr( + "<p>The highlighting styles file <b>{0}</b> could not be" + " read.</p><p>Reason: {1}</p>" + ).format(filename, str(err)) + ) + return False + + for lexerDict in stylesDict["lexers"]: + if lexerDict["name"] in lexers: + lexer = lexers[lexerDict["name"]] + for styleDict in lexerDict["styles"]: + style = styleDict["style"] + substyle = styleDict["substyle"] + lexer.setColor(QColor(styleDict["color"]), style, substyle) + lexer.setPaper(QColor(styleDict["paper"]), style, substyle) + font = QFont() + font.fromString(styleDict["font"]) + lexer.setFont(font, style, substyle) + lexer.setEolFill(styleDict["eolfill"], style, substyle) + if substyle >= 0: + # description and words can only be set for sub-styles + lexer.setDescription(styleDict["description"], + style, substyle) + lexer.setWords(styleDict["words"], style, substyle) + + return True
--- a/eric6/Preferences/Shortcuts.py Thu Jan 28 16:36:29 2021 +0100 +++ b/eric6/Preferences/Shortcuts.py Thu Jan 28 18:29:00 2021 +0100 @@ -233,7 +233,6 @@ .format(fn)) -# TODO: do the JSON shortcuts def importShortcuts(fn, helpViewer=None): """ Module function to import the keyboard shortcuts for the defined actions.