Lexer: implemented basic support for sub-styles. sub_styles

Sat, 09 Mar 2019 17:36:44 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 09 Mar 2019 17:36:44 +0100
branch
sub_styles
changeset 6845
4680adb641e0
parent 6844
d706eb5bc040
child 6846
6ca9ef2c0907

Lexer: implemented basic support for sub-styles.

QScintilla/Editor.py file | annotate | diff | comparison | revisions
QScintilla/Lexers/Lexer.py file | annotate | diff | comparison | revisions
QScintilla/Lexers/LexerCPP.py file | annotate | diff | comparison | revisions
QScintilla/Lexers/LexerPython.py file | annotate | diff | comparison | revisions
QScintilla/Lexers/SubstyledLexer.py file | annotate | diff | comparison | revisions
QScintilla/MiniEditor.py file | annotate | diff | comparison | revisions
QScintilla/Shell.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- a/QScintilla/Editor.py	Sat Mar 09 10:04:18 2019 +0100
+++ b/QScintilla/Editor.py	Sat Mar 09 17:36:44 2019 +0100
@@ -1632,6 +1632,8 @@
             font = QFont(fdesc[0], int(fdesc[1]))
             self.lexer_.setDefaultFont(font)
         self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla")
+        if self.lexer_.hasSubStyles():
+            self.lexer_.readSubstyles(self)
         
         # now set the lexer properties
         self.lexer_.initProperties()
@@ -3311,6 +3313,8 @@
             if self.lexer_:
                 self.lexer_.readSettings(
                     Preferences.Prefs.settings, "Scintilla")
+                if self.lexer_.hasSubStyles():
+                    self.lexer_.readSubstyles(self)
                 self.lexer_.initProperties()
             self.setMonospaced(False)
             self.__setMarginsDisplay()
@@ -4069,6 +4073,8 @@
         # read the lexer settings and reinit the properties
         if self.lexer_ is not None:
             self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla")
+            if self.lexer_.hasSubStyles():
+                self.lexer_.readSubstyles(self)
             self.lexer_.initProperties()
             
             self.lexer_.setDefaultColor(self.lexer_.color(0))
--- a/QScintilla/Lexers/Lexer.py	Sat Mar 09 10:04:18 2019 +0100
+++ b/QScintilla/Lexers/Lexer.py	Sat Mar 09 17:36:44 2019 +0100
@@ -243,3 +243,12 @@
         @return lexer name (string)
         """
         return self.lexer()
+    
+    def hasSubStyles(self):
+        """
+        Public method to indicate the support of sub-styles.
+        
+        @return flag indicating sub-styling support
+        @rtype bool
+        """
+        return False
--- a/QScintilla/Lexers/LexerCPP.py	Sat Mar 09 10:04:18 2019 +0100
+++ b/QScintilla/Lexers/LexerCPP.py	Sat Mar 09 17:36:44 2019 +0100
@@ -9,13 +9,14 @@
 
 from __future__ import unicode_literals
 
+from PyQt5.QtCore import QCoreApplication
 from PyQt5.Qsci import QsciLexerCPP, QsciScintilla
 
-from .Lexer import Lexer
+from .SubstyledLexer import SubstyledLexer
 import Preferences
 
 
-class LexerCPP(Lexer, QsciLexerCPP):
+class LexerCPP(SubstyledLexer, QsciLexerCPP):
     """
     Subclass to implement some additional lexer dependant methods.
     """
@@ -28,7 +29,7 @@
             insensitive (boolean)
         """
         QsciLexerCPP.__init__(self, parent, caseInsensitiveKeywords)
-        Lexer.__init__(self)
+        SubstyledLexer.__init__(self)
         
         self.commentString = "//"
         self.streamCommentString = {
@@ -40,6 +41,68 @@
             'middle': ' * ',
             'end': ' */'
         }
+        
+        ##############################################################
+        ## default sub-style definitions
+        ##############################################################
+        
+        # list of style numbers, that support sub-styling
+        self.baseStyles = [11, 17, 75, 81]
+        
+        self.defaultSubStyles = {
+            11: {
+                "SubStyleLength": 1,
+                "SubStyles": [
+                    {
+                        "Description": QCoreApplication.translate(
+                            "LexerCPP", "Extra Identifiers"),
+                        "Words": "std map string vector",
+                        "Style": {
+                            "fore": 0xEE00AA,
+                        }
+                    },
+                ]
+            },
+            17: {
+                "SubStyleLength": 1,
+                "SubStyles": [
+                    {
+                        "Description": QCoreApplication.translate(
+                            "LexerCPP", "Extra Doc Comment Keywords"),
+                        "Words": "check",
+                        "Style": {
+                            "fore": 0x00AAEE,
+                        }
+                    },
+                ]
+            },
+            75: {
+                "SubStyleLength": 1,
+                "SubStyles": [
+                    {
+                        "Description": QCoreApplication.translate(
+                            "LexerCPP", "Inactive Extra Identifiers"),
+                        "Words": "std map string vector",
+                        "Style": {
+                            "fore": 0xBB6666,
+                        }
+                    },
+                ]
+            },
+            81: {
+                "SubStyleLength": 1,
+                "SubStyles": [
+                    {
+                        "Description": QCoreApplication.translate(
+                            "LexerCPP", "Inactive Extra Doc Comment Keywords"),
+                        "Words": "check",
+                        "Style": {
+                            "fore": 0x6699AA,
+                        }
+                    },
+                ]
+            },
+        }
 
     def initProperties(self):
         """
--- a/QScintilla/Lexers/LexerPython.py	Sat Mar 09 10:04:18 2019 +0100
+++ b/QScintilla/Lexers/LexerPython.py	Sat Mar 09 17:36:44 2019 +0100
@@ -11,13 +11,14 @@
 
 import re
 
+from PyQt5.QtCore import QCoreApplication
 from PyQt5.Qsci import QsciLexerPython, QsciScintilla
 
-from .Lexer import Lexer
+from .SubstyledLexer import SubstyledLexer
 import Preferences
 
 
-class LexerPython(Lexer, QsciLexerPython):
+class LexerPython(SubstyledLexer, QsciLexerPython):
     """
     Subclass to implement some additional lexer dependant methods.
     """
@@ -29,10 +30,65 @@
         @param parent parent widget of this lexer
         """
         QsciLexerPython.__init__(self, parent)
-        Lexer.__init__(self)
+        SubstyledLexer.__init__(self)
         
         self.variant = variant
         self.commentString = "#"
+        
+        ##############################################################
+        ## default sub-style definitions
+        ##############################################################
+        
+        # list of style numbers, that support sub-styling
+        self.baseStyles = [11]
+        
+        self.defaultSubStyles = {
+            11: {
+                "SubStyleLength": 2,
+                "SubStyles": [
+                    {
+                        "Description": QCoreApplication.translate(
+                            "LexerPython", "Standard Library Modules"),
+                        "Words": """
+__main__ _dummy_thread _thread abc aifc argparse array ast asynchat asyncio
+ asyncore atexit audioop base64 bdb binascii binhex bisect builtins bz2
+ calendar cgi cgitb chunk cmath cmd code codecs codeop collections colorsys
+ compileall concurrent configparser contextlib copy copyreg crypt csv ctypes
+ curses datetime dbm decimal difflib dis distutils dummy_threading email
+ ensurepip enum errno faulthandler fcntl filecmp fileinput fnmatch formatter
+ fpectl fractions ftplib functools gc getopt getpass gettext glob grp gzip
+ hashlib heapq hmac html http http imaplib imghdr importlib inspect io
+ ipaddress itertools json keyword linecache locale logging lzma macpath
+ mailbox mailcap marshal math mimetypes mmap modulefinder msilib msvcrt
+ multiprocessing netrc nis nntplib numbers operator os os.path ossaudiodev
+ parser pathlib pdb pickle pickletools pipes pkgutil platform plistlib
+ poplib posix pprint pty pwd py_compile pyclbr queue quopri random re readline
+ reprlib resource rlcompleter runpy sched select selectors shelve shlex shutil
+ signal site smtpd smtplib sndhdr socket socketserver spwd sqlite3 ssl stat
+ statistics string stringprep struct subprocess sunau symbol symtable sys
+ sysconfig syslog tabnanny tarfile telnetlib tempfile termios textwrap
+ threading time timeit tkinter token tokenize trace traceback tracemalloc tty
+ turtle types unicodedata unittest urllib uu uuid venv warnings wave weakref
+ webbrowser winreg winsound wsgiref xdrlib xml xmlrpc zipfile zipimport
+ zlib""",
+                        "Style": {
+                            "fore": 0xDD9900,
+                        }
+                    },
+                    {
+                        "Description": QCoreApplication.translate(
+                            "LexerPython", "__future__ Imports"),
+                        "Words": """
+__future__ with_statement unicode_literals print_function division
+ absolute_import generator_stop annotations""",
+                        "Style": {
+                            "fore": 0xEE00AA,
+                            "font_italic": True,
+                        }
+                    }
+                ]
+            },
+        }
     
     def language(self):
         """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QScintilla/Lexers/SubstyledLexer.py	Sat Mar 09 17:36:44 2019 +0100
@@ -0,0 +1,285 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2003 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the lexer mixin class.
+"""
+
+from __future__ import unicode_literals
+
+import copy
+
+from PyQt5.QtGui import QColor
+
+from .Lexer import Lexer
+
+import Preferences
+
+
+class SubstyledLexer(Lexer):
+    """
+    Class to implement the sub-styled lexer mixin class.
+    """
+    def __init__(self):
+        """
+        Constructor
+        """
+        super(SubstyledLexer, self).__init__()
+        
+        self.baseStyles = []            # list of style numbers, that support
+                                        # sub-styling
+        self.defaultSubStyles = {}
+        # dictionary with sub-styling data
+        # main key: base style number, value : dictionary with
+        #   'SubStyleLength': int
+        #   'SubStyles': list of dict with
+        #       'Description': string containing a short description
+        #       'Words': string of whitespace separated words to be styled
+        #       'Style': dictionary with styling data (only difference to the
+        #                base style is required
+        #           'fore': foreground color (int containing RGB values)
+        #           'paper': background color (int containing RGB values)
+        #           'eolfill': fill to eol (bool)
+        #           'font_family': font family (str)
+        #           'font_size: point size (int)
+        #           'font_bold: bold font (bool)
+        #           'font_italic: italic font (bool)
+        #           'font_underline: underlined font (bool)
+        
+        self.subStyles = {}
+        self.__subStylesInitialized = False
+    
+    def loadSubstyles(self):
+        """
+        Public method to load the sub-styles from the settings file
+        """
+        settings = Preferences.Prefs.settings
+        
+        self.loadDefaultSubStyles()
+        
+        for baseStyle in self.baseStyles:
+            key = "Scintilla/{0}/style{1}/SubStyleLength".format(
+                self.language(), baseStyle)
+            if settings.contains(key):
+                subStyleLength = int(settings.value(key), 0)
+                self.subStyles[baseStyle] = {}
+                self.subStyles[baseStyle]["SubStyleLength"] = subStyleLength
+                if subStyleLength:
+                    self.subStyles[baseStyle]["SubStyles"] = []
+                    for subStyle in range(subStyleLength):
+                        baseKey = "Scintilla/{0}/style{1}/substyle{2}/".format(
+                            self.language(), baseStyle, subStyle)
+                        subStyleData = {}
+                        subStyleData["Description"] = settings.value(
+                            baseKey + "Description", "")
+                        subStyleData["Words"] = settings.value(
+                            baseKey + "Words", "")
+                        style = {}
+                        
+                        key = baseKey + "fore"
+                        if settings.contains(key):
+                            style["fore"] = int(settings.value(key))
+                        key = baseKey + "paper"
+                        if settings.contains(key):
+                            style["paper"] = int(settings.value(key))
+                        key = baseKey + "eolfill"
+                        if settings.contains(key):
+                            style["eolfill"] = Preferences.toBool(
+                                settings.value(key))
+                        key = baseKey + "font_family"
+                        if settings.contains(key):
+                            style["font_family"] = settings.value(key)
+                        key = baseKey + "font_size"
+                        if settings.contains(key):
+                            style["font_size"] = int(settings.value(key))
+                        key = baseKey + "font_bold"
+                        if settings.contains(key):
+                            style["font_bold"] = Preferences.toBool(
+                                settings.value(key))
+                        key = baseKey + "font_italic"
+                        if settings.contains(key):
+                            style["font_italic"] = Preferences.toBool(
+                                settings.value(key))
+                        key = baseKey + "font_underline"
+                        if settings.contains(key):
+                            style["font_underline"] = Preferences.toBool(
+                                settings.value(key))
+                        
+                        subStyleData["Style"] = style
+    
+    def loadDefaultSubStyles(self):
+        """
+        Public method to load the default sub-style definitions.
+        """
+        self.subStyles = copy.deepcopy(self.defaultSubStyles)
+    
+    def readSubstyles(self, editor):
+        """
+        Public method to load the sub-styles and configure the editor.
+        
+        @param editor reference to the editor object
+        @type QsciScintilla
+        """
+        subStyleBasesLength = editor.SendScintilla(
+            editor.SCI_GETSUBSTYLEBASES, 0, None)
+        if not subStyleBasesLength:
+            # lexer does not support sub-styling
+            return
+        
+        self.loadSubstyles()
+        
+        # free existing sub-styles first
+        editor.SendScintilla(editor.SCI_FREESUBSTYLES)
+        subStyleBases = b"\00" * (subStyleBasesLength + 1)
+        editor.SendScintilla(editor.SCI_GETSUBSTYLEBASES, 0, subStyleBases)
+        distanceToSecondary = editor.SendScintilla(
+            editor.SCI_DISTANCETOSECONDARYSTYLES)
+        
+        subStyleBases = [b for b in bytearray(subStyleBases[:-1])]
+        if distanceToSecondary:
+            subStyleBases.extend(b + distanceToSecondary for b in subStyleBases[:])
+        for baseStyleNo in subStyleBases:
+            if baseStyleNo in self.subStyles:
+                subStylesData = self.subStyles[baseStyleNo]
+                subStyleLength = subStylesData["SubStyleLength"]
+                subStyleStart = editor.SendScintilla(
+                    editor.SCI_ALLOCATESUBSTYLES, baseStyleNo, subStyleLength)
+                if subStyleStart < 0:
+                    subStyleLength = 0
+                for subStyleIndex in range(subStyleLength):
+                    subStyle = subStylesData["SubStyles"][subStyleIndex]
+                    # set the words
+                    editor.SendScintilla(
+                        editor.SCI_SETIDENTIFIERS,
+                        subStyleStart + subStyleIndex,
+                        subStyle["Words"].encode())
+                    
+                    # set the style
+                    styleNo = subStyleStart + subStyleIndex
+                    style = subStyle["Style"]
+                    if "fore" in style:
+                        color = QColor(
+                            style["fore"] >> 16 & 0xff,
+                            style["fore"] >> 8 & 0xff,
+                            style["fore"] & 0xff,
+                        )
+                    else:
+                        color = self.color(baseStyleNo)
+                    self.setColor(color, styleNo)
+                    if "paper" in style:
+                        color = QColor(
+                            style["paper"] >> 16 & 0xff,
+                            style["paper"] >> 8 & 0xff,
+                            style["paper"] & 0xff,
+                        )
+                    else:
+                        color = self.paper(baseStyleNo)
+                    self.setPaper(color, styleNo)
+                    if "eolfill" in style:
+                        eolFill = style["eolFill"]
+                    else:
+                        eolFill = self.eolFill(baseStyleNo)
+                    self.setEolFill(eolFill, styleNo)
+                    font = self.font(baseStyleNo)
+                    if "font_family" in style:
+                        font.setFamily(style["font_family"])
+                    if "font_size" in style:
+                        font.setPointSize(style["font_size"])
+                    if "font_bold" in style:
+                        font.setBold(style["font_bold"])
+                    if "font_italic" in style:
+                        font.setItalic(style["font_italic"])
+                    if "font_underline" in style:
+                        font.setUnderline(style["font_underline"])
+                    self.setFont(font, styleNo)
+    
+    def writeSubstyles(self):
+        """
+        Public method to save the sub-styles.
+        """
+    
+    def hasSubStyles(self):
+        """
+        Public method to indicate the support of sub-styles.
+        
+        @return flag indicating sub-styling support
+        @rtype bool
+        """
+        return True
+    
+    def setSubstyleDescription(self, description, style, substyle):
+        """
+        
+        """
+    
+    def substyleDescription(self, style, substyle):
+        """
+        
+        """
+    
+    def setSubstyleColor(self, color, style, substyle):
+        """
+        
+        """
+    
+    def substyleColor(self, style, substyle):
+        """
+        
+        """
+    
+    def setSubstylePaper(self, color, style, substyle):
+        """
+        
+        """
+    
+    def substylePaper(self, style, substyle):
+        """
+        
+        """
+    
+    def setSubstyleEolFill(self, eolFill, style, substyle):
+        """
+        
+        """
+    
+    def substyleEolFill(self, style, substyle):
+        """
+        
+        """
+    
+    def setSubstyleFont(self, font, style, substyle):
+        """
+        
+        """
+    
+    def substyleFont(self, style, substyle):
+        """
+        
+        """
+    
+    def substyleDefaultDescription(self, style, substyle):
+        """
+        
+        """
+    
+    def substyleDefaultColor(self, style, substyle):
+        """
+        
+        """
+    
+    def substyleDefaultPaper(self, style, substyle):
+        """
+        
+        """
+    
+    def substyleDefaultEolFill(self, style, substyle):
+        """
+        
+        """
+    
+    def substyleDefaultFont(self, style, substyle):
+        """
+        
+        """
--- a/QScintilla/MiniEditor.py	Sat Mar 09 10:04:18 2019 +0100
+++ b/QScintilla/MiniEditor.py	Sat Mar 09 17:36:44 2019 +0100
@@ -3044,6 +3044,8 @@
             font = QFont(fdesc[0], int(fdesc[1]))
             self.lexer_.setDefaultFont(font)
         self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla")
+        if self.lexer_.hasSubStyles():
+            self.lexer_.readSubstyles(self.__textEdit)
         
         # now set the lexer properties
         self.lexer_.initProperties()
--- a/QScintilla/Shell.py	Sat Mar 09 10:04:18 2019 +0100
+++ b/QScintilla/Shell.py	Sat Mar 09 17:36:44 2019 +0100
@@ -437,6 +437,8 @@
             self.lexer_.setDefaultFont(font)
         self.setLexer(self.lexer_)
         self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla")
+        if self.lexer_.hasSubStyles():
+            self.lexer_.readSubstyles(self)
         
         # initialize the lexer APIs settings
         api = self.vm.getAPIsManager().getAPIs(self.language)
--- a/eric6.e4p	Sat Mar 09 10:04:18 2019 +0100
+++ b/eric6.e4p	Sat Mar 09 17:36:44 2019 +0100
@@ -1009,6 +1009,7 @@
     <Source>QScintilla/Lexers/LexerVHDL.py</Source>
     <Source>QScintilla/Lexers/LexerXML.py</Source>
     <Source>QScintilla/Lexers/LexerYAML.py</Source>
+    <Source>QScintilla/Lexers/SubstyledLexer.py</Source>
     <Source>QScintilla/Lexers/__init__.py</Source>
     <Source>QScintilla/MarkupProviders/HtmlProvider.py</Source>
     <Source>QScintilla/MarkupProviders/HyperlinkMarkupDialog.py</Source>

eric ide

mercurial