Commits

Henning Schröder  committed b28afde

javascript highlighting

  • Participants
  • Parent commits b323572

Comments (0)

Files changed (4)

 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 import sys
-import os
 from PyQt4.QtGui import QApplication, QMainWindow, QPlainTextEdit, QFont
 from highlighter import SyntaxHighlighter, load_syntax, Format
 from highlighter.python27 import syntax
+#from highlighter.js import syntax
 
 scheme = {
   "syntax_comment": dict(color="green", italic=True),
   "syntax_string": "magenta",
   "syntax_builtin": "red",
-  "syntax_keyword": ("darkred",True),
+  "syntax_keyword": ("darkred", True),
   "syntax_number": "blue",
 }
 
         font = QFont()
         font.setFamily("Courier")
         font.setPointSize(10)
-        
+
         self.edit.setFont(font)
         parts_scanner, code_scanner, formats = load_syntax(syntax, scheme)
         self.hl = SyntaxHighlighter(self.edit.document(),
         self.setWindowTitle("cf: %s (%s,%s)" % (name, row, col))
 
 
+
 if __name__ == "__main__":
     app = QApplication(sys.argv)
     win = MainWindow()
     win.show()
     sys.exit(app.exec_() or 0)
-    
-    
 
+

File highlighter/__init__.py

 import re
 from PyQt4.QtCore import QVariant
 from PyQt4.QtGui import (
-    QSyntaxHighlighter, 
+    QSyntaxHighlighter,
     QColor, QTextCharFormat, QFont, QBrush, QTextFormat)
 
 
-from customhighlighter import CustomHighlighter as QSyntaxHighlighter
-    
+#from customhighlighter import CustomHighlighter as QSyntaxHighlighter
+
 class TextCharFormat(QTextCharFormat):
     pass
 
 class Format(object):
 
     __slots__ = ("NAME", "name", "tcf")
-    
+
     NAME = QTextFormat.UserProperty + 1
 
 
 
 class Partition(object):
     # every partition maps to a specific state in QSyntaxHighlighter
-    
+
     __slots__ = ("name", "start", "end", "is_multiline", "search_end")
 
 
         self.start = start
         self.end = end
         self.is_multiline = is_multiline
-        self.search_end = re.compile(end, re.M|re.S).search
+        try:
+            self.search_end = re.compile(end, re.M|re.S).search
+        except Exception:
+            print name, end
+            raise
 
 
 
 class PartitionScanner(object):
     # The idea to partition the source into different contexts comes from Eclipse.
     # http://wiki.eclipse.org/FAQ_What_is_a_document_partition%3F
-    
+
 
     def __init__(self, partitions):
         start_groups = []
         self.partitions = []
         for i, p in enumerate(partitions):
-            if isinstance(p, (tuple,list)):
+            if isinstance(p, (tuple, list)):
                 p = Partition(*p)
             elif isinstance(p, dict):
-                p = Partitition(**p)
+                p = Partition(**p)
             else:
                 assert isinstance(p, Partition), "Partition expected, got %r" % p
             self.partitions.append(p)
             start_groups.append("(?P<g%s_%s>%s)" % (i, p.name, p.start))
         start_pat = "|".join(start_groups)
-        self.search_start = re.compile(start_pat, re.M|re.S).search
-
+        try:
+            self.search_start = re.compile(start_pat, re.M|re.S).search
+        except Exception, exc:
+            print start_part
+            raise
 
     def scan(self, current_state, text):
         last_pos = 0
         self.prefix = prefix
         self.suffix = suffix
 
-        
+
 
 class Scanner(object):
     __slots__ = ("tokens", "search")
         self.tokens = []
         groups = []
         for t in tokens:
-            if isinstance(t, (list,tuple)):
+            if isinstance(t, (list, tuple)):
                 t = Token(*t)
             elif isinstance(t, dict):
                 t = Token(**t)
             if gdef in t.pattern:
                 p = t.pattern
             else:
-                p = ("(%s%s)" % (gdef, t.pattern)) 
+                p = ("(%s%s)" % (gdef, t.pattern))
             p = t.prefix + p + t.suffix
             groups.append(p)
             self.tokens.append(t)
         pat = "|".join(groups)
         self.search = re.compile(pat).search
 
-        
+
     def scan(self, s):
         search = self.search
         #length = len(s)
         :param parent: QDocument or QTextEdit/QPlainTextEdit instance
         'partition_scanner:
             PartitionScanner instance
-        :param scanner: 
+        :param scanner:
             dictionary of token scanners for each partition
             The key is the name of the partition, the value is a Scanner instance
             The default scanner has the key None
-        :formats: 
+        :formats:
             list of tuples consisting of a name and a format definition
             The name is the name of a partition or token
-            
         """
         super(SyntaxHighlighter, self).__init__(parent)
         if default_font:
             parent.setDefaultFont(default_font)
-        
-        if isinstance(partition_scanner, (list,tuple)):
+
+        if isinstance(partition_scanner, (list, tuple)):
             partition_scanner = PartitionScanner(partition_scanner)
         else:
             assert isinstance(partition_scanner, PartitionScanner), "PartitionScanner expected, got %r" % partition_scanner
         self.partition_scanner = partition_scanner
-        
+
         self.scanner = scanner
         for inside_part, inside_scanner in scanner.items():
-            if isinstance(inside_scanner, (list,tuple)):
+            if isinstance(inside_scanner, (list, tuple)):
                 inside_scanner = Scanner(inside_scanner)
                 self.scanner[inside_part] = inside_scanner
             else:
             else:
                 assert isinstance(f, (Format,dict)), "Format expected, got %r" % f
             if isinstance(f, basestring):
-                f = (f,) # only color specified
-            if isinstance(f, (tuple,list)):
+                f = (f,)  # only color specified
+            if isinstance(f, (tuple, list)):
                 f = Format(*((fname,) + f))
             elif isinstance(f, dict):
                 f = Format(**dict(name=fname, **f))
                 assert isinstance(f, Format), "Format expected, got %r" % f
             f.tcf.setFontFamily(parent.defaultFont().family())
             self.formats[f.name] = f.tcf
-            
+
 
         # reduce name look-ups for better speed
         scan_inside = {}
         self.get_scanner = scan_inside.get
         self.scan_partitions = partition_scanner.scan
         self.get_format = self.formats.get
-        
+
 
     def highlightBlock(self, text):
         "automatically called by Qt"
         get_format = self.get_format
         set_format = self.setFormat
         get_scanner = self.get_scanner
-        
+
         for start, end, partition, new_state, is_inside in self.scan_partitions(previous_state, text):
             f = get_format(partition, None)
             if f:
-                set_format(start, end-start, f)
+                set_format(start, end - start, f)
             if is_inside:
                 scan = get_scanner(partition)
                 if scan:
                     for token, token_pos, token_end in scan(text[start:end]):
                         f = get_format(token)
                         if f:
-                            set_format(start+token_pos, token_end-token_pos, f)
+                            set_format(start + token_pos, token_end - token_pos, f)
 
         self.setCurrentBlockState(new_state)
 
 
 
 
-        
+
 def load_syntax(syntax, context=None):
     context = context or {}
 
                 fstyle = context[key]
             else:
                 fstyle = fstyle % context
-        formats.append((fname,fstyle))
+        formats.append((fname, fstyle))
 
     return partition_scanner, scanners, formats
 
 
 __all__ = [
   "Format", "Partition", "PartitionScanner", "Token", "Scanner", "SynxtaxHighlighter", "load_syntax"
-]
+]

File highlighter/customhighlighter.py

             self._highlight_block(block)
             block = block.next()
         
-        
+    # slot for QTextDocument::contentsChange(int,int,int) signal
     def highlight(self, position, removed, added):
         doc = self.sender()
     
 
     def _highlight_block(self, block):
         del self._overrides[:]
+        pos = block.position()
+        length = 0
+
+        while block and block.isValid():
+            state = block.previous().userState() or -1
+            self.previousBlockState = lambda : state
+            self.setCurrentBlockState = block.setUserState
+        
+            layout = block.layout()
+            text = block.text()
     
-        self.previousBlockState = block.previous().userState
-        self.setCurrentBlockState = block.setUserState
-        
-        layout = block.layout()
-        text = block.text()
-        
-        self.highlightBlock(text)
+            self.highlightBlock(text)
+            
+            length += block.length()
+            if (block.userState() == state):
+                break # state did not change
+             
+            block = block.next()
         
         layout.setAdditionalFormats(self._overrides)
-        block.document().markContentsDirty(block.position(), block.length())
-
+        block.document().markContentsDirty(pos, length)
     
-        
+            
     def highlightBlock(self, text):
         pass

File highlighter/js.py

+keywords = [
+ 'break',
+ 'for',
+ 'throw',
+ 'case',
+ 'function',
+ 'try',
+ 'catch',
+ 'if',
+ 'typeof',
+ 'continue',
+ 'in',
+ 'var',
+ 'default',
+ 'instanceof',
+ 'void',
+ 'delete',
+ 'new',
+ 'undefined',
+ 'do',
+ 'return',
+ 'while',
+ 'else',
+ 'switch',
+ 'with',
+ 'finally',
+ 'this',
+ 'NaN',
+ 'Infinity',
+ 'undefined',
+ 'print',
+ 'parseInt',
+ 'parseFloat',
+ 'isNaN',
+ 'isFinite',
+ 'decodeURI',
+ 'decodeURIComponent',
+ 'encodeURI',
+ 'encodeURIComponent',
+ 'escape',
+ 'unescape',
+ 'version',
+ 'gc',
+ 'Object',
+ 'Function',
+ 'Number',
+ 'Boolean',
+ 'String',
+ 'Date',
+ 'Array',
+ 'RegExp',
+ 'Error',
+ 'EvalError',
+ 'RangeError',
+ 'ReferenceError',
+ 'SyntaxError',
+ 'TypeError',
+ 'URIError',
+ 'eval',
+ 'Math',
+ 'Enumeration',
+ 'Variant',
+ 'QObject',
+ 'QMetaObject']
+
+
+syntax =  {'formats': {'builtin': '%(syntax_builtin)s',
+             'comment': '%(syntax_comment)s',
+             'hexnumber': '%(syntax_number)s',
+             'keyword': '%(syntax_keyword)s',
+             'number': '%(syntax_number)s',
+             'string': '%(syntax_string)s'},
+ 'partitions': [('comment', '//', '\n'),
+                ('comment', "/\*", "\*/", True),
+               ],
+ 'scanner': {None: [('hexnumber', '(0x)([0-9a-fA-F])+?'),
+                    ('number', '\\d+(\\.\\d*)?'),
+                    ('keyword', keywords, '(^|[^\\.\\w])', '[\x08\\W]'),
+					('ident', r'[A-Za-z_][A-Za-z_0-9]*')]}}
+			
+
+if __name__ == "__main__":
+	import pprint
+	pprint.pprint(syntax)