zoukankan      html  css  js  c++  java
  • 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!现在已经可以显示行号和语法高亮了。

  • 相关阅读:
    「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组
    python写一个通讯录
    Git学习笔记
    交换排序
    用Windows自带的方法创建WiFi
    MySQL之触发器
    插入排序
    range和arange的区别
    Spring前后端跨域请求设置
    三、图的定义及遍历
  • 原文地址:https://www.cnblogs.com/china_x01/p/14258318.html
Copyright © 2011-2022 走看看