forked from qt-creator/qt-creator
C++: support smart splitting of strings.
If 'enter' is pressed while the cursor is in the middle of a string, the string is ended at the current cursor position, and a new string is started on the next line. This makes it very easy to split a long string onto multiple lines. In addition, Shift+Enter insert an escape in the string, to continue the string at the beginning of next line. A setting can be used to enable or disable this option. Change-Id: Ia5f3c6989fc00d40d06bc4fe1182fe8b1318f565 Reviewed-by: Francois Ferrand <thetypz@gmail.com> Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -85,6 +85,37 @@ static bool isInCommentHelper(const QTextCursor &cursor, Token *retToken = 0)
|
||||
return tk.isComment();
|
||||
}
|
||||
|
||||
static bool isInStringHelper(const QTextCursor &cursor, Token *retToken = 0)
|
||||
{
|
||||
LanguageFeatures features;
|
||||
features.qtEnabled = false;
|
||||
features.qtKeywordsEnabled = false;
|
||||
features.qtMocRunEnabled = false;
|
||||
features.cxx11Enabled = true;
|
||||
features.c99Enabled = true;
|
||||
|
||||
SimpleLexer tokenize;
|
||||
tokenize.setLanguageFeatures(features);
|
||||
|
||||
const int prevState = BackwardsScanner::previousBlockState(cursor.block()) & 0xFF;
|
||||
const QList<Token> tokens = tokenize(cursor.block().text(), prevState);
|
||||
|
||||
const unsigned pos = cursor.selectionEnd() - cursor.block().position();
|
||||
|
||||
if (tokens.isEmpty() || pos < tokens.first().utf16charsBegin())
|
||||
return prevState > 0;
|
||||
|
||||
if (pos >= tokens.last().utf16charsEnd()) {
|
||||
const Token tk = tokens.last();
|
||||
return tk.isStringLiteral() && prevState > 0;
|
||||
}
|
||||
|
||||
Token tk = tokenAtPosition(tokens, pos);
|
||||
if (retToken)
|
||||
*retToken = tk;
|
||||
return tk.isStringLiteral();
|
||||
}
|
||||
|
||||
bool CppAutoCompleter::contextAllowsAutoParentheses(const QTextCursor &cursor,
|
||||
const QString &textToInsert) const
|
||||
{
|
||||
@@ -124,6 +155,11 @@ bool CppAutoCompleter::isInComment(const QTextCursor &cursor) const
|
||||
return isInCommentHelper(cursor);
|
||||
}
|
||||
|
||||
bool CppAutoCompleter::isInString(const QTextCursor &cursor) const
|
||||
{
|
||||
return isInStringHelper(cursor);
|
||||
}
|
||||
|
||||
QString CppAutoCompleter::insertMatchingBrace(const QTextCursor &cursor,
|
||||
const QString &text,
|
||||
QChar la,
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
const QString &textToInsert = QString()) const;
|
||||
virtual bool contextAllowsElectricCharacters(const QTextCursor &cursor) const;
|
||||
virtual bool isInComment(const QTextCursor &cursor) const;
|
||||
virtual bool isInString(const QTextCursor &cursor) const;
|
||||
virtual QString insertMatchingBrace(const QTextCursor &cursor,
|
||||
const QString &text,
|
||||
QChar la,
|
||||
|
||||
@@ -59,8 +59,10 @@
|
||||
#include <cpptools/cppworkingcopy.h>
|
||||
#include <cpptools/symbolfinder.h>
|
||||
|
||||
#include <texteditor/completionsettings.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/textdocumentlayout.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
#include <texteditor/codeassist/assistproposalitem.h>
|
||||
#include <texteditor/codeassist/genericproposalmodel.h>
|
||||
#include <texteditor/codeassist/genericproposal.h>
|
||||
@@ -536,12 +538,47 @@ void CppEditorWidget::keyPressEvent(QKeyEvent *e)
|
||||
if (d->m_localRenaming.handleKeyPressEvent(e))
|
||||
return;
|
||||
|
||||
if (handleStringSplitting(e))
|
||||
return;
|
||||
|
||||
if (d->m_cppDocumentationCommentHelper.handleKeyPressEvent(e))
|
||||
return;
|
||||
|
||||
TextEditorWidget::keyPressEvent(e);
|
||||
}
|
||||
|
||||
bool CppEditorWidget::handleStringSplitting(QKeyEvent *e) const
|
||||
{
|
||||
if (!TextEditorSettings::completionSettings().m_autoSplitStrings)
|
||||
return false;
|
||||
|
||||
if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
||||
QTextCursor cursor = textCursor();
|
||||
|
||||
if (autoCompleter()->isInString(cursor)) {
|
||||
cursor.beginEditBlock();
|
||||
if (cursor.positionInBlock() > 0
|
||||
&& cursor.block().text().at(cursor.positionInBlock() - 1) == QLatin1Char('\\')) {
|
||||
// Already escaped: simply go back to line, but do not indent.
|
||||
cursor.insertText(QLatin1String("\n"));
|
||||
} else if (e->modifiers() & Qt::ShiftModifier) {
|
||||
// With 'shift' modifier, escape the end of line character
|
||||
// and start at beginning of next line.
|
||||
cursor.insertText(QLatin1String("\\\n"));
|
||||
} else {
|
||||
// End the current string, and start a new one on the line, properly indented.
|
||||
cursor.insertText(QLatin1String("\"\n\""));
|
||||
textDocument()->autoIndent(cursor);
|
||||
}
|
||||
cursor.endEditBlock();
|
||||
e->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CppEditorWidget::applyFontSettings()
|
||||
{
|
||||
// This also makes the document apply font settings
|
||||
|
||||
@@ -101,6 +101,7 @@ protected:
|
||||
bool event(QEvent *e) Q_DECL_OVERRIDE;
|
||||
void contextMenuEvent(QContextMenuEvent *) Q_DECL_OVERRIDE;
|
||||
void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE;
|
||||
bool handleStringSplitting(QKeyEvent *e) const;
|
||||
|
||||
void applyFontSettings() Q_DECL_OVERRIDE;
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ QWidget *CompletionSettingsPage::widget()
|
||||
m_page->surroundSelectedText->setChecked(settings.m_surroundingAutoBrackets);
|
||||
m_page->partiallyComplete->setChecked(settings.m_partiallyComplete);
|
||||
m_page->spaceAfterFunctionName->setChecked(settings.m_spaceAfterFunctionName);
|
||||
m_page->autoSplitStrings->setChecked(settings.m_autoSplitStrings);
|
||||
m_page->enableDoxygenCheckBox->setChecked(m_commentsSettings.m_enableDoxygen);
|
||||
m_page->generateBriefCheckBox->setChecked(m_commentsSettings.m_generateBrief);
|
||||
m_page->leadingAsterisksCheckBox->setChecked(m_commentsSettings.m_leadingAsterisks);
|
||||
@@ -118,6 +119,7 @@ void CompletionSettingsPage::apply()
|
||||
settings.m_surroundingAutoBrackets = m_page->surroundSelectedText->isChecked();
|
||||
settings.m_partiallyComplete = m_page->partiallyComplete->isChecked();
|
||||
settings.m_spaceAfterFunctionName = m_page->spaceAfterFunctionName->isChecked();
|
||||
settings.m_autoSplitStrings = m_page->autoSplitStrings->isChecked();
|
||||
|
||||
TextEditor::TextEditorSettings::setCompletionSettings(settings);
|
||||
|
||||
|
||||
@@ -17,6 +17,72 @@
|
||||
<string>Behavior</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="surroundSelectedText">
|
||||
<property name="toolTip">
|
||||
<string>When typing a matching character and there is a text selection, instead of removing the selection, surrounds it with the corresponding characters.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Surround &text selections</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="completionTriggerLabel">
|
||||
<property name="text">
|
||||
<string>Activate completion:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="caseSensitivityLabel">
|
||||
<property name="text">
|
||||
@@ -52,23 +118,10 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="completionTriggerLabel">
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="autoSplitStrings">
|
||||
<property name="text">
|
||||
<string>Activate completion:</string>
|
||||
<string>Automatically split strings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -91,19 +144,6 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="partiallyComplete">
|
||||
<property name="toolTip">
|
||||
@@ -130,40 +170,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="surroundSelectedText">
|
||||
<property name="toolTip">
|
||||
<string>When typing a matching character and there is a text selection, instead of removing the selection, surrounds it with the corresponding characters.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Surround &text selections</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<item row="5" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
|
||||
@@ -332,6 +332,12 @@ bool AutoCompleter::isInComment(const QTextCursor &cursor) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AutoCompleter::isInString(const QTextCursor &cursor) const
|
||||
{
|
||||
Q_UNUSED(cursor);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString AutoCompleter::insertMatchingBrace(const QTextCursor &cursor,
|
||||
const QString &text,
|
||||
QChar la,
|
||||
|
||||
@@ -72,6 +72,9 @@ public:
|
||||
// Returns true if the cursor is inside a comment.
|
||||
virtual bool isInComment(const QTextCursor &cursor) const;
|
||||
|
||||
// Returns true if the cursor is inside a string.
|
||||
virtual bool isInString(const QTextCursor &cursor) const;
|
||||
|
||||
virtual QString insertMatchingBrace(const QTextCursor &cursor, const
|
||||
QString &text,
|
||||
QChar la,
|
||||
|
||||
@@ -39,6 +39,7 @@ static const char autoInsertBracesKey[] = "AutoInsertBraces";
|
||||
static const char surroundingAutoBracketsKey[] = "SurroundingAutoBrackets";
|
||||
static const char partiallyCompleteKey[] = "PartiallyComplete";
|
||||
static const char spaceAfterFunctionNameKey[] = "SpaceAfterFunctionName";
|
||||
static const char autoSplitStringsKey[] = "AutoSplitStrings";
|
||||
|
||||
using namespace TextEditor;
|
||||
|
||||
@@ -49,6 +50,7 @@ CompletionSettings::CompletionSettings()
|
||||
, m_surroundingAutoBrackets(true)
|
||||
, m_partiallyComplete(true)
|
||||
, m_spaceAfterFunctionName(false)
|
||||
, m_autoSplitStrings(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -65,6 +67,7 @@ void CompletionSettings::toSettings(const QString &category, QSettings *s) const
|
||||
s->setValue(QLatin1String(surroundingAutoBracketsKey), m_surroundingAutoBrackets);
|
||||
s->setValue(QLatin1String(partiallyCompleteKey), m_partiallyComplete);
|
||||
s->setValue(QLatin1String(spaceAfterFunctionNameKey), m_spaceAfterFunctionName);
|
||||
s->setValue(QLatin1String(autoSplitStringsKey), m_autoSplitStrings);
|
||||
s->endGroup();
|
||||
}
|
||||
|
||||
@@ -83,6 +86,7 @@ void CompletionSettings::fromSettings(const QString &category, const QSettings *
|
||||
m_surroundingAutoBrackets = s->value(group + QLatin1String(surroundingAutoBracketsKey), m_surroundingAutoBrackets).toBool();
|
||||
m_partiallyComplete = s->value(group + QLatin1String(partiallyCompleteKey), m_partiallyComplete).toBool();
|
||||
m_spaceAfterFunctionName = s->value(group + QLatin1String(spaceAfterFunctionNameKey), m_spaceAfterFunctionName).toBool();
|
||||
m_autoSplitStrings = s->value(group + QLatin1String(autoSplitStringsKey), m_autoSplitStrings).toBool();
|
||||
}
|
||||
|
||||
bool CompletionSettings::equals(const CompletionSettings &cs) const
|
||||
@@ -93,5 +97,6 @@ bool CompletionSettings::equals(const CompletionSettings &cs) const
|
||||
&& m_surroundingAutoBrackets == cs.m_surroundingAutoBrackets
|
||||
&& m_partiallyComplete == cs.m_partiallyComplete
|
||||
&& m_spaceAfterFunctionName == cs.m_spaceAfterFunctionName
|
||||
&& m_autoSplitStrings == cs.m_autoSplitStrings
|
||||
;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ public:
|
||||
bool m_surroundingAutoBrackets;
|
||||
bool m_partiallyComplete;
|
||||
bool m_spaceAfterFunctionName;
|
||||
bool m_autoSplitStrings;
|
||||
};
|
||||
|
||||
inline bool operator==(const CompletionSettings &t1, const CompletionSettings &t2) { return t1.equals(t2); }
|
||||
|
||||
Reference in New Issue
Block a user