diff python/codeeditor.py @ 97:5a965e9664f2

Movage
author windel
date Mon, 24 Dec 2012 13:32:54 +0100
parents python/libs/widgets/codeeditor.py@4a27c28c7d0f
children fe145e42259d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/codeeditor.py	Mon Dec 24 13:32:54 2012 +0100
@@ -0,0 +1,140 @@
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+import compiler.lexer
+import os.path
+
+class MySyntaxHighlighter(QSyntaxHighlighter):
+   def __init__(self, parent=None):
+      super(MySyntaxHighlighter, self).__init__(parent)
+      # Syntax highlighting:
+      self.rules = []
+      fmt = QTextCharFormat()
+      fmt.setForeground(Qt.darkBlue)
+      fmt.setFontWeight(QFont.Bold)
+      for kw in compiler.lexer.keywords:
+         pattern = '\\b'+kw+'\\b'
+         self.rules.append( (pattern, fmt) )
+
+      # Comments:
+      fmt = QTextCharFormat()
+      fmt.setForeground(Qt.gray)
+      fmt.setFontItalic(True)
+      pattern = '\{.*\}'
+      self.rules.append( (pattern, fmt) )
+
+      # Procedure:
+      fmt = QTextCharFormat()
+      fmt.setForeground(Qt.blue)
+      fmt.setFontItalic(True)
+      #pattern = '(?<=procedure )[A-Za-z]'
+      # TODO lookbehind does not work, think something else
+      #self.rules.append( (pattern, fmt) )
+
+   def highlightBlock(self, text):
+      for pattern, fmt in self.rules:
+         expression = QRegExp(pattern)
+         index = expression.indexIn(text)
+         while index >= 0:
+            length = expression.matchedLength()
+            self.setFormat(index, length, fmt)
+            index = expression.indexIn(text, index + length)
+
+class LineNumberArea(QWidget):
+   def __init__(self, codeedit):
+      super(LineNumberArea, self).__init__(codeedit)
+      self.codeedit = codeedit
+      # TODO: display error in this: self.setToolTip('hello world')
+   def sizeHint(self):
+      return QSize(self.codeedit.lineNumberAreaWidth(), 0)
+   def paintEvent(self, ev):
+      self.codeedit.lineNumberAreaPaintEvent(ev)
+
+class CodeEdit(QPlainTextEdit):
+   def __init__(self, parent=None):
+      super(CodeEdit, self).__init__(parent)
+      # members:
+      self.isUntitled = True
+      self.filename = None
+      self.setFont(QFont('Courier'))
+      self.lineNumberArea = LineNumberArea(self)
+
+      self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
+      self.updateRequest.connect(self.updateLineNumberArea)
+
+      # Syntax highlighter:
+      self.highlighter = MySyntaxHighlighter(self.document())
+
+   def setFileName(self, filename):
+      self.filename = filename
+      self.isUntitled = False
+      self.setWindowTitle(filename)
+   def setSource(self, source):
+      self.setPlainText(source)
+
+   def save(self):
+      pass
+   def saveAs(self):
+      pass
+
+   def saveFile(self):
+      if self.isUntitled:
+         self.saveAs()
+      else:
+         source = str(self.toPlainText())
+         f = open(self.filename, 'w')
+         f.write(source)
+         f.close()
+
+   def highlightErrorLocation(self, row, col):
+      tc = QTextCursor(self.document())
+      tc.clearSelection()
+      tc.movePosition(tc.Down, tc.MoveAnchor, row - 1)
+      tc.movePosition(tc.Right, tc.MoveAnchor, col - 1)
+      tc.movePosition(tc.NextCharacter, tc.KeepAnchor) # Select 1 character
+      selection = QTextEdit.ExtraSelection()
+      lineColor = QColor(Qt.red).lighter(160)
+      selection.format.setBackground(lineColor)
+      #selection.format.setProperty(QTextFormat.FullWidthSelection, True)
+      selection.cursor = tc
+      self.setExtraSelections( [ selection ] )
+   def clearErrors(self):
+      self.setExtraSelections( [  ] )
+
+   def lineNumberAreaWidth(self):
+      digits = 1
+      mx = max(1, self.blockCount())
+      while mx >= 10:
+         mx = mx / 10
+         digits += 1
+      space = 3 + self.fontMetrics().width('8') * digits
+      return space
+   def lineNumberAreaPaintEvent(self, ev):
+      painter = QPainter(self.lineNumberArea)
+      painter.fillRect(ev.rect(), Qt.lightGray)
+      block = self.firstVisibleBlock()
+      blockNumber = block.blockNumber()
+      top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top()
+      bottom = top + self.blockBoundingRect(block).height()
+      while block.isValid() and top <= ev.rect().bottom():
+         if block.isVisible() and bottom >= ev.rect().top():
+            num = str(blockNumber + 1)
+            painter.setPen(Qt.black)
+            painter.drawText(0, top, self.lineNumberArea.width(), self.fontMetrics().height(), Qt.AlignRight, num)
+         block = block.next()
+         top = bottom
+         bottom = top + self.blockBoundingRect(block).height()
+         blockNumber += 1
+   def resizeEvent(self, ev):
+      super(CodeEdit, self).resizeEvent(ev)
+      cr = self.contentsRect()
+      self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height() ))
+   def updateLineNumberAreaWidth(self, newBlockCount):
+      self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
+   def updateLineNumberArea(self, rect, dy):
+      if dy > 0:
+         self.lineNumberArea.scroll(0, dy)
+      else:
+         self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
+      if rect.contains(self.viewport().rect()):
+         self.updateLineNumberAreaWidth(0)
+