Merge branch 'ads-main-vscode-2020-07-15T23-51-12' into main

This commit is contained in:
cssuh
2020-07-17 15:00:28 -04:00
558 changed files with 15180 additions and 8232 deletions
+6 -3
View File
@@ -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
);
+18 -5
View File
@@ -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
+13 -13
View File
@@ -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();
+2 -3
View File
@@ -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 {
+3 -4
View File
@@ -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);
}));
+9 -1
View File
@@ -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);
}
+10 -1
View File
@@ -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>>();
+8
View File
@@ -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)];
}
+4
View File
@@ -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' });
}
+9
View File
@@ -203,3 +203,12 @@ export class NotImplementedError extends Error {
}
}
}
export class NotSupportedError extends Error {
constructor(message?: string) {
super('NotSupported');
if (message) {
this.message = message;
}
}
}
+1 -2
View File
@@ -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}`);
// }
+5 -1
View File
@@ -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; }
-21
View File
@@ -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) {
-29
View File
@@ -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 -8
View File
@@ -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);
}
+1 -1
View File
@@ -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[] = [];
+2 -2
View File
@@ -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) {
+8 -8
View File
@@ -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;
+1 -1
View File
@@ -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
+1 -50
View File
@@ -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');
});
});
@@ -2,6 +2,10 @@
<!DOCTYPE html>
<html>
<head>
<script>
globalThis.MonacoPerformanceMarks = globalThis.MonacoPerformanceMarks || [];
globalThis.MonacoPerformanceMarks.push('renderer/started', Date.now());
</script>
<meta charset="utf-8" />
<!-- Disable pinch zooming -->
@@ -29,6 +33,7 @@
// NOTE: Changes to inline scripts require update of content security policy
self.require = {
baseUrl: `${window.location.origin}/static/out`,
recordStats: true,
paths: {
'vscode-textmate': `${window.location.origin}/static/remote/web/node_modules/vscode-textmate/release/main`,
'vscode-oniguruma': `${window.location.origin}/static/remote/web/node_modules/vscode-oniguruma/release/main`,
@@ -90,7 +95,11 @@
<script src="./static/remote/web/node_modules/slickgrid/plugins/slick.cellrangedecorator.js"></script>
<script src="./static/remote/web/node_modules/zone.js/dist/zone.min.js"></script>
<script src="./static/remote/web/node_modules/reflect-metadata/Reflect.js"></script>
<script src="./static/out/vs/base/common/performance.js"></script>
<script src="./static/out/vs/loader.js"></script>
<script>
globalThis.MonacoPerformanceMarks.push('willLoadWorkbenchMain', Date.now());
</script>
<script>
// NOTE: Changes to inline scripts require update of content security policy
require(['vs/code/browser/workbench/workbench'], function() {});
@@ -2,6 +2,10 @@
<!DOCTYPE html>
<html>
<head>
<script>
globalThis.MonacoPerformanceMarks = globalThis.MonacoPerformanceMarks || [];
globalThis.MonacoPerformanceMarks.push('renderer/started', Date.now());
</script>
<meta charset="utf-8" />
<!-- Disable pinch zooming -->
@@ -30,6 +34,7 @@
// NOTE: Changes to inline scripts require update of content security policy
self.require = {
baseUrl: `${window.location.origin}/static/out`,
recordStats: true,
paths: {
'vscode-textmate': `${window.location.origin}/static/node_modules/vscode-textmate/release/main`,
'vscode-oniguruma': `${window.location.origin}/static/node_modules/vscode-oniguruma/release/main`,
@@ -79,6 +84,9 @@
<script src="./static/node_modules/zone.js/dist/zone.min.js"></script>
<script src="./static/node_modules/reflect-metadata/Reflect.js"></script>
<script src="./static/out/vs/loader.js"></script>
<script>
globalThis.MonacoPerformanceMarks.push('willLoadWorkbenchMain', Date.now());
</script>
<script src="./static/out/vs/workbench/workbench.web.api.nls.js"></script>
<script src="./static/out/vs/workbench/workbench.web.api.js"></script>
<script src="./static/out/vs/code/browser/workbench/workbench.js"></script>
@@ -12,6 +12,7 @@ import { request } from 'vs/base/parts/request/browser/request';
import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows';
import { isEqual } from 'vs/base/common/resources';
import { isStandalone } from 'vs/base/browser/browser';
import { mark } from 'vs/base/common/performance';
interface ICredential {
service: string;
@@ -277,6 +278,10 @@ class WorkspaceProvider implements IWorkspaceProvider {
(function () {
// Mark start of workbench
mark('didLoadWorkbenchMain');
performance.mark('workbench-start');
// Find config by checking for DOM
const configElement = document.getElementById('vscode-workbench-web-configuration');
const configElementAttribute = configElement ? configElement.getAttribute('data-settings') : undefined;
@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/issueReporter';
import { ElectronService, IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
import { ipcRenderer, webFrame } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import 'vs/base/browser/ui/codicons/codiconStyles'; // make sure codicon css is loaded
import * as os from 'os';
import * as browser from 'vs/base/browser/browser';
import { ElectronService, IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox/window';
import { $, windowOpenNoOpener, addClass } from 'vs/base/browser/dom';
import { Button } from 'vs/base/browser/ui/button/button';
import 'vs/base/browser/ui/codicons/codiconStyles'; // make sure codicon css is loaded
import { CodiconLabel } from 'vs/base/browser/ui/codicons/codiconLabel';
import * as collections from 'vs/base/common/collections';
import { debounce } from 'vs/base/common/decorators';
@@ -152,7 +152,7 @@ export class IssueReporter extends Disposable {
this.setUpTypes();
this.setEventHandlers();
this.applyZoom(configuration.data.zoomLevel);
applyZoom(configuration.data.zoomLevel);
this.applyStyles(configuration.data.styles);
this.handleExtensionData(configuration.data.enabledExtensions);
@@ -180,15 +180,6 @@ export class IssueReporter extends Disposable {
}
}
private applyZoom(zoomLevel: number) {
webFrame.setZoomLevel(zoomLevel);
browser.setZoomFactor(webFrame.getZoomFactor());
// See https://github.com/Microsoft/vscode/issues/26151
// Cannot be trusted because the webFrame might take some time
// until it really applies the new zoom level
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
}
private applyStyles(styles: IssueReporterStyles) {
const styleTag = document.createElement('style');
const content: string[] = [];
@@ -505,12 +496,12 @@ export class IssueReporter extends Disposable {
// Cmd/Ctrl + zooms in
if (cmdOrCtrlKey && e.keyCode === 187) {
this.applyZoom(webFrame.getZoomLevel() + 1);
zoomIn();
}
// Cmd/Ctrl - zooms out
if (cmdOrCtrlKey && e.keyCode === 189) {
this.applyZoom(webFrame.getZoomLevel() - 1);
zoomOut();
}
// With latest electron upgrade, cmd+a is no longer propagating correctly for inputs in this window on mac
@@ -5,13 +5,12 @@
import 'vs/css!./media/processExplorer';
import { clipboard } from 'electron';
import { webFrame, ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { repeat } from 'vs/base/common/strings';
import { totalmem } from 'os';
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import product from 'vs/platform/product/common/product';
import { localize } from 'vs/nls';
import { ProcessExplorerStyles, ProcessExplorerData } from 'vs/platform/issue/common/issue';
import * as browser from 'vs/base/browser/browser';
import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox/window';
import * as platform from 'vs/base/common/platform';
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
import { popup } from 'vs/base/parts/contextmenu/electron-sandbox/contextmenu';
@@ -20,13 +19,8 @@ import { addDisposableListener, addClass } from 'vs/base/browser/dom';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
let mapPidToWindowTitle = new Map<number, string>();
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
const listeners = new DisposableStore();
const collapsedStateCache: Map<string, boolean> = new Map<string, boolean>();
let lastRequestTime: number;
interface FormattedProcessItem {
cpu: number;
@@ -37,391 +31,400 @@ interface FormattedProcessItem {
cmd: string;
}
function getProcessList(rootProcess: ProcessItem, isLocal: boolean): FormattedProcessItem[] {
const processes: FormattedProcessItem[] = [];
class ProcessExplorer {
private lastRequestTime: number;
if (rootProcess) {
getProcessItem(processes, rootProcess, 0, isLocal);
private collapsedStateCache: Map<string, boolean> = new Map<string, boolean>();
private mapPidToWindowTitle = new Map<number, string>();
private listeners = new DisposableStore();
constructor(data: ProcessExplorerData) {
this.applyStyles(data.styles);
// Map window process pids to titles, annotate process names with this when rendering to distinguish between them
ipcRenderer.on('vscode:windowsInfoResponse', (event: unknown, windows: any[]) => {
this.mapPidToWindowTitle = new Map<number, string>();
windows.forEach(window => this.mapPidToWindowTitle.set(window.pid, window.title));
});
ipcRenderer.on('vscode:listProcessesResponse', (event: unknown, processRoots: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]) => {
this.updateProcessInfo(processRoots);
this.requestProcessList(0);
});
this.lastRequestTime = Date.now();
ipcRenderer.send('vscode:windowsInfoRequest');
ipcRenderer.send('vscode:listProcesses');
}
return processes;
}
private getProcessList(rootProcess: ProcessItem, isLocal: boolean): FormattedProcessItem[] {
const processes: FormattedProcessItem[] = [];
function getProcessItem(processes: FormattedProcessItem[], item: ProcessItem, indent: number, isLocal: boolean): void {
const isRoot = (indent === 0);
if (rootProcess) {
this.getProcessItem(processes, rootProcess, 0, isLocal);
}
const MB = 1024 * 1024;
let name = item.name;
if (isRoot) {
name = isLocal ? `${product.applicationName} main` : 'remote agent';
return processes;
}
if (name === 'window') {
const windowTitle = mapPidToWindowTitle.get(item.pid);
name = windowTitle !== undefined ? `${name} (${mapPidToWindowTitle.get(item.pid)})` : name;
private getProcessItem(processes: FormattedProcessItem[], item: ProcessItem, indent: number, isLocal: boolean): void {
const isRoot = (indent === 0);
const MB = 1024 * 1024;
let name = item.name;
if (isRoot) {
name = isLocal ? `${product.applicationName} main` : 'remote agent';
}
if (name === 'window') {
const windowTitle = this.mapPidToWindowTitle.get(item.pid);
name = windowTitle !== undefined ? `${name} (${this.mapPidToWindowTitle.get(item.pid)})` : name;
}
// Format name with indent
const formattedName = isRoot ? name : `${' '.repeat(indent)} ${name}`;
const memory = process.platform === 'win32' ? item.mem : (totalmem() * (item.mem / 100));
processes.push({
cpu: item.load,
memory: (memory / MB),
pid: item.pid.toFixed(0),
name,
formattedName,
cmd: item.cmd
});
// Recurse into children if any
if (Array.isArray(item.children)) {
item.children.forEach(child => {
if (child) {
this.getProcessItem(processes, child, indent + 1, isLocal);
}
});
}
}
// Format name with indent
const formattedName = isRoot ? name : `${repeat(' ', indent)} ${name}`;
const memory = process.platform === 'win32' ? item.mem : (totalmem() * (item.mem / 100));
processes.push({
cpu: item.load,
memory: (memory / MB),
pid: item.pid.toFixed(0),
name,
formattedName,
cmd: item.cmd
});
private isDebuggable(cmd: string): boolean {
const matches = DEBUG_FLAGS_PATTERN.exec(cmd);
return (matches && matches.length >= 2) || cmd.indexOf('node ') >= 0 || cmd.indexOf('node.exe') >= 0;
}
// Recurse into children if any
if (Array.isArray(item.children)) {
item.children.forEach(child => {
if (child) {
getProcessItem(processes, child, indent + 1, isLocal);
private attachTo(item: FormattedProcessItem) {
const config: any = {
type: 'node',
request: 'attach',
name: `process ${item.pid}`
};
let matches = DEBUG_FLAGS_PATTERN.exec(item.cmd);
if (matches && matches.length >= 2) {
// attach via port
if (matches.length === 4 && matches[3]) {
config.port = parseInt(matches[3]);
}
config.protocol = matches[1] === 'debug' ? 'legacy' : 'inspector';
} else {
// no port -> try to attach via pid (send SIGUSR1)
config.processId = String(item.pid);
}
// a debug-port=n or inspect-port=n overrides the port
matches = DEBUG_PORT_PATTERN.exec(item.cmd);
if (matches && matches.length === 3) {
// override port
config.port = parseInt(matches[2]);
}
ipcRenderer.send('vscode:workbenchCommand', { id: 'debug.startFromConfig', from: 'processExplorer', args: [config] });
}
private getProcessIdWithHighestProperty(processList: any[], propertyName: string) {
let max = 0;
let maxProcessId;
processList.forEach(process => {
if (process[propertyName] > max) {
max = process[propertyName];
maxProcessId = process.pid;
}
});
return maxProcessId;
}
}
function isDebuggable(cmd: string): boolean {
const matches = DEBUG_FLAGS_PATTERN.exec(cmd);
return (matches && matches.length >= 2) || cmd.indexOf('node ') >= 0 || cmd.indexOf('node.exe') >= 0;
}
function attachTo(item: FormattedProcessItem) {
const config: any = {
type: 'node',
request: 'attach',
name: `process ${item.pid}`
};
let matches = DEBUG_FLAGS_PATTERN.exec(item.cmd);
if (matches && matches.length >= 2) {
// attach via port
if (matches.length === 4 && matches[3]) {
config.port = parseInt(matches[3]);
private updateSectionCollapsedState(shouldExpand: boolean, body: HTMLElement, twistie: HTMLImageElement, sectionName: string) {
if (shouldExpand) {
body.classList.remove('hidden');
this.collapsedStateCache.set(sectionName, false);
twistie.src = './media/expanded.svg';
} else {
body.classList.add('hidden');
this.collapsedStateCache.set(sectionName, true);
twistie.src = './media/collapsed.svg';
}
config.protocol = matches[1] === 'debug' ? 'legacy' : 'inspector';
} else {
// no port -> try to attach via pid (send SIGUSR1)
config.processId = String(item.pid);
}
// a debug-port=n or inspect-port=n overrides the port
matches = DEBUG_PORT_PATTERN.exec(item.cmd);
if (matches && matches.length === 3) {
// override port
config.port = parseInt(matches[2]);
}
ipcRenderer.send('vscode:workbenchCommand', { id: 'debug.startFromConfig', from: 'processExplorer', args: [config] });
}
function getProcessIdWithHighestProperty(processList: any[], propertyName: string) {
let max = 0;
let maxProcessId;
processList.forEach(process => {
if (process[propertyName] > max) {
max = process[propertyName];
maxProcessId = process.pid;
private renderProcessFetchError(sectionName: string, errorMessage: string) {
const container = document.getElementById('process-list');
if (!container) {
return;
}
});
return maxProcessId;
}
const body = document.createElement('tbody');
function updateSectionCollapsedState(shouldExpand: boolean, body: HTMLElement, twistie: HTMLImageElement, sectionName: string) {
if (shouldExpand) {
body.classList.remove('hidden');
collapsedStateCache.set(sectionName, false);
twistie.src = './media/expanded.svg';
} else {
body.classList.add('hidden');
collapsedStateCache.set(sectionName, true);
twistie.src = './media/collapsed.svg';
}
}
this.renderProcessGroupHeader(sectionName, body, container);
function renderProcessFetchError(sectionName: string, errorMessage: string) {
const container = document.getElementById('process-list');
if (!container) {
return;
const errorRow = document.createElement('tr');
const data = document.createElement('td');
data.textContent = errorMessage;
data.className = 'error';
data.colSpan = 4;
errorRow.appendChild(data);
body.appendChild(errorRow);
container.appendChild(body);
}
const body = document.createElement('tbody');
private renderProcessGroupHeader(sectionName: string, body: HTMLElement, container: HTMLElement) {
const headerRow = document.createElement('tr');
const data = document.createElement('td');
data.textContent = sectionName;
data.colSpan = 4;
headerRow.appendChild(data);
renderProcessGroupHeader(sectionName, body, container);
const twistie = document.createElement('img');
this.updateSectionCollapsedState(!this.collapsedStateCache.get(sectionName), body, twistie, sectionName);
data.prepend(twistie);
const errorRow = document.createElement('tr');
const data = document.createElement('td');
data.textContent = errorMessage;
data.className = 'error';
data.colSpan = 4;
errorRow.appendChild(data);
body.appendChild(errorRow);
container.appendChild(body);
}
function renderProcessGroupHeader(sectionName: string, body: HTMLElement, container: HTMLElement) {
const headerRow = document.createElement('tr');
const data = document.createElement('td');
data.textContent = sectionName;
data.colSpan = 4;
headerRow.appendChild(data);
const twistie = document.createElement('img');
updateSectionCollapsedState(!collapsedStateCache.get(sectionName), body, twistie, sectionName);
data.prepend(twistie);
listeners.add(addDisposableListener(data, 'click', (e) => {
const isHidden = body.classList.contains('hidden');
updateSectionCollapsedState(isHidden, body, twistie, sectionName);
}));
container.appendChild(headerRow);
}
function renderTableSection(sectionName: string, processList: FormattedProcessItem[], renderManySections: boolean, sectionIsLocal: boolean): void {
const container = document.getElementById('process-list');
if (!container) {
return;
}
const highestCPUProcess = getProcessIdWithHighestProperty(processList, 'cpu');
const highestMemoryProcess = getProcessIdWithHighestProperty(processList, 'memory');
const body = document.createElement('tbody');
if (renderManySections) {
renderProcessGroupHeader(sectionName, body, container);
}
processList.forEach(p => {
const row = document.createElement('tr');
row.id = p.pid.toString();
const cpu = document.createElement('td');
p.pid === highestCPUProcess
? cpu.classList.add('centered', 'highest')
: cpu.classList.add('centered');
cpu.textContent = p.cpu.toFixed(0);
const memory = document.createElement('td');
p.pid === highestMemoryProcess
? memory.classList.add('centered', 'highest')
: memory.classList.add('centered');
memory.textContent = p.memory.toFixed(0);
const pid = document.createElement('td');
pid.classList.add('centered');
pid.textContent = p.pid;
const name = document.createElement('th');
name.scope = 'row';
name.classList.add('data');
name.title = p.cmd;
name.textContent = p.formattedName;
row.append(cpu, memory, pid, name);
listeners.add(addDisposableListener(row, 'contextmenu', (e) => {
showContextMenu(e, p, sectionIsLocal);
this.listeners.add(addDisposableListener(data, 'click', (e) => {
const isHidden = body.classList.contains('hidden');
this.updateSectionCollapsedState(isHidden, body, twistie, sectionName);
}));
body.appendChild(row);
});
container.appendChild(body);
}
function updateProcessInfo(processLists: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]): void {
const container = document.getElementById('process-list');
if (!container) {
return;
container.appendChild(headerRow);
}
container.innerHTML = '';
listeners.clear();
const tableHead = document.createElement('thead');
tableHead.innerHTML = `<tr>
<th scope="col" class="cpu">${localize('cpu', "CPU %")}</th>
<th scope="col" class="memory">${localize('memory', "Memory (MB)")}</th>
<th scope="col" class="pid">${localize('pid', "pid")}</th>
<th scope="col" class="nameLabel">${localize('name', "Name")}</th>
</tr>`;
container.append(tableHead);
const hasMultipleMachines = Object.keys(processLists).length > 1;
processLists.forEach((remote, i) => {
const isLocal = i === 0;
if (isRemoteDiagnosticError(remote.rootProcess)) {
renderProcessFetchError(remote.name, remote.rootProcess.errorMessage);
} else {
renderTableSection(remote.name, getProcessList(remote.rootProcess, isLocal), hasMultipleMachines, isLocal);
private renderTableSection(sectionName: string, processList: FormattedProcessItem[], renderManySections: boolean, sectionIsLocal: boolean): void {
const container = document.getElementById('process-list');
if (!container) {
return;
}
});
}
function applyStyles(styles: ProcessExplorerStyles): void {
const styleTag = document.createElement('style');
const content: string[] = [];
const highestCPUProcess = this.getProcessIdWithHighestProperty(processList, 'cpu');
const highestMemoryProcess = this.getProcessIdWithHighestProperty(processList, 'memory');
if (styles.hoverBackground) {
content.push(`tbody > tr:hover, table > tr:hover { background-color: ${styles.hoverBackground}; }`);
const body = document.createElement('tbody');
if (renderManySections) {
this.renderProcessGroupHeader(sectionName, body, container);
}
processList.forEach(p => {
const row = document.createElement('tr');
row.id = p.pid.toString();
const cpu = document.createElement('td');
p.pid === highestCPUProcess
? cpu.classList.add('centered', 'highest')
: cpu.classList.add('centered');
cpu.textContent = p.cpu.toFixed(0);
const memory = document.createElement('td');
p.pid === highestMemoryProcess
? memory.classList.add('centered', 'highest')
: memory.classList.add('centered');
memory.textContent = p.memory.toFixed(0);
const pid = document.createElement('td');
pid.classList.add('centered');
pid.textContent = p.pid;
const name = document.createElement('th');
name.scope = 'row';
name.classList.add('data');
name.title = p.cmd;
name.textContent = p.formattedName;
row.append(cpu, memory, pid, name);
this.listeners.add(addDisposableListener(row, 'contextmenu', (e) => {
this.showContextMenu(e, p, sectionIsLocal);
}));
body.appendChild(row);
});
container.appendChild(body);
}
if (styles.hoverForeground) {
content.push(`tbody > tr:hover, table > tr:hover { color: ${styles.hoverForeground}; }`);
private updateProcessInfo(processLists: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]): void {
const container = document.getElementById('process-list');
if (!container) {
return;
}
container.innerHTML = '';
this.listeners.clear();
const tableHead = document.createElement('thead');
tableHead.innerHTML = `<tr>
<th scope="col" class="cpu">${localize('cpu', "CPU %")}</th>
<th scope="col" class="memory">${localize('memory', "Memory (MB)")}</th>
<th scope="col" class="pid">${localize('pid', "pid")}</th>
<th scope="col" class="nameLabel">${localize('name', "Name")}</th>
</tr>`;
container.append(tableHead);
const hasMultipleMachines = Object.keys(processLists).length > 1;
processLists.forEach((remote, i) => {
const isLocal = i === 0;
if (isRemoteDiagnosticError(remote.rootProcess)) {
this.renderProcessFetchError(remote.name, remote.rootProcess.errorMessage);
} else {
this.renderTableSection(remote.name, this.getProcessList(remote.rootProcess, isLocal), hasMultipleMachines, isLocal);
}
});
}
if (styles.highlightForeground) {
content.push(`.highest { color: ${styles.highlightForeground}; }`);
private applyStyles(styles: ProcessExplorerStyles): void {
const styleTag = document.createElement('style');
const content: string[] = [];
if (styles.hoverBackground) {
content.push(`tbody > tr:hover, table > tr:hover { background-color: ${styles.hoverBackground}; }`);
}
if (styles.hoverForeground) {
content.push(`tbody > tr:hover, table > tr:hover { color: ${styles.hoverForeground}; }`);
}
if (styles.highlightForeground) {
content.push(`.highest { color: ${styles.highlightForeground}; }`);
}
styleTag.innerHTML = content.join('\n');
if (document.head) {
document.head.appendChild(styleTag);
}
if (styles.color) {
document.body.style.color = styles.color;
}
}
styleTag.innerHTML = content.join('\n');
if (document.head) {
document.head.appendChild(styleTag);
}
if (styles.color) {
document.body.style.color = styles.color;
}
}
private showContextMenu(e: MouseEvent, item: FormattedProcessItem, isLocal: boolean) {
e.preventDefault();
function applyZoom(zoomLevel: number): void {
webFrame.setZoomLevel(zoomLevel);
browser.setZoomFactor(webFrame.getZoomFactor());
// See https://github.com/Microsoft/vscode/issues/26151
// Cannot be trusted because the webFrame might take some time
// until it really applies the new zoom level
browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false);
}
const items: IContextMenuItem[] = [];
const pid = Number(item.pid);
function showContextMenu(e: MouseEvent, item: FormattedProcessItem, isLocal: boolean) {
e.preventDefault();
if (isLocal) {
items.push({
label: localize('killProcess', "Kill Process"),
click() {
process.kill(pid, 'SIGTERM');
}
});
const items: IContextMenuItem[] = [];
const pid = Number(item.pid);
items.push({
label: localize('forceKillProcess', "Force Kill Process"),
click() {
process.kill(pid, 'SIGKILL');
}
});
items.push({
type: 'separator'
});
}
if (isLocal) {
items.push({
label: localize('killProcess', "Kill Process"),
label: localize('copy', "Copy"),
click() {
process.kill(pid, 'SIGTERM');
const row = document.getElementById(pid.toString());
if (row) {
clipboard.writeText(row.innerText);
}
}
});
items.push({
label: localize('forceKillProcess', "Force Kill Process"),
label: localize('copyAll', "Copy All"),
click() {
process.kill(pid, 'SIGKILL');
const processList = document.getElementById('process-list');
if (processList) {
clipboard.writeText(processList.innerText);
}
}
});
items.push({
type: 'separator'
});
if (item && isLocal && this.isDebuggable(item.cmd)) {
items.push({
type: 'separator'
});
items.push({
label: localize('debug', "Debug"),
click: () => {
this.attachTo(item);
}
});
}
popup(items);
}
items.push({
label: localize('copy', "Copy"),
click() {
const row = document.getElementById(pid.toString());
if (row) {
clipboard.writeText(row.innerText);
}
}
});
private requestProcessList(totalWaitTime: number): void {
setTimeout(() => {
const nextRequestTime = Date.now();
const waited = totalWaitTime + nextRequestTime - this.lastRequestTime;
this.lastRequestTime = nextRequestTime;
items.push({
label: localize('copyAll', "Copy All"),
click() {
const processList = document.getElementById('process-list');
if (processList) {
clipboard.writeText(processList.innerText);
// Wait at least a second between requests.
if (waited > 1000) {
ipcRenderer.send('vscode:windowsInfoRequest');
ipcRenderer.send('vscode:listProcesses');
} else {
this.requestProcessList(waited);
}
}
});
if (item && isLocal && isDebuggable(item.cmd)) {
items.push({
type: 'separator'
});
items.push({
label: localize('debug', "Debug"),
click() {
attachTo(item);
}
});
}, 200);
}
popup(items);
public dispose() {
this.listeners.dispose();
}
}
function requestProcessList(totalWaitTime: number): void {
setTimeout(() => {
const nextRequestTime = Date.now();
const waited = totalWaitTime + nextRequestTime - lastRequestTime;
lastRequestTime = nextRequestTime;
// Wait at least a second between requests.
if (waited > 1000) {
ipcRenderer.send('vscode:windowsInfoRequest');
ipcRenderer.send('vscode:listProcesses');
} else {
requestProcessList(waited);
}
}, 200);
}
function createCloseListener(): void {
// Cmd/Ctrl + w closes process explorer
window.addEventListener('keydown', e => {
const cmdOrCtrlKey = platform.isMacintosh ? e.metaKey : e.ctrlKey;
if (cmdOrCtrlKey && e.keyCode === 87) {
ipcRenderer.send('vscode:closeProcessExplorer');
}
});
}
export function startup(data: ProcessExplorerData): void {
const platformClass = platform.isWindows ? 'windows' : platform.isLinux ? 'linux' : 'mac';
addClass(document.body, platformClass); // used by our fonts
applyStyles(data.styles);
applyZoom(data.zoomLevel);
createCloseListener();
// Map window process pids to titles, annotate process names with this when rendering to distinguish between them
ipcRenderer.on('vscode:windowsInfoResponse', (event: unknown, windows: any[]) => {
mapPidToWindowTitle = new Map<number, string>();
windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
});
ipcRenderer.on('vscode:listProcessesResponse', (event: unknown, processRoots: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]) => {
updateProcessInfo(processRoots);
requestProcessList(0);
});
lastRequestTime = Date.now();
ipcRenderer.send('vscode:windowsInfoRequest');
ipcRenderer.send('vscode:listProcesses');
const processExplorer = new ProcessExplorer(data);
document.onkeydown = (e: KeyboardEvent) => {
const cmdOrCtrlKey = platform.isMacintosh ? e.metaKey : e.ctrlKey;
// Cmd/Ctrl + zooms in
if (cmdOrCtrlKey && e.keyCode === 187) {
applyZoom(webFrame.getZoomLevel() + 1);
zoomIn();
}
// Cmd/Ctrl - zooms out
if (cmdOrCtrlKey && e.keyCode === 189) {
applyZoom(webFrame.getZoomLevel() - 1);
zoomOut();
}
};
// Cmd/Ctrl + w closes process explorer
window.addEventListener('keydown', e => {
const cmdOrCtrlKey = platform.isMacintosh ? e.metaKey : e.ctrlKey;
if (cmdOrCtrlKey && e.keyCode === 87) {
processExplorer.dispose();
ipcRenderer.send('vscode:closeProcessExplorer');
}
});
}
@@ -35,7 +35,7 @@ export class StorageDataCleaner extends Disposable {
const emptyWorkspaces = workspaces.emptyWorkspaceInfos.map(info => info.backupFolder);
// Read all workspace storage folders that exist
return readdir(this.environmentService.workspaceStorageHome).then(storageFolders => {
return readdir(this.environmentService.workspaceStorageHome.fsPath).then(storageFolders => {
const deletes: Promise<void>[] = [];
storageFolders.forEach(storageFolder => {
@@ -44,7 +44,7 @@ export class StorageDataCleaner extends Disposable {
}
if (emptyWorkspaces.indexOf(storageFolder) === -1) {
deletes.push(rimraf(join(this.environmentService.workspaceStorageHome, storageFolder)));
deletes.push(rimraf(join(this.environmentService.workspaceStorageHome.fsPath, storageFolder)));
}
});
@@ -238,7 +238,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
server.registerChannel('userDataSyncAccount', authTokenChannel);
const userDataSyncService = accessor.get(IUserDataSyncService);
const userDataSyncChannel = new UserDataSyncChannel(userDataSyncService, logService);
const userDataSyncChannel = new UserDataSyncChannel(server, userDataSyncService, logService);
server.registerChannel('userDataSync', userDataSyncChannel);
const userDataAutoSync = instantiationService2.createInstance(UserDataAutoSyncService);
@@ -9,41 +9,33 @@
'use strict';
const perf = (function () {
let sharedObj;
if (typeof global === 'object') {
// nodejs
sharedObj = global;
} else if (typeof self === 'object') {
// browser
sharedObj = self;
} else {
sharedObj = {};
}
// @ts-ignore
sharedObj._performanceEntries = sharedObj._performanceEntries || [];
globalThis.MonacoPerformanceMarks = globalThis.MonacoPerformanceMarks || [];
return {
/**
* @param {string} name
*/
mark(name) {
sharedObj._performanceEntries.push(name, Date.now());
globalThis.MonacoPerformanceMarks.push(name, Date.now());
}
};
})();
perf.mark('renderer/started');
// Setup shell environment
process['lazyEnv'] = getLazyEnv();
/**
* @type {{ load: (modules: string[], resultCallback: (result, configuration: object) => any, options: object) => unknown }}
* @type {{
* load: (modules: string[], resultCallback: (result, configuration: object) => any, options: object) => unknown,
* globals: () => typeof import('../../../base/parts/sandbox/electron-sandbox/globals')
* }}
*/
const bootstrapWindow = (() => {
// @ts-ignore (defined in bootstrap-window.js)
return window.MonacoBootstrapWindow;
})();
// Setup shell environment
process['lazyEnv'] = getLazyEnv();
// Load workbench main JS, CSS and NLS all in parallel. This is an
// optimization to prevent a waterfall of loading to happen, because
// we know for a fact that workbench.desktop.main will depend on
@@ -55,6 +47,8 @@ bootstrapWindow.load([
'vs/css!vs/workbench/workbench.desktop.main'
],
function (workbench, configuration) {
// Mark start of workbench
perf.mark('didLoadWorkbenchMain');
performance.mark('workbench-start');
@@ -183,8 +177,7 @@ function showPartsSplash(configuration) {
* @returns {Promise<void>}
*/
function getLazyEnv() {
const ipc = require.__$__nodeRequire('electron').ipcRenderer;
const ipcRenderer = bootstrapWindow.globals().ipcRenderer;
return new Promise(function (resolve) {
const handle = setTimeout(function () {
@@ -192,13 +185,13 @@ function getLazyEnv() {
console.warn('renderer did not receive lazyEnv in time');
}, 10000);
ipc.once('vscode:acceptShellEnv', function (event, shellEnv) {
ipcRenderer.once('vscode:acceptShellEnv', function (event, shellEnv) {
clearTimeout(handle);
Object.assign(process.env, shellEnv);
// @ts-ignore
resolve(process.env);
});
ipc.send('vscode:fetchShellEnv');
ipcRenderer.send('vscode:fetchShellEnv');
});
}
+16 -10
View File
@@ -6,6 +6,7 @@
import { localize } from 'vs/nls';
import { Disposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { BrowserWindow, BrowserWindowConstructorOptions, app, AuthInfo, WebContents, Event as ElectronEvent } from 'electron';
type LoginEvent = {
@@ -58,10 +59,12 @@ export class ProxyAuthHandler extends Disposable {
show: true,
title: 'VS Code',
webPreferences: {
nodeIntegration: true,
preload: URI.parse(require.toUrl('vs/base/parts/sandbox/electron-browser/preload.js')).fsPath,
enableWebSQL: false,
sandbox: true,
devTools: false,
enableRemoteModule: false,
nativeWindowOpen: true
v8CacheOptions: 'bypassHeatCheck'
}
};
@@ -72,24 +75,27 @@ export class ProxyAuthHandler extends Disposable {
}
const win = new BrowserWindow(opts);
const config = {};
const baseUrl = require.toUrl('vs/code/electron-browser/proxy/auth.html');
const url = `${baseUrl}?config=${encodeURIComponent(JSON.stringify(config))}`;
const url = require.toUrl('vs/code/electron-sandbox/proxy/auth.html');
const proxyUrl = `${authInfo.host}:${authInfo.port}`;
const title = localize('authRequire', "Proxy Authentication Required");
const message = localize('proxyauth', "The proxy {0} requires authentication.", proxyUrl);
const data = { title, message };
const javascript = 'promptForCredentials(' + JSON.stringify(data) + ')';
const onWindowClose = () => cb('', '');
win.on('close', onWindowClose);
win.setMenu(null);
win.loadURL(url);
win.webContents.executeJavaScript(javascript, true).then(({ username, password }: Credentials) => {
cb(username, password);
win.webContents.on('did-finish-load', () => {
const data = { title, message };
win.webContents.send('vscode:openProxyAuthDialog', data);
});
win.webContents.on('ipc-message', (event, channel, credentials: Credentials) => {
if (channel === 'vscode:proxyAuthResponse') {
const { username, password } = credentials;
cb(username, password);
}
win.removeListener('close', onWindowClose);
win.close();
});
win.loadURL(url);
}
}
+2 -2
View File
@@ -178,8 +178,8 @@ class CodeMain {
environmentService.extensionsPath,
environmentService.nodeCachedDataDir,
environmentService.logsPath,
environmentService.globalStorageHome,
environmentService.workspaceStorageHome,
environmentService.globalStorageHome.fsPath,
environmentService.workspaceStorageHome.fsPath,
environmentService.backupHome.fsPath
].map((path): undefined | Promise<void> => path ? mkdirp(path) : undefined));
+10 -4
View File
@@ -15,7 +15,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { parseArgs, OPTIONS, ParsedArgs } from 'vs/platform/environment/node/argv';
import product from 'vs/platform/product/common/product';
import { IWindowSettings, MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/windows/common/windows';
import { IWindowSettings, MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, zoomLevelToZoomFactor } from 'vs/platform/windows/common/windows';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
import { ICodeWindow, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
@@ -153,6 +153,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
// in case we are maximized or fullscreen, only show later after the call to maximize/fullscreen (see below)
const isFullscreenOrMaximized = (this.windowState.mode === WindowMode.Maximized || this.windowState.mode === WindowMode.Fullscreen);
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
const options: BrowserWindowConstructorOptions = {
width: this.windowState.width,
height: this.windowState.height,
@@ -169,7 +171,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
webviewTag: true,
enableWebSQL: false,
enableRemoteModule: false,
nativeWindowOpen: true
nativeWindowOpen: true,
zoomFactor: zoomLevelToZoomFactor(windowConfig?.zoomLevel)
}
};
@@ -182,8 +185,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
options.icon = path.join(this.environmentService.appRoot, 'resources/win32/code_150x150.png');
}
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
if (isMacintosh && !this.useNativeFullScreen()) {
options.fullscreenable = false; // enables simple fullscreen mode
}
@@ -214,6 +215,11 @@ export class CodeWindow extends Disposable implements ICodeWindow {
this._win = new BrowserWindow(options);
this._id = this._win.id;
// Open devtools if instructed from command line args
if (this.environmentService.args['open-devtools'] === true) {
this._win.webContents.openDevTools();
}
if (isMacintosh && useCustomTitleStyle) {
this._win.setSheetOffset(22); // offset dialogs by the height of the custom title bar if we have any
}
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
<style>
html,
body {
@@ -78,43 +78,6 @@
</section>
</body>
<script>
function promptForCredentials(data) {
return new Promise((c, e) => {
const $title = document.getElementById('title');
const $username = document.getElementById('username');
const $password = document.getElementById('password');
const $form = document.getElementById('form');
const $cancel = document.getElementById('cancel');
const $message = document.getElementById('message');
function submit() {
c({ username: $username.value, password: $password.value });
return false;
};
function cancel() {
c({ username: '', password: '' });
return false;
};
$form.addEventListener('submit', submit);
$cancel.addEventListener('click', cancel);
document.body.addEventListener('keydown', function (e) {
switch (e.keyCode) {
case 27: e.preventDefault(); e.stopPropagation(); return cancel();
case 13: e.preventDefault(); e.stopPropagation(); return submit();
}
});
$title.textContent = data.title;
$message.textContent = data.message;
$username.focus();
});
}
</script>
<script src="auth.js"></script>
</html>
@@ -0,0 +1,48 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const { ipcRenderer } = window.vscode;
function promptForCredentials(data) {
return new Promise((c, e) => {
const $title = document.getElementById('title');
const $username = document.getElementById('username');
const $password = document.getElementById('password');
const $form = document.getElementById('form');
const $cancel = document.getElementById('cancel');
const $message = document.getElementById('message');
function submit() {
c({ username: $username.value, password: $password.value });
return false;
}
function cancel() {
c({ username: '', password: '' });
return false;
}
$form.addEventListener('submit', submit);
$cancel.addEventListener('click', cancel);
document.body.addEventListener('keydown', function (e) {
switch (e.keyCode) {
case 27: e.preventDefault(); e.stopPropagation(); return cancel();
case 13: e.preventDefault(); e.stopPropagation(); return submit();
}
});
$title.textContent = data.title;
$message.textContent = data.message;
$username.focus();
});
}
ipcRenderer.on('vscode:openProxyAuthDialog', async (event, data) => {
const response = await promptForCredentials(data);
ipcRenderer.send('vscode:proxyAuthResponse', response);
});
+1 -1
View File
@@ -319,7 +319,7 @@ var CSSBuildLoaderPlugin;
global.cssInlinedResources = global.cssInlinedResources || [];
var normalizedFSPath = fsPath.replace(/\\/g, '/');
if (global.cssInlinedResources.indexOf(normalizedFSPath) >= 0) {
console.warn('CSS INLINING IMAGE AT ' + fsPath + ' MORE THAN ONCE. CONSIDER CONSOLIDATING CSS RULES');
// console.warn('CSS INLINING IMAGE AT ' + fsPath + ' MORE THAN ONCE. CONSIDER CONSOLIDATING CSS RULES');
}
global.cssInlinedResources.push(normalizedFSPath);
var MIME = /\.svg$/.test(url) ? 'image/svg+xml' : 'image/png';
@@ -11,10 +11,11 @@ import * as platform from 'vs/base/common/platform';
import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader';
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
import { EditorOption, IEditorConstructionOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
import { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
import { IDimension } from 'vs/editor/common/editorCommon';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { IEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
class CSSBasedConfigurationCache {
+12
View File
@@ -336,6 +336,18 @@ export interface IEditorAriaOptions {
role?: string;
}
export interface IEditorConstructionOptions extends IEditorOptions {
/**
* The initial editor dimension (to avoid measuring the container).
*/
dimension?: editorCommon.IDimension;
/**
* Place overflow widgets inside an external DOM node.
* Defaults to an internal DOM node.
*/
overflowWidgetsDomNode?: HTMLElement;
}
/**
* A rich code editor.
*/
+27 -1
View File
@@ -14,7 +14,7 @@ import { IEditorContribution, IDiffEditorContribution } from 'vs/editor/common/e
import { ITextModel } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { MenuId, MenuRegistry, Action2 } from 'vs/platform/actions/common/actions';
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
@@ -339,6 +339,32 @@ export abstract class EditorAction extends EditorCommand {
//#endregion EditorAction
//#region EditorAction2
export abstract class EditorAction2 extends Action2 {
run(accessor: ServicesAccessor, ...args: any[]) {
// Find the editor with text focus or active
const codeEditorService = accessor.get(ICodeEditorService);
const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();
if (!editor) {
// well, at least we tried...
return;
}
// precondition does hold
return editor.invokeWithinContext((editorAccessor) => {
const kbService = editorAccessor.get(IContextKeyService);
if (kbService.contextMatchesRules(withNullAsUndefined(this.desc.precondition))) {
return this.runEditorCommand(editorAccessor, editor!, args);
}
});
}
abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: any[]): any;
}
//#endregion
// --- Registration of commands and actions
export function registerLanguageCommand<Args extends { [n: string]: any; }>(id: string, handler: (accessor: ServicesAccessor, args: Args) => any) {
+10 -2
View File
@@ -93,7 +93,8 @@ export class View extends ViewEventHandler {
configuration: IConfiguration,
themeService: IThemeService,
model: IViewModel,
userInputEvents: ViewUserInputEvents
userInputEvents: ViewUserInputEvents,
overflowWidgetsDomNode: HTMLElement | undefined
) {
super();
this._selections = [new Selection(1, 1, 1, 1)];
@@ -209,7 +210,12 @@ export class View extends ViewEventHandler {
this._overflowGuardContainer.appendChild(this._overlayWidgets.getDomNode());
this._overflowGuardContainer.appendChild(minimap.getDomNode());
this.domNode.appendChild(this._overflowGuardContainer);
this.domNode.appendChild(this._contentWidgets.overflowingContentWidgetsDomNode);
if (overflowWidgetsDomNode) {
overflowWidgetsDomNode.appendChild(this._contentWidgets.overflowingContentWidgetsDomNode.domNode);
} else {
this.domNode.appendChild(this._contentWidgets.overflowingContentWidgetsDomNode);
}
this._applyLayout();
@@ -317,6 +323,8 @@ export class View extends ViewEventHandler {
this._renderAnimationFrame = null;
}
this._contentWidgets.overflowingContentWidgetsDomNode.domNode.remove();
this._context.removeEventHandler(this);
this._viewLines.dispose();
@@ -21,7 +21,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
import { ICommandDelegate } from 'vs/editor/browser/view/viewController';
import { IContentWidgetData, IOverlayWidgetData, View } from 'vs/editor/browser/view/viewImpl';
import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, IEditorConstructionOptions, filterValidationDecorations } from 'vs/editor/common/config/editorOptions';
import { ConfigurationChangedEvent, EditorLayoutInfo, IEditorOptions, EditorOption, IComputedEditorOptions, FindComputedEditorOptionValueById, filterValidationDecorations } from 'vs/editor/common/config/editorOptions';
import { Cursor } from 'vs/editor/common/controller/cursor';
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
@@ -208,6 +208,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
private readonly _telemetryData?: object;
private readonly _domElement: HTMLElement;
private readonly _overflowWidgetsDomNode: HTMLElement | undefined;
private readonly _id: number;
private readonly _configuration: editorCommon.IConfiguration;
@@ -237,7 +238,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
constructor(
domElement: HTMLElement,
options: IEditorConstructionOptions,
options: editorBrowser.IEditorConstructionOptions,
codeEditorWidgetOptions: ICodeEditorWidgetOptions,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@@ -248,14 +249,17 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
@IAccessibilityService accessibilityService: IAccessibilityService
) {
super();
options = options || {};
this._domElement = domElement;
this._overflowWidgetsDomNode = options.overflowWidgetsDomNode;
this._id = (++EDITOR_ID);
this._decorationTypeKeysToIds = {};
this._decorationTypeSubtypes = {};
this.isSimpleWidget = codeEditorWidgetOptions.isSimpleWidget || false;
this._telemetryData = codeEditorWidgetOptions.telemetryData;
options = options || {};
this._configuration = this._register(this._createConfiguration(options, accessibilityService));
this._register(this._configuration.onDidChange((e) => {
this._onDidChangeConfiguration.fire(e);
@@ -324,7 +328,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
this._codeEditorService.addCodeEditor(this);
}
protected _createConfiguration(options: IEditorConstructionOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
protected _createConfiguration(options: editorBrowser.IEditorConstructionOptions, accessibilityService: IAccessibilityService): editorCommon.IConfiguration {
return new Configuration(this.isSimpleWidget, options, this._domElement, accessibilityService);
}
@@ -1613,7 +1617,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
this._configuration,
this._themeService,
viewModel,
viewUserInputEvents
viewUserInputEvents,
this._overflowWidgetsDomNode
);
return [view, true];
@@ -208,6 +208,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
private _ignoreTrimWhitespace: boolean;
private _originalIsEditable: boolean;
private _originalCodeLens: boolean;
private _modifiedCodeLens: boolean;
private _renderSideBySide: boolean;
private _maxComputationTime: number;
@@ -286,6 +288,16 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
this._originalIsEditable = Boolean(options.originalEditable);
}
this._originalCodeLens = false;
if (typeof options.originalCodeLens !== 'undefined') {
this._originalCodeLens = Boolean(options.originalCodeLens);
}
this._modifiedCodeLens = false;
if (typeof options.modifiedCodeLens !== 'undefined') {
this._modifiedCodeLens = Boolean(options.modifiedCodeLens);
}
this._updateDecorationsRunner = this._register(new RunOnceScheduler(() => this._updateDecorations(), 0));
this._containerDomElement = document.createElement('div');
@@ -474,7 +486,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
}
private _createLeftHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget {
const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options, this._originalIsEditable));
const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options, this._originalIsEditable, this._originalCodeLens));
this._register(editor.onDidScrollChange((e) => {
if (this._isHandlingScrollEvent) {
@@ -507,7 +519,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
}
private _createRightHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget {
const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options));
const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options, this._modifiedCodeLens));
this._register(editor.onDidScrollChange((e) => {
if (this._isHandlingScrollEvent) {
@@ -667,9 +679,15 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
if (typeof newOptions.originalEditable !== 'undefined') {
this._originalIsEditable = Boolean(newOptions.originalEditable);
}
if (typeof newOptions.originalCodeLens !== 'undefined') {
this._originalCodeLens = Boolean(newOptions.originalCodeLens);
}
if (typeof newOptions.modifiedCodeLens !== 'undefined') {
this._modifiedCodeLens = Boolean(newOptions.modifiedCodeLens);
}
this.modifiedEditor.updateOptions(this._adjustOptionsForRightHandSide(newOptions));
this.originalEditor.updateOptions(this._adjustOptionsForLeftHandSide(newOptions, this._originalIsEditable));
this.modifiedEditor.updateOptions(this._adjustOptionsForRightHandSide(newOptions, this._modifiedCodeLens));
this.originalEditor.updateOptions(this._adjustOptionsForLeftHandSide(newOptions, this._originalIsEditable, this._originalCodeLens));
// enableSplitViewResizing
if (typeof newOptions.enableSplitViewResizing !== 'undefined') {
@@ -1065,15 +1083,21 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
return clonedOptions;
}
private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean): IEditorOptions {
private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean, isCodeLensEnabled: boolean): IEditorOptions {
let result = this._adjustOptionsForSubEditor(options);
if (isCodeLensEnabled) {
result.codeLens = true;
}
result.readOnly = !isEditable;
result.extraEditorClassName = 'original-in-monaco-diff-editor';
return result;
}
private _adjustOptionsForRightHandSide(options: IDiffEditorOptions): IEditorOptions {
private _adjustOptionsForRightHandSide(options: IDiffEditorOptions, isCodeLensEnabled: boolean): IEditorOptions {
let result = this._adjustOptionsForSubEditor(options);
if (isCodeLensEnabled) {
result.codeLens = true;
}
result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
result.scrollbar!.verticalHasArrows = false;
result.extraEditorClassName = 'modified-in-monaco-diff-editor';
@@ -541,6 +541,11 @@ const editorConfiguration: IConfigurationNode = {
type: 'boolean',
default: true,
description: nls.localize('renderIndicators', "Controls whether the diff editor shows +/- indicators for added/removed changes.")
},
'diffEditor.codeLens': {
type: 'boolean',
default: false,
description: nls.localize('codeLens', "Controls whether the editor shows CodeLens.")
}
}
};
+23 -11
View File
@@ -11,7 +11,6 @@ import { Constants } from 'vs/base/common/uint';
import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper';
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
import { IDimension } from 'vs/editor/common/editorCommon';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
//#region typed options
@@ -600,13 +599,6 @@ export interface IEditorOptions {
showDeprecated?: boolean;
}
export interface IEditorConstructionOptions extends IEditorOptions {
/**
* The initial editor dimension (to avoid measuring the container).
*/
dimension?: IDimension;
}
/**
* @internal
* The width of the minimap gutter, in pixels.
@@ -647,12 +639,20 @@ export interface IDiffEditorOptions extends IEditorOptions {
* Defaults to false.
*/
originalEditable?: boolean;
// {{SQL CARBON EDIT}}
/**
/** // {{SQL CARBON EDIT}}
* Adding option to reverse coloring in diff editor
*/
reverse?: boolean;
/**
* Original editor should be have code lens enabled?
* Defaults to false.
*/
originalCodeLens?: boolean;
/**
* Modified editor should be have code lens enabled?
* Defaults to false.
*/
modifiedCodeLens?: boolean;
}
//#endregion
@@ -1076,6 +1076,11 @@ export interface IEditorCommentsOptions {
* Defaults to true.
*/
insertSpace?: boolean;
/**
* Ignore empty lines when inserting line comments.
* Defaults to true.
*/
ignoreEmptyLines?: boolean;
}
export type EditorCommentsOptions = Readonly<Required<IEditorCommentsOptions>>;
@@ -1085,6 +1090,7 @@ class EditorComments extends BaseEditorOption<EditorOption.comments, EditorComme
constructor() {
const defaults: EditorCommentsOptions = {
insertSpace: true,
ignoreEmptyLines: true,
};
super(
EditorOption.comments, 'comments', defaults,
@@ -1094,6 +1100,11 @@ class EditorComments extends BaseEditorOption<EditorOption.comments, EditorComme
default: defaults.insertSpace,
description: nls.localize('comments.insertSpace', "Controls whether a space character is inserted when commenting.")
},
'editor.comments.ignoreEmptyLines': {
type: 'boolean',
default: defaults.ignoreEmptyLines,
description: nls.localize('comments.ignoreEmptyLines', 'Controls if empty lines should be ignored with toggle, add or remove actions for line comments.')
},
}
);
}
@@ -1105,6 +1116,7 @@ class EditorComments extends BaseEditorOption<EditorOption.comments, EditorComme
const input = _input as IEditorCommentsOptions;
return {
insertSpace: EditorBooleanOption.boolean(input.insertSpace, this.defaultValue.insertSpace),
ignoreEmptyLines: EditorBooleanOption.boolean(input.ignoreEmptyLines, this.defaultValue.ignoreEmptyLines),
};
}
}
@@ -31,6 +31,7 @@ export class MirrorTextModel {
protected _eol: string;
protected _versionId: number;
protected _lineStarts: PrefixSumComputer | null;
private _cachedTextValue: string | null;
constructor(uri: URI, lines: string[], eol: string, versionId: number) {
this._uri = uri;
@@ -38,6 +39,7 @@ export class MirrorTextModel {
this._eol = eol;
this._versionId = versionId;
this._lineStarts = null;
this._cachedTextValue = null;
}
dispose(): void {
@@ -49,7 +51,10 @@ export class MirrorTextModel {
}
getText(): string {
return this._lines.join(this._eol);
if (this._cachedTextValue === null) {
this._cachedTextValue = this._lines.join(this._eol);
}
return this._cachedTextValue;
}
onEvents(e: IModelChangedEvent): void {
@@ -66,6 +71,7 @@ export class MirrorTextModel {
}
this._versionId = e.versionId;
this._cachedTextValue = null;
}
protected _ensureLineStarts(): void {
@@ -239,7 +239,7 @@ class PieceTreeSearchCache {
this._cache.push(nodePosition);
}
public valdiate(offset: number) {
public validate(offset: number) {
let hasInvalidVal = false;
let tmp: Array<CacheEntry | null> = this._cache;
for (let i = 0; i < tmp.length; i++) {
@@ -838,7 +838,7 @@ export class PieceTreeBase {
if (nodeStartOffset === offset) {
this.insertContentToNodeLeft(value, node);
this._searchCache.valdiate(offset);
this._searchCache.validate(offset);
} else if (nodeStartOffset + node.piece.length > offset) {
// we are inserting into the middle of a node.
let nodesToDel: TreeNode[] = [];
@@ -938,7 +938,7 @@ export class PieceTreeBase {
return;
}
this.deleteNodeHead(startNode, endSplitPosInBuffer);
this._searchCache.valdiate(offset);
this._searchCache.validate(offset);
this.validateCRLFWithPrevNode(startNode);
this.computeBufferMetadata();
return;
@@ -961,7 +961,7 @@ export class PieceTreeBase {
let startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);
this.deleteNodeTail(startNode, startSplitPosInBuffer);
this._searchCache.valdiate(offset);
this._searchCache.validate(offset);
if (startNode.piece.length === 0) {
nodesToDel.push(startNode);
}
@@ -1225,14 +1225,14 @@ export class PieceTreeBase {
let cache = this._searchCache.get2(lineNumber);
if (cache) {
x = cache.node;
let prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber - 1);
let prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber - 1);
let buffer = this._buffers[x.piece.bufferIndex].buffer;
let startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
if (cache.nodeStartLineNumber + x.piece.lineFeedCnt === lineNumber) {
ret = buffer.substring(startOffset + prevAccumualtedValue, startOffset + x.piece.length);
ret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);
} else {
let accumualtedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber);
return buffer.substring(startOffset + prevAccumualtedValue, startOffset + accumualtedValue - endOffset);
let accumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber);
return buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);
}
} else {
let nodeStartOffset = 0;
@@ -1241,8 +1241,8 @@ export class PieceTreeBase {
if (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {
x = x.left;
} else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {
let prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
let accumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);
let prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
let accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);
let buffer = this._buffers[x.piece.bufferIndex].buffer;
let startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
nodeStartOffset += x.size_left;
@@ -1252,13 +1252,13 @@ export class PieceTreeBase {
nodeStartLineNumber: originalLineNumber - (lineNumber - 1 - x.lf_left)
});
return buffer.substring(startOffset + prevAccumualtedValue, startOffset + accumualtedValue - endOffset);
return buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);
} else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {
let prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
let prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
let buffer = this._buffers[x.piece.bufferIndex].buffer;
let startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
ret = buffer.substring(startOffset + prevAccumualtedValue, startOffset + x.piece.length);
ret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);
break;
} else {
lineNumber -= x.lf_left + x.piece.lineFeedCnt;
@@ -1274,10 +1274,10 @@ export class PieceTreeBase {
let buffer = this._buffers[x.piece.bufferIndex].buffer;
if (x.piece.lineFeedCnt > 0) {
let accumualtedValue = this.getAccumulatedValue(x, 0);
let accumulatedValue = this.getAccumulatedValue(x, 0);
let startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
ret += buffer.substring(startOffset, startOffset + accumualtedValue - endOffset);
ret += buffer.substring(startOffset, startOffset + accumulatedValue - endOffset);
return ret;
} else {
let startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
@@ -1304,7 +1304,7 @@ export class PieceTreeBase {
this._lineCnt = lfCnt;
this._length = len;
this._searchCache.valdiate(this._length);
this._searchCache.validate(this._length);
}
// #region node operations
@@ -1504,12 +1504,12 @@ export class PieceTreeBase {
x = x.left;
} else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {
let prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
let accumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);
let accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);
nodeStartOffset += x.size_left;
return {
node: x,
remainder: Math.min(prevAccumualtedValue + column - 1, accumualtedValue),
remainder: Math.min(prevAccumualtedValue + column - 1, accumulatedValue),
nodeStartOffset
};
} else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {
@@ -1536,11 +1536,11 @@ export class PieceTreeBase {
while (x !== SENTINEL) {
if (x.piece.lineFeedCnt > 0) {
let accumualtedValue = this.getAccumulatedValue(x, 0);
let accumulatedValue = this.getAccumulatedValue(x, 0);
let nodeStartOffset = this.offsetOfNode(x);
return {
node: x,
remainder: Math.min(column - 1, accumualtedValue),
remainder: Math.min(column - 1, accumulatedValue),
nodeStartOffset
};
} else {
+2 -3
View File
@@ -30,7 +30,6 @@ import { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode';
import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { withUndefinedAsNull } from 'vs/base/common/types';
import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
import { TokensStore, MultilineTokens, countEOL, MultilineTokens2, TokensStore2 } from 'vs/editor/common/model/tokensStore';
import { Color } from 'vs/base/common/color';
@@ -3185,8 +3184,8 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions {
this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;
this.zIndex = options.zIndex || 0;
this.className = options.className ? cleanClassName(options.className) : null;
this.hoverMessage = withUndefinedAsNull(options.hoverMessage);
this.glyphMarginHoverMessage = withUndefinedAsNull(options.glyphMarginHoverMessage);
this.hoverMessage = options.hoverMessage || null;
this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || null;
this.isWholeLine = options.isWholeLine || false;
this.showIfCollapsed = options.showIfCollapsed || false;
this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false;
+13 -5
View File
@@ -1413,19 +1413,27 @@ export interface AuthenticationSession {
id: string;
accessToken: string;
account: {
displayName: string;
label: string;
id: string;
}
scopes: string[];
scopes: ReadonlyArray<string>;
}
/**
* @internal
*/
export interface AuthenticationSessionsChangeEvent {
added: string[];
removed: string[];
changed: string[];
added: ReadonlyArray<string>;
removed: ReadonlyArray<string>;
changed: ReadonlyArray<string>;
}
/**
* @internal
*/
export interface AuthenticationProviderInformation {
id: string;
label: string;
}
export interface Command {
@@ -7,8 +7,7 @@ import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ColorId, ITokenizationRegistry, ITokenizationSupport, ITokenizationSupportChangedEvent } from 'vs/editor/common/modes';
import { withUndefinedAsNull } from 'vs/base/common/types';
import { keys } from 'vs/base/common/map';
import { toArray } from 'vs/base/common/arrays';
export class TokenizationRegistryImpl implements ITokenizationRegistry {
@@ -77,13 +76,13 @@ export class TokenizationRegistryImpl implements ITokenizationRegistry {
}
public get(language: string): ITokenizationSupport | null {
return withUndefinedAsNull(this._map.get(language));
return (this._map.get(language) || null);
}
public setColorMap(colorMap: Color[]): void {
this._colorMap = colorMap;
this._onDidChange.fire({
changedLanguages: keys(this._map),
changedLanguages: toArray(this._map.keys()),
changedColorMap: true
});
}
@@ -15,7 +15,6 @@ import { NULL_LANGUAGE_IDENTIFIER, NULL_MODE_ID } from 'vs/editor/common/modes/n
import { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { withUndefinedAsNull } from 'vs/base/common/types';
const hasOwnProperty = Object.prototype.hasOwnProperty;
@@ -268,7 +267,7 @@ export class LanguagesRegistry extends Disposable {
return null;
}
const language = this._languages[modeId];
return withUndefinedAsNull(language.mimetypes[0]);
return (language.mimetypes[0] || null);
}
public extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): string[] {
@@ -12,11 +12,9 @@ import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeServ
import { overviewRulerWarning, overviewRulerInfo, overviewRulerError } from 'vs/editor/common/view/editorColorRegistry';
import { IModelService } from 'vs/editor/common/services/modelService';
import { Range } from 'vs/editor/common/core/range';
import { keys } from 'vs/base/common/map';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { Schemas } from 'vs/base/common/network';
import { Emitter, Event } from 'vs/base/common/event';
import { withUndefinedAsNull } from 'vs/base/common/types';
import { minimapWarning, minimapError } from 'vs/platform/theme/common/colorRegistry';
import { Delayer } from 'vs/base/common/async';
@@ -33,7 +31,7 @@ class MarkerDecorations extends Disposable {
) {
super();
this._register(toDisposable(() => {
this.model.deltaDecorations(keys(this._markersData), []);
this.model.deltaDecorations([...this._markersData.keys()], []);
this._markersData.clear();
}));
}
@@ -43,7 +41,7 @@ class MarkerDecorations extends Disposable {
}
public update(markers: IMarker[], newDecorations: IModelDeltaDecoration[]): boolean {
const oldIds = keys(this._markersData);
const oldIds = [...this._markersData.keys()];
this._markersData.clear();
const ids = this.model.deltaDecorations(oldIds, newDecorations);
for (let index = 0; index < ids.length; index++) {
@@ -96,7 +94,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor
getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null {
const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri));
return markerDecorations ? withUndefinedAsNull(markerDecorations.getMarker(decoration)) : null;
return markerDecorations ? (markerDecorations.getMarker(decoration) || null) : null;
}
getLiveMarkers(model: ITextModel): [Range, IMarker][] {
+7 -1
View File
@@ -36,7 +36,13 @@ abstract class CommentLineAction extends EditorAction {
const commentsOptions = editor.getOption(EditorOption.comments);
for (const selection of selections) {
commands.push(new LineCommentCommand(selection, modelOptions.tabSize, this._type, commentsOptions.insertSpace));
commands.push(new LineCommentCommand(
selection,
modelOptions.tabSize,
this._type,
commentsOptions.insertSpace,
commentsOptions.ignoreEmptyLines
));
}
editor.pushUndoStop();
@@ -53,11 +53,18 @@ export class LineCommentCommand implements ICommand {
private readonly _tabSize: number;
private readonly _type: Type;
private readonly _insertSpace: boolean;
private readonly _ignoreEmptyLines: boolean;
private _selectionId: string | null;
private _deltaColumn: number;
private _moveEndPositionDown: boolean;
constructor(selection: Selection, tabSize: number, type: Type, insertSpace: boolean) {
constructor(
selection: Selection,
tabSize: number,
type: Type,
insertSpace: boolean,
ignoreEmptyLines: boolean
) {
this._selection = selection;
this._tabSize = tabSize;
this._type = type;
@@ -65,6 +72,7 @@ export class LineCommentCommand implements ICommand {
this._selectionId = null;
this._deltaColumn = 0;
this._moveEndPositionDown = false;
this._ignoreEmptyLines = ignoreEmptyLines;
}
/**
@@ -100,7 +108,7 @@ export class LineCommentCommand implements ICommand {
* Analyze lines and decide which lines are relevant and what the toggle should do.
* Also, build up several offsets and lengths useful in the generation of editor operations.
*/
public static _analyzeLines(type: Type, insertSpace: boolean, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number): IPreflightData {
public static _analyzeLines(type: Type, insertSpace: boolean, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number, ignoreEmptyLines: boolean): IPreflightData {
let onlyWhitespaceLines = true;
let shouldRemoveComments: boolean;
@@ -121,13 +129,7 @@ export class LineCommentCommand implements ICommand {
if (lineContentStartOffset === -1) {
// Empty or whitespace only line
if (type === Type.Toggle) {
lineData.ignore = true;
} else if (type === Type.ForceAdd) {
lineData.ignore = true;
} else {
lineData.ignore = true;
}
lineData.ignore = ignoreEmptyLines;
lineData.commentStrOffset = lineContent.length;
continue;
}
@@ -176,7 +178,7 @@ export class LineCommentCommand implements ICommand {
/**
* Analyze all lines and decide exactly what to do => not supported | insert line comments | remove line comments
*/
public static _gatherPreflightData(type: Type, insertSpace: boolean, model: ITextModel, startLineNumber: number, endLineNumber: number): IPreflightData {
public static _gatherPreflightData(type: Type, insertSpace: boolean, model: ITextModel, startLineNumber: number, endLineNumber: number, ignoreEmptyLines: boolean): IPreflightData {
const lines = LineCommentCommand._gatherPreflightCommentStrings(model, startLineNumber, endLineNumber);
if (lines === null) {
return {
@@ -184,7 +186,7 @@ export class LineCommentCommand implements ICommand {
};
}
return LineCommentCommand._analyzeLines(type, insertSpace, model, lines, startLineNumber);
return LineCommentCommand._analyzeLines(type, insertSpace, model, lines, startLineNumber, ignoreEmptyLines);
}
/**
@@ -326,7 +328,15 @@ export class LineCommentCommand implements ICommand {
s = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));
}
const data = LineCommentCommand._gatherPreflightData(this._type, this._insertSpace, model, s.startLineNumber, s.endLineNumber);
const data = LineCommentCommand._gatherPreflightData(
this._type,
this._insertSpace,
model,
s.startLineNumber,
s.endLineNumber,
this._ignoreEmptyLines
);
if (data.supported) {
return this._executeLineComments(model, builder, data, s);
}
@@ -19,13 +19,13 @@ suite('Editor Contrib - Line Comment Command', () => {
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<!@#', '#@!>'] });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true, true), expectedLines, expectedSelection);
mode.dispose();
}
function testAddLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<!@#', '#@!>'] });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd, true), expectedLines, expectedSelection);
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd, true, true), expectedLines, expectedSelection);
mode.dispose();
}
@@ -47,7 +47,7 @@ suite('Editor Contrib - Line Comment Command', () => {
test('case insensitive', function () {
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: 'rem' });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true, true), expectedLines, expectedSelection);
mode.dispose();
}
@@ -91,7 +91,7 @@ suite('Editor Contrib - Line Comment Command', () => {
' ',
' c',
'\t\td'
]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1);
]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1, true);
if (!r.supported) {
throw new Error(`unexpected`);
}
@@ -122,7 +122,7 @@ suite('Editor Contrib - Line Comment Command', () => {
' rem ',
' !@# c',
'\t\t!@#d'
]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1);
]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1, true);
if (!r.supported) {
throw new Error(`unexpected`);
}
@@ -631,7 +631,7 @@ suite('Editor Contrib - Line Comment Command', () => {
test('insertSpace false', () => {
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: '!@#' });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, false), expectedLines, expectedSelection);
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, false, true), expectedLines, expectedSelection);
mode.dispose();
}
@@ -650,7 +650,7 @@ suite('Editor Contrib - Line Comment Command', () => {
test('insertSpace false does not remove space', () => {
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: '!@#' });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, false), expectedLines, expectedSelection);
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, false, true), expectedLines, expectedSelection);
mode.dispose();
}
@@ -665,13 +665,104 @@ suite('Editor Contrib - Line Comment Command', () => {
new Selection(1, 1, 1, 1)
);
});
suite('ignoreEmptyLines false', () => {
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: '!@#', blockComment: ['<!@#', '#@!>'] });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true, false), expectedLines, expectedSelection);
mode.dispose();
}
test('does not ignore whitespace lines', () => {
testLineCommentCommand(
[
'\tsome text',
'\t ',
'',
'\tsome more text'
],
new Selection(4, 2, 1, 1),
[
'!@# \tsome text',
'!@# \t ',
'!@# ',
'!@# \tsome more text'
],
new Selection(4, 6, 1, 5)
);
});
test('removes its own', function () {
testLineCommentCommand(
[
'\t!@# some text',
'\t ',
'\t\t!@# some more text'
],
new Selection(3, 2, 1, 1),
[
'\tsome text',
'\t ',
'\t\tsome more text'
],
new Selection(3, 2, 1, 1)
);
});
test('works in only whitespace', function () {
testLineCommentCommand(
[
'\t ',
'\t',
'\t\tsome more text'
],
new Selection(3, 1, 1, 1),
[
'\t!@# ',
'\t!@# ',
'\t\tsome more text'
],
new Selection(3, 1, 1, 1)
);
});
test('comments single line', function () {
testLineCommentCommand(
[
'some text',
'\tsome more text'
],
new Selection(1, 1, 1, 1),
[
'!@# some text',
'\tsome more text'
],
new Selection(1, 5, 1, 5)
);
});
test('detects indentation', function () {
testLineCommentCommand(
[
'\tsome text',
'\tsome more text'
],
new Selection(2, 2, 1, 1),
[
'\t!@# some text',
'\t!@# some more text'
],
new Selection(2, 2, 1, 1)
);
});
});
});
suite('Editor Contrib - Line Comment As Block Comment', () => {
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: '', blockComment: ['(', ')'] });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true, true), expectedLines, expectedSelection);
mode.dispose();
}
@@ -782,7 +873,7 @@ suite('Editor Contrib - Line Comment As Block Comment', () => {
suite('Editor Contrib - Line Comment As Block Comment 2', () => {
function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void {
let mode = new CommentMode({ lineComment: null, blockComment: ['<!@#', '#@!>'] });
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true), expectedLines, expectedSelection);
testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, true, true), expectedLines, expectedSelection);
mode.dispose();
}
@@ -1023,7 +1114,7 @@ suite('Editor Contrib - Line Comment in mixed modes', () => {
lines,
outerMode.getLanguageIdentifier(),
selection,
(sel) => new LineCommentCommand(sel, 4, Type.Toggle, true),
(sel) => new LineCommentCommand(sel, 4, Type.Toggle, true, true),
expectedLines,
expectedSelection,
true
+25 -16
View File
@@ -280,6 +280,12 @@ export class CommonFindController extends Disposable implements IEditorContribut
if (!stateChanges.searchString && opts.seedSearchStringFromGlobalClipboard) {
let selectionSearchString = await this.getGlobalBufferTerm();
if (!this._editor.hasModel()) {
// the editor has lost its model in the meantime
return;
}
if (selectionSearchString) {
stateChanges.searchString = selectionSearchString;
}
@@ -364,13 +370,14 @@ export class CommonFindController extends Disposable implements IEditorContribut
return '';
}
public async setGlobalBufferTerm(text: string) {
public setGlobalBufferTerm(text: string): void {
if (this._editor.getOption(EditorOption.find).globalFindClipboard
&& this._clipboardService
&& this._editor.hasModel()
&& !this._editor.getModel().isTooLargeForSyncing()
) {
await this._clipboardService.writeFindText(text);
// intentionally not awaited
this._clipboardService.writeFindText(text);
}
}
}
@@ -424,10 +431,12 @@ export class FindController extends CommonFindController implements IFindControl
await super._start(opts);
if (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) {
this._widget!.focusReplaceInput();
} else if (opts.shouldFocus === FindStartFocusAction.FocusFindInput) {
this._widget!.focusFindInput();
if (this._widget) {
if (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) {
this._widget.focusReplaceInput();
} else if (opts.shouldFocus === FindStartFocusAction.FocusFindInput) {
this._widget.focusFindInput();
}
}
}
@@ -470,10 +479,10 @@ export class StartFindAction extends EditorAction {
});
}
public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void {
public async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise<void> {
let controller = CommonFindController.get(editor);
if (controller) {
controller.start({
await controller.start({
forceRevealReplace: false,
seedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection,
seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).globalFindClipboard,
@@ -508,7 +517,7 @@ export class StartFindWithSelectionAction extends EditorAction {
public async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
let controller = CommonFindController.get(editor);
if (controller) {
controller.start({
await controller.start({
forceRevealReplace: false,
seedSearchStringFromSelection: true,
seedSearchStringFromGlobalClipboard: false,
@@ -518,15 +527,15 @@ export class StartFindWithSelectionAction extends EditorAction {
loop: editor.getOption(EditorOption.find).loop
});
return controller.setGlobalBufferTerm(controller.getState().searchString);
controller.setGlobalBufferTerm(controller.getState().searchString);
}
}
}
export abstract class MatchFindAction extends EditorAction {
public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void {
public async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise<void> {
let controller = CommonFindController.get(editor);
if (controller && !this._run(controller)) {
controller.start({
await controller.start({
forceRevealReplace: false,
seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getOption(EditorOption.find).seedSearchStringFromSelection,
seedSearchStringFromGlobalClipboard: true,
@@ -629,7 +638,7 @@ export class PreviousMatchFindAction2 extends MatchFindAction {
}
export abstract class SelectionMatchFindAction extends EditorAction {
public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void {
public async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise<void> {
let controller = CommonFindController.get(editor);
if (!controller) {
return;
@@ -639,7 +648,7 @@ export abstract class SelectionMatchFindAction extends EditorAction {
controller.setSearchString(selectionSearchString);
}
if (!this._run(controller)) {
controller.start({
await controller.start({
forceRevealReplace: false,
seedSearchStringFromSelection: editor.getOption(EditorOption.find).seedSearchStringFromSelection,
seedSearchStringFromGlobalClipboard: false,
@@ -720,7 +729,7 @@ export class StartFindReplaceAction extends EditorAction {
});
}
public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void {
public async run(accessor: ServicesAccessor | null, editor: ICodeEditor): Promise<void> {
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly)) {
return;
}
@@ -745,7 +754,7 @@ export class StartFindReplaceAction extends EditorAction {
if (controller) {
controller.start({
await controller.start({
forceRevealReplace: true,
seedSearchStringFromSelection: seedSearchStringFromSelection,
seedSearchStringFromGlobalClipboard: editor.getOption(EditorOption.find).seedSearchStringFromSelection,
@@ -14,7 +14,7 @@ import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { CommonFindController, FindStartFocusAction, IFindStartOptions, NextMatchFindAction, NextSelectionMatchFindAction, StartFindAction, StartFindReplaceAction } from 'vs/editor/contrib/find/findController';
import { CONTEXT_FIND_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel';
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { withAsyncTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
@@ -55,7 +55,7 @@ function fromSelection(slc: Selection): number[] {
return [slc.startLineNumber, slc.startColumn, slc.endLineNumber, slc.endColumn];
}
suite.skip('FindController', () => {
suite.skip('FindController', async () => {
let queryState: { [key: string]: any; } = {};
let clipboardState = '';
let serviceCollection = new ServiceCollection();
@@ -77,13 +77,13 @@ suite.skip('FindController', () => {
});
}
/* test('stores to the global clipboard buffer on start find action', () => {
withTestCodeEditor([
/* test('stores to the global clipboard buffer on start find action', async () => {
await withAsyncTestCodeEditor([
'ABC',
'ABC',
'XYZ',
'ABC'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
if (!platform.isMacintosh) {
assert.ok(true);
@@ -101,13 +101,13 @@ suite.skip('FindController', () => {
});
});
test('reads from the global clipboard buffer on next find action if buffer exists', () => {
withTestCodeEditor([
test('reads from the global clipboard buffer on next find action if buffer exists', async () => {
await withAsyncTestCodeEditor([
'ABC',
'ABC',
'XYZ',
'ABC'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = 'ABC';
if (!platform.isMacintosh) {
@@ -128,13 +128,13 @@ suite.skip('FindController', () => {
});
});
test('writes to the global clipboard buffer when text changes', () => {
withTestCodeEditor([
test('writes to the global clipboard buffer when text changes', async () => {
await withAsyncTestCodeEditor([
'ABC',
'ABC',
'XYZ',
'ABC'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
if (!platform.isMacintosh) {
assert.ok(true);
@@ -152,13 +152,13 @@ suite.skip('FindController', () => {
});
}); */
test('issue #1857: F3, Find Next, acts like "Find Under Cursor"', () => {
withTestCodeEditor([
test('issue #1857: F3, Find Next, acts like "Find Under Cursor"', async () => {
await withAsyncTestCodeEditor([
'ABC',
'ABC',
'XYZ',
'ABC'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
// The cursor is at the very top, of the file, at the first ABC
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
@@ -167,7 +167,7 @@ suite.skip('FindController', () => {
let nextMatchFindAction = new NextMatchFindAction();
// I hit Ctrl+F to show the Find dialog
startFindAction.run(null, editor);
await startFindAction.run(null, editor);
// I type ABC.
findState.change({ searchString: 'A' }, true);
@@ -201,7 +201,7 @@ suite.skip('FindController', () => {
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 4, 1, 4]);
// I hit F3 to "Find Next" to find the next occurrence of ABC, but instead it searches for XYZ.
nextMatchFindAction.run(null, editor);
await nextMatchFindAction.run(null, editor);
assert.equal(findState.searchString, 'ABC');
assert.equal(findController.hasFocus, false);
@@ -210,10 +210,10 @@ suite.skip('FindController', () => {
});
});
test('issue #3090: F3 does not loop with two matches on a single line', () => {
withTestCodeEditor([
test('issue #3090: F3 does not loop with two matches on a single line', async () => {
await withAsyncTestCodeEditor([
'import nls = require(\'vs/nls\');'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
let nextMatchFindAction = new NextMatchFindAction();
@@ -223,22 +223,22 @@ suite.skip('FindController', () => {
column: 9
});
nextMatchFindAction.run(null, editor);
await nextMatchFindAction.run(null, editor);
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 26, 1, 29]);
nextMatchFindAction.run(null, editor);
await nextMatchFindAction.run(null, editor);
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 8, 1, 11]);
findController.dispose();
});
});
test('issue #6149: Auto-escape highlighted text for search and replace regex mode', () => {
withTestCodeEditor([
test('issue #6149: Auto-escape highlighted text for search and replace regex mode', async () => {
await withAsyncTestCodeEditor([
'var x = (3 * 5)',
'var y = (3 * 5)',
'var z = (3 * 5)',
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
let startFindAction = new StartFindAction();
@@ -247,22 +247,22 @@ suite.skip('FindController', () => {
editor.setSelection(new Selection(1, 9, 1, 13));
findController.toggleRegex();
startFindAction.run(null, editor);
await startFindAction.run(null, editor);
nextMatchFindAction.run(null, editor);
await nextMatchFindAction.run(null, editor);
assert.deepEqual(fromSelection(editor.getSelection()!), [2, 9, 2, 13]);
nextMatchFindAction.run(null, editor);
await nextMatchFindAction.run(null, editor);
assert.deepEqual(fromSelection(editor.getSelection()!), [1, 9, 1, 13]);
findController.dispose();
});
});
test('issue #41027: Don\'t replace find input value on replace action if find input is active', () => {
withTestCodeEditor([
test('issue #41027: Don\'t replace find input value on replace action if find input is active', async () => {
await withAsyncTestCodeEditor([
'test',
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
let testRegexString = 'tes.';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
let nextMatchFindAction = new NextMatchFindAction();
@@ -270,7 +270,7 @@ suite.skip('FindController', () => {
findController.toggleRegex();
findController.setSearchString(testRegexString);
findController.start({
await findController.start({
forceRevealReplace: false,
seedSearchStringFromSelection: false,
seedSearchStringFromGlobalClipboard: false,
@@ -279,8 +279,8 @@ suite.skip('FindController', () => {
updateSearchScope: false,
loop: true
});
nextMatchFindAction.run(null, editor);
startFindReplaceAction.run(null, editor);
await nextMatchFindAction.run(null, editor);
await startFindReplaceAction.run(null, editor);
assert.equal(findController.getState().searchString, testRegexString);
@@ -288,15 +288,15 @@ suite.skip('FindController', () => {
});
});
test('issue #9043: Clear search scope when find widget is hidden', () => {
withTestCodeEditor([
test('issue #9043: Clear search scope when find widget is hidden', async () => {
await withAsyncTestCodeEditor([
'var x = (3 * 5)',
'var y = (3 * 5)',
'var z = (3 * 5)',
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
findController.start({
await findController.start({
forceRevealReplace: false,
seedSearchStringFromSelection: false,
seedSearchStringFromGlobalClipboard: false,
@@ -319,15 +319,15 @@ suite.skip('FindController', () => {
});
});
test('issue #18111: Regex replace with single space replaces with no space', () => {
withTestCodeEditor([
test('issue #18111: Regex replace with single space replaces with no space', async () => {
await withAsyncTestCodeEditor([
'HRESULT OnAmbientPropertyChange(DISPID dispid);'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
let startFindAction = new StartFindAction();
startFindAction.run(null, editor);
await startFindAction.run(null, editor);
findController.getState().change({ searchString: '\\b\\s{3}\\b', replaceString: ' ', isRegex: true }, false);
findController.moveToNextMatch();
@@ -344,17 +344,17 @@ suite.skip('FindController', () => {
});
});
test('issue #24714: Regular expression with ^ in search & replace', () => {
withTestCodeEditor([
test('issue #24714: Regular expression with ^ in search & replace', async () => {
await withAsyncTestCodeEditor([
'',
'line2',
'line3'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
let startFindAction = new StartFindAction();
startFindAction.run(null, editor);
await startFindAction.run(null, editor);
findController.getState().change({ searchString: '^', replaceString: 'x', isRegex: true }, false);
findController.moveToNextMatch();
@@ -371,12 +371,12 @@ suite.skip('FindController', () => {
});
});
test('issue #38232: Find Next Selection, regex enabled', () => {
withTestCodeEditor([
test('issue #38232: Find Next Selection, regex enabled', async () => {
await withAsyncTestCodeEditor([
'([funny]',
'',
'([funny]'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
let nextSelectionMatchFindAction = new NextSelectionMatchFindAction();
@@ -388,7 +388,7 @@ suite.skip('FindController', () => {
editor.setSelection(new Selection(1, 1, 1, 9));
// cmd+f3
nextSelectionMatchFindAction.run(null, editor);
await nextSelectionMatchFindAction.run(null, editor);
assert.deepEqual(editor.getSelections()!.map(fromSelection), [
[3, 1, 3, 9]
@@ -398,19 +398,19 @@ suite.skip('FindController', () => {
});
});
test('issue #38232: Find Next Selection, regex enabled, find widget open', () => {
withTestCodeEditor([
test('issue #38232: Find Next Selection, regex enabled, find widget open', async () => {
await withAsyncTestCodeEditor([
'([funny]',
'',
'([funny]'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
clipboardState = '';
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
let startFindAction = new StartFindAction();
let nextSelectionMatchFindAction = new NextSelectionMatchFindAction();
// cmd+f - open find widget
startFindAction.run(null, editor);
await startFindAction.run(null, editor);
// toggle regex
findController.getState().change({ isRegex: true }, false);
@@ -419,7 +419,7 @@ suite.skip('FindController', () => {
editor.setSelection(new Selection(1, 1, 1, 9));
// cmd+f3
nextSelectionMatchFindAction.run(null, editor);
await nextSelectionMatchFindAction.run(null, editor);
assert.deepEqual(editor.getSelections()!.map(fromSelection), [
[3, 1, 3, 9]
@@ -430,7 +430,7 @@ suite.skip('FindController', () => {
});
});
suite.skip('FindController query options persistence', () => {
suite.skip('FindController query options persistence', async () => {
let queryState: { [key: string]: any; } = {};
queryState['editor.isRegex'] = false;
queryState['editor.matchCase'] = false;
@@ -447,13 +447,13 @@ suite.skip('FindController query options persistence', () => {
remove: () => undefined
} as any);
test('matchCase', () => {
withTestCodeEditor([
test('matchCase', async () => {
await withAsyncTestCodeEditor([
'abc',
'ABC',
'XYZ',
'ABC'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
queryState = { 'editor.isRegex': false, 'editor.matchCase': true, 'editor.wholeWord': false };
// The cursor is at the very top, of the file, at the first ABC
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
@@ -461,7 +461,7 @@ suite.skip('FindController query options persistence', () => {
let startFindAction = new StartFindAction();
// I hit Ctrl+F to show the Find dialog
startFindAction.run(null, editor);
await startFindAction.run(null, editor);
// I type ABC.
findState.change({ searchString: 'ABC' }, true);
@@ -474,13 +474,13 @@ suite.skip('FindController query options persistence', () => {
queryState = { 'editor.isRegex': false, 'editor.matchCase': false, 'editor.wholeWord': true };
test('wholeWord', () => {
withTestCodeEditor([
test('wholeWord', async () => {
await withAsyncTestCodeEditor([
'ABC',
'AB',
'XYZ',
'ABC'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
queryState = { 'editor.isRegex': false, 'editor.matchCase': false, 'editor.wholeWord': true };
// The cursor is at the very top, of the file, at the first ABC
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
@@ -488,7 +488,7 @@ suite.skip('FindController query options persistence', () => {
let startFindAction = new StartFindAction();
// I hit Ctrl+F to show the Find dialog
startFindAction.run(null, editor);
await startFindAction.run(null, editor);
// I type AB.
findState.change({ searchString: 'AB' }, true);
@@ -499,13 +499,13 @@ suite.skip('FindController query options persistence', () => {
});
});
test('toggling options is saved', () => {
withTestCodeEditor([
test('toggling options is saved', async () => {
await withAsyncTestCodeEditor([
'ABC',
'AB',
'XYZ',
'ABC'
], { serviceCollection: serviceCollection }, (editor) => {
], { serviceCollection: serviceCollection }, async (editor) => {
queryState = { 'editor.isRegex': false, 'editor.matchCase': false, 'editor.wholeWord': true };
// The cursor is at the very top, of the file, at the first ABC
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
@@ -516,17 +516,17 @@ suite.skip('FindController query options persistence', () => {
});
});
test('issue #27083: Update search scope once find widget becomes visible', () => {
withTestCodeEditor([
test('issue #27083: Update search scope once find widget becomes visible', async () => {
await withAsyncTestCodeEditor([
'var x = (3 * 5)',
'var y = (3 * 5)',
'var z = (3 * 5)',
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, (editor) => {
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, async (editor) => {
// clipboardState = '';
editor.setSelection(new Range(1, 1, 2, 1));
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
findController.start({
await findController.start({
forceRevealReplace: false,
seedSearchStringFromSelection: false,
seedSearchStringFromGlobalClipboard: false,
@@ -540,17 +540,17 @@ suite.skip('FindController query options persistence', () => {
});
});
test('issue #58604: Do not update searchScope if it is empty', () => {
withTestCodeEditor([
test('issue #58604: Do not update searchScope if it is empty', async () => {
await withAsyncTestCodeEditor([
'var x = (3 * 5)',
'var y = (3 * 5)',
'var z = (3 * 5)',
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, (editor) => {
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, async (editor) => {
// clipboardState = '';
editor.setSelection(new Range(1, 2, 1, 2));
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
findController.start({
await findController.start({
forceRevealReplace: false,
seedSearchStringFromSelection: false,
seedSearchStringFromGlobalClipboard: false,
@@ -564,17 +564,17 @@ suite.skip('FindController query options persistence', () => {
});
});
test('issue #58604: Update searchScope if it is not empty', () => {
withTestCodeEditor([
test('issue #58604: Update searchScope if it is not empty', async () => {
await withAsyncTestCodeEditor([
'var x = (3 * 5)',
'var y = (3 * 5)',
'var z = (3 * 5)',
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, (editor) => {
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'always', globalFindClipboard: false } }, async (editor) => {
// clipboardState = '';
editor.setSelection(new Range(1, 2, 1, 3));
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
findController.start({
await findController.start({
forceRevealReplace: false,
seedSearchStringFromSelection: false,
seedSearchStringFromGlobalClipboard: false,
@@ -589,17 +589,17 @@ suite.skip('FindController query options persistence', () => {
});
test('issue #27083: Find in selection when multiple lines are selected', () => {
withTestCodeEditor([
test('issue #27083: Find in selection when multiple lines are selected', async () => {
await withAsyncTestCodeEditor([
'var x = (3 * 5)',
'var y = (3 * 5)',
'var z = (3 * 5)',
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'multiline', globalFindClipboard: false } }, (editor) => {
], { serviceCollection: serviceCollection, find: { autoFindInSelection: 'multiline', globalFindClipboard: false } }, async (editor) => {
// clipboardState = '';
editor.setSelection(new Range(1, 6, 2, 1));
let findController = editor.registerAndInstantiateContribution(TestFindController.ID, TestFindController);
findController.start({
await findController.start({
forceRevealReplace: false,
seedSearchStringFromSelection: false,
seedSearchStringFromGlobalClipboard: false,
@@ -5,6 +5,7 @@
.monaco-editor .monaco-editor-overlaymessage {
padding-bottom: 8px;
z-index: 10000;
}
@keyframes fadeIn {
@@ -29,8 +29,6 @@ export class MessageController extends Disposable implements IEditorContribution
return editor.getContribution<MessageController>(MessageController.ID);
}
private readonly closeTimeout = 3000; // close after 3s
private readonly _editor: ICodeEditor;
private readonly _visible: IContextKey<boolean>;
private readonly _messageWidget = this._register(new MutableDisposable<MessageWidget>());
@@ -70,7 +68,8 @@ export class MessageController extends Disposable implements IEditorContribution
this._messageListeners.add(this._editor.onDidDispose(() => this.closeMessage()));
this._messageListeners.add(this._editor.onDidChangeModel(() => this.closeMessage()));
this._messageListeners.add(new TimeoutTimer(() => this.closeMessage(), this.closeTimeout));
// 3sec
this._messageListeners.add(new TimeoutTimer(() => this.closeMessage(), 3000));
// close on mouse move
let bounds: Range;
+7 -5
View File
@@ -169,7 +169,7 @@ export abstract class PeekViewWidget extends ZoneWidget {
container.appendChild(this._bodyElement);
}
protected _fillHead(container: HTMLElement): void {
protected _fillHead(container: HTMLElement, noCloseAction?: boolean): void {
const titleElement = dom.$('.peekview-title');
dom.append(this._headElement!, titleElement);
dom.addStandardDisposableListener(titleElement, 'click', event => this._onTitleClick(event));
@@ -187,10 +187,12 @@ export abstract class PeekViewWidget extends ZoneWidget {
this._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions);
this._disposables.add(this._actionbarWidget);
this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), Codicon.close.classNames, true, () => {
this.dispose();
return Promise.resolve();
}), { label: false, icon: true });
if (!noCloseAction) {
this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), Codicon.close.classNames, true, () => {
this.dispose();
return Promise.resolve();
}), { label: false, icon: true });
}
}
protected _fillTitleIcon(container: HTMLElement): void {
@@ -174,9 +174,9 @@ export class OneSnippet {
}
return selections;
})!;
});
return !couldSkipThisPlaceholder ? newSelections : this.move(fwd);
return !couldSkipThisPlaceholder ? newSelections ?? [] : this.move(fwd);
}
private _hasPlaceholderBeenCollapsed(placeholder: Placeholder): boolean {
@@ -450,7 +450,7 @@ export class SnippetSession {
modelBasedVariableResolver,
new ClipboardBasedVariableResolver(readClipboardText, idx, indexedSelections.length, editor.getOption(EditorOption.multiCursorPaste) === 'spread'),
new SelectionBasedVariableResolver(model, selection),
new CommentBasedVariableResolver(model),
new CommentBasedVariableResolver(model, selection),
new TimeBasedVariableResolver,
new WorkspaceBasedVariableResolver(workspaceService),
new RandomBasedVariableResolver,
@@ -503,11 +503,9 @@ export class SnippetSession {
if (this._snippets[0].hasPlaceholder) {
return this._move(true);
} else {
return (
undoEdits
.filter(edit => !!edit.identifier) // only use our undo edits
.map(edit => Selection.fromPositions(edit.range.getEndPosition()))
);
return undoEdits
.filter(edit => !!edit.identifier) // only use our undo edits
.map(edit => Selection.fromPositions(edit.range.getEndPosition()));
}
});
this._editor.revealRange(this._editor.getSelections()[0]);
@@ -208,14 +208,15 @@ export class ClipboardBasedVariableResolver implements VariableResolver {
}
export class CommentBasedVariableResolver implements VariableResolver {
constructor(
private readonly _model: ITextModel
private readonly _model: ITextModel,
private readonly _selection: Selection
) {
//
}
resolve(variable: Variable): string | undefined {
const { name } = variable;
const language = this._model.getLanguageIdentifier();
const config = LanguageConfigurationRegistry.getComments(language.id);
const langId = this._model.getLanguageIdAtPosition(this._selection.selectionStartLineNumber, this._selection.selectionStartColumn);
const config = LanguageConfigurationRegistry.getComments(langId);
if (!config) {
return undefined;
}
@@ -439,4 +439,13 @@ suite('SnippetController2', function () {
ctrl.insert('\nfoo');
assertSelections(editor, new Selection(2, 8, 2, 8));
});
test('leading TAB by snippets won\'t replace by spaces #101870', function () {
this.skip();
const ctrl = new SnippetController2(editor, logService, contextKeys);
model.setValue('');
model.updateOptions({ insertSpaces: true, tabSize: 4 });
ctrl.insert('\tHello World\n\tNew Line');
assert.strictEqual(model.getValue(), ' Hello World\n New Line');
});
});
@@ -447,7 +447,7 @@ export class SuggestModel implements IDisposable {
}
let clipboardText: string | undefined;
if (completions.needsClipboard) {
if (completions.needsClipboard || isNonEmptyArray(existingItems)) {
clipboardText = await this._clipboardService.readText();
}
@@ -380,7 +380,7 @@ class SuggestionDetails {
// --- details
if (detail) {
this.type.innerText = detail;
this.type.innerText = detail.length > 100_000 ? `${detail.substr(0, 100_000)}` : detail;
show(this.type);
} else {
this.type.innerText = '';
@@ -5,11 +5,11 @@
import * as aria from 'vs/base/browser/ui/aria/aria';
import { Disposable, IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor, IDiffEditor, IEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
import { IDiffEditorOptions, IEditorOptions, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
import { IModelChangedEvent } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
+20 -2
View File
@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor, IActiveCodeEditor, IEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
import { IEditorContributionCtor } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { View } from 'vs/editor/browser/view/viewImpl';
@@ -34,7 +34,7 @@ export interface ITestCodeEditor extends IActiveCodeEditor {
class TestCodeEditor extends CodeEditorWidget implements ICodeEditor {
//#region testing overrides
protected _createConfiguration(options: editorOptions.IEditorConstructionOptions): IConfiguration {
protected _createConfiguration(options: IEditorConstructionOptions): IConfiguration {
return new TestConfiguration(options);
}
protected _createView(viewModel: ViewModel): [View, boolean] {
@@ -96,6 +96,24 @@ export function withTestCodeEditor(text: string | string[] | null, options: Test
editor.dispose();
}
export async function withAsyncTestCodeEditor(text: string | string[] | null, options: TestCodeEditorCreationOptions, callback: (editor: ITestCodeEditor, viewModel: ViewModel) => Promise<void>): Promise<void> {
// create a model if necessary and remember it in order to dispose it.
if (!options.model) {
if (typeof text === 'string') {
options.model = createTextModel(text);
} else if (text) {
options.model = createTextModel(text.join('\n'));
}
}
const editor = createTestCodeEditor(options);
const viewModel = editor.getViewModel()!;
viewModel.setHasFocus(true);
await callback(<ITestCodeEditor>editor, editor.getViewModel()!);
editor.dispose();
}
export function createTestCodeEditor(options: TestCodeEditorCreationOptions): ITestCodeEditor {
const model = options.model;
+31 -7
View File
@@ -195,7 +195,7 @@ var AMDLoader;
return isEmpty;
};
Utilities.recursiveClone = function (obj) {
if (!obj || typeof obj !== 'object') {
if (!obj || typeof obj !== 'object' || obj instanceof RegExp) {
return obj;
}
var result = Array.isArray(obj) ? [] : {};
@@ -304,6 +304,9 @@ var AMDLoader;
if (typeof options.cspNonce !== 'string') {
options.cspNonce = '';
}
if (typeof options.preferScriptTags === 'undefined') {
options.preferScriptTags = false;
}
if (!Array.isArray(options.nodeModules)) {
options.nodeModules = [];
}
@@ -459,7 +462,9 @@ var AMDLoader;
* Transform a module id to a location. Appends .js to module ids
*/
Configuration.prototype.moduleIdToPaths = function (moduleId) {
if (this.nodeModulesMap[moduleId] === true) {
var isNodeModule = ((this.nodeModulesMap[moduleId] === true)
|| (this.options.amdModulesPattern instanceof RegExp && !this.options.amdModulesPattern.test(moduleId)));
if (isNodeModule) {
// This is a node module...
if (this.isBuild()) {
// ...and we are at build time, drop it
@@ -567,11 +572,24 @@ var AMDLoader;
OnlyOnceScriptLoader.prototype.load = function (moduleManager, scriptSrc, callback, errorback) {
var _this = this;
if (!this._scriptLoader) {
this._scriptLoader = (this._env.isWebWorker
? new WorkerScriptLoader()
: this._env.isNode
? new NodeScriptLoader(this._env)
: new BrowserScriptLoader());
if (this._env.isWebWorker) {
this._scriptLoader = new WorkerScriptLoader();
}
else if (this._env.isElectronRenderer) {
var preferScriptTags = moduleManager.getConfig().getOptionsLiteral().preferScriptTags;
if (preferScriptTags) {
this._scriptLoader = new BrowserScriptLoader();
}
else {
this._scriptLoader = new NodeScriptLoader(this._env);
}
}
else if (this._env.isNode) {
this._scriptLoader = new NodeScriptLoader(this._env);
}
else {
this._scriptLoader = new BrowserScriptLoader();
}
}
var scriptCallbacks = {
callback: callback,
@@ -870,6 +888,12 @@ var AMDLoader;
}
var cachedData = script.createCachedData();
if (cachedData.length === 0 || cachedData.length === lastSize || iteration >= 5) {
// done
return;
}
if (cachedData.length < lastSize) {
// less data than before: skip, try again next round
createLoop();
return;
}
lastSize = cachedData.length;
+28 -8
View File
@@ -3138,13 +3138,6 @@ declare namespace monaco.editor {
showDeprecated?: boolean;
}
export interface IEditorConstructionOptions extends IEditorOptions {
/**
* The initial editor dimension (to avoid measuring the container).
*/
dimension?: IDimension;
}
/**
* Configuration options for the diff editor.
*/
@@ -3179,10 +3172,20 @@ declare namespace monaco.editor {
* Defaults to false.
*/
originalEditable?: boolean;
/**
/** // {{SQL CARBON EDIT}}
* Adding option to reverse coloring in diff editor
*/
reverse?: boolean;
/**
* Original editor should be have code lens enabled?
* Defaults to false.
*/
originalCodeLens?: boolean;
/**
* Modified editor should be have code lens enabled?
* Defaults to false.
*/
modifiedCodeLens?: boolean;
}
/**
@@ -3214,6 +3217,11 @@ declare namespace monaco.editor {
* Defaults to true.
*/
insertSpace?: boolean;
/**
* Ignore empty lines when inserting line comments.
* Defaults to true.
*/
ignoreEmptyLines?: boolean;
}
export type EditorCommentsOptions = Readonly<Required<IEditorCommentsOptions>>;
@@ -4394,6 +4402,18 @@ declare namespace monaco.editor {
readonly mode: string | null;
}
export interface IEditorConstructionOptions extends IEditorOptions {
/**
* The initial editor dimension (to avoid measuring the container).
*/
dimension?: IDimension;
/**
* Place overflow widgets inside an external DOM node.
* Defaults to an internal DOM node.
*/
overflowWidgetsDomNode?: HTMLElement;
}
/**
* A rich code editor.
*/
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as json from 'vs/base/common/json';
import { ResourceMap, values, getOrSet } from 'vs/base/common/map';
import { ResourceMap, getOrSet } from 'vs/base/common/map';
import * as arrays from 'vs/base/common/arrays';
import * as types from 'vs/base/common/types';
import * as objects from 'vs/base/common/objects';
@@ -692,7 +692,7 @@ export class Configuration {
this.userConfiguration.freeze().keys.forEach(key => keys.add(key));
this._workspaceConfiguration.freeze().keys.forEach(key => keys.add(key));
this._folderConfigurations.forEach(folderConfiguraiton => folderConfiguraiton.freeze().keys.forEach(key => keys.add(key)));
return values(keys);
return [...keys.values()];
}
protected getAllKeysForOverrideIdentifier(overrideIdentifier: string): string[] {
@@ -701,7 +701,7 @@ export class Configuration {
this.userConfiguration.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key));
this._workspaceConfiguration.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key));
this._folderConfigurations.forEach(folderConfiguraiton => folderConfiguraiton.getKeysForOverrideIdentifier(overrideIdentifier).forEach(key => keys.add(key)));
return values(keys);
return [...keys.values()];
}
static parse(data: IConfigurationData): Configuration {
@@ -738,8 +738,8 @@ export function mergeChanges(...changes: IConfigurationChange[]): IConfiguration
});
}
const overrides: [string, string[]][] = [];
overridesMap.forEach((keys, identifier) => overrides.push([identifier, values(keys)]));
return { keys: values(keysSet), overrides };
overridesMap.forEach((keys, identifier) => overrides.push([identifier, [...keys.values()]]));
return { keys: [...keysSet.values()], overrides };
}
export class ConfigurationChangeEvent implements IConfigurationChangeEvent {
@@ -753,7 +753,7 @@ export class ConfigurationChangeEvent implements IConfigurationChangeEvent {
const keysSet = new Set<string>();
change.keys.forEach(key => keysSet.add(key));
change.overrides.forEach(([, keys]) => keys.forEach(key => keysSet.add(key)));
this.affectedKeys = values(keysSet);
this.affectedKeys = [...keysSet.values()];
const configurationModel = new ConfigurationModel();
this.affectedKeys.forEach(key => configurationModel.setValue(key, {}));
@@ -10,7 +10,6 @@ import { Registry } from 'vs/platform/registry/common/platform';
import * as types from 'vs/base/common/types';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { values } from 'vs/base/common/map';
export const Extensions = {
Configuration: 'base.contributions.configuration'
@@ -395,7 +394,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
}
private updateOverridePropertyPatternKey(): void {
for (const overrideIdentifier of values(this.overrideIdentifiers)) {
for (const overrideIdentifier of this.overrideIdentifiers.values()) {
const overrideIdentifierProperty = `[${overrideIdentifier}]`;
const resourceLanguagePropertiesSchema: IJSONSchema = {
type: 'object',
@@ -0,0 +1,246 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { Registry } from 'vs/platform/registry/common/platform';
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { URI } from 'vs/base/common/uri';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { Event } from 'vs/base/common/event';
import { NullLogService } from 'vs/platform/log/common/log';
import { FileService } from 'vs/platform/files/common/fileService';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
import { VSBuffer } from 'vs/base/common/buffer';
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
suite('ConfigurationService', () => {
let fileService: IFileService;
let settingsResource: URI;
const disposables: DisposableStore = new DisposableStore();
setup(async () => {
fileService = disposables.add(new FileService(new NullLogService()));
const diskFileSystemProvider = disposables.add(new InMemoryFileSystemProvider());
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
settingsResource = URI.file('settings.json');
});
teardown(() => disposables.clear());
test('simple', async () => {
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }'));
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
await testObject.initialize();
const config = testObject.getValue<{
foo: string;
}>();
assert.ok(config);
assert.equal(config.foo, 'bar');
});
test('config gets flattened', async () => {
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }'));
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
await testObject.initialize();
const config = testObject.getValue<{
testworkbench: {
editor: {
tabs: boolean;
};
};
}>();
assert.ok(config);
assert.ok(config.testworkbench);
assert.ok(config.testworkbench.editor);
assert.equal(config.testworkbench.editor.tabs, true);
});
test('error case does not explode', async () => {
await fileService.writeFile(settingsResource, VSBuffer.fromString(',,,,'));
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
await testObject.initialize();
const config = testObject.getValue<{
foo: string;
}>();
assert.ok(config);
});
test('missing file does not explode', async () => {
const testObject = disposables.add(new ConfigurationService(URI.file('__testFile'), fileService));
await testObject.initialize();
const config = testObject.getValue<{ foo: string }>();
assert.ok(config);
});
test('trigger configuration change event when file does not exist', async () => {
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
await testObject.initialize();
return new Promise(async (c, e) => {
disposables.add(Event.filter(testObject.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(() => {
assert.equal(testObject.getValue('foo'), 'bar');
c();
}));
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }'));
});
});
test('trigger configuration change event when file exists', async () => {
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }'));
await testObject.initialize();
return new Promise((c, e) => {
disposables.add(Event.filter(testObject.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
assert.equal(testObject.getValue('foo'), 'barz');
c();
}));
fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "barz" }'));
});
});
test('reloadConfiguration', async () => {
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "bar" }'));
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
await testObject.initialize();
let config = testObject.getValue<{
foo: string;
}>();
assert.ok(config);
assert.equal(config.foo, 'bar');
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "foo": "changed" }'));
// force a reload to get latest
await testObject.reloadConfiguration();
config = testObject.getValue<{
foo: string;
}>();
assert.ok(config);
assert.equal(config.foo, 'changed');
});
test('model defaults', async () => {
interface ITestSetting {
configuration: {
service: {
testSetting: string;
}
};
}
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'configuration.service.testSetting': {
'type': 'string',
'default': 'isSet'
}
}
});
let testObject = disposables.add(new ConfigurationService(URI.file('__testFile'), fileService));
await testObject.initialize();
let setting = testObject.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isSet');
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "testworkbench.editor.tabs": true }'));
testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
setting = testObject.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isSet');
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "configuration.service.testSetting": "isChanged" }'));
await testObject.reloadConfiguration();
setting = testObject.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isChanged');
});
test('lookup', async () => {
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'lookup.service.testSetting': {
'type': 'string',
'default': 'isSet'
}
}
});
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
testObject.initialize();
let res = testObject.inspect('something.missing');
assert.strictEqual(res.value, undefined);
assert.strictEqual(res.defaultValue, undefined);
assert.strictEqual(res.userValue, undefined);
res = testObject.inspect('lookup.service.testSetting');
assert.strictEqual(res.defaultValue, 'isSet');
assert.strictEqual(res.value, 'isSet');
assert.strictEqual(res.userValue, undefined);
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "lookup.service.testSetting": "bar" }'));
await testObject.reloadConfiguration();
res = testObject.inspect('lookup.service.testSetting');
assert.strictEqual(res.defaultValue, 'isSet');
assert.strictEqual(res.userValue, 'bar');
assert.strictEqual(res.value, 'bar');
});
test('lookup with null', async () => {
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_testNull',
'type': 'object',
'properties': {
'lookup.service.testNullSetting': {
'type': 'null',
}
}
});
const testObject = disposables.add(new ConfigurationService(settingsResource, fileService));
testObject.initialize();
let res = testObject.inspect('lookup.service.testNullSetting');
assert.strictEqual(res.defaultValue, null);
assert.strictEqual(res.value, null);
assert.strictEqual(res.userValue, undefined);
await fileService.writeFile(settingsResource, VSBuffer.fromString('{ "lookup.service.testNullSetting": null }'));
await testObject.reloadConfiguration();
res = testObject.inspect('lookup.service.testNullSetting');
assert.strictEqual(res.defaultValue, null);
assert.strictEqual(res.value, null);
assert.strictEqual(res.userValue, null);
});
});
@@ -1,304 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as os from 'os';
import * as path from 'vs/base/common/path';
import * as fs from 'fs';
import { Registry } from 'vs/platform/registry/common/platform';
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
import * as uuid from 'vs/base/common/uuid';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { testFile } from 'vs/base/test/node/utils';
import { URI } from 'vs/base/common/uri';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { Event } from 'vs/base/common/event';
import { NullLogService } from 'vs/platform/log/common/log';
import { FileService } from 'vs/platform/files/common/fileService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
import { VSBuffer } from 'vs/base/common/buffer';
suite('ConfigurationService - Node', () => {
let fileService: IFileService;
const disposables: IDisposable[] = [];
setup(() => {
const logService = new NullLogService();
fileService = new FileService(logService);
disposables.push(fileService);
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
disposables.push(diskFileSystemProvider);
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
});
test('simple', async () => {
const res = await testFile('config', 'config.json');
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
const config = service.getValue<{
foo: string;
}>();
assert.ok(config);
assert.equal(config.foo, 'bar');
service.dispose();
return res.cleanUp();
});
test('config gets flattened', async () => {
const res = await testFile('config', 'config.json');
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
const config = service.getValue<{
testworkbench: {
editor: {
tabs: boolean;
};
};
}>();
assert.ok(config);
assert.ok(config.testworkbench);
assert.ok(config.testworkbench.editor);
assert.equal(config.testworkbench.editor.tabs, true);
service.dispose();
return res.cleanUp();
});
test('error case does not explode', async () => {
const res = await testFile('config', 'config.json');
fs.writeFileSync(res.testFile, ',,,,');
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
const config = service.getValue<{
foo: string;
}>();
assert.ok(config);
service.dispose();
return res.cleanUp();
});
test('missing file does not explode', async () => {
const id = uuid.generateUuid();
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
const newDir = path.join(parentDir, 'config', id);
const testFile = path.join(newDir, 'config.json');
const service = new ConfigurationService(URI.file(testFile), fileService);
await service.initialize();
const config = service.getValue<{ foo: string }>();
assert.ok(config);
service.dispose();
});
test('trigger configuration change event when file does not exist', async () => {
const res = await testFile('config', 'config.json');
const settingsFile = URI.file(res.testFile);
const service = new ConfigurationService(settingsFile, fileService);
await service.initialize();
return new Promise(async (c, e) => {
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
disposable.dispose();
assert.equal(service.getValue('foo'), 'bar');
service.dispose();
await res.cleanUp();
c();
});
await fileService.writeFile(settingsFile, VSBuffer.fromString('{ "foo": "bar" }'));
});
});
test('trigger configuration change event when file exists', async () => {
const res = await testFile('config', 'config.json');
const service = new ConfigurationService(URI.file(res.testFile), fileService);
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
await service.initialize();
return new Promise((c, e) => {
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
disposable.dispose();
assert.equal(service.getValue('foo'), 'barz');
service.dispose();
await res.cleanUp();
c();
});
fs.writeFileSync(res.testFile, '{ "foo": "barz" }');
});
});
test('reloadConfiguration', async () => {
const res = await testFile('config', 'config.json');
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
const service = new ConfigurationService(URI.file(res.testFile), fileService);
await service.initialize();
let config = service.getValue<{
foo: string;
}>();
assert.ok(config);
assert.equal(config.foo, 'bar');
fs.writeFileSync(res.testFile, '{ "foo": "changed" }');
// still outdated
config = service.getValue<{
foo: string;
}>();
assert.ok(config);
assert.equal(config.foo, 'bar');
// force a reload to get latest
await service.reloadConfiguration();
config = service.getValue<{
foo: string;
}>();
assert.ok(config);
assert.equal(config.foo, 'changed');
service.dispose();
return res.cleanUp();
});
test('model defaults', async () => {
interface ITestSetting {
configuration: {
service: {
testSetting: string;
}
};
}
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'configuration.service.testSetting': {
'type': 'string',
'default': 'isSet'
}
}
});
let serviceWithoutFile = new ConfigurationService(URI.file('__testFile'), fileService);
await serviceWithoutFile.initialize();
let setting = serviceWithoutFile.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isSet');
return testFile('config', 'config.json').then(async res => {
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
const service = new ConfigurationService(URI.file(res.testFile), fileService);
let setting = service.getValue<ITestSetting>();
assert.ok(setting);
assert.equal(setting.configuration.service.testSetting, 'isSet');
fs.writeFileSync(res.testFile, '{ "configuration.service.testSetting": "isChanged" }');
await service.reloadConfiguration();
let setting_1 = service.getValue<ITestSetting>();
assert.ok(setting_1);
assert.equal(setting_1.configuration.service.testSetting, 'isChanged');
service.dispose();
serviceWithoutFile.dispose();
return res.cleanUp();
});
});
test('lookup', async () => {
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'lookup.service.testSetting': {
'type': 'string',
'default': 'isSet'
}
}
});
const r = await testFile('config', 'config.json');
const service = new ConfigurationService(URI.file(r.testFile), fileService);
service.initialize();
let res = service.inspect('something.missing');
assert.strictEqual(res.value, undefined);
assert.strictEqual(res.defaultValue, undefined);
assert.strictEqual(res.userValue, undefined);
res = service.inspect('lookup.service.testSetting');
assert.strictEqual(res.defaultValue, 'isSet');
assert.strictEqual(res.value, 'isSet');
assert.strictEqual(res.userValue, undefined);
fs.writeFileSync(r.testFile, '{ "lookup.service.testSetting": "bar" }');
await service.reloadConfiguration();
res = service.inspect('lookup.service.testSetting');
assert.strictEqual(res.defaultValue, 'isSet');
assert.strictEqual(res.userValue, 'bar');
assert.strictEqual(res.value, 'bar');
service.dispose();
return r.cleanUp();
});
test('lookup with null', async () => {
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
'id': '_testNull',
'type': 'object',
'properties': {
'lookup.service.testNullSetting': {
'type': 'null',
}
}
});
const r = await testFile('config', 'config.json');
const service = new ConfigurationService(URI.file(r.testFile), fileService);
service.initialize();
let res = service.inspect('lookup.service.testNullSetting');
assert.strictEqual(res.defaultValue, null);
assert.strictEqual(res.value, null);
assert.strictEqual(res.userValue, undefined);
fs.writeFileSync(r.testFile, '{ "lookup.service.testNullSetting": null }');
await service.reloadConfiguration();
res = service.inspect('lookup.service.testNullSetting');
assert.strictEqual(res.defaultValue, null);
assert.strictEqual(res.value, null);
assert.strictEqual(res.userValue, null);
service.dispose();
return r.cleanUp();
});
});
@@ -5,11 +5,11 @@
import { Emitter, Event, PauseableEmitter } from 'vs/base/common/event';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { keys } from 'vs/base/common/map';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, SET_CONTEXT_COMMAND_ID, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
import { toArray } from 'vs/base/common/arrays';
const KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context';
@@ -102,7 +102,7 @@ class ConfigAwareContextValuesContainer extends Context {
this._listener = this._configurationService.onDidChangeConfiguration(event => {
if (event.source === ConfigurationTarget.DEFAULT) {
// new setting, reset everything
const allKeys = keys(this._values);
const allKeys = toArray(this._values.keys());
this._values.clear();
emitter.fire(new ArrayContextKeyChangeEvent(allKeys));
} else {
@@ -1167,7 +1167,6 @@ export interface IContextKeyService {
onDidChangeContext: Event<IContextKeyChangeEvent>;
bufferChangeEvents(callback: Function): void;
createKey<T>(key: string, defaultValue: T | undefined): IContextKey<T>;
contextMatchesRules(rules: ContextKeyExpression | undefined): boolean;
getContextKeyValue<T>(key: string): T | undefined;
@@ -63,6 +63,7 @@ export interface ICommonElectronService {
openExternal(url: string): Promise<boolean>;
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
moveItemToTrash(fullPath: string, deleteOnFail?: boolean): Promise<boolean>;
isAdmin(): Promise<boolean>;
// clipboard
readClipboardText(type?: 'selection' | 'clipboard'): Promise<string>;
@@ -10,7 +10,7 @@ import { OpenContext } from 'vs/platform/windows/node/window';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { IOpenedWindow, IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs';
import { isMacintosh } from 'vs/base/common/platform';
import { isMacintosh, isWindows, isRootUser } from 'vs/base/common/platform';
import { ICommonElectronService } from 'vs/platform/electron/common/electron';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -302,6 +302,17 @@ export class ElectronMainService implements IElectronMainService {
return shell.moveItemToTrash(fullPath);
}
async isAdmin(): Promise<boolean> {
let isAdmin: boolean;
if (isWindows) {
isAdmin = (await import('native-is-elevated'))();
} else {
isAdmin = isRootUser();
}
return isAdmin;
}
//#endregion
@@ -40,6 +40,9 @@ export interface IEnvironmentService {
backupHome: URI;
untitledWorkspacesHome: URI;
globalStorageHome: URI;
workspaceStorageHome: URI;
// --- settings sync
userDataSyncLogResource: URI;
userDataSyncHome: URI;
+2
View File
@@ -33,6 +33,7 @@ export interface ParsedArgs {
trace?: boolean;
'trace-category-filter'?: string;
'trace-options'?: string;
'open-devtools'?: boolean;
log?: string;
logExtensionHostCommunication?: boolean;
'extensions-dir'?: string;
@@ -202,6 +203,7 @@ export const OPTIONS: OptionDescriptions<Required<ParsedArgs>> = {
'trace-category-filter': { type: 'string' },
'trace-options': { type: 'string' },
'force-user-env': { type: 'boolean' },
'open-devtools': { type: 'boolean' },
// {{SQL CARBON EDIT}} Start
'command': { type: 'string', alias: 'c', cat: 'o', args: 'command-name', description: localize('commandParameter', 'Name of command to run') },
@@ -39,9 +39,6 @@ export interface INativeEnvironmentService extends IEnvironmentService {
extensionsDownloadPath: string;
builtinExtensionsPath: string;
globalStorageHome: string;
workspaceStorageHome: string;
driverHandle?: string;
driverVerbose: boolean;
@@ -102,10 +99,10 @@ export class EnvironmentService implements INativeEnvironmentService {
get machineSettingsResource(): URI { return resources.joinPath(URI.file(path.join(this.userDataPath, 'Machine')), 'settings.json'); }
@memoize
get globalStorageHome(): string { return path.join(this.appSettingsHome.fsPath, 'globalStorage'); }
get globalStorageHome(): URI { return URI.joinPath(this.appSettingsHome, 'globalStorage'); }
@memoize
get workspaceStorageHome(): string { return path.join(this.appSettingsHome.fsPath, 'workspaceStorage'); }
get workspaceStorageHome(): URI { return URI.joinPath(this.appSettingsHome, 'workspaceStorage'); }
@memoize
get keybindingsResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'keybindings.json'); }
+4 -1
View File
@@ -56,7 +56,10 @@ export async function readFromStdin(targetPath: string, verbose: boolean): Promi
const decoder = iconv.getDecoder(encoding);
process.stdin.on('data', chunk => stdinFileStream.write(decoder.write(chunk)));
process.stdin.on('end', () => {
stdinFileStream.write(decoder.end());
const end = decoder.end();
if (typeof end === 'string') {
stdinFileStream.write(end);
}
stdinFileStream.end();
});
process.stdin.on('error', error => stdinFileStream.destroy(error));
@@ -13,7 +13,6 @@ import { IRequestService, asJson, asText } from 'vs/platform/request/common/requ
import { IRequestOptions, IRequestContext, IHeaders } from 'vs/base/parts/request/common/request';
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { values } from 'vs/base/common/map';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; // {{SQL CARBON EDIT}}
import { CancellationToken } from 'vs/base/common/cancellation';
import { ILogService } from 'vs/platform/log/common/log';
@@ -930,7 +929,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
}
}
return Promise.resolve(values(map));
return [...map.values()];
});
});
}
@@ -10,7 +10,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { URI } from 'vs/base/common/uri';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IExtensionManifest, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
import { IExeBasedExtensionTip } from 'vs/platform/product/common/productService';
export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$';
export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);
@@ -239,7 +238,15 @@ export type IConfigBasedExtensionTip = {
readonly configName: string,
readonly important: boolean,
};
export type IExecutableBasedExtensionTip = { extensionId: string } & Omit<Omit<IExeBasedExtensionTip, 'recommendations'>, 'important'>;
export type IExecutableBasedExtensionTip = {
readonly extensionId: string,
readonly extensionName: string,
readonly isExtensionPack: boolean,
readonly exeFriendlyName: string,
readonly windowsPath?: string,
};
export type IWorkspaceTips = { readonly remoteSet: string[]; readonly recommendations: string[]; };
export const IExtensionTipsService = createDecorator<IExtensionTipsService>('IExtensionTipsService');
@@ -14,7 +14,6 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { ILogService } from 'vs/platform/log/common/log';
import { joinPath } from 'vs/base/common/resources';
import { getDomainsOfRemotes } from 'vs/platform/extensionManagement/common/configRemotes';
import { keys } from 'vs/base/common/map';
export class ExtensionTipsService implements IExtensionTipsService {
@@ -76,7 +75,7 @@ export class ExtensionTipsService implements IExtensionTipsService {
});
}
});
const domains = getDomainsOfRemotes(content.value.toString(), keys(recommendationByRemote));
const domains = getDomainsOfRemotes(content.value.toString(), [...recommendationByRemote.keys()]);
for (const domain of domains) {
const remote = recommendationByRemote.get(domain);
if (remote) {
@@ -130,6 +130,6 @@ export class ExtensionsLifecycle extends Disposable {
}
private getExtensionStoragePath(extension: ILocalExtension): string {
return join(this.environmentService.globalStorageHome, extension.identifier.id.toLowerCase());
return join(this.environmentService.globalStorageHome.fsPath, extension.identifier.id.toLowerCase());
}
}
@@ -5,7 +5,7 @@
import { URI } from 'vs/base/common/uri';
import { join, } from 'vs/base/common/path';
import { IProductService, IExeBasedExtensionTip } from 'vs/platform/product/common/productService';
import { IProductService } from 'vs/platform/product/common/productService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { env as processEnv } from 'vs/base/common/process';
import { INativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
@@ -13,17 +13,23 @@ import { IFileService } from 'vs/platform/files/common/files';
import { isWindows } from 'vs/base/common/platform';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IStringDictionary, forEach } from 'vs/base/common/collections';
import { forEach } from 'vs/base/common/collections';
import { IRequestService } from 'vs/platform/request/common/request';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtensionTipsService as BaseExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionTipsService';
type IExeBasedExtensionTips = {
readonly exeFriendlyName: string,
readonly windowsPath?: string,
readonly recommendations: { extensionId: string, extensionName: string, isExtensionPack: boolean }[];
};
export class ExtensionTipsService extends BaseExtensionTipsService {
_serviceBrand: any;
private readonly allImportantExecutableTips: IStringDictionary<IExeBasedExtensionTip> = {};
private readonly allOtherExecutableTips: IStringDictionary<IExeBasedExtensionTip> = {};
private readonly allImportantExecutableTips: Map<string, IExeBasedExtensionTips> = new Map<string, IExeBasedExtensionTips>();
private readonly allOtherExecutableTips: Map<string, IExeBasedExtensionTips> = new Map<string, IExeBasedExtensionTips>();
constructor(
@IEnvironmentService private readonly environmentService: INativeEnvironmentService,
@@ -35,10 +41,20 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
super(fileService, productService, requestService, logService);
if (productService.exeBasedExtensionTips) {
forEach(productService.exeBasedExtensionTips, ({ key, value }) => {
if (value.important) {
this.allImportantExecutableTips[key] = value;
} else {
this.allOtherExecutableTips[key] = value;
const importantRecommendations: { extensionId: string, extensionName: string, isExtensionPack: boolean }[] = [];
const otherRecommendations: { extensionId: string, extensionName: string, isExtensionPack: boolean }[] = [];
forEach(value.recommendations, ({ key: extensionId, value }) => {
if (value.important) {
importantRecommendations.push({ extensionId, extensionName: value.name, isExtensionPack: !!value.isExtensionPack });
} else {
otherRecommendations.push({ extensionId, extensionName: value.name, isExtensionPack: !!value.isExtensionPack });
}
});
if (importantRecommendations.length) {
this.allImportantExecutableTips.set(key, { exeFriendlyName: value.friendlyName, windowsPath: value.windowsPath, recommendations: importantRecommendations });
}
if (otherRecommendations.length) {
this.allOtherExecutableTips.set(key, { exeFriendlyName: value.friendlyName, windowsPath: value.windowsPath, recommendations: otherRecommendations });
}
});
}
@@ -52,13 +68,13 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
return this.getValidExecutableBasedExtensionTips(this.allOtherExecutableTips);
}
private async getValidExecutableBasedExtensionTips(executableTips: IStringDictionary<IExeBasedExtensionTip>): Promise<IExecutableBasedExtensionTip[]> {
private async getValidExecutableBasedExtensionTips(executableTips: Map<string, IExeBasedExtensionTips>): Promise<IExecutableBasedExtensionTip[]> {
const result: IExecutableBasedExtensionTip[] = [];
const checkedExecutables: Map<string, boolean> = new Map<string, boolean>();
for (const exeName of Object.keys(executableTips)) {
const extensionTip = executableTips[exeName];
if (!isNonEmptyArray(extensionTip?.recommendations)) {
for (const exeName of executableTips.keys()) {
const extensionTip = executableTips.get(exeName);
if (!extensionTip || !isNonEmptyArray(extensionTip.recommendations)) {
continue;
}
@@ -83,12 +99,15 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
checkedExecutables.set(exePath, exists);
}
if (exists) {
extensionTip.recommendations.forEach(recommendation => result.push({
extensionId: recommendation,
friendlyName: extensionTip.friendlyName,
exeFriendlyName: extensionTip.exeFriendlyName,
windowsPath: extensionTip.windowsPath,
}));
for (const { extensionId, extensionName, isExtensionPack } of extensionTip.recommendations) {
result.push({
extensionId,
extensionName,
isExtensionPack,
exeFriendlyName: extensionTip.exeFriendlyName,
windowsPath: extensionTip.windowsPath,
});
}
}
}
}
@@ -63,8 +63,6 @@ export class IndexedDB {
}
class IndexedDBFileSystemProvider extends KeyValueFileSystemProvider {
constructor(scheme: string, private readonly database: IDBDatabase, private readonly store: string) {
+9 -9
View File
@@ -26,19 +26,19 @@ export class FileService extends Disposable implements IFileService {
private readonly BUFFER_SIZE = 64 * 1024;
constructor(@ILogService private logService: ILogService) {
constructor(@ILogService private readonly logService: ILogService) {
super();
}
//#region File System Provider
private _onDidChangeFileSystemProviderRegistrations = this._register(new Emitter<IFileSystemProviderRegistrationEvent>());
private readonly _onDidChangeFileSystemProviderRegistrations = this._register(new Emitter<IFileSystemProviderRegistrationEvent>());
readonly onDidChangeFileSystemProviderRegistrations = this._onDidChangeFileSystemProviderRegistrations.event;
private _onWillActivateFileSystemProvider = this._register(new Emitter<IFileSystemProviderActivationEvent>());
private readonly _onWillActivateFileSystemProvider = this._register(new Emitter<IFileSystemProviderActivationEvent>());
readonly onWillActivateFileSystemProvider = this._onWillActivateFileSystemProvider.event;
private _onDidChangeFileSystemProviderCapabilities = this._register(new Emitter<IFileSystemProviderCapabilitiesChangeEvent>());
private readonly _onDidChangeFileSystemProviderCapabilities = this._register(new Emitter<IFileSystemProviderCapabilitiesChangeEvent>());
readonly onDidChangeFileSystemProviderCapabilities = this._onDidChangeFileSystemProviderCapabilities.event;
private readonly provider = new Map<string, IFileSystemProvider>();
@@ -146,10 +146,10 @@ export class FileService extends Disposable implements IFileService {
//#endregion
private _onDidRunOperation = this._register(new Emitter<FileOperationEvent>());
private readonly _onDidRunOperation = this._register(new Emitter<FileOperationEvent>());
readonly onDidRunOperation = this._onDidRunOperation.event;
private _onError = this._register(new Emitter<Error>());
private readonly _onError = this._register(new Emitter<Error>());
readonly onError = this._onError.event;
//#region File Metadata Resolving
@@ -881,10 +881,10 @@ export class FileService extends Disposable implements IFileService {
//#region File Watching
private _onDidFilesChange = this._register(new Emitter<FileChangesEvent>());
private readonly _onDidFilesChange = this._register(new Emitter<FileChangesEvent>());
readonly onDidFilesChange = this._onDidFilesChange.event;
private activeWatchers = new Map<string, { disposable: IDisposable, count: number }>();
private readonly activeWatchers = new Map<string, { disposable: IDisposable, count: number }>();
watch(resource: URI, options: IWatchOptions = { recursive: false, excludes: [] }): IDisposable {
let watchDisposed = false;
@@ -950,7 +950,7 @@ export class FileService extends Disposable implements IFileService {
//#region Helpers
private writeQueues: Map<string, Queue<void>> = new Map();
private readonly writeQueues: Map<string, Queue<void>> = new Map();
private ensureWriteQueue(provider: IFileSystemProvider, resource: URI): Queue<void> {
const { extUri } = this.getExtUri(provider);
@@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri';
class File implements IStat {
type: FileType;
type: FileType.File;
ctime: number;
mtime: number;
size: number;
@@ -30,7 +30,7 @@ class File implements IStat {
class Directory implements IStat {
type: FileType;
type: FileType.Directory;
ctime: number;
mtime: number;
size: number;
@@ -9,7 +9,6 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { VSBuffer } from 'vs/base/common/buffer';
import { joinPath, extUri, dirname } from 'vs/base/common/resources';
import { values } from 'vs/base/common/map';
import { localize } from 'vs/nls';
export abstract class KeyValueFileSystemProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability {
@@ -97,7 +96,7 @@ export abstract class KeyValueFileSystemProvider extends Disposable implements I
}
}
}
return values(files);
return [...files.values()];
}
async readFile(resource: URI): Promise<Uint8Array> {
@@ -15,7 +15,7 @@ export class DiskFileSystemProvider extends NodeDiskFileSystemProvider {
constructor(
logService: ILogService,
private electronService: IElectronService,
private readonly electronService: IElectronService,
options?: IDiskFileSystemProviderOptions
) {
super(logService, options);
@@ -46,7 +46,10 @@ export class DiskFileSystemProvider extends Disposable implements
private readonly BUFFER_SIZE = this.options?.bufferSize || 64 * 1024;
constructor(private logService: ILogService, private options?: IDiskFileSystemProviderOptions) {
constructor(
private readonly logService: ILogService,
private readonly options?: IDiskFileSystemProviderOptions
) {
super();
}
@@ -198,9 +201,9 @@ export class DiskFileSystemProvider extends Disposable implements
}
}
private mapHandleToPos: Map<number, number> = new Map();
private readonly mapHandleToPos: Map<number, number> = new Map();
private writeHandles: Set<number> = new Set();
private readonly writeHandles: Set<number> = new Set();
private canFlush: boolean = true;
async open(resource: URI, opts: FileOpenOptions): Promise<number> {
@@ -502,14 +505,14 @@ export class DiskFileSystemProvider extends Disposable implements
//#region File Watching
private _onDidWatchErrorOccur = this._register(new Emitter<string>());
private readonly _onDidWatchErrorOccur = this._register(new Emitter<string>());
readonly onDidErrorOccur = this._onDidWatchErrorOccur.event;
private _onDidChangeFile = this._register(new Emitter<readonly IFileChange[]>());
private readonly _onDidChangeFile = this._register(new Emitter<readonly IFileChange[]>());
readonly onDidChangeFile = this._onDidChangeFile.event;
private recursiveWatcher: WindowsWatcherService | UnixWatcherService | NsfwWatcherService | undefined;
private recursiveFoldersToWatch: { path: string, excludes: string[] }[] = [];
private readonly recursiveFoldersToWatch: { path: string, excludes: string[] }[] = [];
private recursiveWatchRequestDelayer = this._register(new ThrottledDelayer<void>(0));
private recursiveWatcherLogLevelListener: IDisposable | undefined;
@@ -20,6 +20,7 @@ import { listProcesses } from 'vs/base/node/ps';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { zoomLevelToZoomFactor } from 'vs/platform/windows/common/windows';
const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
@@ -198,7 +199,8 @@ export class IssueMainService implements ICommonIssueService {
nodeIntegration: true,
enableWebSQL: false,
enableRemoteModule: false,
nativeWindowOpen: true
nativeWindowOpen: true,
zoomFactor: zoomLevelToZoomFactor(data.zoomLevel)
}
});
@@ -251,7 +253,8 @@ export class IssueMainService implements ICommonIssueService {
nodeIntegration: true,
enableWebSQL: false,
enableRemoteModule: false,
nativeWindowOpen: true
nativeWindowOpen: true,
zoomFactor: zoomLevelToZoomFactor(data.zoomLevel)
}
});

Some files were not shown because too many files have changed in this diff Show More