如何在QScintilla中实现基于缩进的代码折叠?

2024-06-16 09:57:37 发布

您现在位置:Python中文网/ 问答频道 /正文

这里的最终目标是在qscintlla中实现基于缩进的代码折叠,类似于sublimitext3的方式。在

首先,这里有一个小例子,说明如何使用QScintilla机制手动提供折叠:

import sys

from PyQt5.Qsci import QsciScintilla
from PyQt5.Qt import *

if __name__ == '__main__':
    app = QApplication(sys.argv)
    view = QsciScintilla()

    # http://www.scintilla.org/ScintillaDoc.html#Folding
    view.setFolding(QsciScintilla.BoxedTreeFoldStyle)

    lines = [
        (0, "def foo():"),
        (1, "    x = 10"),
        (1, "    y = 20"),
        (1, "    return x+y"),
        (-1, ""),
        (0, "def bar(x):"),
        (1, "    if x > 0:"),
        (2, "        print('this is')"),
        (2, "        print('branch1')"),
        (1, "    else:"),
        (2, "        print('and this')"),
        (2, "        print('is branch2')"),
        (-1, ""),
        (-1, ""),
        (-1, ""),
        (-1, "print('end')"),

    ]

    view.setText("\n".join([b for a, b in lines]))
    MASK = QsciScintilla.SC_FOLDLEVELNUMBERMASK

    for i, tpl in enumerate(lines):
        level, line = tpl
        if level >= 0:
            view.SendScintilla(view.SCI_SETFOLDLEVEL, i, level | QsciScintilla.SC_FOLDLEVELHEADERFLAG)
        else:
            view.SendScintilla(view.SCI_SETFOLDLEVEL, i, 0)

    view.show()
    app.exec_()

要想更深入地了解它,你可以查阅官方文件:

参考文献:

正如我所说,我希望像Sublime一样实现代码折叠,所以我创建了一个小mcve作为基本代码来玩玩:

^{pr2}$

在上面的片段中,您可以看到我试图复制一些崇高的函数。如果我的测试没有错误,indentation_level应该提供与SublimeView提供的输出相同的输出。在

问题:您将如何修改上面的代码片段以提供类似Sublime的基于缩进的代码折叠?在

在这里,您可以看到Sublime是如何工作的:

enter image description here

当然,在使用multiselection(在上面的mcve中已经启用)时,一个适当的标识符也应该起作用,例如:

enter image description here

在Sublime中,您可以看到缩进折叠级别如何在每个文档的更改上完美/高效地更新

我的盒子设置:

  • 胜利7
  • Python 3.6.4(x86)
  • PyQt5==5.12
  • QScintilla==2.10.8

我在互联网上发现了一段很有趣的代码,它很好地工作,https://github.com/pyQode/pyqode.core/blob/master/pyqode/core/api/folding.py问题是代码是用来处理QPlainTextEdit和{}的,所以我不太清楚如何调整它以在QScinScintilla小部件中工作


Tags: 代码fromimportviewappifsyslevel
1条回答
网友
1楼 · 发布于 2024-06-16 09:57:37

[删除前面的答案,因为根据最后一个问题,edit可能只有历史值;如果您仍然好奇,请参考编辑历史]

最后,优化的版本-捆绑了80千行的示例文本来展示它的性能。在

from PyQt5.Qsci import QsciScintilla
from PyQt5.Qt import *


def set_fold(prev, line, fold, full):
    if (prev[0] >= 0):
        fmax = max(fold, prev[1])
        for iter in range(prev[0], line + 1):
            view.SendScintilla(view.SCI_SETFOLDLEVEL, iter,
                fmax | (0, view.SC_FOLDLEVELHEADERFLAG)[iter + 1 < full])

def line_empty(line):
    return view.SendScintilla(view.SCI_GETLINEENDPOSITION, line) \
        <= view.SendScintilla(view.SCI_GETLINEINDENTPOSITION, line)

def modify(position, modificationType, text, length, linesAdded,
           line, foldLevelNow, foldLevelPrev, token, annotationLinesAdded):
    full = view.SC_MOD_INSERTTEXT | view.SC_MOD_DELETETEXT
    if (~modificationType & full == full):
        return
    prev = [-1, 0]
    full = view.SendScintilla(view.SCI_GETLINECOUNT)
    lbgn = view.SendScintilla(view.SCI_LINEFROMPOSITION, position)
    lend = view.SendScintilla(view.SCI_LINEFROMPOSITION, position + length)
    for iter in range(max(lbgn - 1, 0), -1, -1):
        if ((iter == 0) or not line_empty(iter)):
            lbgn = iter
            break
    for iter in range(min(lend + 1, full), full + 1):
        if ((iter == full) or not line_empty(iter)):
            lend = min(iter + 1, full)
            break
    for iter in range(lbgn, lend):
        if (line_empty(iter)):
            if (prev[0] == -1):
                prev[0] = iter
        else:
            fold = view.SendScintilla(view.SCI_GETLINEINDENTATION, iter)
            fold //= view.SendScintilla(view.SCI_GETTABWIDTH)
            set_fold(prev, iter - 1, fold, full)
            set_fold([iter, fold], iter, fold, full)
            prev = [-1, fold]
    set_fold(prev, lend - 1, 0, full)


if __name__ == '__main__':
    import sys
    import textwrap

    app = QApplication(sys.argv)
    view = QsciScintilla()
    view.SendScintilla(view.SCI_SETMULTIPLESELECTION, True)
    view.SendScintilla(view.SCI_SETMULTIPASTE, 1)
    view.SendScintilla(view.SCI_SETADDITIONALSELECTIONTYPING, True)
    view.SendScintilla(view.SCI_SETINDENTATIONGUIDES, view.SC_IV_REAL);
    view.SendScintilla(view.SCI_SETTABWIDTH, 4)
    view.setFolding(view.BoxedFoldStyle)
    view.SCN_MODIFIED.connect(modify)

    NUM_CHUNKS = 20000
    chunk = textwrap.dedent("""\
        x = 1
            x = 2
            x = 3
    """)
    view.setText("\n".join([chunk for i in range(NUM_CHUNKS)]))
    view.show()
    app.exec_()

相关问题 更多 >