diff --git a/src/vs/editor/common/model/indentationGuesser.ts b/src/vs/editor/common/model/indentationGuesser.ts index 0ec4e0c63efcc1a8768042ffeba6e88c17c7ba23..8b49b66fa2ec8146cff7e83a567c29521965465d 100644 --- a/src/vs/editor/common/model/indentationGuesser.ts +++ b/src/vs/editor/common/model/indentationGuesser.ts @@ -7,12 +7,12 @@ import { CharCode } from 'vs/base/common/charCode'; import { ITextBuffer } from 'vs/editor/common/model/textBuffer'; -export interface IIndentationGuesserTarget { +export interface IIndentationGuesserSource { getLineCount(): number; getLineContent(lineNumber: number): string; } -export class IndentationGuesserTextBufferTarget implements IIndentationGuesserTarget { +export class IndentationGuesserTextBufferSource implements IIndentationGuesserSource { constructor( private readonly _buffer: ITextBuffer @@ -27,7 +27,7 @@ export class IndentationGuesserTextBufferTarget implements IIndentationGuesserTa } } -export class IndentationGuesserStringArrayTarget implements IIndentationGuesserTarget { +export class IndentationGuesserStringArraySource implements IIndentationGuesserSource { constructor( private readonly _lines: string[] @@ -116,9 +116,9 @@ export interface IGuessedIndentation { insertSpaces: boolean; } -export function guessIndentation(target: IIndentationGuesserTarget, defaultTabSize: number, defaultInsertSpaces: boolean): IGuessedIndentation { +export function guessIndentation(source: IIndentationGuesserSource, defaultTabSize: number, defaultInsertSpaces: boolean): IGuessedIndentation { // Look at most at the first 10k lines - const linesCount = Math.min(target.getLineCount(), 10000); + const linesCount = Math.min(source.getLineCount(), 10000); let linesIndentedWithTabsCount = 0; // number of lines that contain at least one tab in indentation let linesIndentedWithSpacesCount = 0; // number of lines that contain only spaces in indentation @@ -132,7 +132,7 @@ export function guessIndentation(target: IIndentationGuesserTarget, defaultTabSi let spacesDiffCount = [0, 0, 0, 0, 0, 0, 0, 0, 0]; // `tabSize` scores for (let lineNumber = 1; lineNumber <= linesCount; lineNumber++) { - let currentLineText = target.getLineContent(lineNumber); + let currentLineText = source.getLineContent(lineNumber); let currentLineHasContent = false; // does `currentLineText` contain non-whitespace chars let currentLineIndentation = 0; // index at which `currentLineText` contains the first non-whitespace char diff --git a/src/vs/editor/common/model/modelLine.ts b/src/vs/editor/common/model/modelLine.ts index e674fe4b5f492f3f633b11c6cf4202571a48b614..1ae6837159733d9dfaa2e4d5365ba82ec986e357 100644 --- a/src/vs/editor/common/model/modelLine.ts +++ b/src/vs/editor/common/model/modelLine.ts @@ -5,7 +5,6 @@ 'use strict'; import { IState, FontStyle, StandardTokenType, MetadataConsts, ColorId, LanguageId, ITokenizationSupport, LanguageIdentifier } from 'vs/editor/common/modes'; -import { CharCode } from 'vs/base/common/charCode'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import * as arrays from 'vs/base/common/arrays'; import { Position } from 'vs/editor/common/core/position'; @@ -16,35 +15,6 @@ import { ITextBuffer } from 'vs/editor/common/model/textBuffer'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; import { nullTokenize2 } from 'vs/editor/common/modes/nullMode'; -/** - * Returns: - * - -1 => the line consists of whitespace - * - otherwise => the indent level is returned value - */ -export function computeIndentLevel(line: string, tabSize: number): number { - let indent = 0; - let i = 0; - let len = line.length; - - while (i < len) { - let chCode = line.charCodeAt(i); - if (chCode === CharCode.Space) { - indent++; - } else if (chCode === CharCode.Tab) { - indent = indent - indent % tabSize + tabSize; - } else { - break; - } - i++; - } - - if (i === len) { - return -1; // line only consists of whitespace - } - - return indent; -} - function getDefaultMetadata(topLevelLanguageId: LanguageId): number { return ( (topLevelLanguageId << MetadataConsts.LANGUAGEID_OFFSET) diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 5cb22619cfd2fa5a55eea087afdabbe961773c42..61b78f704466fe3eeb34d6c903f15028dac37673 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -28,8 +28,8 @@ import { Position, IPosition } from 'vs/editor/common/core/position'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { getWordAtText } from 'vs/editor/common/model/wordHelper'; -import { ModelLinesTokens, computeIndentLevel, ModelTokensChangedEventBuilder } from 'vs/editor/common/model/modelLine'; -import { guessIndentation, IndentationGuesserTextBufferTarget, IndentationGuesserStringArrayTarget } from 'vs/editor/common/model/indentationGuesser'; +import { ModelLinesTokens, ModelTokensChangedEventBuilder } from 'vs/editor/common/model/modelLine'; +import { guessIndentation, IndentationGuesserTextBufferSource, IndentationGuesserStringArraySource } from 'vs/editor/common/model/indentationGuesser'; import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { TextModelSearch, SearchParams } from 'vs/editor/common/model/textModelSearch'; import { TextBuffer, ITextBuffer } from 'vs/editor/common/model/textBuffer'; @@ -82,7 +82,7 @@ export class TextModel extends Disposable implements model.ITextModel { let resolvedOpts: model.TextModelResolvedOptions; if (options.detectIndentation) { - const guessedIndentation = guessIndentation(new IndentationGuesserStringArrayTarget(textSource.lines), options.tabSize, options.insertSpaces); + const guessedIndentation = guessIndentation(new IndentationGuesserStringArraySource(textSource.lines), options.tabSize, options.insertSpaces); resolvedOpts = new model.TextModelResolvedOptions({ tabSize: guessedIndentation.tabSize, insertSpaces: guessedIndentation.insertSpaces, @@ -515,7 +515,7 @@ export class TextModel extends Disposable implements model.ITextModel { public detectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void { this._assertNotDisposed(); - let guessedIndentation = guessIndentation(new IndentationGuesserTextBufferTarget(this._buffer), defaultTabSize, defaultInsertSpaces); + let guessedIndentation = guessIndentation(new IndentationGuesserTextBufferSource(this._buffer), defaultTabSize, defaultInsertSpaces); this.updateOptions({ insertSpaces: guessedIndentation.insertSpaces, tabSize: guessedIndentation.tabSize @@ -1944,8 +1944,37 @@ export class TextModel extends Disposable implements model.ITextModel { }; } + /** + * Returns: + * - -1 => the line consists of whitespace + * - otherwise => the indent level is returned value + */ + public static computeIndentLevel(line: string, tabSize: number): number { + let indent = 0; + let i = 0; + let len = line.length; + + while (i < len) { + let chCode = line.charCodeAt(i); + if (chCode === CharCode.Space) { + indent++; + } else if (chCode === CharCode.Tab) { + indent = indent - indent % tabSize + tabSize; + } else { + break; + } + i++; + } + + if (i === len) { + return -1; // line only consists of whitespace + } + + return indent; + } + private _computeIndentLevel(lineIndex: number): number { - return computeIndentLevel(this._buffer.getLineContent(lineIndex + 1), this._options.tabSize); + return TextModel.computeIndentLevel(this._buffer.getLineContent(lineIndex + 1), this._options.tabSize); } public getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] { diff --git a/src/vs/editor/contrib/folding/indentRangeProvider.ts b/src/vs/editor/contrib/folding/indentRangeProvider.ts index fcecb4f4c50b1b4fd3dbbb0f7e82f2d8ddfcfaeb..04259b2c8b81d77a5c46fea453d96a585cd68593 100644 --- a/src/vs/editor/contrib/folding/indentRangeProvider.ts +++ b/src/vs/editor/contrib/folding/indentRangeProvider.ts @@ -7,8 +7,8 @@ import { ITextModel } from 'vs/editor/common/model'; import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration'; -import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; import { FoldingRanges, MAX_LINE_NUMBER } from 'vs/editor/contrib/folding/foldingRanges'; +import { TextModel } from 'vs/editor/common/model/textModel'; const MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000; @@ -71,7 +71,7 @@ export class RangesCollector { for (let i = this._length - 1, k = 0; i >= 0; i--) { let startIndex = this._startIndexes[i]; let lineContent = model.getLineContent(startIndex); - let indent = computeIndentLevel(lineContent, tabSize); + let indent = TextModel.computeIndentLevel(lineContent, tabSize); if (indent < maxIndent) { startIndexes[k] = startIndex; endIndexes[k] = this._endIndexes[i]; @@ -101,7 +101,7 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol for (let line = model.getLineCount(); line > 0; line--) { let lineContent = model.getLineContent(line); - let indent = computeIndentLevel(lineContent, tabSize); + let indent = TextModel.computeIndentLevel(lineContent, tabSize); let previous = previousRegions[previousRegions.length - 1]; if (indent === -1) { if (offSide && !previous.marker) { diff --git a/src/vs/editor/contrib/quickFix/lightBulbWidget.ts b/src/vs/editor/contrib/quickFix/lightBulbWidget.ts index 70859d7e5a0ab470cb8550fa95a53d1b49fcdd44..fa09031b8a5566648f8bf84b632f6d30b9faa73b 100644 --- a/src/vs/editor/contrib/quickFix/lightBulbWidget.ts +++ b/src/vs/editor/contrib/quickFix/lightBulbWidget.ts @@ -12,7 +12,7 @@ import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveM import * as dom from 'vs/base/browser/dom'; import { ICodeEditor, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { QuickFixComputeEvent } from './quickFixModel'; -import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; +import { TextModel } from 'vs/editor/common/model/textModel'; export class LightBulbWidget implements IDisposable, IContentWidget { @@ -139,7 +139,7 @@ export class LightBulbWidget implements IDisposable, IContentWidget { const model = this._editor.getModel(); const tabSize = model.getOptions().tabSize; const lineContent = model.getLineContent(lineNumber); - const indent = computeIndentLevel(lineContent, tabSize); + const indent = TextModel.computeIndentLevel(lineContent, tabSize); const lineHasSpace = config.fontInfo.spaceWidth * indent > 22; let effectiveLineNumber = lineNumber; diff --git a/src/vs/editor/test/common/model/model.line.test.ts b/src/vs/editor/test/common/model/model.line.test.ts index 2ef7b856f34b65b8c66eb69b287a500130913586..3a8baf6f4c844d7df1faadb68025986f5b94d8b1 100644 --- a/src/vs/editor/test/common/model/model.line.test.ts +++ b/src/vs/editor/test/common/model/model.line.test.ts @@ -6,7 +6,6 @@ import * as assert from 'assert'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; -import { computeIndentLevel } from 'vs/editor/common/model/modelLine'; import { LanguageIdentifier, MetadataConsts } from 'vs/editor/common/modes'; import { Range } from 'vs/editor/common/core/range'; import { ViewLineToken, ViewLineTokenFactory } from 'vs/editor/test/common/core/viewLineToken'; @@ -46,7 +45,7 @@ function assertLineTokens(__actual: LineTokens, _expected: TestToken[]): void { suite('ModelLine - getIndentLevel', () => { function assertIndentLevel(text: string, expected: number, tabSize: number = 4): void { - let actual = computeIndentLevel(text, tabSize); + let actual = TextModel.computeIndentLevel(text, tabSize); assert.equal(actual, expected, text); }