Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229 (#8962)

* Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229

* skip failing tests

* update mac build image
This commit is contained in:
Anthony Dresser
2020-01-27 15:28:17 -08:00
committed by Karl Burtram
parent 0eaee18dc4
commit fefe1454de
481 changed files with 12764 additions and 7836 deletions

View File

@@ -287,7 +287,7 @@ export function addDisposableGenericMouseUpListner(node: EventTarget, handler: (
export function addDisposableNonBubblingMouseOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable {
return addDisposableListener(node, 'mouseout', (e: MouseEvent) => {
// Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements
let toElement: Node | null = <Node>(e.relatedTarget || e.target);
let toElement: Node | null = <Node>(e.relatedTarget);
while (toElement && toElement !== node) {
toElement = toElement.parentNode;
}
@@ -302,7 +302,7 @@ export function addDisposableNonBubblingMouseOutListener(node: Element, handler:
export function addDisposableNonBubblingPointerOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable {
return addDisposableListener(node, 'pointerout', (e: MouseEvent) => {
// Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements
let toElement: Node | null = <Node>(e.relatedTarget || e.target);
let toElement: Node | null = <Node>(e.relatedTarget);
while (toElement && toElement !== node) {
toElement = toElement.parentNode;
}
@@ -628,11 +628,17 @@ export function getTopLeftOffset(element: HTMLElement): { left: number; top: num
// Adapted from WinJS.Utilities.getPosition
// and added borders to the mix
let offsetParent = element.offsetParent, top = element.offsetTop, left = element.offsetLeft;
let offsetParent = element.offsetParent;
let top = element.offsetTop;
let left = element.offsetLeft;
while ((element = <HTMLElement>element.parentNode) !== null && element !== document.body && element !== document.documentElement) {
while (
(element = <HTMLElement>element.parentNode) !== null
&& element !== document.body
&& element !== document.documentElement
) {
top -= element.scrollTop;
let c = getComputedStyle(element);
const c = isShadowRoot(element) ? null : getComputedStyle(element);
if (c) {
left -= c.direction !== 'rtl' ? element.scrollLeft : -element.scrollLeft;
}
@@ -793,7 +799,7 @@ export function isAncestor(testChild: Node | null, testAncestor: Node | null): b
}
export function findParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): HTMLElement | null {
while (node) {
while (node && node.nodeType === node.ELEMENT_NODE) {
if (hasClass(node, clazz)) {
return node;
}
@@ -820,6 +826,27 @@ export function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazz
return !!findParentWithClass(node, clazz, stopAtClazzOrNode);
}
export function isShadowRoot(node: Node): node is ShadowRoot {
return (
node && !!(<ShadowRoot>node).host && !!(<ShadowRoot>node).mode
);
}
export function isInShadowDOM(domNode: Node): boolean {
return !!getShadowRoot(domNode);
}
export function getShadowRoot(domNode: Node): ShadowRoot | null {
while (domNode.parentNode) {
if (domNode === document.body) {
// reached the body
return null;
}
domNode = domNode.parentNode;
}
return isShadowRoot(domNode) ? domNode : null;
}
export function createStyleSheet(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLStyleElement {
let style = document.createElement('style');
style.type = 'text/css';
@@ -1167,7 +1194,7 @@ export function hide(...elements: HTMLElement[]): void {
}
function findParentWithAttribute(node: Node | null, attribute: string): HTMLElement | null {
while (node) {
while (node && node.nodeType === node.ELEMENT_NODE) {
if (node instanceof HTMLElement && node.hasAttribute(attribute)) {
return node;
}

View File

@@ -25,6 +25,7 @@ export class FastDomNode<T extends HTMLElement> {
private _display: string;
private _position: string;
private _visibility: string;
private _backgroundColor: string;
private _layerHint: boolean;
private _contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint';
@@ -47,6 +48,7 @@ export class FastDomNode<T extends HTMLElement> {
this._display = '';
this._position = '';
this._visibility = '';
this._backgroundColor = '';
this._layerHint = false;
this._contain = 'none';
}
@@ -200,6 +202,14 @@ export class FastDomNode<T extends HTMLElement> {
this.domNode.style.visibility = this._visibility;
}
public setBackgroundColor(backgroundColor: string): void {
if (this._backgroundColor === backgroundColor) {
return;
}
this._backgroundColor = backgroundColor;
this.domNode.style.backgroundColor = this._backgroundColor;
}
public setLayerHinting(layerHint: boolean): void {
if (this._layerHint === layerHint) {
return;

View File

@@ -75,6 +75,7 @@ export class GlobalMouseMoveMonitor<R extends { buttons: number; }> implements I
}
public startMonitoring(
initialElement: HTMLElement,
initialButtons: number,
mouseMoveEventMerger: IEventMerger<R>,
mouseMoveCallback: IMouseMoveCallback<R>,
@@ -88,11 +89,18 @@ export class GlobalMouseMoveMonitor<R extends { buttons: number; }> implements I
this._mouseMoveCallback = mouseMoveCallback;
this._onStopCallback = onStopCallback;
let windowChain = IframeUtils.getSameOriginWindowChain();
const windowChain = IframeUtils.getSameOriginWindowChain();
const mouseMove = platform.isIOS && BrowserFeatures.pointerEvents ? 'pointermove' : 'mousemove';
const mouseUp = platform.isIOS && BrowserFeatures.pointerEvents ? 'pointerup' : 'mouseup';
for (const element of windowChain) {
this._hooks.add(dom.addDisposableThrottledListener(element.window.document, mouseMove,
const listenTo: (Document | ShadowRoot)[] = windowChain.map(element => element.window.document);
const shadowRoot = dom.getShadowRoot(initialElement);
if (shadowRoot) {
listenTo.unshift(shadowRoot);
}
for (const element of listenTo) {
this._hooks.add(dom.addDisposableThrottledListener(element, mouseMove,
(data: R) => {
if (data.buttons !== initialButtons) {
// Buttons state has changed in the meantime
@@ -103,7 +111,7 @@ export class GlobalMouseMoveMonitor<R extends { buttons: number; }> implements I
},
(lastEvent: R | null, currentEvent) => this._mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent)
));
this._hooks.add(dom.addDisposableListener(element.window.document, mouseUp, (e: MouseEvent) => this.stopMonitoring(true)));
this._hooks.add(dom.addDisposableListener(element, mouseUp, (e: MouseEvent) => this.stopMonitoring(true)));
}
if (IframeUtils.hasDifferentOriginAncestor()) {

View File

@@ -5,7 +5,7 @@
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?ed926e87ee4e27771159d875e877f74a") format("truetype");
src: url("./codicon.ttf?be537a78617db0869caa4b4cc683a24a") format("truetype");
}
.codicon[class*='codicon-'] {
@@ -119,6 +119,7 @@
.codicon-github:before { content: "\ea84" }
.codicon-terminal:before { content: "\ea85" }
.codicon-console:before { content: "\ea85" }
.codicon-repl:before { content: "\ea85" }
.codicon-zap:before { content: "\ea86" }
.codicon-symbol-event:before { content: "\ea86" }
.codicon-error:before { content: "\ea87" }
@@ -410,4 +411,6 @@
.codicon-menu:before { content: "\eb94" }
.codicon-expand-all:before { content: "\eb95" }
.codicon-feedback:before { content: "\eb96" }
.codicon-group-by-ref-type:before { content: "\eb97" }
.codicon-ungroup-by-ref-type:before { content: "\eb98" }
.codicon-debug-alt:before { content: "\f101" }

View File

@@ -92,8 +92,10 @@ class FastLabelNode {
export class IconLabel extends Disposable {
private domNode: FastLabelNode;
private descriptionContainer: FastLabelNode;
private nameNode: Label | LabelWithHighlights;
private descriptionContainer: FastLabelNode;
private descriptionNode: FastLabelNode | HighlightedLabel | undefined;
private descriptionNodeFactory: () => FastLabelNode | HighlightedLabel;

View File

@@ -844,7 +844,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
}
// sanitize feedback list
feedback = distinct(feedback).filter(i => i >= -1 && i < this.length).sort();
feedback = distinct(feedback).filter(i => i >= -1 && i < this.length).sort((a, b) => a - b);
feedback = feedback[0] === -1 ? [-1] : feedback;
if (equalsDragFeedback(this.currentDragFeedback, feedback)) {

View File

@@ -61,6 +61,7 @@ export abstract class AbstractScrollbar extends Widget {
this._scrollable = opts.scrollable;
this._scrollbarState = opts.scrollbarState;
this._visibilityController = this._register(new ScrollbarVisibilityController(opts.visibility, 'visible scrollbar ' + opts.extraScrollbarClassName, 'invisible scrollbar ' + opts.extraScrollbarClassName));
this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
this._mouseMoveMonitor = this._register(new GlobalMouseMoveMonitor<IStandardMouseMoveEventData>());
this._shouldRender = true;
this.domNode = createFastDomNode(document.createElement('div'));
@@ -216,13 +217,14 @@ export abstract class AbstractScrollbar extends Widget {
}
}
private _sliderMouseDown(e: ISimplifiedMouseEvent, onDragFinished: () => void): void {
private _sliderMouseDown(e: IMouseEvent, onDragFinished: () => void): void {
const initialMousePosition = this._sliderMousePosition(e);
const initialMouseOrthogonalPosition = this._sliderOrthogonalMousePosition(e);
const initialScrollbarState = this._scrollbarState.clone();
this.slider.toggleClassName('active', true);
this._mouseMoveMonitor.startMonitoring(
e.target,
e.buttons,
standardMouseMoveMerger,
(mouseMoveData: IStandardMouseMoveEventData) => {

View File

@@ -13,13 +13,18 @@ import { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from
export class HorizontalScrollbar extends AbstractScrollbar {
constructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {
const scrollDimensions = scrollable.getScrollDimensions();
const scrollPosition = scrollable.getCurrentScrollPosition();
super({
lazyRender: options.lazyRender,
host: host,
scrollbarState: new ScrollbarState(
(options.horizontalHasArrows ? options.arrowSize : 0),
(options.horizontal === ScrollbarVisibility.Hidden ? 0 : options.horizontalScrollbarSize),
(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize)
(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize),
scrollDimensions.width,
scrollDimensions.scrollWidth,
scrollPosition.scrollLeft
),
visibility: options.horizontal,
extraScrollbarClassName: 'horizontal',

View File

@@ -93,6 +93,7 @@ export class ScrollbarArrow extends Widget {
this._mousedownScheduleRepeatTimer.cancelAndSet(scheduleRepeater, 200);
this._mouseMoveMonitor.startMonitoring(
e.target,
e.buttons,
standardMouseMoveMerger,
(mouseMoveData: IStandardMouseMoveEventData) => {

View File

@@ -62,14 +62,14 @@ export class ScrollbarState {
private _computedSliderRatio: number;
private _computedSliderPosition: number;
constructor(arrowSize: number, scrollbarSize: number, oppositeScrollbarSize: number) {
constructor(arrowSize: number, scrollbarSize: number, oppositeScrollbarSize: number, visibleSize: number, scrollSize: number, scrollPosition: number) {
this._scrollbarSize = Math.round(scrollbarSize);
this._oppositeScrollbarSize = Math.round(oppositeScrollbarSize);
this._arrowSize = Math.round(arrowSize);
this._visibleSize = 0;
this._scrollSize = 0;
this._scrollPosition = 0;
this._visibleSize = visibleSize;
this._scrollSize = scrollSize;
this._scrollPosition = scrollPosition;
this._computedAvailableSize = 0;
this._computedIsNeeded = false;
@@ -81,11 +81,7 @@ export class ScrollbarState {
}
public clone(): ScrollbarState {
let r = new ScrollbarState(this._arrowSize, this._scrollbarSize, this._oppositeScrollbarSize);
r.setVisibleSize(this._visibleSize);
r.setScrollSize(this._scrollSize);
r.setScrollPosition(this._scrollPosition);
return r;
return new ScrollbarState(this._arrowSize, this._scrollbarSize, this._oppositeScrollbarSize, this._visibleSize, this._scrollSize, this._scrollPosition);
}
public setVisibleSize(visibleSize: number): boolean {

View File

@@ -13,6 +13,8 @@ import { INewScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from
export class VerticalScrollbar extends AbstractScrollbar {
constructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {
const scrollDimensions = scrollable.getScrollDimensions();
const scrollPosition = scrollable.getCurrentScrollPosition();
super({
lazyRender: options.lazyRender,
host: host,
@@ -20,7 +22,10 @@ export class VerticalScrollbar extends AbstractScrollbar {
(options.verticalHasArrows ? options.arrowSize : 0),
(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize),
// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom
0
0,
scrollDimensions.height,
scrollDimensions.scrollHeight,
scrollPosition.scrollTop
),
visibility: options.vertical,
extraScrollbarClassName: 'vertical',

View File

@@ -6,7 +6,11 @@
import { URI } from 'vs/base/common/uri';
export function getPathFromAmdModule(requirefn: typeof require, relativePath: string): string {
return URI.parse(requirefn.toUrl(relativePath)).fsPath;
return getUriFromAmdModule(requirefn, relativePath).fsPath;
}
export function getUriFromAmdModule(requirefn: typeof require, relativePath: string): URI {
return URI.parse(requirefn.toUrl(relativePath));
}
/**

View File

@@ -481,8 +481,9 @@ export class Queue<T> extends Limiter<T> {
* A helper to organize queues per resource. The ResourceQueue makes sure to manage queues per resource
* by disposing them once the queue is empty.
*/
export class ResourceQueue {
private queues: Map<string, Queue<void>> = new Map();
export class ResourceQueue implements IDisposable {
private readonly queues = new Map<string, Queue<void>>();
queueFor(resource: URI): Queue<void> {
const key = resource.toString();
@@ -498,6 +499,11 @@ export class ResourceQueue {
return this.queues.get(key)!;
}
dispose(): void {
this.queues.forEach(queue => queue.dispose());
this.queues.clear();
}
}
export class TimeoutTimer implements IDisposable {

View File

@@ -148,6 +148,7 @@ export namespace Event {
if (leading && !handle) {
emitter.fire(output);
output = undefined;
}
clearTimeout(handle);

View File

@@ -120,7 +120,7 @@ export function setProperty(text: string, originalPath: JSONPath, value: any, fo
}
}
function withFormatting(text: string, edit: Edit, formattingOptions: FormattingOptions): Edit[] {
export function withFormatting(text: string, edit: Edit, formattingOptions: FormattingOptions): Edit[] {
// apply the edit
let newText = applyEdit(text, edit);

View File

@@ -228,7 +228,7 @@ function computeIndentLevel(content: string, options: FormattingOptions): number
return Math.floor(nChars / tabSize);
}
function getEOL(options: FormattingOptions, text: string): string {
export function getEOL(options: FormattingOptions, text: string): string {
for (let i = 0; i < text.length; i++) {
const ch = text.charAt(i);
if (ch === '\r') {
@@ -245,4 +245,4 @@ function getEOL(options: FormattingOptions, text: string): string {
export function isEOL(text: string, offset: number) {
return '\r\n'.indexOf(text.charAt(offset)) !== -1;
}
}

View File

@@ -72,6 +72,49 @@ function doFindFreePort(startPort: number, giveUpAfter: number, clb: (port: numb
client.connect(startPort, '127.0.0.1');
}
/**
* Uses listen instead of connect. Is faster, but if there is another listener on 0.0.0.0 then this will take 127.0.0.1 from that listener.
*/
export function findFreePortFaster(startPort: number, giveUpAfter: number, timeout: number): Promise<number> {
let resolved: boolean = false;
let timeoutHandle: NodeJS.Timeout | undefined = undefined;
let countTried: number = 1;
const server = net.createServer({ pauseOnConnect: true });
function doResolve(port: number, resolve: (port: number) => void) {
if (!resolved) {
resolved = true;
server.removeAllListeners();
server.close();
if (timeoutHandle) {
clearTimeout(timeoutHandle);
}
resolve(port);
}
}
return new Promise<number>(resolve => {
timeoutHandle = setTimeout(() => {
doResolve(0, resolve);
}, timeout);
server.on('listening', () => {
doResolve(startPort, resolve);
});
server.on('error', err => {
if (err && ((<any>err).code === 'EADDRINUSE' || (<any>err).code === 'EACCES') && (countTried < giveUpAfter)) {
startPort++;
countTried++;
server.listen(startPort, '127.0.0.1');
} else {
doResolve(0, resolve);
}
});
server.on('close', () => {
doResolve(0, resolve);
});
server.listen(startPort, '127.0.0.1');
});
}
function dispose(socket: net.Socket): void {
try {
socket.removeAllListeners('connect');

File diff suppressed because one or more lines are too long

View File

@@ -8,10 +8,7 @@ import { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';
suite('ScrollbarState', () => {
test('inflates slider size', () => {
let actual = new ScrollbarState(0, 14, 0);
actual.setVisibleSize(339);
actual.setScrollSize(42423);
actual.setScrollPosition(32787);
let actual = new ScrollbarState(0, 14, 0, 339, 42423, 32787);
assert.equal(actual.getArrowSize(), 0);
assert.equal(actual.getScrollPosition(), 32787);
@@ -34,10 +31,7 @@ suite('ScrollbarState', () => {
});
test('inflates slider size with arrows', () => {
let actual = new ScrollbarState(12, 14, 0);
actual.setVisibleSize(339);
actual.setScrollSize(42423);
actual.setScrollPosition(32787);
let actual = new ScrollbarState(12, 14, 0, 339, 42423, 32787);
assert.equal(actual.getArrowSize(), 12);
assert.equal(actual.getScrollPosition(), 32787);

View File

@@ -237,6 +237,20 @@ suite('Event', function () {
assert.equal(calls, 2);
});
test('Debounce Event - leading reset', async function () {
const emitter = new Emitter<number>();
let debounced = Event.debounce(emitter.event, (l, e) => l ? l + 1 : 1, 0, /*leading=*/true);
let calls: number[] = [];
debounced((e) => calls.push(e));
emitter.fire(1);
emitter.fire(1);
await timeout(1);
assert.deepEqual(calls, [1, 1]);
});
test('Emitter - In Order Delivery', function () {
const a = new Emitter<string>();
const listener2Events: string[] = [];