[英]How can I make QScintilla auto-indent like SublimeText?
考慮下面的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
與您的自定義插槽連接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仍然可以看作是黑匣子。
看來您必須編寫自己的版本, 文檔在“ 安裝 ”一章中已經提到了最重要的一點:
隨附的QScintilla將構建為共享庫/ DLL,並安裝在與Qt庫相同的目錄中,並包含文件。
如果您希望構建靜態版本的庫,請在qmake命令行中傳遞CONFIG + = staticlib。
如果要對配置進行更重要的更改,請在Qt4Qt5目錄中編輯文件qscintilla.pro。
如果確實要進行更改,特別是對安裝目錄的名稱或庫的名稱進行更改,則可能還需要更新Qt4Qt5 / features / qscintilla2.prf文件。*
那里也解釋了進一步的步驟。
在QScintilla
(特別是在SublimeText
),沒有使自動縮進起作用的集成方法。 此行為是特定於語言和特定於用戶的。 本機Scintilla文檔包含有關如何觸發自動縮進的示例。 抱歉,它是用C#編寫的。 我還沒有發現它是用Python編寫的。
這是一個代碼(我知道QScintilla是Qt的端口,此面向Scintilla的代碼也應與QScintilla一起使用,或者最壞的情況是您可以將其改編為C ++):
private void Scintilla_InsertCheck(object sender, InsertCheckEventArgs e) {
if ((e.Text.EndsWith("" + Constants.vbCr) || e.Text.EndsWith("" + Constants.vbLf))) {
int startPos = Scintilla.Lines(Scintilla.LineFromPosition(Scintilla.CurrentPosition)).Position;
int endPos = e.Position;
string curLineText = Scintilla.GetTextRange(startPos, (endPos - startPos));
// Text until the caret so that the whitespace is always
// equal in every line.
Match indent = Regex.Match(curLineText, "^[ \\t]*");
e.Text = (e.Text + indent.Value);
if (Regex.IsMatch(curLineText, "{\\s*$")) {
e.Text = (e.Text + Constants.vbTab);
}
}
}
private void Scintilla_CharAdded(object sender, CharAddedEventArgs e) {
//The '}' char.
if (e.Char == 125) {
int curLine = Scintilla.LineFromPosition(Scintilla.CurrentPosition);
if (Scintilla.Lines(curLine).Text.Trim() == "}") {
//Check whether the bracket is the only thing on the line.
//For cases like "if() { }".
SetIndent(Scintilla, curLine, GetIndent(Scintilla, curLine) - 4);
}
}
}
//Codes for the handling the Indention of the lines.
//They are manually added here until they get officially
//added to the Scintilla control.
#region "CodeIndent Handlers"
const int SCI_SETLINEINDENTATION = 2126;
const int SCI_GETLINEINDENTATION = 2127;
private void SetIndent(ScintillaNET.Scintilla scin, int line, int indent) {
scin.DirectMessage(SCI_SETLINEINDENTATION, new IntPtr(line), new IntPtr(indent));
}
private int GetIndent(ScintillaNET.Scintilla scin, int line) {
return (scin.DirectMessage(SCI_GETLINEINDENTATION, new IntPtr(line), null).ToInt32);
}
#endregion
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.