考虑下面的 mcve:
import sys
import textwrap
from PyQt5.Qsci import QsciScintilla
from PyQt5.Qt import *
if __name__ == '__main__':
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.setAutoIndent(True)
view.setTabWidth(4)
view.setIndentationGuides(True)
view.setIndentationsUseTabs(False)
view.setBackspaceUnindents(True)
view.setText(textwrap.dedent("""\
def foo(a,b):
print('hello')
"""))
view.show()
app.exec_()
与SublimeText或CodeMirror等编辑器进行比较时,上述代码段的自动缩进行为非常糟糕。首先让我们看看 SublimeText 中的自动缩进功能在单选或多选时会有多好的表现。
现在让我们看看自动缩进如何与上面的代码片段一起工作:
与 SublimeText 相比,当单选/多选启用自动缩进时,QScintilla 的工作方式很糟糕,而且非常糟糕/无法使用。
使小部件更像 SublimeText/Codemirror 的第一步是断开使自动缩进表现不佳的当前插槽,我们可以通过这样做来实现:
print(view.receivers(view.SCN_CHARADDED))
view.SCN_CHARADDED.disconnect()
print(view.receivers(view.SCN_CHARADDED))
在这一点上,您已经准备好SCN_CHARADDED
与您的自定义插槽连接做所有的魔法:)
问题:您将如何修改上述代码段,以便保留所有选择,并且自动缩进的行为与 SublimeText、Codemirror 或任何严肃的文本编辑器完全一样?
参考:
https://www.riverbankcomputing.com/static/Docs/QScintilla/classQsciScintillaBase.html#signals
QScintilla 源代码,您可以在下面看到我们使用断开连接的私有插槽的
disconnect
样子:
qsciscintilla.h
class QSCINTILLA_EXPORT QsciScintilla : public QsciScintillaBase
{
Q_OBJECT
public:
...
private slots:
void handleCharAdded(int charadded);
...
private:
void autoIndentation(char ch, long pos);
qsciscintilla.cpp
connect(this,SIGNAL(SCN_CHARADDED(int)),
SLOT(handleCharAdded(int)));
...
// Handle the addition of a character.
void QsciScintilla::handleCharAdded(int ch)
{
// Ignore if there is a selection.
long pos = SendScintilla(SCI_GETSELECTIONSTART);
if (pos != SendScintilla(SCI_GETSELECTIONEND) || pos == 0)
return;
// If auto-completion is already active then see if this character is a
// start character. If it is then create a new list which will be a subset
// of the current one. The case where it isn't a start character seems to
// be handled correctly elsewhere.
if (isListActive() && isStartChar(ch))
{
cancelList();
startAutoCompletion(acSource, false, use_single == AcusAlways);
return;
}
// Handle call tips.
if (call_tips_style != CallTipsNone && !lex.isNull() && strchr("(),", ch) != NULL)
callTip();
// Handle auto-indentation.
if (autoInd)
{
if (lex.isNull() || (lex->autoIndentStyle() & AiMaintain))
maintainIndentation(ch, pos);
else
autoIndentation(ch, pos);
}
// See if we might want to start auto-completion.
if (!isCallTipActive() && acSource != AcsNone)
{
if (isStartChar(ch))
startAutoCompletion(acSource, false, use_single == AcusAlways);
else if (acThresh >= 1 && isWordCharacter(ch))
startAutoCompletion(acSource, true, use_single == AcusAlways);
}
}
重要提示:我决定发布相关的 c++ 位,以便您了解更多关于如何在内部实现缩进的背景知识,以提供更多关于可能替代的线索......这个线程的目标是尝试找到一个纯 python解决方案。我想避免修改 QScintilla 源代码(如果可能的话),因此维护/升级将保持尽可能简单,并且 QScintilla dep 仍然可以被视为一个黑匣子。