I'm trying to implement the fold_by_level
SublimeText3 feature on a QScintilla component but I don't know very well how to do it, so far I've come up with this code:
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()
The docs I've followed are https://www.scintilla.org/ScintillaDoc.html#Folding and http://pyqt.sourceforge.net/Docs/QScintilla2/classQsciScintilla.html.
As I said, the fold_by_level
feature is intended to behave exactly like SublimeText but I'm unsure about ST's feature implementation details. In any case, let me post some screenshots after testing some basic sequences on SublimeText that could clarify a bit what I'm trying to achieve here:
Sequence1: {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}
Sequence2: {ctrl+k, ctrl+5}, {ctrl+k, ctrl+4}, {ctrl+k, ctrl+3}, {ctrl+k, ctrl+2}, {ctrl+k, ctrl+1}
I'm sure there are more inner details on SublimeText behaviour but if my example behaved exactly like posted on those shots after testing the sequences you could say the feature has become quite handy to use.