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 &amp;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