From 777c5e0f3b83b7e865982026314dfe4e6663fc0e Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Sat, 4 Feb 2017 11:10:06 +0100 Subject: [PATCH] Remove VerticalObjects --- .../browser/viewLayout/layoutProvider.ts | 48 +- .../browser/viewParts/lines/viewLines.ts | 2 +- .../editor/common/viewLayout/linesLayout.ts | 434 ++++++++++--- .../common/viewLayout/verticalObjects.ts | 455 -------------- .../common/viewLayout/whitespaceComputer.ts | 205 +++--- .../common/viewLayout/linesLayout.test.ts | 579 +++++++++++++++++ .../common/viewLayout/verticalObjects.test.ts | 588 ------------------ 7 files changed, 1058 insertions(+), 1253 deletions(-) delete mode 100644 src/vs/editor/common/viewLayout/verticalObjects.ts create mode 100644 src/vs/editor/test/common/viewLayout/linesLayout.test.ts delete mode 100644 src/vs/editor/test/common/viewLayout/verticalObjects.test.ts diff --git a/src/vs/editor/browser/viewLayout/layoutProvider.ts b/src/vs/editor/browser/viewLayout/layoutProvider.ts index 74844f77758..94c8bf6473d 100644 --- a/src/vs/editor/browser/viewLayout/layoutProvider.ts +++ b/src/vs/editor/browser/viewLayout/layoutProvider.ts @@ -78,11 +78,6 @@ export interface IVerticalLayoutProvider { */ getVerticalOffsetForLineNumber(lineNumber: number): number; - /** - * Returns the height in pixels for `lineNumber`. - */ - heightInPxForLine(lineNumber: number): number; - /** * Return line number at `verticalOffset` or closest line number */ @@ -121,7 +116,7 @@ export class LayoutProvider extends ViewEventHandler implements IDisposable, ILa this.configuration.setMaxLineNumber(this.model.getMaxLineNumber()); - this.linesLayout = new LinesLayout(configuration, this.model.getLineCount()); + this.linesLayout = new LinesLayout(this.model.getLineCount(), this.configuration.editor.lineHeight); this._updateHeight(); } @@ -149,21 +144,23 @@ export class LayoutProvider extends ViewEventHandler implements IDisposable, ILa } public onModelLinesDeleted(e: editorCommon.IViewLinesDeletedEvent): boolean { - this.linesLayout.onModelLinesDeleted(e); + this.linesLayout.onModelLinesDeleted(e.fromLineNumber, e.toLineNumber); this.updateLineCount(); this._updateHeight(); return false; } public onModelLinesInserted(e: editorCommon.IViewLinesInsertedEvent): boolean { - this.linesLayout.onModelLinesInserted(e); + this.linesLayout.onModelLinesInserted(e.fromLineNumber, e.toLineNumber); this.updateLineCount(); this._updateHeight(); return false; } public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean { - this.linesLayout.onConfigurationChanged(e); + if (e.lineHeight) { + this.linesLayout.setLineHeight(this.configuration.editor.lineHeight); + } if (e.layoutInfo) { this.scrollManager.onLayoutInfoChanged(); this._emitLayoutChangedEvent(); @@ -251,15 +248,34 @@ export class LayoutProvider extends ViewEventHandler implements IDisposable, ILa public getVerticalOffsetForLineNumber(lineNumber: number): number { return this.linesLayout.getVerticalOffsetForLineNumber(lineNumber); } - public heightInPxForLine(lineNumber: number): number { - return this.linesLayout.getHeightForLineNumber(lineNumber); - } public isAfterLines(verticalOffset: number): boolean { return this.linesLayout.isAfterLines(verticalOffset); } public getLineNumberAtVerticalOffset(verticalOffset: number): number { return this.linesLayout.getLineNumberAtOrAfterVerticalOffset(verticalOffset); } + + /** + * Get the sum of heights for all objects and compute basically the `scrollHeight` for the editor content. + * + * Take into account the `scrollBeyondLastLine` and `reserveHorizontalScrollbarHeight` and produce a scrollHeight that is at least as large as `viewport`.height. + * + * @param viewport The viewport. + * @param reserveHorizontalScrollbarHeight The height of the horizontal scrollbar. + * @return Basically, the `scrollHeight` for the editor content. + */ + private _getTotalHeight(viewport: editorCommon.Viewport, reserveHorizontalScrollbarHeight: number): number { + var totalLinesHeight = this.linesLayout.getLinesTotalHeight(); + + if (this.configuration.editor.viewInfo.scrollBeyondLastLine) { + totalLinesHeight += viewport.height - this.configuration.editor.lineHeight; + } else { + totalLinesHeight += reserveHorizontalScrollbarHeight; + } + + return Math.max(viewport.height, totalLinesHeight); + } + public getTotalHeight(): number { let reserveHorizontalScrollbarHeight = 0; if (this.scrollManager.getScrollWidth() > this.scrollManager.getWidth()) { @@ -267,16 +283,18 @@ export class LayoutProvider extends ViewEventHandler implements IDisposable, ILa reserveHorizontalScrollbarHeight = this.configuration.editor.viewInfo.scrollbar.horizontalScrollbarSize; } } - return this.linesLayout.getTotalHeight(this.getCurrentViewport(), reserveHorizontalScrollbarHeight); + return this._getTotalHeight(this.getCurrentViewport(), reserveHorizontalScrollbarHeight); } public getWhitespaceAtVerticalOffset(verticalOffset: number): editorCommon.IViewWhitespaceViewportData { return this.linesLayout.getWhitespaceAtVerticalOffset(verticalOffset); } public getLinesViewportData(): IPartialViewLinesViewportData { - return this.linesLayout.getLinesViewportData(this.getCurrentViewport()); + const visibleBox = this.getCurrentViewport(); + return this.linesLayout.getLinesViewportData(visibleBox.top, visibleBox.top + visibleBox.height); } public getWhitespaceViewportData(): editorCommon.IViewWhitespaceViewportData[] { - return this.linesLayout.getWhitespaceViewportData(this.getCurrentViewport()); + const visibleBox = this.getCurrentViewport(); + return this.linesLayout.getWhitespaceViewportData(visibleBox.top, visibleBox.top + visibleBox.height); } public getWhitespaces(): editorCommon.IEditorWhitespace[] { return this.linesLayout.getWhitespaces(); diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index caca907ddc1..88f10de80a4 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -486,7 +486,7 @@ export class ViewLines extends ViewLayer implements IViewLines { // Have a box that includes one extra line height (for the horizontal scrollbar) boxStartY = this._layoutProvider.getVerticalOffsetForLineNumber(range.startLineNumber); - boxEndY = this._layoutProvider.getVerticalOffsetForLineNumber(range.endLineNumber) + this._layoutProvider.heightInPxForLine(range.endLineNumber); + boxEndY = this._layoutProvider.getVerticalOffsetForLineNumber(range.endLineNumber) + this._lineHeight; if (verticalType === editorCommon.VerticalRevealType.Simple || verticalType === editorCommon.VerticalRevealType.Bottom) { // Reveal one line more when the last line would be covered by the scrollbar - arrow down case or revealing a line explicitly at bottom boxEndY += this._lineHeight; diff --git a/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts index 117073d0360..cbcde814d90 100644 --- a/src/vs/editor/common/viewLayout/linesLayout.ts +++ b/src/vs/editor/common/viewLayout/linesLayout.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as editorCommon from 'vs/editor/common/editorCommon'; -import { VerticalObjects } from 'vs/editor/common/viewLayout/verticalObjects'; +import { IEditorWhitespace, IViewWhitespaceViewportData } from 'vs/editor/common/editorCommon'; +import { WhitespaceComputer } from 'vs/editor/common/viewLayout/whitespaceComputer'; import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; /** @@ -13,32 +13,46 @@ import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewL * * These objects are basically either text (lines) or spaces between those lines (whitespaces). * This provides commodity operations for working with lines that contain whitespace that pushes lines lower (vertically). - * This is a thin wrapper around VerticalObjects.VerticalObjects, with knowledge of the editor. + * This is written with no knowledge of an editor in mind. */ export class LinesLayout { - private configuration: editorCommon.IConfiguration; - private verticalObjects: VerticalObjects; + /** + * Keep track of the total number of lines. + * This is useful for doing binary searches or for doing hit-testing. + */ + private _lineCount: number; + /** + * The height of a line in pixels. + */ private _lineHeight: number; - private _scrollBeyondLastLine: boolean; - constructor(configuration: editorCommon.IConfiguration, lineCount: number) { - this.configuration = configuration; - this._lineHeight = this.configuration.editor.lineHeight; - this._scrollBeyondLastLine = this.configuration.editor.viewInfo.scrollBeyondLastLine; + /** + * Contains whitespace information in pixels + */ + private _whitespaces: WhitespaceComputer; - this.verticalObjects = new VerticalObjects(); - this.verticalObjects.replaceLines(lineCount); + constructor(lineCount: number, lineHeight: number) { + this._lineCount = lineCount; + this._lineHeight = lineHeight; + this._whitespaces = new WhitespaceComputer(); } - public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): void { - if (e.lineHeight) { - this._lineHeight = this.configuration.editor.lineHeight; - } - if (e.viewInfo.scrollBeyondLastLine) { - this._scrollBeyondLastLine = this.configuration.editor.viewInfo.scrollBeyondLastLine; - } + /** + * Change the height of a line in pixels. + */ + public setLineHeight(lineHeight: number): void { + this._lineHeight = lineHeight; + } + + /** + * Set the number of lines. + * + * @param lineCount New number of lines. + */ + public onModelFlushed(lineCount: number): void { + this._lineCount = lineCount; } /** @@ -50,12 +64,15 @@ export class LinesLayout { * @param heightInPx The height of the whitespace, in pixels. * @return An id that can be used later to mutate or delete the whitespace */ - public insertWhitespace(afterLineNumber: number, ordinal: number, height: number): number { - return this.verticalObjects.insertWhitespace(afterLineNumber, ordinal, height); + public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number): number { + return this._whitespaces.insertWhitespace(afterLineNumber, ordinal, heightInPx); } + /** + * Change properties associated with a certain whitespace. + */ public changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean { - return this.verticalObjects.changeWhitespace(id, newAfterLineNumber, newHeight); + return this._whitespaces.changeWhitespace(id, newAfterLineNumber, newHeight); } /** @@ -65,28 +82,40 @@ export class LinesLayout { * @return Returns true if the whitespace is found and it is removed. */ public removeWhitespace(id: number): boolean { - return this.verticalObjects.removeWhitespace(id); + return this._whitespaces.removeWhitespace(id); } /** - * Event handler, call when the model associated to this view has been flushed. + * Notify the layouter that lines have been deleted (a continuous zone of lines). + * + * @param fromLineNumber The line number at which the deletion started, inclusive + * @param toLineNumber The line number at which the deletion ended, inclusive */ - public onModelFlushed(lineCount: number): void { - this.verticalObjects.replaceLines(lineCount); + public onModelLinesDeleted(fromLineNumber: number, toLineNumber: number): void { + this._lineCount -= (toLineNumber - fromLineNumber + 1); + this._whitespaces.onModelLinesDeleted(fromLineNumber, toLineNumber); } /** - * Event handler, call when the model has had lines deleted. + * Notify the layouter that lines have been inserted (a continuous zone of lines). + * + * @param fromLineNumber The line number at which the insertion started, inclusive + * @param toLineNumber The line number at which the insertion ended, inclusive. */ - public onModelLinesDeleted(e: editorCommon.IViewLinesDeletedEvent): void { - this.verticalObjects.onModelLinesDeleted(e.fromLineNumber, e.toLineNumber); + public onModelLinesInserted(fromLineNumber: number, toLineNumber: number): void { + this._lineCount += (toLineNumber - fromLineNumber + 1); + this._whitespaces.onModelLinesInserted(fromLineNumber, toLineNumber); } /** - * Event handler, call when the model has had lines inserted. + * Get the sum of heights for all objects. + * + * @return The sum of heights for all objects. */ - public onModelLinesInserted(e: editorCommon.IViewLinesInsertedEvent): void { - this.verticalObjects.onModelLinesInserted(e.fromLineNumber, e.toLineNumber); + public getLinesTotalHeight(): number { + let linesHeight = this._lineHeight * this._lineCount; + let whitespacesHeight = this._whitespaces.getTotalHeight(); + return linesHeight + whitespacesHeight; } /** @@ -96,40 +125,42 @@ export class LinesLayout { * @return The sum of heights for all objects above `lineNumber`. */ public getVerticalOffsetForLineNumber(lineNumber: number): number { - return this.verticalObjects.getVerticalOffsetForLineNumber(lineNumber, this._lineHeight); - } + lineNumber = lineNumber | 0; - public getLinesTotalHeight(): number { - return this.verticalObjects.getTotalHeight(this._lineHeight); + let previousLinesHeight: number; + if (lineNumber > 1) { + previousLinesHeight = this._lineHeight * (lineNumber - 1); + } else { + previousLinesHeight = 0; + } + + let previousWhitespacesHeight = this._whitespaces.getAccumulatedHeightBeforeLineNumber(lineNumber); + + return previousLinesHeight + previousWhitespacesHeight; } /** - * Get the sum of heights for all objects and compute basically the `scrollHeight` for the editor content. - * - * Take into account the `scrollBeyondLastLine` and `reserveHorizontalScrollbarHeight` and produce a scrollHeight that is at least as large as `viewport`.height. + * Returns the accumulated height of whitespaces before the given line number. * - * @param viewport The viewport. - * @param reserveHorizontalScrollbarHeight The height of the horizontal scrollbar. - * @return Basically, the `scrollHeight` for the editor content. + * @param lineNumber The line number */ - public getTotalHeight(viewport: editorCommon.Viewport, reserveHorizontalScrollbarHeight: number): number { - var totalLinesHeight = this.getLinesTotalHeight(); - - // if (this.context.configuration.editor.autoSize) { - // return linesHeight; - // } - - if (this._scrollBeyondLastLine) { - totalLinesHeight += viewport.height - this._lineHeight; - } else { - totalLinesHeight += reserveHorizontalScrollbarHeight; - } + public getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number { + return this._whitespaces.getAccumulatedHeightBeforeLineNumber(lineNumber); + } - return Math.max(viewport.height, totalLinesHeight); + /** + * Returns if there is any whitespace in the document. + */ + public hasWhitespace(): boolean { + return this._whitespaces.getCount() > 0; } + /** + * Check if `verticalOffset` is below all lines. + */ public isAfterLines(verticalOffset: number): boolean { - return this.verticalObjects.isAfterLines(verticalOffset, this._lineHeight); + let totalHeight = this.getLinesTotalHeight(); + return verticalOffset > totalHeight; } /** @@ -141,31 +172,209 @@ export class LinesLayout { * @return The line number at or after vertical offset `verticalOffset`. */ public getLineNumberAtOrAfterVerticalOffset(verticalOffset: number): number { - return this.verticalObjects.getLineNumberAtOrAfterVerticalOffset(verticalOffset, this._lineHeight); + verticalOffset = verticalOffset | 0; + + if (verticalOffset < 0) { + return 1; + } + + const linesCount = this._lineCount | 0; + const lineHeight = this._lineHeight; + let minLineNumber = 1; + let maxLineNumber = linesCount; + + while (minLineNumber < maxLineNumber) { + let midLineNumber = ((minLineNumber + maxLineNumber) / 2) | 0; + + let midLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(midLineNumber) | 0; + + if (verticalOffset >= midLineNumberVerticalOffset + lineHeight) { + // vertical offset is after mid line number + minLineNumber = midLineNumber + 1; + } else if (verticalOffset >= midLineNumberVerticalOffset) { + // Hit + return midLineNumber; + } else { + // vertical offset is before mid line number, but mid line number could still be what we're searching for + maxLineNumber = midLineNumber; + } + } + + if (minLineNumber > linesCount) { + return linesCount; + } + + return minLineNumber; } /** - * Get the height, in pixels, for line `lineNumber`. + * Get all the lines and their relative vertical offsets that are positioned between `verticalOffset1` and `verticalOffset2`. * - * @param lineNumber The line number - * @return The height, in pixels, for line `lineNumber`. + * @param verticalOffset1 The beginning of the viewport. + * @param verticalOffset2 The end of the viewport. + * @return A structure describing the lines positioned between `verticalOffset1` and `verticalOffset2`. */ - public getHeightForLineNumber(lineNumber: number): number { - return this._lineHeight; + public getLinesViewportData(verticalOffset1: number, verticalOffset2: number): IPartialViewLinesViewportData { + verticalOffset1 = verticalOffset1 | 0; + verticalOffset2 = verticalOffset2 | 0; + const lineHeight = this._lineHeight; + + // Find first line number + // We don't live in a perfect world, so the line number might start before or after verticalOffset1 + let startLineNumber = this.getLineNumberAtOrAfterVerticalOffset(verticalOffset1) | 0; + + let endLineNumber = this._lineCount | 0; + let startLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(startLineNumber) | 0; + + // Also keep track of what whitespace we've got + let whitespaceIndex = this._whitespaces.getFirstWhitespaceIndexAfterLineNumber(startLineNumber) | 0; + let whitespaceCount = this._whitespaces.getCount() | 0; + let currentWhitespaceHeight: number; + let currentWhitespaceAfterLineNumber: number; + + if (whitespaceIndex === -1) { + whitespaceIndex = whitespaceCount; + currentWhitespaceAfterLineNumber = endLineNumber + 1; + currentWhitespaceHeight = 0; + } else { + currentWhitespaceAfterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; + currentWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(whitespaceIndex) | 0; + } + + let currentVerticalOffset = startLineNumberVerticalOffset; + let currentLineRelativeOffset = currentVerticalOffset; + + // IE (all versions) cannot handle units above about 1,533,908 px, so every 500k pixels bring numbers down + const STEP_SIZE = 500000; + let bigNumbersDelta = 0; + if (startLineNumberVerticalOffset >= STEP_SIZE) { + // Compute a delta that guarantees that lines are positioned at `lineHeight` increments + bigNumbersDelta = Math.floor(startLineNumberVerticalOffset / STEP_SIZE) * STEP_SIZE; + bigNumbersDelta = Math.floor(bigNumbersDelta / lineHeight) * lineHeight; + + currentLineRelativeOffset -= bigNumbersDelta; + } + + let linesOffsets: number[] = []; + + let verticalCenter = verticalOffset1 + (verticalOffset2 - verticalOffset1) / 2; + let centeredLineNumber = -1; + + // Figure out how far the lines go + for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { + + if (centeredLineNumber === -1) { + let currentLineTop = currentVerticalOffset; + let currentLineBottom = currentVerticalOffset + lineHeight; + if ((currentLineTop <= verticalCenter && verticalCenter < currentLineBottom) || currentLineTop > verticalCenter) { + centeredLineNumber = lineNumber; + } + } + + // Count current line height in the vertical offsets + currentVerticalOffset += lineHeight; + linesOffsets[lineNumber - startLineNumber] = currentLineRelativeOffset; + + // Next line starts immediately after this one + currentLineRelativeOffset += lineHeight; + while (currentWhitespaceAfterLineNumber === lineNumber) { + // Push down next line with the height of the current whitespace + currentLineRelativeOffset += currentWhitespaceHeight; + + // Count current whitespace in the vertical offsets + currentVerticalOffset += currentWhitespaceHeight; + whitespaceIndex++; + + if (whitespaceIndex >= whitespaceCount) { + currentWhitespaceAfterLineNumber = endLineNumber + 1; + } else { + currentWhitespaceAfterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; + currentWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(whitespaceIndex) | 0; + } + } + + if (currentVerticalOffset >= verticalOffset2) { + // We have covered the entire viewport area, time to stop + endLineNumber = lineNumber; + break; + } + } + + if (centeredLineNumber === -1) { + centeredLineNumber = endLineNumber; + } + + return { + viewportTop: verticalOffset1 - bigNumbersDelta, + viewportHeight: verticalOffset2 - verticalOffset1, + bigNumbersDelta: bigNumbersDelta, + startLineNumber: startLineNumber, + endLineNumber: endLineNumber, + visibleRangesDeltaTop: -(verticalOffset1 - bigNumbersDelta), + relativeVerticalOffset: linesOffsets, + centeredLineNumber: centeredLineNumber + }; } - /** - * Get a list of whitespaces that are positioned inside `viewport`. - * - * @param viewport The viewport. - * @return An array with all the whitespaces in the viewport. If no whitespace is in viewport, the array is empty. - */ - public getWhitespaceViewportData(visibleBox: editorCommon.Viewport): editorCommon.IViewWhitespaceViewportData[] { - return this.verticalObjects.getWhitespaceViewportData(visibleBox.top, visibleBox.top + visibleBox.height, this._lineHeight); + public getVerticalOffsetForWhitespaceIndex(whitespaceIndex: number): number { + whitespaceIndex = whitespaceIndex | 0; + + let afterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex); + + let previousLinesHeight: number; + if (afterLineNumber >= 1) { + previousLinesHeight = this._lineHeight * afterLineNumber; + } else { + previousLinesHeight = 0; + } + + let previousWhitespacesHeight: number; + if (whitespaceIndex > 0) { + previousWhitespacesHeight = this._whitespaces.getAccumulatedHeight(whitespaceIndex - 1); + } else { + previousWhitespacesHeight = 0; + } + return previousLinesHeight + previousWhitespacesHeight; } - public getWhitespaces(): editorCommon.IEditorWhitespace[] { - return this.verticalObjects.getWhitespaces(this._lineHeight); + public getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number): number { + verticalOffset = verticalOffset | 0; + + let midWhitespaceIndex: number, + minWhitespaceIndex = 0, + maxWhitespaceIndex = this._whitespaces.getCount() - 1, + midWhitespaceVerticalOffset: number, + midWhitespaceHeight: number; + + if (maxWhitespaceIndex < 0) { + return -1; + } + + // Special case: nothing to be found + let maxWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(maxWhitespaceIndex); + let maxWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(maxWhitespaceIndex); + if (verticalOffset >= maxWhitespaceVerticalOffset + maxWhitespaceHeight) { + return -1; + } + + while (minWhitespaceIndex < maxWhitespaceIndex) { + midWhitespaceIndex = Math.floor((minWhitespaceIndex + maxWhitespaceIndex) / 2); + + midWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(midWhitespaceIndex); + midWhitespaceHeight = this._whitespaces.getHeightForWhitespaceIndex(midWhitespaceIndex); + + if (verticalOffset >= midWhitespaceVerticalOffset + midWhitespaceHeight) { + // vertical offset is after whitespace + minWhitespaceIndex = midWhitespaceIndex + 1; + } else if (verticalOffset >= midWhitespaceVerticalOffset) { + // Hit + return midWhitespaceIndex; + } else { + // vertical offset is before whitespace, but midWhitespaceIndex might still be what we're searching for + maxWhitespaceIndex = midWhitespaceIndex; + } + } + return minWhitespaceIndex; } /** @@ -174,33 +383,78 @@ export class LinesLayout { * @param verticalOffset The vertical offset. * @return Precisely the whitespace that is layouted at `verticaloffset` or null. */ - public getWhitespaceAtVerticalOffset(verticalOffset: number): editorCommon.IViewWhitespaceViewportData { - return this.verticalObjects.getWhitespaceAtVerticalOffset(verticalOffset, this._lineHeight); - } + public getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData { + verticalOffset = verticalOffset | 0; - /** - * Get all the lines and their relative vertical offsets that are positioned inside `viewport`. - * - * @param viewport The viewport. - * @return A structure describing the lines positioned between `verticalOffset1` and `verticalOffset2`. - */ - public getLinesViewportData(visibleBox: editorCommon.Viewport): IPartialViewLinesViewportData { - return this.verticalObjects.getLinesViewportData(visibleBox.top, visibleBox.top + visibleBox.height, this._lineHeight); + let candidateIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset); + + if (candidateIndex < 0) { + return null; + } + + if (candidateIndex >= this._whitespaces.getCount()) { + return null; + } + + let candidateTop = this.getVerticalOffsetForWhitespaceIndex(candidateIndex); + + if (candidateTop > verticalOffset) { + return null; + } + + let candidateHeight = this._whitespaces.getHeightForWhitespaceIndex(candidateIndex); + let candidateId = this._whitespaces.getIdForWhitespaceIndex(candidateIndex); + let candidateAfterLineNumber = this._whitespaces.getAfterLineNumberForWhitespaceIndex(candidateIndex); + + return { + id: candidateId, + afterLineNumber: candidateAfterLineNumber, + verticalOffset: candidateTop, + height: candidateHeight + }; } /** - * Returns the accumulated height of whitespaces before the given line number. + * Get a list of whitespaces that are positioned between `verticalOffset1` and `verticalOffset2`. * - * @param lineNumber The line number + * @param verticalOffset1 The beginning of the viewport. + * @param verticalOffset2 The end of the viewport. + * @return An array with all the whitespaces in the viewport. If no whitespace is in viewport, the array is empty. */ - public getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number { - return this.verticalObjects.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber); + public getWhitespaceViewportData(verticalOffset1: number, verticalOffset2: number): IViewWhitespaceViewportData[] { + verticalOffset1 = verticalOffset1 | 0; + verticalOffset2 = verticalOffset2 | 0; + + let startIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset1); + let endIndex = this._whitespaces.getCount() - 1; + + if (startIndex < 0) { + return []; + } + + let result: IViewWhitespaceViewportData[] = []; + for (let i = startIndex; i <= endIndex; i++) { + let top = this.getVerticalOffsetForWhitespaceIndex(i); + let height = this._whitespaces.getHeightForWhitespaceIndex(i); + if (top >= verticalOffset2) { + break; + } + + result.push({ + id: this._whitespaces.getIdForWhitespaceIndex(i), + afterLineNumber: this._whitespaces.getAfterLineNumberForWhitespaceIndex(i), + verticalOffset: top, + height: height + }); + } + + return result; } /** - * Returns if there is any whitespace in the document. + * Get all whitespaces. */ - public hasWhitespace(): boolean { - return this.verticalObjects.hasWhitespace(); + public getWhitespaces(): IEditorWhitespace[] { + return this._whitespaces.getWhitespaces(this._lineHeight); } } diff --git a/src/vs/editor/common/viewLayout/verticalObjects.ts b/src/vs/editor/common/viewLayout/verticalObjects.ts deleted file mode 100644 index 9ceb263e700..00000000000 --- a/src/vs/editor/common/viewLayout/verticalObjects.ts +++ /dev/null @@ -1,455 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import { IEditorWhitespace, IViewWhitespaceViewportData } from 'vs/editor/common/editorCommon'; -import { WhitespaceComputer } from 'vs/editor/common/viewLayout/whitespaceComputer'; -import { IPartialViewLinesViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; - -/** - * Layouting of objects that take vertical space (by having a height) and push down other objects. - * - * These objects are basically either text (lines) or spaces between those lines (whitespaces). - * This provides commodity operations for working with lines that contain whitespace that pushes lines lower (vertically). - * This is written with no knowledge of an editor in mind. - */ -export class VerticalObjects { - - /** - * Keep track of the total number of lines. - * This is useful for doing binary searches or for doing hit-testing. - */ - private linesCount: number; - - /** - * Contains whitespace information in pixels - */ - private whitespaces: WhitespaceComputer; - - constructor() { - this.linesCount = 0; - this.whitespaces = new WhitespaceComputer(); - } - - /** - * Set the number of lines. - * - * @param newLineCount New number of lines. - */ - public replaceLines(newLineCount: number): void { - this.linesCount = newLineCount; - } - - /** - * Insert a new whitespace of a certain height after a line number. - * The whitespace has a "sticky" characteristic. - * Irrespective of edits above or below `afterLineNumber`, the whitespace will follow the initial line. - * - * @param afterLineNumber The conceptual position of this whitespace. The whitespace will follow this line as best as possible even when deleting/inserting lines above/below. - * @param heightInPx The height of the whitespace, in pixels. - * @return An id that can be used later to mutate or delete the whitespace - */ - public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number): number { - return this.whitespaces.insertWhitespace(afterLineNumber, ordinal, heightInPx); - } - - public changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean { - return this.whitespaces.changeWhitespace(id, newAfterLineNumber, newHeight); - } - - /** - * Remove an existing whitespace. - * - * @param id The whitespace to remove - * @return Returns true if the whitespace is found and it is removed. - */ - public removeWhitespace(id: number): boolean { - return this.whitespaces.removeWhitespace(id); - } - - /** - * Notify the layouter that lines have been deleted (a continuous zone of lines). - * - * @param fromLineNumber The line number at which the deletion started, inclusive - * @param toLineNumber The line number at which the deletion ended, inclusive - */ - public onModelLinesDeleted(fromLineNumber: number, toLineNumber: number): void { - this.linesCount -= (toLineNumber - fromLineNumber + 1); - this.whitespaces.onModelLinesDeleted(fromLineNumber, toLineNumber); - } - - /** - * Notify the layouter that lines have been inserted (a continuous zone of lines). - * - * @param fromLineNumber The line number at which the insertion started, inclusive - * @param toLineNumber The line number at which the insertion ended, inclusive. - */ - public onModelLinesInserted(fromLineNumber: number, toLineNumber: number): void { - this.linesCount += (toLineNumber - fromLineNumber + 1); - this.whitespaces.onModelLinesInserted(fromLineNumber, toLineNumber); - } - - /** - * Get the sum of heights for all objects. - * - * @param deviceLineHeight The height, in pixels, for one rendered line. - * @return The sum of heights for all objects. - */ - public getTotalHeight(deviceLineHeight: number): number { - deviceLineHeight = deviceLineHeight | 0; - - let linesHeight = deviceLineHeight * this.linesCount; - let whitespacesHeight = this.whitespaces.getTotalHeight(); - return linesHeight + whitespacesHeight; - } - - /** - * Get the vertical offset (the sum of heights for all objects above) a certain line number. - * - * @param lineNumber The line number - * @param deviceLineHeight The height, in pixels, for one rendered line. - * @return The sum of heights for all objects above `lineNumber`. - */ - public getVerticalOffsetForLineNumber(lineNumber: number, deviceLineHeight: number): number { - lineNumber = lineNumber | 0; - deviceLineHeight = deviceLineHeight | 0; - - let previousLinesHeight: number; - if (lineNumber > 1) { - previousLinesHeight = deviceLineHeight * (lineNumber - 1); - } else { - previousLinesHeight = 0; - } - - let previousWhitespacesHeight = this.whitespaces.getAccumulatedHeightBeforeLineNumber(lineNumber); - - return previousLinesHeight + previousWhitespacesHeight; - } - - /** - * Returns the accumulated height of whitespaces before the given line number. - * - * @param lineNumber The line number - */ - public getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number { - return this.whitespaces.getAccumulatedHeightBeforeLineNumber(lineNumber); - } - - /** - * Returns if there is any whitespace in the document. - */ - public hasWhitespace(): boolean { - return this.whitespaces.getCount() > 0; - } - - public isAfterLines(verticalOffset: number, deviceLineHeight: number): boolean { - let totalHeight = this.getTotalHeight(deviceLineHeight); - return verticalOffset > totalHeight; - } - - /** - * Find the first line number that is at or after vertical offset `verticalOffset`. - * i.e. if getVerticalOffsetForLine(line) is x and getVerticalOffsetForLine(line + 1) is y, then - * getLineNumberAtOrAfterVerticalOffset(i) = line, x <= i < y. - * - * @param verticalOffset The vertical offset to search at. - * @param deviceLineHeight The height, in piexels, for one rendered line. - * @return The line number at or after vertical offset `verticalOffset`. - */ - public getLineNumberAtOrAfterVerticalOffset(verticalOffset: number, deviceLineHeight: number): number { - verticalOffset = verticalOffset | 0; - deviceLineHeight = deviceLineHeight | 0; - - if (verticalOffset < 0) { - return 1; - } - - let minLineNumber = 1; - let linesCount = this.linesCount | 0; - let maxLineNumber = linesCount; - - while (minLineNumber < maxLineNumber) { - let midLineNumber = ((minLineNumber + maxLineNumber) / 2) | 0; - - let midLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(midLineNumber, deviceLineHeight) | 0; - - if (verticalOffset >= midLineNumberVerticalOffset + deviceLineHeight) { - // vertical offset is after mid line number - minLineNumber = midLineNumber + 1; - } else if (verticalOffset >= midLineNumberVerticalOffset) { - // Hit - return midLineNumber; - } else { - // vertical offset is before mid line number, but mid line number could still be what we're searching for - maxLineNumber = midLineNumber; - } - } - - if (minLineNumber > linesCount) { - return linesCount; - } - - return minLineNumber; - } - - /** - * Get all the lines and their relative vertical offsets that are positioned between `verticalOffset1` and `verticalOffset2`. - * - * @param verticalOffset1 The beginning of the viewport. - * @param verticalOffset2 The end of the viewport. - * @param deviceLineHeight The height, in pixels, for one rendered line. - * @return A structure describing the lines positioned between `verticalOffset1` and `verticalOffset2`. - */ - public getLinesViewportData(verticalOffset1: number, verticalOffset2: number, deviceLineHeight: number): IPartialViewLinesViewportData { - verticalOffset1 = verticalOffset1 | 0; - verticalOffset2 = verticalOffset2 | 0; - deviceLineHeight = deviceLineHeight | 0; - - // Find first line number - // We don't live in a perfect world, so the line number might start before or after verticalOffset1 - let startLineNumber = this.getLineNumberAtOrAfterVerticalOffset(verticalOffset1, deviceLineHeight) | 0; - - let endLineNumber = this.linesCount | 0; - let startLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(startLineNumber, deviceLineHeight) | 0; - - // Also keep track of what whitespace we've got - let whitespaceIndex = this.whitespaces.getFirstWhitespaceIndexAfterLineNumber(startLineNumber) | 0; - let whitespaceCount = this.whitespaces.getCount() | 0; - let currentWhitespaceHeight: number; - let currentWhitespaceAfterLineNumber: number; - - if (whitespaceIndex === -1) { - whitespaceIndex = whitespaceCount; - currentWhitespaceAfterLineNumber = endLineNumber + 1; - currentWhitespaceHeight = 0; - } else { - currentWhitespaceAfterLineNumber = this.whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; - currentWhitespaceHeight = this.whitespaces.getHeightForWhitespaceIndex(whitespaceIndex) | 0; - } - - let currentVerticalOffset = startLineNumberVerticalOffset; - let currentLineRelativeOffset = currentVerticalOffset; - - // IE (all versions) cannot handle units above about 1,533,908 px, so every 500k pixels bring numbers down - const STEP_SIZE = 500000; - let bigNumbersDelta = 0; - if (startLineNumberVerticalOffset >= STEP_SIZE) { - // Compute a delta that guarantees that lines are positioned at `lineHeight` increments - bigNumbersDelta = Math.floor(startLineNumberVerticalOffset / STEP_SIZE) * STEP_SIZE; - bigNumbersDelta = Math.floor(bigNumbersDelta / deviceLineHeight) * deviceLineHeight; - - currentLineRelativeOffset -= bigNumbersDelta; - } - - let linesOffsets: number[] = []; - - let verticalCenter = verticalOffset1 + (verticalOffset2 - verticalOffset1) / 2; - let centeredLineNumber = -1; - - // Figure out how far the lines go - for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { - - if (centeredLineNumber === -1) { - let currentLineTop = currentVerticalOffset; - let currentLineBottom = currentVerticalOffset + deviceLineHeight; - if ((currentLineTop <= verticalCenter && verticalCenter < currentLineBottom) || currentLineTop > verticalCenter) { - centeredLineNumber = lineNumber; - } - } - - // Count current line height in the vertical offsets - currentVerticalOffset += deviceLineHeight; - linesOffsets[lineNumber - startLineNumber] = currentLineRelativeOffset; - - // Next line starts immediately after this one - currentLineRelativeOffset += deviceLineHeight; - while (currentWhitespaceAfterLineNumber === lineNumber) { - // Push down next line with the height of the current whitespace - currentLineRelativeOffset += currentWhitespaceHeight; - - // Count current whitespace in the vertical offsets - currentVerticalOffset += currentWhitespaceHeight; - whitespaceIndex++; - - if (whitespaceIndex >= whitespaceCount) { - currentWhitespaceAfterLineNumber = endLineNumber + 1; - } else { - currentWhitespaceAfterLineNumber = this.whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0; - currentWhitespaceHeight = this.whitespaces.getHeightForWhitespaceIndex(whitespaceIndex) | 0; - } - } - - if (currentVerticalOffset >= verticalOffset2) { - // We have covered the entire viewport area, time to stop - endLineNumber = lineNumber; - break; - } - } - - if (centeredLineNumber === -1) { - centeredLineNumber = endLineNumber; - } - - return { - viewportTop: verticalOffset1 - bigNumbersDelta, - viewportHeight: verticalOffset2 - verticalOffset1, - bigNumbersDelta: bigNumbersDelta, - startLineNumber: startLineNumber, - endLineNumber: endLineNumber, - visibleRangesDeltaTop: -(verticalOffset1 - bigNumbersDelta), - relativeVerticalOffset: linesOffsets, - centeredLineNumber: centeredLineNumber - }; - } - - public getVerticalOffsetForWhitespaceIndex(whitespaceIndex: number, deviceLineHeight: number): number { - whitespaceIndex = whitespaceIndex | 0; - deviceLineHeight = deviceLineHeight | 0; - - let afterLineNumber = this.whitespaces.getAfterLineNumberForWhitespaceIndex(whitespaceIndex); - - let previousLinesHeight: number; - if (afterLineNumber >= 1) { - previousLinesHeight = deviceLineHeight * afterLineNumber; - } else { - previousLinesHeight = 0; - } - - let previousWhitespacesHeight: number; - if (whitespaceIndex > 0) { - previousWhitespacesHeight = this.whitespaces.getAccumulatedHeight(whitespaceIndex - 1); - } else { - previousWhitespacesHeight = 0; - } - return previousLinesHeight + previousWhitespacesHeight; - } - - public getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number, deviceLineHeight: number): number { - verticalOffset = verticalOffset | 0; - deviceLineHeight = deviceLineHeight | 0; - - let midWhitespaceIndex: number, - minWhitespaceIndex = 0, - maxWhitespaceIndex = this.whitespaces.getCount() - 1, - midWhitespaceVerticalOffset: number, - midWhitespaceHeight: number; - - if (maxWhitespaceIndex < 0) { - return -1; - } - - // Special case: nothing to be found - let maxWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(maxWhitespaceIndex, deviceLineHeight); - let maxWhitespaceHeight = this.whitespaces.getHeightForWhitespaceIndex(maxWhitespaceIndex); - if (verticalOffset >= maxWhitespaceVerticalOffset + maxWhitespaceHeight) { - return -1; - } - - while (minWhitespaceIndex < maxWhitespaceIndex) { - midWhitespaceIndex = Math.floor((minWhitespaceIndex + maxWhitespaceIndex) / 2); - - midWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(midWhitespaceIndex, deviceLineHeight); - midWhitespaceHeight = this.whitespaces.getHeightForWhitespaceIndex(midWhitespaceIndex); - - if (verticalOffset >= midWhitespaceVerticalOffset + midWhitespaceHeight) { - // vertical offset is after whitespace - minWhitespaceIndex = midWhitespaceIndex + 1; - } else if (verticalOffset >= midWhitespaceVerticalOffset) { - // Hit - return midWhitespaceIndex; - } else { - // vertical offset is before whitespace, but midWhitespaceIndex might still be what we're searching for - maxWhitespaceIndex = midWhitespaceIndex; - } - } - return minWhitespaceIndex; - } - - /** - * Get exactly the whitespace that is layouted at `verticalOffset`. - * - * @param verticalOffset The vertical offset. - * @param deviceLineHeight The height, in pixels, for one rendered line. - * @return Precisely the whitespace that is layouted at `verticaloffset` or null. - */ - public getWhitespaceAtVerticalOffset(verticalOffset: number, deviceLineHeight: number): IViewWhitespaceViewportData { - verticalOffset = verticalOffset | 0; - deviceLineHeight = deviceLineHeight | 0; - - let candidateIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset, deviceLineHeight); - - if (candidateIndex < 0) { - return null; - } - - if (candidateIndex >= this.whitespaces.getCount()) { - return null; - } - - let candidateTop = this.getVerticalOffsetForWhitespaceIndex(candidateIndex, deviceLineHeight); - - if (candidateTop > verticalOffset) { - return null; - } - - let candidateHeight = this.whitespaces.getHeightForWhitespaceIndex(candidateIndex); - let candidateId = this.whitespaces.getIdForWhitespaceIndex(candidateIndex); - let candidateAfterLineNumber = this.whitespaces.getAfterLineNumberForWhitespaceIndex(candidateIndex); - - return { - id: candidateId, - afterLineNumber: candidateAfterLineNumber, - verticalOffset: candidateTop, - height: candidateHeight - }; - } - - /** - * Get a list of whitespaces that are positioned between `verticalOffset1` and `verticalOffset2`. - * - * @param verticalOffset1 The beginning of the viewport. - * @param verticalOffset2 The end of the viewport. - * @param deviceLineHeight The height, in pixels, for one rendered line. - * @return An array with all the whitespaces in the viewport. If no whitespace is in viewport, the array is empty. - */ - public getWhitespaceViewportData(verticalOffset1: number, verticalOffset2: number, deviceLineHeight: number): IViewWhitespaceViewportData[] { - verticalOffset1 = verticalOffset1 | 0; - verticalOffset2 = verticalOffset2 | 0; - deviceLineHeight = deviceLineHeight | 0; - - let startIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset1, deviceLineHeight); - let endIndex = this.whitespaces.getCount() - 1; - - if (startIndex < 0) { - return []; - } - - let result: IViewWhitespaceViewportData[] = [], - i: number, - top: number, - height: number; - - for (i = startIndex; i <= endIndex; i++) { - top = this.getVerticalOffsetForWhitespaceIndex(i, deviceLineHeight); - height = this.whitespaces.getHeightForWhitespaceIndex(i); - if (top >= verticalOffset2) { - break; - } - - result.push({ - id: this.whitespaces.getIdForWhitespaceIndex(i), - afterLineNumber: this.whitespaces.getAfterLineNumberForWhitespaceIndex(i), - verticalOffset: top, - height: height - }); - } - - return result; - } - - public getWhitespaces(deviceLineHeight: number): IEditorWhitespace[] { - return this.whitespaces.getWhitespaces(deviceLineHeight); - } -} \ No newline at end of file diff --git a/src/vs/editor/common/viewLayout/whitespaceComputer.ts b/src/vs/editor/common/viewLayout/whitespaceComputer.ts index 218b7bb2b2d..4216b2b69d5 100644 --- a/src/vs/editor/common/viewLayout/whitespaceComputer.ts +++ b/src/vs/editor/common/viewLayout/whitespaceComputer.ts @@ -15,54 +15,54 @@ export class WhitespaceComputer { /** * heights[i] is the height in pixels for whitespace at index i */ - private heights: number[]; + private _heights: number[]; /** * afterLineNumbers[i] is the line number whitespace at index i is after */ - private afterLineNumbers: number[]; + private _afterLineNumbers: number[]; /** * ordinals[i] is the orinal of the whitespace at index i */ - private ordinals: number[]; + private _ordinals: number[]; /** * prefixSum[i] = SUM(heights[j]), 1 <= j <= i */ - private prefixSum: number[]; + private _prefixSum: number[]; /** * prefixSum[i], 1 <= i <= prefixSumValidIndex can be trusted */ - private prefixSumValidIndex: number; + private _prefixSumValidIndex: number; /** * ids[i] is the whitespace id of whitespace at index i */ - private ids: number[]; + private _ids: number[]; /** * index at which a whitespace is positioned (inside heights, afterLineNumbers, prefixSum members) */ - private whitespaceId2Index: { + private _whitespaceId2Index: { [id: string]: number; }; /** * last whitespace id issued */ - private lastWhitespaceId: number; + private _lastWhitespaceId: number; constructor() { - this.heights = []; - this.ids = []; - this.afterLineNumbers = []; - this.ordinals = []; - this.prefixSum = []; - this.prefixSumValidIndex = -1; - this.whitespaceId2Index = {}; - this.lastWhitespaceId = 0; + this._heights = []; + this._ids = []; + this._afterLineNumbers = []; + this._ordinals = []; + this._prefixSum = []; + this._prefixSumValidIndex = -1; + this._whitespaceId2Index = {}; + this._lastWhitespaceId = 0; } /** @@ -70,12 +70,11 @@ export class WhitespaceComputer { * If the value is already present in the sorted array, the insertion index will be after the already existing value. */ public static findInsertionIndex(sortedArray: number[], value: number, ordinals: number[], valueOrdinal: number): number { - var low = 0, - high = sortedArray.length, - mid: number; + let low = 0; + let high = sortedArray.length; while (low < high) { - mid = ((low + high) >>> 1); + let mid = ((low + high) >>> 1); if (value === sortedArray[mid]) { if (valueOrdinal < ordinals[mid]) { @@ -107,38 +106,41 @@ export class WhitespaceComputer { ordinal = ordinal | 0; heightInPx = heightInPx | 0; - var id = (++this.lastWhitespaceId); - var insertionIndex = WhitespaceComputer.findInsertionIndex(this.afterLineNumbers, afterLineNumber, this.ordinals, ordinal); - this.insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx); + let id = (++this._lastWhitespaceId); + let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal); + this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx); return id; } - private insertWhitespaceAtIndex(id: number, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number): void { + private _insertWhitespaceAtIndex(id: number, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number): void { id = id | 0; insertIndex = insertIndex | 0; afterLineNumber = afterLineNumber | 0; ordinal = ordinal | 0; heightInPx = heightInPx | 0; - this.heights.splice(insertIndex, 0, heightInPx); - this.ids.splice(insertIndex, 0, id); - this.afterLineNumbers.splice(insertIndex, 0, afterLineNumber); - this.ordinals.splice(insertIndex, 0, ordinal); - this.prefixSum.splice(insertIndex, 0, 0); + this._heights.splice(insertIndex, 0, heightInPx); + this._ids.splice(insertIndex, 0, id); + this._afterLineNumbers.splice(insertIndex, 0, afterLineNumber); + this._ordinals.splice(insertIndex, 0, ordinal); + this._prefixSum.splice(insertIndex, 0, 0); - let keys = Object.keys(this.whitespaceId2Index); + let keys = Object.keys(this._whitespaceId2Index); for (let i = 0, len = keys.length; i < len; i++) { let sid = keys[i]; - let oldIndex = this.whitespaceId2Index[sid]; + let oldIndex = this._whitespaceId2Index[sid]; if (oldIndex >= insertIndex) { - this.whitespaceId2Index[sid] = oldIndex + 1; + this._whitespaceId2Index[sid] = oldIndex + 1; } } - this.whitespaceId2Index[id.toString()] = insertIndex; - this.prefixSumValidIndex = Math.min(this.prefixSumValidIndex, insertIndex - 1); + this._whitespaceId2Index[id.toString()] = insertIndex; + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1); } + /** + * Change properties associated with a certain whitespace. + */ public changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean { id = id | 0; newAfterLineNumber = newAfterLineNumber | 0; @@ -161,12 +163,12 @@ export class WhitespaceComputer { id = id | 0; newHeightInPx = newHeightInPx | 0; - var sid = id.toString(); - if (this.whitespaceId2Index.hasOwnProperty(sid)) { - var index = this.whitespaceId2Index[sid]; - if (this.heights[index] !== newHeightInPx) { - this.heights[index] = newHeightInPx; - this.prefixSumValidIndex = Math.min(this.prefixSumValidIndex, index - 1); + let sid = id.toString(); + if (this._whitespaceId2Index.hasOwnProperty(sid)) { + let index = this._whitespaceId2Index[sid]; + if (this._heights[index] !== newHeightInPx) { + this._heights[index] = newHeightInPx; + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1); return true; } } @@ -184,24 +186,24 @@ export class WhitespaceComputer { id = id | 0; newAfterLineNumber = newAfterLineNumber | 0; - var sid = id.toString(); - if (this.whitespaceId2Index.hasOwnProperty(sid)) { - var index = this.whitespaceId2Index[sid]; - if (this.afterLineNumbers[index] !== newAfterLineNumber) { + let sid = id.toString(); + if (this._whitespaceId2Index.hasOwnProperty(sid)) { + let index = this._whitespaceId2Index[sid]; + if (this._afterLineNumbers[index] !== newAfterLineNumber) { // `afterLineNumber` changed for this whitespace // Record old ordinal - var ordinal = this.ordinals[index]; + let ordinal = this._ordinals[index]; // Record old height - var heightInPx = this.heights[index]; + let heightInPx = this._heights[index]; // Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace this.removeWhitespace(id); // And add it again - var insertionIndex = WhitespaceComputer.findInsertionIndex(this.afterLineNumbers, newAfterLineNumber, this.ordinals, ordinal); - this.insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx); + let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal); + this._insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx); return true; } @@ -218,34 +220,34 @@ export class WhitespaceComputer { public removeWhitespace(id: number): boolean { id = id | 0; - var sid = id.toString(); + let sid = id.toString(); - if (this.whitespaceId2Index.hasOwnProperty(sid)) { - var index = this.whitespaceId2Index[sid]; - delete this.whitespaceId2Index[sid]; - this.removeWhitespaceAtIndex(index); + if (this._whitespaceId2Index.hasOwnProperty(sid)) { + let index = this._whitespaceId2Index[sid]; + delete this._whitespaceId2Index[sid]; + this._removeWhitespaceAtIndex(index); return true; } return false; } - private removeWhitespaceAtIndex(removeIndex: number): void { + private _removeWhitespaceAtIndex(removeIndex: number): void { removeIndex = removeIndex | 0; - this.heights.splice(removeIndex, 1); - this.ids.splice(removeIndex, 1); - this.afterLineNumbers.splice(removeIndex, 1); - this.ordinals.splice(removeIndex, 1); - this.prefixSum.splice(removeIndex, 1); - this.prefixSumValidIndex = Math.min(this.prefixSumValidIndex, removeIndex - 1); + this._heights.splice(removeIndex, 1); + this._ids.splice(removeIndex, 1); + this._afterLineNumbers.splice(removeIndex, 1); + this._ordinals.splice(removeIndex, 1); + this._prefixSum.splice(removeIndex, 1); + this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1); - let keys = Object.keys(this.whitespaceId2Index); + let keys = Object.keys(this._whitespaceId2Index); for (let i = 0, len = keys.length; i < len; i++) { let sid = keys[i]; - let oldIndex = this.whitespaceId2Index[sid]; + let oldIndex = this._whitespaceId2Index[sid]; if (oldIndex >= removeIndex) { - this.whitespaceId2Index[sid] = oldIndex - 1; + this._whitespaceId2Index[sid] = oldIndex - 1; } } } @@ -261,21 +263,17 @@ export class WhitespaceComputer { fromLineNumber = fromLineNumber | 0; toLineNumber = toLineNumber | 0; - var afterLineNumber: number, - i: number, - len: number; - - for (i = 0, len = this.afterLineNumbers.length; i < len; i++) { - afterLineNumber = this.afterLineNumbers[i]; + for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { + let afterLineNumber = this._afterLineNumbers[i]; if (fromLineNumber <= afterLineNumber && afterLineNumber <= toLineNumber) { // The line this whitespace was after has been deleted // => move whitespace to before first deleted line - this.afterLineNumbers[i] = fromLineNumber - 1; + this._afterLineNumbers[i] = fromLineNumber - 1; } else if (afterLineNumber > toLineNumber) { // The line this whitespace was after has been moved up // => move whitespace up - this.afterLineNumbers[i] -= (toLineNumber - fromLineNumber + 1); + this._afterLineNumbers[i] -= (toLineNumber - fromLineNumber + 1); } } } @@ -291,15 +289,11 @@ export class WhitespaceComputer { fromLineNumber = fromLineNumber | 0; toLineNumber = toLineNumber | 0; - var afterLineNumber: number, - i: number, - len: number; - - for (i = 0, len = this.afterLineNumbers.length; i < len; i++) { - afterLineNumber = this.afterLineNumbers[i]; + for (let i = 0, len = this._afterLineNumbers.length; i < len; i++) { + let afterLineNumber = this._afterLineNumbers[i]; if (fromLineNumber <= afterLineNumber) { - this.afterLineNumbers[i] += (toLineNumber - fromLineNumber + 1); + this._afterLineNumbers[i] += (toLineNumber - fromLineNumber + 1); } } } @@ -308,10 +302,10 @@ export class WhitespaceComputer { * Get the sum of all the whitespaces. */ public getTotalHeight(): number { - if (this.heights.length === 0) { + if (this._heights.length === 0) { return 0; } - return this.getAccumulatedHeight(this.heights.length - 1); + return this.getAccumulatedHeight(this._heights.length - 1); } /** @@ -324,17 +318,17 @@ export class WhitespaceComputer { public getAccumulatedHeight(index: number): number { index = index | 0; - var startIndex = Math.max(0, this.prefixSumValidIndex + 1); + let startIndex = Math.max(0, this._prefixSumValidIndex + 1); if (startIndex === 0) { - this.prefixSum[0] = this.heights[0]; + this._prefixSum[0] = this._heights[0]; startIndex++; } - for (var i = startIndex; i <= index; i++) { - this.prefixSum[i] = this.prefixSum[i - 1] + this.heights[i]; + for (let i = startIndex; i <= index; i++) { + this._prefixSum[i] = this._prefixSum[i - 1] + this._heights[i]; } - this.prefixSumValidIndex = Math.max(this.prefixSumValidIndex, index); - return this.prefixSum[index]; + this._prefixSumValidIndex = Math.max(this._prefixSumValidIndex, index); + return this._prefixSum[index]; } /** @@ -346,7 +340,7 @@ export class WhitespaceComputer { public getAccumulatedHeightBeforeLineNumber(lineNumber: number): number { lineNumber = lineNumber | 0; - var lastWhitespaceBeforeLineNumber = this.findLastWhitespaceBeforeLineNumber(lineNumber); + let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); if (lastWhitespaceBeforeLineNumber === -1) { return 0; @@ -355,11 +349,11 @@ export class WhitespaceComputer { return this.getAccumulatedHeight(lastWhitespaceBeforeLineNumber); } - private findLastWhitespaceBeforeLineNumber(lineNumber: number): number { + private _findLastWhitespaceBeforeLineNumber(lineNumber: number): number { lineNumber = lineNumber | 0; // Find the whitespace before line number - let afterLineNumbers = this.afterLineNumbers; + let afterLineNumbers = this._afterLineNumbers; let low = 0; let high = afterLineNumbers.length - 1; @@ -382,13 +376,13 @@ export class WhitespaceComputer { return -1; } - private findFirstWhitespaceAfterLineNumber(lineNumber: number): number { + private _findFirstWhitespaceAfterLineNumber(lineNumber: number): number { lineNumber = lineNumber | 0; - var lastWhitespaceBeforeLineNumber = this.findLastWhitespaceBeforeLineNumber(lineNumber); - var firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1; + let lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber); + let firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1; - if (firstWhitespaceAfterLineNumber < this.heights.length) { + if (firstWhitespaceAfterLineNumber < this._heights.length) { return firstWhitespaceAfterLineNumber; } @@ -402,14 +396,14 @@ export class WhitespaceComputer { public getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number { lineNumber = lineNumber | 0; - return this.findFirstWhitespaceAfterLineNumber(lineNumber); + return this._findFirstWhitespaceAfterLineNumber(lineNumber); } /** * The number of whitespaces. */ public getCount(): number { - return this.heights.length; + return this._heights.length; } /** @@ -421,7 +415,7 @@ export class WhitespaceComputer { public getAfterLineNumberForWhitespaceIndex(index: number): number { index = index | 0; - return this.afterLineNumbers[index]; + return this._afterLineNumbers[index]; } /** @@ -433,7 +427,7 @@ export class WhitespaceComputer { public getIdForWhitespaceIndex(index: number): number { index = index | 0; - return this.ids[index]; + return this._ids[index]; } /** @@ -445,20 +439,23 @@ export class WhitespaceComputer { public getHeightForWhitespaceIndex(index: number): number { index = index | 0; - return this.heights[index]; + return this._heights[index]; } + /** + * Get all whitespaces. + */ public getWhitespaces(deviceLineHeight: number): IEditorWhitespace[] { deviceLineHeight = deviceLineHeight | 0; - var result: IEditorWhitespace[] = []; - for (var i = 0; i < this.heights.length; i++) { + let result: IEditorWhitespace[] = []; + for (let i = 0; i < this._heights.length; i++) { result.push({ - id: this.ids[i], - afterLineNumber: this.afterLineNumbers[i], - heightInLines: this.heights[i] / deviceLineHeight + id: this._ids[i], + afterLineNumber: this._afterLineNumbers[i], + heightInLines: this._heights[i] / deviceLineHeight }); } return result; } -} \ No newline at end of file +} diff --git a/src/vs/editor/test/common/viewLayout/linesLayout.test.ts b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts new file mode 100644 index 00000000000..0f0a556eb4e --- /dev/null +++ b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts @@ -0,0 +1,579 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as assert from 'assert'; +import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout'; + +suite('Editor ViewLayout - LinesLayout', () => { + + test('LinesLayout 1', () => { + + // Start off with 10 lines + var linesLayout = new LinesLayout(10, 10); + + // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + // whitespace: - + assert.equal(linesLayout.getLinesTotalHeight(), 100); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 30); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 40); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 50); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 60); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 70); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 80); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 90); + + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(5), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(11), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(15), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(19), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(21), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(29), 3); + + // Add whitespace of height 5px after 2nd line + linesLayout.insertWhitespace(2, 0, 5); + // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + // whitespace: a(2,5) + assert.equal(linesLayout.getLinesTotalHeight(), 105); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 25); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 35); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 45); + + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(21), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(24), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(25), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(35), 4); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(45), 5); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(104), 10); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(105), 10); + + // Add two more whitespaces of height 5px + linesLayout.insertWhitespace(3, 0, 5); + linesLayout.insertWhitespace(4, 0, 5); + // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + // whitespace: a(2,5), b(3, 5), c(4, 5) + assert.equal(linesLayout.getLinesTotalHeight(), 115); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 25); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 40); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 55); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 65); + + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(19), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(34), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(35), 4); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(49), 4); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(50), 5); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(64), 5); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(65), 6); + + assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(0), 20); // 20 -> 25 + assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(1), 35); // 35 -> 40 + assert.equal(linesLayout.getVerticalOffsetForWhitespaceIndex(2), 50); + + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(0), 0); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(19), 0); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(20), 0); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(21), 0); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(22), 0); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(23), 0); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(24), 0); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(25), 1); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(26), 1); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(34), 1); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(35), 1); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(36), 1); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(39), 1); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(40), 2); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(41), 2); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(49), 2); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(50), 2); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(51), 2); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(54), 2); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(55), -1); + assert.equal(linesLayout.getWhitespaceIndexAtOrAfterVerticallOffset(1000), -1); + + }); + + test('LinesLayout 2', () => { + + // Start off with 10 lines and one whitespace after line 2, of height 5 + var linesLayout = new LinesLayout(10, 1); + var a = linesLayout.insertWhitespace(2, 0, 5); + + // 10 lines + // whitespace: - a(2,5) + assert.equal(linesLayout.getLinesTotalHeight(), 15); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 7); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 8); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 9); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 10); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 11); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 12); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 13); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 14); + + // Change whitespace height + // 10 lines + // whitespace: - a(2,10) + linesLayout.changeWhitespace(a, 2, 10); + assert.equal(linesLayout.getLinesTotalHeight(), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 12); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 13); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 14); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 15); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19); + + // Change whitespace position + // 10 lines + // whitespace: - a(5,10) + linesLayout.changeWhitespace(a, 5, 10); + assert.equal(linesLayout.getLinesTotalHeight(), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 15); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19); + + // Pretend that lines 5 and 6 were deleted + // 8 lines + // whitespace: - a(4,10) + linesLayout.onModelLinesDeleted(5, 6); + assert.equal(linesLayout.getLinesTotalHeight(), 18); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 14); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 15); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17); + + // Insert two lines at the beginning + // 10 lines + // whitespace: - a(6,10) + linesLayout.onModelLinesInserted(1, 2); + assert.equal(linesLayout.getLinesTotalHeight(), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19); + + // Remove whitespace + // 10 lines + linesLayout.removeWhitespace(a); + assert.equal(linesLayout.getLinesTotalHeight(), 10); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 6); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 7); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 8); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 9); + }); + + test('LinesLayout getLineNumberAtOrAfterVerticalOffset', () => { + var linesLayout = new LinesLayout(10, 1); + linesLayout.insertWhitespace(6, 0, 10); + + // 10 lines + // whitespace: - a(6,10) + assert.equal(linesLayout.getLinesTotalHeight(), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19); + + // Do some hit testing + // line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + // vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19] + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(-100), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(-1), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(0), 1); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(1), 2); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(2), 3); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(3), 4); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(4), 5); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(5), 6); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(6), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(7), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(8), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(9), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(10), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(11), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(12), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(13), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(14), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(15), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(16), 7); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(17), 8); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(18), 9); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(19), 10); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(20), 10); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(21), 10); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(22), 10); + assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(23), 10); + }); + + test('LinesLayout getCenteredLineInViewport', () => { + var linesLayout = new LinesLayout(10, 1); + linesLayout.insertWhitespace(6, 0, 10); + + // 10 lines + // whitespace: - a(6,10) + assert.equal(linesLayout.getLinesTotalHeight(), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 1); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 2); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 3); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 4); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 5); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 16); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 17); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 18); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 19); + + // Find centered line in viewport 1 + // line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + // vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19] + assert.equal(linesLayout.getLinesViewportData(0, 1).centeredLineNumber, 1); + assert.equal(linesLayout.getLinesViewportData(0, 2).centeredLineNumber, 2); + assert.equal(linesLayout.getLinesViewportData(0, 3).centeredLineNumber, 2); + assert.equal(linesLayout.getLinesViewportData(0, 4).centeredLineNumber, 3); + assert.equal(linesLayout.getLinesViewportData(0, 5).centeredLineNumber, 3); + assert.equal(linesLayout.getLinesViewportData(0, 6).centeredLineNumber, 4); + assert.equal(linesLayout.getLinesViewportData(0, 7).centeredLineNumber, 4); + assert.equal(linesLayout.getLinesViewportData(0, 8).centeredLineNumber, 5); + assert.equal(linesLayout.getLinesViewportData(0, 9).centeredLineNumber, 5); + assert.equal(linesLayout.getLinesViewportData(0, 10).centeredLineNumber, 6); + assert.equal(linesLayout.getLinesViewportData(0, 11).centeredLineNumber, 6); + assert.equal(linesLayout.getLinesViewportData(0, 12).centeredLineNumber, 6); + assert.equal(linesLayout.getLinesViewportData(0, 13).centeredLineNumber, 6); + assert.equal(linesLayout.getLinesViewportData(0, 14).centeredLineNumber, 6); + assert.equal(linesLayout.getLinesViewportData(0, 15).centeredLineNumber, 6); + assert.equal(linesLayout.getLinesViewportData(0, 16).centeredLineNumber, 6); + assert.equal(linesLayout.getLinesViewportData(0, 17).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 18).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 19).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 21).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 22).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 23).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 24).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 25).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 26).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 27).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 28).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 29).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 30).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 31).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 32).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(0, 33).centeredLineNumber, 7); + + // Find centered line in viewport 2 + // line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + // vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19] + assert.equal(linesLayout.getLinesViewportData(0, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(1, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(2, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(3, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(4, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(5, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(6, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(7, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(8, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(9, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(10, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(11, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(12, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(13, 20).centeredLineNumber, 7); + assert.equal(linesLayout.getLinesViewportData(14, 20).centeredLineNumber, 8); + assert.equal(linesLayout.getLinesViewportData(15, 20).centeredLineNumber, 8); + assert.equal(linesLayout.getLinesViewportData(16, 20).centeredLineNumber, 9); + assert.equal(linesLayout.getLinesViewportData(17, 20).centeredLineNumber, 9); + assert.equal(linesLayout.getLinesViewportData(18, 20).centeredLineNumber, 10); + assert.equal(linesLayout.getLinesViewportData(19, 20).centeredLineNumber, 10); + assert.equal(linesLayout.getLinesViewportData(20, 23).centeredLineNumber, 10); + assert.equal(linesLayout.getLinesViewportData(21, 23).centeredLineNumber, 10); + assert.equal(linesLayout.getLinesViewportData(22, 23).centeredLineNumber, 10); + }); + + test('LinesLayout getLinesViewportData 1', () => { + var linesLayout = new LinesLayout(10, 10); + linesLayout.insertWhitespace(6, 0, 100); + + // 10 lines + // whitespace: - a(6,100) + assert.equal(linesLayout.getLinesTotalHeight(), 200); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 30); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 40); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 50); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 160); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 170); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 180); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 190); + + // viewport 0->50 + var viewportData = linesLayout.getLinesViewportData(0, 50); + assert.equal(viewportData.startLineNumber, 1); + assert.equal(viewportData.endLineNumber, 5); + assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40]); + assert.equal(viewportData.visibleRangesDeltaTop, 0); + + // viewport 1->51 + viewportData = linesLayout.getLinesViewportData(1, 51); + assert.equal(viewportData.startLineNumber, 1); + assert.equal(viewportData.endLineNumber, 6); + assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40, 50]); + assert.equal(viewportData.visibleRangesDeltaTop, -1); + + // viewport 5->55 + viewportData = linesLayout.getLinesViewportData(5, 55); + assert.equal(viewportData.startLineNumber, 1); + assert.equal(viewportData.endLineNumber, 6); + assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40, 50]); + assert.equal(viewportData.visibleRangesDeltaTop, -5); + + // viewport 10->60 + viewportData = linesLayout.getLinesViewportData(10, 60); + assert.equal(viewportData.startLineNumber, 2); + assert.equal(viewportData.endLineNumber, 6); + assert.deepEqual(viewportData.relativeVerticalOffset, [10, 20, 30, 40, 50]); + assert.equal(viewportData.visibleRangesDeltaTop, -10); + + // viewport 50->100 + viewportData = linesLayout.getLinesViewportData(50, 100); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 6); + assert.deepEqual(viewportData.relativeVerticalOffset, [50]); + assert.equal(viewportData.visibleRangesDeltaTop, -50); + + // viewport 60->110 + viewportData = linesLayout.getLinesViewportData(60, 110); + assert.equal(viewportData.startLineNumber, 7); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [160]); + assert.equal(viewportData.visibleRangesDeltaTop, -60); + + // viewport 65->115 + viewportData = linesLayout.getLinesViewportData(65, 115); + assert.equal(viewportData.startLineNumber, 7); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [160]); + assert.equal(viewportData.visibleRangesDeltaTop, -65); + + // viewport 50->159 + viewportData = linesLayout.getLinesViewportData(50, 159); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 6); + assert.deepEqual(viewportData.relativeVerticalOffset, [50]); + assert.equal(viewportData.visibleRangesDeltaTop, -50); + + // viewport 50->160 + viewportData = linesLayout.getLinesViewportData(50, 160); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 6); + assert.deepEqual(viewportData.relativeVerticalOffset, [50]); + assert.equal(viewportData.visibleRangesDeltaTop, -50); + + // viewport 51->161 + viewportData = linesLayout.getLinesViewportData(51, 161); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]); + assert.equal(viewportData.visibleRangesDeltaTop, -51); + + + // viewport 150->169 + viewportData = linesLayout.getLinesViewportData(150, 169); + assert.equal(viewportData.startLineNumber, 7); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [160]); + assert.equal(viewportData.visibleRangesDeltaTop, -150); + + // viewport 159->169 + viewportData = linesLayout.getLinesViewportData(159, 169); + assert.equal(viewportData.startLineNumber, 7); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [160]); + assert.equal(viewportData.visibleRangesDeltaTop, -159); + + // viewport 160->169 + viewportData = linesLayout.getLinesViewportData(160, 169); + assert.equal(viewportData.startLineNumber, 7); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [160]); + assert.equal(viewportData.visibleRangesDeltaTop, -160); + + + // viewport 160->1000 + viewportData = linesLayout.getLinesViewportData(160, 1000); + assert.equal(viewportData.startLineNumber, 7); + assert.equal(viewportData.endLineNumber, 10); + assert.deepEqual(viewportData.relativeVerticalOffset, [160, 170, 180, 190]); + assert.equal(viewportData.visibleRangesDeltaTop, -160); + }); + + + test('LinesLayout getLinesViewportData 2 & getWhitespaceViewportData', () => { + var linesLayout = new LinesLayout(10, 10); + var a = linesLayout.insertWhitespace(6, 0, 100); + var b = linesLayout.insertWhitespace(7, 0, 50); + + // 10 lines + // whitespace: - a(6,100), b(7, 50) + assert.equal(linesLayout.getLinesTotalHeight(), 250); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(1), 0); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(2), 10); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(3), 20); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(4), 30); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(5), 40); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(6), 50); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(7), 160); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(8), 220); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(9), 230); + assert.equal(linesLayout.getVerticalOffsetForLineNumber(10), 240); + + // viewport 50->160 + var viewportData = linesLayout.getLinesViewportData(50, 160); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 6); + assert.deepEqual(viewportData.relativeVerticalOffset, [50]); + assert.equal(viewportData.visibleRangesDeltaTop, -50); + var whitespaceData = linesLayout.getWhitespaceViewportData(50, 160); + assert.deepEqual(whitespaceData, [{ + id: a, + afterLineNumber: 6, + verticalOffset: 60, + height: 100 + }]); + + // viewport 50->219 + viewportData = linesLayout.getLinesViewportData(50, 219); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]); + assert.equal(viewportData.visibleRangesDeltaTop, -50); + whitespaceData = linesLayout.getWhitespaceViewportData(50, 219); + assert.deepEqual(whitespaceData, [{ + id: a, + afterLineNumber: 6, + verticalOffset: 60, + height: 100 + }, { + id: b, + afterLineNumber: 7, + verticalOffset: 170, + height: 50 + }]); + + // viewport 50->220 + viewportData = linesLayout.getLinesViewportData(50, 220); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 7); + assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]); + assert.equal(viewportData.visibleRangesDeltaTop, -50); + + // viewport 50->250 + viewportData = linesLayout.getLinesViewportData(50, 250); + assert.equal(viewportData.startLineNumber, 6); + assert.equal(viewportData.endLineNumber, 10); + assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160, 220, 230, 240]); + assert.equal(viewportData.visibleRangesDeltaTop, -50); + }); + + test('LinesLayout getWhitespaceAtVerticalOffset', () => { + var linesLayout = new LinesLayout(10, 10); + var a = linesLayout.insertWhitespace(6, 0, 100); + var b = linesLayout.insertWhitespace(7, 0, 50); + + var whitespace = linesLayout.getWhitespaceAtVerticalOffset(0); + assert.equal(whitespace, null); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(59); + assert.equal(whitespace, null); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(60); + assert.equal(whitespace.id, a); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(61); + assert.equal(whitespace.id, a); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(159); + assert.equal(whitespace.id, a); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(160); + assert.equal(whitespace, null); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(161); + assert.equal(whitespace, null); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(169); + assert.equal(whitespace, null); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(170); + assert.equal(whitespace.id, b); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(171); + assert.equal(whitespace.id, b); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(219); + assert.equal(whitespace.id, b); + + whitespace = linesLayout.getWhitespaceAtVerticalOffset(220); + assert.equal(whitespace, null); + }); +}); diff --git a/src/vs/editor/test/common/viewLayout/verticalObjects.test.ts b/src/vs/editor/test/common/viewLayout/verticalObjects.test.ts deleted file mode 100644 index 27a0ffc78fd..00000000000 --- a/src/vs/editor/test/common/viewLayout/verticalObjects.test.ts +++ /dev/null @@ -1,588 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import * as assert from 'assert'; -import { VerticalObjects } from 'vs/editor/common/viewLayout/verticalObjects'; - -suite('Editor ViewLayout - VerticalObjects', () => { - - test('VerticalObjects 1', () => { - - var verticalObjects = new VerticalObjects(); - - // Start off with 10 lines - verticalObjects.replaceLines(10); - - // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - // whitespace: - - assert.equal(verticalObjects.getTotalHeight(10), 100); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 10), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 10), 10); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 10), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 10), 30); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 10), 40); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 10), 50); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 10), 60); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 10), 70); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 10), 80); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 10), 90); - - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(0, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(1, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(5, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(9, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(10, 10), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(11, 10), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(15, 10), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(19, 10), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(20, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(21, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(29, 10), 3); - - // Add whitespace of height 5px after 2nd line - verticalObjects.insertWhitespace(2, 0, 5); - // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - // whitespace: a(2,5) - assert.equal(verticalObjects.getTotalHeight(10), 105); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 10), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 10), 10); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 10), 25); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 10), 35); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 10), 45); - - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(0, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(1, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(9, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(10, 10), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(20, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(21, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(24, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(25, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(35, 10), 4); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(45, 10), 5); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(104, 10), 10); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(105, 10), 10); - - // Add two more whitespaces of height 5px - verticalObjects.insertWhitespace(3, 0, 5); - verticalObjects.insertWhitespace(4, 0, 5); - // lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - // whitespace: a(2,5), b(3, 5), c(4, 5) - assert.equal(verticalObjects.getTotalHeight(10), 115); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 10), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 10), 10); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 10), 25); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 10), 40); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 10), 55); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 10), 65); - - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(0, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(1, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(9, 10), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(10, 10), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(19, 10), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(20, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(34, 10), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(35, 10), 4); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(49, 10), 4); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(50, 10), 5); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(64, 10), 5); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(65, 10), 6); - - assert.equal(verticalObjects.getVerticalOffsetForWhitespaceIndex(0, 10), 20); // 20 -> 25 - assert.equal(verticalObjects.getVerticalOffsetForWhitespaceIndex(1, 10), 35); // 35 -> 40 - assert.equal(verticalObjects.getVerticalOffsetForWhitespaceIndex(2, 10), 50); - - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(0, 10), 0); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(19, 10), 0); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(20, 10), 0); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(21, 10), 0); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(22, 10), 0); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(23, 10), 0); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(24, 10), 0); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(25, 10), 1); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(26, 10), 1); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(34, 10), 1); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(35, 10), 1); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(36, 10), 1); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(39, 10), 1); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(40, 10), 2); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(41, 10), 2); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(49, 10), 2); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(50, 10), 2); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(51, 10), 2); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(54, 10), 2); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(55, 10), -1); - assert.equal(verticalObjects.getWhitespaceIndexAtOrAfterVerticallOffset(1000, 10), -1); - - }); - - test('VerticalObjects 2', () => { - - var verticalObjects = new VerticalObjects(); - - // Start off with 10 lines and one whitespace after line 2, of height 5 - verticalObjects.replaceLines(10); - var a = verticalObjects.insertWhitespace(2, 0, 5); - - // 10 lines - // whitespace: - a(2,5) - assert.equal(verticalObjects.getTotalHeight(1), 15); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 7); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 8); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 9); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 10); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 11); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 12); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 1), 13); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 1), 14); - - // Change whitespace height - // 10 lines - // whitespace: - a(2,10) - verticalObjects.changeWhitespace(a, 2, 10); - assert.equal(verticalObjects.getTotalHeight(1), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 12); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 13); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 14); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 15); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 16); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 17); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 1), 18); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 1), 19); - - // Change whitespace position - // 10 lines - // whitespace: - a(5,10) - verticalObjects.changeWhitespace(a, 5, 10); - assert.equal(verticalObjects.getTotalHeight(1), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 2); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 3); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 4); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 15); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 16); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 17); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 1), 18); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 1), 19); - - // Pretend that lines 5 and 6 were deleted - // 8 lines - // whitespace: - a(4,10) - verticalObjects.onModelLinesDeleted(5, 6); - assert.equal(verticalObjects.getTotalHeight(1), 18); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 2); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 3); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 14); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 15); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 16); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 17); - - // Insert two lines at the beginning - // 10 lines - // whitespace: - a(6,10) - verticalObjects.onModelLinesInserted(1, 2); - assert.equal(verticalObjects.getTotalHeight(1), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 2); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 3); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 4); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 5); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 16); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 17); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 1), 18); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 1), 19); - - // Remove whitespace - // 10 lines - verticalObjects.removeWhitespace(a); - assert.equal(verticalObjects.getTotalHeight(1), 10); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 2); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 3); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 4); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 5); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 6); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 7); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 1), 8); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 1), 9); - }); - - test('VerticalObjects getLineNumberAtOrAfterVerticalOffset', () => { - var verticalObjects = new VerticalObjects(); - verticalObjects.replaceLines(10); - verticalObjects.insertWhitespace(6, 0, 10); - - // 10 lines - // whitespace: - a(6,10) - assert.equal(verticalObjects.getTotalHeight(1), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 2); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 3); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 4); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 5); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 16); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 17); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 1), 18); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 1), 19); - - // Do some hit testing - // line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - // vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19] - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(-100, 1), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(-1, 1), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(0, 1), 1); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(1, 1), 2); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(2, 1), 3); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(3, 1), 4); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(4, 1), 5); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(5, 1), 6); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(6, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(7, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(8, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(9, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(10, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(11, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(12, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(13, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(14, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(15, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(16, 1), 7); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(17, 1), 8); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(18, 1), 9); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(19, 1), 10); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(20, 1), 10); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(21, 1), 10); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(22, 1), 10); - assert.equal(verticalObjects.getLineNumberAtOrAfterVerticalOffset(23, 1), 10); - }); - - test('VerticalObjects getCenteredLineInViewport', () => { - var verticalObjects = new VerticalObjects(); - verticalObjects.replaceLines(10); - verticalObjects.insertWhitespace(6, 0, 10); - - // 10 lines - // whitespace: - a(6,10) - assert.equal(verticalObjects.getTotalHeight(1), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 1), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 1), 1); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 1), 2); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 1), 3); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 1), 4); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 1), 5); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 1), 16); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 1), 17); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 1), 18); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 1), 19); - - // Find centered line in viewport 1 - // line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - // vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19] - assert.equal(verticalObjects.getLinesViewportData(0, 1, 1).centeredLineNumber, 1); - assert.equal(verticalObjects.getLinesViewportData(0, 2, 1).centeredLineNumber, 2); - assert.equal(verticalObjects.getLinesViewportData(0, 3, 1).centeredLineNumber, 2); - assert.equal(verticalObjects.getLinesViewportData(0, 4, 1).centeredLineNumber, 3); - assert.equal(verticalObjects.getLinesViewportData(0, 5, 1).centeredLineNumber, 3); - assert.equal(verticalObjects.getLinesViewportData(0, 6, 1).centeredLineNumber, 4); - assert.equal(verticalObjects.getLinesViewportData(0, 7, 1).centeredLineNumber, 4); - assert.equal(verticalObjects.getLinesViewportData(0, 8, 1).centeredLineNumber, 5); - assert.equal(verticalObjects.getLinesViewportData(0, 9, 1).centeredLineNumber, 5); - assert.equal(verticalObjects.getLinesViewportData(0, 10, 1).centeredLineNumber, 6); - assert.equal(verticalObjects.getLinesViewportData(0, 11, 1).centeredLineNumber, 6); - assert.equal(verticalObjects.getLinesViewportData(0, 12, 1).centeredLineNumber, 6); - assert.equal(verticalObjects.getLinesViewportData(0, 13, 1).centeredLineNumber, 6); - assert.equal(verticalObjects.getLinesViewportData(0, 14, 1).centeredLineNumber, 6); - assert.equal(verticalObjects.getLinesViewportData(0, 15, 1).centeredLineNumber, 6); - assert.equal(verticalObjects.getLinesViewportData(0, 16, 1).centeredLineNumber, 6); - assert.equal(verticalObjects.getLinesViewportData(0, 17, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 18, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 19, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 21, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 22, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 23, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 24, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 25, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 26, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 27, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 28, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 29, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 30, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 31, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 32, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(0, 33, 1).centeredLineNumber, 7); - - // Find centered line in viewport 2 - // line [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - // vertical: [0, 1, 2, 3, 4, 5, 16, 17, 18, 19] - assert.equal(verticalObjects.getLinesViewportData(0, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(1, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(2, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(3, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(4, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(5, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(6, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(7, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(8, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(9, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(10, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(11, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(12, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(13, 20, 1).centeredLineNumber, 7); - assert.equal(verticalObjects.getLinesViewportData(14, 20, 1).centeredLineNumber, 8); - assert.equal(verticalObjects.getLinesViewportData(15, 20, 1).centeredLineNumber, 8); - assert.equal(verticalObjects.getLinesViewportData(16, 20, 1).centeredLineNumber, 9); - assert.equal(verticalObjects.getLinesViewportData(17, 20, 1).centeredLineNumber, 9); - assert.equal(verticalObjects.getLinesViewportData(18, 20, 1).centeredLineNumber, 10); - assert.equal(verticalObjects.getLinesViewportData(19, 20, 1).centeredLineNumber, 10); - assert.equal(verticalObjects.getLinesViewportData(20, 23, 1).centeredLineNumber, 10); - assert.equal(verticalObjects.getLinesViewportData(21, 23, 1).centeredLineNumber, 10); - assert.equal(verticalObjects.getLinesViewportData(22, 23, 1).centeredLineNumber, 10); - }); - - test('VerticalObjects getLinesViewportData 1', () => { - var verticalObjects = new VerticalObjects(); - verticalObjects.replaceLines(10); - verticalObjects.insertWhitespace(6, 0, 100); - - // 10 lines - // whitespace: - a(6,100) - assert.equal(verticalObjects.getTotalHeight(10), 200); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 10), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 10), 10); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 10), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 10), 30); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 10), 40); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 10), 50); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 10), 160); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 10), 170); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 10), 180); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 10), 190); - - // viewport 0->50 - var viewportData = verticalObjects.getLinesViewportData(0, 50, 10); - assert.equal(viewportData.startLineNumber, 1); - assert.equal(viewportData.endLineNumber, 5); - assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40]); - assert.equal(viewportData.visibleRangesDeltaTop, 0); - - // viewport 1->51 - viewportData = verticalObjects.getLinesViewportData(1, 51, 10); - assert.equal(viewportData.startLineNumber, 1); - assert.equal(viewportData.endLineNumber, 6); - assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40, 50]); - assert.equal(viewportData.visibleRangesDeltaTop, -1); - - // viewport 5->55 - viewportData = verticalObjects.getLinesViewportData(5, 55, 10); - assert.equal(viewportData.startLineNumber, 1); - assert.equal(viewportData.endLineNumber, 6); - assert.deepEqual(viewportData.relativeVerticalOffset, [0, 10, 20, 30, 40, 50]); - assert.equal(viewportData.visibleRangesDeltaTop, -5); - - // viewport 10->60 - viewportData = verticalObjects.getLinesViewportData(10, 60, 10); - assert.equal(viewportData.startLineNumber, 2); - assert.equal(viewportData.endLineNumber, 6); - assert.deepEqual(viewportData.relativeVerticalOffset, [10, 20, 30, 40, 50]); - assert.equal(viewportData.visibleRangesDeltaTop, -10); - - // viewport 50->100 - viewportData = verticalObjects.getLinesViewportData(50, 100, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 6); - assert.deepEqual(viewportData.relativeVerticalOffset, [50]); - assert.equal(viewportData.visibleRangesDeltaTop, -50); - - // viewport 60->110 - viewportData = verticalObjects.getLinesViewportData(60, 110, 10); - assert.equal(viewportData.startLineNumber, 7); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [160]); - assert.equal(viewportData.visibleRangesDeltaTop, -60); - - // viewport 65->115 - viewportData = verticalObjects.getLinesViewportData(65, 115, 10); - assert.equal(viewportData.startLineNumber, 7); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [160]); - assert.equal(viewportData.visibleRangesDeltaTop, -65); - - // viewport 50->159 - viewportData = verticalObjects.getLinesViewportData(50, 159, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 6); - assert.deepEqual(viewportData.relativeVerticalOffset, [50]); - assert.equal(viewportData.visibleRangesDeltaTop, -50); - - // viewport 50->160 - viewportData = verticalObjects.getLinesViewportData(50, 160, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 6); - assert.deepEqual(viewportData.relativeVerticalOffset, [50]); - assert.equal(viewportData.visibleRangesDeltaTop, -50); - - // viewport 51->161 - viewportData = verticalObjects.getLinesViewportData(51, 161, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]); - assert.equal(viewportData.visibleRangesDeltaTop, -51); - - - // viewport 150->169 - viewportData = verticalObjects.getLinesViewportData(150, 169, 10); - assert.equal(viewportData.startLineNumber, 7); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [160]); - assert.equal(viewportData.visibleRangesDeltaTop, -150); - - // viewport 159->169 - viewportData = verticalObjects.getLinesViewportData(159, 169, 10); - assert.equal(viewportData.startLineNumber, 7); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [160]); - assert.equal(viewportData.visibleRangesDeltaTop, -159); - - // viewport 160->169 - viewportData = verticalObjects.getLinesViewportData(160, 169, 10); - assert.equal(viewportData.startLineNumber, 7); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [160]); - assert.equal(viewportData.visibleRangesDeltaTop, -160); - - - // viewport 160->1000 - viewportData = verticalObjects.getLinesViewportData(160, 1000, 10); - assert.equal(viewportData.startLineNumber, 7); - assert.equal(viewportData.endLineNumber, 10); - assert.deepEqual(viewportData.relativeVerticalOffset, [160, 170, 180, 190]); - assert.equal(viewportData.visibleRangesDeltaTop, -160); - }); - - - test('VerticalObjects getLinesViewportData 2 & getWhitespaceViewportData', () => { - var verticalObjects = new VerticalObjects(); - verticalObjects.replaceLines(10); - var a = verticalObjects.insertWhitespace(6, 0, 100); - var b = verticalObjects.insertWhitespace(7, 0, 50); - - // 10 lines - // whitespace: - a(6,100), b(7, 50) - assert.equal(verticalObjects.getTotalHeight(10), 250); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(1, 10), 0); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(2, 10), 10); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(3, 10), 20); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(4, 10), 30); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(5, 10), 40); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(6, 10), 50); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(7, 10), 160); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(8, 10), 220); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(9, 10), 230); - assert.equal(verticalObjects.getVerticalOffsetForLineNumber(10, 10), 240); - - // viewport 50->160 - var viewportData = verticalObjects.getLinesViewportData(50, 160, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 6); - assert.deepEqual(viewportData.relativeVerticalOffset, [50]); - assert.equal(viewportData.visibleRangesDeltaTop, -50); - var whitespaceData = verticalObjects.getWhitespaceViewportData(50, 160, 10); - assert.deepEqual(whitespaceData, [{ - id: a, - afterLineNumber: 6, - verticalOffset: 60, - height: 100 - }]); - - // viewport 50->219 - viewportData = verticalObjects.getLinesViewportData(50, 219, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]); - assert.equal(viewportData.visibleRangesDeltaTop, -50); - whitespaceData = verticalObjects.getWhitespaceViewportData(50, 219, 10); - assert.deepEqual(whitespaceData, [{ - id: a, - afterLineNumber: 6, - verticalOffset: 60, - height: 100 - }, { - id: b, - afterLineNumber: 7, - verticalOffset: 170, - height: 50 - }]); - - // viewport 50->220 - viewportData = verticalObjects.getLinesViewportData(50, 220, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 7); - assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160]); - assert.equal(viewportData.visibleRangesDeltaTop, -50); - - // viewport 50->250 - viewportData = verticalObjects.getLinesViewportData(50, 250, 10); - assert.equal(viewportData.startLineNumber, 6); - assert.equal(viewportData.endLineNumber, 10); - assert.deepEqual(viewportData.relativeVerticalOffset, [50, 160, 220, 230, 240]); - assert.equal(viewportData.visibleRangesDeltaTop, -50); - }); - - test('VerticalObjects getWhitespaceAtVerticalOffset', () => { - var verticalObjects = new VerticalObjects(); - verticalObjects.replaceLines(10); - var a = verticalObjects.insertWhitespace(6, 0, 100); - var b = verticalObjects.insertWhitespace(7, 0, 50); - - var whitespace = verticalObjects.getWhitespaceAtVerticalOffset(0, 10); - assert.equal(whitespace, null); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(59, 10); - assert.equal(whitespace, null); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(60, 10); - assert.equal(whitespace.id, a); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(61, 10); - assert.equal(whitespace.id, a); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(159, 10); - assert.equal(whitespace.id, a); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(160, 10); - assert.equal(whitespace, null); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(161, 10); - assert.equal(whitespace, null); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(169, 10); - assert.equal(whitespace, null); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(170, 10); - assert.equal(whitespace.id, b); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(171, 10); - assert.equal(whitespace.id, b); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(219, 10); - assert.equal(whitespace.id, b); - - whitespace = verticalObjects.getWhitespaceAtVerticalOffset(220, 10); - assert.equal(whitespace, null); - }); -}); -- GitLab