diff --git a/src/vs/editor/common/model/indentationGuesser.ts b/src/vs/editor/common/model/indentationGuesser.ts index 3f89f6d9cd39e7188e4216a4df7a7c0057842782..01e850b65ff55d4b29b293fb52822b3180e310f6 100644 --- a/src/vs/editor/common/model/indentationGuesser.ts +++ b/src/vs/editor/common/model/indentationGuesser.ts @@ -7,10 +7,18 @@ import { CharCode } from 'vs/base/common/charCode'; import { ITextBuffer } from 'vs/editor/common/model'; +class SpacesDiffResult { + public spacesDiff: number; + public looksLikeAlignment: boolean; +} + /** * Compute the diff in spaces between two line's indentation. */ -function spacesDiff(a: string, aLength: number, b: string, bLength: number): number { +function spacesDiff(a: string, aLength: number, b: string, bLength: number, result: SpacesDiffResult): void { + + result.spacesDiff = 0; + result.looksLikeAlignment = false; // This can go both ways (e.g.): // - a: "\t" @@ -49,22 +57,35 @@ function spacesDiff(a: string, aLength: number, b: string, bLength: number): num } if (aSpacesCnt > 0 && aTabsCount > 0) { - return 0; + return; } if (bSpacesCnt > 0 && bTabsCount > 0) { - return 0; + return; } let tabsDiff = Math.abs(aTabsCount - bTabsCount); let spacesDiff = Math.abs(aSpacesCnt - bSpacesCnt); if (tabsDiff === 0) { - return spacesDiff; + // check if the indentation difference might be caused by alignment reasons + // sometime folks like to align their code, but this should not be used as a hint + result.spacesDiff = spacesDiff; + + if (spacesDiff > 0 && 0 <= bSpacesCnt - 1 && bSpacesCnt - 1 < a.length && bSpacesCnt < b.length) { + if (b.charCodeAt(bSpacesCnt) !== CharCode.Space && a.charCodeAt(bSpacesCnt - 1) === CharCode.Space) { + // This looks like an alignment desire: e.g. + // const a = b + c, + // d = b - c; + + result.looksLikeAlignment = true; + } + } + return; } if (spacesDiff % tabsDiff === 0) { - return spacesDiff / tabsDiff; + result.spacesDiff = spacesDiff / tabsDiff; + return; } - return 0; } /** @@ -95,6 +116,7 @@ export function guessIndentation(source: ITextBuffer, defaultTabSize: number, de const MAX_ALLOWED_TAB_SIZE_GUESS = 8; // max(2,4,6,8) = 8 let spacesDiffCount = [0, 0, 0, 0, 0, 0, 0, 0, 0]; // `tabSize` scores + let tmp = new SpacesDiffResult(); for (let lineNumber = 1; lineNumber <= linesCount; lineNumber++) { let currentLineLength = source.getLineLength(lineNumber); @@ -134,7 +156,14 @@ export function guessIndentation(source: ITextBuffer, defaultTabSize: number, de linesIndentedWithSpacesCount++; } - let currentSpacesDiff = spacesDiff(previousLineText, previousLineIndentation, currentLineText, currentLineIndentation); + spacesDiff(previousLineText, previousLineIndentation, currentLineText, currentLineIndentation, tmp); + + if (tmp.looksLikeAlignment) { + // skip this line entirely + continue; + } + + let currentSpacesDiff = tmp.spacesDiff; if (currentSpacesDiff <= MAX_ALLOWED_TAB_SIZE_GUESS) { spacesDiffCount[currentSpacesDiff]++; } diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index d4506ec14e00f98a69c4fb5d4e94878f20f22488..ae557f66ab4f933e6234463f9c6a918a43138502 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -550,6 +550,32 @@ suite('Editor Model - TextModel', () => { ]); }); + test('issue #55818: Broken indentation detection', () => { + assertGuess(true, 2, [ + '', + '/* REQUIRE */', + '', + 'const foo = require ( \'foo\' ),', + ' bar = require ( \'bar\' );', + '', + '/* MY FN */', + '', + 'function myFn () {', + '', + ' const asd = 1,', + ' dsa = 2;', + '', + ' return bar ( foo ( asd ) );', + '', + '}', + '', + '/* EXPORT */', + '', + 'module.exports = myFn;', + '', + ]); + }); + test('validatePosition', () => { let m = TextModel.createFromString('line one\nline two');