From 15627c7403732469108f50f22872d1e3427c6ac6 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 2 Feb 2017 16:28:31 +0100 Subject: [PATCH] View improvements: - add a prefix sum cache that is warmed up for the viewport - improve some of the position mapping/validation code --- src/vs/editor/browser/editorBrowser.ts | 1 - src/vs/editor/browser/view/viewImpl.ts | 16 +- .../editor/browser/widget/codeEditorWidget.ts | 2 +- src/vs/editor/common/commonCodeEditor.ts | 3 +- .../common/viewModel/prefixSumComputer.ts | 91 +++++++- .../common/viewModel/splitLinesCollection.ts | 212 +++++++++++------- src/vs/editor/common/viewModel/viewModel.ts | 5 + .../common/viewModel/viewModelCursors.ts | 81 ++----- .../editor/common/viewModel/viewModelImpl.ts | 99 ++++---- .../viewModel/splitLinesCollection.test.ts | 166 +++++++------- .../viewModel/viewModelDecorations.test.ts | 5 +- 11 files changed, 369 insertions(+), 312 deletions(-) diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 34096c5e735..45e36245072 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -58,7 +58,6 @@ export interface IView extends IDisposable { createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): IOverviewRuler; getCodeEditorHelper(): ICodeEditorHelper; - getCenteredRangeInViewport(): Range; /** * Returns the range of lines in the view port which are completely visible. */ diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 279db3098a2..df80c3d53d2 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -852,20 +852,6 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp return result; } - private _lastRenderedCenteredLineNumber: number = -1; - - public getCenteredRangeInViewport(): Range { - if (this._isDisposed) { - throw new Error('ViewImpl.getCenteredRangeInViewport: View is disposed'); - } - if (this._lastRenderedCenteredLineNumber === -1) { - return null; - } - let viewLineNumber = this._lastRenderedCenteredLineNumber; - let currentCenteredViewRange = new Range(viewLineNumber, this._context.model.getLineMinColumn(viewLineNumber), viewLineNumber, this._context.model.getLineMaxColumn(viewLineNumber)); - return this._context.model.convertViewRangeToModelRange(currentCenteredViewRange); - } - private _actualRender(): void { if (!dom.isInDOM(this.domNode)) { return; @@ -880,7 +866,7 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp } let partialViewportData = this.layoutProvider.getLinesViewportData(); - this._lastRenderedCenteredLineNumber = partialViewportData.centeredLineNumber; + this._context.model.setViewport(partialViewportData.startLineNumber, partialViewportData.endLineNumber, partialViewportData.centeredLineNumber); let viewportData = new ViewportData(partialViewportData, this._context.model); diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 6bd46d9b65e..862a801f08f 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -151,7 +151,7 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito if (!this.hasView) { return null; } - return this._view.getCenteredRangeInViewport(); + return this.viewModel.getCenteredRangeInViewport(); } public getCompletelyVisibleLinesRangeInViewport(): Range { diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index d4dec32f0ff..bb64dd98bb4 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -809,8 +809,7 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom linesCollection, this.id, this._configuration, - this.model, - () => this.getCenteredRangeInViewport() + this.model ); let viewModelHelper: IViewModelHelper = { diff --git a/src/vs/editor/common/viewModel/prefixSumComputer.ts b/src/vs/editor/common/viewModel/prefixSumComputer.ts index 7bde8adfc66..83c07ac898a 100644 --- a/src/vs/editor/common/viewModel/prefixSumComputer.ts +++ b/src/vs/editor/common/viewModel/prefixSumComputer.ts @@ -46,14 +46,14 @@ export class PrefixSumComputer { return this.values.length; } - public insertValues(insertIndex: number, insertValues: Uint32Array): void { + public insertValues(insertIndex: number, insertValues: Uint32Array): boolean { insertIndex = toUint32(insertIndex); const oldValues = this.values; const oldPrefixSum = this.prefixSum; const insertValuesLen = insertValues.length; if (insertValuesLen === 0) { - return; + return false; } this.values = new Uint32Array(oldValues.length + insertValuesLen); @@ -69,22 +69,24 @@ export class PrefixSumComputer { if (this.prefixSumValidIndex[0] >= 0) { this.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1)); } + return true; } - public changeValue(index: number, value: number): void { + public changeValue(index: number, value: number): boolean { index = toUint32(index); value = toUint32(value); if (this.values[index] === value) { - return; + return false; } this.values[index] = value; if (index - 1 < this.prefixSumValidIndex[0]) { this.prefixSumValidIndex[0] = index - 1; } + return true; } - public removeValues(startIndex: number, cnt: number): void { + public removeValues(startIndex: number, cnt: number): boolean { startIndex = toUint32(startIndex); cnt = toUint32(cnt); @@ -92,7 +94,7 @@ export class PrefixSumComputer { const oldPrefixSum = this.prefixSum; if (startIndex >= oldValues.length) { - return; + return false; } let maxCnt = oldValues.length - startIndex; @@ -101,7 +103,7 @@ export class PrefixSumComputer { } if (cnt === 0) { - return; + return false; } this.values = new Uint32Array(oldValues.length - cnt); @@ -115,6 +117,7 @@ export class PrefixSumComputer { if (this.prefixSumValidIndex[0] >= 0) { this.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1)); } + return true; } public getTotalValue(): number { @@ -185,3 +188,77 @@ export class PrefixSumComputer { return new PrefixSumIndexOfResult(mid, accumulatedValue - midStart); } } + +export class PrefixSumComputerWithCache { + + private readonly _actual: PrefixSumComputer; + private _cacheAccumulatedValueStart: number = 0; + private _cache: PrefixSumIndexOfResult[] = null; + + constructor(values: Uint32Array) { + this._actual = new PrefixSumComputer(values); + this._bustCache(); + } + + private _bustCache(): void { + this._cacheAccumulatedValueStart = 0; + this._cache = null; + } + + public getCount(): number { + return this._actual.getCount(); + } + + public insertValues(insertIndex: number, insertValues: Uint32Array): void { + if (this._actual.insertValues(insertIndex, insertValues)) { + this._bustCache(); + } + } + + public changeValue(index: number, value: number): void { + if (this._actual.changeValue(index, value)) { + this._bustCache(); + } + } + + public removeValues(startIndex: number, cnt: number): void { + if (this._actual.removeValues(startIndex, cnt)) { + this._bustCache(); + } + } + + public getTotalValue(): number { + return this._actual.getTotalValue(); + } + + public getAccumulatedValue(index: number): number { + return this._actual.getAccumulatedValue(index); + } + + public getIndexOf(accumulatedValue: number): PrefixSumIndexOfResult { + accumulatedValue = Math.floor(accumulatedValue); //@perf + + if (this._cache !== null) { + let cacheIndex = accumulatedValue - this._cacheAccumulatedValueStart; + if (cacheIndex >= 0 && cacheIndex < this._cache.length) { + // Cache hit! + return this._cache[cacheIndex]; + } + } + + // Cache miss! + return this._actual.getIndexOf(accumulatedValue); + } + + /** + * Gives a hint that a lot of requests are about to come in for these accumulated values. + */ + public warmUpCache(accumulatedValueStart: number, accumulatedValueEnd: number): void { + let newCache: PrefixSumIndexOfResult[] = []; + for (let accumulatedValue = accumulatedValueStart; accumulatedValue <= accumulatedValueEnd; accumulatedValue++) { + newCache[accumulatedValue - accumulatedValueStart] = this.getIndexOf(accumulatedValue); + } + this._cache = newCache; + this._cacheAccumulatedValueStart = accumulatedValueStart; + } +} diff --git a/src/vs/editor/common/viewModel/splitLinesCollection.ts b/src/vs/editor/common/viewModel/splitLinesCollection.ts index 356beba8678..69a4707e559 100644 --- a/src/vs/editor/common/viewModel/splitLinesCollection.ts +++ b/src/vs/editor/common/viewModel/splitLinesCollection.ts @@ -8,7 +8,7 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; -import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; +import { PrefixSumComputerWithCache } from 'vs/editor/common/viewModel/prefixSumComputer'; import { ViewLineToken } from 'vs/editor/common/core/viewLineToken'; export class OutputPosition { @@ -44,14 +44,14 @@ export interface ISplitLine { isVisible(): boolean; setVisible(isVisible: boolean): ISplitLine; - getOutputLineCount(): number; - getOutputLineContent(model: IModel, myLineNumber: number, outputLineIndex: number): string; - getOutputLineMinColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number; - getOutputLineMaxColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number; - getOutputLineRenderingData(model: IModel, myLineNumber: number, outputLineIndex: number): OutputLineRenderingData; + getViewLineCount(): number; + getViewLineContent(model: IModel, modelLineNumber: number, outputLineIndex: number): string; + getViewLineMinColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number; + getViewLineMaxColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number; + getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData; - getInputColumnOfOutputPosition(outputLineIndex: number, outputColumn: number): number; - getOutputPositionOfInputPosition(deltaLineNumber: number, inputColumn: number): Position; + getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number; + getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position; } class VisibleIdentitySplitLine implements ISplitLine { @@ -71,36 +71,36 @@ class VisibleIdentitySplitLine implements ISplitLine { return InvisibleIdentitySplitLine.INSTANCE; } - public getOutputLineCount(): number { + public getViewLineCount(): number { return 1; } - public getOutputLineContent(model: IModel, myLineNumber: number, outputLineIndex: number): string { - return model.getLineContent(myLineNumber); + public getViewLineContent(model: IModel, modelLineNumber: number, outputLineIndex: number): string { + return model.getLineContent(modelLineNumber); } - public getOutputLineMinColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number { - return model.getLineMinColumn(myLineNumber); + public getViewLineMinColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number { + return model.getLineMinColumn(modelLineNumber); } - public getOutputLineMaxColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number { - return model.getLineMaxColumn(myLineNumber); + public getViewLineMaxColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number { + return model.getLineMaxColumn(modelLineNumber); } - public getOutputLineRenderingData(model: IModel, myLineNumber: number, outputLineIndex: number): OutputLineRenderingData { + public getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData { return new OutputLineRenderingData( - model.getLineContent(myLineNumber), - model.getLineMinColumn(myLineNumber), - model.getLineMaxColumn(myLineNumber), - model.getLineTokens(myLineNumber, true).inflate() + model.getLineContent(modelLineNumber), + model.getLineMinColumn(modelLineNumber), + model.getLineMaxColumn(modelLineNumber), + model.getLineTokens(modelLineNumber, true).inflate() ); } - public getInputColumnOfOutputPosition(outputLineIndex: number, outputColumn: number): number { + public getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number { return outputColumn; } - public getOutputPositionOfInputPosition(deltaLineNumber: number, inputColumn: number): Position { + public getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position { return new Position(deltaLineNumber, inputColumn); } } @@ -122,31 +122,31 @@ class InvisibleIdentitySplitLine implements ISplitLine { return VisibleIdentitySplitLine.INSTANCE; } - public getOutputLineCount(): number { + public getViewLineCount(): number { return 0; } - public getOutputLineContent(model: IModel, myLineNumber: number, outputLineIndex: number): string { + public getViewLineContent(model: IModel, modelLineNumber: number, outputLineIndex: number): string { throw new Error('Not supported'); } - public getOutputLineMinColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number { + public getViewLineMinColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number { throw new Error('Not supported'); } - public getOutputLineMaxColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number { + public getViewLineMaxColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number { throw new Error('Not supported'); } - public getOutputLineRenderingData(model: IModel, myLineNumber: number, outputLineIndex: number): OutputLineRenderingData { + public getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData { throw new Error('Not supported'); } - public getInputColumnOfOutputPosition(outputLineIndex: number, outputColumn: number): number { + public getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number { throw new Error('Not supported'); } - public getOutputPositionOfInputPosition(deltaLineNumber: number, inputColumn: number): Position { + public getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position { throw new Error('Not supported'); } } @@ -177,7 +177,7 @@ export class SplitLine implements ISplitLine { return this; } - public getOutputLineCount(): number { + public getViewLineCount(): number { if (!this._isVisible) { return 0; } @@ -188,20 +188,20 @@ export class SplitLine implements ISplitLine { return this.positionMapper.getInputOffsetOfOutputPosition(outputLineIndex, 0); } - private getInputEndOffsetOfOutputLineIndex(model: IModel, myLineNumber: number, outputLineIndex: number): number { + private getInputEndOffsetOfOutputLineIndex(model: IModel, modelLineNumber: number, outputLineIndex: number): number { if (outputLineIndex + 1 === this.outputLineCount) { - return model.getLineMaxColumn(myLineNumber) - 1; + return model.getLineMaxColumn(modelLineNumber) - 1; } return this.positionMapper.getInputOffsetOfOutputPosition(outputLineIndex + 1, 0); } - public getOutputLineContent(model: IModel, myLineNumber: number, outputLineIndex: number): string { + public getViewLineContent(model: IModel, modelLineNumber: number, outputLineIndex: number): string { if (!this._isVisible) { throw new Error('Not supported'); } let startOffset = this.getInputStartOffsetOfOutputLineIndex(outputLineIndex); - let endOffset = this.getInputEndOffsetOfOutputLineIndex(model, myLineNumber, outputLineIndex); - let r = model.getLineContent(myLineNumber).substring(startOffset, endOffset); + let endOffset = this.getInputEndOffsetOfOutputLineIndex(model, modelLineNumber, outputLineIndex); + let r = model.getLineContent(modelLineNumber).substring(startOffset, endOffset); if (outputLineIndex > 0) { r = this.wrappedIndent + r; @@ -210,7 +210,7 @@ export class SplitLine implements ISplitLine { return r; } - public getOutputLineMinColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number { + public getViewLineMinColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number { if (!this._isVisible) { throw new Error('Not supported'); } @@ -220,22 +220,22 @@ export class SplitLine implements ISplitLine { return 1; } - public getOutputLineMaxColumn(model: IModel, myLineNumber: number, outputLineIndex: number): number { + public getViewLineMaxColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number { if (!this._isVisible) { throw new Error('Not supported'); } - return this.getOutputLineContent(model, myLineNumber, outputLineIndex).length + 1; + return this.getViewLineContent(model, modelLineNumber, outputLineIndex).length + 1; } - public getOutputLineRenderingData(model: IModel, myLineNumber: number, outputLineIndex: number): OutputLineRenderingData { + public getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData { if (!this._isVisible) { throw new Error('Not supported'); } let startOffset = this.getInputStartOffsetOfOutputLineIndex(outputLineIndex); - let endOffset = this.getInputEndOffsetOfOutputLineIndex(model, myLineNumber, outputLineIndex); + let endOffset = this.getInputEndOffsetOfOutputLineIndex(model, modelLineNumber, outputLineIndex); - let lineContent = model.getLineContent(myLineNumber).substring(startOffset, endOffset); + let lineContent = model.getLineContent(modelLineNumber).substring(startOffset, endOffset); if (outputLineIndex > 0) { lineContent = this.wrappedIndent + lineContent; } @@ -247,7 +247,7 @@ export class SplitLine implements ISplitLine { if (outputLineIndex > 0) { deltaStartIndex = this.wrappedIndentLength; } - let lineTokens = model.getLineTokens(myLineNumber, true); + let lineTokens = model.getLineTokens(modelLineNumber, true); return new OutputLineRenderingData( lineContent, @@ -257,7 +257,7 @@ export class SplitLine implements ISplitLine { ); } - public getInputColumnOfOutputPosition(outputLineIndex: number, outputColumn: number): number { + public getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number { if (!this._isVisible) { throw new Error('Not supported'); } @@ -272,7 +272,7 @@ export class SplitLine implements ISplitLine { return this.positionMapper.getInputOffsetOfOutputPosition(outputLineIndex, adjustedColumn) + 1; } - public getOutputPositionOfInputPosition(deltaLineNumber: number, inputColumn: number): Position { + public getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position { if (!this._isVisible) { throw new Error('Not supported'); } @@ -312,7 +312,9 @@ export class SplitLinesCollection { private wrappingIndent: editorCommon.WrappingIndent; private tabSize: number; private lines: ISplitLine[]; - private prefixSumComputer: PrefixSumComputer; + + private prefixSumComputer: PrefixSumComputerWithCache; + private linePositionMapperFactory: ILineMapperFactory; private hiddenAreasIds: string[]; @@ -368,13 +370,13 @@ export class SplitLinesCollection { let isInHiddenArea = (lineNumber >= hiddenAreaStart && lineNumber <= hiddenAreaEnd); let line = createSplitLine(this.linePositionMapperFactory, linesContent[i], this.tabSize, this.wrappingColumn, this.columnsForFullWidthChar, this.wrappingIndent, !isInHiddenArea); - values[i] = line.getOutputLineCount(); + values[i] = line.getViewLineCount(); this.lines[i] = line; } this._validModelVersionId = this.model.getVersionId(); - this.prefixSumComputer = new PrefixSumComputer(values); + this.prefixSumComputer = new PrefixSumComputerWithCache(values); } private getHiddenAreas(): Range[] { @@ -470,7 +472,7 @@ export class SplitLinesCollection { } } if (lineChanged) { - let newOutputLineCount = this.lines[i].getOutputLineCount(); + let newOutputLineCount = this.lines[i].getViewLineCount(); this.prefixSumComputer.changeValue(i, newOutputLineCount); } } @@ -479,12 +481,12 @@ export class SplitLinesCollection { return true; } - public inputPositionIsVisible(inputLineNumber: number, inputColumn: number): boolean { - if (inputLineNumber < 1 || inputLineNumber > this.lines.length) { + public modelPositionIsVisible(modelLineNumber: number, modelColumn: number): boolean { + if (modelLineNumber < 1 || modelLineNumber > this.lines.length) { // invalid arguments return false; } - return this.lines[inputLineNumber - 1].isVisible(); + return this.lines[modelLineNumber - 1].isVisible(); } public setTabSize(newTabSize: number, emit: (evenType: string, payload: any) => void): boolean { @@ -573,7 +575,7 @@ export class SplitLinesCollection { let line = createSplitLine(this.linePositionMapperFactory, text[i], this.tabSize, this.wrappingColumn, this.columnsForFullWidthChar, this.wrappingIndent, !isInHiddenArea); insertLines.push(line); - let outputLineCount = line.getOutputLineCount(); + let outputLineCount = line.getViewLineCount(); totalOutputLineCount += outputLineCount; insertPrefixSumValues[i] = outputLineCount; } @@ -596,11 +598,11 @@ export class SplitLinesCollection { this._validModelVersionId = versionId; let lineIndex = lineNumber - 1; - let oldOutputLineCount = this.lines[lineIndex].getOutputLineCount(); + let oldOutputLineCount = this.lines[lineIndex].getViewLineCount(); let isVisible = this.lines[lineIndex].isVisible(); let line = createSplitLine(this.linePositionMapperFactory, newText, this.tabSize, this.wrappingColumn, this.columnsForFullWidthChar, this.wrappingIndent, isVisible); this.lines[lineIndex] = line; - let newOutputLineCount = this.lines[lineIndex].getOutputLineCount(); + let newOutputLineCount = this.lines[lineIndex].getViewLineCount(); let lineMappingChanged = false; let changeFrom = 0; @@ -659,86 +661,122 @@ export class SplitLinesCollection { return lineMappingChanged; } - public getOutputLineCount(): number { + public getViewLineCount(): number { this._ensureValidState(); return this.prefixSumComputer.getTotalValue(); } - private _toValidOutputLineNumber(outputLineNumber: number): number { - if (outputLineNumber < 1) { + private _toValidViewLineNumber(viewLineNumber: number): number { + if (viewLineNumber < 1) { return 1; } - let outputLineCount = this.getOutputLineCount(); - if (outputLineNumber > outputLineCount) { - return outputLineCount; + let viewLineCount = this.getViewLineCount(); + if (viewLineNumber > viewLineCount) { + return viewLineCount; } - return outputLineNumber; + return viewLineNumber; + } + + /** + * Gives a hint that a lot of requests are about to come in for these line numbers. + */ + public warmUpLookupCache(viewStartLineNumber: number, viewEndLineNumber: number): void { + this.prefixSumComputer.warmUpCache(viewStartLineNumber - 1, viewEndLineNumber - 1); } - public getOutputIndentGuide(outputLineNumber: number): number { + public getViewLineIndentGuide(viewLineNumber: number): number { this._ensureValidState(); - outputLineNumber = this._toValidOutputLineNumber(outputLineNumber); - let r = this.prefixSumComputer.getIndexOf(outputLineNumber - 1); + viewLineNumber = this._toValidViewLineNumber(viewLineNumber); + let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); return this.model.getLineIndentGuide(r.index + 1); } - public getOutputLineContent(outputLineNumber: number): string { + public getViewLineContent(viewLineNumber: number): string { this._ensureValidState(); - outputLineNumber = this._toValidOutputLineNumber(outputLineNumber); - let r = this.prefixSumComputer.getIndexOf(outputLineNumber - 1); + viewLineNumber = this._toValidViewLineNumber(viewLineNumber); + let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); let lineIndex = r.index; let remainder = r.remainder; - return this.lines[lineIndex].getOutputLineContent(this.model, lineIndex + 1, remainder); + return this.lines[lineIndex].getViewLineContent(this.model, lineIndex + 1, remainder); } - public getOutputLineMinColumn(outputLineNumber: number): number { + public getViewLineMinColumn(viewLineNumber: number): number { this._ensureValidState(); - outputLineNumber = this._toValidOutputLineNumber(outputLineNumber); - let r = this.prefixSumComputer.getIndexOf(outputLineNumber - 1); + viewLineNumber = this._toValidViewLineNumber(viewLineNumber); + let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); let lineIndex = r.index; let remainder = r.remainder; - return this.lines[lineIndex].getOutputLineMinColumn(this.model, lineIndex + 1, remainder); + return this.lines[lineIndex].getViewLineMinColumn(this.model, lineIndex + 1, remainder); } - public getOutputLineMaxColumn(outputLineNumber: number): number { + public getViewLineMaxColumn(viewLineNumber: number): number { this._ensureValidState(); - outputLineNumber = this._toValidOutputLineNumber(outputLineNumber); - let r = this.prefixSumComputer.getIndexOf(outputLineNumber - 1); + viewLineNumber = this._toValidViewLineNumber(viewLineNumber); + let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); let lineIndex = r.index; let remainder = r.remainder; - return this.lines[lineIndex].getOutputLineMaxColumn(this.model, lineIndex + 1, remainder); + return this.lines[lineIndex].getViewLineMaxColumn(this.model, lineIndex + 1, remainder); } - public getOutputLineRenderingData(outputLineNumber: number): OutputLineRenderingData { + public getViewLineRenderingData(viewLineNumber: number): OutputLineRenderingData { this._ensureValidState(); - outputLineNumber = this._toValidOutputLineNumber(outputLineNumber); - let r = this.prefixSumComputer.getIndexOf(outputLineNumber - 1); + viewLineNumber = this._toValidViewLineNumber(viewLineNumber); + let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); let lineIndex = r.index; let remainder = r.remainder; - return this.lines[lineIndex].getOutputLineRenderingData(this.model, lineIndex + 1, remainder); + return this.lines[lineIndex].getViewLineRenderingData(this.model, lineIndex + 1, remainder); + } + + public validateViewPosition(viewLineNumber: number, viewColumn: number, expectedModelPosition: Position): Position { + this._ensureValidState(); + viewLineNumber = this._toValidViewLineNumber(viewLineNumber); + + let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); + let lineIndex = r.index; + let remainder = r.remainder; + + let line = this.lines[lineIndex]; + + let minColumn = line.getViewLineMinColumn(this.model, lineIndex + 1, remainder); + let maxColumn = line.getViewLineMaxColumn(this.model, lineIndex + 1, remainder); + if (viewColumn < minColumn) { + viewColumn = minColumn; + } + if (viewColumn > maxColumn) { + viewColumn = maxColumn; + } + + let computedModelColumn = line.getModelColumnOfViewPosition(remainder, viewColumn); + let computedModelPosition = this.model.validatePosition(new Position(lineIndex + 1, computedModelColumn)); + + if (computedModelPosition.equals(expectedModelPosition)) { + return new Position(viewLineNumber, viewColumn); + } + + return this.convertModelPositionToViewPosition(expectedModelPosition.lineNumber, expectedModelPosition.column); } - public convertOutputPositionToInputPosition(viewLineNumber: number, viewColumn: number): Position { + public convertViewPositionToModelPosition(viewLineNumber: number, viewColumn: number): Position { this._ensureValidState(); - viewLineNumber = this._toValidOutputLineNumber(viewLineNumber); + viewLineNumber = this._toValidViewLineNumber(viewLineNumber); let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1); let lineIndex = r.index; let remainder = r.remainder; - let inputColumn = this.lines[lineIndex].getInputColumnOfOutputPosition(remainder, viewColumn); + let inputColumn = this.lines[lineIndex].getModelColumnOfViewPosition(remainder, viewColumn); // console.log('out -> in ' + viewLineNumber + ',' + viewColumn + ' ===> ' + (lineIndex+1) + ',' + inputColumn); return this.model.validatePosition(new Position(lineIndex + 1, inputColumn)); } - public convertInputPositionToOutputPosition(_inputLineNumber: number, _inputColumn: number): Position { + public convertModelPositionToViewPosition(_modelLineNumber: number, _modelColumn: number): Position { this._ensureValidState(); - let validPosition = this.model.validatePosition(new Position(_inputLineNumber, _inputColumn)); + let validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn)); let inputLineNumber = validPosition.lineNumber; let inputColumn = validPosition.column; @@ -756,9 +794,9 @@ export class SplitLinesCollection { let r: Position; if (lineIndexChanged) { - r = this.lines[lineIndex].getOutputPositionOfInputPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1)); + r = this.lines[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1)); } else { - r = this.lines[inputLineNumber - 1].getOutputPositionOfInputPosition(deltaLineNumber, inputColumn); + r = this.lines[inputLineNumber - 1].getViewPositionOfModelPosition(deltaLineNumber, inputColumn); } // console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r); diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 522b539c465..dfca9baf93d 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -11,6 +11,11 @@ import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; export interface IViewModel extends IEventEmitter { + /** + * Gives a hint that a lot of requests are about to come in for these line numbers. + */ + setViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void; + getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[]; getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData; diff --git a/src/vs/editor/common/viewModel/viewModelCursors.ts b/src/vs/editor/common/viewModel/viewModelCursors.ts index 37c3e1ae9cc..441d7f475e8 100644 --- a/src/vs/editor/common/viewModel/viewModelCursors.ts +++ b/src/vs/editor/common/viewModel/viewModelCursors.ts @@ -4,66 +4,45 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { Range } from 'vs/editor/common/core/range'; -import { Selection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { Position } from 'vs/editor/common/core/position'; -export interface IConverter { - validateViewPosition(viewLineNumber: number, viewColumn: number, modelPosition: Position): Position; - validateViewSelection(viewSelection: Selection, modelSelection: Selection): Selection; - convertModelSelectionToViewSelection(modelSelection: Selection): Selection; - convertModelRangeToViewRange(modelRange: Range): Range; -} - export class ViewModelCursors { - private configuration: editorCommon.IConfiguration; - private converter: IConverter; + private readonly configuration: editorCommon.IConfiguration; private lastCursorPositionChangedEvent: editorCommon.ICursorPositionChangedEvent; private lastCursorSelectionChangedEvent: editorCommon.ICursorSelectionChangedEvent; - constructor(configuration: editorCommon.IConfiguration, converter: IConverter) { + constructor(configuration: editorCommon.IConfiguration) { this.configuration = configuration; - this.converter = converter; this.lastCursorPositionChangedEvent = null; this.lastCursorSelectionChangedEvent = null; } - public getSelections(): Selection[] { - if (this.lastCursorSelectionChangedEvent) { - var selections: Selection[] = []; - selections.push(this.converter.convertModelSelectionToViewSelection(this.lastCursorSelectionChangedEvent.selection)); - for (var i = 0, len = this.lastCursorSelectionChangedEvent.secondarySelections.length; i < len; i++) { - selections.push(this.converter.convertModelSelectionToViewSelection(this.lastCursorSelectionChangedEvent.secondarySelections[i])); - } - return selections; - } else { - return [new Selection(1, 1, 1, 1)]; + /** + * Limit position to be somewhere where it can actually be rendered + */ + private static _toPositionThatCanBeRendered(position: Position, stopRenderingLineAfter: number) { + // Limit position to be somewhere where it can actually be rendered + if (stopRenderingLineAfter !== -1 && position.column > stopRenderingLineAfter) { + position = new Position(position.lineNumber, stopRenderingLineAfter); } + return position; } public onCursorPositionChanged(e: editorCommon.ICursorPositionChangedEvent, emit: (eventType: string, payload: any) => void): void { this.lastCursorPositionChangedEvent = e; - var position = this.converter.validateViewPosition(e.viewPosition.lineNumber, e.viewPosition.column, e.position), - stopRenderingLineAfter = this.configuration.editor.viewInfo.stopRenderingLineAfter; + const stopRenderingLineAfter = this.configuration.editor.viewInfo.stopRenderingLineAfter; - // Limit position to be somewhere where it can actually be rendered - if (stopRenderingLineAfter !== -1 && position.column > stopRenderingLineAfter) { - position = new Position(position.lineNumber, stopRenderingLineAfter); - } - var secondaryPositions: Position[] = []; - for (var i = 0, len = e.secondaryPositions.length; i < len; i++) { - secondaryPositions[i] = this.converter.validateViewPosition(e.secondaryViewPositions[i].lineNumber, e.secondaryViewPositions[i].column, e.secondaryPositions[i]); - // Limit position to be somewhere where it can actually be rendered - if (stopRenderingLineAfter !== -1 && secondaryPositions[i].column > stopRenderingLineAfter) { - secondaryPositions[i] = new Position(secondaryPositions[i].lineNumber, stopRenderingLineAfter); - } + let position = ViewModelCursors._toPositionThatCanBeRendered(e.viewPosition, stopRenderingLineAfter); + let secondaryPositions: Position[] = []; + for (let i = 0, len = e.secondaryPositions.length; i < len; i++) { + secondaryPositions[i] = ViewModelCursors._toPositionThatCanBeRendered(e.secondaryViewPositions[i], stopRenderingLineAfter); } - var newEvent: editorCommon.IViewCursorPositionChangedEvent = { + let newEvent: editorCommon.IViewCursorPositionChangedEvent = { position: position, secondaryPositions: secondaryPositions, isInEditableRange: e.isInEditableRange @@ -74,31 +53,16 @@ export class ViewModelCursors { public onCursorSelectionChanged(e: editorCommon.ICursorSelectionChangedEvent, emit: (eventType: string, payload: any) => void): void { this.lastCursorSelectionChangedEvent = e; - let selection = this.converter.validateViewSelection(e.viewSelection, e.selection); - let secondarySelections: Selection[] = []; - for (let i = 0, len = e.secondarySelections.length; i < len; i++) { - secondarySelections[i] = this.converter.validateViewSelection(e.secondaryViewSelections[i], e.secondarySelections[i]); - } - let newEvent: editorCommon.IViewCursorSelectionChangedEvent = { - selection: selection, - secondarySelections: secondarySelections + selection: e.viewSelection, + secondarySelections: e.secondaryViewSelections }; emit(editorCommon.ViewEventNames.CursorSelectionChangedEvent, newEvent); } public onCursorRevealRange(e: editorCommon.ICursorRevealRangeEvent, emit: (eventType: string, payload: any) => void): void { - var viewRange: Range = null; - if (e.viewRange) { - var viewStartRange = this.converter.validateViewPosition(e.viewRange.startLineNumber, e.viewRange.startColumn, e.range.getStartPosition()); - var viewEndRange = this.converter.validateViewPosition(e.viewRange.endLineNumber, e.viewRange.endColumn, e.range.getEndPosition()); - viewRange = new Range(viewStartRange.lineNumber, viewStartRange.column, viewEndRange.lineNumber, viewEndRange.column); - } else { - viewRange = this.converter.convertModelRangeToViewRange(e.range); - } - - var newEvent: editorCommon.IViewRevealRangeEvent = { - range: viewRange, + let newEvent: editorCommon.IViewRevealRangeEvent = { + range: e.viewRange, verticalType: e.verticalType, revealHorizontal: e.revealHorizontal, revealCursor: e.revealCursor @@ -107,7 +71,7 @@ export class ViewModelCursors { } public onCursorScrollRequest(e: editorCommon.ICursorScrollRequestEvent, emit: (eventType: string, payload: any) => void): void { - var newEvent: editorCommon.IViewScrollRequestEvent = { + let newEvent: editorCommon.IViewScrollRequestEvent = { deltaLines: e.deltaLines, revealCursor: e.revealCursor }; @@ -122,5 +86,4 @@ export class ViewModelCursors { this.onCursorSelectionChanged(this.lastCursorSelectionChangedEvent, emit); } } - -} \ No newline at end of file +} diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 821f19d26a5..d16594597ad 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -32,9 +32,9 @@ export class ViewModel extends EventEmitter implements IViewModel { private _renderRelativeLineNumbers: boolean; private _lastCursorPosition: Position; - private getCurrentCenteredModelRange: () => Range; + private _centeredViewLine: number; - constructor(lines: SplitLinesCollection, editorId: number, configuration: editorCommon.IConfiguration, model: editorCommon.IModel, getCurrentCenteredModelRange: () => Range) { + constructor(lines: SplitLinesCollection, editorId: number, configuration: editorCommon.IConfiguration, model: editorCommon.IModel) { super(); this.lines = lines; @@ -46,7 +46,7 @@ export class ViewModel extends EventEmitter implements IViewModel { this._renderCustomLineNumbers = this.configuration.editor.viewInfo.renderCustomLineNumbers; this._renderRelativeLineNumbers = this.configuration.editor.viewInfo.renderRelativeLineNumbers; - this.getCurrentCenteredModelRange = getCurrentCenteredModelRange; + this._centeredViewLine = -1; this.decorations = new ViewModelDecorations(this.editorId, this.model, this.configuration, { convertModelRangeToViewRange: (modelRange: Range, isWholeLine: boolean): Range => { @@ -61,7 +61,7 @@ export class ViewModel extends EventEmitter implements IViewModel { }); this.decorations.reset(); - this.cursors = new ViewModelCursors(this.configuration, this); + this.cursors = new ViewModelCursors(this.configuration); this.listenersToRemove = []; this._toDispose = []; @@ -180,6 +180,16 @@ export class ViewModel extends EventEmitter implements IViewModel { return false; } + public getCenteredRangeInViewport(): Range { + if (this._centeredViewLine === -1) { + // Never got rendered + return null; + } + let viewLineNumber = this._centeredViewLine; + let currentCenteredViewRange = new Range(viewLineNumber, this.getLineMinColumn(viewLineNumber), viewLineNumber, this.getLineMaxColumn(viewLineNumber)); + return this.convertViewRangeToModelRange(currentCenteredViewRange); + } + private _onEvents(events: EmitterEvent[]): void { // We might need to restore the current centered view range in the following circumstances: @@ -193,7 +203,7 @@ export class ViewModel extends EventEmitter implements IViewModel { let previousCenteredModelRange: Range = null; if (!ViewModel._containsModelContentChangeEvent(events) && ViewModel._containsWrappingRelatedEvents(events)) { - previousCenteredModelRange = this.getCurrentCenteredModelRange(); + previousCenteredModelRange = this.getCenteredRangeInViewport(); } let i: number, @@ -254,9 +264,9 @@ export class ViewModel extends EventEmitter implements IViewModel { case editorCommon.EventType.ModelOptionsChanged: // A tab size change causes a line mapping changed event => all view parts will repaint OK, no further event needed here - let prevLineCount = this.lines.getOutputLineCount(); + let prevLineCount = this.lines.getViewLineCount(); let tabSizeChanged = this._onTabSizeChange(this.model.getOptions().tabSize); - let newLineCount = this.lines.getOutputLineCount(); + let newLineCount = this.lines.getViewLineCount(); if (tabSizeChanged && prevLineCount !== newLineCount) { revealPreviousCenteredModelRange = true; } @@ -363,37 +373,8 @@ export class ViewModel extends EventEmitter implements IViewModel { return new Range(validViewStart.lineNumber, validViewStart.column, validViewEnd.lineNumber, validViewEnd.column); } - public validateViewPosition(viewLineNumber: number, viewColumn: number, modelPosition: Position): Position { - if (viewLineNumber < 1) { - viewLineNumber = 1; - } - var lineCount = this.getLineCount(); - if (viewLineNumber > lineCount) { - viewLineNumber = lineCount; - } - var viewMinColumn = this.getLineMinColumn(viewLineNumber); - var viewMaxColumn = this.getLineMaxColumn(viewLineNumber); - if (viewColumn < viewMinColumn) { - viewColumn = viewMinColumn; - } - if (viewColumn > viewMaxColumn) { - viewColumn = viewMaxColumn; - } - var computedModelPosition = this.convertViewPositionToModelPosition(viewLineNumber, viewColumn); - if (computedModelPosition.equals(modelPosition)) { - return new Position(viewLineNumber, viewColumn); - } - return this.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column); - } - - public validateViewSelection(viewSelection: Selection, modelSelection: Selection): Selection { - let modelSelectionStart = new Position(modelSelection.selectionStartLineNumber, modelSelection.selectionStartColumn); - let modelPosition = new Position(modelSelection.positionLineNumber, modelSelection.positionColumn); - - let viewSelectionStart = this.validateViewPosition(viewSelection.selectionStartLineNumber, viewSelection.selectionStartColumn, modelSelectionStart); - let viewPosition = this.validateViewPosition(viewSelection.positionLineNumber, viewSelection.positionColumn, modelPosition); - - return new Selection(viewSelectionStart.lineNumber, viewSelectionStart.column, viewPosition.lineNumber, viewPosition.column); + public validateViewPosition(viewLineNumber: number, viewColumn: number, expectedModelPosition: Position): Position { + return this.lines.validateViewPosition(viewLineNumber, viewColumn, expectedModelPosition); } private onCursorPositionChanged(e: editorCommon.ICursorPositionChangedEvent): void { @@ -403,6 +384,16 @@ export class ViewModel extends EventEmitter implements IViewModel { this.cursors.onCursorSelectionChanged(e, (eventType: string, payload: any) => this.emit(eventType, payload)); } private onCursorRevealRange(e: editorCommon.ICursorRevealRangeEvent): void { + // Ensure event has viewRange + if (!e.viewRange) { + e = { + range: e.range, + viewRange: this.convertModelRangeToViewRange(e.range), + verticalType: e.verticalType, + revealHorizontal: e.revealHorizontal, + revealCursor: e.revealCursor, + }; + } this.cursors.onCursorRevealRange(e, (eventType: string, payload: any) => this.emit(eventType, payload)); } private onCursorScrollRequest(e: editorCommon.ICursorScrollRequestEvent): void { @@ -415,23 +406,31 @@ export class ViewModel extends EventEmitter implements IViewModel { } public getLineCount(): number { - return this.lines.getOutputLineCount(); + return this.lines.getViewLineCount(); + } + + /** + * Gives a hint that a lot of requests are about to come in for these line numbers. + */ + public setViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void { + this._centeredViewLine = centeredLineNumber; + this.lines.warmUpLookupCache(startLineNumber, endLineNumber); } public getLineIndentGuide(lineNumber: number): number { - return this.lines.getOutputIndentGuide(lineNumber); + return this.lines.getViewLineIndentGuide(lineNumber); } public getLineContent(lineNumber: number): string { - return this.lines.getOutputLineContent(lineNumber); + return this.lines.getViewLineContent(lineNumber); } public getLineMinColumn(lineNumber: number): number { - return this.lines.getOutputLineMinColumn(lineNumber); + return this.lines.getViewLineMinColumn(lineNumber); } public getLineMaxColumn(lineNumber: number): number { - return this.lines.getOutputLineMaxColumn(lineNumber); + return this.lines.getViewLineMaxColumn(lineNumber); } public getLineFirstNonWhitespaceColumn(lineNumber: number): number { @@ -485,7 +484,7 @@ export class ViewModel extends EventEmitter implements IViewModel { let mightContainRTL = this.model.mightContainRTL(); let mightContainNonBasicASCII = this.model.mightContainNonBasicASCII(); let tabSize = this.getTabSize(); - let lineData = this.lines.getOutputLineRenderingData(lineNumber); + let lineData = this.lines.getViewLineRenderingData(lineNumber); let allInlineDecorations = this.decorations.getDecorationsViewportData(visibleRange).inlineDecorations; let inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber]; @@ -517,7 +516,7 @@ export class ViewModel extends EventEmitter implements IViewModel { // View -> Model conversion and related methods public convertViewPositionToModelPosition(viewLineNumber: number, viewColumn: number): Position { - return this.lines.convertOutputPositionToInputPosition(viewLineNumber, viewColumn); + return this.lines.convertViewPositionToModelPosition(viewLineNumber, viewColumn); } public convertViewRangeToModelRange(viewRange: Range): Range { @@ -547,7 +546,7 @@ export class ViewModel extends EventEmitter implements IViewModel { } public convertModelPositionToViewPosition(modelLineNumber: number, modelColumn: number): Position { - return this.lines.convertInputPositionToOutputPosition(modelLineNumber, modelColumn); + return this.lines.convertModelPositionToViewPosition(modelLineNumber, modelColumn); } public convertModelRangeToViewRange(modelRange: Range): Range { @@ -562,14 +561,8 @@ export class ViewModel extends EventEmitter implements IViewModel { return new Range(start.lineNumber, start.column, end.lineNumber, end.column); } - public convertModelSelectionToViewSelection(modelSelection: Selection): Selection { - var selectionStart = this.convertModelPositionToViewPosition(modelSelection.selectionStartLineNumber, modelSelection.selectionStartColumn); - var position = this.convertModelPositionToViewPosition(modelSelection.positionLineNumber, modelSelection.positionColumn); - return new Selection(selectionStart.lineNumber, selectionStart.column, position.lineNumber, position.column); - } - public modelPositionIsVisible(position: Position): boolean { - return this.lines.inputPositionIsVisible(position.lineNumber, position.column); + return this.lines.modelPositionIsVisible(position.lineNumber, position.column); } } \ No newline at end of file diff --git a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts index 2ed55ff9a86..51475610103 100644 --- a/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts +++ b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts @@ -18,65 +18,65 @@ suite('Editor ViewModel - SplitLinesCollection', () => { var model1 = createModel('My First LineMy Second LineAnd another one'); var line1 = createSplitLine([13, 14, 15], ''); - assert.equal(line1.getOutputLineCount(), 3); - assert.equal(line1.getOutputLineContent(model1, 1, 0), 'My First Line'); - assert.equal(line1.getOutputLineContent(model1, 1, 1), 'My Second Line'); - assert.equal(line1.getOutputLineContent(model1, 1, 2), 'And another one'); - assert.equal(line1.getOutputLineMaxColumn(model1, 1, 0), 14); - assert.equal(line1.getOutputLineMaxColumn(model1, 1, 1), 15); - assert.equal(line1.getOutputLineMaxColumn(model1, 1, 2), 16); + assert.equal(line1.getViewLineCount(), 3); + assert.equal(line1.getViewLineContent(model1, 1, 0), 'My First Line'); + assert.equal(line1.getViewLineContent(model1, 1, 1), 'My Second Line'); + assert.equal(line1.getViewLineContent(model1, 1, 2), 'And another one'); + assert.equal(line1.getViewLineMaxColumn(model1, 1, 0), 14); + assert.equal(line1.getViewLineMaxColumn(model1, 1, 1), 15); + assert.equal(line1.getViewLineMaxColumn(model1, 1, 2), 16); for (var col = 1; col <= 14; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')'); } for (var col = 1; col <= 15; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(1, col), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(1, col), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')'); } for (var col = 1; col <= 16; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')'); } for (var col = 1; col <= 13; col++) { - assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(0, col), 'getOutputPositionOfInputPosition(' + col + ')'); + assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(0, col), 'getOutputPositionOfInputPosition(' + col + ')'); } for (var col = 1 + 13; col <= 14 + 13; col++) { - assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(1, col - 13), 'getOutputPositionOfInputPosition(' + col + ')'); + assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(1, col - 13), 'getOutputPositionOfInputPosition(' + col + ')'); } for (var col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) { - assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(2, col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')'); + assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')'); } model1 = createModel('My First LineMy Second LineAnd another one'); line1 = createSplitLine([13, 14, 15], '\t'); - assert.equal(line1.getOutputLineCount(), 3); - assert.equal(line1.getOutputLineContent(model1, 1, 0), 'My First Line'); - assert.equal(line1.getOutputLineContent(model1, 1, 1), '\tMy Second Line'); - assert.equal(line1.getOutputLineContent(model1, 1, 2), '\tAnd another one'); - assert.equal(line1.getOutputLineMaxColumn(model1, 1, 0), 14); - assert.equal(line1.getOutputLineMaxColumn(model1, 1, 1), 16); - assert.equal(line1.getOutputLineMaxColumn(model1, 1, 2), 17); + assert.equal(line1.getViewLineCount(), 3); + assert.equal(line1.getViewLineContent(model1, 1, 0), 'My First Line'); + assert.equal(line1.getViewLineContent(model1, 1, 1), '\tMy Second Line'); + assert.equal(line1.getViewLineContent(model1, 1, 2), '\tAnd another one'); + assert.equal(line1.getViewLineMaxColumn(model1, 1, 0), 14); + assert.equal(line1.getViewLineMaxColumn(model1, 1, 1), 16); + assert.equal(line1.getViewLineMaxColumn(model1, 1, 2), 17); for (var col = 1; col <= 14; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(0, col), col, 'getInputColumnOfOutputPosition(0, ' + col + ')'); } for (var col = 1; col <= 1; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(1, 1), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(1, 1), 13 + col, 'getInputColumnOfOutputPosition(1, ' + col + ')'); } for (var col = 2; col <= 16; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(1, col), 13 + col - 1, 'getInputColumnOfOutputPosition(1, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(1, col), 13 + col - 1, 'getInputColumnOfOutputPosition(1, ' + col + ')'); } for (var col = 1; col <= 1; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col, 'getInputColumnOfOutputPosition(2, ' + col + ')'); } for (var col = 2; col <= 17; col++) { - assert.equal(line1.getInputColumnOfOutputPosition(2, col), 13 + 14 + col - 1, 'getInputColumnOfOutputPosition(2, ' + col + ')'); + assert.equal(line1.getModelColumnOfViewPosition(2, col), 13 + 14 + col - 1, 'getInputColumnOfOutputPosition(2, ' + col + ')'); } for (var col = 1; col <= 13; col++) { - assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(0, col), 'getOutputPositionOfInputPosition(' + col + ')'); + assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(0, col), 'getOutputPositionOfInputPosition(' + col + ')'); } for (var col = 1 + 13; col <= 14 + 13; col++) { - assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(1, 1 + col - 13), 'getOutputPositionOfInputPosition(' + col + ')'); + assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(1, 1 + col - 13), 'getOutputPositionOfInputPosition(' + col + ')'); } for (var col = 1 + 13 + 14; col <= 15 + 14 + 13; col++) { - assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(2, 1 + col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')'); + assert.deepEqual(line1.getViewPositionOfModelPosition(0, col), pos(2, 1 + col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')'); } }); @@ -126,63 +126,63 @@ suite('Editor ViewModel - SplitLinesCollection', () => { ].join('\n'); withSplitLinesCollection(text, (model, linesCollection) => { - assert.equal(linesCollection.getOutputLineCount(), 6); + assert.equal(linesCollection.getViewLineCount(), 6); // getOutputIndentGuide - assert.equal(linesCollection.getOutputIndentGuide(-1), 0); - assert.equal(linesCollection.getOutputIndentGuide(0), 0); - assert.equal(linesCollection.getOutputIndentGuide(1), 0); - assert.equal(linesCollection.getOutputIndentGuide(2), 1); - assert.equal(linesCollection.getOutputIndentGuide(3), 0); - assert.equal(linesCollection.getOutputIndentGuide(4), 0); - assert.equal(linesCollection.getOutputIndentGuide(5), 1); - assert.equal(linesCollection.getOutputIndentGuide(6), 0); - assert.equal(linesCollection.getOutputIndentGuide(7), 0); + assert.equal(linesCollection.getViewLineIndentGuide(-1), 0); + assert.equal(linesCollection.getViewLineIndentGuide(0), 0); + assert.equal(linesCollection.getViewLineIndentGuide(1), 0); + assert.equal(linesCollection.getViewLineIndentGuide(2), 1); + assert.equal(linesCollection.getViewLineIndentGuide(3), 0); + assert.equal(linesCollection.getViewLineIndentGuide(4), 0); + assert.equal(linesCollection.getViewLineIndentGuide(5), 1); + assert.equal(linesCollection.getViewLineIndentGuide(6), 0); + assert.equal(linesCollection.getViewLineIndentGuide(7), 0); // getOutputLineContent - assert.equal(linesCollection.getOutputLineContent(-1), 'int main() {'); - assert.equal(linesCollection.getOutputLineContent(0), 'int main() {'); - assert.equal(linesCollection.getOutputLineContent(1), 'int main() {'); - assert.equal(linesCollection.getOutputLineContent(2), '\tprintf("Hello world!");'); - assert.equal(linesCollection.getOutputLineContent(3), '}'); - assert.equal(linesCollection.getOutputLineContent(4), 'int main() {'); - assert.equal(linesCollection.getOutputLineContent(5), '\tprintf("Hello world!");'); - assert.equal(linesCollection.getOutputLineContent(6), '}'); - assert.equal(linesCollection.getOutputLineContent(7), '}'); + assert.equal(linesCollection.getViewLineContent(-1), 'int main() {'); + assert.equal(linesCollection.getViewLineContent(0), 'int main() {'); + assert.equal(linesCollection.getViewLineContent(1), 'int main() {'); + assert.equal(linesCollection.getViewLineContent(2), '\tprintf("Hello world!");'); + assert.equal(linesCollection.getViewLineContent(3), '}'); + assert.equal(linesCollection.getViewLineContent(4), 'int main() {'); + assert.equal(linesCollection.getViewLineContent(5), '\tprintf("Hello world!");'); + assert.equal(linesCollection.getViewLineContent(6), '}'); + assert.equal(linesCollection.getViewLineContent(7), '}'); // getOutputLineMinColumn - assert.equal(linesCollection.getOutputLineMinColumn(-1), 1); - assert.equal(linesCollection.getOutputLineMinColumn(0), 1); - assert.equal(linesCollection.getOutputLineMinColumn(1), 1); - assert.equal(linesCollection.getOutputLineMinColumn(2), 1); - assert.equal(linesCollection.getOutputLineMinColumn(3), 1); - assert.equal(linesCollection.getOutputLineMinColumn(4), 1); - assert.equal(linesCollection.getOutputLineMinColumn(5), 1); - assert.equal(linesCollection.getOutputLineMinColumn(6), 1); - assert.equal(linesCollection.getOutputLineMinColumn(7), 1); + assert.equal(linesCollection.getViewLineMinColumn(-1), 1); + assert.equal(linesCollection.getViewLineMinColumn(0), 1); + assert.equal(linesCollection.getViewLineMinColumn(1), 1); + assert.equal(linesCollection.getViewLineMinColumn(2), 1); + assert.equal(linesCollection.getViewLineMinColumn(3), 1); + assert.equal(linesCollection.getViewLineMinColumn(4), 1); + assert.equal(linesCollection.getViewLineMinColumn(5), 1); + assert.equal(linesCollection.getViewLineMinColumn(6), 1); + assert.equal(linesCollection.getViewLineMinColumn(7), 1); // getOutputLineMaxColumn - assert.equal(linesCollection.getOutputLineMaxColumn(-1), 13); - assert.equal(linesCollection.getOutputLineMaxColumn(0), 13); - assert.equal(linesCollection.getOutputLineMaxColumn(1), 13); - assert.equal(linesCollection.getOutputLineMaxColumn(2), 25); - assert.equal(linesCollection.getOutputLineMaxColumn(3), 2); - assert.equal(linesCollection.getOutputLineMaxColumn(4), 13); - assert.equal(linesCollection.getOutputLineMaxColumn(5), 25); - assert.equal(linesCollection.getOutputLineMaxColumn(6), 2); - assert.equal(linesCollection.getOutputLineMaxColumn(7), 2); + assert.equal(linesCollection.getViewLineMaxColumn(-1), 13); + assert.equal(linesCollection.getViewLineMaxColumn(0), 13); + assert.equal(linesCollection.getViewLineMaxColumn(1), 13); + assert.equal(linesCollection.getViewLineMaxColumn(2), 25); + assert.equal(linesCollection.getViewLineMaxColumn(3), 2); + assert.equal(linesCollection.getViewLineMaxColumn(4), 13); + assert.equal(linesCollection.getViewLineMaxColumn(5), 25); + assert.equal(linesCollection.getViewLineMaxColumn(6), 2); + assert.equal(linesCollection.getViewLineMaxColumn(7), 2); // convertOutputPositionToInputPosition - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(-1, 1), new Position(1, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(0, 1), new Position(1, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(1, 1), new Position(1, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(2, 1), new Position(2, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(3, 1), new Position(3, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(4, 1), new Position(4, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(5, 1), new Position(5, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(6, 1), new Position(6, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(7, 1), new Position(6, 1)); - assert.deepEqual(linesCollection.convertOutputPositionToInputPosition(8, 1), new Position(6, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(-1, 1), new Position(1, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(0, 1), new Position(1, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(1, 1), new Position(1, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(2, 1), new Position(2, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(3, 1), new Position(3, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(4, 1), new Position(4, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(5, 1), new Position(5, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(6, 1), new Position(6, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(7, 1), new Position(6, 1)); + assert.deepEqual(linesCollection.convertViewPositionToModelPosition(8, 1), new Position(6, 1)); }); }); @@ -210,7 +210,7 @@ suite('Editor ViewModel - SplitLinesCollection', () => { endColumn: 1 }], (eventType, payload) => {/*no-op*/ }); - let viewLineCount = linesCollection.getOutputLineCount(); + let viewLineCount = linesCollection.getViewLineCount(); assert.equal(viewLineCount, 1, 'getOutputLineCount()'); let modelLineCount = model.getLineCount(); @@ -218,7 +218,7 @@ suite('Editor ViewModel - SplitLinesCollection', () => { let lineMinColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMinColumn(lineNumber) : 1; let lineMaxColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMaxColumn(lineNumber) : 1; for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) { - let viewPosition = linesCollection.convertInputPositionToOutputPosition(lineNumber, column); + let viewPosition = linesCollection.convertModelPositionToViewPosition(lineNumber, column); // validate view position let viewLineNumber = viewPosition.lineNumber; @@ -226,12 +226,12 @@ suite('Editor ViewModel - SplitLinesCollection', () => { if (viewLineNumber < 1) { viewLineNumber = 1; } - var lineCount = linesCollection.getOutputLineCount(); + var lineCount = linesCollection.getViewLineCount(); if (viewLineNumber > lineCount) { viewLineNumber = lineCount; } - var viewMinColumn = linesCollection.getOutputLineMinColumn(viewLineNumber); - var viewMaxColumn = linesCollection.getOutputLineMaxColumn(viewLineNumber); + var viewMinColumn = linesCollection.getViewLineMinColumn(viewLineNumber); + var viewMaxColumn = linesCollection.getViewLineMaxColumn(viewLineNumber); if (viewColumn < viewMinColumn) { viewColumn = viewMinColumn; } @@ -244,10 +244,10 @@ suite('Editor ViewModel - SplitLinesCollection', () => { } for (let lineNumber = 0; lineNumber <= viewLineCount + 1; lineNumber++) { - let lineMinColumn = linesCollection.getOutputLineMinColumn(lineNumber); - let lineMaxColumn = linesCollection.getOutputLineMaxColumn(lineNumber); + let lineMinColumn = linesCollection.getViewLineMinColumn(lineNumber); + let lineMaxColumn = linesCollection.getViewLineMaxColumn(lineNumber); for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) { - let modelPosition = linesCollection.convertOutputPositionToInputPosition(lineNumber, column); + let modelPosition = linesCollection.convertViewPositionToModelPosition(lineNumber, column); let validModelPosition = model.validatePosition(modelPosition); assert.equal(modelPosition.toString(), validModelPosition.toString(), 'view->model for ' + lineNumber + ', ' + column); } diff --git a/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts index a384b8fddac..e14fbf88ef4 100644 --- a/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts +++ b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts @@ -47,10 +47,7 @@ suite('ViewModelDecorations', () => { linesCollection, EDITOR_ID, configuration, - model, - () => { - return new Range(1, 1, 1, 1); - } + model ); callback(viewModel, model); -- GitLab