Archived
Merge branch 'ads-main-vscode-2020-09-03T02-34-50' into main
This commit is contained in:
@@ -16,6 +16,7 @@ exports.base = [{
|
||||
}];
|
||||
|
||||
exports.workerExtensionHost = [entrypoint('vs/workbench/services/extensions/worker/extensionHostWorker')];
|
||||
exports.workerNotebook = [entrypoint('vs/workbench/contrib/notebook/common/services/notebookSimpleWorker')];
|
||||
|
||||
exports.workbenchDesktop = require('./vs/workbench/buildfile.desktop').collectModules();
|
||||
exports.workbenchWeb = require('./vs/workbench/buildfile.web').collectModules();
|
||||
|
||||
@@ -92,7 +92,7 @@ export default class DiffEditorComponent extends ComponentBase implements ICompo
|
||||
let editorinput1 = this._instantiationService.createInstance(ResourceEditorInput, uri1, 'source', undefined, undefined);
|
||||
let editorinput2 = this._instantiationService.createInstance(ResourceEditorInput, uri2, 'target', undefined, undefined);
|
||||
this._editorInput = new DiffEditorInput('DiffEditor', undefined, editorinput1, editorinput2, true);
|
||||
this._editor.setInput(this._editorInput, undefined, cancellationTokenSource.token);
|
||||
this._editor.setInput(this._editorInput, undefined, undefined, cancellationTokenSource.token);
|
||||
|
||||
|
||||
this._editorInput.resolve().then(model => {
|
||||
|
||||
@@ -70,7 +70,7 @@ export default class EditorComponent extends ComponentBase implements IComponent
|
||||
this._editor.setVisible(true);
|
||||
let uri = this.createUri();
|
||||
this._editorInput = this.editorService.createEditorInput({ forceUntitled: true, resource: uri, mode: 'plaintext' }) as UntitledTextEditorInput;
|
||||
await this._editor.setInput(this._editorInput, undefined);
|
||||
await this._editor.setInput(this._editorInput, undefined, undefined);
|
||||
const model = await this._editorInput.resolve();
|
||||
this._editorModel = model.textEditorModel;
|
||||
this.fireEvent({
|
||||
|
||||
@@ -6,15 +6,15 @@ import 'vs/css!./media/modelViewEditor';
|
||||
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
|
||||
import { ModelViewInput } from 'sql/workbench/browser/modelComponents/modelViewInput';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
export class ModelViewEditor extends BaseEditor {
|
||||
export class ModelViewEditor extends EditorPane {
|
||||
|
||||
public static ID: string = 'workbench.editor.modelViewEditor';
|
||||
|
||||
@@ -62,7 +62,7 @@ export class ModelViewEditor extends BaseEditor {
|
||||
}
|
||||
}
|
||||
|
||||
async setInput(input: ModelViewInput, options?: EditorOptions): Promise<void> {
|
||||
async setInput(input: ModelViewInput, options?: EditorOptions, context?: IEditorOpenContext): Promise<void> {
|
||||
if (this.input && this.input.matches(input)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ export class ModelViewEditor extends BaseEditor {
|
||||
input.container.style.visibility = 'visible';
|
||||
this._content.setAttribute('aria-flowto', input.container.id);
|
||||
|
||||
await super.setInput(input, options, CancellationToken.None);
|
||||
await super.setInput(input, options, context, CancellationToken.None);
|
||||
this.doUpdateContainer();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -85,8 +85,8 @@ export class QueryTextEditor extends BaseTextEditor {
|
||||
return options;
|
||||
}
|
||||
|
||||
setInput(input: UntitledTextEditorInput, options: EditorOptions): Promise<void> {
|
||||
return super.setInput(input, options, CancellationToken.None)
|
||||
setInput(input: UntitledTextEditorInput, options: EditorOptions, context: IEditorOpenContext): Promise<void> {
|
||||
return super.setInput(input, options, context, CancellationToken.None)
|
||||
.then(() => this.input.resolve()
|
||||
.then(editorModel => editorModel.load())
|
||||
.then(editorModel => this.getControl().setModel((<ResourceEditorModel>editorModel).textEditorModel)));
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -25,7 +25,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
||||
|
||||
export class DashboardEditor extends BaseEditor {
|
||||
export class DashboardEditor extends EditorPane {
|
||||
|
||||
public static ID: string = 'workbench.editor.connectiondashboard';
|
||||
private _dashboardContainer: HTMLElement;
|
||||
@@ -77,14 +77,14 @@ export class DashboardEditor extends BaseEditor {
|
||||
this._dashboardService.layout(dimension);
|
||||
}
|
||||
|
||||
public async setInput(input: DashboardInput, options: EditorOptions): Promise<void> {
|
||||
public async setInput(input: DashboardInput, options: EditorOptions, context: IEditorOpenContext): Promise<void> {
|
||||
if (this.input && this.input.matches(input)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const parentElement = this.getContainer();
|
||||
|
||||
super.setInput(input, options, CancellationToken.None);
|
||||
super.setInput(input, options, context, CancellationToken.None);
|
||||
|
||||
DOM.clearNode(parentElement);
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import * as strings from 'vs/base/common/strings';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
import { EditorOptions, EditorInput, IEditorControl, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions, EditorInput, IEditorControl, IEditorPane, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
@@ -41,7 +41,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
/**
|
||||
* Editor that hosts an action bar and a resultSetInput for an edit data session
|
||||
*/
|
||||
export class EditDataEditor extends BaseEditor {
|
||||
export class EditDataEditor extends EditorPane {
|
||||
|
||||
public static ID: string = 'workbench.editor.editDataEditor';
|
||||
|
||||
@@ -213,7 +213,7 @@ export class EditDataEditor extends BaseEditor {
|
||||
/**
|
||||
* Sets the input data for this editor.
|
||||
*/
|
||||
public setInput(newInput: EditDataInput, options?: EditorOptions): Promise<void> {
|
||||
public setInput(newInput: EditDataInput, options?: EditorOptions, context?: IEditorOpenContext): Promise<void> {
|
||||
let oldInput = <EditDataInput>this.input;
|
||||
if (!newInput.setup) {
|
||||
this._initialized = false;
|
||||
@@ -224,7 +224,7 @@ export class EditDataEditor extends BaseEditor {
|
||||
newInput.setupComplete();
|
||||
}
|
||||
|
||||
return super.setInput(newInput, options, CancellationToken.None)
|
||||
return super.setInput(newInput, options, context, CancellationToken.None)
|
||||
.then(() => this._updateInput(oldInput, newInput, options));
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ export class EditDataEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
// PRIVATE METHODS ////////////////////////////////////////////////////////////
|
||||
private _createEditor(editorInput: EditorInput, container: HTMLElement): Promise<BaseEditor> {
|
||||
private _createEditor(editorInput: EditorInput, container: HTMLElement): Promise<EditorPane> {
|
||||
const descriptor = this._editorDescriptorService.getEditor(editorInput);
|
||||
if (!descriptor) {
|
||||
return Promise.reject(new Error(strings.format('Can not find a registered editor for the input {0}', editorInput)));
|
||||
@@ -493,7 +493,7 @@ export class EditDataEditor extends BaseEditor {
|
||||
*/
|
||||
private _onResultsEditorCreated(resultsEditor: EditDataResultsEditor, resultsInput: EditDataResultsInput, options: EditorOptions): Promise<void> {
|
||||
this._resultsEditor = resultsEditor;
|
||||
return this._resultsEditor.setInput(resultsInput, options);
|
||||
return this._resultsEditor.setInput(resultsInput, options, undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -501,7 +501,7 @@ export class EditDataEditor extends BaseEditor {
|
||||
*/
|
||||
private _onSqlEditorCreated(sqlEditor: TextResourceEditor, sqlInput: UntitledTextEditorInput, options: EditorOptions): Thenable<void> {
|
||||
this._sqlEditor = sqlEditor;
|
||||
return this._sqlEditor.setInput(sqlInput, options, CancellationToken.None);
|
||||
return this._sqlEditor.setInput(sqlInput, options, undefined, CancellationToken.None);
|
||||
}
|
||||
|
||||
private _resizeGridContents(): void {
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { getZoomLevel } from 'vs/base/browser/browser';
|
||||
import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import * as types from 'vs/base/common/types';
|
||||
|
||||
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
|
||||
@@ -21,7 +21,7 @@ import { EditDataResultsInput } from 'sql/workbench/browser/editData/editDataRes
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
export class EditDataResultsEditor extends BaseEditor {
|
||||
export class EditDataResultsEditor extends EditorPane {
|
||||
|
||||
public static ID: string = 'workbench.editor.editDataResultsEditor';
|
||||
protected _input: EditDataResultsInput;
|
||||
@@ -63,8 +63,8 @@ export class EditDataResultsEditor extends BaseEditor {
|
||||
public layout(dimension: DOM.Dimension): void {
|
||||
}
|
||||
|
||||
public setInput(input: EditDataResultsInput, options: EditorOptions): Promise<void> {
|
||||
super.setInput(input, options, CancellationToken.None);
|
||||
public setInput(input: EditDataResultsInput, options: EditorOptions, context: IEditorOpenContext): Promise<void> {
|
||||
super.setInput(input, options, context, CancellationToken.None);
|
||||
this._applySettings();
|
||||
if (!input.hasBootstrapped) {
|
||||
this.createGridPanel();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { ExtensionRecommendations, ExtensionRecommendation, PromptedExtensionRecommendations } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -19,6 +19,7 @@ import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { InstallRecommendedExtensionsByScenarioAction, ShowRecommendedExtensionsByScenarioAction } from 'sql/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
|
||||
const choiceNever = localize('neverShowAgain', "Don't Show Again");
|
||||
|
||||
@@ -28,18 +29,20 @@ export class ScenarioRecommendations extends ExtensionRecommendations {
|
||||
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
|
||||
|
||||
constructor(
|
||||
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
|
||||
promptedExtensionRecommendations: PromptedExtensionRecommendations,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IExtensionManagementService protected readonly extensionManagementService: IExtensionManagementService,
|
||||
@IAdsTelemetryService private readonly adsTelemetryService: IAdsTelemetryService,
|
||||
@IExtensionsWorkbenchService protected readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
|
||||
) {
|
||||
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
|
||||
super(promptedExtensionRecommendations);
|
||||
|
||||
// this._recommendations = productService.recommendedExtensionsByScenario.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
|
||||
}
|
||||
@@ -123,12 +126,11 @@ export class ScenarioRecommendations extends ExtensionRecommendations {
|
||||
});
|
||||
}
|
||||
|
||||
getRecommendedExtensionsByScenario(scenarioType: string): Promise<IExtensionRecommendation[]> {
|
||||
async getRecommendedExtensionsByScenario(scenarioType: string): Promise<IExtensionRecommendation[]> {
|
||||
if (!scenarioType) {
|
||||
return Promise.reject(new Error(localize('scenarioTypeUndefined', 'The scenario type for extension recommendations must be provided.')));
|
||||
}
|
||||
return Promise.resolve((this.productService.recommendedExtensionsByScenario[scenarioType] || [])
|
||||
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
|
||||
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] })));
|
||||
return this.promptedExtensionRecommendations.filterIgnoredOrNotAllowed(this.productService.recommendedExtensionsByScenario[scenarioType] || [])
|
||||
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,10 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { ExtensionRecommendations, ExtensionRecommendation, PromptedExtensionRecommendations } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
|
||||
export class StaticRecommendations extends ExtensionRecommendations {
|
||||
|
||||
@@ -20,16 +14,10 @@ export class StaticRecommendations extends ExtensionRecommendations {
|
||||
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
|
||||
|
||||
constructor(
|
||||
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
|
||||
@IProductService productService: IProductService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
|
||||
promptedExtensionRecommendations: PromptedExtensionRecommendations,
|
||||
@IProductService productService: IProductService
|
||||
) {
|
||||
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
|
||||
super(promptedExtensionRecommendations);
|
||||
|
||||
this._recommendations = productService.recommendedExtensions.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
|
||||
cellModelSource = Array.isArray(this.cellModel.source) ? this.cellModel.source.join('') : this.cellModel.source;
|
||||
const model = this._instantiationService.createInstance(UntitledTextEditorModel, uri, false, cellModelSource, this.cellModel.language, undefined);
|
||||
this._editorInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
|
||||
await this._editor.setInput(this._editorInput, undefined);
|
||||
await this._editor.setInput(this._editorInput, undefined, undefined);
|
||||
this.setFocusAndScroll();
|
||||
|
||||
let untitledEditorModel = await this._editorInput.resolve() as UntitledTextEditorModel;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { bootstrapAngular } from 'sql/workbench/services/bootstrap/browser/bootstrapService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -35,7 +35,7 @@ import { TimeoutTimer } from 'vs/base/common/async';
|
||||
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
export class NotebookEditor extends BaseEditor implements IFindNotebookController {
|
||||
export class NotebookEditor extends EditorPane implements IFindNotebookController {
|
||||
|
||||
public static ID: string = 'workbench.editor.notebookEditor';
|
||||
private _notebookContainer: HTMLElement;
|
||||
@@ -187,14 +187,14 @@ export class NotebookEditor extends BaseEditor implements IFindNotebookControlle
|
||||
}
|
||||
}
|
||||
|
||||
public async setInput(input: NotebookInput, options: EditorOptions): Promise<void> {
|
||||
public async setInput(input: NotebookInput, options: EditorOptions, context: IEditorOpenContext): Promise<void> {
|
||||
if (this.input && this.input.matches(input)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const parentElement = this.getContainer();
|
||||
|
||||
await super.setInput(input, options, CancellationToken.None);
|
||||
await super.setInput(input, options, context, CancellationToken.None);
|
||||
DOM.clearNode(parentElement);
|
||||
await this.setFindInput(parentElement);
|
||||
if (!input.hasBootstrapped) {
|
||||
|
||||
@@ -126,7 +126,7 @@ suite.skip('Test class NotebookEditor:', () => {
|
||||
const testNotebookEditor = new NotebookEditorStub({ cellGuid: cellTextEditorGuid, editor: queryTextEditor, model: notebookModel, notebookParams: <INotebookParams>{ notebookUri: untitledNotebookInput.notebookUri } });
|
||||
notebookService.addNotebookEditor(testNotebookEditor);
|
||||
notebookEditor.clearInput();
|
||||
await notebookEditor.setInput(untitledNotebookInput, EditorOptions.create({ pinned: true }));
|
||||
await notebookEditor.setInput(untitledNotebookInput, EditorOptions.create({ pinned: true }), undefined);
|
||||
untitledNotebookInput.notebookFindModel.notebookModel = undefined; // clear preexisting notebookModel
|
||||
const result = await notebookEditor.getNotebookModel();
|
||||
assert.strictEqual(result, notebookModel, `getNotebookModel() should return the model set in the INotebookEditor object`);
|
||||
@@ -214,7 +214,7 @@ suite.skip('Test class NotebookEditor:', () => {
|
||||
untitledNotebookInput /* set to a known input */,
|
||||
untitledNotebookInput /* tries to set the same input that was previously set */
|
||||
]) {
|
||||
await notebookEditor.setInput(input, editorOptions);
|
||||
await notebookEditor.setInput(input, editorOptions, undefined);
|
||||
assert.strictEqual(notebookEditor.input, input, `notebookEditor.input should be the one that we set`);
|
||||
}
|
||||
});
|
||||
@@ -225,7 +225,7 @@ suite.skip('Test class NotebookEditor:', () => {
|
||||
for (const isRevealed of [true, false]) {
|
||||
notebookEditor['_findState']['_isRevealed'] = isRevealed;
|
||||
notebookEditor.clearInput();
|
||||
await notebookEditor.setInput(untitledNotebookInput, editorOptions);
|
||||
await notebookEditor.setInput(untitledNotebookInput, editorOptions, undefined);
|
||||
assert.strictEqual(notebookEditor.input, untitledNotebookInput, `notebookEditor.input should be the one that we set`);
|
||||
}
|
||||
});
|
||||
@@ -744,7 +744,7 @@ async function setupNotebookEditor(notebookEditor: NotebookEditor, untitledNoteb
|
||||
|
||||
async function setInputDocument(notebookEditor: NotebookEditor, untitledNotebookInput: UntitledNotebookInput): Promise<void> {
|
||||
const editorOptions = EditorOptions.create({ pinned: true });
|
||||
await notebookEditor.setInput(untitledNotebookInput, editorOptions);
|
||||
await notebookEditor.setInput(untitledNotebookInput, editorOptions, undefined);
|
||||
assert.strictEqual(notebookEditor.options, editorOptions, 'NotebookEditor options must be the ones that we set');
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IView, SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkbenchThemeService, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
@@ -117,7 +117,7 @@ export interface IDetailData {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export class ProfilerEditor extends BaseEditor {
|
||||
export class ProfilerEditor extends EditorPane {
|
||||
public static readonly ID: string = 'workbench.editor.profiler';
|
||||
|
||||
private _untitledTextEditorModel: UntitledTextEditorModel;
|
||||
@@ -440,7 +440,7 @@ export class ProfilerEditor extends BaseEditor {
|
||||
this._editor.setVisible(true);
|
||||
this._untitledTextEditorModel = this._instantiationService.createInstance(UntitledTextEditorModel, URI.from({ scheme: Schemas.untitled }), false, undefined, 'sql', undefined);
|
||||
this._editorInput = this._instantiationService.createInstance(UntitledTextEditorInput, this._untitledTextEditorModel);
|
||||
this._editor.setInput(this._editorInput, undefined);
|
||||
this._editor.setInput(this._editorInput, undefined, undefined);
|
||||
this._editorInput.resolve().then(model => this._editorModel = model.textEditorModel);
|
||||
return editorContainer;
|
||||
}
|
||||
@@ -460,7 +460,7 @@ export class ProfilerEditor extends BaseEditor {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return super.setInput(input, options, CancellationToken.None).then(() => {
|
||||
return super.setInput(input, options, undefined, CancellationToken.None).then(() => {
|
||||
this._profilerTableEditor.setInput(input);
|
||||
|
||||
if (input.viewTemplate) {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
@@ -75,8 +75,8 @@ export class ProfilerResourceEditor extends BaseTextEditor {
|
||||
return options;
|
||||
}
|
||||
|
||||
setInput(input: UntitledTextEditorInput, options: EditorOptions): Promise<void> {
|
||||
return super.setInput(input, options, CancellationToken.None)
|
||||
setInput(input: UntitledTextEditorInput, options: EditorOptions, context: IEditorOpenContext): Promise<void> {
|
||||
return super.setInput(input, options, context, CancellationToken.None)
|
||||
.then(() => this.input.resolve()
|
||||
.then(editorModel => editorModel.load())
|
||||
.then(editorModel => this.getControl().setModel((<ResourceEditorModel>editorModel).textEditorModel)));
|
||||
|
||||
@@ -20,7 +20,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IEditorAction } from 'vs/editor/common/editorCommon';
|
||||
import { IOverlayWidget } from 'vs/editor/browser/editorBrowser';
|
||||
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -39,7 +39,7 @@ export interface ProfilerTableViewState {
|
||||
scrollLeft: number;
|
||||
}
|
||||
|
||||
export class ProfilerTableEditor extends BaseEditor implements IProfilerController, ITableController {
|
||||
export class ProfilerTableEditor extends EditorPane implements IProfilerController, ITableController {
|
||||
|
||||
public static ID: string = 'workbench.editor.profiler.table';
|
||||
protected _input: ProfilerInput;
|
||||
|
||||
@@ -7,8 +7,8 @@ import 'vs/css!./media/queryEditor';
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { EditorOptions, IEditorControl, IEditorMemento } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor, EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions, IEditorControl, IEditorMemento, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { EditorPane, EditorMemento } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
@@ -50,7 +50,7 @@ interface IQueryEditorViewState {
|
||||
* Editor that hosts 2 sub-editors: A TextResourceEditor for SQL file editing, and a QueryResultsEditor
|
||||
* for viewing and editing query results. This editor is based off SideBySideEditor.
|
||||
*/
|
||||
export class QueryEditor extends BaseEditor {
|
||||
export class QueryEditor extends EditorPane {
|
||||
|
||||
public static ID: string = 'workbench.editor.queryEditor';
|
||||
|
||||
@@ -320,7 +320,7 @@ export class QueryEditor extends BaseEditor {
|
||||
this.taskbar.setContent(content);
|
||||
}
|
||||
|
||||
public async setInput(newInput: QueryEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
public async setInput(newInput: QueryEditorInput, options: EditorOptions, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
|
||||
const oldInput = this.input;
|
||||
|
||||
if (newInput.matches(oldInput)) {
|
||||
@@ -350,9 +350,9 @@ export class QueryEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
super.setInput(newInput, options, token),
|
||||
this.currentTextEditor.setInput(newInput.text, options, token),
|
||||
this.resultsEditor.setInput(newInput.results, options)
|
||||
super.setInput(newInput, options, context, token),
|
||||
this.currentTextEditor.setInput(newInput.text, options, context, token),
|
||||
this.resultsEditor.setInput(newInput.results, options, context)
|
||||
]);
|
||||
|
||||
this.inputDisposables.clear();
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { getZoomLevel } from 'vs/base/browser/browser';
|
||||
@@ -71,7 +71,7 @@ export function getBareResultsGridInfoStyles(info: BareResultsGridInfo): string
|
||||
/**
|
||||
* Editor associated with viewing and editing the data of a query results grid.
|
||||
*/
|
||||
export class QueryResultsEditor extends BaseEditor {
|
||||
export class QueryResultsEditor extends EditorPane {
|
||||
|
||||
public static ID: string = 'workbench.editor.queryResultsEditor';
|
||||
protected _rawOptions: BareResultsGridInfo;
|
||||
@@ -131,8 +131,8 @@ export class QueryResultsEditor extends BaseEditor {
|
||||
this.resultsView.layout(dimension);
|
||||
}
|
||||
|
||||
setInput(input: QueryResultsInput, options: EditorOptions): Promise<void> {
|
||||
super.setInput(input, options, CancellationToken.None);
|
||||
setInput(input: QueryResultsInput, options: EditorOptions, context: IEditorOpenContext): Promise<void> {
|
||||
super.setInput(input, options, context, CancellationToken.None);
|
||||
this.resultsView.input = input;
|
||||
return Promise.resolve<void>(null);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { EditorDescriptorService } from 'sql/workbench/services/queryEditor/brow
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as assert from 'assert';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||
@@ -76,7 +76,7 @@ suite('SQL QueryEditor Tests', () => {
|
||||
getId: function (): string { return 'id'; },
|
||||
getName: function (): string { return 'name'; },
|
||||
describes: function (obj: any): boolean { return true; },
|
||||
instantiate(instantiationService: IInstantiationService): BaseEditor { return undefined; }
|
||||
instantiate(instantiationService: IInstantiationService): EditorPane { return undefined; }
|
||||
};
|
||||
editorDescriptorService = TypeMoq.Mock.ofType(EditorDescriptorService, TypeMoq.MockBehavior.Loose);
|
||||
editorDescriptorService.setup(x => x.getEditor(TypeMoq.It.isAny())).returns(() => descriptor);
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { QueryPlanInput } from 'sql/workbench/contrib/queryPlan/common/queryPlanInput';
|
||||
@@ -13,7 +13,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { QueryPlanView } from 'sql/workbench/contrib/queryPlan/browser/queryPlan';
|
||||
|
||||
export class QueryPlanEditor extends BaseEditor {
|
||||
export class QueryPlanEditor extends EditorPane {
|
||||
|
||||
public static ID: string = 'workbench.editor.queryplan';
|
||||
|
||||
@@ -60,13 +60,13 @@ export class QueryPlanEditor extends BaseEditor {
|
||||
this.view.layout(dimension);
|
||||
}
|
||||
|
||||
public async setInput(input: QueryPlanInput, options: EditorOptions): Promise<void> {
|
||||
public async setInput(input: QueryPlanInput, options: EditorOptions, context: IEditorOpenContext): Promise<void> {
|
||||
if (this.input instanceof QueryPlanInput && this.input.matches(input)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
await input.resolve();
|
||||
|
||||
await super.setInput(input, options, CancellationToken.None);
|
||||
await super.setInput(input, options, context, CancellationToken.None);
|
||||
|
||||
this.view.showPlan(input.planXml!);
|
||||
}
|
||||
|
||||
@@ -8,16 +8,16 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IResourceViewerStateChangedEvent } from 'sql/workbench/common/editor/resourceViewer/resourceViewerState';
|
||||
import { ResourceViewerInput } from 'sql/workbench/browser/editor/resourceViewer/resourceViewerInput';
|
||||
import { ResourceViewerTable } from 'sql/workbench/contrib/resourceViewer/browser/resourceViewerTable';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
|
||||
export class ResourceViewerEditor extends BaseEditor {
|
||||
export class ResourceViewerEditor extends EditorPane {
|
||||
public static readonly ID: string = 'workbench.editor.resource-viewer';
|
||||
|
||||
private _container!: HTMLElement;
|
||||
@@ -72,8 +72,8 @@ export class ResourceViewerEditor extends BaseEditor {
|
||||
return this._input as ResourceViewerInput;
|
||||
}
|
||||
|
||||
public async setInput(input: ResourceViewerInput, options?: EditorOptions): Promise<void> {
|
||||
await super.setInput(input, options, CancellationToken.None);
|
||||
async setInput(input: ResourceViewerInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
|
||||
await super.setInput(input, options, context, token);
|
||||
|
||||
this._inputDisposables.clear();
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
},
|
||||
"lib": [
|
||||
"ES2015",
|
||||
"ES2016.Array.Include",
|
||||
"ES2017.String",
|
||||
"ES2018.Promise",
|
||||
"DOM",
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
"include": [
|
||||
"typings/require.d.ts",
|
||||
"typings/thenable.d.ts",
|
||||
"typings/lib.array-ext.d.ts",
|
||||
"vs/css.d.ts",
|
||||
"vs/monaco.d.ts",
|
||||
"vs/nls.d.ts",
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
"./vs/workbench/api/node/**/*.ts", // 328 errors
|
||||
"./vs/workbench/api/worker/**/*.ts", // 294 errors
|
||||
"./vs/workbench/contrib/backup/**/*.ts", // 3162 errors
|
||||
"./vs/workbench/contrib/bulkEdit/**/*.ts",
|
||||
"./vs/workbench/contrib/codeEditor/**/*.ts", // 3162 errors
|
||||
"./vs/workbench/contrib/comments/**/*.ts", // 64 errors
|
||||
"./vs/workbench/contrib/configExporter/**/*.ts", // 3162 errors
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { renderCodiconsRegex } from 'vs/base/common/codicons';
|
||||
|
||||
export function renderCodiconsAsElement(text: string): Array<HTMLSpanElement | string> {
|
||||
const elements = new Array<HTMLSpanElement | string>();
|
||||
let match: RegExpMatchArray | null;
|
||||
|
||||
let textStart = 0, textStop = 0;
|
||||
while ((match = renderCodiconsRegex.exec(text)) !== null) {
|
||||
textStop = match.index || 0;
|
||||
elements.push(text.substring(textStart, textStop));
|
||||
textStart = (match.index || 0) + match[0].length;
|
||||
|
||||
const [, escaped, codicon, name, animation] = match;
|
||||
elements.push(escaped ? `$(${codicon})` : dom.$(`span.codicon.codicon-${name}${animation ? `.codicon-animation-${animation}` : ''}`));
|
||||
}
|
||||
|
||||
if (textStart < text.length) {
|
||||
elements.push(text.substring(textStart));
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
@@ -997,6 +997,11 @@ export function trackFocus(element: HTMLElement | Window): IFocusTracker {
|
||||
return new FocusTracker(element);
|
||||
}
|
||||
|
||||
export function after<T extends Node>(sibling: HTMLElement, child: T): T {
|
||||
sibling.after(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
export function append<T extends Node>(parent: HTMLElement, ...children: T[]): T {
|
||||
children.forEach(child => parent.appendChild(child));
|
||||
return children[children.length - 1];
|
||||
@@ -1009,6 +1014,18 @@ export function prepend<T extends Node>(parent: HTMLElement, child: T): T {
|
||||
|
||||
const SELECTOR_REGEX = /([\w\-]+)?(#([\w\-]+))?((\.([\w\-]+))*)/;
|
||||
|
||||
export function reset<T extends Node>(parent: HTMLElement, ...children: Array<Node | string>) {
|
||||
parent.innerText = '';
|
||||
coalesce(children)
|
||||
.forEach(child => {
|
||||
if (child instanceof Node) {
|
||||
parent.appendChild(child);
|
||||
} else {
|
||||
parent.appendChild(document.createTextNode(child as string));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export enum Namespace {
|
||||
HTML = 'http://www.w3.org/1999/xhtml',
|
||||
SVG = 'http://www.w3.org/2000/svg'
|
||||
|
||||
@@ -205,6 +205,40 @@ const altKeyMod = KeyMod.Alt;
|
||||
const shiftKeyMod = KeyMod.Shift;
|
||||
const metaKeyMod = (platform.isMacintosh ? KeyMod.CtrlCmd : KeyMod.WinCtrl);
|
||||
|
||||
export function printKeyboardEvent(e: KeyboardEvent): string {
|
||||
let modifiers: string[] = [];
|
||||
if (e.ctrlKey) {
|
||||
modifiers.push(`ctrl`);
|
||||
}
|
||||
if (e.shiftKey) {
|
||||
modifiers.push(`shift`);
|
||||
}
|
||||
if (e.altKey) {
|
||||
modifiers.push(`alt`);
|
||||
}
|
||||
if (e.metaKey) {
|
||||
modifiers.push(`meta`);
|
||||
}
|
||||
return `modifiers: [${modifiers.join(',')}], code: ${e.code}, keyCode: ${e.keyCode}, key: ${e.key}`;
|
||||
}
|
||||
|
||||
export function printStandardKeyboardEvent(e: StandardKeyboardEvent): string {
|
||||
let modifiers: string[] = [];
|
||||
if (e.ctrlKey) {
|
||||
modifiers.push(`ctrl`);
|
||||
}
|
||||
if (e.shiftKey) {
|
||||
modifiers.push(`shift`);
|
||||
}
|
||||
if (e.altKey) {
|
||||
modifiers.push(`alt`);
|
||||
}
|
||||
if (e.metaKey) {
|
||||
modifiers.push(`meta`);
|
||||
}
|
||||
return `modifiers: [${modifiers.join(',')}], code: ${e.code}, keyCode: ${e.keyCode} ('${KeyCodeUtils.toString(e.keyCode)}')`;
|
||||
}
|
||||
|
||||
export class StandardKeyboardEvent implements IKeyboardEvent {
|
||||
|
||||
readonly _standardKeyboardEventBrand = true;
|
||||
|
||||
@@ -12,8 +12,7 @@ import { mixin } from 'vs/base/common/objects';
|
||||
import { Event as BaseEvent, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Gesture, EventType } from 'vs/base/browser/touch';
|
||||
import { renderCodicons } from 'vs/base/common/codicons';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { renderCodiconsAsElement } from 'vs/base/browser/codicons';
|
||||
|
||||
export interface IButtonOptions extends IButtonStyles {
|
||||
readonly title?: boolean | string;
|
||||
@@ -181,7 +180,7 @@ export class Button extends Disposable {
|
||||
DOM.addClass(this._element, 'monaco-text-button');
|
||||
}
|
||||
if (this.options.supportCodicons) {
|
||||
this._element.innerHTML = renderCodicons(escape(value));
|
||||
DOM.reset(this._element, ...renderCodiconsAsElement(value));
|
||||
} else {
|
||||
this._element.textContent = value;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { renderCodicons } from 'vs/base/common/codicons';
|
||||
import { reset } from 'vs/base/browser/dom';
|
||||
import { renderCodiconsAsElement } from 'vs/base/browser/codicons';
|
||||
|
||||
export class CodiconLabel {
|
||||
|
||||
@@ -13,7 +13,7 @@ export class CodiconLabel {
|
||||
) { }
|
||||
|
||||
set text(text: string) {
|
||||
this._container.innerHTML = renderCodicons(escape(text ?? ''));
|
||||
reset(this._container, ...renderCodiconsAsElement(text ?? ''));
|
||||
}
|
||||
|
||||
set title(title: string) {
|
||||
|
||||
@@ -121,7 +121,7 @@ export class ExternalElementsDragAndDropData<T> implements IDragAndDropData {
|
||||
}
|
||||
}
|
||||
|
||||
export class DesktopDragAndDropData implements IDragAndDropData {
|
||||
export class NativeDragAndDropData implements IDragAndDropData {
|
||||
|
||||
readonly types: any[];
|
||||
readonly files: any[];
|
||||
@@ -976,7 +976,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.currentDragData = new DesktopDragAndDropData();
|
||||
this.currentDragData = new NativeDragAndDropData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface IPaneOptions {
|
||||
expanded?: boolean;
|
||||
orientation?: Orientation;
|
||||
title: string;
|
||||
titleDescription?: string;
|
||||
}
|
||||
|
||||
export interface IPaneStyles {
|
||||
|
||||
@@ -590,17 +590,6 @@ export function asArray<T>(x: T | T[]): T[] {
|
||||
return Array.isArray(x) ? x : [x];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `Array.from` or `[...iter]`
|
||||
*/
|
||||
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)];
|
||||
}
|
||||
|
||||
@@ -170,6 +170,25 @@ export class Sequencer {
|
||||
}
|
||||
}
|
||||
|
||||
export class SequencerByKey<TKey> {
|
||||
|
||||
private promiseMap = new Map<TKey, Promise<any>>();
|
||||
|
||||
queue<T>(key: TKey, promiseTask: ITask<Promise<T>>): Promise<T> {
|
||||
const runningPromise = this.promiseMap.get(key) ?? Promise.resolve();
|
||||
const newPromise = runningPromise
|
||||
.catch(() => { })
|
||||
.then(promiseTask)
|
||||
.finally(() => {
|
||||
if (this.promiseMap.get(key) === newPromise) {
|
||||
this.promiseMap.delete(key);
|
||||
}
|
||||
});
|
||||
this.promiseMap.set(key, newPromise);
|
||||
return newPromise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to delay execution of a task that is being requested often.
|
||||
*
|
||||
|
||||
@@ -499,7 +499,11 @@ export function markdownUnescapeCodicons(text: string): string {
|
||||
return text.replace(markdownUnescapeCodiconsRegex, (match, escaped, codicon) => escaped ? match : `$(${codicon})`);
|
||||
}
|
||||
|
||||
const renderCodiconsRegex = /(\\)?\$\((([a-z0-9\-]+?)(?:~([a-z0-9\-]*?))?)\)/gi;
|
||||
export const renderCodiconsRegex = /(\\)?\$\((([a-z0-9\-]+?)(?:~([a-z0-9\-]*?))?)\)/gi;
|
||||
|
||||
/**
|
||||
* @deprecated Use `renderCodiconsAsElement` instead
|
||||
*/
|
||||
export function renderCodicons(text: string): string {
|
||||
return text.replace(renderCodiconsRegex, (_, escaped, codicon, name, animation) => {
|
||||
// If the class for codicons is changed, it should also be updated in src\vs\base\browser\markdownRenderer.ts
|
||||
|
||||
@@ -142,7 +142,7 @@ export function isUNC(path: string): boolean {
|
||||
// Reference: https://en.wikipedia.org/wiki/Filename
|
||||
const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g;
|
||||
const UNIX_INVALID_FILE_CHARS = /[\\/]/g;
|
||||
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i;
|
||||
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])(\.(.*?))?$/i;
|
||||
export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean = isWindows): boolean {
|
||||
const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { compareAnything } from 'vs/base/common/comparers';
|
||||
import { matchesPrefix, IMatch, isUpper, fuzzyScore, createMatches as createFuzzyMatches, matchesStrictPrefix } from 'vs/base/common/filters';
|
||||
import { matchesPrefix, IMatch, isUpper, fuzzyScore, createMatches as createFuzzyMatches } from 'vs/base/common/filters';
|
||||
import { sep } from 'vs/base/common/path';
|
||||
import { isWindows, isLinux } from 'vs/base/common/platform';
|
||||
import { stripWildcards, equalsIgnoreCase } from 'vs/base/common/strings';
|
||||
@@ -369,9 +369,8 @@ export interface IItemAccessor<T> {
|
||||
}
|
||||
|
||||
const PATH_IDENTITY_SCORE = 1 << 18;
|
||||
const LABEL_PREFIX_SCORE_MATCHCASE = 1 << 17;
|
||||
const LABEL_PREFIX_SCORE_IGNORECASE = 1 << 16;
|
||||
const LABEL_SCORE_THRESHOLD = 1 << 15;
|
||||
const LABEL_PREFIX_SCORE_THRESHOLD = 1 << 17;
|
||||
const LABEL_SCORE_THRESHOLD = 1 << 16;
|
||||
|
||||
export function scoreItemFuzzy<T>(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: FuzzyScorerCache): IItemScore {
|
||||
if (!item || !query.normalized) {
|
||||
@@ -460,20 +459,33 @@ function doScoreItemFuzzyMultiple(label: string, description: string | undefined
|
||||
|
||||
function doScoreItemFuzzySingle(label: string, description: string | undefined, path: string | undefined, query: IPreparedQueryPiece, preferLabelMatches: boolean, fuzzy: boolean): IItemScore {
|
||||
|
||||
// Prefer label matches if told so
|
||||
if (preferLabelMatches) {
|
||||
|
||||
// Treat prefix matches on the label highest
|
||||
const prefixLabelMatchIgnoreCase = matchesPrefix(query.normalized, label);
|
||||
if (prefixLabelMatchIgnoreCase) {
|
||||
const prefixLabelMatchStrictCase = matchesStrictPrefix(query.normalized, label);
|
||||
return { score: prefixLabelMatchStrictCase ? LABEL_PREFIX_SCORE_MATCHCASE : LABEL_PREFIX_SCORE_IGNORECASE, labelMatch: prefixLabelMatchStrictCase || prefixLabelMatchIgnoreCase };
|
||||
}
|
||||
|
||||
// Second, score fuzzy
|
||||
// Prefer label matches if told so or we have no description
|
||||
if (preferLabelMatches || !description) {
|
||||
const [labelScore, labelPositions] = scoreFuzzy(label, query.normalized, query.normalizedLowercase, fuzzy);
|
||||
if (labelScore) {
|
||||
return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) };
|
||||
|
||||
// If we have a prefix match on the label, we give a much
|
||||
// higher baseScore to elevate these matches over others
|
||||
// This ensures that typing a file name wins over results
|
||||
// that are present somewhere in the label, but not the
|
||||
// beginning.
|
||||
const labelPrefixMatch = matchesPrefix(query.normalized, label);
|
||||
let baseScore: number;
|
||||
if (labelPrefixMatch) {
|
||||
baseScore = LABEL_PREFIX_SCORE_THRESHOLD;
|
||||
|
||||
// We give another boost to labels that are short, e.g. given
|
||||
// files "window.ts" and "windowActions.ts" and a query of
|
||||
// "window", we want "window.ts" to receive a higher score.
|
||||
// As such we compute the percentage the query has within the
|
||||
// label and add that to the baseScore.
|
||||
const prefixLengthBoost = Math.round((query.normalized.length / label.length) * 100);
|
||||
baseScore += prefixLengthBoost;
|
||||
} else {
|
||||
baseScore = LABEL_SCORE_THRESHOLD;
|
||||
}
|
||||
|
||||
return { score: baseScore + labelScore, labelMatch: labelPrefixMatch || createMatches(labelPositions) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,46 +612,19 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
|
||||
}
|
||||
}
|
||||
|
||||
// 2.) prefer label prefix matches (match case)
|
||||
if (scoreA === LABEL_PREFIX_SCORE_MATCHCASE || scoreB === LABEL_PREFIX_SCORE_MATCHCASE) {
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA === LABEL_PREFIX_SCORE_MATCHCASE ? -1 : 1;
|
||||
}
|
||||
|
||||
const labelA = accessor.getItemLabel(itemA) || '';
|
||||
const labelB = accessor.getItemLabel(itemB) || '';
|
||||
|
||||
// prefer shorter names when both match on label prefix
|
||||
if (labelA.length !== labelB.length) {
|
||||
return labelA.length - labelB.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 3.) prefer label prefix matches (ignore case)
|
||||
if (scoreA === LABEL_PREFIX_SCORE_IGNORECASE || scoreB === LABEL_PREFIX_SCORE_IGNORECASE) {
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA === LABEL_PREFIX_SCORE_IGNORECASE ? -1 : 1;
|
||||
}
|
||||
|
||||
const labelA = accessor.getItemLabel(itemA) || '';
|
||||
const labelB = accessor.getItemLabel(itemB) || '';
|
||||
|
||||
// prefer shorter names when both match on label prefix
|
||||
if (labelA.length !== labelB.length) {
|
||||
return labelA.length - labelB.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 4.) matches on label are considered higher compared to label+description matches
|
||||
// 2.) matches on label are considered higher compared to label+description matches
|
||||
if (scoreA > LABEL_SCORE_THRESHOLD || scoreB > LABEL_SCORE_THRESHOLD) {
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA > scoreB ? -1 : 1;
|
||||
}
|
||||
|
||||
// prefer more compact matches over longer in label
|
||||
const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);
|
||||
if (comparedByMatchLength !== 0) {
|
||||
return comparedByMatchLength;
|
||||
// prefer more compact matches over longer in label (unless this is a prefix match where
|
||||
// longer prefix matches are actually preferred)
|
||||
if (scoreA < LABEL_PREFIX_SCORE_THRESHOLD && scoreB < LABEL_PREFIX_SCORE_THRESHOLD) {
|
||||
const comparedByMatchLength = compareByMatchLength(itemScoreA.labelMatch, itemScoreB.labelMatch);
|
||||
if (comparedByMatchLength !== 0) {
|
||||
return comparedByMatchLength;
|
||||
}
|
||||
}
|
||||
|
||||
// prefer shorter labels over longer labels
|
||||
@@ -650,12 +635,12 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
|
||||
}
|
||||
}
|
||||
|
||||
// 5.) compare by score in label+description
|
||||
// 3.) compare by score in label+description
|
||||
if (scoreA !== scoreB) {
|
||||
return scoreA > scoreB ? -1 : 1;
|
||||
}
|
||||
|
||||
// 6.) scores are identical: prefer matches in label over non-label matches
|
||||
// 4.) scores are identical: prefer matches in label over non-label matches
|
||||
const itemAHasLabelMatches = Array.isArray(itemScoreA.labelMatch) && itemScoreA.labelMatch.length > 0;
|
||||
const itemBHasLabelMatches = Array.isArray(itemScoreB.labelMatch) && itemScoreB.labelMatch.length > 0;
|
||||
if (itemAHasLabelMatches && !itemBHasLabelMatches) {
|
||||
@@ -664,14 +649,14 @@ export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPrepared
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 7.) scores are identical: prefer more compact matches (label and description)
|
||||
// 5.) scores are identical: prefer more compact matches (label and description)
|
||||
const itemAMatchDistance = computeLabelAndDescriptionMatchDistance(itemA, itemScoreA, accessor);
|
||||
const itemBMatchDistance = computeLabelAndDescriptionMatchDistance(itemB, itemScoreB, accessor);
|
||||
if (itemAMatchDistance && itemBMatchDistance && itemAMatchDistance !== itemBMatchDistance) {
|
||||
return itemBMatchDistance > itemAMatchDistance ? -1 : 1;
|
||||
}
|
||||
|
||||
// 8.) scores are identical: start to use the fallback compare
|
||||
// 6.) scores are identical: start to use the fallback compare
|
||||
return fallbackCompare(itemA, itemB, query, accessor);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ export class MarkdownString implements IMarkdownString {
|
||||
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
|
||||
this._value += (this._supportThemeIcons ? escapeCodicons(value) : value)
|
||||
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
|
||||
.replace('\n', '\n\n');
|
||||
.replace(/\n/g, '\n\n');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { regExpFlags } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
|
||||
export function stringify(obj: any): string {
|
||||
return JSON.stringify(obj, replacer);
|
||||
@@ -33,7 +33,15 @@ function replacer(key: string, value: any): any {
|
||||
return value;
|
||||
}
|
||||
|
||||
export function revive(obj: any, depth = 0): any {
|
||||
|
||||
type Deserialize<T> = T extends UriComponents ? URI
|
||||
: T extends object
|
||||
? Revived<T>
|
||||
: T;
|
||||
|
||||
export type Revived<T> = { [K in keyof T]: Deserialize<T[K]> };
|
||||
|
||||
export function revive<T = any>(obj: any, depth = 0): Revived<T> {
|
||||
if (!obj || depth > 200) {
|
||||
return obj;
|
||||
}
|
||||
@@ -41,15 +49,15 @@ export function revive(obj: any, depth = 0): any {
|
||||
if (typeof obj === 'object') {
|
||||
|
||||
switch ((<MarshalledObject>obj).$mid) {
|
||||
case 1: return URI.revive(obj);
|
||||
case 2: return new RegExp(obj.source, obj.flags);
|
||||
case 1: return <any>URI.revive(obj);
|
||||
case 2: return <any>new RegExp(obj.source, obj.flags);
|
||||
}
|
||||
|
||||
if (
|
||||
obj instanceof VSBuffer
|
||||
|| obj instanceof Uint8Array
|
||||
) {
|
||||
return obj;
|
||||
return <any>obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
|
||||
@@ -33,7 +33,7 @@ export interface ReadableStreamEvents<T> {
|
||||
|
||||
/**
|
||||
* A interface that emulates the API shape of a node.js readable
|
||||
* stream for use in desktop and web environments.
|
||||
* stream for use in native and web environments.
|
||||
*/
|
||||
export interface ReadableStream<T> extends ReadableStreamEvents<T> {
|
||||
|
||||
@@ -60,7 +60,7 @@ export interface ReadableStream<T> extends ReadableStreamEvents<T> {
|
||||
|
||||
/**
|
||||
* A interface that emulates the API shape of a node.js readable
|
||||
* for use in desktop and web environments.
|
||||
* for use in native and web environments.
|
||||
*/
|
||||
export interface Readable<T> {
|
||||
|
||||
@@ -73,7 +73,7 @@ export interface Readable<T> {
|
||||
|
||||
/**
|
||||
* A interface that emulates the API shape of a node.js writeable
|
||||
* stream for use in desktop and web environments.
|
||||
* stream for use in native and web environments.
|
||||
*/
|
||||
export interface WriteableStream<T> extends ReadableStream<T> {
|
||||
|
||||
|
||||
@@ -258,14 +258,12 @@ export type UriDto<T> = { [K in keyof T]: T[K] extends URI
|
||||
/**
|
||||
* Mapped-type that replaces all occurrences of URI with UriComponents and
|
||||
* drops all functions.
|
||||
* todo@joh use toJSON-results
|
||||
*/
|
||||
export type Dto<T> = { [K in keyof T]: T[K] extends URI
|
||||
? UriComponents
|
||||
: T[K] extends Function
|
||||
? never
|
||||
: UriDto<T[K]> };
|
||||
|
||||
export type Dto<T> = T extends { toJSON(): infer U }
|
||||
? U
|
||||
: T extends object
|
||||
? { [k in keyof T]: Dto<T[k]>; }
|
||||
: T;
|
||||
|
||||
export function NotImplementedProxy<T>(name: string): { new(): T } {
|
||||
return <any>class {
|
||||
|
||||
@@ -93,6 +93,14 @@
|
||||
process: {
|
||||
platform: process.platform,
|
||||
env: process.env,
|
||||
_whenEnvResolved: undefined,
|
||||
get whenEnvResolved() {
|
||||
if (!this._whenEnvResolved) {
|
||||
this._whenEnvResolved = resolveEnv();
|
||||
}
|
||||
|
||||
return this._whenEnvResolved;
|
||||
},
|
||||
on:
|
||||
/**
|
||||
* @param {string} type
|
||||
@@ -157,5 +165,33 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If VSCode is not run from a terminal, we should resolve additional
|
||||
* shell specific environment from the OS shell to ensure we are seeing
|
||||
* all development related environment variables. We do this from the
|
||||
* main process because it may involve spawning a shell.
|
||||
*/
|
||||
function resolveEnv() {
|
||||
return new Promise(function (resolve) {
|
||||
const handle = setTimeout(function () {
|
||||
console.warn('Preload: Unable to resolve shell environment in a reasonable time');
|
||||
|
||||
// It took too long to fetch the shell environment, return
|
||||
resolve();
|
||||
}, 3000);
|
||||
|
||||
ipcRenderer.once('vscode:acceptShellEnv', function (event, shellEnv) {
|
||||
clearTimeout(handle);
|
||||
|
||||
// Assign all keys of the shell environment to our process environment
|
||||
Object.assign(process.env, shellEnv);
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
ipcRenderer.send('vscode:fetchShellEnv');
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}());
|
||||
|
||||
@@ -84,6 +84,12 @@ export const process = (window as any).vscode.process as {
|
||||
*/
|
||||
env: { [key: string]: string | undefined };
|
||||
|
||||
/**
|
||||
* Allows to await resolving the full process environment by checking for the shell environment
|
||||
* of the OS in certain cases (e.g. when the app is started from the Dock on macOS).
|
||||
*/
|
||||
whenEnvResolved: Promise<void>;
|
||||
|
||||
/**
|
||||
* A listener on the process. Only a small subset of listener types are allowed.
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Database, Statement } from 'vscode-sqlite3';
|
||||
import type { Database, Statement } from 'vscode-sqlite3';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { mapToString, setToString } from 'vs/base/common/map';
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { renderCodiconsAsElement } from 'vs/base/browser/codicons';
|
||||
import * as assert from 'assert';
|
||||
|
||||
suite('renderCodicons', () => {
|
||||
|
||||
test('no codicons', () => {
|
||||
const result = renderCodiconsAsElement(' hello World .');
|
||||
|
||||
assert.equal(elementsToString(result), ' hello World .');
|
||||
});
|
||||
|
||||
test('codicon only', () => {
|
||||
const result = renderCodiconsAsElement('$(alert)');
|
||||
|
||||
assert.equal(elementsToString(result), '<span class="codicon codicon-alert"></span>');
|
||||
});
|
||||
|
||||
test('codicon and non-codicon strings', () => {
|
||||
const result = renderCodiconsAsElement(` $(alert) Unresponsive`);
|
||||
|
||||
assert.equal(elementsToString(result), ' <span class="codicon codicon-alert"></span> Unresponsive');
|
||||
});
|
||||
|
||||
test('multiple codicons', () => {
|
||||
const result = renderCodiconsAsElement('$(check)$(error)');
|
||||
|
||||
assert.equal(elementsToString(result), '<span class="codicon codicon-check"></span><span class="codicon codicon-error"></span>');
|
||||
});
|
||||
|
||||
test('escaped codicon', () => {
|
||||
const result = renderCodiconsAsElement('\\$(escaped)');
|
||||
|
||||
assert.equal(elementsToString(result), '$(escaped)');
|
||||
});
|
||||
|
||||
test('codicon with animation', () => {
|
||||
const result = renderCodiconsAsElement('$(zip~anim)');
|
||||
|
||||
assert.equal(elementsToString(result), '<span class="codicon codicon-zip codicon-animation-anim"></span>');
|
||||
});
|
||||
|
||||
const elementsToString = (elements: Array<HTMLElement | string>): string => {
|
||||
return elements
|
||||
.map(elem => elem instanceof HTMLElement ? elem.outerHTML : elem)
|
||||
.reduce((a, b) => a + b, '');
|
||||
};
|
||||
});
|
||||
@@ -688,4 +688,22 @@ suite('Async', () => {
|
||||
assert.ok(Date.now() - now < 100);
|
||||
assert.equal(timedout, false);
|
||||
});
|
||||
|
||||
test('SequencerByKey', async () => {
|
||||
const s = new async.SequencerByKey<string>();
|
||||
|
||||
const r1 = await s.queue('key1', () => Promise.resolve('hello'));
|
||||
assert.equal(r1, 'hello');
|
||||
|
||||
await s.queue('key2', () => Promise.reject(new Error('failed'))).then(() => {
|
||||
throw new Error('should not be resolved');
|
||||
}, err => {
|
||||
// Expected error
|
||||
assert.equal(err.message, 'failed');
|
||||
});
|
||||
|
||||
// Still works after a queued promise is rejected
|
||||
const r3 = await s.queue('key2', () => Promise.resolve('hello'));
|
||||
assert.equal(r3, 'hello');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,6 +57,13 @@ suite('Paths', () => {
|
||||
assert.ok(!extpath.isValidBasename('aux'));
|
||||
assert.ok(!extpath.isValidBasename('Aux'));
|
||||
assert.ok(!extpath.isValidBasename('LPT0'));
|
||||
assert.ok(!extpath.isValidBasename('aux.txt'));
|
||||
assert.ok(!extpath.isValidBasename('com0.abc'));
|
||||
assert.ok(extpath.isValidBasename('LPT00'));
|
||||
assert.ok(extpath.isValidBasename('aux1'));
|
||||
assert.ok(extpath.isValidBasename('aux1.txt'));
|
||||
assert.ok(extpath.isValidBasename('aux1.aux.txt'));
|
||||
|
||||
assert.ok(!extpath.isValidBasename('test.txt.'));
|
||||
assert.ok(!extpath.isValidBasename('test.txt..'));
|
||||
assert.ok(!extpath.isValidBasename('test.txt '));
|
||||
|
||||
@@ -1025,6 +1025,51 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(res[1], resourceB);
|
||||
});
|
||||
|
||||
test('compareFilesByScore - boost better prefix match if multiple queries are used', function () {
|
||||
const resourceA = URI.file('src/vs/workbench/services/host/browser/browserHostService.ts');
|
||||
const resourceB = URI.file('src/vs/workbench/browser/workbench.ts');
|
||||
|
||||
for (const query of ['workbench.ts browser', 'browser workbench.ts', 'browser workbench', 'workbench browser']) {
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
}
|
||||
});
|
||||
|
||||
test('compareFilesByScore - boost shorter prefix match if multiple queries are used', function () {
|
||||
const resourceA = URI.file('src/vs/workbench/browser/actions/windowActions.ts');
|
||||
const resourceB = URI.file('src/vs/workbench/electron-browser/window.ts');
|
||||
|
||||
for (const query of ['window browser', 'window.ts browser']) {
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
}
|
||||
});
|
||||
|
||||
test('compareFilesByScore - boost shorter prefix match if multiple queries are used (#99171)', function () {
|
||||
const resourceA = URI.file('mesh_editor_lifetime_job.h');
|
||||
const resourceB = URI.file('lifetime_job.h');
|
||||
|
||||
for (const query of ['m life, life m']) {
|
||||
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
|
||||
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
|
||||
assert.equal(res[0], resourceB);
|
||||
assert.equal(res[1], resourceA);
|
||||
}
|
||||
});
|
||||
|
||||
test('prepareQuery', () => {
|
||||
assert.equal(scorer.prepareQuery(' f*a ').normalized, 'fa');
|
||||
assert.equal(scorer.prepareQuery('model Tester.ts').original, 'model Tester.ts');
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
<!-- Builtin Extensions (running out of sources) -->
|
||||
<meta id="vscode-workbench-builtin-extensions" data-settings="{{WORKBENCH_BUILTIN_EXTENSIONS}}">
|
||||
|
||||
<!-- Workbench Credentials (running out of sources) -->
|
||||
<meta id="vscode-workbench-credentials" data-settings="{{WORKBENCH_CREDENTIALS}}">
|
||||
|
||||
<!-- Workarounds/Hacks (remote user data uri) -->
|
||||
<meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}">
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkbenchConstructionOptions, create, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IWindowIndicator, ICommand, IHomeIndicator, IProductQualityChangeHandler } from 'vs/workbench/workbench.web.api';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IWorkbenchConstructionOptions, create, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IWindowIndicator, IHomeIndicator, IProductQualityChangeHandler } from 'vs/workbench/workbench.web.api';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
@@ -16,6 +15,7 @@ import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/wi
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { isStandalone } from 'vs/base/browser/browser';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
interface ICredential {
|
||||
service: string;
|
||||
@@ -27,6 +27,13 @@ class LocalStorageCredentialsProvider implements ICredentialsProvider {
|
||||
|
||||
static readonly CREDENTIALS_OPENED_KEY = 'credentials.provider';
|
||||
|
||||
constructor(credentials: ICredential[]) {
|
||||
this._credentials = credentials;
|
||||
for (const { service, account, password } of this._credentials) {
|
||||
this.setPassword(service, account, password);
|
||||
}
|
||||
}
|
||||
|
||||
private _credentials: ICredential[] | undefined;
|
||||
private get credentials(): ICredential[] {
|
||||
if (!this._credentials) {
|
||||
@@ -277,6 +284,20 @@ class WorkspaceProvider implements IWorkspaceProvider {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
hasRemote(): boolean {
|
||||
if (this.workspace) {
|
||||
if (isFolderToOpen(this.workspace)) {
|
||||
return this.workspace.folderUri.scheme === Schemas.vscodeRemote;
|
||||
}
|
||||
|
||||
if (isWorkspaceToOpen(this.workspace)) {
|
||||
return this.workspace.workspaceUri.scheme === Schemas.vscodeRemote;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class WindowIndicator implements IWindowIndicator {
|
||||
@@ -287,8 +308,6 @@ class WindowIndicator implements IWindowIndicator {
|
||||
readonly tooltip: string;
|
||||
readonly command: string | undefined;
|
||||
|
||||
readonly commandImpl: ICommand | undefined = undefined;
|
||||
|
||||
constructor(workspace: IWorkspace) {
|
||||
let repositoryOwner: string | undefined = undefined;
|
||||
let repositoryName: string | undefined = undefined;
|
||||
@@ -306,20 +325,16 @@ class WindowIndicator implements IWindowIndicator {
|
||||
}
|
||||
}
|
||||
|
||||
// Repo
|
||||
if (repositoryName && repositoryOwner) {
|
||||
this.label = localize('openInDesktopLabel', "$(remote) Open in Desktop");
|
||||
this.tooltip = localize('openInDesktopTooltip', "Open in Desktop");
|
||||
this.command = '_web.openInDesktop';
|
||||
this.commandImpl = {
|
||||
id: this.command,
|
||||
handler: () => {
|
||||
const protocol = product.quality === 'stable' ? 'vscode' : 'vscode-insiders';
|
||||
window.open(`${protocol}://vscode.git/clone?url=${encodeURIComponent(`https://github.com/${repositoryOwner}/${repositoryName}.git`)}`);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
this.label = localize('playgroundLabel', "Web Playground");
|
||||
this.tooltip = this.label;
|
||||
this.label = localize('playgroundLabelRepository', "$(remote) VS Code Web Playground: {0}/{1}", repositoryOwner, repositoryName);
|
||||
this.tooltip = localize('playgroundRepositoryTooltip', "VS Code Web Playground: {0}/{1}", repositoryOwner, repositoryName);
|
||||
}
|
||||
|
||||
// No Repo
|
||||
else {
|
||||
this.label = localize('playgroundLabel', "$(remote) VS Code Web Playground");
|
||||
this.tooltip = localize('playgroundTooltip', "VS Code Web Playground");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,6 +406,9 @@ class WindowIndicator implements IWindowIndicator {
|
||||
}
|
||||
}
|
||||
|
||||
// Workspace Provider
|
||||
const workspaceProvider = new WorkspaceProvider(workspace, payload);
|
||||
|
||||
// Home Indicator
|
||||
const homeIndicator: IHomeIndicator = {
|
||||
href: 'https://github.com/Microsoft/vscode',
|
||||
@@ -398,13 +416,10 @@ class WindowIndicator implements IWindowIndicator {
|
||||
title: localize('home', "Home")
|
||||
};
|
||||
|
||||
// Commands
|
||||
const commands: ICommand[] = [];
|
||||
|
||||
// Window indicator
|
||||
const windowIndicator = new WindowIndicator(workspace);
|
||||
if (windowIndicator.commandImpl) {
|
||||
commands.push(windowIndicator.commandImpl);
|
||||
// Window indicator (unless connected to a remote)
|
||||
let windowIndicator: WindowIndicator | undefined = undefined;
|
||||
if (!workspaceProvider.hasRemote()) {
|
||||
windowIndicator = new WindowIndicator(workspace);
|
||||
}
|
||||
|
||||
// Product Quality Change Handler
|
||||
@@ -422,15 +437,19 @@ class WindowIndicator implements IWindowIndicator {
|
||||
window.location.href = `${window.location.origin}?${queryString}`;
|
||||
};
|
||||
|
||||
// Find credentials from DOM
|
||||
const credentialsElement = document.getElementById('vscode-workbench-credentials');
|
||||
const credentialsElementAttribute = credentialsElement ? credentialsElement.getAttribute('data-settings') : undefined;
|
||||
const credentialsProvider = new LocalStorageCredentialsProvider(credentialsElementAttribute ? JSON.parse(credentialsElementAttribute) : []);
|
||||
|
||||
// Finally create workbench
|
||||
create(document.body, {
|
||||
...config,
|
||||
homeIndicator,
|
||||
commands,
|
||||
windowIndicator,
|
||||
productQualityChangeHandler,
|
||||
workspaceProvider: new WorkspaceProvider(workspace, payload),
|
||||
workspaceProvider,
|
||||
urlCallbackProvider: new PollingURLCallbackProvider(),
|
||||
credentialsProvider: new LocalStorageCredentialsProvider()
|
||||
credentialsProvider
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -33,8 +33,8 @@ const bootstrapWindow = (() => {
|
||||
return window.MonacoBootstrapWindow;
|
||||
})();
|
||||
|
||||
// Setup shell environment
|
||||
process['lazyEnv'] = getLazyEnv();
|
||||
// Load environment in parallel to workbench loading to avoid waterfall
|
||||
const whenEnvResolved = bootstrapWindow.globals().process.whenEnvResolved;
|
||||
|
||||
// Load workbench main JS, CSS and NLS all in parallel. This is an
|
||||
// optimization to prevent a waterfall of loading to happen, because
|
||||
@@ -46,18 +46,19 @@ bootstrapWindow.load([
|
||||
'vs/nls!vs/workbench/workbench.desktop.main',
|
||||
'vs/css!vs/workbench/workbench.desktop.main'
|
||||
],
|
||||
function (workbench, configuration) {
|
||||
async function (workbench, configuration) {
|
||||
|
||||
// Mark start of workbench
|
||||
perf.mark('didLoadWorkbenchMain');
|
||||
performance.mark('workbench-start');
|
||||
|
||||
return process['lazyEnv'].then(function () {
|
||||
perf.mark('main/startup');
|
||||
// Wait for process environment being fully resolved
|
||||
await whenEnvResolved;
|
||||
|
||||
// @ts-ignore
|
||||
return require('vs/workbench/electron-browser/desktop.main').main(configuration);
|
||||
});
|
||||
perf.mark('main/startup');
|
||||
|
||||
// @ts-ignore
|
||||
return require('vs/workbench/electron-browser/desktop.main').main(configuration);
|
||||
},
|
||||
{
|
||||
removeDeveloperKeybindingsAfterLoad: true,
|
||||
@@ -77,7 +78,7 @@ bootstrapWindow.load([
|
||||
* @param {{
|
||||
* partsSplashPath?: string,
|
||||
* highContrast?: boolean,
|
||||
* defaultThemeType?: string,
|
||||
* autoDetectHighContrast?: boolean,
|
||||
* extensionDevelopmentPath?: string[],
|
||||
* folderUri?: object,
|
||||
* workspace?: object
|
||||
@@ -96,7 +97,8 @@ function showPartsSplash(configuration) {
|
||||
}
|
||||
|
||||
// high contrast mode has been turned on from the outside, e.g. OS -> ignore stored colors and layouts
|
||||
if (data && configuration.highContrast && data.baseTheme !== 'hc-black') {
|
||||
const isHighContrast = configuration.highContrast && configuration.autoDetectHighContrast;
|
||||
if (data && isHighContrast && data.baseTheme !== 'hc-black') {
|
||||
data = undefined;
|
||||
}
|
||||
|
||||
@@ -111,14 +113,10 @@ function showPartsSplash(configuration) {
|
||||
baseTheme = data.baseTheme;
|
||||
shellBackground = data.colorInfo.editorBackground;
|
||||
shellForeground = data.colorInfo.foreground;
|
||||
} else if (configuration.highContrast || configuration.defaultThemeType === 'hc') {
|
||||
} else if (isHighContrast) {
|
||||
baseTheme = 'hc-black';
|
||||
shellBackground = '#000000';
|
||||
shellForeground = '#FFFFFF';
|
||||
} else if (configuration.defaultThemeType === 'vs') {
|
||||
baseTheme = 'vs';
|
||||
shellBackground = '#FFFFFF';
|
||||
shellForeground = '#000000';
|
||||
} else {
|
||||
baseTheme = 'vs-dark';
|
||||
shellBackground = '#1E1E1E';
|
||||
@@ -172,26 +170,3 @@ function showPartsSplash(configuration) {
|
||||
|
||||
perf.mark('didShowPartsSplash');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
function getLazyEnv() {
|
||||
const ipcRenderer = bootstrapWindow.globals().ipcRenderer;
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
const handle = setTimeout(function () {
|
||||
resolve();
|
||||
console.warn('renderer did not receive lazyEnv in time');
|
||||
}, 10000);
|
||||
|
||||
ipcRenderer.once('vscode:acceptShellEnv', function (event, shellEnv) {
|
||||
clearTimeout(handle);
|
||||
Object.assign(process.env, shellEnv);
|
||||
// @ts-ignore
|
||||
resolve(process.env);
|
||||
});
|
||||
|
||||
ipcRenderer.send('vscode:fetchShellEnv');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ import { setUnexpectedErrorHandler, onUnexpectedError } from 'vs/base/common/err
|
||||
import { ElectronURLListener } from 'vs/platform/url/electron-main/electronUrlListener';
|
||||
import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver';
|
||||
import { IMenubarMainService, MenubarMainService } from 'vs/platform/menubar/electron-main/menubarMainService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { RunOnceScheduler, timeout } from 'vs/base/common/async';
|
||||
import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu';
|
||||
import { homedir } from 'os';
|
||||
import { join, sep, posix } from 'vs/base/common/path';
|
||||
@@ -68,11 +68,11 @@ import { statSync } from 'fs';
|
||||
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
|
||||
import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||
import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
||||
import { ElectronExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/electron-main/extensionHostDebugIpc';
|
||||
import { IElectronMainService, ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
|
||||
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
|
||||
import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { StorageKeysSyncRegistryChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
|
||||
@@ -80,8 +80,6 @@ import { INativeEnvironmentService } from 'vs/platform/environment/node/environm
|
||||
import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels';
|
||||
import { WebviewMainService } from 'vs/platform/webview/electron-main/webviewMainService';
|
||||
import { IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService';
|
||||
import { createServer, AddressInfo } from 'net';
|
||||
import { IOpenExtensionWindowResult } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { stripComments } from 'vs/base/common/json';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
@@ -272,6 +270,12 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
try {
|
||||
const shellEnv = await getShellEnvironment(this.logService, this.environmentService);
|
||||
|
||||
// TODO@sandbox workaround for https://github.com/electron/electron/issues/25119
|
||||
if (this.environmentService.sandbox) {
|
||||
await timeout(100);
|
||||
}
|
||||
|
||||
if (!webContents.isDestroyed()) {
|
||||
webContents.send('vscode:acceptShellEnv', shellEnv);
|
||||
}
|
||||
@@ -297,7 +301,7 @@ export class CodeApplication extends Disposable {
|
||||
const nativeKeymap = await import('native-keymap');
|
||||
nativeKeymap.onDidChangeKeyboardLayout(() => {
|
||||
if (this.windowsMainService) {
|
||||
this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false);
|
||||
this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged');
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -364,17 +368,17 @@ export class CodeApplication extends Disposable {
|
||||
const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
|
||||
const sharedProcessClient = sharedProcess.whenIpcReady().then(() => {
|
||||
this.logService.trace('Shared process: IPC ready');
|
||||
|
||||
return connect(this.environmentService.sharedIPCHandle, 'main');
|
||||
});
|
||||
const sharedProcessReady = sharedProcess.whenReady().then(() => {
|
||||
this.logService.trace('Shared process: init ready');
|
||||
|
||||
return sharedProcessClient;
|
||||
});
|
||||
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => {
|
||||
this._register(new RunOnceScheduler(async () => {
|
||||
const userEnv = await getShellEnvironment(this.logService, this.environmentService);
|
||||
|
||||
sharedProcess.spawn(userEnv);
|
||||
sharedProcess.spawn(await getShellEnvironment(this.logService, this.environmentService));
|
||||
}, 3000)).schedule();
|
||||
});
|
||||
|
||||
@@ -847,6 +851,9 @@ export class CodeApplication extends Disposable {
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
}
|
||||
|
||||
// Start to fetch shell environment after window has opened
|
||||
getShellEnvironment(this.logService, this.environmentService);
|
||||
}
|
||||
|
||||
private handleRemoteAuthorities(): void {
|
||||
@@ -858,100 +865,3 @@ export class CodeApplication extends Disposable {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ElectronExtensionHostDebugBroadcastChannel<TContext> extends ExtensionHostDebugBroadcastChannel<TContext> {
|
||||
|
||||
constructor(private windowsMainService: IWindowsMainService) {
|
||||
super();
|
||||
}
|
||||
|
||||
call(ctx: TContext, command: string, arg?: any): Promise<any> {
|
||||
if (command === 'openExtensionDevelopmentHostWindow') {
|
||||
return this.openExtensionDevelopmentHostWindow(arg[0], arg[1], arg[2]);
|
||||
} else {
|
||||
return super.call(ctx, command, arg);
|
||||
}
|
||||
}
|
||||
|
||||
private async openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment, debugRenderer: boolean): Promise<IOpenExtensionWindowResult> {
|
||||
const pargs = parseArgs(args, OPTIONS);
|
||||
const extDevPaths = pargs.extensionDevelopmentPath;
|
||||
if (!extDevPaths) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const [codeWindow] = this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, {
|
||||
context: OpenContext.API,
|
||||
cli: pargs,
|
||||
userEnv: Object.keys(env).length > 0 ? env : undefined
|
||||
});
|
||||
|
||||
if (!debugRenderer) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const debug = codeWindow.win.webContents.debugger;
|
||||
|
||||
let listeners = debug.isAttached() ? Infinity : 0;
|
||||
const server = createServer(listener => {
|
||||
if (listeners++ === 0) {
|
||||
debug.attach();
|
||||
}
|
||||
|
||||
let closed = false;
|
||||
const writeMessage = (message: object) => {
|
||||
if (!closed) { // in case sendCommand promises settle after closed
|
||||
listener.write(JSON.stringify(message) + '\0'); // null-delimited, CDP-compatible
|
||||
}
|
||||
};
|
||||
|
||||
const onMessage = (_event: Event, method: string, params: unknown, sessionId?: string) =>
|
||||
writeMessage(({ method, params, sessionId }));
|
||||
|
||||
codeWindow.win.on('close', () => {
|
||||
debug.removeListener('message', onMessage);
|
||||
listener.end();
|
||||
closed = true;
|
||||
});
|
||||
|
||||
debug.addListener('message', onMessage);
|
||||
|
||||
let buf = Buffer.alloc(0);
|
||||
listener.on('data', data => {
|
||||
buf = Buffer.concat([buf, data]);
|
||||
for (let delimiter = buf.indexOf(0); delimiter !== -1; delimiter = buf.indexOf(0)) {
|
||||
let data: { id: number; sessionId: string; params: {} };
|
||||
try {
|
||||
const contents = buf.slice(0, delimiter).toString('utf8');
|
||||
buf = buf.slice(delimiter + 1);
|
||||
data = JSON.parse(contents);
|
||||
} catch (e) {
|
||||
console.error('error reading cdp line', e);
|
||||
}
|
||||
|
||||
// depends on a new API for which electron.d.ts has not been updated:
|
||||
// @ts-ignore
|
||||
debug.sendCommand(data.method, data.params, data.sessionId)
|
||||
.then((result: object) => writeMessage({ id: data.id, sessionId: data.sessionId, result }))
|
||||
.catch((error: Error) => writeMessage({ id: data.id, sessionId: data.sessionId, error: { code: 0, message: error.message } }));
|
||||
}
|
||||
});
|
||||
|
||||
listener.on('error', err => {
|
||||
console.error('error on cdp pipe:', err);
|
||||
});
|
||||
|
||||
listener.on('close', () => {
|
||||
closed = true;
|
||||
if (--listeners === 0) {
|
||||
debug.detach();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise(r => server.listen(0, r));
|
||||
codeWindow.win.on('close', () => server.close());
|
||||
|
||||
return { rendererDebugPort: (server.address() as AddressInfo).port };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as objects from 'vs/base/common/objects';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event } from 'electron';
|
||||
import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event, Details } from 'electron';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -167,12 +167,23 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
title: product.nameLong,
|
||||
webPreferences: {
|
||||
preload: URI.parse(this.doGetPreloadUrl()).fsPath,
|
||||
nodeIntegration: true,
|
||||
enableWebSQL: false,
|
||||
enableRemoteModule: false,
|
||||
nativeWindowOpen: true,
|
||||
webviewTag: true,
|
||||
zoomFactor: zoomLevelToZoomFactor(windowConfig?.zoomLevel)
|
||||
zoomFactor: zoomLevelToZoomFactor(windowConfig?.zoomLevel),
|
||||
...this.environmentService.sandbox ?
|
||||
|
||||
// Sandbox
|
||||
{
|
||||
sandbox: true,
|
||||
contextIsolation: true
|
||||
} :
|
||||
|
||||
// No Sandbox
|
||||
{
|
||||
nodeIntegration: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -325,7 +336,18 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
return !!this.documentEdited;
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
focus(options?: { force: boolean }): void {
|
||||
// macOS: Electron >6.x changed its behaviour to not
|
||||
// bring the application to the foreground when a window
|
||||
// is focused programmatically. Only via `app.focus` and
|
||||
// the option `steal: true` can you get the previous
|
||||
// behaviour back. The only reason to use this option is
|
||||
// when a window is getting focused while the application
|
||||
// is not in the foreground.
|
||||
if (isMacintosh && options?.force) {
|
||||
app.focus({ steal: true });
|
||||
}
|
||||
|
||||
if (!this._win) {
|
||||
return;
|
||||
}
|
||||
@@ -392,7 +414,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
private registerListeners(): void {
|
||||
|
||||
// Crashes & Unrsponsive
|
||||
this._win.webContents.on('crashed', () => this.onWindowError(WindowError.CRASHED));
|
||||
this._win.webContents.on('render-process-gone', (event, details) => this.onWindowError(WindowError.CRASHED, details));
|
||||
this._win.on('unresponsive', () => this.onWindowError(WindowError.UNRESPONSIVE));
|
||||
|
||||
// Window close
|
||||
@@ -524,8 +546,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.marketplaceHeadersPromise.then(headers => cb({ cancel: false, requestHeaders: Object.assign(details.requestHeaders, headers) })));
|
||||
}
|
||||
|
||||
private onWindowError(error: WindowError): void {
|
||||
this.logService.error(error === WindowError.CRASHED ? '[VS Code]: renderer process crashed!' : '[VS Code]: detected unresponsive');
|
||||
private onWindowError(error: WindowError.UNRESPONSIVE): void;
|
||||
private onWindowError(error: WindowError.CRASHED, details: Details): void;
|
||||
private onWindowError(error: WindowError, details?: Details): void {
|
||||
this.logService.error(error === WindowError.CRASHED ? `[VS Code]: renderer process crashed (detail: ${details?.reason})` : '[VS Code]: detected unresponsive');
|
||||
|
||||
// If we run extension tests from CLI, showing a dialog is not
|
||||
// very helpful in this case. Rather, we bring down the test run
|
||||
@@ -579,11 +603,18 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
// Crashed
|
||||
else {
|
||||
let message: string;
|
||||
if (details && details.reason !== 'crashed') {
|
||||
message = nls.localize('appCrashedDetails', "The window has crashed (reason: '{0}')", details?.reason);
|
||||
} else {
|
||||
message = nls.localize('appCrashed', "The window has crashed", details?.reason);
|
||||
}
|
||||
|
||||
this.dialogMainService.showMessageBox({
|
||||
title: product.nameLong,
|
||||
type: 'warning',
|
||||
buttons: [mnemonicButtonLabel(nls.localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(nls.localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
|
||||
message: nls.localize('appCrashed', "The window has crashed"),
|
||||
message,
|
||||
detail: nls.localize('appCrashedDetail', "We are sorry for the inconvenience! You can reopen the window to continue where you left off."),
|
||||
noLink: true
|
||||
}, this._win).then(result => {
|
||||
@@ -699,7 +730,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.showTimeoutHandle = setTimeout(() => {
|
||||
if (this._win && !this._win.isVisible() && !this._win.isMinimized()) {
|
||||
this._win.show();
|
||||
this._win.focus();
|
||||
this.focus({ force: true });
|
||||
this._win.webContents.openDevTools();
|
||||
}
|
||||
}, 10000);
|
||||
@@ -754,11 +785,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
windowConfiguration.fullscreen = this.isFullScreen;
|
||||
|
||||
// Set Accessibility Config
|
||||
let autoDetectHighContrast = true;
|
||||
if (windowConfig?.autoDetectHighContrast === false) {
|
||||
autoDetectHighContrast = false;
|
||||
}
|
||||
windowConfiguration.highContrast = isWindows && autoDetectHighContrast && nativeTheme.shouldUseInvertedColorScheme;
|
||||
windowConfiguration.highContrast = nativeTheme.shouldUseInvertedColorScheme || nativeTheme.shouldUseHighContrastColors;
|
||||
windowConfiguration.autoDetectHighContrast = windowConfig?.autoDetectHighContrast ?? true;
|
||||
windowConfiguration.accessibilitySupport = app.accessibilitySupportEnabled;
|
||||
|
||||
// Title style related
|
||||
@@ -799,7 +827,14 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
|
||||
private doGetUrl(config: object): string {
|
||||
return `${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`;
|
||||
let workbench: string;
|
||||
if (this.environmentService.sandbox) {
|
||||
workbench = 'vs/code/electron-sandbox/workbench/workbench.html';
|
||||
} else {
|
||||
workbench = 'vs/code/electron-browser/workbench/workbench.html';
|
||||
}
|
||||
|
||||
return `${require.toUrl(workbench)}?config=${encodeURIComponent(JSON.stringify(config))}`;
|
||||
}
|
||||
|
||||
private doGetPreloadUrl(): string {
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'vs/base/browser/ui/codicons/codiconStyles'; // make sure codicon css is
|
||||
import { ElectronService, IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { ipcRenderer, process } 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 { $, reset, windowOpenNoOpener, addClass } from 'vs/base/browser/dom';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { CodiconLabel } from 'vs/base/browser/ui/codicons/codiconLabel';
|
||||
import * as collections from 'vs/base/common/collections';
|
||||
@@ -277,33 +277,25 @@ export class IssueReporter extends Disposable {
|
||||
}
|
||||
|
||||
private updateSettingsSearchDetails(data: ISettingsSearchIssueReporterData): void {
|
||||
const target = document.querySelector('.block-settingsSearchResults .block-info');
|
||||
const target = document.querySelector<HTMLElement>('.block-settingsSearchResults .block-info');
|
||||
if (target) {
|
||||
const details = `
|
||||
<div class='block-settingsSearchResults-details'>
|
||||
<div>Query: "${data.query}"</div>
|
||||
<div>Literal match count: ${data.filterResultCount}</div>
|
||||
</div>
|
||||
`;
|
||||
const queryDiv = $<HTMLDivElement>('div', undefined, `Query: "${data.query}"` as string);
|
||||
const countDiv = $<HTMLElement>('div', undefined, `Literal match count: ${data.filterResultCount}` as string);
|
||||
const detailsDiv = $<HTMLDivElement>('.block-settingsSearchResults-details', undefined, queryDiv, countDiv);
|
||||
|
||||
let table = `
|
||||
<tr>
|
||||
<th>Setting</th>
|
||||
<th>Extension</th>
|
||||
<th>Score</th>
|
||||
</tr>`;
|
||||
|
||||
data.actualSearchResults
|
||||
.forEach(setting => {
|
||||
table += `
|
||||
<tr>
|
||||
<td>${setting.key}</td>
|
||||
<td>${setting.extensionId}</td>
|
||||
<td>${String(setting.score).slice(0, 5)}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
target.innerHTML = `${details}<table>${table}</table>`;
|
||||
const table = $('table', undefined,
|
||||
$('tr', undefined,
|
||||
$('th', undefined, 'Setting'),
|
||||
$('th', undefined, 'Extension'),
|
||||
$('th', undefined, 'Score'),
|
||||
),
|
||||
...data.actualSearchResults.map(setting => $('tr', undefined,
|
||||
$('td', undefined, setting.key),
|
||||
$('td', undefined, setting.extensionId),
|
||||
$('td', undefined, String(setting.score).slice(0, 5)),
|
||||
))
|
||||
);
|
||||
reset(target, detailsDiv, table);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,9 +646,9 @@ export class IssueReporter extends Disposable {
|
||||
issueState.appendChild(issueIcon);
|
||||
issueState.appendChild(issueStateLabel);
|
||||
|
||||
item = $('div.issue', {}, issueState, link);
|
||||
item = $('div.issue', undefined, issueState, link);
|
||||
} else {
|
||||
item = $('div.issue', {}, link);
|
||||
item = $('div.issue', undefined, link);
|
||||
}
|
||||
|
||||
issues.appendChild(item);
|
||||
@@ -672,19 +664,19 @@ export class IssueReporter extends Disposable {
|
||||
}
|
||||
|
||||
private setUpTypes(): void {
|
||||
const makeOption = (issueType: IssueType, description: string) => `<option value="${issueType.valueOf()}">${escape(description)}</option>`;
|
||||
const makeOption = (issueType: IssueType, description: string) => $('option', { 'value': issueType.valueOf() }, escape(description));
|
||||
|
||||
const typeSelect = this.getElementById('issue-type')! as HTMLSelectElement;
|
||||
const { issueType } = this.issueReporterModel.getData();
|
||||
if (issueType === IssueType.SettingsSearchIssue) {
|
||||
typeSelect.innerHTML = makeOption(IssueType.SettingsSearchIssue, localize('settingsSearchIssue', "Settings Search Issue"));
|
||||
reset(typeSelect, makeOption(IssueType.SettingsSearchIssue, localize('settingsSearchIssue', "Settings Search Issue")));
|
||||
typeSelect.disabled = true;
|
||||
} else {
|
||||
typeSelect.innerHTML = [
|
||||
reset(typeSelect,
|
||||
makeOption(IssueType.Bug, localize('bugReporter', "Bug Report")),
|
||||
makeOption(IssueType.FeatureRequest, localize('featureRequest', "Feature Request")),
|
||||
makeOption(IssueType.PerformanceIssue, localize('performanceIssue', "Performance Issue"))
|
||||
].join('\n');
|
||||
);
|
||||
}
|
||||
|
||||
typeSelect.value = issueType.toString();
|
||||
@@ -774,9 +766,8 @@ export class IssueReporter extends Disposable {
|
||||
} else {
|
||||
show(extensionsBlock);
|
||||
}
|
||||
|
||||
descriptionTitle.innerHTML = `${localize('stepsToReproduce', "Steps to Reproduce")} <span class="required-input">*</span>`;
|
||||
descriptionSubtitle.innerHTML = localize('bugDescription', "Share the steps needed to reliably reproduce the problem. Please include actual and expected results. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.");
|
||||
reset(descriptionTitle, localize('stepsToReproduce', "Steps to Reproduce"), $('span.required-input', undefined, '*'));
|
||||
reset(descriptionSubtitle, localize('bugDescription', "Share the steps needed to reliably reproduce the problem. Please include actual and expected results. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub."));
|
||||
} else if (issueType === IssueType.PerformanceIssue) {
|
||||
show(blockContainer);
|
||||
show(systemBlock);
|
||||
@@ -790,11 +781,11 @@ export class IssueReporter extends Disposable {
|
||||
show(extensionsBlock);
|
||||
}
|
||||
|
||||
descriptionTitle.innerHTML = `${localize('stepsToReproduce', "Steps to Reproduce")} <span class="required-input">*</span>`;
|
||||
descriptionSubtitle.innerHTML = localize('performanceIssueDesciption', "When did this performance issue happen? Does it occur on startup or after a specific series of actions? We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.");
|
||||
reset(descriptionTitle, localize('stepsToReproduce', "Steps to Reproduce"), $('span.required-input', undefined, '*'));
|
||||
reset(descriptionSubtitle, localize('performanceIssueDesciption', "When did this performance issue happen? Does it occur on startup or after a specific series of actions? We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub."));
|
||||
} else if (issueType === IssueType.FeatureRequest) {
|
||||
descriptionTitle.innerHTML = `${localize('description', "Description")} <span class="required-input">*</span>`;
|
||||
descriptionSubtitle.innerHTML = localize('featureRequestDescription', "Please describe the feature you would like to see. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.");
|
||||
reset(descriptionTitle, localize('description', "Description"), $('span.required-input', undefined, '*'));
|
||||
reset(descriptionSubtitle, localize('featureRequestDescription', "Please describe the feature you would like to see. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub."));
|
||||
show(problemSource);
|
||||
|
||||
if (fileOnExtension) {
|
||||
@@ -805,8 +796,8 @@ export class IssueReporter extends Disposable {
|
||||
show(searchedExtensionsBlock);
|
||||
show(settingsSearchResultsBlock);
|
||||
|
||||
descriptionTitle.innerHTML = `${localize('expectedResults', "Expected Results")} <span class="required-input">*</span>`;
|
||||
descriptionSubtitle.innerHTML = localize('settingsSearchResultsDescription', "Please list the results that you were expecting to see when you searched with this query. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub.");
|
||||
reset(descriptionTitle, localize('expectedResults', "Expected Results"), $('span.required-input', undefined, '*'));
|
||||
reset(descriptionSubtitle, localize('settingsSearchResultsDescription', "Please list the results that you were expecting to see when you searched with this query. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,42 +919,82 @@ export class IssueReporter extends Disposable {
|
||||
}
|
||||
|
||||
private updateSystemInfo(state: IssueReporterModelData) {
|
||||
const target = document.querySelector('.block-system .block-info');
|
||||
const target = document.querySelector<HTMLElement>('.block-system .block-info');
|
||||
|
||||
if (target) {
|
||||
const systemInfo = state.systemInfo!;
|
||||
let renderedData = `
|
||||
<table>
|
||||
<tr><td>CPUs</td><td>${systemInfo.cpus}</td></tr>
|
||||
<tr><td>GPU Status</td><td>${Object.keys(systemInfo.gpuStatus).map(key => `${key}: ${systemInfo.gpuStatus[key]}`).join('<br>')}</td></tr>
|
||||
<tr><td>Load (avg)</td><td>${systemInfo.load}</td></tr>
|
||||
<tr><td>Memory (System)</td><td>${systemInfo.memory}</td></tr>
|
||||
<tr><td>Process Argv</td><td>${systemInfo.processArgs}</td></tr>
|
||||
<tr><td>Screen Reader</td><td>${systemInfo.screenReader}</td></tr>
|
||||
<tr><td>VM</td><td>${systemInfo.vmHint}</td></tr>
|
||||
</table>`;
|
||||
const renderedDataTable = $('table', undefined,
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'CPUs'),
|
||||
$('td', undefined, systemInfo.cpus || ''),
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'GPU Status' as string),
|
||||
$('td', undefined, Object.keys(systemInfo.gpuStatus).map(key => `${key}: ${systemInfo.gpuStatus[key]}`).join('\n')),
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'Load (avg)' as string),
|
||||
$('td', undefined, systemInfo.load || ''),
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'Memory (System)' as string),
|
||||
$('td', undefined, systemInfo.memory),
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'Process Argv' as string),
|
||||
$('td', undefined, systemInfo.processArgs),
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'Screen Reader' as string),
|
||||
$('td', undefined, systemInfo.screenReader),
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'VM'),
|
||||
$('td', undefined, systemInfo.vmHint),
|
||||
),
|
||||
);
|
||||
reset(target, renderedDataTable);
|
||||
|
||||
systemInfo.remoteData.forEach(remote => {
|
||||
target.appendChild($<HTMLHRElement>('hr'));
|
||||
if (isRemoteDiagnosticError(remote)) {
|
||||
renderedData += `
|
||||
<hr>
|
||||
<table>
|
||||
<tr><td>Remote</td><td>${remote.hostName}</td></tr>
|
||||
<tr><td></td><td>${remote.errorMessage}</td></tr>
|
||||
</table>`;
|
||||
const remoteDataTable = $('table', undefined,
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'Remote'),
|
||||
$('td', undefined, remote.hostName)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, ''),
|
||||
$('td', undefined, remote.errorMessage)
|
||||
)
|
||||
);
|
||||
target.appendChild(remoteDataTable);
|
||||
} else {
|
||||
renderedData += `
|
||||
<hr>
|
||||
<table>
|
||||
<tr><td>Remote</td><td>${remote.hostName}</td></tr>
|
||||
<tr><td>OS</td><td>${remote.machineInfo.os}</td></tr>
|
||||
<tr><td>CPUs</td><td>${remote.machineInfo.cpus}</td></tr>
|
||||
<tr><td>Memory (System)</td><td>${remote.machineInfo.memory}</td></tr>
|
||||
<tr><td>VM</td><td>${remote.machineInfo.vmHint}</td></tr>
|
||||
</table>`;
|
||||
const remoteDataTable = $('table', undefined,
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'Remote'),
|
||||
$('td', undefined, remote.hostName)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'OS'),
|
||||
$('td', undefined, remote.machineInfo.os)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'CPUs'),
|
||||
$('td', undefined, remote.machineInfo.cpus || '')
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'Memory (System)' as string),
|
||||
$('td', undefined, remote.machineInfo.memory)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td', undefined, 'VM'),
|
||||
$('td', undefined, remote.machineInfo.vmHint)
|
||||
),
|
||||
);
|
||||
target.appendChild(remoteDataTable);
|
||||
}
|
||||
});
|
||||
|
||||
target.innerHTML = renderedData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,15 +1026,18 @@ export class IssueReporter extends Disposable {
|
||||
return 0;
|
||||
});
|
||||
|
||||
const makeOption = (extension: IOption, selectedExtension?: IssueReporterExtensionData) => {
|
||||
const makeOption = (extension: IOption, selectedExtension?: IssueReporterExtensionData): HTMLOptionElement => {
|
||||
const selected = selectedExtension && extension.id === selectedExtension.id;
|
||||
return `<option value="${extension.id}" ${selected ? 'selected' : ''}>${escape(extension.name)}</option>`;
|
||||
return $<HTMLOptionElement>('option', {
|
||||
'value': extension.id,
|
||||
'selected': selected || ''
|
||||
}, extension.name);
|
||||
};
|
||||
|
||||
const extensionsSelector = this.getElementById('extension-selector');
|
||||
if (extensionsSelector) {
|
||||
const { selectedExtension } = this.issueReporterModel.getData();
|
||||
extensionsSelector.innerHTML = '<option></option>' + extensionOptions.map(extension => makeOption(extension, selectedExtension)).join('\n');
|
||||
reset(extensionsSelector, $<HTMLOptionElement>('option'), ...extensionOptions.map(extension => makeOption(extension, selectedExtension)));
|
||||
|
||||
this.addEventListener('extension-selector', 'change', (e: Event) => {
|
||||
const selectedExtensionId = (<HTMLInputElement>e.target).value;
|
||||
@@ -1071,9 +1105,9 @@ export class IssueReporter extends Disposable {
|
||||
}
|
||||
|
||||
private updateProcessInfo(state: IssueReporterModelData) {
|
||||
const target = document.querySelector('.block-process .block-info');
|
||||
const target = document.querySelector('.block-process .block-info') as HTMLElement;
|
||||
if (target) {
|
||||
target.innerHTML = `<code>${state.processInfo}</code>`;
|
||||
reset(target, $('code', undefined, state.processInfo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,7 +1119,7 @@ export class IssueReporter extends Disposable {
|
||||
const target = document.querySelector<HTMLElement>('.block-extensions .block-info');
|
||||
if (target) {
|
||||
if (this.configuration.disableExtensions) {
|
||||
target.innerHTML = localize('disabledExtensions', "Extensions are disabled");
|
||||
reset(target, localize('disabledExtensions', "Extensions are disabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1097,8 +1131,7 @@ export class IssueReporter extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const table = this.getExtensionTableHtml(extensions);
|
||||
target.innerHTML = `<table>${table}</table>${themeExclusionStr}`;
|
||||
reset(target, this.getExtensionTableHtml(extensions), document.createTextNode(themeExclusionStr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,28 +1144,24 @@ export class IssueReporter extends Disposable {
|
||||
}
|
||||
|
||||
const table = this.getExtensionTableHtml(extensions);
|
||||
target.innerHTML = `<table>${table}</table>`;
|
||||
target.innerText = '';
|
||||
target.appendChild(table);
|
||||
}
|
||||
}
|
||||
|
||||
private getExtensionTableHtml(extensions: IssueReporterExtensionData[]): string {
|
||||
let table = `
|
||||
<tr>
|
||||
<th>Extension</th>
|
||||
<th>Author (truncated)</th>
|
||||
<th>Version</th>
|
||||
</tr>`;
|
||||
|
||||
table += extensions.map(extension => {
|
||||
return `
|
||||
<tr>
|
||||
<td>${extension.name}</td>
|
||||
<td>${extension.publisher.substr(0, 3)}</td>
|
||||
<td>${extension.version}</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
|
||||
return table;
|
||||
private getExtensionTableHtml(extensions: IssueReporterExtensionData[]): HTMLTableElement {
|
||||
return $('table', undefined,
|
||||
$('tr', undefined,
|
||||
$('th', undefined, 'Extension'),
|
||||
$('th', undefined, 'Author (truncated)' as string),
|
||||
$('th', undefined, 'Version'),
|
||||
),
|
||||
...extensions.map(extension => $('tr', undefined,
|
||||
$('td', undefined, extension.name),
|
||||
$('td', undefined, extension.publisher.substr(0, 3)),
|
||||
$('td', undefined, extension.version),
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
private openLink(event: MouseEvent): void {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"/></svg>
|
||||
|
Before Width: | Height: | Size: 139 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M11 10H5.344L11 4.414V10z"/></svg>
|
||||
|
Before Width: | Height: | Size: 118 B |
@@ -58,6 +58,7 @@ table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
th[scope='col'] {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
@@ -65,6 +66,7 @@ th[scope='col'] {
|
||||
border-top: 1px solid #cccccc;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: .25rem;
|
||||
vertical-align: top;
|
||||
@@ -100,7 +102,6 @@ tbody > tr:hover {
|
||||
display: none;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
margin-right: 4px;
|
||||
.header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/processExplorer';
|
||||
import 'vs/base/browser/ui/codicons/codiconStyles'; // make sure codicon css is loaded
|
||||
import { ElectronService, IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -16,6 +17,7 @@ import { addDisposableListener, addClass } from 'vs/base/browser/dom';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { MainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
|
||||
import { CodiconLabel } from 'vs/base/browser/ui/codicons/codiconLabel';
|
||||
|
||||
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
|
||||
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
|
||||
@@ -156,15 +158,15 @@ class ProcessExplorer {
|
||||
return maxProcessId;
|
||||
}
|
||||
|
||||
private updateSectionCollapsedState(shouldExpand: boolean, body: HTMLElement, twistie: HTMLImageElement, sectionName: string) {
|
||||
private updateSectionCollapsedState(shouldExpand: boolean, body: HTMLElement, twistie: CodiconLabel, sectionName: string) {
|
||||
if (shouldExpand) {
|
||||
body.classList.remove('hidden');
|
||||
this.collapsedStateCache.set(sectionName, false);
|
||||
twistie.src = './media/expanded.svg';
|
||||
twistie.text = '$(chevron-down)';
|
||||
} else {
|
||||
body.classList.add('hidden');
|
||||
this.collapsedStateCache.set(sectionName, true);
|
||||
twistie.src = './media/collapsed.svg';
|
||||
twistie.text = '$(chevron-right)';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,18 +193,27 @@ class ProcessExplorer {
|
||||
|
||||
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);
|
||||
|
||||
const twistie = document.createElement('img');
|
||||
this.updateSectionCollapsedState(!this.collapsedStateCache.get(sectionName), body, twistie, sectionName);
|
||||
data.prepend(twistie);
|
||||
const headerData = document.createElement('td');
|
||||
headerData.colSpan = 4;
|
||||
headerRow.appendChild(headerData);
|
||||
|
||||
this.listeners.add(addDisposableListener(data, 'click', (e) => {
|
||||
const headerContainer = document.createElement('div');
|
||||
headerContainer.className = 'header';
|
||||
headerData.appendChild(headerContainer);
|
||||
|
||||
const twistieContainer = document.createElement('div');
|
||||
const twistieCodicon = new CodiconLabel(twistieContainer);
|
||||
this.updateSectionCollapsedState(!this.collapsedStateCache.get(sectionName), body, twistieCodicon, sectionName);
|
||||
headerContainer.appendChild(twistieContainer);
|
||||
|
||||
const headerLabel = document.createElement('span');
|
||||
headerLabel.textContent = sectionName;
|
||||
headerContainer.appendChild(headerLabel);
|
||||
|
||||
this.listeners.add(addDisposableListener(headerData, 'click', (e) => {
|
||||
const isHidden = body.classList.contains('hidden');
|
||||
this.updateSectionCollapsedState(isHidden, body, twistie, sectionName);
|
||||
this.updateSectionCollapsedState(isHidden, body, twistieCodicon, sectionName);
|
||||
}));
|
||||
|
||||
container.appendChild(headerRow);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote-resource:; media-src 'none'; frame-src 'self' vscode-webview: https://*.vscode-webview-test.com; object-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https: vscode-remote-resource:;">
|
||||
</head>
|
||||
<body aria-label="">
|
||||
</body>
|
||||
|
||||
<!-- Init Bootstrap Helpers -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
|
||||
<!-- Startup via workbench.js -->
|
||||
<script src="workbench.js"></script>
|
||||
</html>
|
||||
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path="../../../../typings/require.d.ts" />
|
||||
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
const perf = (function () {
|
||||
globalThis.MonacoPerformanceMarks = globalThis.MonacoPerformanceMarks || [];
|
||||
return {
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
mark(name) {
|
||||
globalThis.MonacoPerformanceMarks.push(name, Date.now());
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
perf.mark('renderer/started');
|
||||
|
||||
/**
|
||||
* @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;
|
||||
})();
|
||||
|
||||
// Load environment in parallel to workbench loading to avoid waterfall
|
||||
const whenEnvResolved = bootstrapWindow.globals().process.whenEnvResolved;
|
||||
|
||||
// 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.sandbox.main will depend on
|
||||
// the related CSS and NLS counterparts.
|
||||
bootstrapWindow.load([
|
||||
'vs/workbench/workbench.desktop.sandbox.main',
|
||||
'vs/nls!vs/workbench/workbench.desktop.main',
|
||||
'vs/css!vs/workbench/workbench.desktop.main'
|
||||
],
|
||||
async function (workbench, configuration) {
|
||||
|
||||
// Mark start of workbench
|
||||
perf.mark('didLoadWorkbenchMain');
|
||||
performance.mark('workbench-start');
|
||||
|
||||
// Wait for process environment being fully resolved
|
||||
await whenEnvResolved;
|
||||
|
||||
perf.mark('main/startup');
|
||||
|
||||
// @ts-ignore
|
||||
return require('vs/workbench/electron-sandbox/desktop.main').main(configuration);
|
||||
},
|
||||
{
|
||||
removeDeveloperKeybindingsAfterLoad: true,
|
||||
canModifyDOM: function (windowConfig) {
|
||||
// TODO@sandbox part-splash is non-sandboxed only
|
||||
},
|
||||
beforeLoaderConfig: function (windowConfig, loaderConfig) {
|
||||
loaderConfig.recordStats = true;
|
||||
},
|
||||
beforeRequire: function () {
|
||||
perf.mark('willLoadWorkbenchMain');
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -14,7 +14,7 @@ import * as paths from 'vs/base/common/path';
|
||||
import { whenDeleted, writeFileSync } from 'vs/base/node/pfs';
|
||||
import { findFreePort, randomPort } from 'vs/base/node/ports';
|
||||
import { isWindows, isLinux } from 'vs/base/common/platform';
|
||||
import { ProfilingSession, Target } from 'v8-inspect-profiler';
|
||||
import type { ProfilingSession, Target } from 'v8-inspect-profiler';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
import { hasStdinWithoutTty, stdinDataListener, getStdinFilePath, readFromStdin } from 'vs/platform/environment/node/stdin';
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { localize } from 'vs/nls';
|
||||
import { raceTimeout } from 'vs/base/common/async';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as semver from 'semver-umd';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -214,6 +213,8 @@ export class Main {
|
||||
throw new Error('Invalid vsix');
|
||||
}
|
||||
|
||||
const semver = await import('semver-umd');
|
||||
|
||||
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
|
||||
const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const newer = installedExtensions.find(local => areSameExtensions(extensionIdentifier, local.identifier) && semver.gt(local.manifest.version, manifest.version));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import { spawn } from 'child_process';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -30,7 +30,7 @@ function getUnixShellEnvironment(logService: ILogService): Promise<typeof proces
|
||||
logService.trace('getUnixShellEnvironment#env', env);
|
||||
logService.trace('getUnixShellEnvironment#spawn', command);
|
||||
|
||||
const child = cp.spawn(process.env.SHELL!, ['-ilc', command], {
|
||||
const child = spawn(process.env.SHELL!, ['-ilc', command], {
|
||||
detached: true,
|
||||
stdio: ['ignore', 'pipe', process.stderr],
|
||||
env
|
||||
@@ -82,8 +82,7 @@ function getUnixShellEnvironment(logService: ILogService): Promise<typeof proces
|
||||
return promise.catch(() => ({}));
|
||||
}
|
||||
|
||||
|
||||
let _shellEnv: Promise<typeof process.env>;
|
||||
let shellEnvPromise: Promise<typeof process.env> | undefined = undefined;
|
||||
|
||||
/**
|
||||
* We need to get the environment from a user's shell.
|
||||
@@ -91,21 +90,21 @@ let _shellEnv: Promise<typeof process.env>;
|
||||
* from within a shell.
|
||||
*/
|
||||
export function getShellEnvironment(logService: ILogService, environmentService: INativeEnvironmentService): Promise<typeof process.env> {
|
||||
if (_shellEnv === undefined) {
|
||||
if (!shellEnvPromise) {
|
||||
if (environmentService.args['disable-user-env-probe']) {
|
||||
logService.trace('getShellEnvironment: disable-user-env-probe set, skipping');
|
||||
_shellEnv = Promise.resolve({});
|
||||
shellEnvPromise = Promise.resolve({});
|
||||
} else if (isWindows) {
|
||||
logService.trace('getShellEnvironment: running on Windows, skipping');
|
||||
_shellEnv = Promise.resolve({});
|
||||
shellEnvPromise = Promise.resolve({});
|
||||
} else if (process.env['VSCODE_CLI'] === '1' && process.env['VSCODE_FORCE_USER_ENV'] !== '1') {
|
||||
logService.trace('getShellEnvironment: running on CLI, skipping');
|
||||
_shellEnv = Promise.resolve({});
|
||||
shellEnvPromise = Promise.resolve({});
|
||||
} else {
|
||||
logService.trace('getShellEnvironment: running on Unix');
|
||||
_shellEnv = getUnixShellEnvironment(logService);
|
||||
shellEnvPromise = getUnixShellEnvironment(logService);
|
||||
}
|
||||
}
|
||||
|
||||
return _shellEnv;
|
||||
return shellEnvPromise;
|
||||
}
|
||||
|
||||
@@ -28,9 +28,8 @@ suite('Windows Native Helpers', () => {
|
||||
});
|
||||
|
||||
test('vscode-windows-ca-certs', async () => {
|
||||
const windowsCerts = await new Promise<any>((resolve, reject) => {
|
||||
require(['vscode-windows-ca-certs'], resolve, reject);
|
||||
});
|
||||
// @ts-ignore Windows only
|
||||
const windowsCerts = await import('vscode-windows-ca-certs');
|
||||
assert.ok(windowsCerts, 'Unable to load vscode-windows-ca-certs dependency.');
|
||||
});
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ interface InMemoryClipboardMetadata {
|
||||
* Every time we read from the cipboard, if the text matches our last written text,
|
||||
* we can fetch the previous metadata.
|
||||
*/
|
||||
class InMemoryClipboardMetadataManager {
|
||||
export class InMemoryClipboardMetadataManager {
|
||||
public static readonly INSTANCE = new InMemoryClipboardMetadataManager();
|
||||
|
||||
private _lastState: InMemoryClipboardMetadata | null;
|
||||
|
||||
@@ -348,6 +348,14 @@ export interface IEditorConstructionOptions extends IEditorOptions {
|
||||
overflowWidgetsDomNode?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface IDiffEditorConstructionOptions extends IDiffEditorOptions {
|
||||
/**
|
||||
* Place overflow widgets inside an external DOM node.
|
||||
* Defaults to an internal DOM node.
|
||||
*/
|
||||
overflowWidgetsDomNode?: HTMLElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* A rich code editor.
|
||||
*/
|
||||
|
||||
@@ -4,13 +4,64 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { WorkspaceEdit } from 'vs/editor/common/modes';
|
||||
import { TextEdit, WorkspaceEdit, WorkspaceEditMetadata, WorkspaceFileEdit, WorkspaceFileEditOptions, WorkspaceTextEdit } from 'vs/editor/common/modes';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
|
||||
export const IBulkEditService = createDecorator<IBulkEditService>('IWorkspaceEditService');
|
||||
|
||||
function isWorkspaceFileEdit(thing: any): thing is WorkspaceFileEdit {
|
||||
return isObject(thing) && (Boolean((<WorkspaceFileEdit>thing).newUri) || Boolean((<WorkspaceFileEdit>thing).oldUri));
|
||||
}
|
||||
|
||||
function isWorkspaceTextEdit(thing: any): thing is WorkspaceTextEdit {
|
||||
return isObject(thing) && URI.isUri((<WorkspaceTextEdit>thing).resource) && isObject((<WorkspaceTextEdit>thing).edit);
|
||||
}
|
||||
|
||||
export class ResourceEdit {
|
||||
|
||||
protected constructor(readonly metadata?: WorkspaceEditMetadata) { }
|
||||
|
||||
static convert(edit: WorkspaceEdit): ResourceEdit[] {
|
||||
|
||||
|
||||
return edit.edits.map(edit => {
|
||||
if (isWorkspaceTextEdit(edit)) {
|
||||
return new ResourceTextEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata);
|
||||
}
|
||||
if (isWorkspaceFileEdit(edit)) {
|
||||
return new ResourceFileEdit(edit.oldUri, edit.newUri, edit.options, edit.metadata);
|
||||
}
|
||||
throw new Error('Unsupported edit');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ResourceTextEdit extends ResourceEdit {
|
||||
constructor(
|
||||
readonly resource: URI,
|
||||
readonly textEdit: TextEdit,
|
||||
readonly versionId?: number,
|
||||
readonly metadata?: WorkspaceEditMetadata
|
||||
) {
|
||||
super(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
export class ResourceFileEdit extends ResourceEdit {
|
||||
constructor(
|
||||
readonly oldResource: URI | undefined,
|
||||
readonly newResource: URI | undefined,
|
||||
readonly options?: WorkspaceFileEditOptions,
|
||||
readonly metadata?: WorkspaceEditMetadata
|
||||
) {
|
||||
super(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IBulkEditOptions {
|
||||
editor?: ICodeEditor;
|
||||
progress?: IProgress<IProgressStep>;
|
||||
@@ -23,7 +74,7 @@ export interface IBulkEditResult {
|
||||
ariaSummary: string;
|
||||
}
|
||||
|
||||
export type IBulkEditPreviewHandler = (edit: WorkspaceEdit, options?: IBulkEditOptions) => Promise<WorkspaceEdit>;
|
||||
export type IBulkEditPreviewHandler = (edits: ResourceEdit[], options?: IBulkEditOptions) => Promise<ResourceEdit[]>;
|
||||
|
||||
export interface IBulkEditService {
|
||||
readonly _serviceBrand: undefined;
|
||||
@@ -32,6 +83,5 @@ export interface IBulkEditService {
|
||||
|
||||
setPreviewHandler(handler: IBulkEditPreviewHandler): IDisposable;
|
||||
|
||||
apply(edit: WorkspaceEdit, options?: IBulkEditOptions): Promise<IBulkEditResult>;
|
||||
apply(edit: ResourceEdit[], options?: IBulkEditOptions): Promise<IBulkEditResult>;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export class DomReadingContext {
|
||||
|
||||
export class ViewLineOptions {
|
||||
public readonly themeType: ThemeType;
|
||||
public readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all';
|
||||
public readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
|
||||
public readonly renderControlCharacters: boolean;
|
||||
public readonly spaceWidth: number;
|
||||
public readonly middotWidth: number;
|
||||
|
||||
@@ -217,7 +217,7 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
endStyle.top = CornerStyle.INTERN;
|
||||
}
|
||||
} else if (previousFrameTop) {
|
||||
// Accept some hick-ups near the viewport edges to save on repaints
|
||||
// Accept some hiccups near the viewport edges to save on repaints
|
||||
startStyle.top = previousFrameTop.startStyle!.top;
|
||||
endStyle.top = previousFrameTop.endStyle!.top;
|
||||
}
|
||||
@@ -239,7 +239,7 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
endStyle.bottom = CornerStyle.INTERN;
|
||||
}
|
||||
} else if (previousFrameBottom) {
|
||||
// Accept some hick-ups near the viewport edges to save on repaints
|
||||
// Accept some hiccups near the viewport edges to save on repaints
|
||||
startStyle.bottom = previousFrameBottom.startStyle!.bottom;
|
||||
endStyle.bottom = previousFrameBottom.endStyle!.bottom;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ interface IEditorsZones {
|
||||
modified: IMyViewZone[];
|
||||
}
|
||||
|
||||
interface IDiffEditorWidgetStyle {
|
||||
export interface IDiffEditorWidgetStyle {
|
||||
// {{SQL CARBON EDIT}}
|
||||
getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, reverse?: boolean): IEditorsDiffDecorationsWithZones;
|
||||
setEnableSplitViewResizing(enableSplitViewResizing: boolean): void;
|
||||
@@ -177,6 +177,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
private readonly _onDidUpdateDiff: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onDidUpdateDiff: Event<void> = this._onDidUpdateDiff.event;
|
||||
|
||||
private readonly _onDidContentSizeChange: Emitter<editorCommon.IContentSizeChangedEvent> = this._register(new Emitter<editorCommon.IContentSizeChangedEvent>());
|
||||
public readonly onDidContentSizeChange: Event<editorCommon.IContentSizeChangedEvent> = this._onDidContentSizeChange.event;
|
||||
|
||||
private readonly id: number;
|
||||
private _state: editorBrowser.DiffEditorState;
|
||||
private _updatingDiffProgress: IProgressRunner | null;
|
||||
@@ -230,7 +233,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: IDiffEditorOptions,
|
||||
options: editorBrowser.IDiffEditorConstructionOptions,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IEditorWorkerService editorWorkerService: IEditorWorkerService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@@ -353,21 +356,19 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._diffComputationResult = null;
|
||||
|
||||
const leftContextKeyService = this._contextKeyService.createScoped();
|
||||
leftContextKeyService.createKey('isInDiffLeftEditor', true);
|
||||
|
||||
const leftServices = new ServiceCollection();
|
||||
leftServices.set(IContextKeyService, leftContextKeyService);
|
||||
const leftScopedInstantiationService = instantiationService.createChild(leftServices);
|
||||
|
||||
const rightContextKeyService = this._contextKeyService.createScoped();
|
||||
rightContextKeyService.createKey('isInDiffRightEditor', true);
|
||||
|
||||
const rightServices = new ServiceCollection();
|
||||
rightServices.set(IContextKeyService, rightContextKeyService);
|
||||
const rightScopedInstantiationService = instantiationService.createChild(rightServices);
|
||||
|
||||
this.originalEditor = this._createLeftHandSideEditor(options, leftScopedInstantiationService);
|
||||
this.modifiedEditor = this._createRightHandSideEditor(options, rightScopedInstantiationService);
|
||||
this.originalEditor = this._createLeftHandSideEditor(options, leftScopedInstantiationService, leftContextKeyService);
|
||||
this.modifiedEditor = this._createRightHandSideEditor(options, rightScopedInstantiationService, rightContextKeyService);
|
||||
|
||||
this._originalOverviewRuler = null;
|
||||
this._modifiedOverviewRuler = null;
|
||||
@@ -377,8 +378,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._containerDomElement.appendChild(this._reviewPane.shadow.domNode);
|
||||
this._containerDomElement.appendChild(this._reviewPane.actionBarContainer.domNode);
|
||||
|
||||
|
||||
|
||||
// enableSplitViewResizing
|
||||
this._enableSplitViewResizing = true;
|
||||
if (typeof options.enableSplitViewResizing !== 'undefined') {
|
||||
@@ -426,6 +425,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return this._renderIndicators;
|
||||
}
|
||||
|
||||
public getContentHeight(): number {
|
||||
return this.modifiedEditor.getContentHeight();
|
||||
}
|
||||
|
||||
private _setState(newState: editorBrowser.DiffEditorState): void {
|
||||
if (this._state === newState) {
|
||||
return;
|
||||
@@ -485,7 +488,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._layoutOverviewRulers();
|
||||
}
|
||||
|
||||
private _createLeftHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget {
|
||||
private _createLeftHandSideEditor(options: editorBrowser.IDiffEditorConstructionOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {
|
||||
const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options, this._originalIsEditable, this._originalCodeLens));
|
||||
|
||||
this._register(editor.onDidScrollChange((e) => {
|
||||
@@ -515,10 +518,26 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
}));
|
||||
|
||||
const isInDiffLeftEditorKey = contextKeyService.createKey<boolean>('isInDiffLeftEditor', undefined);
|
||||
this._register(editor.onDidFocusEditorWidget(() => isInDiffLeftEditorKey.set(true)));
|
||||
this._register(editor.onDidBlurEditorWidget(() => isInDiffLeftEditorKey.set(false)));
|
||||
|
||||
this._register(editor.onDidContentSizeChange(e => {
|
||||
const width = this.originalEditor.getContentWidth() + this.modifiedEditor.getContentWidth() + DiffEditorWidget.ONE_OVERVIEW_WIDTH;
|
||||
const height = Math.max(this.modifiedEditor.getContentHeight(), this.originalEditor.getContentHeight());
|
||||
|
||||
this._onDidContentSizeChange.fire({
|
||||
contentHeight: height,
|
||||
contentWidth: width,
|
||||
contentHeightChanged: e.contentHeightChanged,
|
||||
contentWidthChanged: e.contentWidthChanged
|
||||
});
|
||||
}));
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
private _createRightHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget {
|
||||
private _createRightHandSideEditor(options: editorBrowser.IDiffEditorConstructionOptions, instantiationService: IInstantiationService, contextKeyService: IContextKeyService): CodeEditorWidget {
|
||||
const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options, this._modifiedCodeLens));
|
||||
|
||||
this._register(editor.onDidScrollChange((e) => {
|
||||
@@ -560,6 +579,22 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
}));
|
||||
|
||||
const isInDiffRightEditorKey = contextKeyService.createKey<boolean>('isInDiffRightEditor', undefined);
|
||||
this._register(editor.onDidFocusEditorWidget(() => isInDiffRightEditorKey.set(true)));
|
||||
this._register(editor.onDidBlurEditorWidget(() => isInDiffRightEditorKey.set(false)));
|
||||
|
||||
this._register(editor.onDidContentSizeChange(e => {
|
||||
const width = this.originalEditor.getContentWidth() + this.modifiedEditor.getContentWidth() + DiffEditorWidget.ONE_OVERVIEW_WIDTH;
|
||||
const height = Math.max(this.modifiedEditor.getContentHeight(), this.originalEditor.getContentHeight());
|
||||
|
||||
this._onDidContentSizeChange.fire({
|
||||
contentHeight: height,
|
||||
contentWidth: width,
|
||||
contentHeightChanged: e.contentHeightChanged,
|
||||
contentWidthChanged: e.contentWidthChanged
|
||||
});
|
||||
}));
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
@@ -1064,8 +1099,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
}
|
||||
}
|
||||
|
||||
private _adjustOptionsForSubEditor(options: IDiffEditorOptions): IDiffEditorOptions {
|
||||
let clonedOptions: IDiffEditorOptions = objects.deepClone(options || {});
|
||||
private _adjustOptionsForSubEditor(options: editorBrowser.IDiffEditorConstructionOptions): editorBrowser.IDiffEditorConstructionOptions {
|
||||
let clonedOptions: editorBrowser.IDiffEditorConstructionOptions = objects.deepClone(options || {});
|
||||
clonedOptions.inDiffEditor = true;
|
||||
clonedOptions.wordWrap = 'off';
|
||||
clonedOptions.wordWrapMinified = false;
|
||||
@@ -1075,6 +1110,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
clonedOptions.folding = false;
|
||||
clonedOptions.codeLens = false;
|
||||
clonedOptions.fixedOverflowWidgets = true;
|
||||
clonedOptions.overflowWidgetsDomNode = options.overflowWidgetsDomNode;
|
||||
// clonedOptions.lineDecorationsWidth = '2ch';
|
||||
if (!clonedOptions.minimap) {
|
||||
clonedOptions.minimap = {};
|
||||
@@ -1083,7 +1119,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return clonedOptions;
|
||||
}
|
||||
|
||||
private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean, isCodeLensEnabled: boolean): IEditorOptions {
|
||||
private _adjustOptionsForLeftHandSide(options: editorBrowser.IDiffEditorConstructionOptions, isEditable: boolean, isCodeLensEnabled: boolean): editorBrowser.IEditorConstructionOptions {
|
||||
let result = this._adjustOptionsForSubEditor(options);
|
||||
if (isCodeLensEnabled) {
|
||||
result.codeLens = true;
|
||||
@@ -1093,7 +1129,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
return result;
|
||||
}
|
||||
|
||||
private _adjustOptionsForRightHandSide(options: IDiffEditorOptions, isCodeLensEnabled: boolean): IEditorOptions {
|
||||
private _adjustOptionsForRightHandSide(options: editorBrowser.IDiffEditorConstructionOptions, isCodeLensEnabled: boolean): editorBrowser.IEditorConstructionOptions {
|
||||
let result = this._adjustOptionsForSubEditor(options);
|
||||
if (isCodeLensEnabled) {
|
||||
result.codeLens = true;
|
||||
@@ -1628,14 +1664,14 @@ abstract class ViewZonesComputer {
|
||||
protected abstract _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null;
|
||||
}
|
||||
|
||||
function createDecoration(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, options: ModelDecorationOptions) {
|
||||
export function createDecoration(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, options: ModelDecorationOptions) {
|
||||
return {
|
||||
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
|
||||
options: options
|
||||
};
|
||||
}
|
||||
|
||||
const DECORATIONS = {
|
||||
export const DECORATIONS = {
|
||||
|
||||
charDelete: ModelDecorationOptions.register({
|
||||
className: 'char-delete'
|
||||
@@ -1683,7 +1719,7 @@ const DECORATIONS = {
|
||||
|
||||
};
|
||||
|
||||
class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider {
|
||||
export class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider {
|
||||
|
||||
static readonly MINIMUM_EDITOR_WIDTH = 100;
|
||||
|
||||
@@ -2211,11 +2247,11 @@ class InlineViewZonesComputer extends ViewZonesComputer {
|
||||
}
|
||||
}
|
||||
|
||||
function isChangeOrInsert(lineChange: editorCommon.IChange): boolean {
|
||||
export function isChangeOrInsert(lineChange: editorCommon.IChange): boolean {
|
||||
return lineChange.modifiedEndLineNumber > 0;
|
||||
}
|
||||
|
||||
function isChangeOrDelete(lineChange: editorCommon.IChange): boolean {
|
||||
export function isChangeOrDelete(lineChange: editorCommon.IChange): boolean {
|
||||
return lineChange.originalEndLineNumber > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -529,7 +529,7 @@ export interface IEditorOptions {
|
||||
* Enable rendering of whitespace.
|
||||
* Defaults to none.
|
||||
*/
|
||||
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all';
|
||||
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
|
||||
/**
|
||||
* Enable rendering of control characters.
|
||||
* Defaults to false.
|
||||
@@ -856,15 +856,13 @@ class EditorBooleanOption<K1 extends EditorOption> extends SimpleEditorOption<K1
|
||||
|
||||
class EditorIntOption<K1 extends EditorOption> extends SimpleEditorOption<K1, number> {
|
||||
|
||||
public static clampedInt(value: any, defaultValue: number, minimum: number, maximum: number): number {
|
||||
let r: number;
|
||||
public static clampedInt<T>(value: any, defaultValue: T, minimum: number, maximum: number): number | T {
|
||||
if (typeof value === 'undefined') {
|
||||
r = defaultValue;
|
||||
} else {
|
||||
r = parseInt(value, 10);
|
||||
if (isNaN(r)) {
|
||||
r = defaultValue;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
let r = parseInt(value, 10);
|
||||
if (isNaN(r)) {
|
||||
return defaultValue;
|
||||
}
|
||||
r = Math.max(minimum, r);
|
||||
r = Math.min(maximum, r);
|
||||
@@ -1348,7 +1346,7 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
|
||||
nls.localize('editor.find.autoFindInSelection.always', 'Always turn on Find in selection automatically'),
|
||||
nls.localize('editor.find.autoFindInSelection.multiline', 'Turn on Find in selection automatically when multiple lines of content are selected.')
|
||||
],
|
||||
description: nls.localize('find.autoFindInSelection', "Controls whether the find operation is carried out on selected text or the entire file in the editor.")
|
||||
description: nls.localize('find.autoFindInSelection', "Controls the condition for turning on find in selection automatically.")
|
||||
},
|
||||
'editor.find.globalFindClipboard': {
|
||||
type: 'boolean',
|
||||
@@ -1491,6 +1489,48 @@ class EditorFontSize extends SimpleEditorOption<EditorOption.fontSize, number> {
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region fontWeight
|
||||
|
||||
class EditorFontWeight extends BaseEditorOption<EditorOption.fontWeight, string> {
|
||||
private static SUGGESTION_VALUES = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
|
||||
private static MINIMUM_VALUE = 1;
|
||||
private static MAXIMUM_VALUE = 1000;
|
||||
|
||||
constructor() {
|
||||
super(
|
||||
EditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight,
|
||||
{
|
||||
anyOf: [
|
||||
{
|
||||
type: 'number',
|
||||
minimum: EditorFontWeight.MINIMUM_VALUE,
|
||||
maximum: EditorFontWeight.MAXIMUM_VALUE,
|
||||
errorMessage: nls.localize('fontWeightErrorMessage', "Only \"normal\" and \"bold\" keywords or numbers between 1 and 1000 are allowed.")
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
pattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$'
|
||||
},
|
||||
{
|
||||
enum: EditorFontWeight.SUGGESTION_VALUES
|
||||
}
|
||||
],
|
||||
default: EDITOR_FONT_DEFAULTS.fontWeight,
|
||||
description: nls.localize('fontWeight', "Controls the font weight. Accepts \"normal\" and \"bold\" keywords or numbers between 1 and 1000.")
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public validate(input: any): string {
|
||||
if (input === 'normal' || input === 'bold') {
|
||||
return input;
|
||||
}
|
||||
return String(EditorIntOption.clampedInt(input, EDITOR_FONT_DEFAULTS.fontWeight, EditorFontWeight.MINIMUM_VALUE, EditorFontWeight.MAXIMUM_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region gotoLocation
|
||||
|
||||
export type GoToLocationValues = 'peek' | 'gotoAndPeek' | 'goto';
|
||||
@@ -1824,7 +1864,7 @@ export interface EditorLayoutInfoComputerEnv {
|
||||
readonly memory: ComputeOptionsMemory | null;
|
||||
readonly outerWidth: number;
|
||||
readonly outerHeight: number;
|
||||
readonly isDominatedByLongLines: boolean
|
||||
readonly isDominatedByLongLines: boolean;
|
||||
readonly lineHeight: number;
|
||||
readonly viewLineCount: number;
|
||||
readonly lineNumbersDigitCount: number;
|
||||
@@ -1839,7 +1879,7 @@ export interface EditorLayoutInfoComputerEnv {
|
||||
export interface IEditorLayoutComputerInput {
|
||||
readonly outerWidth: number;
|
||||
readonly outerHeight: number;
|
||||
readonly isDominatedByLongLines: boolean
|
||||
readonly isDominatedByLongLines: boolean;
|
||||
readonly lineHeight: number;
|
||||
readonly lineNumbersDigitCount: number;
|
||||
readonly typicalHalfwidthCharacterWidth: number;
|
||||
@@ -3102,7 +3142,7 @@ export interface ISuggestOptions {
|
||||
* Controls the visibility of the status bar at the bottom of the suggest widget.
|
||||
*/
|
||||
visible?: boolean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type InternalSuggestOptions = Readonly<Required<ISuggestOptions>>;
|
||||
@@ -3869,13 +3909,7 @@ export const EditorOptions = {
|
||||
fontInfo: register(new EditorFontInfo()),
|
||||
fontLigatures2: register(new EditorFontLigatures()),
|
||||
fontSize: register(new EditorFontSize()),
|
||||
fontWeight: register(new EditorStringOption(
|
||||
EditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight,
|
||||
{
|
||||
enum: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
|
||||
description: nls.localize('fontWeight', "Controls the font weight.")
|
||||
}
|
||||
)),
|
||||
fontWeight: register(new EditorFontWeight()),
|
||||
formatOnPaste: register(new EditorBooleanOption(
|
||||
EditorOption.formatOnPaste, 'formatOnPaste', false,
|
||||
{ description: nls.localize('formatOnPaste', "Controls whether the editor should automatically format the pasted content. A formatter must be available and the formatter should be able to format a range in a document.") }
|
||||
@@ -4054,13 +4088,14 @@ export const EditorOptions = {
|
||||
)),
|
||||
renderWhitespace: register(new EditorStringEnumOption(
|
||||
EditorOption.renderWhitespace, 'renderWhitespace',
|
||||
'selection' as 'selection' | 'none' | 'boundary' | 'all',
|
||||
['none', 'boundary', 'selection', 'all'] as const,
|
||||
'selection' as 'selection' | 'none' | 'boundary' | 'trailing' | 'all',
|
||||
['none', 'boundary', 'selection', 'trailing', 'all'] as const,
|
||||
{
|
||||
enumDescriptions: [
|
||||
'',
|
||||
nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."),
|
||||
nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."),
|
||||
nls.localize('renderWhitespace.trailing', "Render only trailing whitespace characters"),
|
||||
''
|
||||
],
|
||||
description: nls.localize('renderWhitespace', "Controls how the editor should render whitespace characters.")
|
||||
|
||||
@@ -1312,6 +1312,7 @@ export interface IReadonlyTextBuffer {
|
||||
getLinesContent(): string[];
|
||||
getLineContent(lineNumber: number): string;
|
||||
getLineCharCode(lineNumber: number, index: number): number;
|
||||
getCharCode(offset: number): number;
|
||||
getLineLength(lineNumber: number): number;
|
||||
getLineFirstNonWhitespaceColumn(lineNumber: number): number;
|
||||
getLineLastNonWhitespaceColumn(lineNumber: number): number;
|
||||
|
||||
@@ -626,8 +626,7 @@ export class PieceTreeBase {
|
||||
return this._lastVisitedLine.value;
|
||||
}
|
||||
|
||||
public getLineCharCode(lineNumber: number, index: number): number {
|
||||
let nodePos = this.nodeAt2(lineNumber, index + 1);
|
||||
private _getCharCode(nodePos: NodePosition): number {
|
||||
if (nodePos.remainder === nodePos.node.piece.length) {
|
||||
// the char we want to fetch is at the head of next node.
|
||||
let matchingNode = nodePos.node.next();
|
||||
@@ -647,6 +646,11 @@ export class PieceTreeBase {
|
||||
}
|
||||
}
|
||||
|
||||
public getLineCharCode(lineNumber: number, index: number): number {
|
||||
let nodePos = this.nodeAt2(lineNumber, index + 1);
|
||||
return this._getCharCode(nodePos);
|
||||
}
|
||||
|
||||
public getLineLength(lineNumber: number): number {
|
||||
if (lineNumber === this.getLineCount()) {
|
||||
let startOffset = this.getOffsetAt(lineNumber, 1);
|
||||
@@ -655,6 +659,11 @@ export class PieceTreeBase {
|
||||
return this.getOffsetAt(lineNumber + 1, 1) - this.getOffsetAt(lineNumber, 1) - this._EOLLength;
|
||||
}
|
||||
|
||||
public getCharCode(offset: number): number {
|
||||
let nodePos = this.nodeAt(offset);
|
||||
return this._getCharCode(nodePos);
|
||||
}
|
||||
|
||||
public findMatchesInNode(node: TreeNode, searcher: Searcher, startLineNumber: number, startColumn: number, startCursor: BufferCursor, endCursor: BufferCursor, searchData: SearchData, captureMatches: boolean, limitResultCount: number, resultLen: number, result: FindMatch[]) {
|
||||
let buffer = this._buffers[node.piece.bufferIndex];
|
||||
let startOffsetInBuffer = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);
|
||||
|
||||
@@ -178,6 +178,10 @@ export class PieceTreeTextBuffer implements ITextBuffer, IDisposable {
|
||||
return this._pieceTree.getLineCharCode(lineNumber, index);
|
||||
}
|
||||
|
||||
public getCharCode(offset: number): number {
|
||||
return this._pieceTree.getCharCode(offset);
|
||||
}
|
||||
|
||||
public getLineLength(lineNumber: number): number {
|
||||
return this._pieceTree.getLineLength(lineNumber);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Color } from 'vs/base/common/color';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
@@ -1337,29 +1336,6 @@ export class FoldingRangeKind {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export namespace WorkspaceFileEdit {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function is(thing: any): thing is WorkspaceFileEdit {
|
||||
return isObject(thing) && (Boolean((<WorkspaceFileEdit>thing).newUri) || Boolean((<WorkspaceFileEdit>thing).oldUri));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export namespace WorkspaceTextEdit {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function is(thing: any): thing is WorkspaceTextEdit {
|
||||
return isObject(thing) && URI.isUri((<WorkspaceTextEdit>thing).resource) && isObject((<WorkspaceTextEdit>thing).edit);
|
||||
}
|
||||
}
|
||||
|
||||
export interface WorkspaceEditMetadata {
|
||||
needsConfirmation: boolean;
|
||||
|
||||
@@ -399,10 +399,10 @@ export function generateTokensCSSForColorMap(colorMap: Color[]): string {
|
||||
let rules: string[] = [];
|
||||
for (let i = 1, len = colorMap.length; i < len; i++) {
|
||||
let color = colorMap[i];
|
||||
rules[i] = `.mtk${i} { color: ${color}; }`;
|
||||
rules[i] = `.monaco-editor .mtk${i} { color: ${color}; }`;
|
||||
}
|
||||
rules.push('.mtki { font-style: italic; }');
|
||||
rules.push('.mtkb { font-weight: bold; }');
|
||||
rules.push('.mtku { text-decoration: underline; text-underline-position: under; }');
|
||||
rules.push('.monaco-editor .mtki { font-style: italic; }');
|
||||
rules.push('.monaco-editor .mtkb { font-weight: bold; }');
|
||||
rules.push('.monaco-editor .mtku { text-decoration: underline; text-underline-position: under; }');
|
||||
return rules.join('\n');
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ 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 { toArray } from 'vs/base/common/arrays';
|
||||
|
||||
export class TokenizationRegistryImpl implements ITokenizationRegistry {
|
||||
|
||||
@@ -82,7 +81,7 @@ export class TokenizationRegistryImpl implements ITokenizationRegistry {
|
||||
public setColorMap(colorMap: Color[]): void {
|
||||
this._colorMap = colorMap;
|
||||
this._onDidChange.fire({
|
||||
changedLanguages: toArray(this._map.keys()),
|
||||
changedLanguages: Array.from(this._map.keys()),
|
||||
changedColorMap: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,6 +54,11 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
||||
export function getIconClassesForModeId(modeId: string): string[] {
|
||||
return ['file-icon', `${cssEscape(modeId)}-lang-file-icon`];
|
||||
}
|
||||
|
||||
export function detectModeId(modelService: IModelService, modeService: IModeService, resource: uri): string | null {
|
||||
if (!resource) {
|
||||
return null; // we need a resource at least
|
||||
|
||||
@@ -14,7 +14,8 @@ export const enum RenderWhitespace {
|
||||
None = 0,
|
||||
Boundary = 1,
|
||||
Selection = 2,
|
||||
All = 3
|
||||
Trailing = 3,
|
||||
All = 4
|
||||
}
|
||||
|
||||
export const enum LinePartMetadata {
|
||||
@@ -113,7 +114,7 @@ export class RenderLineInput {
|
||||
middotWidth: number,
|
||||
wsmiddotWidth: number,
|
||||
stopRenderingLineAfter: number,
|
||||
renderWhitespace: 'none' | 'boundary' | 'selection' | 'all',
|
||||
renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all',
|
||||
renderControlCharacters: boolean,
|
||||
fontLigatures: boolean,
|
||||
selectionsOnLine: LineRange[] | null
|
||||
@@ -138,7 +139,9 @@ export class RenderLineInput {
|
||||
? RenderWhitespace.Boundary
|
||||
: renderWhitespace === 'selection'
|
||||
? RenderWhitespace.Selection
|
||||
: RenderWhitespace.None
|
||||
: renderWhitespace === 'trailing'
|
||||
? RenderWhitespace.Trailing
|
||||
: RenderWhitespace.None
|
||||
);
|
||||
this.renderControlCharacters = renderControlCharacters;
|
||||
this.fontLigatures = fontLigatures;
|
||||
@@ -435,7 +438,11 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
|
||||
}
|
||||
|
||||
let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len);
|
||||
if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) {
|
||||
if (input.renderWhitespace === RenderWhitespace.All ||
|
||||
input.renderWhitespace === RenderWhitespace.Boundary ||
|
||||
(input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine) ||
|
||||
input.renderWhitespace === RenderWhitespace.Trailing) {
|
||||
|
||||
tokens = _applyRenderWhitespace(input, lineContent, len, tokens);
|
||||
}
|
||||
let containsForeignElements = ForeignElementType.None;
|
||||
@@ -592,6 +599,7 @@ function _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len
|
||||
const useMonospaceOptimizations = input.useMonospaceOptimizations;
|
||||
const selections = input.selectionsOnLine;
|
||||
const onlyBoundary = (input.renderWhitespace === RenderWhitespace.Boundary);
|
||||
const onlyTrailing = (input.renderWhitespace === RenderWhitespace.Trailing);
|
||||
const generateLinePartForEachWhitespace = (input.renderSpaceWidth !== input.spaceWidth);
|
||||
|
||||
let result: LinePart[] = [], resultLen = 0;
|
||||
@@ -600,10 +608,11 @@ function _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len
|
||||
let tokenEndIndex = tokens[tokenIndex].endIndex;
|
||||
const tokensLength = tokens.length;
|
||||
|
||||
let lineIsEmptyOrWhitespace = false;
|
||||
let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);
|
||||
let lastNonWhitespaceIndex: number;
|
||||
if (firstNonWhitespaceIndex === -1) {
|
||||
// The entire line is whitespace
|
||||
lineIsEmptyOrWhitespace = true;
|
||||
firstNonWhitespaceIndex = len;
|
||||
lastNonWhitespaceIndex = len;
|
||||
} else {
|
||||
@@ -651,6 +660,11 @@ function _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len
|
||||
isInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex;
|
||||
}
|
||||
|
||||
// If rendering only trailing whitespace, check that the charIndex points to trailing whitespace.
|
||||
if (isInWhitespace && onlyTrailing) {
|
||||
isInWhitespace = lineIsEmptyOrWhitespace || charIndex > lastNonWhitespaceIndex;
|
||||
}
|
||||
|
||||
if (wasInWhitespace) {
|
||||
// was in whitespace token
|
||||
if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { CopyOptions } from 'vs/editor/browser/controller/textAreaInput';
|
||||
import { CopyOptions, InMemoryClipboardMetadataManager } from 'vs/editor/browser/controller/textAreaInput';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, registerEditorAction, Command, MultiCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
@@ -16,6 +16,8 @@ import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { Handler } from 'vs/editor/common/editorCommon';
|
||||
|
||||
const CLIPBOARD_CONTEXT_MENU_GROUP = '9_cutcopypaste';
|
||||
|
||||
@@ -23,10 +25,9 @@ const supportsCut = (platform.isNative || document.queryCommandSupported('cut'))
|
||||
const supportsCopy = (platform.isNative || document.queryCommandSupported('copy'));
|
||||
// IE and Edge have trouble with setting html content in clipboard
|
||||
const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdge);
|
||||
// Chrome incorrectly returns true for document.queryCommandSupported('paste')
|
||||
// when the paste feature is available but the calling script has insufficient
|
||||
// privileges to actually perform the action
|
||||
const supportsPaste = (platform.isNative || (!browser.isChrome && document.queryCommandSupported('paste')));
|
||||
// Firefox only supports navigator.clipboard.readText() in browser extensions.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText#Browser_compatibility
|
||||
const supportsPaste = (browser.isFirefox ? document.queryCommandSupported('paste') : true);
|
||||
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
@@ -160,7 +161,7 @@ class ExecCommandCopyWithSyntaxHighlightingAction extends EditorAction {
|
||||
}
|
||||
}
|
||||
|
||||
function registerExecCommandImpl(target: MultiCommand | undefined, browserCommand: 'cut' | 'copy' | 'paste'): void {
|
||||
function registerExecCommandImpl(target: MultiCommand | undefined, browserCommand: 'cut' | 'copy'): void {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
@@ -170,13 +171,11 @@ function registerExecCommandImpl(target: MultiCommand | undefined, browserComman
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
if (browserCommand === 'cut' || browserCommand === 'copy') {
|
||||
// Do not execute if there is no selection and empty selection clipboard is off
|
||||
const emptySelectionClipboard = focusedEditor.getOption(EditorOption.emptySelectionClipboard);
|
||||
const selection = focusedEditor.getSelection();
|
||||
if (selection && selection.isEmpty() && !emptySelectionClipboard) {
|
||||
return true;
|
||||
}
|
||||
// Do not execute if there is no selection and empty selection clipboard is off
|
||||
const emptySelectionClipboard = focusedEditor.getOption(EditorOption.emptySelectionClipboard);
|
||||
const selection = focusedEditor.getSelection();
|
||||
if (selection && selection.isEmpty() && !emptySelectionClipboard) {
|
||||
return true;
|
||||
}
|
||||
document.execCommand(browserCommand);
|
||||
return true;
|
||||
@@ -186,7 +185,6 @@ function registerExecCommandImpl(target: MultiCommand | undefined, browserComman
|
||||
|
||||
// 2. (default) handle case when focus is somewhere else.
|
||||
target.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
document.execCommand(browserCommand);
|
||||
return true;
|
||||
});
|
||||
@@ -194,7 +192,52 @@ function registerExecCommandImpl(target: MultiCommand | undefined, browserComman
|
||||
|
||||
registerExecCommandImpl(CutAction, 'cut');
|
||||
registerExecCommandImpl(CopyAction, 'copy');
|
||||
registerExecCommandImpl(PasteAction, 'paste');
|
||||
|
||||
if (PasteAction) {
|
||||
// 1. Paste: handle case when focus is in editor.
|
||||
PasteAction.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {
|
||||
const codeEditorService = accessor.get(ICodeEditorService);
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
const focusedEditor = codeEditorService.getFocusedCodeEditor();
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
const result = document.execCommand('paste');
|
||||
// Use the clipboard service if document.execCommand('paste') was not successful
|
||||
if (!result && platform.isWeb) {
|
||||
(async () => {
|
||||
const clipboardText = await clipboardService.readText();
|
||||
if (clipboardText !== '') {
|
||||
const metadata = InMemoryClipboardMetadataManager.INSTANCE.get(clipboardText);
|
||||
let pasteOnNewLine = false;
|
||||
let multicursorText: string[] | null = null;
|
||||
let mode: string | null = null;
|
||||
if (metadata) {
|
||||
pasteOnNewLine = (focusedEditor.getOption(EditorOption.emptySelectionClipboard) && !!metadata.isFromEmptySelection);
|
||||
multicursorText = (typeof metadata.multicursorText !== 'undefined' ? metadata.multicursorText : null);
|
||||
mode = metadata.mode;
|
||||
}
|
||||
focusedEditor.trigger('keyboard', Handler.Paste, {
|
||||
text: clipboardText,
|
||||
pasteOnNewLine,
|
||||
multicursorText,
|
||||
mode
|
||||
});
|
||||
}
|
||||
})();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 2. Paste: (default) handle case when focus is somewhere else.
|
||||
PasteAction.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
|
||||
document.execCommand('paste');
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (supportsCopyWithSyntaxHighlighting) {
|
||||
registerEditorAction(ExecCommandCopyWithSyntaxHighlightingAction);
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
@@ -163,7 +163,7 @@ export async function applyCodeAction(
|
||||
});
|
||||
|
||||
if (action.edit) {
|
||||
await bulkEditService.apply(action.edit, { editor, label: action.title });
|
||||
await bulkEditService.apply(ResourceEdit.convert(action.edit), { editor, label: action.title });
|
||||
}
|
||||
|
||||
if (action.command) {
|
||||
|
||||
@@ -89,6 +89,7 @@ function createCodeActionKeybinding(keycode: KeyCode, command: string, commandAr
|
||||
command,
|
||||
commandArgs,
|
||||
undefined,
|
||||
false);
|
||||
false,
|
||||
null);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
@@ -371,7 +370,6 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
|
||||
public async getGlobalBufferTerm(): Promise<string> {
|
||||
if (this._editor.getOption(EditorOption.find).globalFindClipboard
|
||||
&& this._clipboardService
|
||||
&& this._editor.hasModel()
|
||||
&& !this._editor.getModel().isTooLargeForSyncing()
|
||||
) {
|
||||
@@ -382,7 +380,6 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
|
||||
public setGlobalBufferTerm(text: string): void {
|
||||
if (this._editor.getOption(EditorOption.find).globalFindClipboard
|
||||
&& this._clipboardService
|
||||
&& this._editor.hasModel()
|
||||
&& !this._editor.getModel().isTooLargeForSyncing()
|
||||
) {
|
||||
@@ -406,7 +403,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IStorageService _storageService: IStorageService,
|
||||
@IStorageKeysSyncRegistryService private readonly _storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
|
||||
@optional(IClipboardService) clipboardService: IClipboardService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
) {
|
||||
super(editor, _contextKeyService, _storageService, clipboardService);
|
||||
this._widget = null;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/* Find widget */
|
||||
.monaco-editor .find-widget {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
z-index: 50;
|
||||
height: 33px;
|
||||
overflow: hidden;
|
||||
line-height: 19px;
|
||||
|
||||
@@ -267,14 +267,16 @@ class FormatSelectionAction extends EditorAction {
|
||||
}
|
||||
const instaService = accessor.get(IInstantiationService);
|
||||
const model = editor.getModel();
|
||||
let range: Range = editor.getSelection();
|
||||
if (range.isEmpty()) {
|
||||
range = new Range(range.startLineNumber, 1, range.startLineNumber, model.getLineMaxColumn(range.startLineNumber));
|
||||
}
|
||||
|
||||
const ranges = editor.getSelections().map(range => {
|
||||
return range.isEmpty()
|
||||
? new Range(range.startLineNumber, 1, range.startLineNumber, model.getLineMaxColumn(range.startLineNumber))
|
||||
: range;
|
||||
});
|
||||
|
||||
const progressService = accessor.get(IEditorProgressService);
|
||||
await progressService.showWhile(
|
||||
instaService.invokeFunction(formatDocumentRangesWithSelectedProvider, editor, range, FormattingMode.Explicit, Progress.None, CancellationToken.None),
|
||||
instaService.invokeFunction(formatDocumentRangesWithSelectedProvider, editor, ranges, FormattingMode.Explicit, Progress.None, CancellationToken.None),
|
||||
250
|
||||
);
|
||||
}
|
||||
|
||||
@@ -971,7 +971,7 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut
|
||||
return;
|
||||
}
|
||||
|
||||
const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model);
|
||||
const hasFindOccurrences = DocumentHighlightProviderRegistry.has(model) && this.editor.getOption(EditorOption.occurrencesHighlight);
|
||||
|
||||
let allMatches = model.findMatches(this.state.searchText, true, false, this.state.matchCase, this.state.wordSeparators, false).map(m => m.range);
|
||||
allMatches.sort(Range.compareRangesUsingStarts);
|
||||
|
||||
@@ -46,6 +46,8 @@ export class OnTypeRenameContribution extends Disposable implements IEditorContr
|
||||
return editor.getContribution<OnTypeRenameContribution>(OnTypeRenameContribution.ID);
|
||||
}
|
||||
|
||||
private _debounceDuration = 200;
|
||||
|
||||
private readonly _editor: ICodeEditor;
|
||||
private _enabled: boolean;
|
||||
|
||||
@@ -121,15 +123,15 @@ export class OnTypeRenameContribution extends Disposable implements IEditorContr
|
||||
this._languageWordPattern = LanguageConfigurationRegistry.getWordDefinition(model.getLanguageIdentifier().id);
|
||||
}));
|
||||
|
||||
const rangeUpdateScheduler = new Delayer(200);
|
||||
const rangeUpdateScheduler = new Delayer(this._debounceDuration);
|
||||
const triggerRangeUpdate = () => {
|
||||
this._rangeUpdateTriggerPromise = rangeUpdateScheduler.trigger(() => this.updateRanges());
|
||||
this._rangeUpdateTriggerPromise = rangeUpdateScheduler.trigger(() => this.updateRanges(), this._debounceDuration);
|
||||
};
|
||||
const rangeSyncScheduler = new Delayer(0);
|
||||
const triggerRangeSync = (decorations: string[]) => {
|
||||
this._rangeSyncTriggerPromise = rangeSyncScheduler.trigger(() => this._syncRanges(decorations));
|
||||
};
|
||||
this._localToDispose.add(this._editor.onDidChangeCursorPosition((e) => {
|
||||
this._localToDispose.add(this._editor.onDidChangeCursorPosition(() => {
|
||||
triggerRangeUpdate();
|
||||
}));
|
||||
this._localToDispose.add(this._editor.onDidChangeModelContent((e) => {
|
||||
@@ -332,6 +334,11 @@ export class OnTypeRenameContribution extends Disposable implements IEditorContr
|
||||
return request;
|
||||
}
|
||||
|
||||
// for testing
|
||||
public setDebounceDuration(timeInMS: number) {
|
||||
this._debounceDuration = timeInMS;
|
||||
}
|
||||
|
||||
// private printDecorators(model: ITextModel) {
|
||||
// return this._currentDecorations.map(d => {
|
||||
// const range = model.getDecorationRange(d);
|
||||
|
||||
@@ -22,7 +22,7 @@ import { MessageController } from 'vs/editor/contrib/message/messageController';
|
||||
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/browser/core/editorState';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
@@ -226,7 +226,7 @@ class RenameController implements IEditorContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
this._bulkEditService.apply(renameResult, {
|
||||
this._bulkEditService.apply(ResourceEdit.convert(renameResult), {
|
||||
editor: this.editor,
|
||||
showPreview: inputFieldResult.wantsPreview,
|
||||
label: nls.localize('label', "Renaming '{0}'", loc?.text),
|
||||
|
||||
@@ -79,6 +79,7 @@ suite('On type rename', () => {
|
||||
OnTypeRenameContribution.ID,
|
||||
OnTypeRenameContribution
|
||||
);
|
||||
ontypeRenameContribution.setDebounceDuration(0);
|
||||
|
||||
const testEditor: TestEditor = {
|
||||
setPosition(pos: Position) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from '
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { SnippetSession } from './snippetSession';
|
||||
import { OvertypingCapturer } from 'vs/editor/contrib/suggest/suggestOvertypingCapturer';
|
||||
|
||||
export interface ISnippetInsertOptions {
|
||||
overwriteBefore: number;
|
||||
@@ -26,6 +27,7 @@ export interface ISnippetInsertOptions {
|
||||
undoStopBefore: boolean;
|
||||
undoStopAfter: boolean;
|
||||
clipboardText: string | undefined;
|
||||
overtypingCapturer: OvertypingCapturer | undefined;
|
||||
}
|
||||
|
||||
const _defaultOptions: ISnippetInsertOptions = {
|
||||
@@ -34,7 +36,8 @@ const _defaultOptions: ISnippetInsertOptions = {
|
||||
undoStopBefore: true,
|
||||
undoStopAfter: true,
|
||||
adjustWhitespace: true,
|
||||
clipboardText: undefined
|
||||
clipboardText: undefined,
|
||||
overtypingCapturer: undefined
|
||||
};
|
||||
|
||||
export class SnippetController2 implements IEditorContribution {
|
||||
|
||||
@@ -23,6 +23,7 @@ import * as colors from 'vs/platform/theme/common/colorRegistry';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { OvertypingCapturer } from 'vs/editor/contrib/suggest/suggestOvertypingCapturer';
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
|
||||
@@ -319,13 +320,15 @@ export interface ISnippetSessionInsertOptions {
|
||||
overwriteAfter: number;
|
||||
adjustWhitespace: boolean;
|
||||
clipboardText: string | undefined;
|
||||
overtypingCapturer: OvertypingCapturer | undefined;
|
||||
}
|
||||
|
||||
const _defaultOptions: ISnippetSessionInsertOptions = {
|
||||
overwriteBefore: 0,
|
||||
overwriteAfter: 0,
|
||||
adjustWhitespace: true,
|
||||
clipboardText: undefined
|
||||
clipboardText: undefined,
|
||||
overtypingCapturer: undefined
|
||||
};
|
||||
|
||||
export class SnippetSession {
|
||||
@@ -382,7 +385,7 @@ export class SnippetSession {
|
||||
return selection;
|
||||
}
|
||||
|
||||
static createEditsAndSnippets(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean, clipboardText: string | undefined): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } {
|
||||
static createEditsAndSnippets(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean, clipboardText: string | undefined, overtypingCapturer: OvertypingCapturer | undefined): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } {
|
||||
const edits: IIdentifiedSingleEditOperation[] = [];
|
||||
const snippets: OneSnippet[] = [];
|
||||
|
||||
@@ -449,7 +452,7 @@ export class SnippetSession {
|
||||
snippet.resolveVariables(new CompositeSnippetVariableResolver([
|
||||
modelBasedVariableResolver,
|
||||
new ClipboardBasedVariableResolver(readClipboardText, idx, indexedSelections.length, editor.getOption(EditorOption.multiCursorPaste) === 'spread'),
|
||||
new SelectionBasedVariableResolver(model, selection),
|
||||
new SelectionBasedVariableResolver(model, selection, idx, overtypingCapturer),
|
||||
new CommentBasedVariableResolver(model, selection),
|
||||
new TimeBasedVariableResolver,
|
||||
new WorkspaceBasedVariableResolver(workspaceService),
|
||||
@@ -496,7 +499,7 @@ export class SnippetSession {
|
||||
}
|
||||
|
||||
// make insert edit and start with first selections
|
||||
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._options.overwriteBefore, this._options.overwriteAfter, false, this._options.adjustWhitespace, this._options.clipboardText);
|
||||
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._options.overwriteBefore, this._options.overwriteAfter, false, this._options.adjustWhitespace, this._options.clipboardText, this._options.overtypingCapturer);
|
||||
this._snippets = snippets;
|
||||
|
||||
this._editor.executeEdits('snippet', edits, undoEdits => {
|
||||
@@ -516,7 +519,7 @@ export class SnippetSession {
|
||||
return;
|
||||
}
|
||||
this._templateMerges.push([this._snippets[0]._nestingLevel, this._snippets[0]._placeholderGroupsIdx, template]);
|
||||
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, options.overwriteBefore, options.overwriteAfter, true, options.adjustWhitespace, options.clipboardText);
|
||||
const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, options.overwriteBefore, options.overwriteAfter, true, options.adjustWhitespace, options.clipboardText, options.overtypingCapturer);
|
||||
|
||||
this._editor.executeEdits('snippet', edits, undoEdits => {
|
||||
for (const snippet of this._snippets) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier, WORKSPACE_EXT
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { OvertypingCapturer } from 'vs/editor/contrib/suggest/suggestOvertypingCapturer';
|
||||
|
||||
export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze({
|
||||
'CURRENT_YEAR': true,
|
||||
@@ -71,7 +72,9 @@ export class SelectionBasedVariableResolver implements VariableResolver {
|
||||
|
||||
constructor(
|
||||
private readonly _model: ITextModel,
|
||||
private readonly _selection: Selection
|
||||
private readonly _selection: Selection,
|
||||
private readonly _selectionIdx: number,
|
||||
private readonly _overtypingCapturer: OvertypingCapturer | undefined
|
||||
) {
|
||||
//
|
||||
}
|
||||
@@ -82,7 +85,18 @@ export class SelectionBasedVariableResolver implements VariableResolver {
|
||||
|
||||
if (name === 'SELECTION' || name === 'TM_SELECTED_TEXT') {
|
||||
let value = this._model.getValueInRange(this._selection) || undefined;
|
||||
if (value && this._selection.startLineNumber !== this._selection.endLineNumber && variable.snippet) {
|
||||
let isMultiline = this._selection.startLineNumber !== this._selection.endLineNumber;
|
||||
|
||||
// If there was no selected text, try to get last overtyped text
|
||||
if (!value && this._overtypingCapturer) {
|
||||
const info = this._overtypingCapturer.getLastOvertypedInfo(this._selectionIdx);
|
||||
if (info) {
|
||||
value = info.value;
|
||||
isMultiline = info.multiline;
|
||||
}
|
||||
}
|
||||
|
||||
if (value && isMultiline && variable.snippet) {
|
||||
// Selection is a multiline string which we indentation we now
|
||||
// need to adjust. We compare the indentation of this variable
|
||||
// with the indentation at the editor position and add potential
|
||||
|
||||
@@ -127,7 +127,7 @@ suite('SnippetSession', function () {
|
||||
test('snippets, newline NO whitespace adjust', () => {
|
||||
|
||||
editor.setSelection(new Selection(2, 5, 2, 5));
|
||||
const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', { overwriteBefore: 0, overwriteAfter: 0, adjustWhitespace: false, clipboardText: undefined });
|
||||
const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', { overwriteBefore: 0, overwriteAfter: 0, adjustWhitespace: false, clipboardText: undefined, overtypingCapturer: undefined });
|
||||
session.insert();
|
||||
assert.equal(editor.getModel()!.getValue(), 'function foo() {\n abc\n foo\n bar\nconsole.log(a);\n}');
|
||||
});
|
||||
@@ -649,7 +649,7 @@ suite('SnippetSession', function () {
|
||||
assert.ok(actual.equalsSelection(new Selection(1, 9, 1, 12)));
|
||||
|
||||
editor.setSelections([new Selection(1, 9, 1, 12)]);
|
||||
new SnippetSession(editor, 'far', { overwriteBefore: 3, overwriteAfter: 0, adjustWhitespace: true, clipboardText: undefined }).insert();
|
||||
new SnippetSession(editor, 'far', { overwriteBefore: 3, overwriteAfter: 0, adjustWhitespace: true, clipboardText: undefined, overtypingCapturer: undefined }).insert();
|
||||
assert.equal(model.getValue(), 'console.far');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ suite('Snippet Variables Resolver', function () {
|
||||
|
||||
resolver = new CompositeSnippetVariableResolver([
|
||||
new ModelBasedVariableResolver(labelService, model),
|
||||
new SelectionBasedVariableResolver(model, new Selection(1, 1, 1, 1)),
|
||||
new SelectionBasedVariableResolver(model, new Selection(1, 1, 1, 1), 0, undefined),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -102,24 +102,24 @@ suite('Snippet Variables Resolver', function () {
|
||||
|
||||
test('editor variables, selection', function () {
|
||||
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(1, 2, 2, 3));
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(1, 2, 2, 3), 0, undefined);
|
||||
assertVariableResolve(resolver, 'TM_SELECTED_TEXT', 'his is line one\nth');
|
||||
assertVariableResolve(resolver, 'TM_CURRENT_LINE', 'this is line two');
|
||||
assertVariableResolve(resolver, 'TM_LINE_INDEX', '1');
|
||||
assertVariableResolve(resolver, 'TM_LINE_NUMBER', '2');
|
||||
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(2, 3, 1, 2));
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(2, 3, 1, 2), 0, undefined);
|
||||
assertVariableResolve(resolver, 'TM_SELECTED_TEXT', 'his is line one\nth');
|
||||
assertVariableResolve(resolver, 'TM_CURRENT_LINE', 'this is line one');
|
||||
assertVariableResolve(resolver, 'TM_LINE_INDEX', '0');
|
||||
assertVariableResolve(resolver, 'TM_LINE_NUMBER', '1');
|
||||
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(1, 2, 1, 2));
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(1, 2, 1, 2), 0, undefined);
|
||||
assertVariableResolve(resolver, 'TM_SELECTED_TEXT', undefined);
|
||||
|
||||
assertVariableResolve(resolver, 'TM_CURRENT_WORD', 'this');
|
||||
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(3, 1, 3, 1));
|
||||
resolver = new SelectionBasedVariableResolver(model, new Selection(3, 1, 3, 1), 0, undefined);
|
||||
assertVariableResolve(resolver, 'TM_CURRENT_WORD', undefined);
|
||||
|
||||
});
|
||||
|
||||
@@ -34,6 +34,7 @@ import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerServ
|
||||
import { IdleValue } from 'vs/base/common/async';
|
||||
import { isObject, assertType } from 'vs/base/common/types';
|
||||
import { CommitCharacterController } from './suggestCommitCharacters';
|
||||
import { OvertypingCapturer } from './suggestOvertypingCapturer';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
@@ -112,6 +113,7 @@ export class SuggestController implements IEditorContribution {
|
||||
private readonly _alternatives: IdleValue<SuggestAlternatives>;
|
||||
private readonly _lineSuffix = new MutableDisposable<LineSuffix>();
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private readonly _overtypingCapturer: IdleValue<OvertypingCapturer>;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@@ -203,6 +205,11 @@ export class SuggestController implements IEditorContribution {
|
||||
return widget;
|
||||
}));
|
||||
|
||||
// Wire up text overtyping capture
|
||||
this._overtypingCapturer = this._toDispose.add(new IdleValue(() => {
|
||||
return this._toDispose.add(new OvertypingCapturer(this.editor, this.model));
|
||||
}));
|
||||
|
||||
this._alternatives = this._toDispose.add(new IdleValue(() => {
|
||||
return this._toDispose.add(new SuggestAlternatives(this.editor, this._contextKeyService));
|
||||
}));
|
||||
@@ -361,7 +368,8 @@ export class SuggestController implements IEditorContribution {
|
||||
undoStopBefore: false,
|
||||
undoStopAfter: false,
|
||||
adjustWhitespace: !(item.completion.insertTextRules! & CompletionItemInsertTextRule.KeepWhitespace),
|
||||
clipboardText: event.model.clipboardText
|
||||
clipboardText: event.model.clipboardText,
|
||||
overtypingCapturer: this._overtypingCapturer.value
|
||||
});
|
||||
|
||||
if (!(flags & InsertFlags.NoAfterUndoStop)) {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { SuggestModel } from 'vs/editor/contrib/suggest/suggestModel';
|
||||
|
||||
export class OvertypingCapturer implements IDisposable {
|
||||
|
||||
private static readonly _maxSelectionLength = 51200;
|
||||
private readonly _disposables = new DisposableStore();
|
||||
|
||||
private _lastOvertyped: { value: string; multiline: boolean }[] = [];
|
||||
private _empty: boolean = true;
|
||||
|
||||
constructor(editor: ICodeEditor, suggestModel: SuggestModel) {
|
||||
|
||||
this._disposables.add(editor.onWillType(() => {
|
||||
if (!this._empty) {
|
||||
return;
|
||||
}
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selections = editor.getSelections();
|
||||
const selectionsLength = selections.length;
|
||||
|
||||
// Check if it will overtype any selections
|
||||
let willOvertype = false;
|
||||
for (let i = 0; i < selectionsLength; i++) {
|
||||
if (!selections[i].isEmpty()) {
|
||||
willOvertype = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!willOvertype) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._lastOvertyped = [];
|
||||
const model = editor.getModel();
|
||||
for (let i = 0; i < selectionsLength; i++) {
|
||||
const selection = selections[i];
|
||||
// Check for overtyping capturer restrictions
|
||||
if (model.getValueLengthInRange(selection) > OvertypingCapturer._maxSelectionLength) {
|
||||
return;
|
||||
}
|
||||
this._lastOvertyped[i] = { value: model.getValueInRange(selection), multiline: selection.startLineNumber !== selection.endLineNumber };
|
||||
}
|
||||
this._empty = false;
|
||||
}));
|
||||
|
||||
this._disposables.add(suggestModel.onDidCancel(e => {
|
||||
if (!this._empty) {
|
||||
this._empty = true;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
getLastOvertypedInfo(idx: number): { value: string; multiline: boolean } | undefined {
|
||||
if (!this._empty && idx >= 0 && idx < this._lastOvertyped.length) {
|
||||
return this._lastOvertyped[idx];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._disposables.dispose();
|
||||
}
|
||||
}
|
||||
@@ -101,13 +101,7 @@ export class CursorWordStartLeft extends WordLeftCommand {
|
||||
inSelectionMode: false,
|
||||
wordNavigationType: WordNavigationType.WordStart,
|
||||
id: 'cursorWordStartLeft',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.LeftArrow,
|
||||
mac: { primary: KeyMod.Alt | KeyCode.LeftArrow },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
precondition: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -129,7 +123,13 @@ export class CursorWordLeft extends WordLeftCommand {
|
||||
inSelectionMode: false,
|
||||
wordNavigationType: WordNavigationType.WordStartFast,
|
||||
id: 'cursorWordLeft',
|
||||
precondition: undefined
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.LeftArrow,
|
||||
mac: { primary: KeyMod.Alt | KeyCode.LeftArrow },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -140,13 +140,7 @@ export class CursorWordStartLeftSelect extends WordLeftCommand {
|
||||
inSelectionMode: true,
|
||||
wordNavigationType: WordNavigationType.WordStart,
|
||||
id: 'cursorWordStartLeftSelect',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow,
|
||||
mac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
precondition: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -168,7 +162,13 @@ export class CursorWordLeftSelect extends WordLeftCommand {
|
||||
inSelectionMode: true,
|
||||
wordNavigationType: WordNavigationType.WordStartFast,
|
||||
id: 'cursorWordLeftSelect',
|
||||
precondition: undefined
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow,
|
||||
mac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./inspectTokens';
|
||||
import { $, append, reset } from 'vs/base/browser/dom';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
@@ -115,23 +115,11 @@ function renderTokenText(tokenText: string): string {
|
||||
let charCode = tokenText.charCodeAt(charIndex);
|
||||
switch (charCode) {
|
||||
case CharCode.Tab:
|
||||
result += '→';
|
||||
result += '\u2192'; // →
|
||||
break;
|
||||
|
||||
case CharCode.Space:
|
||||
result += '·';
|
||||
break;
|
||||
|
||||
case CharCode.LessThan:
|
||||
result += '<';
|
||||
break;
|
||||
|
||||
case CharCode.GreaterThan:
|
||||
result += '>';
|
||||
break;
|
||||
|
||||
case CharCode.Ampersand:
|
||||
result += '&';
|
||||
result += '\u00B7'; // ·
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -211,8 +199,6 @@ class InspectTokensWidget extends Disposable implements IContentWidget {
|
||||
}
|
||||
}
|
||||
|
||||
let result = '';
|
||||
|
||||
let lineContent = this._model.getLineContent(position.lineNumber);
|
||||
let tokenText = '';
|
||||
if (token1Index < data.tokens1.length) {
|
||||
@@ -220,26 +206,43 @@ class InspectTokensWidget extends Disposable implements IContentWidget {
|
||||
let tokenEndIndex = token1Index + 1 < data.tokens1.length ? data.tokens1[token1Index + 1].offset : lineContent.length;
|
||||
tokenText = lineContent.substring(tokenStartIndex, tokenEndIndex);
|
||||
}
|
||||
result += `<h2 class="tm-token">${renderTokenText(tokenText)}<span class="tm-token-length">(${tokenText.length} ${tokenText.length === 1 ? 'char' : 'chars'})</span></h2>`;
|
||||
reset(this._domNode,
|
||||
$('h2.tm-token', undefined, renderTokenText(tokenText),
|
||||
$('span.tm-token-length', undefined, `${tokenText.length} ${tokenText.length === 1 ? 'char' : 'chars'}`)));
|
||||
|
||||
result += `<hr class="tokens-inspect-separator" style="clear:both"/>`;
|
||||
append(this._domNode, $('hr.tokens-inspect-separator', { 'style': 'clear:both' }));
|
||||
|
||||
let metadata = (token2Index << 1) + 1 < data.tokens2.length ? this._decodeMetadata(data.tokens2[(token2Index << 1) + 1]) : null;
|
||||
result += `<table class="tm-metadata-table"><tbody>`;
|
||||
result += `<tr><td class="tm-metadata-key">language</td><td class="tm-metadata-value">${metadata ? escape(metadata.languageIdentifier.language) : '-?-'}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">token type</td><td class="tm-metadata-value">${metadata ? this._tokenTypeToString(metadata.tokenType) : '-?-'}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">font style</td><td class="tm-metadata-value">${metadata ? this._fontStyleToString(metadata.fontStyle) : '-?-'}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">foreground</td><td class="tm-metadata-value">${metadata ? Color.Format.CSS.formatHex(metadata.foreground) : '-?-'}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">background</td><td class="tm-metadata-value">${metadata ? Color.Format.CSS.formatHex(metadata.background) : '-?-'}</td>`;
|
||||
result += `</tbody></table>`;
|
||||
|
||||
result += `<hr class="tokens-inspect-separator"/>`;
|
||||
const metadata = (token2Index << 1) + 1 < data.tokens2.length ? this._decodeMetadata(data.tokens2[(token2Index << 1) + 1]) : null;
|
||||
append(this._domNode, $('table.tm-metadata-table', undefined,
|
||||
$('tbody', undefined,
|
||||
$('tr', undefined,
|
||||
$('td.tm-metadata-key', undefined, 'language'),
|
||||
$('td.tm-metadata-value', undefined, `${metadata ? metadata.languageIdentifier.language : '-?-'}`)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td.tm-metadata-key', undefined, 'token type' as string),
|
||||
$('td.tm-metadata-value', undefined, `${metadata ? this._tokenTypeToString(metadata.tokenType) : '-?-'}`)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td.tm-metadata-key', undefined, 'font style' as string),
|
||||
$('td.tm-metadata-value', undefined, `${metadata ? this._fontStyleToString(metadata.fontStyle) : '-?-'}`)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td.tm-metadata-key', undefined, 'foreground'),
|
||||
$('td.tm-metadata-value', undefined, `${metadata ? Color.Format.CSS.formatHex(metadata.foreground) : '-?-'}`)
|
||||
),
|
||||
$('tr', undefined,
|
||||
$('td.tm-metadata-key', undefined, 'background'),
|
||||
$('td.tm-metadata-value', undefined, `${metadata ? Color.Format.CSS.formatHex(metadata.background) : '-?-'}`)
|
||||
)
|
||||
)
|
||||
));
|
||||
append(this._domNode, $('hr.tokens-inspect-separator'));
|
||||
|
||||
if (token1Index < data.tokens1.length) {
|
||||
result += `<span class="tm-token-type">${escape(data.tokens1[token1Index].type)}</span>`;
|
||||
append(this._domNode, $('span.tm-token-type', undefined, data.tokens1[token1Index].type));
|
||||
}
|
||||
|
||||
this._domNode.innerHTML = result;
|
||||
this._editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,13 @@ import { OS, isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditor, IDiffEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IBulkEditOptions, IBulkEditResult, IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IBulkEditOptions, IBulkEditResult, IBulkEditService, ResourceEdit, ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { isDiffEditorConfigurationKey, isEditorConfigurationKey } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { IPosition, Position as Pos } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IEditor } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel, ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { TextEdit, WorkspaceEdit, WorkspaceTextEdit } from 'vs/editor/common/modes';
|
||||
import { IIdentifiedSingleEditOperation, ITextModel, ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IResolvedTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { ITextResourceConfigurationService, ITextResourcePropertiesService, ITextResourceConfigurationChangeEvent } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
@@ -47,6 +46,7 @@ import { SimpleServicesNLS } from 'vs/editor/common/standaloneStrings';
|
||||
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
export class SimpleModel implements IResolvedTextEditorModel {
|
||||
|
||||
@@ -78,10 +78,17 @@ export class SimpleModel implements IResolvedTextEditorModel {
|
||||
return false;
|
||||
}
|
||||
|
||||
private disposed = false;
|
||||
public dispose(): void {
|
||||
this.disposed = true;
|
||||
|
||||
this._onDispose.fire();
|
||||
}
|
||||
|
||||
public isDisposed(): boolean {
|
||||
return this.disposed;
|
||||
}
|
||||
|
||||
public isResolved(): boolean {
|
||||
return true;
|
||||
}
|
||||
@@ -293,7 +300,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
|
||||
notificationService: INotificationService,
|
||||
domNode: HTMLElement
|
||||
) {
|
||||
super(contextKeyService, commandService, telemetryService, notificationService);
|
||||
super(contextKeyService, commandService, telemetryService, notificationService, new NullLogService());
|
||||
|
||||
this._cachedResolver = null;
|
||||
this._dynamicKeybindings = [];
|
||||
@@ -319,7 +326,8 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
|
||||
command: commandId,
|
||||
when: when,
|
||||
weight1: 1000,
|
||||
weight2: 0
|
||||
weight2: 0,
|
||||
extensionId: null
|
||||
});
|
||||
|
||||
toDispose.add(toDisposable(() => {
|
||||
@@ -350,7 +358,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
|
||||
if (!this._cachedResolver) {
|
||||
const defaults = this._toNormalizedKeybindingItems(KeybindingsRegistry.getDefaultKeybindings(), true);
|
||||
const overrides = this._toNormalizedKeybindingItems(this._dynamicKeybindings, false);
|
||||
this._cachedResolver = new KeybindingResolver(defaults, overrides);
|
||||
this._cachedResolver = new KeybindingResolver(defaults, overrides, (str) => this._log(str));
|
||||
}
|
||||
return this._cachedResolver;
|
||||
}
|
||||
@@ -367,11 +375,11 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
|
||||
|
||||
if (!keybinding) {
|
||||
// This might be a removal keybinding item in user settings => accept it
|
||||
result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault);
|
||||
result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault, null);
|
||||
} else {
|
||||
const resolvedKeybindings = this.resolveKeybinding(keybinding);
|
||||
for (const resolvedKeybinding of resolvedKeybindings) {
|
||||
result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybinding, item.command, item.commandArgs, when, isDefault);
|
||||
result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybinding, item.command, item.commandArgs, when, isDefault, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -665,42 +673,43 @@ export class SimpleBulkEditService implements IBulkEditService {
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
apply(workspaceEdit: WorkspaceEdit, options?: IBulkEditOptions): Promise<IBulkEditResult> {
|
||||
async apply(edits: ResourceEdit[], _options?: IBulkEditOptions): Promise<IBulkEditResult> {
|
||||
|
||||
let edits = new Map<ITextModel, TextEdit[]>();
|
||||
const textEdits = new Map<ITextModel, IIdentifiedSingleEditOperation[]>();
|
||||
|
||||
if (workspaceEdit.edits) {
|
||||
for (let edit of workspaceEdit.edits) {
|
||||
if (!WorkspaceTextEdit.is(edit)) {
|
||||
return Promise.reject(new Error('bad edit - only text edits are supported'));
|
||||
}
|
||||
let model = this._modelService.getModel(edit.resource);
|
||||
if (!model) {
|
||||
return Promise.reject(new Error('bad edit - model not found'));
|
||||
}
|
||||
let array = edits.get(model);
|
||||
if (!array) {
|
||||
array = [];
|
||||
edits.set(model, array);
|
||||
}
|
||||
array.push(edit.edit);
|
||||
for (let edit of edits) {
|
||||
if (!(edit instanceof ResourceTextEdit)) {
|
||||
throw new Error('bad edit - only text edits are supported');
|
||||
}
|
||||
const model = this._modelService.getModel(edit.resource);
|
||||
if (!model) {
|
||||
throw new Error('bad edit - model not found');
|
||||
}
|
||||
if (typeof edit.versionId === 'number' && model.getVersionId() !== edit.versionId) {
|
||||
throw new Error('bad state - model changed in the meantime');
|
||||
}
|
||||
let array = textEdits.get(model);
|
||||
if (!array) {
|
||||
array = [];
|
||||
textEdits.set(model, array);
|
||||
}
|
||||
array.push(EditOperation.replaceMove(Range.lift(edit.textEdit.range), edit.textEdit.text));
|
||||
}
|
||||
|
||||
|
||||
let totalEdits = 0;
|
||||
let totalFiles = 0;
|
||||
edits.forEach((edits, model) => {
|
||||
for (const [model, edits] of textEdits) {
|
||||
model.pushStackElement();
|
||||
model.pushEditOperations([], edits.map((e) => EditOperation.replaceMove(Range.lift(e.range), e.text)), () => []);
|
||||
model.pushEditOperations([], edits, () => []);
|
||||
model.pushStackElement();
|
||||
totalFiles += 1;
|
||||
totalEdits += edits.length;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
selection: undefined,
|
||||
return {
|
||||
ariaSummary: strings.format(SimpleServicesNLS.bulkEditServiceSummary, totalEdits, totalFiles)
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -869,7 +869,7 @@ suite('viewLineRenderer.renderLine', () => {
|
||||
|
||||
suite('viewLineRenderer.renderLine 2', () => {
|
||||
|
||||
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', selections: LineRange[] | null, expected: string): void {
|
||||
function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all', selections: LineRange[] | null, expected: string): void {
|
||||
let actual = renderViewLine(new RenderLineInput(
|
||||
fontIsMonospace,
|
||||
true,
|
||||
@@ -1355,6 +1355,95 @@ suite('viewLineRenderer.renderLine 2', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('createLineParts render whitespace for trailing with leading, inner, and without trailing whitespace', () => {
|
||||
testCreateLineParts(
|
||||
false,
|
||||
' Hello world!',
|
||||
[
|
||||
createPart(4, 0),
|
||||
createPart(6, 1),
|
||||
createPart(14, 2)
|
||||
],
|
||||
0,
|
||||
'trailing',
|
||||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="mtk0">\u00a0Hel</span>',
|
||||
'<span class="mtk1">lo</span>',
|
||||
'<span class="mtk2">\u00a0world!</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
});
|
||||
|
||||
test('createLineParts render whitespace for trailing with leading, inner, and trailing whitespace', () => {
|
||||
testCreateLineParts(
|
||||
false,
|
||||
' Hello world! \t',
|
||||
[
|
||||
createPart(4, 0),
|
||||
createPart(6, 1),
|
||||
createPart(15, 2)
|
||||
],
|
||||
0,
|
||||
'trailing',
|
||||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="mtk0">\u00a0Hel</span>',
|
||||
'<span class="mtk1">lo</span>',
|
||||
'<span class="mtk2">\u00a0world!</span>',
|
||||
'<span class="mtkz" style="width:30px">\u00b7\u2192\u00a0</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
});
|
||||
|
||||
test('createLineParts render whitespace for trailing with 8 leading and 8 trailing whitespaces', () => {
|
||||
testCreateLineParts(
|
||||
false,
|
||||
' Hello world! ',
|
||||
[
|
||||
createPart(8, 1),
|
||||
createPart(10, 2),
|
||||
createPart(28, 3)
|
||||
],
|
||||
0,
|
||||
'trailing',
|
||||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="mtk1">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="mtk2">He</span>',
|
||||
'<span class="mtk3">llo\u00a0world!</span>',
|
||||
'<span class="mtkz" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="mtkz" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
});
|
||||
|
||||
test('createLineParts render whitespace for trailing with line containing only whitespaces', () => {
|
||||
testCreateLineParts(
|
||||
false,
|
||||
' \t ',
|
||||
[
|
||||
createPart(2, 0),
|
||||
createPart(3, 1),
|
||||
],
|
||||
0,
|
||||
'trailing',
|
||||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="mtkz" style="width:40px">\u00b7\u2192\u00a0\u00a0</span>',
|
||||
'<span class="mtkz" style="width:10px">\u00b7</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
});
|
||||
|
||||
test('createLineParts can handle unsorted inline decorations', () => {
|
||||
let actual = renderViewLine(new RenderLineInput(
|
||||
false,
|
||||
|
||||
Vendored
+10
-2
@@ -3068,7 +3068,7 @@ declare namespace monaco.editor {
|
||||
* Enable rendering of whitespace.
|
||||
* Defaults to none.
|
||||
*/
|
||||
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all';
|
||||
renderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';
|
||||
/**
|
||||
* Enable rendering of control characters.
|
||||
* Defaults to false.
|
||||
@@ -4056,7 +4056,7 @@ declare namespace monaco.editor {
|
||||
renderLineHighlight: IEditorOption<EditorOption.renderLineHighlight, 'all' | 'line' | 'none' | 'gutter'>;
|
||||
renderLineHighlightOnlyWhenFocus: IEditorOption<EditorOption.renderLineHighlightOnlyWhenFocus, boolean>;
|
||||
renderValidationDecorations: IEditorOption<EditorOption.renderValidationDecorations, 'on' | 'off' | 'editable'>;
|
||||
renderWhitespace: IEditorOption<EditorOption.renderWhitespace, 'all' | 'none' | 'boundary' | 'selection'>;
|
||||
renderWhitespace: IEditorOption<EditorOption.renderWhitespace, 'all' | 'none' | 'boundary' | 'selection' | 'trailing'>;
|
||||
revealHorizontalRightPadding: IEditorOption<EditorOption.revealHorizontalRightPadding, number>;
|
||||
roundedSelection: IEditorOption<EditorOption.roundedSelection, boolean>;
|
||||
rulers: IEditorOption<EditorOption.rulers, {}>;
|
||||
@@ -4418,6 +4418,14 @@ declare namespace monaco.editor {
|
||||
overflowWidgetsDomNode?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface IDiffEditorConstructionOptions extends IDiffEditorOptions {
|
||||
/**
|
||||
* Place overflow widgets inside an external DOM node.
|
||||
* Defaults to an internal DOM node.
|
||||
*/
|
||||
overflowWidgetsDomNode?: HTMLElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* A rich code editor.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user