mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 1b314ab317fbff7d799b21754326b7d849889ceb
This commit is contained in:
@@ -221,10 +221,13 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
|
||||
allowedSchemes.push(Schemas.command);
|
||||
}
|
||||
|
||||
// values that are too long will freeze the UI
|
||||
let value = markdown.value ?? '';
|
||||
if (value.length > 100_000) {
|
||||
value = `${value.substr(0, 100_000)}…`;
|
||||
}
|
||||
const renderedMarkdown = marked.parse(
|
||||
markdown.supportThemeIcons
|
||||
? markdownEscapeEscapedCodicons(markdown.value || '')
|
||||
: (markdown.value || ''),
|
||||
markdown.supportThemeIcons ? markdownEscapeEscapedCodicons(value) : value,
|
||||
markedOptions
|
||||
);
|
||||
|
||||
|
||||
@@ -406,6 +406,7 @@ export interface IActionBarOptions {
|
||||
animated?: boolean;
|
||||
triggerKeys?: ActionTrigger;
|
||||
allowContextMenu?: boolean;
|
||||
preventLoopNavigation?: boolean;
|
||||
}
|
||||
|
||||
const defaultOptions: IActionBarOptions = {
|
||||
@@ -509,9 +510,9 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
let eventHandled = true;
|
||||
|
||||
if (event.equals(previousKey)) {
|
||||
this.focusPrevious();
|
||||
eventHandled = this.focusPrevious();
|
||||
} else if (event.equals(nextKey)) {
|
||||
this.focusNext();
|
||||
eventHandled = this.focusNext();
|
||||
} else if (event.equals(KeyCode.Escape)) {
|
||||
this._onDidCancel.fire();
|
||||
} else if (this.isTriggerKeyEvent(event)) {
|
||||
@@ -724,7 +725,7 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
|
||||
if (selectFirst && typeof this.focusedItem === 'undefined') {
|
||||
// Focus the first enabled item
|
||||
this.focusedItem = this.viewItems.length - 1;
|
||||
this.focusedItem = -1;
|
||||
this.focusNext();
|
||||
} else {
|
||||
if (index !== undefined) {
|
||||
@@ -735,7 +736,7 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
}
|
||||
}
|
||||
|
||||
protected focusNext(): void {
|
||||
protected focusNext(): boolean {
|
||||
if (typeof this.focusedItem === 'undefined') {
|
||||
this.focusedItem = this.viewItems.length - 1;
|
||||
}
|
||||
@@ -744,6 +745,11 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
let item: IActionViewItem;
|
||||
|
||||
do {
|
||||
if (this.options.preventLoopNavigation && this.focusedItem + 1 >= this.viewItems.length) {
|
||||
this.focusedItem = startIndex;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.focusedItem = (this.focusedItem + 1) % this.viewItems.length;
|
||||
item = this.viewItems[this.focusedItem];
|
||||
} while (this.focusedItem !== startIndex && !item.isEnabled());
|
||||
@@ -753,9 +759,10 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
}
|
||||
|
||||
this.updateFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected focusPrevious(): void {
|
||||
protected focusPrevious(): boolean {
|
||||
if (typeof this.focusedItem === 'undefined') {
|
||||
this.focusedItem = 0;
|
||||
}
|
||||
@@ -767,6 +774,11 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
this.focusedItem = this.focusedItem - 1;
|
||||
|
||||
if (this.focusedItem < 0) {
|
||||
if (this.options.preventLoopNavigation) {
|
||||
this.focusedItem = startIndex;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.focusedItem = this.viewItems.length - 1;
|
||||
}
|
||||
|
||||
@@ -778,6 +790,7 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
}
|
||||
|
||||
this.updateFocus(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected updateFocus(fromRight?: boolean, preventScroll?: boolean): void {
|
||||
|
||||
Binary file not shown.
@@ -162,6 +162,7 @@ export class ContextView extends Disposable {
|
||||
this.view.className = 'context-view';
|
||||
this.view.style.top = '0px';
|
||||
this.view.style.left = '0px';
|
||||
this.view.style.position = this.useFixedPosition ? 'fixed' : 'absolute';
|
||||
DOM.show(this.view);
|
||||
|
||||
// Render content
|
||||
|
||||
@@ -175,8 +175,8 @@ export class InputBox extends Widget {
|
||||
this.input.setAttribute('autocapitalize', 'off');
|
||||
this.input.setAttribute('spellcheck', 'false');
|
||||
|
||||
this.onfocus(this.input, () => dom.addClass(this.element, 'synthetic-focus'));
|
||||
this.onblur(this.input, () => dom.removeClass(this.element, 'synthetic-focus'));
|
||||
this.onfocus(this.input, () => this.element.classList.add('synthetic-focus'));
|
||||
this.onblur(this.input, () => this.element.classList.remove('synthetic-focus'));
|
||||
|
||||
if (this.options.flexibleHeight) {
|
||||
this.maxHeight = typeof this.options.flexibleMaxHeight === 'number' ? this.options.flexibleMaxHeight : Number.POSITIVE_INFINITY;
|
||||
@@ -392,11 +392,11 @@ export class InputBox extends Widget {
|
||||
public showMessage(message: IMessage, force?: boolean): void {
|
||||
this.message = message;
|
||||
|
||||
dom.removeClass(this.element, 'idle');
|
||||
dom.removeClass(this.element, 'info');
|
||||
dom.removeClass(this.element, 'warning');
|
||||
dom.removeClass(this.element, 'error');
|
||||
dom.addClass(this.element, this.classForType(message.type));
|
||||
this.element.classList.remove('idle');
|
||||
this.element.classList.remove('info');
|
||||
this.element.classList.remove('warning');
|
||||
this.element.classList.remove('error');
|
||||
this.element.classList.add(this.classForType(message.type));
|
||||
|
||||
const styles = this.stylesForType(this.message.type);
|
||||
this.element.style.border = styles.border ? `1px solid ${styles.border}` : '';
|
||||
@@ -409,10 +409,10 @@ export class InputBox extends Widget {
|
||||
public hideMessage(): void {
|
||||
this.message = null;
|
||||
|
||||
dom.removeClass(this.element, 'info');
|
||||
dom.removeClass(this.element, 'warning');
|
||||
dom.removeClass(this.element, 'error');
|
||||
dom.addClass(this.element, 'idle');
|
||||
this.element.classList.remove('info');
|
||||
this.element.classList.remove('warning');
|
||||
this.element.classList.remove('error');
|
||||
this.element.classList.add('idle');
|
||||
|
||||
this._hideMessage();
|
||||
this.applyStyles();
|
||||
@@ -494,7 +494,7 @@ export class InputBox extends Widget {
|
||||
const spanElement = (this.message.formatContent
|
||||
? renderFormattedText(this.message.content, renderOptions)
|
||||
: renderText(this.message.content, renderOptions));
|
||||
dom.addClass(spanElement, this.classForType(this.message.type));
|
||||
spanElement.classList.add(this.classForType(this.message.type));
|
||||
|
||||
const styles = this.stylesForType(this.message.type);
|
||||
spanElement.style.backgroundColor = styles.background ? styles.background.toString() : '';
|
||||
@@ -543,7 +543,7 @@ export class InputBox extends Widget {
|
||||
|
||||
this.validate();
|
||||
this.updateMirror();
|
||||
dom.toggleClass(this.input, 'empty', !this.value);
|
||||
this.input.classList.toggle('empty', !this.value);
|
||||
|
||||
if (this.state === 'open' && this.contextViewProvider) {
|
||||
this.contextViewProvider.layout();
|
||||
|
||||
@@ -411,7 +411,6 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
if (this.supportDynamicHeights) {
|
||||
this._rerender(this.lastRenderTop, this.lastRenderHeight);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
splice(start: number, deleteCount: number, elements: T[] = []): T[] {
|
||||
@@ -790,8 +789,8 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
item.dragStartDisposable.dispose();
|
||||
|
||||
const renderer = this.renderers.get(item.templateId);
|
||||
if (renderer && renderer.disposeElement) {
|
||||
renderer.disposeElement(item.element, index, item.row!.templateData, item.size);
|
||||
if (item.row && renderer && renderer.disposeElement) {
|
||||
renderer.disposeElement(item.element, index, item.row.templateData, item.size);
|
||||
}
|
||||
|
||||
this.cache.release(item.row!);
|
||||
|
||||
@@ -854,6 +854,7 @@ export interface IListOptions<T> {
|
||||
readonly horizontalScrolling?: boolean;
|
||||
readonly additionalScrollHeight?: number;
|
||||
readonly transformOptimization?: boolean;
|
||||
readonly smoothScrolling?: boolean;
|
||||
}
|
||||
|
||||
export interface IListStyles {
|
||||
|
||||
@@ -395,10 +395,9 @@ class BaseMenuActionViewItem extends BaseActionViewItem {
|
||||
}
|
||||
|
||||
this._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => {
|
||||
if (e.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
// removed default prevention as it conflicts
|
||||
// with BaseActionViewItem #101537
|
||||
// add back if issues arise and link new issue
|
||||
EventHelper.stop(e, true);
|
||||
this.onClick(e);
|
||||
}));
|
||||
|
||||
@@ -326,7 +326,15 @@ export class MenuBar extends Disposable {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
let eventHandled = true;
|
||||
|
||||
if ((event.equals(KeyCode.DownArrow) || event.equals(KeyCode.Enter) || (this.options.compactMode !== undefined && event.equals(KeyCode.Space))) && !this.isOpen) {
|
||||
const triggerKeys = [KeyCode.Enter];
|
||||
if (this.options.compactMode === undefined) {
|
||||
triggerKeys.push(KeyCode.DownArrow);
|
||||
} else {
|
||||
triggerKeys.push(KeyCode.Space);
|
||||
triggerKeys.push(this.options.compactMode === Direction.Right ? KeyCode.RightArrow : KeyCode.LeftArrow);
|
||||
}
|
||||
|
||||
if ((triggerKeys.some(k => event.equals(k)) && !this.isOpen)) {
|
||||
this.focusedMenu = { index: MenuBar.OVERFLOW_INDEX };
|
||||
this.openedViaKeyboard = true;
|
||||
this.focusState = MenubarState.OPEN;
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { INewScrollDimensions, INewScrollPosition, IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { getZoomFactor } from 'vs/base/browser/browser';
|
||||
|
||||
const HIDE_TIMEOUT = 500;
|
||||
const SCROLL_WHEEL_SENSITIVITY = 50;
|
||||
@@ -130,13 +131,18 @@ export class MouseWheelClassifier {
|
||||
// }
|
||||
}
|
||||
|
||||
if (Math.abs(item.deltaX - Math.round(item.deltaX)) > 0 || Math.abs(item.deltaY - Math.round(item.deltaY)) > 0) {
|
||||
if (!this._isAlmostInt(item.deltaX) || !this._isAlmostInt(item.deltaY)) {
|
||||
// non-integer deltas => indicator that this is not a physical mouse wheel
|
||||
score += 0.25;
|
||||
}
|
||||
|
||||
return Math.min(Math.max(score, 0), 1);
|
||||
}
|
||||
|
||||
private _isAlmostInt(value: number): boolean {
|
||||
const delta = Math.abs(Math.round(value) - value);
|
||||
return (delta < 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AbstractScrollableElement extends Widget {
|
||||
@@ -343,10 +349,11 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
|
||||
const classifier = MouseWheelClassifier.INSTANCE;
|
||||
if (SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED) {
|
||||
if (platform.isWindows) {
|
||||
// On Windows, the incoming delta events are multiplied with the device pixel ratio,
|
||||
// so to get a better classification, simply undo that.
|
||||
classifier.accept(Date.now(), e.deltaX / window.devicePixelRatio, e.deltaY / window.devicePixelRatio);
|
||||
const osZoomFactor = window.devicePixelRatio / getZoomFactor();
|
||||
if (platform.isWindows || platform.isLinux) {
|
||||
// On Windows and Linux, the incoming delta events are multiplied with the OS zoom factor.
|
||||
// The OS zoom factor can be reverse engineered by using the device pixel ratio and the configured zoom factor into account.
|
||||
classifier.accept(Date.now(), e.deltaX / osZoomFactor, e.deltaY / osZoomFactor);
|
||||
} else {
|
||||
classifier.accept(Date.now(), e.deltaX, e.deltaY);
|
||||
}
|
||||
|
||||
@@ -951,6 +951,7 @@ export interface IAbstractTreeOptionsUpdate extends ITreeRendererOptions {
|
||||
readonly filterOnType?: boolean;
|
||||
readonly smoothScrolling?: boolean;
|
||||
readonly horizontalScrolling?: boolean;
|
||||
readonly expandOnlyOnDoubleClick?: boolean;
|
||||
}
|
||||
|
||||
export interface IAbstractTreeOptions<T, TFilterData = void> extends IAbstractTreeOptionsUpdate, IListOptions<T> {
|
||||
@@ -1094,7 +1095,10 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
|
||||
return super.onViewPointer(e);
|
||||
}
|
||||
|
||||
const onTwistie = hasClass(e.browserEvent.target as HTMLElement, 'monaco-tl-twistie');
|
||||
const target = e.browserEvent.target as HTMLElement;
|
||||
const onTwistie = hasClass(target, 'monaco-tl-twistie')
|
||||
|| (hasClass(target, 'monaco-icon-label') && hasClass(target, 'folder-icon') && e.browserEvent.offsetX < 16);
|
||||
|
||||
let expandOnlyOnTwistieClick = false;
|
||||
|
||||
if (typeof this.tree.expandOnlyOnTwistieClick === 'function') {
|
||||
@@ -1107,6 +1111,10 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
|
||||
return super.onViewPointer(e);
|
||||
}
|
||||
|
||||
if (this.tree.expandOnlyOnDoubleClick && e.browserEvent.detail !== 2 && !onTwistie) {
|
||||
return super.onViewPointer(e);
|
||||
}
|
||||
|
||||
if (node.collapsible) {
|
||||
const model = ((this.tree as any).model as ITreeModel<T, TFilterData, TRef>); // internal
|
||||
const location = model.getNodeLocation(node);
|
||||
@@ -1244,6 +1252,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
||||
get filterOnType(): boolean { return !!this._options.filterOnType; }
|
||||
get onDidChangeTypeFilterPattern(): Event<string> { return this.typeFilterController ? this.typeFilterController.onDidChangePattern : Event.None; }
|
||||
|
||||
get expandOnlyOnDoubleClick(): boolean { return this._options.expandOnlyOnDoubleClick ?? false; }
|
||||
get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; }
|
||||
|
||||
private readonly _onDidUpdateOptions = new Emitter<IAbstractTreeOptions<T, TFilterData>>();
|
||||
|
||||
@@ -591,6 +591,14 @@ export function asArray<T>(x: T | T[]): T[] {
|
||||
return Array.isArray(x) ? x : [x];
|
||||
}
|
||||
|
||||
export function toArray<T>(iterable: IterableIterator<T>): T[] {
|
||||
const result: T[] = [];
|
||||
for (let element of iterable) {
|
||||
result.push(element);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getRandomElement<T>(arr: T[]): T | undefined {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ export class Codicon {
|
||||
_registry.add(this);
|
||||
}
|
||||
public get classNames() { return 'codicon codicon-' + this.id; }
|
||||
// classNamesArray is useful for migrating to ES6 classlist
|
||||
public get classNamesArray() { return ['codicon', 'codicon-' + this.id]; }
|
||||
public get cssSelector() { return '.codicon.codicon-' + this.id; }
|
||||
}
|
||||
|
||||
@@ -472,6 +474,8 @@ export namespace Codicon {
|
||||
export const stopCircle = new Codicon('stop-circle', { character: '\\eba5' });
|
||||
export const playCircle = new Codicon('play-circle', { character: '\\eba6' });
|
||||
export const record = new Codicon('record', { character: '\\eba7' });
|
||||
export const debugAltSmall = new Codicon('debug-alt-small', { character: '\\eba8' });
|
||||
export const vmConnect = new Codicon('vm-connect', { character: '\\eba9' });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -203,3 +203,12 @@ export class NotImplementedError extends Error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class NotSupportedError extends Error {
|
||||
constructor(message?: string) {
|
||||
super('NotSupported');
|
||||
if (message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,7 @@ export function scoreFuzzy(target: string, query: string, queryLower: string, fu
|
||||
// When not searching fuzzy, we require the query to be contained fully
|
||||
// in the target string contiguously.
|
||||
if (!fuzzy) {
|
||||
const indexOfQueryInTarget = targetLower.indexOf(queryLower);
|
||||
if (indexOfQueryInTarget === -1) {
|
||||
if (!targetLower.includes(queryLower)) {
|
||||
// if (DEBUG) {
|
||||
// console.log(`Characters not matching consecutively ${queryLower} within ${targetLower}`);
|
||||
// }
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import { UriComponents } from 'vs/base/common/uri';
|
||||
import { escapeCodicons } from 'vs/base/common/codicons';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
|
||||
export interface IMarkdownString {
|
||||
readonly value: string;
|
||||
@@ -22,6 +23,10 @@ export class MarkdownString implements IMarkdownString {
|
||||
private _value: string = '',
|
||||
isTrustedOrOptions: boolean | { isTrusted?: boolean, supportThemeIcons?: boolean } = false,
|
||||
) {
|
||||
if (typeof this._value !== 'string') {
|
||||
throw illegalArgument('value');
|
||||
}
|
||||
|
||||
if (typeof isTrustedOrOptions === 'boolean') {
|
||||
this._isTrusted = isTrustedOrOptions;
|
||||
this._supportThemeIcons = false;
|
||||
@@ -30,7 +35,6 @@ export class MarkdownString implements IMarkdownString {
|
||||
this._isTrusted = isTrustedOrOptions.isTrusted ?? false;
|
||||
this._supportThemeIcons = isTrustedOrOptions.supportThemeIcons ?? false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
get value() { return this._value; }
|
||||
|
||||
@@ -9,27 +9,6 @@ import { compareSubstringIgnoreCase, compare, compareSubstring } from 'vs/base/c
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
|
||||
/**
|
||||
* @deprecated ES6: use `[...SetOrMap.values()]`
|
||||
*/
|
||||
export function values<V = any>(set: Set<V>): V[];
|
||||
export function values<K = any, V = any>(map: Map<K, V>): V[];
|
||||
export function values<V>(forEachable: { forEach(callback: (value: V, ...more: any[]) => any): void }): V[] {
|
||||
const result: V[] = [];
|
||||
forEachable.forEach(value => result.push(value));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated ES6: use `[...map.keys()]`
|
||||
*/
|
||||
export function keys<K, V>(map: Map<K, V>): K[] {
|
||||
const result: K[] = [];
|
||||
map.forEach((_value, key) => result.push(key));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getOrSet<K, V>(map: Map<K, V>, key: K, value: V): V {
|
||||
let result = map.get(key);
|
||||
if (result === undefined) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { basename, posix, extname } from 'vs/base/common/path';
|
||||
import { startsWithUTF8BOM } from 'vs/base/common/strings';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { match } from 'vs/base/common/glob';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -247,34 +246,6 @@ export function isUnspecific(mime: string[] | string): boolean {
|
||||
return mime.length === 1 && isUnspecific(mime[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suggestion for the filename by the following logic:
|
||||
* 1. If a relevant extension exists and is an actual filename extension (starting with a dot), suggest the prefix appended by the first one.
|
||||
* 2. Otherwise, if there are other extensions, suggest the first one.
|
||||
* 3. Otherwise, suggest the prefix.
|
||||
*/
|
||||
export function suggestFilename(mode: string | undefined, prefix: string): string {
|
||||
const extensions = registeredAssociations
|
||||
.filter(assoc => !assoc.userConfigured && assoc.extension && assoc.id === mode)
|
||||
.map(assoc => assoc.extension);
|
||||
|
||||
const extensionsWithDotFirst = coalesce(extensions)
|
||||
.filter(assoc => assoc.startsWith('.'));
|
||||
|
||||
if (extensionsWithDotFirst.length > 0) {
|
||||
const candidateExtension = extensionsWithDotFirst[0];
|
||||
if (prefix.endsWith(candidateExtension)) {
|
||||
// do not add the prefix if it already exists
|
||||
// https://github.com/microsoft/vscode/issues/83603
|
||||
return prefix;
|
||||
}
|
||||
|
||||
return prefix + candidateExtension;
|
||||
}
|
||||
|
||||
return extensions[0] || prefix;
|
||||
}
|
||||
|
||||
interface MapExtToMediaMimes {
|
||||
[index: string]: string;
|
||||
}
|
||||
|
||||
@@ -9,22 +9,22 @@
|
||||
|
||||
function _factory(sharedObj) {
|
||||
|
||||
sharedObj._performanceEntries = sharedObj._performanceEntries || [];
|
||||
sharedObj.MonacoPerformanceMarks = sharedObj.MonacoPerformanceMarks || [];
|
||||
|
||||
const _dataLen = 2;
|
||||
const _timeStamp = typeof console.timeStamp === 'function' ? console.timeStamp.bind(console) : () => { };
|
||||
|
||||
function importEntries(entries) {
|
||||
sharedObj._performanceEntries.splice(0, 0, ...entries);
|
||||
sharedObj.MonacoPerformanceMarks.splice(0, 0, ...entries);
|
||||
}
|
||||
|
||||
function exportEntries() {
|
||||
return sharedObj._performanceEntries.slice(0);
|
||||
return sharedObj.MonacoPerformanceMarks.slice(0);
|
||||
}
|
||||
|
||||
function getEntries() {
|
||||
const result = [];
|
||||
const entries = sharedObj._performanceEntries;
|
||||
const entries = sharedObj.MonacoPerformanceMarks;
|
||||
for (let i = 0; i < entries.length; i += _dataLen) {
|
||||
result.push({
|
||||
name: entries[i],
|
||||
@@ -35,7 +35,7 @@ function _factory(sharedObj) {
|
||||
}
|
||||
|
||||
function getDuration(from, to) {
|
||||
const entries = sharedObj._performanceEntries;
|
||||
const entries = sharedObj.MonacoPerformanceMarks;
|
||||
let target = to;
|
||||
let endIndex = 0;
|
||||
for (let i = entries.length - _dataLen; i >= 0; i -= _dataLen) {
|
||||
@@ -54,7 +54,7 @@ function _factory(sharedObj) {
|
||||
}
|
||||
|
||||
function mark(name) {
|
||||
sharedObj._performanceEntries.push(name, Date.now());
|
||||
sharedObj.MonacoPerformanceMarks.push(name, Date.now());
|
||||
_timeStamp(name);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@ function _factory(sharedObj) {
|
||||
// Because we want both instances to use the same perf-data
|
||||
// we store them globally
|
||||
|
||||
let sharedObj;
|
||||
// eslint-disable-next-line no-var
|
||||
var sharedObj;
|
||||
if (typeof global === 'object') {
|
||||
// nodejs
|
||||
sharedObj = global;
|
||||
@@ -91,5 +92,5 @@ if (typeof define === 'function') {
|
||||
// commonjs
|
||||
module.exports = _factory(sharedObj);
|
||||
} else {
|
||||
// invalid context...
|
||||
sharedObj.perf = _factory(sharedObj);
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@ export function peekReadable<T>(readable: Readable<T>, reducer: IReducer<T>, max
|
||||
/**
|
||||
* Helper to fully read a T stream into a T.
|
||||
*/
|
||||
export function consumeStream<T>(stream: ReadableStream<T>, reducer: IReducer<T>): Promise<T> {
|
||||
export function consumeStream<T>(stream: ReadableStreamEvents<T>, reducer: IReducer<T>): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks: T[] = [];
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
/**
|
||||
* @returns whether the provided parameter is a JavaScript Array or not.
|
||||
*/
|
||||
export function isArray(array: any): array is any[] {
|
||||
export function isArray<T>(array: T | {}): array is T extends readonly any[] ? (unknown extends T ? never : readonly any[]) : any[] {
|
||||
return Array.isArray(array);
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ export function validateConstraint(arg: any, constraint: TypeConstraint | undefi
|
||||
if (arg instanceof constraint) {
|
||||
return;
|
||||
}
|
||||
} catch{
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
if (!isUndefinedOrNull(arg) && arg.constructor === constraint) {
|
||||
|
||||
@@ -252,7 +252,7 @@ export class URI implements UriComponents {
|
||||
return this;
|
||||
}
|
||||
|
||||
return new _URI(scheme, authority, path, query, fragment);
|
||||
return new CachingURI(scheme, authority, path, query, fragment);
|
||||
}
|
||||
|
||||
// ---- parse & validate ------------------------
|
||||
@@ -266,9 +266,9 @@ export class URI implements UriComponents {
|
||||
static parse(value: string, _strict: boolean = false): URI {
|
||||
const match = _regexp.exec(value);
|
||||
if (!match) {
|
||||
return new _URI(_empty, _empty, _empty, _empty, _empty);
|
||||
return new CachingURI(_empty, _empty, _empty, _empty, _empty);
|
||||
}
|
||||
return new _URI(
|
||||
return new CachingURI(
|
||||
match[2] || _empty,
|
||||
percentDecode(match[4] || _empty),
|
||||
percentDecode(match[5] || _empty),
|
||||
@@ -323,11 +323,11 @@ export class URI implements UriComponents {
|
||||
}
|
||||
}
|
||||
|
||||
return new _URI('file', authority, path, _empty, _empty);
|
||||
return new CachingURI('file', authority, path, _empty, _empty);
|
||||
}
|
||||
|
||||
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
|
||||
return new _URI(
|
||||
return new CachingURI(
|
||||
components.scheme,
|
||||
components.authority,
|
||||
components.path,
|
||||
@@ -388,7 +388,7 @@ export class URI implements UriComponents {
|
||||
} else if (data instanceof URI) {
|
||||
return data;
|
||||
} else {
|
||||
const result = new _URI(data);
|
||||
const result = new CachingURI(data);
|
||||
result._formatted = (<UriState>data).external;
|
||||
result._fsPath = (<UriState>data)._sep === _pathSepMarker ? (<UriState>data).fsPath : null;
|
||||
return result;
|
||||
@@ -413,8 +413,8 @@ interface UriState extends UriComponents {
|
||||
|
||||
const _pathSepMarker = isWindows ? 1 : undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
class _URI extends URI {
|
||||
// This class exists so that URI is compatibile with vscode.Uri (API).
|
||||
class CachingURI extends URI {
|
||||
|
||||
_formatted: string | null = null;
|
||||
_fsPath: string | null = null;
|
||||
|
||||
@@ -457,7 +457,7 @@ export namespace win32 {
|
||||
|
||||
async function fileExists(path: string): Promise<boolean> {
|
||||
if (await promisify(fs.exists)(path)) {
|
||||
return !((await promisify(fs.stat)(path)).isDirectory);
|
||||
return !((await promisify(fs.stat)(path)).isDirectory());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,7 @@ export interface IPopupOptions {
|
||||
x?: number;
|
||||
y?: number;
|
||||
positioningItem?: number;
|
||||
onHide?: () => void;
|
||||
}
|
||||
|
||||
export const CONTEXT_MENU_CHANNEL = 'vscode:contextmenu';
|
||||
export const CONTEXT_MENU_CLOSE_CHANNEL = 'vscode:onCloseContextMenu';
|
||||
export const CONTEXT_MENU_CLOSE_CHANNEL = 'vscode:onCloseContextMenu';
|
||||
|
||||
@@ -9,9 +9,10 @@ import { ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHANNEL, CONTEXT_MENU_
|
||||
export function registerContextMenuListener(): void {
|
||||
ipcMain.on(CONTEXT_MENU_CHANNEL, (event: IpcMainEvent, contextMenuId: number, items: ISerializableContextMenuItem[], onClickChannel: string, options?: IPopupOptions) => {
|
||||
const menu = createMenu(event, onClickChannel, items);
|
||||
const window = BrowserWindow.fromWebContents(event.sender);
|
||||
|
||||
menu.popup({
|
||||
window: BrowserWindow.fromWebContents(event.sender),
|
||||
window: window ? window : undefined,
|
||||
x: options ? options.x : undefined,
|
||||
y: options ? options.y : undefined,
|
||||
positioningItem: options ? options.positioningItem : undefined,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IContextMenuItem, ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHAN
|
||||
|
||||
let contextMenuIdPool = 0;
|
||||
|
||||
export function popup(items: IContextMenuItem[], options?: IPopupOptions): void {
|
||||
export function popup(items: IContextMenuItem[], options?: IPopupOptions, onHide?: () => void): void {
|
||||
const processedItems: IContextMenuItem[] = [];
|
||||
|
||||
const contextMenuId = contextMenuIdPool++;
|
||||
@@ -28,8 +28,8 @@ export function popup(items: IContextMenuItem[], options?: IPopupOptions): void
|
||||
|
||||
ipcRenderer.removeListener(onClickChannel, onClickChannelHandler);
|
||||
|
||||
if (options?.onHide) {
|
||||
options.onHide();
|
||||
if (onHide) {
|
||||
onHide();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1230,10 +1230,10 @@ export class QuickInputController extends Disposable {
|
||||
this.previousFocusElement = e.relatedTarget instanceof HTMLElement ? e.relatedTarget : undefined;
|
||||
}, true));
|
||||
this._register(focusTracker.onDidBlur(() => {
|
||||
this.previousFocusElement = undefined;
|
||||
if (!this.getUI().ignoreFocusOut && !this.options.ignoreFocusOut()) {
|
||||
this.hide(true);
|
||||
this.hide();
|
||||
}
|
||||
this.previousFocusElement = undefined;
|
||||
}));
|
||||
this._register(dom.addDisposableListener(container, dom.EventType.FOCUS, (e: FocusEvent) => {
|
||||
inputBox.setFocus();
|
||||
@@ -1574,13 +1574,14 @@ export class QuickInputController extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
hide(focusLost?: boolean) {
|
||||
hide() {
|
||||
const controller = this.controller;
|
||||
if (controller) {
|
||||
const focusChanged = !this.ui?.container.contains(document.activeElement);
|
||||
this.controller = null;
|
||||
this.onHideEmitter.fire();
|
||||
this.getUI().container.style.display = 'none';
|
||||
if (!focusLost) {
|
||||
if (!focusChanged) {
|
||||
if (this.previousFocusElement && this.previousFocusElement.offsetParent) {
|
||||
this.previousFocusElement.focus();
|
||||
this.previousFocusElement = undefined;
|
||||
|
||||
@@ -68,14 +68,6 @@
|
||||
*/
|
||||
webFrame: {
|
||||
|
||||
getZoomFactor() {
|
||||
return webFrame.getZoomFactor();
|
||||
},
|
||||
|
||||
getZoomLevel() {
|
||||
return webFrame.getZoomLevel();
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} level
|
||||
*/
|
||||
|
||||
@@ -43,16 +43,6 @@ export const ipcRenderer = (window as any).vscode.ipcRenderer as {
|
||||
|
||||
export const webFrame = (window as any).vscode.webFrame as {
|
||||
|
||||
/**
|
||||
* The current zoom factor.
|
||||
*/
|
||||
getZoomFactor(): number;
|
||||
|
||||
/**
|
||||
* The current zoom level.
|
||||
*/
|
||||
getZoomLevel(): number;
|
||||
|
||||
/**
|
||||
* Changes the zoom level to the specified level. The original size is 0 and each
|
||||
* increment above or below represents zooming 20% larger or smaller to default
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { guessMimeTypes, registerTextMime, suggestFilename } from 'vs/base/common/mime';
|
||||
import { guessMimeTypes, registerTextMime } from 'vs/base/common/mime';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
suite('Mime', () => {
|
||||
@@ -126,53 +126,4 @@ suite('Mime', () => {
|
||||
|
||||
assert.deepEqual(guessMimeTypes(URI.parse(`data:;label:something.data;description:data,`)), ['text/data', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Filename Suggestion - Suggest prefix only when there are no relevant extensions', () => {
|
||||
const id = 'plumbus0';
|
||||
const mime = `text/${id}`;
|
||||
for (let extension of ['one', 'two']) {
|
||||
registerTextMime({ id, mime, extension });
|
||||
}
|
||||
|
||||
let suggested = suggestFilename('shleem', 'Untitled-1');
|
||||
assert.equal(suggested, 'Untitled-1');
|
||||
});
|
||||
|
||||
test('Filename Suggestion - Suggest prefix with first extension that begins with a dot', () => {
|
||||
const id = 'plumbus1';
|
||||
const mime = `text/${id}`;
|
||||
for (let extension of ['plumbus', '.shleem', '.gazorpazorp']) {
|
||||
registerTextMime({ id, mime, extension });
|
||||
}
|
||||
|
||||
let suggested = suggestFilename('plumbus1', 'Untitled-1');
|
||||
assert.equal(suggested, 'Untitled-1.shleem');
|
||||
});
|
||||
|
||||
test('Filename Suggestion - Suggest first relevant extension when there are none that begin with a dot', () => {
|
||||
const id = 'plumbus2';
|
||||
const mime = `text/${id}`;
|
||||
for (let extension of ['plumbus', 'shleem', 'gazorpazorp']) {
|
||||
registerTextMime({ id, mime, extension });
|
||||
}
|
||||
|
||||
let suggested = suggestFilename('plumbus2', 'Untitled-1');
|
||||
assert.equal(suggested, 'plumbus');
|
||||
});
|
||||
|
||||
test('Filename Suggestion - Should ignore user-configured associations', () => {
|
||||
registerTextMime({ id: 'plumbus3', mime: 'text/plumbus3', extension: 'plumbus', userConfigured: true });
|
||||
registerTextMime({ id: 'plumbus3', mime: 'text/plumbus3', extension: '.shleem', userConfigured: true });
|
||||
registerTextMime({ id: 'plumbus3', mime: 'text/plumbus3', extension: '.gazorpazorp', userConfigured: false });
|
||||
|
||||
let suggested = suggestFilename('plumbus3', 'Untitled-1');
|
||||
assert.equal(suggested, 'Untitled-1.gazorpazorp');
|
||||
|
||||
registerTextMime({ id: 'plumbus4', mime: 'text/plumbus4', extension: 'plumbus', userConfigured: true });
|
||||
registerTextMime({ id: 'plumbus4', mime: 'text/plumbus4', extension: '.shleem', userConfigured: true });
|
||||
registerTextMime({ id: 'plumbus4', mime: 'text/plumbus4', extension: '.gazorpazorp', userConfigured: true });
|
||||
|
||||
suggested = suggestFilename('plumbus4', 'Untitled-1');
|
||||
assert.equal(suggested, 'Untitled-1');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user