作者:719苗苗113 | 来源:互联网 | 2022-11-01 19:13
这里的最终目标是在QScintilla中实现基于缩进的代码折叠,类似于SublimeText3所做的方式。
首先,这是一个使用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_()
要更深入地了解它,可以查看官方文档:
Doc参考:
QSciScintilla
闪烁折叠
就像我说的,我想像Sublime一样实现代码折叠,因此我创建了这个小mcve作为基本代码,可以作为参考:
import re
import time
from pathlib import Path
from PyQt5.Qsci import QsciLexerCustom, QsciScintilla
from PyQt5.Qt import *
def lskip_nonewlines(text, pt):
len_text = len(text)
while True:
if pt <= 0 or pt >= len_text:
break
if text[pt - 1] == "\n" or text[pt] == "\n":
break
pt -= 1
return pt
def rskip_nonewlines(text, pt):
len_text = len(text)
while True:
if pt <= 0 or pt >= len_text:
break
if text[pt] == "\n":
break
pt += 1
return pt
class Region():
__slots__ = ['a', 'b']
def __init__(self, x, b=None):
if b is None:
if isinstance(x, int):
self.a = x
self.b = x
elif isinstance(x, tuple):
self.a = x[0]
self.b = x[1]
elif isinstance(x, Region):
self.a = x.a
self.b = x.b
else:
raise TypeError(f"Can't convert {x.__class__} to Region")
else:
self.a = x
self.b = b
def __str__(self):
return "(" + str(self.a) + ", " + str(self.b) + ")"
def __repr__(self):
return "(" + str(self.a) + ", " + str(self.b) + ")"
def __len__(self):
return self.size()
def __eq__(self, rhs):
return isinstance(rhs, Region) and self.a == rhs.a and self.b == rhs.b
def __lt__(self, rhs):
lhs_begin = self.begin()
rhs_begin = rhs.begin()
if lhs_begin == rhs_begin:
return self.end() rhs.end():
return [self]
elif rhs.contains(self):
return []
elif self.contains(rhs):
return [Region(self.begin(), rhs.begin()), Region(rhs.end(), self.end())]
elif rhs.begin() <= self.begin():
return [Region(rhs.end(), self.end())]
elif rhs.begin() > self.begin():
return [Region(self.begin(), rhs.begin())]
else:
raise Exception("Unknown case")
def empty(self):
return self.a == self.b
def begin(self):
if self.a = self.begin() and x <= self.end()
def cover(self, rhs):
a = min(self.begin(), rhs.begin())
b = max(self.end(), rhs.end())
if self.a = rhs.end():
return Region(0)
return Region(max(self.begin(), rhs.begin()), min(self.end(), rhs.end()))
def intersects(self, rhs):
lb = self.begin()
le = self.end()
rb = rhs.begin()
re = rhs.end()
return (
(lb == rb and le == re) or
(rb > lb and rb lb and re rb and lb rb and le view.size():
return 0
else:
i = 0
count = 0
len_line = len(line)
level = 0
while True:
if i >= len_line:
break
if line[i] == " ":
i += 1
count += 1
if count == self.tab_size:
level += 1
count = 0
elif line[i] == "\t":
level += 1
else:
break
if count != 0:
level += 1
return level
if __name__ == '__main__':
import sys
import textwrap
app = QApplication(sys.argv)
view = View()
view.setText(textwrap.dedent("""\
x - 0
x - 3
x - 3
x - 4
x - 3
x - 1
x - 2
x - 2
x - 2
x - 3
x - 3
x - 4
x - 3
x - 1
x - 4
x - 0
a
b
c
d
e
f
"""))
view.show()
app.exec_()
在上面的代码片段中,您可以看到我已经尝试复制一些Sublime函数。如果我的测试没有错,则indentation_level
应该提供与Sublime View提供的输出相同的输出。
问题:您将如何修改上面的代码片段,以提供基于缩进的代码折叠(例如Sublime的代码折叠)?
在这里,您可以看到Sublime如何工作的示例:
当然,使用多重选择(在上面的mcve中已启用)时,适当的标识符也应该起作用,例如:
您可以查看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
,QSyntaxHighlighter
所以我不太清楚如何调整它以在QScinScintilla
小部件中工作
1> hidefromkgb..:
[删除了先前的答案,因为鉴于最后一个问题,编辑可能唯一具有历史价值的值;如果仍然感到好奇,请参阅编辑历史记录]
最后,优化版本-捆绑了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