• x01.DiamondIDE: hello ide


    x01.DiamondIDE

    虽然一直在用 vscode,但自己写一个也不错。通过比较,选择 Spyder 来学习。代码: x01.DiamondIDE

    1 Edit

    1.1 hello DiamondIDE

    使用 pip 安装所需模块 pyqt 等,自不待言。hello.py 代码如下:

    from qtpy.QtWidgets import QApplication, QPlainTextEdit
    
    app = QApplication(['x01.DiamondIDE'])
    edit = QPlainTextEdit('hello DiamondIDE')
    edit.show()
    app.exec_()
    

    终端输入: python3 hello.py 运行一下,OK!

    1.2 添加测试

    删除 hello.py, 添加 widgets/edit.py 如下:

    # widgets/edit.py (c) 2021 by x01
    
    from qtpy.QtWidgets import QPlainTextEdit, QApplication
    
    class Edit(QPlainTextEdit):
        def __init__(self, parent=None):
            super().__init__(parent=parent)
    
    def test_edit():
        app = QApplication(['x01.DiamondIDE'])
        edit = Edit()
        edit.setPlainText('Hello IDE!')
        edit.show()
        app.exec()
    
    if __name__ == "__main__":
        test_edit()
    

    添加 tests/test_edit.py 如下:

    import os, sys 
    RootDir = os.path.dirname(os.path.dirname(__file__))
    sys.path.append(RootDir)
    
    import widgets.edit as edit 
    
    def test_edit():
        edit.test_edit()
    

    先安装 pytest: python3 -m pip install -U pytest, 然后在终端运行测试: pytest, OK!
    顺便添加 main.py,代码如下:

    import os, sys 
    
    CurrDir = os.path.dirname(__file__)
    sys.path.append(CurrDir)
    
    from widgets.edit import test_edit
    
    def main():
        test_edit()
    
    if __name__ == "__main__":
        main()
    

    运行一下,OK!
    注释 tests/test_edit.py 的 RootDir,添加 test.py 以在测试时统一添加路径,代码如下:

    import os, sys 
    RootDir = os.path.dirname(__file__)
    sys.path.append(RootDir)
    
    import pytest
    
    if __name__ == "__main__":
        pytest.main()
    

    运行一下,OK!

    1.3 切入点

    在 Python 的 site-packages 目录下新建 mypath.pth 文件,添加 x01.DiamondIDE 所在路径,以便导入。
    Spyder 太大,还是以 CodeEditor作为切入点。
    widgets/edit.py 更改如下:

    # widgets/edit.py (c) 2021 by x01
    
    from PyQt5.QtGui import QColor, QFont, QPaintEvent, QPainter, QSyntaxHighlighter, QTextBlock, QTextCharFormat, QTextDocument, QTextFormat
    from PyQt5.QtCore import QRect, Qt, QSize
    from PyQt5.QtWidgets import QMainWindow, QTextEdit, QPlainTextEdit, QApplication, QWidget
    from functools import namedtuple
    import re
    
    def get_span(match, key=None):
        if key is not None:
            start, end = match.span(key)
        else:
            start, end = match.span()
        start = len(match.string[:start])
        end = len(match.string[:end])
        return start, end
    
    class Highlighter(QSyntaxHighlighter):
        HighlightingRule = namedtuple('HighlightingRule', ['pattern', 'format'])
    
        def __init__(self, parent: QTextDocument=None):
            super().__init__(parent)
            self.keywordFormat = QTextCharFormat()
            self.keywordFormat.setForeground(Qt.red)
            self.keywordFormat.setFontWeight(QFont.Bold)
            self.keywords = r'' + '(?P<keyword>' + '|'.join("class int char".split()) + ')' + r''
    
        def highlightBlock(self, text:str):
            patterns = re.compile(self.keywords, re.S)
            match = patterns.search(text)
            index = 0
            while match:
                for key, value in list(match.groupdict().items()):
                    if value:
                        start, end = get_span(match, key)
                        index += end - start 
                        self.setFormat(start, end-start, self.keywordFormat)
                match = patterns.search(text, match.end())
    
    
    class LineNumberArea(QWidget):
        def __init__(self, editor=None):
            super().__init__(editor)
            self.editor = editor
            self.left_padding = 3
            self.right_padding = 6
    
        # override
        def sizeHint(self):
            return QSize(self.editor.LineNumberAreaWidth(), 0)
    
        def paintEvent(self, event):
            self.editor.LineNumberAreaPaintEvent(event)
    
    
    class CodeEditor(QPlainTextEdit):
        def __init__(self, parent=None):
            super().__init__(parent=parent)
            self.line_number_area = LineNumberArea(self)
            self.line_number_enabled = True 
    
            #event
            self.blockCountChanged.connect(self.UpdateLineNumberAreaWidth)
            self.updateRequest.connect(self.UpdateLineNumberArea)
            self.cursorPositionChanged.connect(self.HighlightCurrentLine)
    
            self.UpdateLineNumberAreaWidth(0)
            self.HighlightCurrentLine()
            self.highlighting = Highlighter(self.document())
    
        def resizeEvent(self, event):
            super().resizeEvent(event)
            cr:QRect = self.contentsRect()
            self.line_number_area.setGeometry(QRect(cr.left(), cr.top(), self.LineNumberAreaWidth(), cr.height()))
    
        def LineNumberAreaWidth(self):
            width = 0
            if self.line_number_enabled:
                digits = 1
                count = max(1, self.blockCount())
                while count >= 10:
                    count /= 10
                    digits += 1
                fm = self.fontMetrics()
                width = fm.width('9') * digits + self.line_number_area.left_padding  + self.line_number_area.right_padding
            return width 
    
        def LineNumberAreaPaintEvent(self, event:QPaintEvent):
            if self.line_number_enabled:
                painter = QPainter(self.line_number_area)
                painter.fillRect(event.rect(), Qt.lightGray)
    
                block:QTextBlock  = self.firstVisibleBlock()
                block_number = block.blockNumber()
                top = round(self.blockBoundingGeometry(block).translated(self.contentOffset()).top())
                bottom = top + round(self.blockBoundingRect(block).height())
    
                while block.isValid() and top <= event.rect().bottom():
                    if block.isVisible() and bottom >= event.rect().top():
                        number = block_number + 1
                        painter.setPen(Qt.black)
                        painter.drawText(0, top, self.line_number_area.width() - self.line_number_area.right_padding, 
                                self.fontMetrics().height(), Qt.AlignRight, str(number))
                    block = block.next()
                    top = bottom 
                    bottom = top + round(self.blockBoundingRect(block).height())
                    block_number += 1
    
    
        def UpdateLineNumberAreaWidth(self, new_block_count=None):
            self.setViewportMargins(self.LineNumberAreaWidth(),0,0,0)
    
        def UpdateLineNumberArea(self, rect, dy):
            if self.line_number_enabled:
                if dy:
                    self.line_number_area.scroll(0, dy)
                else:
                    self.line_number_area.update(0, rect.y(), self.line_number_area.width(), rect.height())
                if rect.contains(self.viewport().rect()):
                    self.UpdateLineNumberAreaWidth(0)
    
        def HighlightCurrentLine(self):
            extra = []
            if not self.isReadOnly():
                lineColor = QColor(Qt.yellow).lighter(160)
                selection = QTextEdit.ExtraSelection()
                selection.format.setBackground(lineColor)
                selection.format.setProperty(QTextFormat.FullWidthSelection, True)
                selection.cursor = self.textCursor()
                selection.cursor.clearSelection()
                extra.append(selection)
            self.setExtraSelections(extra)
    
    def test_edit():
        app = QApplication(['x01.DiamondIDE'])
        ed = CodeEditor()
        ed.setPlainText('Hello IDE!')
        ed.show()
        app.exec_()
    
    if __name__ == "__main__":
        test_edit()
    

    运行一下,OK!现在已经可以显示行号和语法高亮了。

  • 相关阅读:
    自己用的,存储代码
    ASCII编码表
    全球最热门编程语言20种
    C++中二维数组new小结
    字符,字节和编码
    让工资涨的快的小技巧
    Ip Messenger
    xajax中文手册
    BitmapFile Formats(BMP文件的格式)
    python中返回字符串中指定字符的索引
  • 原文地址:https://www.cnblogs.com/china_x01/p/14258318.html
Copyright © 2020-2023  润新知