6#include "kateindentdetecter.h"
8#include "katedocument.h"
10KateIndentDetecter::KateIndentDetecter(KTextEditor::DocumentPrivate *doc)
15struct SpacesDiffResult {
17 bool looksLikeAlignment =
false;
20static SpacesDiffResult spacesDiff(
const QString &a,
int aLength,
const QString &b,
int bLength)
22 SpacesDiffResult result;
23 result.spacesDiff = 0;
24 result.looksLikeAlignment =
false;
33 for (i = 0; i < aLength && i < bLength; i++) {
34 const auto aCharCode = a.
at(i);
35 const auto bCharCode = b.
at(i);
37 if (aCharCode != bCharCode) {
44 for (
int j = i; j < aLength; j++) {
45 const auto aCharCode = a.
at(j);
55 for (
int j = i; j < bLength; j++) {
56 const auto bCharCode = b.
at(j);
64 if (aSpacesCnt > 0 && aTabsCount > 0) {
67 if (bSpacesCnt > 0 && bTabsCount > 0) {
71 const auto tabsDiff = std::abs(aTabsCount - bTabsCount);
72 const auto spacesDiff = std::abs(aSpacesCnt - bSpacesCnt);
77 result.spacesDiff = spacesDiff;
79 if (spacesDiff > 0 && 0 <= bSpacesCnt - 1 && bSpacesCnt - 1 < a.
length() && bSpacesCnt < b.
length()) {
85 result.looksLikeAlignment =
true;
91 if (spacesDiff % tabsDiff == 0) {
92 result.spacesDiff = spacesDiff / tabsDiff;
98KateIndentDetecter::Result KateIndentDetecter::detect(
int defaultTabSize,
bool defaultInsertSpaces)
101 const int linesCount = std::min(m_doc->lines(), 10000);
103 int linesIndentedWithTabsCount = 0;
104 int linesIndentedWithSpacesCount = 0;
107 int previousLineIndentation = 0;
109 constexpr int ALLOWED_TAB_SIZE_GUESSES[7] = {2, 4, 6, 8, 3, 5, 7};
110 constexpr int MAX_ALLOWED_TAB_SIZE_GUESS = 8;
112 int spacesDiffCount[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
113 SpacesDiffResult tmp;
115 for (
int lineNumber = 0; lineNumber < linesCount; lineNumber++) {
116 const QString currentLineText = m_doc->line(lineNumber);
117 const int currentLineLength = currentLineText.
length();
119 bool currentLineHasContent =
false;
120 int currentLineIndentation = 0;
121 int currentLineSpacesCount = 0;
122 int currentLineTabsCount = 0;
123 for (
int j = 0, lenJ = currentLineLength; j < lenJ; j++) {
124 const auto charCode = currentLineText.
at(j);
127 currentLineTabsCount++;
129 currentLineSpacesCount++;
132 currentLineHasContent =
true;
133 currentLineIndentation = j;
139 if (!currentLineHasContent) {
143 if (currentLineTabsCount > 0) {
144 linesIndentedWithTabsCount++;
145 }
else if (currentLineSpacesCount > 1) {
146 linesIndentedWithSpacesCount++;
149 tmp = spacesDiff(previousLineText, previousLineIndentation, currentLineText, currentLineIndentation);
151 if (tmp.looksLikeAlignment) {
162 if (!(defaultInsertSpaces && defaultTabSize == tmp.spacesDiff)) {
167 const int currentSpacesDiff = tmp.spacesDiff;
168 if (currentSpacesDiff <= MAX_ALLOWED_TAB_SIZE_GUESS) {
169 spacesDiffCount[currentSpacesDiff]++;
172 previousLineText = currentLineText;
173 previousLineIndentation = currentLineIndentation;
176 bool insertSpaces = defaultInsertSpaces;
177 if (linesIndentedWithTabsCount != linesIndentedWithSpacesCount) {
178 insertSpaces = (linesIndentedWithTabsCount < linesIndentedWithSpacesCount);
181 int tabSize = defaultTabSize;
185 int tabSizeScore = 0;
186 for (
int i = 0; i < 7; ++i) {
187 int possibleTabSize = ALLOWED_TAB_SIZE_GUESSES[i];
188 const int possibleTabSizeScore = spacesDiffCount[possibleTabSize];
189 if (possibleTabSizeScore > tabSizeScore) {
190 tabSizeScore = possibleTabSizeScore;
191 tabSize = possibleTabSize;
197 if (tabSize == 4 && spacesDiffCount[4] > 0 && spacesDiffCount[2] > 0 && spacesDiffCount[2] >= spacesDiffCount[4] / 2) {
202 if (tabSizeScore == 0) {
203 const auto it = std::max_element(spacesDiffCount, spacesDiffCount + 9);
204 const auto maxIdx = std::distance(spacesDiffCount, it);
211 return {tabSize, insertSpaces};
const QChar at(qsizetype position) const const
qsizetype length() const const