Mercurial > lcfOS
view python/libs/widgets/codeeditor.py @ 64:4a27c28c7d0f
File movage
author | windel |
---|---|
date | Sun, 07 Oct 2012 17:13:47 +0200 |
parents | python/apps/ide/codeeditor.py@32078200cdd6 |
children |
line wrap: on
line source
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)