Commit 061865ef authored by mae's avatar mae

move auto parentheses handling into the cpp editor

parent 71c46fbc
......@@ -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;
......
......@@ -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;
};
......
......@@ -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;
......
......@@ -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)
......
......@@ -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.
......
......@@ -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);
......
......@@ -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>
......
......@@ -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
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment