forked from qt-creator/qt-creator
Automagically insert matching characters.
This commit is contained in:
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
using namespace CPlusPlus;
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, int maxBlockCount)
|
BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suffix, int maxBlockCount)
|
||||||
: _offset(0)
|
: _offset(0)
|
||||||
, _blocksTokenized(0)
|
, _blocksTokenized(0)
|
||||||
, _block(cursor.block())
|
, _block(cursor.block())
|
||||||
@@ -40,6 +40,10 @@ BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, int maxBlockCount)
|
|||||||
{
|
{
|
||||||
_tokenize.setSkipComments(true);
|
_tokenize.setSkipComments(true);
|
||||||
_text = _block.text().left(cursor.position() - cursor.block().position());
|
_text = _block.text().left(cursor.position() - cursor.block().position());
|
||||||
|
|
||||||
|
if (! suffix.isEmpty())
|
||||||
|
_text += suffix;
|
||||||
|
|
||||||
_tokens.append(_tokenize(_text, previousBlockState(_block)));
|
_tokens.append(_tokenize(_text, previousBlockState(_block)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ class CPLUSPLUS_EXPORT BackwardsScanner
|
|||||||
enum { MAX_BLOCK_COUNT = 10 };
|
enum { MAX_BLOCK_COUNT = 10 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BackwardsScanner(const QTextCursor &cursor, int maxBlockCount = MAX_BLOCK_COUNT);
|
BackwardsScanner(const QTextCursor &cursor,
|
||||||
|
const QString &suffix = QString(),
|
||||||
|
int maxBlockCount = MAX_BLOCK_COUNT);
|
||||||
|
|
||||||
int state() const;
|
int state() const;
|
||||||
int startToken() const;
|
int startToken() const;
|
||||||
|
|||||||
@@ -153,10 +153,8 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor)
|
|||||||
return scanner.text(i, initialSize);
|
return scanner.text(i, initialSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor)
|
int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const
|
||||||
{
|
{
|
||||||
QString text;
|
|
||||||
|
|
||||||
BackwardsScanner scanner(cursor);
|
BackwardsScanner scanner(cursor);
|
||||||
|
|
||||||
int index = scanner.startToken();
|
int index = scanner.startToken();
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
~ExpressionUnderCursor();
|
~ExpressionUnderCursor();
|
||||||
|
|
||||||
QString operator()(const QTextCursor &cursor);
|
QString operator()(const QTextCursor &cursor);
|
||||||
int startOfFunctionCall(const QTextCursor &cursor);
|
int startOfFunctionCall(const QTextCursor &cursor) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int startOfExpression(BackwardsScanner &tk, int index);
|
int startOfExpression(BackwardsScanner &tk, int index);
|
||||||
|
|||||||
@@ -34,17 +34,124 @@
|
|||||||
|
|
||||||
using namespace CPlusPlus;
|
using namespace CPlusPlus;
|
||||||
|
|
||||||
|
enum { MAX_NUM_LINES = 400 };
|
||||||
|
|
||||||
|
static bool maybeOverrideChar(const QChar &ch)
|
||||||
|
{
|
||||||
|
if (ch == QLatin1Char(')')) return true;
|
||||||
|
else if (ch == QLatin1Char(']')) return true;
|
||||||
|
else if (ch == QLatin1Char('"')) return true;
|
||||||
|
else if (ch == QLatin1Char('\'')) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isCompleteStringLiteral(const BackwardsScanner &tk, int index, int startToken)
|
||||||
|
{
|
||||||
|
const QStringRef text = tk.textRef(index, startToken);
|
||||||
|
|
||||||
|
if (text.length() < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
else if (text.at(text.length() - 1) == QLatin1Char('"'))
|
||||||
|
return text.at(text.length() - 2) != QLatin1Char('\\'); // ### not exactly.
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isCompleteCharLiteral(const BackwardsScanner &tk, int index, int startToken)
|
||||||
|
{
|
||||||
|
const QStringRef text = tk.textRef(index, startToken);
|
||||||
|
|
||||||
|
if (text.length() < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
else if (text.at(text.length() - 1) == QLatin1Char('\''))
|
||||||
|
return text.at(text.length() - 2) != QLatin1Char('\\'); // ### not exactly.
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MatchingText::MatchingText()
|
MatchingText::MatchingText()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QString &textToProcess, int *skippedChars) const
|
||||||
|
{
|
||||||
|
*skippedChars = 0;
|
||||||
|
|
||||||
|
QTextCursor tc = cursor;
|
||||||
|
QString text = textToProcess;
|
||||||
|
|
||||||
|
const QString blockText = tc.block().text().mid(tc.columnNumber());
|
||||||
|
const int length = qMin(blockText.length(), textToProcess.length());
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
const QChar ch1 = blockText.at(i);
|
||||||
|
const QChar ch2 = textToProcess.at(i);
|
||||||
|
|
||||||
|
if (ch1 != ch2)
|
||||||
|
break;
|
||||||
|
else if (! maybeOverrideChar(ch1))
|
||||||
|
break;
|
||||||
|
|
||||||
|
++*skippedChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*skippedChars != 0) {
|
||||||
|
tc.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, *skippedChars);
|
||||||
|
text = textToProcess.mid(*skippedChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.isEmpty())
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
BackwardsScanner tk(tc, textToProcess.left(*skippedChars), MAX_NUM_LINES);
|
||||||
|
const int startToken = tk.startToken();
|
||||||
|
int index = startToken;
|
||||||
|
|
||||||
|
const SimpleToken &token = tk[index - 1];
|
||||||
|
|
||||||
|
if (text.at(0) == QLatin1Char('"') && (token.is(T_STRING_LITERAL) || token.is(T_WIDE_STRING_LITERAL))) {
|
||||||
|
if (text.length() != 1)
|
||||||
|
qWarning() << Q_FUNC_INFO << "handle event compression";
|
||||||
|
|
||||||
|
if (isCompleteStringLiteral(tk, index - 1, startToken))
|
||||||
|
return QLatin1String("\"");
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
} else if (text.at(0) == QLatin1Char('\'') && (token.is(T_CHAR_LITERAL) || token.is(T_WIDE_CHAR_LITERAL))) {
|
||||||
|
if (text.length() != 1)
|
||||||
|
qWarning() << Q_FUNC_INFO << "handle event compression";
|
||||||
|
|
||||||
|
if (isCompleteCharLiteral(tk, index - 1, startToken))
|
||||||
|
return QLatin1String("'");
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString result;
|
||||||
|
|
||||||
|
foreach (const QChar &ch, text) {
|
||||||
|
if (ch == QLatin1Char('(')) result += ')';
|
||||||
|
else if (ch == QLatin1Char('[')) result += ']';
|
||||||
|
else if (ch == QLatin1Char('"')) result += '"';
|
||||||
|
else if (ch == QLatin1Char('\'')) result += '\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) const
|
QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) const
|
||||||
{
|
{
|
||||||
BackwardsScanner tk(tc, 400);
|
BackwardsScanner tk(tc, QString(), MAX_NUM_LINES);
|
||||||
int index = tk.startToken();
|
int index = tk.startToken();
|
||||||
|
|
||||||
if (tk[index - 1].isNot(T_LBRACE))
|
if (tk[index - 1].isNot(T_LBRACE))
|
||||||
return QString(); // nothing to do.
|
return QString(); // nothing to do.
|
||||||
|
|
||||||
|
const QString textBlock = tc.block().text().mid(tc.columnNumber()).trimmed();
|
||||||
|
if (! textBlock.isEmpty())
|
||||||
|
return QString();
|
||||||
|
|
||||||
--index; // consume the `{'
|
--index; // consume the `{'
|
||||||
|
|
||||||
const SimpleToken &token = tk[index - 1];
|
const SimpleToken &token = tk[index - 1];
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class CPLUSPLUS_EXPORT MatchingText
|
|||||||
public:
|
public:
|
||||||
MatchingText();
|
MatchingText();
|
||||||
|
|
||||||
|
QString insertMatchingBrace(const QTextCursor &tc, const QString &text, int *skippedChars) const;
|
||||||
QString insertParagraphSeparator(const QTextCursor &tc) const;
|
QString insertParagraphSeparator(const QTextCursor &tc) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1269,6 +1269,27 @@ bool CPPEditor::isElectricCharacter(const QChar &ch) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const
|
||||||
|
{
|
||||||
|
if (!contextAllowsAutoParentheses(cursor))
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
QString autoText;
|
||||||
|
int skippedChars = 0;
|
||||||
|
|
||||||
|
MatchingText matchingText;
|
||||||
|
autoText = matchingText.insertMatchingBrace(cursor, text, &skippedChars);
|
||||||
|
|
||||||
|
if (skippedChars) {
|
||||||
|
const int pos = cursor.position();
|
||||||
|
cursor.setPosition(pos + skippedChars);
|
||||||
|
cursor.setPosition(pos, QTextCursor::KeepAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return autoText;
|
||||||
|
}
|
||||||
|
#else
|
||||||
QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const
|
QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const
|
||||||
{
|
{
|
||||||
bool checkBlockEnd = m_allowSkippingOfBlockEnd;
|
bool checkBlockEnd = m_allowSkippingOfBlockEnd;
|
||||||
@@ -1328,6 +1349,7 @@ QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const
|
|||||||
|
|
||||||
return autoText;
|
return autoText;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool CPPEditor::autoBackspace(QTextCursor &cursor)
|
bool CPPEditor::autoBackspace(QTextCursor &cursor)
|
||||||
{
|
{
|
||||||
@@ -1401,9 +1423,10 @@ bool CPPEditor::contextAllowsAutoParentheses(const QTextCursor &cursor) const
|
|||||||
{
|
{
|
||||||
CPlusPlus::TokenUnderCursor tokenUnderCursor;
|
CPlusPlus::TokenUnderCursor tokenUnderCursor;
|
||||||
const SimpleToken tk = tokenUnderCursor(cursor);
|
const SimpleToken tk = tokenUnderCursor(cursor);
|
||||||
if (tk.isComment() || tk.isLiteral())
|
|
||||||
if (tk.end() > cursor.position() - cursor.block().position())
|
if (tk.isComment())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user