mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-06 05:38:13 +01:00
Extract RangeUtil to its own file
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 {HorizontalRange} from 'vs/editor/common/editorCommon';
|
||||
|
||||
export class RangeUtil {
|
||||
|
||||
/**
|
||||
* Reusing the same range here
|
||||
* because IE is buggy and constantly freezes when using a large number
|
||||
* of ranges and calling .detach on them
|
||||
*/
|
||||
private static _handyReadyRange:Range;
|
||||
|
||||
private static _createRange(): Range {
|
||||
if (!this._handyReadyRange) {
|
||||
this._handyReadyRange = document.createRange();
|
||||
}
|
||||
return this._handyReadyRange;
|
||||
}
|
||||
|
||||
private static _detachRange(range:Range, endNode:HTMLElement): void {
|
||||
// Move range out of the span node, IE doesn't like having many ranges in
|
||||
// the same spot and will act badly for lines containing dashes ('-')
|
||||
range.selectNodeContents(endNode);
|
||||
}
|
||||
|
||||
private static _readClientRects(startElement:Node, startOffset:number, endElement:Node, endOffset:number, endNode:HTMLElement): ClientRectList {
|
||||
let range = this._createRange();
|
||||
try {
|
||||
range.setStart(startElement, startOffset);
|
||||
range.setEnd(endElement, endOffset);
|
||||
|
||||
return range.getClientRects();
|
||||
} catch (e) {
|
||||
// This is life ...
|
||||
return null;
|
||||
} finally {
|
||||
this._detachRange(range, endNode);
|
||||
}
|
||||
}
|
||||
|
||||
private static _createHorizontalRangesFromClientRects(clientRects:ClientRectList, clientRectDeltaLeft:number, scaleRatio:number): HorizontalRange[] {
|
||||
if (!clientRects || clientRects.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let result:HorizontalRange[] = [];
|
||||
let prevLeft = Math.max(0, clientRects[0].left * scaleRatio - clientRectDeltaLeft);
|
||||
let prevWidth = clientRects[0].width * scaleRatio;
|
||||
|
||||
for (let i = 1, len = clientRects.length; i < len; i++) {
|
||||
let myLeft = Math.max(0, clientRects[i].left * scaleRatio - clientRectDeltaLeft);
|
||||
let myWidth = clientRects[i].width * scaleRatio;
|
||||
|
||||
if (myLeft < prevLeft) {
|
||||
console.error('Unexpected: RangeUtil._createHorizontalRangesFromClientRects: client rects are not sorted');
|
||||
}
|
||||
|
||||
if (prevLeft + prevWidth + 0.9 /* account for browser's rounding errors*/ >= myLeft) {
|
||||
prevWidth = Math.max(prevWidth, myLeft + myWidth - prevLeft);
|
||||
} else {
|
||||
result.push(new HorizontalRange(prevLeft, prevWidth));
|
||||
prevLeft = myLeft;
|
||||
prevWidth = myWidth;
|
||||
}
|
||||
}
|
||||
|
||||
result.push(new HorizontalRange(prevLeft, prevWidth));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static readHorizontalRanges(domNode:HTMLElement, startChildIndex:number, startOffset:number, endChildIndex:number, endOffset:number, clientRectDeltaLeft:number, scaleRatio:number, endNode:HTMLElement): HorizontalRange[] {
|
||||
// Panic check
|
||||
let min = 0;
|
||||
let max = domNode.children.length - 1;
|
||||
if (min > max) {
|
||||
return null;
|
||||
}
|
||||
startChildIndex = Math.min(max, Math.max(min, startChildIndex));
|
||||
endChildIndex = Math.min(max, Math.max(min, endChildIndex));
|
||||
|
||||
// If crossing over to a span only to select offset 0, then use the previous span's maximum offset
|
||||
// Chrome is buggy and doesn't handle 0 offsets well sometimes.
|
||||
if (startChildIndex !== endChildIndex) {
|
||||
if (endChildIndex > 0 && endOffset === 0) {
|
||||
endChildIndex--;
|
||||
endOffset = Number.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
let startElement = domNode.children[startChildIndex].firstChild;
|
||||
let endElement = domNode.children[endChildIndex].firstChild;
|
||||
|
||||
if (!startElement || !endElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
startOffset = Math.min(startElement.textContent.length, Math.max(0, startOffset));
|
||||
endOffset = Math.min(endElement.textContent.length, Math.max(0, endOffset));
|
||||
|
||||
let clientRects = this._readClientRects(startElement, startOffset, endElement, endOffset, endNode);
|
||||
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft, scaleRatio);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import {ILineParts, createLineParts} from 'vs/editor/common/viewLayout/viewLineP
|
||||
import {renderLine, RenderLineInput} from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||
import {ClassNames, IViewContext} from 'vs/editor/browser/editorBrowser';
|
||||
import {IVisibleLineData} from 'vs/editor/browser/view/viewLayer';
|
||||
import {RangeUtil} from 'vs/editor/browser/viewParts/lines/rangeUtil';
|
||||
|
||||
export class ViewLine implements IVisibleLineData {
|
||||
|
||||
@@ -412,107 +413,6 @@ class WebKitViewLine extends ViewLine {
|
||||
}
|
||||
}
|
||||
|
||||
class RangeUtil {
|
||||
|
||||
/**
|
||||
* Reusing the same range here
|
||||
* because IE is buggy and constantly freezes when using a large number
|
||||
* of ranges and calling .detach on them
|
||||
*/
|
||||
private static _handyReadyRange:Range;
|
||||
|
||||
private static _createRange(): Range {
|
||||
if (!this._handyReadyRange) {
|
||||
this._handyReadyRange = document.createRange();
|
||||
}
|
||||
return this._handyReadyRange;
|
||||
}
|
||||
|
||||
private static _detachRange(range:Range, endNode:HTMLElement): void {
|
||||
// Move range out of the span node, IE doesn't like having many ranges in
|
||||
// the same spot and will act badly for lines containing dashes ('-')
|
||||
range.selectNodeContents(endNode);
|
||||
}
|
||||
|
||||
private static _readClientRects(startElement:Node, startOffset:number, endElement:Node, endOffset:number, endNode:HTMLElement): ClientRectList {
|
||||
let range = this._createRange();
|
||||
try {
|
||||
range.setStart(startElement, startOffset);
|
||||
range.setEnd(endElement, endOffset);
|
||||
|
||||
return range.getClientRects();
|
||||
} catch (e) {
|
||||
// This is life ...
|
||||
return null;
|
||||
} finally {
|
||||
this._detachRange(range, endNode);
|
||||
}
|
||||
}
|
||||
|
||||
private static _createHorizontalRangesFromClientRects(clientRects:ClientRectList, clientRectDeltaLeft:number, scaleRatio:number): HorizontalRange[] {
|
||||
if (!clientRects || clientRects.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let result:HorizontalRange[] = [];
|
||||
let prevLeft = Math.max(0, clientRects[0].left * scaleRatio - clientRectDeltaLeft);
|
||||
let prevWidth = clientRects[0].width * scaleRatio;
|
||||
|
||||
for (let i = 1, len = clientRects.length; i < len; i++) {
|
||||
let myLeft = Math.max(0, clientRects[i].left * scaleRatio - clientRectDeltaLeft);
|
||||
let myWidth = clientRects[i].width * scaleRatio;
|
||||
|
||||
if (myLeft < prevLeft) {
|
||||
console.error('Unexpected: RangeUtil._createHorizontalRangesFromClientRects: client rects are not sorted');
|
||||
}
|
||||
|
||||
if (prevLeft + prevWidth + 0.9 /* account for browser's rounding errors*/ >= myLeft) {
|
||||
prevWidth = Math.max(prevWidth, myLeft + myWidth - prevLeft);
|
||||
} else {
|
||||
result.push(new HorizontalRange(prevLeft, prevWidth));
|
||||
prevLeft = myLeft;
|
||||
prevWidth = myWidth;
|
||||
}
|
||||
}
|
||||
|
||||
result.push(new HorizontalRange(prevLeft, prevWidth));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static readHorizontalRanges(domNode:HTMLElement, startChildIndex:number, startOffset:number, endChildIndex:number, endOffset:number, clientRectDeltaLeft:number, scaleRatio:number, endNode:HTMLElement): HorizontalRange[] {
|
||||
// Panic check
|
||||
let min = 0;
|
||||
let max = domNode.children.length - 1;
|
||||
if (min > max) {
|
||||
return null;
|
||||
}
|
||||
startChildIndex = Math.min(max, Math.max(min, startChildIndex));
|
||||
endChildIndex = Math.min(max, Math.max(min, endChildIndex));
|
||||
|
||||
// If crossing over to a span only to select offset 0, then use the previous span's maximum offset
|
||||
// Chrome is buggy and doesn't handle 0 offsets well sometimes.
|
||||
if (startChildIndex !== endChildIndex) {
|
||||
if (endChildIndex > 0 && endOffset === 0) {
|
||||
endChildIndex--;
|
||||
endOffset = Number.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
let startElement = domNode.children[startChildIndex].firstChild;
|
||||
let endElement = domNode.children[endChildIndex].firstChild;
|
||||
|
||||
if (!startElement || !endElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
startOffset = Math.min(startElement.textContent.length, Math.max(0, startOffset));
|
||||
endOffset = Math.min(endElement.textContent.length, Math.max(0, endOffset));
|
||||
|
||||
let clientRects = this._readClientRects(startElement, startOffset, endElement, endOffset, endNode);
|
||||
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft, scaleRatio);
|
||||
}
|
||||
}
|
||||
|
||||
function findIndexInArrayWithMax(lineParts:ILineParts, desiredIndex: number, maxResult:number): number {
|
||||
let r = lineParts.findIndexOfOffset(desiredIndex);
|
||||
|
||||
Reference in New Issue
Block a user