代码之家  ›  专栏  ›  技术社区  ›  BPL

如何在QSCINTILA中实现Sublimitext逐层折叠功能

  •  5
  • BPL  · 技术社区  · 7 年前

    我正在努力实现 fold_by_level QScintilla组件上的Sublimitetext3功能,但我不太清楚如何实现,到目前为止,我已经想出了以下代码:

    import sys
    import re
    import math
    
    from PyQt5.Qt import *  # noqa
    
    from PyQt5.Qsci import QsciScintilla
    from PyQt5 import Qsci
    from PyQt5.Qsci import QsciLexerCPP
    
    
    class Foo(QsciScintilla):
    
        def __init__(self, parent=None):
            super().__init__(parent)
    
            # http://www.scintilla.org/ScintillaDoc.html#Folding
            self.setFolding(QsciScintilla.BoxedTreeFoldStyle)
    
            # Indentation
            self.setIndentationsUseTabs(False)
            self.setIndentationWidth(4)
            self.setBackspaceUnindents(True)
            self.setIndentationGuides(True)
    
            # Set the default font
            self.font = QFont()
            self.font.setFamily('Consolas')
            self.font.setFixedPitch(True)
            self.font.setPointSize(10)
            self.setFont(self.font)
            self.setMarginsFont(self.font)
    
            # Margin 0 is used for line numbers
            fontmetrics = QFontMetrics(self.font)
            self.setMarginsFont(self.font)
            self.setMarginWidth(0, fontmetrics.width("000") + 6)
            self.setMarginLineNumbers(0, True)
            self.setMarginsBackgroundColor(QColor("#cccccc"))
    
            # Indentation
            self.setIndentationsUseTabs(False)
            self.setIndentationWidth(4)
            self.setBackspaceUnindents(True)
    
            lexer = QsciLexerCPP()
            lexer.setFoldAtElse(True)
            lexer.setFoldComments(True)
            lexer.setFoldCompact(False)
            lexer.setFoldPreprocessor(True)
            self.setLexer(lexer)
    
            QShortcut(QKeySequence("Ctrl+K, Ctrl+J"), self,
                      lambda level=-1: self.fold_by_level(level))
            QShortcut(QKeySequence("Ctrl+K, Ctrl+1"), self,
                      lambda level=1: self.fold_by_level(level))
            QShortcut(QKeySequence("Ctrl+K, Ctrl+2"), self,
                      lambda level=2: self.fold_by_level(level))
            QShortcut(QKeySequence("Ctrl+K, Ctrl+3"), self,
                      lambda level=3: self.fold_by_level(level))
            QShortcut(QKeySequence("Ctrl+K, Ctrl+4"), self,
                      lambda level=4: self.fold_by_level(level))
            QShortcut(QKeySequence("Ctrl+K, Ctrl+5"), self,
                      lambda level=5: self.fold_by_level(level))
    
        def fold_by_level(self, lvl):
            if lvl < 0:
                self.foldAll(True)
            else:
                for i in range(self.lines()):
                    level = self.SendScintilla(
                        QsciScintilla.SCI_GETFOLDLEVEL, i) & QsciScintilla.SC_FOLDLEVELNUMBERMASK
                    level -= 0x400
                    print(f"line={i+1}, level={level}")
                    if lvl == level:
                        self.foldLine(i)
    
    
    def main():
        app = QApplication(sys.argv)
        ex = Foo()
        ex.setText("""\
    #include <iostream>
    using namespace std;
    
    void Function0() {
        cout << "Function0";
    }
    
    void Function1() {
        cout << "Function1";
    }
    
    void Function2() {
        cout << "Function2";
    }
    
    void Function3() {
        cout << "Function3";
    }
    
    
    int main(void) {
        if (1) {
            if (1) {
                if (1) {
                    if (1) {
                        int yay;
                    }
                }
            }
        }
    
        if (1) {
            if (1) {
                if (1) {
                    if (1) {
                        int yay2;
                    }
                }
            }
        }
    
        return 0;
    }\
        """)
        ex.resize(800, 600)
        ex.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    我关注的文档是 https://www.scintilla.org/ScintillaDoc.html#Folding http://pyqt.sourceforge.net/Docs/QScintilla2/classQsciScintilla.html

    正如我所说 按级别折叠\u 该特性的行为与Sublimitext完全一样,但我不确定ST的特性实现细节。无论如何,让我在Sublimitext上测试一些基本序列后发布一些屏幕截图,这可以澄清我在这里要实现的目标:

    序列1: {ctrl+k, ctrl+5}, {ctrl+k, ctrl+j} {ctrl+k, ctrl+4}, {ctrl+k, ctrl+j} {ctrl+k, ctrl+3}, {ctrl+k, ctrl+j} {ctrl+k, ctrl+2}, {ctrl+k, ctrl+j} {ctrl+k, ctrl+1}, {ctrl+k, ctrl+j}

    enter image description here

    序列2: {ctrl+k, ctrl+5}, {ctrl+k, ctrl+4}, {ctrl+k, ctrl+3}, {ctrl+k, ctrl+2}, {ctrl+k, ctrl+1}

    enter image description here

    我确信Sublimitext行为有更多的内部细节,但如果我的示例在测试序列后的行为与这些快照上发布的行为完全相同,那么可以说该功能已经变得非常方便使用了。

    1 回复  |  直到 6 年前
        1
  •  3
  •   ekhumoro    6 年前

    您的示例中的问题主要是由QsciScintilla API中的一些错误命名引起的。这个 foldLine foldAll 方法真的应该被调用 toggleFoldLine toggleFoldAll ,因为他们实际上 打开 以前的状态。这意味着,例如,如果两个连续的行具有相同的折叠级别,则调用 foldLine 两次不会导致净变化。

    在下面的实现中,我使用了更明确的闪烁消息,因此只有真正需要折叠的行才会受到影响。我还更改了键盘快捷键,以匹配Sublimitext中的默认值:

    class Foo(QsciScintilla):
        def __init__(self, parent=None):
            ...
            QShortcut(QKeySequence("Ctrl+K, Ctrl+J"), self, self.fold_by_level)
            QShortcut(QKeySequence("Ctrl+K, Ctrl+0"), self, self.fold_by_level)
            ...
    
        def fold_by_level(self, level=0):
            SCI = self.SendScintilla
            if level:
                level += 0x400
                MASK = QsciScintilla.SC_FOLDLEVELNUMBERMASK
                for line in range(self.lines()):
                    foldlevel = SCI(QsciScintilla.SCI_GETFOLDLEVEL, line) & MASK
                    print('line=%i, level=%i' % (line + 1, foldlevel), end='')
                    if foldlevel == level:
                        line = SCI(QsciScintilla.SCI_GETFOLDPARENT, line)
                        if SCI(QsciScintilla.SCI_GETFOLDEXPANDED, line):
                            print(', foldline:', line + 1, end='')
                            SCI(QsciScintilla.SCI_FOLDLINE, line,
                                QsciScintilla.SC_FOLDACTION_CONTRACT)
                    print()
            else:
                SCI(QsciScintilla.SCI_FOLDALL, QsciScintilla.SC_FOLDACTION_EXPAND)