From 061865efa4f8299e391cc09c4751b5543a12ba62 Mon Sep 17 00:00:00 2001 From: mae <qt-info@nokia.com> Date: Thu, 17 Sep 2009 12:36:40 +0200 Subject: [PATCH] move auto parentheses handling into the cpp editor --- src/plugins/cppeditor/cppeditor.cpp | 124 ++++++++++++++++- src/plugins/cppeditor/cppeditor.h | 6 + src/plugins/cpptools/cppcodecompletion.cpp | 4 +- src/plugins/texteditor/basetexteditor.cpp | 127 +++--------------- src/plugins/texteditor/basetexteditor.h | 11 +- .../texteditor/behaviorsettingspage.cpp | 2 - .../texteditor/behaviorsettingspage.ui | 9 +- src/plugins/texteditor/tabsettings.cpp | 5 - src/plugins/texteditor/tabsettings.h | 1 - 9 files changed, 157 insertions(+), 132 deletions(-) diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index c90fd1f4be0..ec75b632693 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -529,6 +529,7 @@ CPPEditor::CPPEditor(QWidget *parent) : TextEditor::BaseTextEditor(parent) , m_currentRenameSelection(-1) , m_inRename(false) + , m_allowSkippingOfBlockEnd(false) { qRegisterMetaType<SemanticInfo>("SemanticInfo"); @@ -536,7 +537,6 @@ CPPEditor::CPPEditor(QWidget *parent) m_semanticHighlighter->start(); setParenthesesMatchingEnabled(true); - setAutoParenthesesEnabled(true); setMarksVisible(true); setCodeFoldingSupported(true); setCodeFoldingVisible(true); @@ -1268,6 +1268,128 @@ bool CPPEditor::isElectricCharacter(const QChar &ch) const return false; } +QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const +{ + bool checkBlockEnd = m_allowSkippingOfBlockEnd; + m_allowSkippingOfBlockEnd = false; + + if (!contextAllowsAutoParentheses(cursor)) + return QString(); + + QString autoText; + QChar lookAhead = characterAt(cursor.position()); + if (lookAhead.isSpace() // Only auto-insert when the text right of the cursor seems unrelated + || lookAhead == QLatin1Char('{') + || lookAhead == QLatin1Char('}') + || lookAhead == QLatin1Char(']') + || lookAhead == QLatin1Char(')') + || lookAhead == QLatin1Char(';') + || lookAhead == QLatin1Char(',') + ) { + foreach (QChar c, text) { + QChar close; + if (c == QLatin1Char('(')) { + close = QLatin1Char(')'); + } else if (c == QLatin1Char('[')) + close = QLatin1Char(']'); + else if (c == QLatin1Char('\"')) + close = c; + else if (c == QLatin1Char('\'')) + close = c; + if (!close.isNull()) + autoText += close; + } + } + + bool skip = false; + QChar first = text.at(0); + if (first == QLatin1Char(')') + || first == QLatin1Char(']') + || first == QLatin1Char(';') + ) { + skip = (first == lookAhead); + } else if (first == QLatin1Char('\"') || first == QLatin1Char('\'')) { + if (first == lookAhead) { + QChar lookBehind = characterAt(cursor.position()-1); + skip = (lookBehind != '\\'); + } + } else if (checkBlockEnd && first == QLatin1Char('}') + && lookAhead == QChar::ParagraphSeparator) { + skip = (first == characterAt(cursor.position() + 1)); + cursor.movePosition(QTextCursor::Right); + } + + if (skip) { + int pos = cursor.position(); + cursor.setPosition(pos+1); + cursor.setPosition(pos, QTextCursor::KeepAnchor); + } + + return autoText; +} + +bool CPPEditor::autoBackspace(QTextCursor &cursor) +{ + m_allowSkippingOfBlockEnd = false; + + int pos = cursor.position(); + QTextCursor c = cursor; + c.setPosition(pos - 1); + if (!contextAllowsAutoParentheses(c)) + return false; + + QChar lookAhead = characterAt(pos); + QChar lookBehind = characterAt(pos-1); + QChar lookFurtherBehind = characterAt(pos-2); + if ((lookBehind == QLatin1Char('(') && lookAhead == QLatin1Char(')')) + || (lookBehind == QLatin1Char('[') && lookAhead == QLatin1Char(']')) + || (lookBehind == QLatin1Char('"') && lookAhead == QLatin1Char('"') + && lookFurtherBehind != QLatin1Char('\\')) + || (lookBehind == QLatin1Char('\'') && lookAhead == QLatin1Char('\'') + && lookFurtherBehind != QLatin1Char('\\'))) { + cursor.beginEditBlock(); + cursor.deleteChar(); + cursor.deletePreviousChar(); + cursor.endEditBlock(); + return true; + } + return false; +} + +void CPPEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) +{ + if (characterAt(cursor.position()-1) != QLatin1Char('{')) + return; + + if (!contextAllowsAutoParentheses(cursor)) + return; + + + // verify that we indeed do have an extra opening brace in the document + int braceDepth = document()->lastBlock().userState(); + if (braceDepth >= 0) + braceDepth >>= 8; + else + braceDepth= 0; + + if (braceDepth > 0) { // we do have an extra brace, let's close it + int pos = cursor.position(); + cursor.insertText(QLatin1String("}")); + cursor.setPosition(pos); + const TabSettings &ts = tabSettings(); + if (ts.m_autoIndent) { + cursor.insertBlock(); + indent(document(), cursor, QChar::Null); + } else { + QString previousBlockText = cursor.block().text(); + cursor.insertBlock(); + cursor.insertText(ts.indentationString(previousBlockText)); + } + cursor.setPosition(pos); + m_allowSkippingOfBlockEnd = true; + } +} + bool CPPEditor::contextAllowsAutoParentheses(const QTextCursor &cursor) const { CPlusPlus::TokenUnderCursor tokenUnderCursor; diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 82368bd0903..cb2f0d303a1 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -213,6 +213,10 @@ protected: // These override BaseTextEditor bool isElectricCharacter(const QChar &ch) const; + QString autoComplete(QTextCursor &cursor, const QString &text) const; + bool autoBackspace(QTextCursor &cursor); + void paragraphSeparatorAboutToBeInserted(QTextCursor &cursor); + bool contextAllowsAutoParentheses(const QTextCursor &cursor) const; private Q_SLOTS: @@ -279,6 +283,8 @@ private: int m_currentRenameSelection; bool m_inRename; + mutable bool m_allowSkippingOfBlockEnd; + SemanticHighlighter *m_semanticHighlighter; SemanticInfo m_lastSemanticInfo; }; diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 718c2f02ed0..4c7c0a038f5 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -1470,9 +1470,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) int extraLength = 0; int cursorOffset = 0; - bool autoParenthesesEnabled = false; - if (TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(m_editor->widget())) - autoParenthesesEnabled = edit->tabSettings().m_autoParentheses; + bool autoParenthesesEnabled = true; if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { toInsert = item.m_text; diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 51ded1681aa..930039bbcc8 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -178,7 +178,6 @@ BaseTextEditor::BaseTextEditor(QWidget *parent) // (void) new QShortcut(tr("F11"), this, SLOT(slotToggleBlockVisible())); - d->m_autoParenthesesEnabled = false; // parentheses matcher d->m_parenthesesMatchingEnabled = false; d->m_formatRange = true; @@ -891,31 +890,7 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) const TabSettings &ts = d->m_document->tabSettings(); cursor.beginEditBlock(); - if (d->m_autoParenthesesEnabled && ts.m_autoParentheses - && characterAt(cursor.position()-1) == QLatin1Char('{')) { - - // verify that we indeed do have an extra opening brace in the document - int braceDepth = document()->lastBlock().userState(); - if (braceDepth >= 0) - braceDepth >>= 8; - else - braceDepth= 0; - - if (braceDepth > 0) { // we do have an extra brace, let's close it - int pos = cursor.position(); - cursor.insertText(QLatin1String("}")); - cursor.setPosition(pos); - if (ts.m_autoIndent) { - cursor.insertBlock(); - indent(document(), cursor, QChar::Null); - } else { - QString previousBlockText = cursor.block().text(); - cursor.insertBlock(); - cursor.insertText(ts.indentationString(previousBlockText)); - } - cursor.setPosition(pos); - } - } + paragraphSeparatorAboutToBeInserted(cursor); // virtual if (ts.m_autoIndent) { cursor.insertBlock(); @@ -1070,53 +1045,8 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) } else { QTextCursor cursor = textCursor(); QString text = e->text(); - QString autoText; - - if (d->m_autoParenthesesEnabled && d->m_document->tabSettings().m_autoParentheses) { - QChar lookAhead = characterAt(cursor.position()); - if (lookAhead.isSpace() // Only auto-insert when the text right of the cursor seems unrelated - || lookAhead == QLatin1Char('{') - || lookAhead == QLatin1Char('}') - || lookAhead == QLatin1Char(']') - || lookAhead == QLatin1Char(')') - || lookAhead == QLatin1Char(';') - || lookAhead == QLatin1Char(',') - ) { - foreach (QChar c, text) { - QChar close; - if (c == QLatin1Char('(')) { - close = QLatin1Char(')'); - } else if (c == QLatin1Char('[')) - close = QLatin1Char(']'); - else if (c == QLatin1Char('\"')) - close = c; - else if (c == QLatin1Char('\'')) - close = c; - if (!close.isNull()) - autoText += close; - } - } + QString autoText = autoComplete(cursor, text); - bool skip = false; - QChar first = text.at(0); - if (first == QLatin1Char(')') - || first == QLatin1Char(']') - || first == QLatin1Char(';') - ) { - skip = (first == lookAhead); - } else if (first == QLatin1Char('\"') || first == QLatin1Char('\'')) { - if (first == lookAhead) { - QChar lookBehind = characterAt(cursor.position()-1); - skip = (lookBehind != '\\'); - } - } - - if (skip) { - int pos = cursor.position(); - cursor.setPosition(pos+1); - cursor.setPosition(pos, QTextCursor::KeepAnchor); - } - } QChar electricChar; if (d->m_document->tabSettings().m_autoIndent) { foreach (QChar c, text) { @@ -1129,10 +1059,9 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) if (!electricChar.isNull()) cursor.beginEditBlock(); - bool insertAutoParentheses = !autoText.isEmpty() && contextAllowsAutoParentheses(cursor); cursor.insertText(text); - if (insertAutoParentheses) { + if (!autoText.isEmpty()) { int pos = cursor.position(); cursor.insertText(autoText); cursor.setPosition(pos); @@ -1349,16 +1278,6 @@ bool BaseTextEditor::isParenthesesMatchingEnabled() const return d->m_parenthesesMatchingEnabled; } -void BaseTextEditor::setAutoParenthesesEnabled(bool b) -{ - d->m_autoParenthesesEnabled = b; -} - -bool BaseTextEditor::isAutoParenthesesEnabled() const -{ - return d->m_autoParenthesesEnabled; -} - void BaseTextEditor::setHighlightCurrentLine(bool b) { d->m_highlightCurrentLine = b; @@ -3274,27 +3193,8 @@ void BaseTextEditor::handleBackspaceKey() const TextEditor::TabSettings &tabSettings = d->m_document->tabSettings(); - if (tabSettings.m_autoParentheses) { - QChar lookAhead = characterAt(pos); - QChar lookBehind = characterAt(pos-1); - QChar lookFurtherBehind = characterAt(pos-2); - if ((lookBehind == QLatin1Char('(') && lookAhead == QLatin1Char(')')) - || (lookBehind == QLatin1Char('[') && lookAhead == QLatin1Char(']')) - || (lookBehind == QLatin1Char('"') && lookAhead == QLatin1Char('"') - && lookFurtherBehind != QLatin1Char('\\')) - || (lookBehind == QLatin1Char('\'') && lookAhead == QLatin1Char('\'') - && lookFurtherBehind != QLatin1Char('\\'))) { - QTextCursor c = cursor; - c.setPosition(pos - 1); - if (contextAllowsAutoParentheses(c)) { - cursor.beginEditBlock(); - cursor.deleteChar(); - cursor.deletePreviousChar(); - cursor.endEditBlock(); - return; - } - } - } + if (autoBackspace(cursor)) + return; if (!tabSettings.m_smartBackspace) { cursor.deletePreviousChar(); @@ -3366,9 +3266,22 @@ bool BaseTextEditor::isElectricCharacter(const QChar &) const return false; } -bool BaseTextEditor::contextAllowsAutoParentheses(const QTextCursor &) const +QString BaseTextEditor::autoComplete(QTextCursor &cursor, const QString &text) const { - return true; + Q_UNUSED(cursor); + Q_UNUSED(text); + return QString(); +} + +bool BaseTextEditor::autoBackspace(QTextCursor &cursor) +{ + Q_UNUSED(cursor); + return false; +} + +void BaseTextEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) +{ + Q_UNUSED(cursor) } void BaseTextEditor::indentBlock(QTextDocument *, QTextBlock, QChar) diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index efaae0024eb..595b55865d1 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -322,9 +322,6 @@ public: void setParenthesesMatchingEnabled(bool b); bool isParenthesesMatchingEnabled() const; - void setAutoParenthesesEnabled(bool b); - bool isAutoParenthesesEnabled() const; - void setHighlightCurrentLine(bool b); bool highlightCurrentLine() const; @@ -508,8 +505,12 @@ protected: // Returns true if key triggers an indent. virtual bool isElectricCharacter(const QChar &ch) const; - // Returns true if automatic brace matching should be enabled in the context of the given cursor - virtual bool contextAllowsAutoParentheses(const QTextCursor &cursor) const; + // Returns the text to complete at the cursor position, or an empty string + virtual QString autoComplete(QTextCursor &cursor, const QString &text) const; + // Handles backspace. When returning true, backspace processing is stopped + virtual bool autoBackspace(QTextCursor &cursor); + // Hook to insert special characters on enter + virtual void paragraphSeparatorAboutToBeInserted(QTextCursor &cursor); // Indent a text block based on previous line. Default does nothing virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar); // Indent at cursor. Calls indentBlock for selection or current line. diff --git a/src/plugins/texteditor/behaviorsettingspage.cpp b/src/plugins/texteditor/behaviorsettingspage.cpp index a8fa108b7af..ed013c6b610 100644 --- a/src/plugins/texteditor/behaviorsettingspage.cpp +++ b/src/plugins/texteditor/behaviorsettingspage.cpp @@ -130,7 +130,6 @@ void BehaviorSettingsPage::settingsFromUI(TabSettings &tabSettings, { tabSettings.m_spacesForTabs = m_d->m_page.insertSpaces->isChecked(); tabSettings.m_autoIndent = m_d->m_page.autoIndent->isChecked(); - tabSettings.m_autoParentheses= m_d->m_page.autoParentheses->isChecked(); tabSettings.m_smartBackspace = m_d->m_page.smartBackspace->isChecked(); tabSettings.m_tabSize = m_d->m_page.tabSize->value(); tabSettings.m_indentSize = m_d->m_page.indentSize->value(); @@ -147,7 +146,6 @@ void BehaviorSettingsPage::settingsToUI() const TabSettings &tabSettings = m_d->m_tabSettings; m_d->m_page.insertSpaces->setChecked(tabSettings.m_spacesForTabs); m_d->m_page.autoIndent->setChecked(tabSettings.m_autoIndent); - m_d->m_page.autoParentheses->setChecked(tabSettings.m_autoParentheses); m_d->m_page.smartBackspace->setChecked(tabSettings.m_smartBackspace); m_d->m_page.tabSize->setValue(tabSettings.m_tabSize); m_d->m_page.indentSize->setValue(tabSettings.m_indentSize); diff --git a/src/plugins/texteditor/behaviorsettingspage.ui b/src/plugins/texteditor/behaviorsettingspage.ui index a245afcebaf..c20e2aaad12 100644 --- a/src/plugins/texteditor/behaviorsettingspage.ui +++ b/src/plugins/texteditor/behaviorsettingspage.ui @@ -14,7 +14,7 @@ <item> <widget class="QGroupBox" name="groupBoxTabAndIndentSettings"> <property name="title"> - <string>Tabs, Indentation, and Parentheses</string> + <string>Tabs and Indentation</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> @@ -133,13 +133,6 @@ </property> </spacer> </item> - <item row="3" column="0"> - <widget class="QCheckBox" name="autoParentheses"> - <property name="text"> - <string>Enable automatic &parentheses</string> - </property> - </widget> - </item> </layout> </item> <item> diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index 7be914b3171..393434d9085 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -38,7 +38,6 @@ static const char *spacesForTabsKey = "SpacesForTabs"; static const char *smartBackspaceKey = "SmartBackspace"; static const char *autoIndentKey = "AutoIndent"; -static const char *autoParenthesesKey= "AutoParentheses"; static const char *tabSizeKey = "TabSize"; static const char *indentSizeKey = "IndentSize"; static const char *tabKeyBehaviorKey = "TabKeyBehavior"; @@ -49,7 +48,6 @@ namespace TextEditor { TabSettings::TabSettings() : m_spacesForTabs(true), m_autoIndent(true), - m_autoParentheses(true), m_smartBackspace(false), m_tabSize(8), m_indentSize(4), @@ -65,7 +63,6 @@ void TabSettings::toSettings(const QString &category, QSettings *s) const s->beginGroup(group); s->setValue(QLatin1String(spacesForTabsKey), m_spacesForTabs); s->setValue(QLatin1String(autoIndentKey), m_autoIndent); - s->setValue(QLatin1String(autoParenthesesKey), m_autoParentheses); s->setValue(QLatin1String(smartBackspaceKey), m_smartBackspace); s->setValue(QLatin1String(tabSizeKey), m_tabSize); s->setValue(QLatin1String(indentSizeKey), m_indentSize); @@ -84,7 +81,6 @@ void TabSettings::fromSettings(const QString &category, const QSettings *s) m_spacesForTabs = s->value(group + QLatin1String(spacesForTabsKey), m_spacesForTabs).toBool(); m_autoIndent = s->value(group + QLatin1String(autoIndentKey), m_autoIndent).toBool(); - m_autoParentheses = s->value(group + QLatin1String(autoParenthesesKey), m_autoParentheses).toBool(); m_smartBackspace = s->value(group + QLatin1String(smartBackspaceKey), m_smartBackspace).toBool(); m_tabSize = s->value(group + QLatin1String(tabSizeKey), m_tabSize).toInt(); m_indentSize = s->value(group + QLatin1String(indentSizeKey), m_indentSize).toInt(); @@ -263,7 +259,6 @@ bool TabSettings::equals(const TabSettings &ts) const { return m_spacesForTabs == ts.m_spacesForTabs && m_autoIndent == ts.m_autoIndent - && m_autoParentheses== ts.m_autoParentheses && m_smartBackspace == ts.m_smartBackspace && m_tabSize == ts.m_tabSize && m_indentSize == ts.m_indentSize diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index 64bdf89b0da..f26e0bb5ad9 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -74,7 +74,6 @@ struct TEXTEDITOR_EXPORT TabSettings bool m_spacesForTabs; bool m_autoIndent; - bool m_autoParentheses; bool m_smartBackspace; int m_tabSize; int m_indentSize; -- GitLab