aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/utils/textutils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/utils/textutils.cpp')
-rw-r--r--src/libs/utils/textutils.cpp134
1 files changed, 100 insertions, 34 deletions
diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp
index 1222038039..28a9e12e1b 100644
--- a/src/libs/utils/textutils.cpp
+++ b/src/libs/utils/textutils.cpp
@@ -2,40 +2,116 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "textutils.h"
+#include "qtcassert.h"
-#include <QTextDocument>
+#include <QRegularExpression>
#include <QTextBlock>
+#include <QTextDocument>
+
+namespace Utils::Text {
+
+bool Position::operator==(const Position &other) const
+{
+ return line == other.line && column == other.column;
+}
+
+/*!
+ Returns the text position of a \a fileName and sets the \a postfixPos if
+ it can find a positional postfix.
+
+ The following patterns are supported: \c {filepath.txt:19},
+ \c{filepath.txt:19:12}, \c {filepath.txt+19},
+ \c {filepath.txt+19+12}, and \c {filepath.txt(19)}.
+*/
+
+Position Position::fromFileName(QStringView fileName, int &postfixPos)
+{
+ static const auto regexp = QRegularExpression("[:+](\\d+)?([:+](\\d+)?)?$");
+ // (10) MSVC-style
+ static const auto vsRegexp = QRegularExpression("[(]((\\d+)[)]?)?$");
+ const QRegularExpressionMatch match = regexp.match(fileName);
+ Position pos;
+ if (match.hasMatch()) {
+ postfixPos = match.capturedStart(0);
+ if (match.lastCapturedIndex() > 0) {
+ pos.line = match.captured(1).toInt();
+ if (match.lastCapturedIndex() > 2) // index 2 includes the + or : for the column number
+ pos.column = match.captured(3).toInt() - 1; //column is 0 based, despite line being 1 based
+ }
+ } else {
+ const QRegularExpressionMatch vsMatch = vsRegexp.match(fileName);
+ postfixPos = vsMatch.capturedStart(0);
+ if (vsMatch.lastCapturedIndex() > 1) // index 1 includes closing )
+ pos.line = vsMatch.captured(2).toInt();
+ }
+ if (pos.line > 0 && pos.column < 0)
+ pos.column = 0; // if we got a valid line make sure to return a valid TextPosition
+ return pos;
+}
+
+Position Position::fromPositionInDocument(const QTextDocument *document, int pos)
+{
+ QTC_ASSERT(document, return {});
+ const QTextBlock block = document->findBlock(pos);
+ if (block.isValid())
+ return {block.blockNumber() + 1, pos - block.position()};
+
+ return {};
+}
+
+Position Position::fromCursor(const QTextCursor &c)
+{
+ return c.isNull() ? Position{} : Position{c.blockNumber() + 1, c.positionInBlock()};
+}
+
+int Range::length(const QString &text) const
+{
+ if (end.line < begin.line)
+ return -1;
-namespace Utils {
-namespace Text {
+ if (begin.line == end.line)
+ return end.column - begin.column;
+
+ int index = 0;
+ int currentLine = 1;
+ while (currentLine < begin.line) {
+ index = text.indexOf(QChar::LineFeed, index);
+ if (index < 0)
+ return -1;
+ ++index;
+ ++currentLine;
+ }
+ const int beginIndex = index + begin.column;
+ while (currentLine < end.line) {
+ index = text.indexOf(QChar::LineFeed, index);
+ if (index < 0)
+ return -1;
+ ++index;
+ ++currentLine;
+ }
+ return index + end.column - beginIndex;
+}
+
+bool Range::operator==(const Range &other) const
+{
+ return begin == other.begin && end == other.end;
+}
bool convertPosition(const QTextDocument *document, int pos, int *line, int *column)
{
QTextBlock block = document->findBlock(pos);
if (!block.isValid()) {
(*line) = -1;
- (*column) = -1;
+ (*column) = 0;
return false;
} else {
// line and column are both 1-based
(*line) = block.blockNumber() + 1;
- (*column) = pos - block.position() + 1;
+ (*column) = pos - block.position();
return true;
}
}
-OptionalLineColumn convertPosition(const QTextDocument *document, int pos)
-{
- OptionalLineColumn optional;
-
- QTextBlock block = document->findBlock(pos);
-
- if (block.isValid())
- optional.emplace(block.blockNumber() + 1, pos - block.position() + 1);
-
- return optional;
-}
-
int positionInText(const QTextDocument *textDocument, int line, int column)
{
// Deduct 1 from line and column since they are 1-based.
@@ -141,21 +217,6 @@ int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffe
return utf8Offset;
}
-LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset)
-{
- LineColumn lineColumn;
- lineColumn.line = static_cast<int>(
- std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n'))
- + 1;
- const int startOfLineOffset = utf8Offset ? (utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1)
- : 0;
- lineColumn.column = QString::fromUtf8(
- utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset))
- .length()
- + 1;
- return lineColumn;
-}
-
QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset)
{
const int lineStartUtf8Offset = currentUtf8Offset
@@ -211,5 +272,10 @@ void applyReplacements(QTextDocument *doc, const Replacements &replacements)
editCursor.endEditBlock();
}
-} // Text
-} // Utils
+QDebug &operator<<(QDebug &stream, const Position &pos)
+{
+ stream << "line: " << pos.line << ", column: " << pos.column;
+ return stream;
+}
+
+} // namespace Utils::Text