Merge from vscode e558dc6ea73a75bd69d7a0b485f0e7e4194c66bf (#6864)

This commit is contained in:
Anthony Dresser
2019-08-21 20:44:59 -07:00
committed by GitHub
parent d2ae0f0154
commit 985bfae8a0
107 changed files with 2260 additions and 814 deletions

View File

@@ -1186,22 +1186,14 @@ export function animate(fn: () => void): IDisposable {
return toDisposable(() => stepDisposable.dispose());
}
const _location = URI.parse(window.location.href);
RemoteAuthorities.setPreferredWebSchema(/^https:/.test(window.location.href) ? 'https' : 'http');
export function asDomUri(uri: URI): URI {
if (!uri) {
return uri;
}
if (Schemas.vscodeRemote === uri.scheme) {
if (platform.isWeb) {
// rewrite vscode-remote-uris to uris of the window location
// so that they can be intercepted by the service worker
return _location.with({ path: '/vscode-remote', query: JSON.stringify(uri) });
} else {
return RemoteAuthorities.rewrite(uri.authority, uri.path);
}
return RemoteAuthorities.rewrite(uri.authority, uri.path);
}
return uri;
}

View File

@@ -197,9 +197,11 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
allowedAttributes: {
'a': ['href', 'name', 'target', 'data-href'],
'iframe': ['allowfullscreen', 'frameborder', 'src'],
'img': ['src', 'title', 'alt', 'width', 'height']
'img': ['src', 'title', 'alt', 'width', 'height'],
'div': ['class', 'data-code']
}
});
signalInnerHTML!();
return element;

View File

@@ -24,6 +24,8 @@ export interface IFindInputOptions extends IFindInputStyles {
readonly validation?: IInputValidator;
readonly label: string;
readonly flexibleHeight?: boolean;
readonly flexibleWidth?: boolean;
readonly flexibleMaxHeight?: number;
readonly appendCaseSensitiveLabel?: string;
readonly appendWholeWordsLabel?: string;
@@ -119,6 +121,8 @@ export class FindInput extends Widget {
const appendRegexLabel = options.appendRegexLabel || '';
const history = options.history || [];
const flexibleHeight = !!options.flexibleHeight;
const flexibleWidth = !!options.flexibleWidth;
const flexibleMaxHeight = options.flexibleMaxHeight;
this.domNode = document.createElement('div');
dom.addClass(this.domNode, 'monaco-findInput');
@@ -142,7 +146,9 @@ export class FindInput extends Widget {
inputValidationErrorForeground: this.inputValidationErrorForeground,
inputValidationErrorBorder: this.inputValidationErrorBorder,
history,
flexibleHeight
flexibleHeight,
flexibleWidth,
flexibleMaxHeight
}));
this.regex = this._register(new RegexCheckbox({
@@ -194,11 +200,7 @@ export class FindInput extends Widget {
}));
if (this._showOptionButtons) {
const paddingRight = (this.caseSensitive.width() + this.wholeWords.width() + this.regex.width()) + 'px';
this.inputBox.inputElement.style.paddingRight = paddingRight;
if (this.inputBox.mirrorElement) {
this.inputBox.mirrorElement.style.paddingRight = paddingRight;
}
this.inputBox.paddingRight = this.caseSensitive.width() + this.wholeWords.width() + this.regex.width();
}
// Arrow-Key support to navigate between options

View File

@@ -0,0 +1,373 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./findInput';
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { IMessage as InputBoxMessage, IInputValidator, IInputBoxStyles, HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
import { Widget } from 'vs/base/browser/ui/widget';
import { Event, Emitter } from 'vs/base/common/event';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Color } from 'vs/base/common/color';
import { ICheckboxStyles, Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
import { IFindInputCheckboxOpts } from 'vs/base/browser/ui/findinput/findInputCheckboxes';
export interface IReplaceInputOptions extends IReplaceInputStyles {
readonly placeholder?: string;
readonly width?: number;
readonly validation?: IInputValidator;
readonly label: string;
readonly flexibleHeight?: boolean;
readonly flexibleWidth?: boolean;
readonly flexibleMaxHeight?: number;
readonly history?: string[];
}
export interface IReplaceInputStyles extends IInputBoxStyles {
inputActiveOptionBorder?: Color;
}
const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input");
const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case");
export class PreserveCaseCheckbox extends Checkbox {
constructor(opts: IFindInputCheckboxOpts) {
super({
// TODO: does this need its own icon?
actionClassName: 'monaco-case-sensitive',
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
inputActiveOptionBorder: opts.inputActiveOptionBorder
});
}
}
export class ReplaceInput extends Widget {
static readonly OPTION_CHANGE: string = 'optionChange';
private contextViewProvider: IContextViewProvider | undefined;
private placeholder: string;
private validation?: IInputValidator;
private label: string;
private fixFocusOnOptionClickEnabled = true;
private inputActiveOptionBorder?: Color;
private inputBackground?: Color;
private inputForeground?: Color;
private inputBorder?: Color;
private inputValidationInfoBorder?: Color;
private inputValidationInfoBackground?: Color;
private inputValidationInfoForeground?: Color;
private inputValidationWarningBorder?: Color;
private inputValidationWarningBackground?: Color;
private inputValidationWarningForeground?: Color;
private inputValidationErrorBorder?: Color;
private inputValidationErrorBackground?: Color;
private inputValidationErrorForeground?: Color;
private preserveCase: PreserveCaseCheckbox;
private cachedOptionsWidth: number = 0;
public domNode: HTMLElement;
public inputBox: HistoryInputBox;
private readonly _onDidOptionChange = this._register(new Emitter<boolean>());
public readonly onDidOptionChange: Event<boolean /* via keyboard */> = this._onDidOptionChange.event;
private readonly _onKeyDown = this._register(new Emitter<IKeyboardEvent>());
public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;
private readonly _onMouseDown = this._register(new Emitter<IMouseEvent>());
public readonly onMouseDown: Event<IMouseEvent> = this._onMouseDown.event;
private readonly _onInput = this._register(new Emitter<void>());
public readonly onInput: Event<void> = this._onInput.event;
private readonly _onKeyUp = this._register(new Emitter<IKeyboardEvent>());
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
private _onPreserveCaseKeyDown = this._register(new Emitter<IKeyboardEvent>());
public readonly onPreserveCaseKeyDown: Event<IKeyboardEvent> = this._onPreserveCaseKeyDown.event;
constructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, private readonly _showOptionButtons: boolean, options: IReplaceInputOptions) {
super();
this.contextViewProvider = contextViewProvider;
this.placeholder = options.placeholder || '';
this.validation = options.validation;
this.label = options.label || NLS_DEFAULT_LABEL;
this.inputActiveOptionBorder = options.inputActiveOptionBorder;
this.inputBackground = options.inputBackground;
this.inputForeground = options.inputForeground;
this.inputBorder = options.inputBorder;
this.inputValidationInfoBorder = options.inputValidationInfoBorder;
this.inputValidationInfoBackground = options.inputValidationInfoBackground;
this.inputValidationInfoForeground = options.inputValidationInfoForeground;
this.inputValidationWarningBorder = options.inputValidationWarningBorder;
this.inputValidationWarningBackground = options.inputValidationWarningBackground;
this.inputValidationWarningForeground = options.inputValidationWarningForeground;
this.inputValidationErrorBorder = options.inputValidationErrorBorder;
this.inputValidationErrorBackground = options.inputValidationErrorBackground;
this.inputValidationErrorForeground = options.inputValidationErrorForeground;
const flexibleHeight = !!options.flexibleHeight;
const flexibleWidth = !!options.flexibleWidth;
const flexibleMaxHeight = options.flexibleMaxHeight;
this.buildDomNode(options.history || [], flexibleHeight, flexibleWidth, flexibleMaxHeight);
if (parent) {
parent.appendChild(this.domNode);
}
this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));
this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));
this.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());
this.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));
}
public enable(): void {
dom.removeClass(this.domNode, 'disabled');
this.inputBox.enable();
this.preserveCase.enable();
}
public disable(): void {
dom.addClass(this.domNode, 'disabled');
this.inputBox.disable();
this.preserveCase.disable();
}
public setFocusInputOnOptionClick(value: boolean): void {
this.fixFocusOnOptionClickEnabled = value;
}
public setEnabled(enabled: boolean): void {
if (enabled) {
this.enable();
} else {
this.disable();
}
}
public clear(): void {
this.clearValidation();
this.setValue('');
this.focus();
}
public getValue(): string {
return this.inputBox.value;
}
public setValue(value: string): void {
if (this.inputBox.value !== value) {
this.inputBox.value = value;
}
}
public onSearchSubmit(): void {
this.inputBox.addToHistory();
}
public style(styles: IReplaceInputStyles): void {
this.inputActiveOptionBorder = styles.inputActiveOptionBorder;
this.inputBackground = styles.inputBackground;
this.inputForeground = styles.inputForeground;
this.inputBorder = styles.inputBorder;
this.inputValidationInfoBackground = styles.inputValidationInfoBackground;
this.inputValidationInfoForeground = styles.inputValidationInfoForeground;
this.inputValidationInfoBorder = styles.inputValidationInfoBorder;
this.inputValidationWarningBackground = styles.inputValidationWarningBackground;
this.inputValidationWarningForeground = styles.inputValidationWarningForeground;
this.inputValidationWarningBorder = styles.inputValidationWarningBorder;
this.inputValidationErrorBackground = styles.inputValidationErrorBackground;
this.inputValidationErrorForeground = styles.inputValidationErrorForeground;
this.inputValidationErrorBorder = styles.inputValidationErrorBorder;
this.applyStyles();
}
protected applyStyles(): void {
if (this.domNode) {
const checkBoxStyles: ICheckboxStyles = {
inputActiveOptionBorder: this.inputActiveOptionBorder,
};
this.preserveCase.style(checkBoxStyles);
const inputBoxStyles: IInputBoxStyles = {
inputBackground: this.inputBackground,
inputForeground: this.inputForeground,
inputBorder: this.inputBorder,
inputValidationInfoBackground: this.inputValidationInfoBackground,
inputValidationInfoForeground: this.inputValidationInfoForeground,
inputValidationInfoBorder: this.inputValidationInfoBorder,
inputValidationWarningBackground: this.inputValidationWarningBackground,
inputValidationWarningForeground: this.inputValidationWarningForeground,
inputValidationWarningBorder: this.inputValidationWarningBorder,
inputValidationErrorBackground: this.inputValidationErrorBackground,
inputValidationErrorForeground: this.inputValidationErrorForeground,
inputValidationErrorBorder: this.inputValidationErrorBorder
};
this.inputBox.style(inputBoxStyles);
}
}
public select(): void {
this.inputBox.select();
}
public focus(): void {
this.inputBox.focus();
}
public getPreserveCase(): boolean {
return this.preserveCase.checked;
}
public setPreserveCase(value: boolean): void {
this.preserveCase.checked = value;
}
public focusOnPreserve(): void {
this.preserveCase.focus();
}
private _lastHighlightFindOptions: number = 0;
public highlightFindOptions(): void {
dom.removeClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
this._lastHighlightFindOptions = 1 - this._lastHighlightFindOptions;
dom.addClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
}
private buildDomNode(history: string[], flexibleHeight: boolean, flexibleWidth: boolean, flexibleMaxHeight: number | undefined): void {
this.domNode = document.createElement('div');
dom.addClass(this.domNode, 'monaco-findInput');
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
ariaLabel: this.label || '',
placeholder: this.placeholder || '',
validationOptions: {
validation: this.validation
},
inputBackground: this.inputBackground,
inputForeground: this.inputForeground,
inputBorder: this.inputBorder,
inputValidationInfoBackground: this.inputValidationInfoBackground,
inputValidationInfoForeground: this.inputValidationInfoForeground,
inputValidationInfoBorder: this.inputValidationInfoBorder,
inputValidationWarningBackground: this.inputValidationWarningBackground,
inputValidationWarningForeground: this.inputValidationWarningForeground,
inputValidationWarningBorder: this.inputValidationWarningBorder,
inputValidationErrorBackground: this.inputValidationErrorBackground,
inputValidationErrorForeground: this.inputValidationErrorForeground,
inputValidationErrorBorder: this.inputValidationErrorBorder,
history,
flexibleHeight,
flexibleWidth,
flexibleMaxHeight
}));
this.preserveCase = this._register(new PreserveCaseCheckbox({
appendTitle: '',
isChecked: false,
inputActiveOptionBorder: this.inputActiveOptionBorder
}));
this._register(this.preserveCase.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.preserveCase.onKeyDown(e => {
this._onPreserveCaseKeyDown.fire(e);
}));
if (this._showOptionButtons) {
this.cachedOptionsWidth = this.preserveCase.width();
} else {
this.cachedOptionsWidth = 0;
}
// Arrow-Key support to navigate between options
let indexes = [this.preserveCase.domNode];
this.onkeydown(this.domNode, (event: IKeyboardEvent) => {
if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {
let index = indexes.indexOf(<HTMLElement>document.activeElement);
if (index >= 0) {
let newIndex: number = -1;
if (event.equals(KeyCode.RightArrow)) {
newIndex = (index + 1) % indexes.length;
} else if (event.equals(KeyCode.LeftArrow)) {
if (index === 0) {
newIndex = indexes.length - 1;
} else {
newIndex = index - 1;
}
}
if (event.equals(KeyCode.Escape)) {
indexes[index].blur();
} else if (newIndex >= 0) {
indexes[newIndex].focus();
}
dom.EventHelper.stop(event, true);
}
}
});
let controls = document.createElement('div');
controls.className = 'controls';
controls.style.display = this._showOptionButtons ? 'block' : 'none';
controls.appendChild(this.preserveCase.domNode);
this.domNode.appendChild(controls);
}
public validate(): void {
if (this.inputBox) {
this.inputBox.validate();
}
}
public showMessage(message: InputBoxMessage): void {
if (this.inputBox) {
this.inputBox.showMessage(message);
}
}
public clearMessage(): void {
if (this.inputBox) {
this.inputBox.hideMessage();
}
}
private clearValidation(): void {
if (this.inputBox) {
this.inputBox.hideMessage();
}
}
public set width(newWidth: number) {
this.inputBox.paddingRight = this.cachedOptionsWidth;
this.inputBox.width = newWidth;
this.domNode.style.width = newWidth + 'px';
}
public dispose(): void {
super.dispose();
}
}

View File

@@ -60,6 +60,8 @@
display: block;
-ms-overflow-style: none; /* IE 10+ */
overflow: -moz-scrollbars-none; /* Firefox */
scrollbar-width: none; /* Firefox ^64 */
outline: none;
}
.monaco-inputbox > .wrapper > textarea.input::-webkit-scrollbar {

View File

@@ -32,6 +32,7 @@ export interface IInputOptions extends IInputBoxStyles {
readonly type?: string;
readonly validationOptions?: IInputValidationOptions;
readonly flexibleHeight?: boolean;
readonly flexibleWidth?: boolean;
readonly flexibleMaxHeight?: number;
readonly actions?: ReadonlyArray<IAction>;
@@ -185,6 +186,13 @@ export class InputBox extends Widget {
this.mirror.innerHTML = '&nbsp;';
this.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });
if (this.options.flexibleWidth) {
this.input.setAttribute('wrap', 'off');
this.mirror.style.whiteSpace = 'pre';
this.mirror.style.wordWrap = 'initial';
}
dom.append(container, this.scrollableElement.getDomNode());
this._register(this.scrollableElement);
@@ -345,12 +353,36 @@ export class InputBox extends Widget {
}
public set width(width: number) {
this.input.style.width = width + 'px';
if (this.options.flexibleHeight && this.options.flexibleWidth) {
// textarea with horizontal scrolling
let horizontalPadding = 0;
if (this.mirror) {
const paddingLeft = parseFloat(this.mirror.style.paddingLeft || '') || 0;
const paddingRight = parseFloat(this.mirror.style.paddingRight || '') || 0;
horizontalPadding = paddingLeft + paddingRight;
}
this.input.style.width = (width - horizontalPadding) + 'px';
} else {
this.input.style.width = width + 'px';
}
if (this.mirror) {
this.mirror.style.width = width + 'px';
}
}
public set paddingRight(paddingRight: number) {
if (this.options.flexibleHeight && this.options.flexibleWidth) {
this.input.style.width = `calc(100% - ${paddingRight}px)`;
} else {
this.input.style.paddingRight = paddingRight + 'px';
}
if (this.mirror) {
this.mirror.style.paddingRight = paddingRight + 'px';
}
}
private updateScrollDimensions(): void {
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number') {
return;

View File

@@ -683,6 +683,22 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.scrollableElement.setScrollPosition({ scrollTop });
}
getScrollLeft(): number {
const scrollPosition = this.scrollableElement.getScrollPosition();
return scrollPosition.scrollLeft;
}
setScrollLeftt(scrollLeft: number): void {
if (this.scrollableElementUpdateDisposable) {
this.scrollableElementUpdateDisposable.dispose();
this.scrollableElementUpdateDisposable = null;
this.scrollableElement.setScrollDimensions({ scrollWidth: this.scrollWidth });
}
this.scrollableElement.setScrollPosition({ scrollLeft });
}
get scrollTop(): number {
return this.getScrollTop();
}

View File

@@ -1307,6 +1307,14 @@ export class List<T> implements ISpliceable<T>, IDisposable {
this.view.setScrollTop(scrollTop);
}
get scrollLeft(): number {
return this.view.getScrollLeft();
}
set scrollLeft(scrollLeft: number) {
this.view.setScrollLeftt(scrollLeft);
}
get scrollHeight(): number {
return this.view.scrollHeight;
}

View File

@@ -1319,6 +1319,14 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.view.scrollTop = scrollTop;
}
get scrollLeft(): number {
return this.view.scrollTop;
}
set scrollLeft(scrollLeft: number) {
this.view.scrollLeft = scrollLeft;
}
get scrollHeight(): number {
return this.view.scrollHeight;
}

View File

@@ -400,6 +400,14 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
this.tree.scrollTop = scrollTop;
}
get scrollLeft(): number {
return this.tree.scrollLeft;
}
set scrollLeft(scrollLeft: number) {
this.tree.scrollLeft = scrollLeft;
}
get scrollHeight(): number {
return this.tree.scrollHeight;
}

View File

@@ -219,7 +219,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
const result = this._setListNodeCollapsed(node, listIndex, revealed, collapsed!, recursive || false);
if (this.autoExpandSingleChildren && !collapsed! && !recursive) {
if (node !== this.root && this.autoExpandSingleChildren && !collapsed! && !recursive) {
let onlyVisibleChildIndex = -1;
for (let i = 0; i < node.children.length; i++) {

View File

@@ -549,7 +549,7 @@ export function fuzzyScore(pattern: string, patternLow: string, patternPos: numb
const patternStartPos = patternPos;
const wordStartPos = wordPos;
// There will be a mach, fill in tables
// There will be a match, fill in tables
for (patternPos = patternStartPos + 1; patternPos <= patternLen; patternPos++) {
for (wordPos = 1; wordPos <= wordLen; wordPos++) {
@@ -573,6 +573,11 @@ export function fuzzyScore(pattern: string, patternLow: string, patternPos: numb
} else {
score = 5;
}
} else if (isSeparatorAtPos(wordLow, wordPos - 1) && (wordPos === 1 || !isSeparatorAtPos(wordLow, wordPos - 2))) {
// hitting a separator: `. <-> foo.bar`
// ^
score = 5;
} else if (isSeparatorAtPos(wordLow, wordPos - 2) || isWhitespaceAtPos(wordLow, wordPos - 2)) {
// post separator: `foo <-> bar_foo`
// ^^^

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import * as platform from 'vs/base/common/platform';
export namespace Schemas {
@@ -58,11 +59,17 @@ class RemoteAuthoritiesImpl {
private readonly _hosts: { [authority: string]: string; };
private readonly _ports: { [authority: string]: number; };
private readonly _connectionTokens: { [authority: string]: string; };
private _preferredWebSchema: 'http' | 'https';
constructor() {
this._hosts = Object.create(null);
this._ports = Object.create(null);
this._connectionTokens = Object.create(null);
this._preferredWebSchema = 'http';
}
public setPreferredWebSchema(schema: 'http' | 'https') {
this._preferredWebSchema = schema;
}
public set(authority: string, host: string, port: number): void {
@@ -79,9 +86,9 @@ class RemoteAuthoritiesImpl {
const port = this._ports[authority];
const connectionToken = this._connectionTokens[authority];
return URI.from({
scheme: Schemas.vscodeRemoteResource,
scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
authority: `${host}:${port}`,
path: `/vscode-remote2`,
path: `/vscode-remote-resource`,
query: `path=${encodeURIComponent(path)}&tkn=${encodeURIComponent(connectionToken)}`
});
}

View File

@@ -366,6 +366,10 @@ suite('Filters', () => {
assertMatches('f', ':foo', ':^foo', fuzzyScore);
});
test('Separator only match should not be weak #79558', function () {
assertMatches('.', 'foo.bar', 'foo^.bar', fuzzyScore);
});
test('Cannot set property \'1\' of undefined, #26511', function () {
let word = new Array<void>(123).join('a');
let pattern = new Array<void>(120).join('a');