mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-06-22 19:25:09 -04:00
Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463 (#7206)
* Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463 * fix config changes * fix strictnull checks
This commit is contained in:
@@ -92,9 +92,9 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
enableFindWidget: false,
|
||||
extension: { id: extensionId, location: URI.revive(extensionLocation) }
|
||||
}, {
|
||||
allowScripts: options.enableScripts,
|
||||
localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined
|
||||
});
|
||||
allowScripts: options.enableScripts,
|
||||
localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined
|
||||
});
|
||||
|
||||
const webviewZone = new EditorWebviewZone(editor, line, height, webview);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadCommands)
|
||||
export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
@@ -19,6 +20,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostCommands);
|
||||
|
||||
@@ -70,10 +72,14 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
}
|
||||
}
|
||||
|
||||
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined> {
|
||||
async $executeCommand<T>(id: string, args: any[], retry: boolean): Promise<T | undefined> {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = revive(args[i], 0);
|
||||
}
|
||||
if (retry && args.length > 0 && !CommandsRegistry.getCommand(id)) {
|
||||
await this._extensionService.activateByEvent(`onCommand:${id}`);
|
||||
throw new Error('$executeCommand:retry');
|
||||
}
|
||||
return this._commandService.executeCommand<T>(id, ...args);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
|
||||
private readonly _proxy: ExtHostDebugServiceShape;
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private _breakpointEventsActive: boolean;
|
||||
private _breakpointEventsActive: boolean | undefined;
|
||||
private readonly _debugAdapters: Map<number, ExtensionHostDebugAdapter>;
|
||||
private _debugAdaptersHandleCounter = 1;
|
||||
private readonly _debugConfigurationProviders: Map<number, IDebugConfigurationProvider>;
|
||||
@@ -35,6 +35,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
|
||||
this._toDispose.add(debugService.onDidNewSession(session => {
|
||||
this._proxy.$acceptDebugSessionStarted(this.getSessionDto(session));
|
||||
this._toDispose.add(session.onDidChangeName(name => {
|
||||
this._proxy.$acceptDebugSessionNameChanged(this.getSessionDto(session), name);
|
||||
}));
|
||||
}));
|
||||
// Need to start listening early to new session events because a custom event can come while a session is initialising
|
||||
this._toDispose.add(debugService.onWillNewSession(session => {
|
||||
@@ -225,6 +228,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
});
|
||||
}
|
||||
|
||||
public $setDebugSessionName(sessionId: DebugSessionUUID, name: string): void {
|
||||
const session = this.debugService.getModel().getSession(sessionId);
|
||||
if (session) {
|
||||
session.setName(name);
|
||||
}
|
||||
}
|
||||
|
||||
public $customDebugAdapterRequest(sessionId: DebugSessionUUID, request: string, args: any): Promise<any> {
|
||||
const session = this.debugService.getModel().getSession(sessionId, true);
|
||||
if (session) {
|
||||
@@ -351,23 +361,24 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
|
||||
super();
|
||||
}
|
||||
|
||||
public fireError(handle: number, err: Error) {
|
||||
fireError(handle: number, err: Error) {
|
||||
this._onError.fire(err);
|
||||
}
|
||||
|
||||
public fireExit(handle: number, code: number, signal: string) {
|
||||
fireExit(handle: number, code: number, signal: string) {
|
||||
this._onExit.fire(code);
|
||||
}
|
||||
|
||||
public startSession(): Promise<void> {
|
||||
startSession(): Promise<void> {
|
||||
return Promise.resolve(this._proxy.$startDASession(this._handle, this._ds.getSessionDto(this._session)));
|
||||
}
|
||||
|
||||
public sendMessage(message: DebugProtocol.ProtocolMessage): void {
|
||||
sendMessage(message: DebugProtocol.ProtocolMessage): void {
|
||||
this._proxy.$sendDAMessage(this._handle, convertToDAPaths(message, true));
|
||||
}
|
||||
|
||||
public stopSession(): Promise<void> {
|
||||
async stopSession(): Promise<void> {
|
||||
await this.cancelPendingRequests();
|
||||
return Promise.resolve(this._proxy.$stopDASession(this._handle));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,14 +93,13 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
|
||||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
const [weight, bubble, tooltip, letter, themeColor, source] = data;
|
||||
const [weight, bubble, tooltip, letter, themeColor] = data;
|
||||
return <IDecorationData>{
|
||||
weight: weight || 0,
|
||||
bubble: bubble || false,
|
||||
color: themeColor && themeColor.id,
|
||||
tooltip,
|
||||
letter,
|
||||
source,
|
||||
letter
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions';
|
||||
import { RenderLineNumbersType, TextEditorCursorStyle, cursorStyleToString, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
@@ -58,9 +58,10 @@ export class MainThreadTextEditorProperties {
|
||||
let cursorStyle: TextEditorCursorStyle;
|
||||
let lineNumbers: RenderLineNumbersType;
|
||||
if (codeEditor) {
|
||||
const codeEditorOpts = codeEditor.getConfiguration();
|
||||
cursorStyle = codeEditorOpts.viewInfo.cursorStyle;
|
||||
lineNumbers = codeEditorOpts.viewInfo.renderLineNumbers;
|
||||
const options = codeEditor.getOptions();
|
||||
const lineNumbersOpts = options.get(EditorOption.lineNumbers);
|
||||
cursorStyle = options.get(EditorOption.cursorStyle);
|
||||
lineNumbers = lineNumbersOpts.renderType;
|
||||
} else if (previousProperties) {
|
||||
cursorStyle = previousProperties.options.cursorStyle;
|
||||
lineNumbers = previousProperties.options.lineNumbers;
|
||||
|
||||
@@ -15,7 +15,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorOptions, ITextEditorOptions, IResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorOptions, ITextEditorOptions, IResourceInput, EditorActivation } from 'vs/platform/editor/common/editor';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
@@ -118,7 +118,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
const editorOptions: ITextEditorOptions = {
|
||||
preserveFocus: options.preserveFocus,
|
||||
pinned: options.pinned,
|
||||
selection: options.selection
|
||||
selection: options.selection,
|
||||
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
|
||||
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
|
||||
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined
|
||||
};
|
||||
|
||||
const input: IResourceInput = {
|
||||
|
||||
@@ -31,6 +31,10 @@ export class MainThreadKeytar implements MainThreadKeytarShape {
|
||||
return this._credentialsService.findPassword(service);
|
||||
}
|
||||
|
||||
async $findCredentials(service: string): Promise<Array<{ account: string, password: string }>> {
|
||||
return this._credentialsService.findCredentials(service);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
//
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Position as EditorPosition } from 'vs/editor/common/core/position';
|
||||
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto } from '../common/extHost.protocol';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
@@ -19,7 +19,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
@@ -111,7 +111,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
return <modes.ILink>data;
|
||||
}
|
||||
|
||||
private static _reviveCallHierarchyItemDto(data: ICallHierarchyDto | undefined): callh.CallHierarchyItem {
|
||||
private static _reviveCallHierarchyItemDto(data: ICallHierarchyItemDto | undefined): callh.CallHierarchyItem {
|
||||
if (data) {
|
||||
data.uri = URI.revive(data.uri);
|
||||
}
|
||||
@@ -495,21 +495,28 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {
|
||||
this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {
|
||||
provideCallHierarchyItem: (document, position, token) => {
|
||||
return this._proxy.$provideCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto);
|
||||
provideOutgoingCalls: async (model, position, token) => {
|
||||
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, model.uri, position, token);
|
||||
if (!outgoing) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
return outgoing.map(([item, sourceRanges]): callh.OutgoingCall => {
|
||||
return {
|
||||
target: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
|
||||
sourceRanges
|
||||
};
|
||||
});
|
||||
},
|
||||
resolveCallHierarchyItem: (item, direction, token) => {
|
||||
return this._proxy.$resolveCallHierarchyItem(handle, item, direction, token).then(data => {
|
||||
if (data) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const [item, locations] = data[i];
|
||||
data[i] = [
|
||||
MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
|
||||
MainThreadLanguageFeatures._reviveLocationDto(locations)
|
||||
];
|
||||
}
|
||||
}
|
||||
return data as [callh.CallHierarchyItem, modes.Location[]][];
|
||||
provideIncomingCalls: async (model, position, token) => {
|
||||
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, model.uri, position, token);
|
||||
if (!incoming) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
return incoming.map(([item, sourceRanges]): callh.IncomingCall => {
|
||||
return {
|
||||
source: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
|
||||
sourceRanges
|
||||
};
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -97,7 +97,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
|
||||
});
|
||||
}
|
||||
|
||||
private _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number | undefined> {
|
||||
private async _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number | undefined> {
|
||||
let cancelId: number | undefined = undefined;
|
||||
|
||||
const buttons = commands.map((command, index) => {
|
||||
@@ -118,7 +118,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
|
||||
cancelId = buttons.length - 1;
|
||||
}
|
||||
|
||||
return this._dialogService.show(severity, message, buttons, { cancelId })
|
||||
.then(result => result === commands.length ? undefined : commands[result].handle);
|
||||
const { choice } = await this._dialogService.show(severity, message, buttons, { cancelId });
|
||||
return choice === commands.length ? undefined : commands[choice].handle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
|
||||
for (const [start, deleteCount, rawResources] of groupSlices) {
|
||||
const resources = rawResources.map(rawResource => {
|
||||
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] = rawResource;
|
||||
const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource;
|
||||
const icon = icons[0];
|
||||
const iconDark = icons[1] || icon;
|
||||
const decorations = {
|
||||
@@ -206,10 +206,7 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
iconDark: iconDark ? URI.parse(iconDark) : undefined,
|
||||
tooltip,
|
||||
strikeThrough,
|
||||
faded,
|
||||
source,
|
||||
letter,
|
||||
color: color ? color.id : undefined
|
||||
faded
|
||||
};
|
||||
|
||||
return new MainThreadSCMResource(
|
||||
|
||||
@@ -10,7 +10,6 @@ import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
|
||||
import { ICodeActionsOnSaveOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
@@ -31,13 +30,13 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; // {{SQL CARBON EDIT}}
|
||||
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; // {{SQL CARBON EDIT}}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
|
||||
export interface ICodeActionsOnSaveOptions {
|
||||
[kind: string]: boolean;
|
||||
}
|
||||
|
||||
/*
|
||||
* An update participant that ensures any un-tracked changes are synced to the JSON file contents for a
|
||||
@@ -45,7 +44,7 @@ import { INotebookService } from 'sql/workbench/services/notebook/browser/notebo
|
||||
* updates the backing model in-place, this is a backup mechanism to hard-update the file before save in case
|
||||
* some are missed.
|
||||
*/
|
||||
class NotebookUpdateParticipant implements ISaveParticipantParticipant {
|
||||
class NotebookUpdateParticipant implements ISaveParticipantParticipant { // {{SQL CARBON EDIT}} add notebook participant
|
||||
|
||||
constructor(
|
||||
@INotebookService private notebookService: INotebookService
|
||||
@@ -153,16 +152,12 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant {
|
||||
return;
|
||||
}
|
||||
|
||||
let prevSelection: Selection[] = [];
|
||||
const edits = [EditOperation.insert(new Position(lineCount, model.getLineMaxColumn(lineCount)), model.getEOL())];
|
||||
const editor = findEditor(model, this.codeEditorService);
|
||||
if (editor) {
|
||||
prevSelection = editor.getSelections();
|
||||
}
|
||||
|
||||
model.pushEditOperations(prevSelection, [EditOperation.insert(new Position(lineCount, model.getLineMaxColumn(lineCount)), model.getEOL())], edits => prevSelection);
|
||||
|
||||
if (editor) {
|
||||
editor.setSelections(prevSelection);
|
||||
editor.executeEdits('insertFinalNewLine', edits, editor.getSelections());
|
||||
} else {
|
||||
model.pushEditOperations([], edits, () => null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,7 +271,8 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
constructor(
|
||||
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
|
||||
@@ -342,7 +338,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
|
||||
private async applyCodeActions(actionsToRun: readonly CodeAction[]) {
|
||||
for (const action of actionsToRun) {
|
||||
await applyCodeAction(action, this._bulkEditService, this._commandService);
|
||||
await this._instantiationService.invokeFunction(applyCodeAction, action, this._bulkEditService, this._commandService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -626,6 +626,9 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
getDefaultShellAndArgs: (): Promise<{ shell: string, args: string[] | string | undefined }> => {
|
||||
return Promise.resolve(this._proxy.$getDefaultShellAndArgs());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, IShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { ITerminalInstanceService, ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
@@ -21,7 +21,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
private readonly _terminalProcesses = new Map<number, Promise<ITerminalProcessExtHostProxy>>();
|
||||
private readonly _terminalProcessesReady = new Map<number, (proxy: ITerminalProcessExtHostProxy) => void>();
|
||||
private readonly _terminalOnDidWriteDataListeners = new Map<number, IDisposable>();
|
||||
private _dataEventTracker: TerminalDataEventTracker | undefined;
|
||||
|
||||
constructor(
|
||||
@@ -131,30 +130,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public $registerOnDataListener(terminalId: number): void {
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Listener already registered
|
||||
if (this._terminalOnDidWriteDataListeners.has(terminalId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register
|
||||
const listener = terminalInstance.onData(data => {
|
||||
this._onTerminalData(terminalId, data);
|
||||
});
|
||||
this._terminalOnDidWriteDataListeners.set(terminalId, listener);
|
||||
terminalInstance.addDisposable(listener);
|
||||
}
|
||||
|
||||
public $startSendingDataEvents(): void {
|
||||
if (!this._dataEventTracker) {
|
||||
this._dataEventTracker = this._instantiationService.createInstance(TerminalDataEventTracker, (id, data) => {
|
||||
this._onTerminalData2(id, data);
|
||||
this._onTerminalData(id, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -170,15 +149,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._proxy.$acceptActiveTerminalChanged(terminalId);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
private _onTerminalData(terminalId: number, data: string): void {
|
||||
this._proxy.$acceptTerminalProcessData(terminalId, data);
|
||||
}
|
||||
|
||||
private _onTerminalData2(terminalId: number, data: string): void {
|
||||
this._proxy.$acceptTerminalProcessData2(terminalId, data);
|
||||
}
|
||||
|
||||
private _onTitleChanged(terminalId: number, name: string): void {
|
||||
this._proxy.$acceptTerminalTitleChange(terminalId, name);
|
||||
}
|
||||
|
||||
@@ -35,9 +35,11 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
this._dataProviders.set(treeViewId, dataProvider);
|
||||
const viewer = this.getTreeView(treeViewId);
|
||||
if (viewer) {
|
||||
viewer.dataProvider = dataProvider;
|
||||
// Order is important here. The internal tree isn't created until the dataProvider is set.
|
||||
// Set all other properties first!
|
||||
viewer.showCollapseAllAction = !!options.showCollapseAll;
|
||||
viewer.canSelectMany = !!options.canSelectMany;
|
||||
viewer.dataProvider = dataProvider;
|
||||
this.registerListeners(treeViewId, viewer);
|
||||
this._proxy.$setVisible(treeViewId, viewer.visible);
|
||||
} else {
|
||||
@@ -74,6 +76,13 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
}
|
||||
}
|
||||
|
||||
$setTitle(treeViewId: string, title: string): void {
|
||||
const viewer = this.getTreeView(treeViewId);
|
||||
if (viewer) {
|
||||
viewer.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, itemIn: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void> {
|
||||
options = options ? options : { select: false, focus: false };
|
||||
const select = isUndefinedOrNull(options.select) ? false : options.select;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
|
||||
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/extensionUrlHandler';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
class ExtensionUrlHandler implements IURLHandler {
|
||||
@@ -37,7 +37,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IURLService private readonly urlService: IURLService,
|
||||
@IExtensionUrlHandler private readonly inactiveExtensionUrlHandler: IExtensionUrlHandler
|
||||
@IExtensionUrlHandler private readonly extensionUrlHandler: IExtensionUrlHandler
|
||||
) {
|
||||
this.proxy = context.getProxy(ExtHostContext.ExtHostUrls);
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
|
||||
const disposable = this.urlService.registerHandler(handler);
|
||||
|
||||
this.handlers.set(handle, { extensionId, disposable });
|
||||
this.inactiveExtensionUrlHandler.registerExtensionHandler(extensionId, handler);
|
||||
this.extensionUrlHandler.registerExtensionHandler(extensionId, handler);
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -61,7 +61,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
|
||||
|
||||
const { extensionId, disposable } = tuple;
|
||||
|
||||
this.inactiveExtensionUrlHandler.unregisterExtensionHandler(extensionId);
|
||||
this.extensionUrlHandler.unregisterExtensionHandler(extensionId);
|
||||
this.handlers.delete(handle);
|
||||
disposable.dispose();
|
||||
|
||||
|
||||
@@ -16,18 +16,13 @@ import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions, WebviewPanelViewStateData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewEditorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
|
||||
interface OldMainThreadWebviewState {
|
||||
readonly viewType: string;
|
||||
state: any;
|
||||
}
|
||||
import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
|
||||
|
||||
/**
|
||||
* Bi-directional map between webview handles and inputs.
|
||||
@@ -78,6 +73,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
private readonly _proxy: ExtHostWebviewsShape;
|
||||
private readonly _webviewEditorInputs = new WebviewHandleStore();
|
||||
private readonly _revivers = new Map<string, IDisposable>();
|
||||
private readonly _editorProviders = new Map<string, IDisposable>();
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@@ -95,11 +91,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
this._register(_editorService.onDidActiveEditorChange(this.updateWebviewViewStates, this));
|
||||
this._register(_editorService.onDidVisibleEditorsChange(this.updateWebviewViewStates, this));
|
||||
|
||||
// This reviver's only job is to activate webview extensions
|
||||
// This reviver's only job is to activate webview panel extensions
|
||||
// This should trigger the real reviver to be registered from the extension host side.
|
||||
this._register(_webviewEditorService.registerReviver({
|
||||
canRevive: (webview: WebviewEditorInput) => {
|
||||
if (!webview.webview.state) {
|
||||
this._register(_webviewEditorService.registerResolver({
|
||||
canResolve: (webview: WebviewEditorInput) => {
|
||||
if (!webview.webview.state && webview.getTypeId() === WebviewEditorInput.typeId) { // TODO: The typeid check is a workaround for the CustomFileEditorInput case
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,7 +105,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
}
|
||||
return false;
|
||||
},
|
||||
reviveWebview: () => { throw new Error('not implemented'); }
|
||||
resolveWebview: () => { throw new Error('not implemented'); }
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -154,19 +150,26 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
webview.setName(value);
|
||||
}
|
||||
|
||||
public $setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void {
|
||||
const webview = this.getWebviewEditorInput(handle);
|
||||
if (webview instanceof CustomFileEditorInput) {
|
||||
webview.setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
public $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void {
|
||||
const webview = this.getWebviewEditorInput(handle);
|
||||
webview.iconPath = reviveWebviewIcon(value);
|
||||
}
|
||||
|
||||
public $setHtml(handle: WebviewPanelHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.html = value;
|
||||
const webview = this.getWebviewEditorInput(handle);
|
||||
webview.webview.html = value;
|
||||
}
|
||||
|
||||
public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */);
|
||||
const webview = this.getWebviewEditorInput(handle);
|
||||
webview.webview.contentOptions = reviveWebviewOptions(options as any /*todo@mat */);
|
||||
}
|
||||
|
||||
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
|
||||
@@ -182,8 +185,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
}
|
||||
|
||||
public async $postMessage(handle: WebviewPanelHandle, message: any): Promise<boolean> {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.sendMessage(message);
|
||||
const webview = this.getWebviewEditorInput(handle);
|
||||
webview.webview.sendMessage(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -192,11 +195,11 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
throw new Error(`Reviver for ${viewType} already registered`);
|
||||
}
|
||||
|
||||
this._revivers.set(viewType, this._webviewEditorService.registerReviver({
|
||||
canRevive: (webviewEditorInput) => {
|
||||
this._revivers.set(viewType, this._webviewEditorService.registerResolver({
|
||||
canResolve: (webviewEditorInput) => {
|
||||
return !!webviewEditorInput.webview.state && webviewEditorInput.viewType === this.getInternalWebviewViewType(viewType);
|
||||
},
|
||||
reviveWebview: async (webviewEditorInput): Promise<void> => {
|
||||
resolveWebview: async (webviewEditorInput): Promise<void> => {
|
||||
const viewType = this.fromInternalWebviewViewType(webviewEditorInput.viewType);
|
||||
if (!viewType) {
|
||||
webviewEditorInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewEditorInput.viewType);
|
||||
@@ -210,16 +213,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
let state = undefined;
|
||||
if (webviewEditorInput.webview.state) {
|
||||
try {
|
||||
// Check for old-style webview state first which stored state inside another state object
|
||||
// TODO: remove this after 1.37 ships.
|
||||
if (
|
||||
typeof (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState).viewType === 'string' &&
|
||||
'state' in (webviewEditorInput.webview.state as unknown as OldMainThreadWebviewState)
|
||||
) {
|
||||
state = JSON.parse((webviewEditorInput.webview.state as any).state);
|
||||
} else {
|
||||
state = JSON.parse(webviewEditorInput.webview.state);
|
||||
}
|
||||
state = JSON.parse(webviewEditorInput.webview.state);
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
@@ -245,6 +239,48 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
this._revivers.delete(viewType);
|
||||
}
|
||||
|
||||
public $registerEditorProvider(viewType: string): void {
|
||||
if (this._editorProviders.has(viewType)) {
|
||||
throw new Error(`Provider for ${viewType} already registered`);
|
||||
}
|
||||
|
||||
this._editorProviders.set(viewType, this._webviewEditorService.registerResolver({
|
||||
canResolve: (webviewEditorInput) => {
|
||||
return webviewEditorInput.getTypeId() !== WebviewEditorInput.typeId && webviewEditorInput.viewType === viewType;
|
||||
},
|
||||
resolveWebview: async (webview) => {
|
||||
const handle = `resolved-${MainThreadWebviews.revivalPool++}`;
|
||||
this._webviewEditorInputs.add(handle, webview);
|
||||
this.hookupWebviewEventDelegate(handle, webview);
|
||||
|
||||
try {
|
||||
await this._proxy.$resolveWebviewEditor(
|
||||
webview.getResource(),
|
||||
handle,
|
||||
viewType,
|
||||
webview.getTitle(),
|
||||
webview.webview.state,
|
||||
editorGroupToViewColumn(this._editorGroupService, webview.group || 0),
|
||||
webview.webview.options
|
||||
);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webview.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public $unregisterEditorProvider(viewType: string): void {
|
||||
const provider = this._editorProviders.get(viewType);
|
||||
if (!provider) {
|
||||
throw new Error(`No provider for ${viewType} registered`);
|
||||
}
|
||||
|
||||
provider.dispose();
|
||||
this._editorProviders.delete(viewType);
|
||||
}
|
||||
|
||||
private getInternalWebviewViewType(viewType: string): string {
|
||||
return `mainThreadWebview-${viewType}`;
|
||||
}
|
||||
@@ -271,6 +307,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
}
|
||||
webview.webview.state = newState;
|
||||
});
|
||||
input.webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value));
|
||||
}
|
||||
|
||||
private updateWebviewViewStates() {
|
||||
@@ -333,10 +370,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
return this._webviewEditorInputs.getInputForHandle(handle);
|
||||
}
|
||||
|
||||
private getWebview(handle: WebviewPanelHandle): Webview {
|
||||
return this.getWebviewEditorInput(handle).webview;
|
||||
}
|
||||
|
||||
private static getDeserializationFailedContents(viewType: string) {
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
@@ -48,7 +48,7 @@ const configurationEntrySchema: IJSONSchema = {
|
||||
nls.localize('scope.resource.description', "Configuration that can be configured in the user, remote, workspace or folder settings."),
|
||||
nls.localize('scope.machine-overridable.description', "Machine configuration that can be configured also in workspace or folder settings.")
|
||||
],
|
||||
description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `application`, `machine`, `window` and `resource`.")
|
||||
description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `application`, `machine`, `window`, `resource` and `machine-overridable`.")
|
||||
},
|
||||
enumDescriptions: {
|
||||
type: 'array',
|
||||
@@ -238,6 +238,7 @@ function validateProperties(configuration: IConfigurationNode, extension: IExten
|
||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||
jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
|
||||
allowComments: true,
|
||||
allowsTrailingCommas: true,
|
||||
default: {
|
||||
folders: [
|
||||
{
|
||||
|
||||
@@ -517,7 +517,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
}
|
||||
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
|
||||
}
|
||||
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
|
||||
return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs);
|
||||
},
|
||||
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
|
||||
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
|
||||
@@ -528,6 +528,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer);
|
||||
},
|
||||
registerWebviewEditorProvider: (viewType: string, provider: vscode.WebviewEditorProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostWebviews.registerWebviewEditorProvider(viewType, provider);
|
||||
},
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostDecorations.registerDecorationProvider(provider, extension.identifier);
|
||||
@@ -838,7 +842,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
DocumentSymbol: extHostTypes.DocumentSymbol,
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
EventEmitter: Emitter,
|
||||
ExtensionExecutionContext: extHostTypes.ExtensionExecutionContext,
|
||||
ExtensionKind: extHostTypes.ExtensionKind,
|
||||
CustomExecution2: extHostTypes.CustomExecution2,
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
@@ -897,8 +900,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
ViewColumn: extHostTypes.ViewColumn,
|
||||
WorkspaceEdit: extHostTypes.WorkspaceEdit,
|
||||
// proposed
|
||||
CallHierarchyDirection: extHostTypes.CallHierarchyDirection,
|
||||
CallHierarchyItem: extHostTypes.CallHierarchyItem
|
||||
CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall,
|
||||
CallHierarchyIncomingCall: extHostTypes.CallHierarchyIncomingCall,
|
||||
CallHierarchyItem: extHostTypes.CallHierarchyItem,
|
||||
Decoration: extHostTypes.Decoration,
|
||||
WebviewEditorState: extHostTypes.WebviewEditorState,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import * as tasks from 'vs/workbench/api/common/shared/tasks';
|
||||
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IAdapterDescriptor, IConfig } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
@@ -120,7 +119,7 @@ export interface MainThreadClipboardShape extends IDisposable {
|
||||
export interface MainThreadCommandsShape extends IDisposable {
|
||||
$registerCommand(id: string): void;
|
||||
$unregisterCommand(id: string): void;
|
||||
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined>;
|
||||
$executeCommand<T>(id: string, args: any[], retry: boolean): Promise<T | undefined>;
|
||||
$getCommands(): Promise<string[]>;
|
||||
}
|
||||
|
||||
@@ -248,6 +247,7 @@ export interface MainThreadTreeViewsShape extends IDisposable {
|
||||
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
|
||||
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void>;
|
||||
$setMessage(treeViewId: string, message: string): void;
|
||||
$setTitle(treeViewId: string, title: string): void;
|
||||
}
|
||||
|
||||
export interface MainThreadDownloadServiceShape extends IDisposable {
|
||||
@@ -267,6 +267,7 @@ export interface MainThreadKeytarShape extends IDisposable {
|
||||
$setPassword(service: string, account: string, password: string): Promise<void>;
|
||||
$deletePassword(service: string, account: string): Promise<boolean>;
|
||||
$findPassword(service: string): Promise<string | null>;
|
||||
$findCredentials(service: string): Promise<Array<{ account: string, password: string }>>;
|
||||
}
|
||||
|
||||
export interface IRegExpDto {
|
||||
@@ -401,8 +402,6 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$hide(terminalId: number): void;
|
||||
$sendText(terminalId: number, text: string, addNewLine: boolean): void;
|
||||
$show(terminalId: number, preserveFocus: boolean): void;
|
||||
/** @deprecated */
|
||||
$registerOnDataListener(terminalId: number): void;
|
||||
$startSendingDataEvents(): void;
|
||||
$stopSendingDataEvents(): void;
|
||||
|
||||
@@ -543,6 +542,7 @@ export interface MainThreadWebviewsShape extends IDisposable {
|
||||
$disposeWebview(handle: WebviewPanelHandle): void;
|
||||
$reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void;
|
||||
$setTitle(handle: WebviewPanelHandle, value: string): void;
|
||||
$setState(handle: WebviewPanelHandle, state: modes.WebviewEditorState): void;
|
||||
$setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void;
|
||||
|
||||
$setHtml(handle: WebviewPanelHandle, value: string): void;
|
||||
@@ -551,6 +551,9 @@ export interface MainThreadWebviewsShape extends IDisposable {
|
||||
|
||||
$registerSerializer(viewType: string): void;
|
||||
$unregisterSerializer(viewType: string): void;
|
||||
|
||||
$registerEditorProvider(viewType: string): void;
|
||||
$unregisterEditorProvider(viewType: string): void;
|
||||
}
|
||||
|
||||
export interface WebviewPanelViewStateData {
|
||||
@@ -563,9 +566,11 @@ export interface WebviewPanelViewStateData {
|
||||
|
||||
export interface ExtHostWebviewsShape {
|
||||
$onMessage(handle: WebviewPanelHandle, message: any): void;
|
||||
$onMissingCsp(handle: WebviewPanelHandle, extensionId: string): void;
|
||||
$onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void;
|
||||
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise<void>;
|
||||
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
|
||||
$resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
@@ -663,11 +668,7 @@ export type SCMRawResource = [
|
||||
string[] /*icons: light, dark*/,
|
||||
string /*tooltip*/,
|
||||
boolean /*strike through*/,
|
||||
boolean /*faded*/,
|
||||
|
||||
string | undefined /*source*/,
|
||||
string | undefined /*letter*/,
|
||||
ThemeColor | null /*color*/
|
||||
boolean /*faded*/
|
||||
];
|
||||
|
||||
export type SCMRawResourceSplice = [
|
||||
@@ -719,6 +720,7 @@ export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
$unregisterDebugConfigurationProvider(handle: number): void;
|
||||
$unregisterDebugAdapterDescriptorFactory(handle: number): void;
|
||||
$startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, parentSessionID: string | undefined): Promise<boolean>;
|
||||
$setDebugSessionName(id: DebugSessionUUID, name: string): void;
|
||||
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise<any>;
|
||||
$appendDebugConsole(value: string): void;
|
||||
$startBreakpointEvents(): void;
|
||||
@@ -1069,8 +1071,7 @@ export interface ICodeLensDto {
|
||||
command?: ICommandDto;
|
||||
}
|
||||
|
||||
export interface ICallHierarchyDto {
|
||||
_id: number;
|
||||
export interface ICallHierarchyItemDto {
|
||||
kind: modes.SymbolKind;
|
||||
name: string;
|
||||
detail?: string;
|
||||
@@ -1113,8 +1114,8 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined>;
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise<modes.FoldingRange[] | undefined>;
|
||||
$provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise<modes.SelectionRange[][]>;
|
||||
$provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ICallHierarchyDto | undefined>;
|
||||
$resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[ICallHierarchyDto, modes.Location[]][]>;
|
||||
$provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
|
||||
$provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
|
||||
}
|
||||
|
||||
export interface ExtHostQuickOpenShape {
|
||||
@@ -1156,9 +1157,7 @@ export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalOpened(id: number, name: string): void;
|
||||
$acceptActiveTerminalChanged(id: number | null): void;
|
||||
$acceptTerminalProcessId(id: number, processId: number): void;
|
||||
/** @deprecated */
|
||||
$acceptTerminalProcessData(id: number, data: string): void;
|
||||
$acceptTerminalProcessData2(id: number, data: string): void;
|
||||
$acceptTerminalTitleChange(id: number, name: string): void;
|
||||
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
||||
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
|
||||
@@ -1191,6 +1190,7 @@ export interface ExtHostTaskShape {
|
||||
$onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void;
|
||||
$OnDidEndTask(execution: tasks.TaskExecutionDTO): void;
|
||||
$resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string }, variables: string[] }): Promise<{ process?: string; variables: { [key: string]: string } }>;
|
||||
$getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined }>;
|
||||
}
|
||||
|
||||
export interface IBreakpointDto {
|
||||
@@ -1266,6 +1266,7 @@ export interface ExtHostDebugServiceShape {
|
||||
$acceptDebugSessionActiveChanged(session: IDebugSessionDto | undefined): void;
|
||||
$acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void;
|
||||
$acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void;
|
||||
$acceptDebugSessionNameChanged(session: IDebugSessionDto, name: string): void;
|
||||
}
|
||||
|
||||
export interface DecorationRequest {
|
||||
@@ -1274,7 +1275,7 @@ export interface DecorationRequest {
|
||||
readonly uri: UriComponents;
|
||||
}
|
||||
|
||||
export type DecorationData = [number, boolean, string, string, ThemeColor, string];
|
||||
export type DecorationData = [number, boolean, string, string, ThemeColor];
|
||||
export type DecorationReply = { [id: number]: DecorationData };
|
||||
|
||||
export interface ExtHostDecorationsShape {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as vscode from 'vscode';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IRawColorInfo, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
@@ -182,6 +182,22 @@ export class ExtHostApiCommands {
|
||||
],
|
||||
returns: 'A promise that resolves to an array of DocumentLink-instances.'
|
||||
});
|
||||
this._register('vscode.executeCallHierarchyProviderIncomingCalls', this._executeCallHierarchyIncomingCallsProvider, {
|
||||
description: 'Execute call hierarchy provider for incoming calls',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
|
||||
],
|
||||
returns: 'A promise that resolves to an array of CallHierarchyIncomingCall-instances.'
|
||||
});
|
||||
this._register('vscode.executeCallHierarchyProviderOutgoingCalls', this._executeCallHierarchyOutgoingCallsProvider, {
|
||||
description: 'Execute call hierarchy provider for outgoing calls',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
|
||||
],
|
||||
returns: 'A promise that resolves to an array of CallHierarchyOutgoingCall-instances.'
|
||||
});
|
||||
this._register('vscode.executeDocumentColorProvider', this._executeDocumentColorProvider, {
|
||||
description: 'Execute document color provider.',
|
||||
args: [
|
||||
@@ -557,6 +573,36 @@ export class ExtHostApiCommands {
|
||||
return this._commands.executeCommand<modes.ILink[]>('_executeLinkProvider', resource)
|
||||
.then(tryMapWith(typeConverters.DocumentLink.to));
|
||||
}
|
||||
|
||||
private async _executeCallHierarchyIncomingCallsProvider(resource: URI, position: types.Position): Promise<vscode.CallHierarchyIncomingCall[]> {
|
||||
type IncomingCallDto = {
|
||||
source: ICallHierarchyItemDto;
|
||||
sourceRanges: IRange[];
|
||||
};
|
||||
const args = { resource, position: typeConverters.Position.from(position) };
|
||||
const calls = await this._commands.executeCommand<IncomingCallDto[]>('_executeCallHierarchyIncomingCalls', args);
|
||||
|
||||
const result: vscode.CallHierarchyIncomingCall[] = [];
|
||||
for (const call of calls) {
|
||||
result.push(new types.CallHierarchyIncomingCall(typeConverters.CallHierarchyItem.to(call.source), <vscode.Range[]>call.sourceRanges.map(typeConverters.Range.to)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async _executeCallHierarchyOutgoingCallsProvider(resource: URI, position: types.Position): Promise<vscode.CallHierarchyOutgoingCall[]> {
|
||||
type OutgoingCallDto = {
|
||||
sourceRanges: IRange[];
|
||||
target: ICallHierarchyItemDto;
|
||||
};
|
||||
const args = { resource, position: typeConverters.Position.from(position) };
|
||||
const calls = await this._commands.executeCommand<OutgoingCallDto[]>('_executeCallHierarchyOutgoingCalls', args);
|
||||
|
||||
const result: vscode.CallHierarchyOutgoingCall[] = [];
|
||||
for (const call of calls) {
|
||||
result.push(new types.CallHierarchyOutgoingCall(typeConverters.CallHierarchyItem.to(call.target), <vscode.Range[]>call.sourceRanges.map(typeConverters.Range.to)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function tryMapWith<T, R>(f: (x: T) => R) {
|
||||
|
||||
@@ -33,7 +33,7 @@ export interface ArgumentProcessor {
|
||||
|
||||
export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _commands = new Map<string, CommandHandler>();
|
||||
private readonly _proxy: MainThreadCommandsShape;
|
||||
@@ -112,6 +112,10 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
|
||||
executeCommand<T>(id: string, ...args: any[]): Promise<T> {
|
||||
this._logService.trace('ExtHostCommands#executeCommand', id);
|
||||
return this._doExecuteCommand(id, args, true);
|
||||
}
|
||||
|
||||
private async _doExecuteCommand<T>(id: string, args: any[], retry: boolean): Promise<T> {
|
||||
|
||||
if (this._commands.has(id)) {
|
||||
// we stay inside the extension host and support
|
||||
@@ -120,8 +124,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
|
||||
} else {
|
||||
// automagically convert some argument types
|
||||
|
||||
args = cloneAndChange(args, function (value) {
|
||||
const toArgs = cloneAndChange(args, function (value) {
|
||||
if (value instanceof extHostTypes.Position) {
|
||||
return extHostTypeConverter.Position.from(value);
|
||||
}
|
||||
@@ -136,7 +139,19 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
}
|
||||
});
|
||||
|
||||
return this._proxy.$executeCommand<T>(id, args).then(result => revive(result, 0));
|
||||
try {
|
||||
const result = await this._proxy.$executeCommand<T>(id, toArgs, retry);
|
||||
return revive(result, 0);
|
||||
} catch (e) {
|
||||
// Rerun the command when it wasn't known, had arguments, and when retry
|
||||
// is enabled. We do this because the command might be registered inside
|
||||
// the extension host now and can therfore accept the arguments as-is.
|
||||
if (e instanceof Error && e.message === '$executeCommand:retry') {
|
||||
return this._doExecuteCommand(id, args, false);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ type ConfigurationInspect<T> = {
|
||||
|
||||
export class ExtHostConfiguration implements ExtHostConfigurationShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _proxy: MainThreadConfigurationShape;
|
||||
private readonly _extHostWorkspace: ExtHostWorkspace;
|
||||
|
||||
@@ -13,7 +13,7 @@ export const IExtHostDebugService = createDecorator<IExtHostDebugService>('IExtH
|
||||
|
||||
export interface IExtHostDebugService extends ExtHostDebugServiceShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
onDidStartDebugSession: Event<vscode.DebugSession>;
|
||||
onDidTerminateDebugSession: Event<vscode.DebugSession>;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { MainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData, DecorationRequest, DecorationReply } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { Disposable, Decoration } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { asArray } from 'vs/base/common/arrays';
|
||||
@@ -59,12 +59,14 @@ export class ExtHostDecorations implements IExtHostDecorations {
|
||||
}
|
||||
const { provider, extensionId } = entry;
|
||||
return Promise.resolve(provider.provideDecoration(URI.revive(uri), token)).then(data => {
|
||||
if (data && data.letter && data.letter.length !== 1) {
|
||||
console.warn(`INVALID decoration from extension '${extensionId.value}'. The 'letter' must be set and be one character, not '${data.letter}'.`);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
if (data) {
|
||||
result[id] = <DecorationData>[data.priority, data.bubble, data.title, data.letter, data.color, data.source];
|
||||
|
||||
try {
|
||||
Decoration.validate(data);
|
||||
result[id] = <DecorationData>[data.priority, data.bubble, data.title, data.letter, data.color];
|
||||
} catch (e) {
|
||||
console.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`);
|
||||
}
|
||||
}, err => {
|
||||
console.error(err);
|
||||
|
||||
@@ -17,7 +17,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private _disposables: Disposable[] = [];
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as vscode from 'vscode';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -11,29 +12,11 @@ import { ExtensionActivationError, MissingDependencyError } from 'vs/workbench/s
|
||||
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
|
||||
export interface IExtensionMemento {
|
||||
get<T>(key: string): T | undefined;
|
||||
get<T>(key: string, defaultValue: T): T;
|
||||
update(key: string, value: any): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IExtensionContext {
|
||||
subscriptions: IDisposable[];
|
||||
workspaceState: IExtensionMemento;
|
||||
globalState: IExtensionMemento;
|
||||
extensionPath: string;
|
||||
storagePath: string;
|
||||
globalStoragePath: string;
|
||||
asAbsolutePath(relativePath: string): string;
|
||||
readonly logPath: string;
|
||||
executionContext: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the source code (module) of an extension.
|
||||
*/
|
||||
export interface IExtensionModule {
|
||||
activate?(ctx: IExtensionContext): Promise<IExtensionAPI>;
|
||||
activate?(ctx: vscode.ExtensionContext): Promise<IExtensionAPI>;
|
||||
deactivate?(): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -25,7 +25,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||
import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ResolvedAuthority, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
@@ -64,7 +64,7 @@ type TelemetryActivationEventFragment = {
|
||||
|
||||
export abstract class AbstractExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
|
||||
|
||||
@@ -331,11 +331,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`);
|
||||
|
||||
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
|
||||
return Promise.all<any>([
|
||||
this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder),
|
||||
return Promise.all([
|
||||
this._loadCommonJSModule<IExtensionModule>(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder),
|
||||
this._loadExtensionContext(extensionDescription)
|
||||
]).then(values => {
|
||||
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
|
||||
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
this._storagePath.whenReady
|
||||
]).then(() => {
|
||||
const that = this;
|
||||
return Object.freeze(<IExtensionContext>{
|
||||
return Object.freeze<vscode.ExtensionContext>({
|
||||
globalState,
|
||||
workspaceState,
|
||||
subscriptions: [],
|
||||
@@ -361,13 +361,12 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
get storagePath() { return that._storagePath.workspaceValue(extensionDescription); },
|
||||
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
|
||||
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
|
||||
executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local,
|
||||
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<ActivatedExtension> {
|
||||
private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<ActivatedExtension> {
|
||||
// Make sure the extension's surface is not undefined
|
||||
extensionModule = extensionModule || {
|
||||
activate: undefined,
|
||||
@@ -379,7 +378,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
});
|
||||
}
|
||||
|
||||
private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<IExtensionAPI> {
|
||||
private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: vscode.ExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<IExtensionAPI> {
|
||||
if (typeof extensionModule.activate === 'function') {
|
||||
try {
|
||||
activationTimesBuilder.activateCallStart();
|
||||
@@ -767,7 +766,7 @@ function getTelemetryActivationEvent(extensionDescription: IExtensionDescription
|
||||
export const IExtHostExtensionService = createDecorator<IExtHostExtensionService>('IExtHostExtensionService');
|
||||
|
||||
export interface IExtHostExtensionService extends AbstractExtHostExtensionService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
initialize(): Promise<void>;
|
||||
isActivated(extensionId: ExtensionIdentifier): boolean;
|
||||
activateByIdWithErrors(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, IRawColorInfo, IMainContext, IdObject, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILanguageConfigurationDto, IWorkspaceSymbolDto, ISuggestResultDto, IWorkspaceSymbolsDto, ICodeActionDto, IDocumentFilterDto, IWorkspaceEditDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICodeLensDto, ISuggestDataDto, ILinksListDto, ChainedCacheId, ICodeLensListDto, ICodeActionListDto, ISignatureHelpDto, ISignatureHelpContextDto } from './extHost.protocol';
|
||||
import * as extHostProtocol from './extHost.protocol';
|
||||
import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
@@ -24,8 +24,6 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
@@ -67,10 +65,10 @@ class DocumentSymbolAdapter {
|
||||
const res: modes.DocumentSymbol[] = [];
|
||||
const parentStack: modes.DocumentSymbol[] = [];
|
||||
for (const info of infos) {
|
||||
const element = <modes.DocumentSymbol>{
|
||||
const element: modes.DocumentSymbol = {
|
||||
name: info.name || '!!MISSING: name!!',
|
||||
kind: typeConvert.SymbolKind.from(info.kind),
|
||||
tags: info.tags && info.tags.map(typeConvert.SymbolTag.from),
|
||||
tags: info.tags ? info.tags.map(typeConvert.SymbolTag.from) : [],
|
||||
detail: '',
|
||||
containerName: info.containerName,
|
||||
range: typeConvert.Range.from(info.location.range),
|
||||
@@ -112,7 +110,7 @@ class CodeLensAdapter {
|
||||
private readonly _provider: vscode.CodeLensProvider
|
||||
) { }
|
||||
|
||||
provideCodeLenses(resource: URI, token: CancellationToken): Promise<ICodeLensListDto | undefined> {
|
||||
provideCodeLenses(resource: URI, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
|
||||
return asPromise(() => this._provider.provideCodeLenses(doc, token)).then(lenses => {
|
||||
@@ -125,7 +123,7 @@ class CodeLensAdapter {
|
||||
const disposables = new DisposableStore();
|
||||
this._disposables.set(cacheId, disposables);
|
||||
|
||||
const result: ICodeLensListDto = {
|
||||
const result: extHostProtocol.ICodeLensListDto = {
|
||||
cacheId,
|
||||
lenses: [],
|
||||
};
|
||||
@@ -142,7 +140,7 @@ class CodeLensAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveCodeLens(symbol: ICodeLensDto, token: CancellationToken): Promise<ICodeLensDto | undefined> {
|
||||
resolveCodeLens(symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
|
||||
|
||||
const lens = symbol.cacheId && this._cache.get(...symbol.cacheId);
|
||||
if (!lens) {
|
||||
@@ -309,7 +307,7 @@ class ReferenceAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
export interface CustomCodeAction extends ICodeActionDto {
|
||||
export interface CustomCodeAction extends extHostProtocol.ICodeActionDto {
|
||||
_isSynthetic?: boolean;
|
||||
}
|
||||
|
||||
@@ -328,7 +326,7 @@ class CodeActionAdapter {
|
||||
private readonly _extensionId: ExtensionIdentifier
|
||||
) { }
|
||||
|
||||
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined> {
|
||||
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<extHostProtocol.ICodeActionListDto | undefined> {
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const ran = Selection.isISelection(rangeOrSelection)
|
||||
@@ -392,7 +390,7 @@ class CodeActionAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
return <ICodeActionListDto>{ cacheId, actions };
|
||||
return <extHostProtocol.ICodeActionListDto>{ cacheId, actions };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -481,8 +479,8 @@ class NavigateTypeAdapter {
|
||||
this._provider = provider;
|
||||
}
|
||||
|
||||
provideWorkspaceSymbols(search: string, token: CancellationToken): Promise<IWorkspaceSymbolsDto> {
|
||||
const result: IWorkspaceSymbolsDto = IdObject.mixin({ symbols: [] });
|
||||
provideWorkspaceSymbols(search: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolsDto> {
|
||||
const result: extHostProtocol.IWorkspaceSymbolsDto = extHostProtocol.IdObject.mixin({ symbols: [] });
|
||||
return asPromise(() => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
|
||||
if (isNonEmptyArray(value)) {
|
||||
for (const item of value) {
|
||||
@@ -494,7 +492,7 @@ class NavigateTypeAdapter {
|
||||
console.warn('INVALID SymbolInformation, lacks name', item);
|
||||
continue;
|
||||
}
|
||||
const symbol = IdObject.mixin(typeConvert.WorkspaceSymbol.from(item));
|
||||
const symbol = extHostProtocol.IdObject.mixin(typeConvert.WorkspaceSymbol.from(item));
|
||||
this._symbolCache[symbol._id!] = item;
|
||||
result.symbols.push(symbol);
|
||||
}
|
||||
@@ -507,7 +505,7 @@ class NavigateTypeAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveWorkspaceSymbol(symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise<IWorkspaceSymbolDto | undefined> {
|
||||
resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
|
||||
|
||||
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
|
||||
return Promise.resolve(symbol);
|
||||
@@ -544,7 +542,7 @@ class RenameAdapter {
|
||||
private readonly _provider: vscode.RenameProvider
|
||||
) { }
|
||||
|
||||
provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise<IWorkspaceEditDto | undefined> {
|
||||
provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | undefined> {
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
@@ -557,10 +555,10 @@ class RenameAdapter {
|
||||
}, err => {
|
||||
const rejectReason = RenameAdapter._asMessage(err);
|
||||
if (rejectReason) {
|
||||
return <IWorkspaceEditDto>{ rejectReason, edits: undefined! };
|
||||
return <extHostProtocol.IWorkspaceEditDto>{ rejectReason, edits: undefined! };
|
||||
} else {
|
||||
// generic error
|
||||
return Promise.reject<IWorkspaceEditDto>(err);
|
||||
return Promise.reject<extHostProtocol.IWorkspaceEditDto>(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -634,7 +632,7 @@ class SuggestAdapter {
|
||||
this._provider = provider;
|
||||
}
|
||||
|
||||
provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined> {
|
||||
provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<extHostProtocol.ISuggestResultDto | undefined> {
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
@@ -663,7 +661,7 @@ class SuggestAdapter {
|
||||
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos))
|
||||
.with({ end: pos });
|
||||
|
||||
const result: ISuggestResultDto = {
|
||||
const result: extHostProtocol.ISuggestResultDto = {
|
||||
x: pid,
|
||||
b: [],
|
||||
a: typeConvert.Range.from(wordRangeBeforePos),
|
||||
@@ -683,7 +681,7 @@ class SuggestAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveCompletionItem(_resource: URI, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined> {
|
||||
resolveCompletionItem(_resource: URI, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
|
||||
|
||||
if (typeof this._provider.resolveCompletionItem !== 'function') {
|
||||
return Promise.resolve(undefined);
|
||||
@@ -711,7 +709,7 @@ class SuggestAdapter {
|
||||
this._cache.delete(id);
|
||||
}
|
||||
|
||||
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId): ISuggestDataDto | undefined {
|
||||
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: extHostProtocol.ChainedCacheId): extHostProtocol.ISuggestDataDto | undefined {
|
||||
if (typeof item.label !== 'string' || item.label.length === 0) {
|
||||
console.warn('INVALID text edit -> must have at least a label');
|
||||
return undefined;
|
||||
@@ -722,7 +720,7 @@ class SuggestAdapter {
|
||||
throw Error('DisposableStore is missing...');
|
||||
}
|
||||
|
||||
const result: ISuggestDataDto = {
|
||||
const result: extHostProtocol.ISuggestDataDto = {
|
||||
//
|
||||
x: id,
|
||||
//
|
||||
@@ -779,7 +777,7 @@ class SignatureHelpAdapter {
|
||||
private readonly _provider: vscode.SignatureHelpProvider,
|
||||
) { }
|
||||
|
||||
provideSignatureHelp(resource: URI, position: IPosition, context: ISignatureHelpContextDto, token: CancellationToken): Promise<ISignatureHelpDto | undefined> {
|
||||
provideSignatureHelp(resource: URI, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise<extHostProtocol.ISignatureHelpDto | undefined> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
const vscodeContext = this.reviveContext(context);
|
||||
@@ -793,7 +791,7 @@ class SignatureHelpAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
private reviveContext(context: ISignatureHelpContextDto): vscode.SignatureHelpContext {
|
||||
private reviveContext(context: extHostProtocol.ISignatureHelpContextDto): vscode.SignatureHelpContext {
|
||||
let activeSignatureHelp: vscode.SignatureHelp | undefined = undefined;
|
||||
if (context.activeSignatureHelp) {
|
||||
const revivedSignatureHelp = typeConvert.SignatureHelp.to(context.activeSignatureHelp);
|
||||
@@ -857,7 +855,7 @@ class LinkProviderAdapter {
|
||||
private readonly _provider: vscode.DocumentLinkProvider
|
||||
) { }
|
||||
|
||||
provideLinks(resource: URI, token: CancellationToken): Promise<ILinksListDto | undefined> {
|
||||
provideLinks(resource: URI, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
|
||||
return asPromise(() => this._provider.provideDocumentLinks(doc, token)).then(links => {
|
||||
@@ -879,9 +877,9 @@ class LinkProviderAdapter {
|
||||
} else {
|
||||
// cache links for future resolving
|
||||
const pid = this._cache.add(links);
|
||||
const result: ILinksListDto = { links: [], id: pid };
|
||||
const result: extHostProtocol.ILinksListDto = { links: [], id: pid };
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
const dto: ILinkDto = typeConvert.DocumentLink.from(links[i]);
|
||||
const dto: extHostProtocol.ILinkDto = typeConvert.DocumentLink.from(links[i]);
|
||||
dto.cacheId = [pid, i];
|
||||
result.links.push(dto);
|
||||
}
|
||||
@@ -890,7 +888,7 @@ class LinkProviderAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveLink(id: ChainedCacheId, token: CancellationToken): Promise<ILinkDto | undefined> {
|
||||
resolveLink(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
|
||||
if (typeof this._provider.resolveDocumentLink !== 'function') {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -915,14 +913,14 @@ class ColorProviderAdapter {
|
||||
private _provider: vscode.DocumentColorProvider
|
||||
) { }
|
||||
|
||||
provideColors(resource: URI, token: CancellationToken): Promise<IRawColorInfo[]> {
|
||||
provideColors(resource: URI, token: CancellationToken): Promise<extHostProtocol.IRawColorInfo[]> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
return asPromise(() => this._provider.provideDocumentColors(doc, token)).then(colors => {
|
||||
if (!Array.isArray<vscode.ColorInformation>(colors)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const colorInfos: IRawColorInfo[] = colors.map(ci => {
|
||||
const colorInfos: extHostProtocol.IRawColorInfo[] = colors.map(ci => {
|
||||
return {
|
||||
color: typeConvert.Color.from(ci.color),
|
||||
range: typeConvert.Range.from(ci.range)
|
||||
@@ -933,7 +931,7 @@ class ColorProviderAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
provideColorPresentations(resource: URI, raw: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
|
||||
provideColorPresentations(resource: URI, raw: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
|
||||
const document = this._documents.getDocument(resource);
|
||||
const range = typeConvert.Range.to(raw.range);
|
||||
const color = typeConvert.Color.to(raw.color);
|
||||
@@ -1011,56 +1009,29 @@ class SelectionRangeAdapter {
|
||||
|
||||
class CallHierarchyAdapter {
|
||||
|
||||
// todo@joh keep object (heap service, lifecycle)
|
||||
private readonly _cache = new LRUCache<number, vscode.CallHierarchyItem>(1000, 0.8);
|
||||
private _idPool = 0;
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _provider: vscode.CallHierarchyItemProvider
|
||||
) { }
|
||||
|
||||
provideCallHierarchyItem(resource: URI, pos: IPosition, token: CancellationToken): Promise<undefined | callHierarchy.CallHierarchyItem> {
|
||||
const document = this._documents.getDocument(resource);
|
||||
const position = typeConvert.Position.to(pos);
|
||||
|
||||
return asPromise(() => this._provider.provideCallHierarchyItem(document, position, token)).then(item => {
|
||||
if (!item) {
|
||||
return undefined;
|
||||
}
|
||||
return this._fromItem(item);
|
||||
});
|
||||
async provideCallsTo(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
|
||||
const doc = this._documents.getDocument(uri);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
const calls = await this._provider.provideCallHierarchyIncomingCalls(doc, pos, token);
|
||||
if (!calls) {
|
||||
return undefined;
|
||||
}
|
||||
return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.source), call.sourceRanges.map(typeConvert.Range.from)]));
|
||||
}
|
||||
|
||||
resolveCallHierarchyItem(item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> {
|
||||
return asPromise(() => this._provider.resolveCallHierarchyItem(
|
||||
this._cache.get(item._id)!,
|
||||
direction as number, token) // todo@joh proper convert
|
||||
).then(data => {
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
return data.map(tuple => {
|
||||
return <[callHierarchy.CallHierarchyItem, modes.Location[]]>[
|
||||
this._fromItem(tuple[0]),
|
||||
tuple[1].map(typeConvert.location.from)
|
||||
];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _fromItem(item: vscode.CallHierarchyItem, _id: number = this._idPool++): callHierarchy.CallHierarchyItem {
|
||||
const res = <callHierarchy.CallHierarchyItem>{
|
||||
_id,
|
||||
name: item.name,
|
||||
detail: item.detail,
|
||||
kind: typeConvert.SymbolKind.from(item.kind),
|
||||
uri: item.uri,
|
||||
range: typeConvert.Range.from(item.range),
|
||||
selectionRange: typeConvert.Range.from(item.selectionRange),
|
||||
};
|
||||
this._cache.set(_id, item);
|
||||
return res;
|
||||
async provideCallsFrom(uri: URI, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
|
||||
const doc = this._documents.getDocument(uri);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
const calls = await this._provider.provideCallHierarchyOutgoingCalls(doc, pos, token);
|
||||
if (!calls) {
|
||||
return undefined;
|
||||
}
|
||||
return calls.map(call => (<[extHostProtocol.ICallHierarchyItemDto, IRange[]]>[typeConvert.CallHierarchyItem.from(call.target), call.sourceRanges.map(typeConvert.Range.from)]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1077,12 +1048,12 @@ class AdapterData {
|
||||
) { }
|
||||
}
|
||||
|
||||
export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageFeaturesShape {
|
||||
|
||||
private static _handlePool: number = 0;
|
||||
|
||||
private readonly _uriTransformer: IURITransformer | null;
|
||||
private _proxy: MainThreadLanguageFeaturesShape;
|
||||
private _proxy: extHostProtocol.MainThreadLanguageFeaturesShape;
|
||||
private _documents: ExtHostDocuments;
|
||||
private _commands: ExtHostCommands;
|
||||
private _diagnostics: ExtHostDiagnostics;
|
||||
@@ -1090,7 +1061,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
private readonly _logService: ILogService;
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
uriTransformer: IURITransformer | null,
|
||||
documents: ExtHostDocuments,
|
||||
commands: ExtHostCommands,
|
||||
@@ -1098,18 +1069,18 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
logService: ILogService
|
||||
) {
|
||||
this._uriTransformer = uriTransformer;
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguageFeatures);
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadLanguageFeatures);
|
||||
this._documents = documents;
|
||||
this._commands = commands;
|
||||
this._diagnostics = diagnostics;
|
||||
this._logService = logService;
|
||||
}
|
||||
|
||||
private _transformDocumentSelector(selector: vscode.DocumentSelector): Array<IDocumentFilterDto> {
|
||||
private _transformDocumentSelector(selector: vscode.DocumentSelector): Array<extHostProtocol.IDocumentFilterDto> {
|
||||
return coalesce(asArray(selector).map(sel => this._doTransformDocumentSelector(sel)));
|
||||
}
|
||||
|
||||
private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): IDocumentFilterDto | undefined {
|
||||
private _doTransformDocumentSelector(selector: string | vscode.DocumentFilter): extHostProtocol.IDocumentFilterDto | undefined {
|
||||
if (typeof selector === 'string') {
|
||||
return {
|
||||
$serialized: true,
|
||||
@@ -1217,11 +1188,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined> {
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined);
|
||||
}
|
||||
|
||||
$resolveCodeLens(handle: number, symbol: ICodeLensDto, token: CancellationToken): Promise<ICodeLensDto | undefined> {
|
||||
$resolveCodeLens(handle: number, symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1316,7 +1287,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
}
|
||||
|
||||
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined> {
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<extHostProtocol.ICodeActionListDto | undefined> {
|
||||
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1364,11 +1335,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise<IWorkspaceSymbolsDto> {
|
||||
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolsDto> {
|
||||
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search, token), { symbols: [] });
|
||||
}
|
||||
|
||||
$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise<IWorkspaceSymbolDto | undefined> {
|
||||
$resolveWorkspaceSymbol(handle: number, symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
|
||||
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1384,7 +1355,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<IWorkspaceEditDto | undefined> {
|
||||
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | undefined> {
|
||||
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1400,11 +1371,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined> {
|
||||
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<extHostProtocol.ISuggestResultDto | undefined> {
|
||||
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token), undefined);
|
||||
}
|
||||
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined> {
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
|
||||
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, id, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1415,7 +1386,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
// --- parameter hints
|
||||
|
||||
registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable {
|
||||
const metadata: ISignatureHelpProviderMetadataDto | undefined = Array.isArray(metadataOrTriggerChars)
|
||||
const metadata: extHostProtocol.ISignatureHelpProviderMetadataDto | undefined = Array.isArray(metadataOrTriggerChars)
|
||||
? { triggerCharacters: metadataOrTriggerChars, retriggerCharacters: [] }
|
||||
: metadataOrTriggerChars;
|
||||
|
||||
@@ -1424,7 +1395,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: ISignatureHelpContextDto, token: CancellationToken): Promise<ISignatureHelpDto | undefined> {
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise<extHostProtocol.ISignatureHelpDto | undefined> {
|
||||
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position, context, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1440,11 +1411,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<ILinksListDto | undefined> {
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource), token), undefined);
|
||||
}
|
||||
|
||||
$resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ILinkDto | undefined> {
|
||||
$resolveDocumentLink(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(id, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1458,11 +1429,11 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise<IRawColorInfo[]> {
|
||||
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.IRawColorInfo[]> {
|
||||
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource), token), []);
|
||||
}
|
||||
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined> {
|
||||
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token), undefined);
|
||||
}
|
||||
|
||||
@@ -1496,24 +1467,24 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<undefined | callHierarchy.CallHierarchyItem> {
|
||||
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallHierarchyItem(URI.revive(resource), position, token), undefined);
|
||||
$provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
|
||||
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(URI.revive(resource), position, token), undefined);
|
||||
}
|
||||
|
||||
$resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> {
|
||||
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.resolveCallHierarchyItem(item, direction, token), []);
|
||||
$provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[extHostProtocol.ICallHierarchyItemDto, IRange[]][] | undefined> {
|
||||
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(URI.revive(resource), position, token), undefined);
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
|
||||
private static _serializeRegExp(regExp: RegExp): IRegExpDto {
|
||||
private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto {
|
||||
return {
|
||||
pattern: regExp.source,
|
||||
flags: regExpFlags(regExp),
|
||||
};
|
||||
}
|
||||
|
||||
private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): IIndentationRuleDto {
|
||||
private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): extHostProtocol.IIndentationRuleDto {
|
||||
return {
|
||||
decreaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.decreaseIndentPattern),
|
||||
increaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.increaseIndentPattern),
|
||||
@@ -1522,7 +1493,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
};
|
||||
}
|
||||
|
||||
private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): IOnEnterRuleDto {
|
||||
private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): extHostProtocol.IOnEnterRuleDto {
|
||||
return {
|
||||
beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText),
|
||||
afterText: onEnterRule.afterText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText) : undefined,
|
||||
@@ -1531,7 +1502,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
};
|
||||
}
|
||||
|
||||
private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): IOnEnterRuleDto[] {
|
||||
private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): extHostProtocol.IOnEnterRuleDto[] {
|
||||
return onEnterRules.map(ExtHostLanguageFeatures._serializeOnEnterRule);
|
||||
}
|
||||
|
||||
@@ -1551,7 +1522,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
}
|
||||
|
||||
const handle = this._nextHandle();
|
||||
const serializedConfiguration: ILanguageConfigurationDto = {
|
||||
const serializedConfiguration: extHostProtocol.ILanguageConfigurationDto = {
|
||||
comments: configuration.comments,
|
||||
brackets: configuration.brackets,
|
||||
wordPattern: configuration.wordPattern ? ExtHostLanguageFeatures._serializeRegExp(configuration.wordPattern) : undefined,
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionMemento } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
|
||||
export class ExtensionMemento implements IExtensionMemento {
|
||||
export class ExtensionMemento implements vscode.Memento {
|
||||
|
||||
private readonly _id: string;
|
||||
private readonly _shared: boolean;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { MainContext, MainThreadOutputServiceShape, ExtHostOutputServiceShape }
|
||||
import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
@@ -137,23 +137,15 @@ export class LazyOutputChannel implements vscode.OutputChannel {
|
||||
|
||||
export class ExtHostOutputService implements ExtHostOutputServiceShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
protected readonly _proxy: MainThreadOutputServiceShape;
|
||||
protected readonly _channels: Map<string, AbstractExtHostOutputChannel> = new Map<string, AbstractExtHostOutputChannel>();
|
||||
protected readonly _visibleChannelDisposable = new MutableDisposable();
|
||||
|
||||
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadOutputService);
|
||||
}
|
||||
|
||||
$setVisibleChannel(channelId: string): void {
|
||||
if (channelId) {
|
||||
const channel = this._channels.get(channelId);
|
||||
if (channel) {
|
||||
this._visibleChannelDisposable.value = channel.onDidAppend(() => channel.update());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createOutputChannel(name: string): vscode.OutputChannel {
|
||||
|
||||
@@ -134,6 +134,7 @@ interface IKeytarModule {
|
||||
setPassword(service: string, account: string, password: string): Promise<void>;
|
||||
deletePassword(service: string, account: string): Promise<boolean>;
|
||||
findPassword(service: string): Promise<string | null>;
|
||||
findCredentials(service: string): Promise<Array<{ account: string, password: string }>>;
|
||||
}
|
||||
|
||||
class KeytarNodeModuleFactory implements INodeModuleFactory {
|
||||
@@ -174,6 +175,9 @@ class KeytarNodeModuleFactory implements INodeModuleFactory {
|
||||
},
|
||||
findPassword: (service: string): Promise<string | null> => {
|
||||
return mainThreadKeytar.$findPassword(service);
|
||||
},
|
||||
findCredentials(service: string): Promise<Array<{ account: string, password: string }>> {
|
||||
return mainThreadKeytar.$findCredentials(service);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
export const IExtHostRpcService = createDecorator<IExtHostRpcService>('IExtHostRpcService');
|
||||
|
||||
export interface IExtHostRpcService extends IRPCProtocol {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
}
|
||||
|
||||
export class ExtHostRpcService implements IExtHostRpcService {
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
readonly getProxy: <T>(identifier: ProxyIdentifier<T>) => T;
|
||||
readonly set: <T, R extends T> (identifier: ProxyIdentifier<T>, instance: R) => R;
|
||||
|
||||
@@ -319,11 +319,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
|
||||
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
|
||||
const faded = r.decorations && !!r.decorations.faded;
|
||||
|
||||
const source = r.decorations && r.decorations.source || undefined;
|
||||
const letter = r.decorations && r.decorations.letter || undefined;
|
||||
const color = r.decorations && r.decorations.color || undefined;
|
||||
|
||||
const rawResource = [handle, <UriComponents>sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource;
|
||||
const rawResource = [handle, <UriComponents>sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource;
|
||||
|
||||
return { rawResource, handle };
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface IStorageChangeEvent {
|
||||
|
||||
export class ExtHostStorage implements ExtHostStorageShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private _proxy: MainThreadStorageShape;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
export const IExtensionStoragePaths = createDecorator<IExtensionStoragePaths>('IExtensionStoragePaths');
|
||||
|
||||
export interface IExtensionStoragePaths {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
whenReady: Promise<any>;
|
||||
workspaceValue(extension: IExtensionDescription): string | undefined;
|
||||
globalValue(extension: IExtensionDescription): string;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
|
||||
export interface IExtHostTask extends ExtHostTaskShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
taskExecutions: vscode.TaskExecution[];
|
||||
onDidStartTask: Event<vscode.TaskStartEvent>;
|
||||
|
||||
@@ -4,14 +4,18 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { EXT_HOST_CREATION_DELAY, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
|
||||
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
activeTerminal: vscode.Terminal | undefined;
|
||||
terminals: vscode.Terminal[];
|
||||
@@ -30,3 +34,562 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
|
||||
}
|
||||
|
||||
export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
|
||||
|
||||
export class BaseExtHostTerminal {
|
||||
public _id: number | undefined;
|
||||
protected _idPromise: Promise<number>;
|
||||
private _idPromiseComplete: ((value: number) => any) | undefined;
|
||||
private _disposed: boolean = false;
|
||||
private _queuedRequests: ApiRequest[] = [];
|
||||
|
||||
constructor(
|
||||
protected _proxy: MainThreadTerminalServiceShape,
|
||||
id?: number
|
||||
) {
|
||||
this._idPromise = new Promise<number>(c => {
|
||||
if (id !== undefined) {
|
||||
this._id = id;
|
||||
c(id);
|
||||
} else {
|
||||
this._idPromiseComplete = c;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (!this._disposed) {
|
||||
this._disposed = true;
|
||||
this._queueApiRequest(this._proxy.$dispose, []);
|
||||
}
|
||||
}
|
||||
|
||||
protected _checkDisposed() {
|
||||
if (this._disposed) {
|
||||
throw new Error('Terminal has already been disposed');
|
||||
}
|
||||
}
|
||||
|
||||
protected _queueApiRequest(callback: (...args: any[]) => void, args: any[]): void {
|
||||
const request: ApiRequest = new ApiRequest(callback, args);
|
||||
if (!this._id) {
|
||||
this._queuedRequests.push(request);
|
||||
return;
|
||||
}
|
||||
request.run(this._proxy, this._id);
|
||||
}
|
||||
|
||||
public _runQueuedRequests(id: number): void {
|
||||
this._id = id;
|
||||
if (this._idPromiseComplete) {
|
||||
this._idPromiseComplete(id);
|
||||
this._idPromiseComplete = undefined;
|
||||
}
|
||||
this._queuedRequests.forEach((r) => {
|
||||
r.run(this._proxy, id);
|
||||
});
|
||||
this._queuedRequests.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal {
|
||||
private _pidPromise: Promise<number | undefined>;
|
||||
private _cols: number | undefined;
|
||||
private _pidPromiseComplete: ((value: number | undefined) => any) | undefined;
|
||||
private _rows: number | undefined;
|
||||
|
||||
public isOpen: boolean = false;
|
||||
|
||||
constructor(
|
||||
proxy: MainThreadTerminalServiceShape,
|
||||
private _name?: string,
|
||||
id?: number
|
||||
) {
|
||||
super(proxy, id);
|
||||
this._pidPromise = new Promise<number>(c => this._pidPromiseComplete = c);
|
||||
}
|
||||
|
||||
public async create(
|
||||
shellPath?: string,
|
||||
shellArgs?: string[] | string,
|
||||
cwd?: string | URI,
|
||||
env?: { [key: string]: string | null },
|
||||
waitOnExit?: boolean,
|
||||
strictEnv?: boolean,
|
||||
hideFromUser?: boolean
|
||||
): Promise<void> {
|
||||
const terminal = await this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser });
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
}
|
||||
|
||||
public async createExtensionTerminal(): Promise<number> {
|
||||
const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true });
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
return terminal.id;
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this._name || '';
|
||||
}
|
||||
|
||||
public set name(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public get dimensions(): vscode.TerminalDimensions | undefined {
|
||||
if (this._cols === undefined || this._rows === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
columns: this._cols,
|
||||
rows: this._rows
|
||||
};
|
||||
}
|
||||
|
||||
public setDimensions(cols: number, rows: number): boolean {
|
||||
if (cols === this._cols && rows === this._rows) {
|
||||
// Nothing changed
|
||||
return false;
|
||||
}
|
||||
this._cols = cols;
|
||||
this._rows = rows;
|
||||
return true;
|
||||
}
|
||||
|
||||
public get processId(): Promise<number | undefined> {
|
||||
return this._pidPromise;
|
||||
}
|
||||
|
||||
public sendText(text: string, addNewLine: boolean = true): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]);
|
||||
}
|
||||
|
||||
public show(preserveFocus: boolean): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$show, [preserveFocus]);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$hide, []);
|
||||
}
|
||||
|
||||
public _setProcessId(processId: number | undefined): void {
|
||||
// The event may fire 2 times when the panel is restored
|
||||
if (this._pidPromiseComplete) {
|
||||
this._pidPromiseComplete(processId);
|
||||
this._pidPromiseComplete = undefined;
|
||||
} else {
|
||||
// Recreate the promise if this is the nth processId set (e.g. reused task terminals)
|
||||
this._pidPromise.then(pid => {
|
||||
if (pid !== processId) {
|
||||
this._pidPromise = Promise.resolve(processId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ApiRequest {
|
||||
private _callback: (...args: any[]) => void;
|
||||
private _args: any[];
|
||||
|
||||
constructor(callback: (...args: any[]) => void, args: any[]) {
|
||||
this._callback = callback;
|
||||
this._args = args;
|
||||
}
|
||||
|
||||
public run(proxy: MainThreadTerminalServiceShape, id: number) {
|
||||
this._callback.apply(proxy, [id].concat(this._args));
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
private readonly _onProcessData = new Emitter<string>();
|
||||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = new Emitter<number>();
|
||||
public readonly onProcessExit: Event<number> = this._onProcessExit.event;
|
||||
private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>();
|
||||
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = new Emitter<string>();
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
|
||||
constructor(private readonly _pty: vscode.Pseudoterminal) { }
|
||||
|
||||
shutdown(): void {
|
||||
this._pty.close();
|
||||
}
|
||||
|
||||
input(data: string): void {
|
||||
if (this._pty.handleInput) {
|
||||
this._pty.handleInput(data);
|
||||
}
|
||||
}
|
||||
|
||||
resize(cols: number, rows: number): void {
|
||||
if (this._pty.setDimensions) {
|
||||
this._pty.setDimensions({ columns: cols, rows });
|
||||
}
|
||||
}
|
||||
|
||||
getInitialCwd(): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
getCwd(): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
getLatency(): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
|
||||
// Attach the listeners
|
||||
this._pty.onDidWrite(e => this._onProcessData.fire(e));
|
||||
if (this._pty.onDidClose) {
|
||||
this._pty.onDidClose(e => this._onProcessExit.fire(e || 0));
|
||||
}
|
||||
if (this._pty.onDidOverrideDimensions) {
|
||||
this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBONEDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
this._pty.open(initialDimensions ? initialDimensions : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class BaseExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
protected _proxy: MainThreadTerminalServiceShape;
|
||||
protected _activeTerminal: ExtHostTerminal | undefined;
|
||||
protected _terminals: ExtHostTerminal[] = [];
|
||||
protected _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
|
||||
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
|
||||
|
||||
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
|
||||
public get terminals(): ExtHostTerminal[] { return this._terminals; }
|
||||
|
||||
protected readonly _onDidCloseTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
|
||||
public get onDidCloseTerminal(): Event<vscode.Terminal> { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; }
|
||||
protected readonly _onDidOpenTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
|
||||
public get onDidOpenTerminal(): Event<vscode.Terminal> { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; }
|
||||
protected readonly _onDidChangeActiveTerminal: Emitter<vscode.Terminal | undefined> = new Emitter<vscode.Terminal | undefined>();
|
||||
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
|
||||
protected readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
|
||||
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
|
||||
protected readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
|
||||
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
|
||||
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService
|
||||
) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
|
||||
this._onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
|
||||
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
|
||||
onLastListenerRemove: () => this._proxy.$stopSendingDataEvents()
|
||||
});
|
||||
}
|
||||
|
||||
public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
|
||||
public abstract createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal;
|
||||
public abstract getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
|
||||
public abstract $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void>;
|
||||
public abstract $requestAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
public abstract $requestDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
|
||||
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
|
||||
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options.name);
|
||||
const p = new ExtHostPseudoterminal(options.pty);
|
||||
terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p));
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
}
|
||||
|
||||
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
|
||||
const terminal = this._getTerminalByIdEventually(id);
|
||||
if (!terminal) {
|
||||
throw new Error(`Cannot resolve terminal with id ${id} for virtual process`);
|
||||
}
|
||||
const p = new ExtHostPseudoterminal(pty);
|
||||
this._setupExtHostProcessListeners(id, p);
|
||||
}
|
||||
|
||||
public async $acceptActiveTerminalChanged(id: number | null): Promise<void> {
|
||||
const original = this._activeTerminal;
|
||||
if (id === null) {
|
||||
this._activeTerminal = undefined;
|
||||
if (original !== this._activeTerminal) {
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
this._activeTerminal = terminal;
|
||||
if (original !== this._activeTerminal) {
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
this._onDidWriteTerminalData.fire({ terminal, data });
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
if (terminal.setDimensions(cols, rows)) {
|
||||
this._onDidChangeTerminalDimensions.fire({
|
||||
terminal: terminal,
|
||||
dimensions: terminal.dimensions as vscode.TerminalDimensions
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
|
||||
if (this._terminalProcesses[id]) {
|
||||
// Extension pty terminal only - when virtual process resize fires it means that the
|
||||
// terminal's maximum dimensions changed
|
||||
this._terminalProcesses[id].resize(cols, rows);
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalTitleChange(id: number, name: string): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
const extHostTerminal = this._getTerminalObjectById(this.terminals, id);
|
||||
if (extHostTerminal) {
|
||||
extHostTerminal.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalClosed(id: number): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
const index = this._getTerminalObjectIndexById(this.terminals, id);
|
||||
if (index !== null) {
|
||||
const terminal = this._terminals.splice(index, 1)[0];
|
||||
this._onDidCloseTerminal.fire(terminal);
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalOpened(id: number, name: string): void {
|
||||
const index = this._getTerminalObjectIndexById(this._terminals, id);
|
||||
if (index !== null) {
|
||||
// The terminal has already been created (via createTerminal*), only fire the event
|
||||
this._onDidOpenTerminal.fire(this.terminals[index]);
|
||||
this.terminals[index].isOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const terminal = new ExtHostTerminal(this._proxy, name, id);
|
||||
this._terminals.push(terminal);
|
||||
this._onDidOpenTerminal.fire(terminal);
|
||||
terminal.isOpen = true;
|
||||
}
|
||||
|
||||
public async $acceptTerminalProcessId(id: number, processId: number): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
terminal._setProcessId(processId);
|
||||
}
|
||||
}
|
||||
|
||||
public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
|
||||
// TODO: Use await this._getTerminalByIdEventually(id);
|
||||
let terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
callback(terminal);
|
||||
} else {
|
||||
// Retry one more time in case the terminal has not yet been initialized.
|
||||
setTimeout(() => {
|
||||
terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
callback(terminal);
|
||||
}
|
||||
}, EXT_HOST_CREATION_DELAY * 2);
|
||||
}
|
||||
}
|
||||
|
||||
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<void> {
|
||||
// Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
|
||||
// Pseudoterminal.start
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (!terminal) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for onDidOpenTerminal to fire
|
||||
let openPromise: Promise<void>;
|
||||
if (terminal.isOpen) {
|
||||
openPromise = Promise.resolve();
|
||||
} else {
|
||||
openPromise = new Promise<void>(r => {
|
||||
// Ensure open is called after onDidOpenTerminal
|
||||
const listener = this.onDidOpenTerminal(async e => {
|
||||
if (e === terminal) {
|
||||
listener.dispose();
|
||||
r();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
await openPromise;
|
||||
|
||||
// Processes should be initialized here for normal virtual process terminals, however for
|
||||
// tasks they are responsible for attaching the virtual process to a terminal so this
|
||||
// function may be called before tasks is able to attach to the terminal.
|
||||
let retries = 5;
|
||||
while (retries-- > 0) {
|
||||
if (this._terminalProcesses[id]) {
|
||||
(this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions);
|
||||
return;
|
||||
}
|
||||
await timeout(50);
|
||||
}
|
||||
}
|
||||
|
||||
protected _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
|
||||
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
|
||||
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
|
||||
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
|
||||
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode));
|
||||
if (p.onProcessOverrideDimensions) {
|
||||
p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e));
|
||||
}
|
||||
this._terminalProcesses[id] = p;
|
||||
}
|
||||
|
||||
public $acceptProcessInput(id: number, data: string): void {
|
||||
this._terminalProcesses[id].input(data);
|
||||
}
|
||||
|
||||
public $acceptProcessResize(id: number, cols: number, rows: number): void {
|
||||
try {
|
||||
this._terminalProcesses[id].resize(cols, rows);
|
||||
} catch (error) {
|
||||
// We tried to write to a closed pipe / channel.
|
||||
if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') {
|
||||
throw (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptProcessShutdown(id: number, immediate: boolean): void {
|
||||
this._terminalProcesses[id].shutdown(immediate);
|
||||
}
|
||||
|
||||
public $acceptProcessRequestInitialCwd(id: number): void {
|
||||
this._terminalProcesses[id].getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd));
|
||||
}
|
||||
|
||||
public $acceptProcessRequestCwd(id: number): void {
|
||||
this._terminalProcesses[id].getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd));
|
||||
}
|
||||
|
||||
public $acceptProcessRequestLatency(id: number): number {
|
||||
return id;
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number): void {
|
||||
// Remove process reference
|
||||
delete this._terminalProcesses[id];
|
||||
|
||||
// Send exit event to main side
|
||||
this._proxy.$sendProcessExit(id, exitCode);
|
||||
}
|
||||
|
||||
// TODO: This could be improved by using a single promise and resolve it when the terminal is ready
|
||||
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal | undefined> {
|
||||
if (!this._getTerminalPromises[id]) {
|
||||
this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries);
|
||||
} else {
|
||||
this._getTerminalPromises[id].then(c => {
|
||||
return this._createGetTerminalPromise(id, retries);
|
||||
});
|
||||
}
|
||||
return this._getTerminalPromises[id];
|
||||
}
|
||||
|
||||
private _createGetTerminalPromise(id: number, retries: number = 5): Promise<ExtHostTerminal> {
|
||||
return new Promise(c => {
|
||||
if (retries === 0) {
|
||||
c(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
c(terminal);
|
||||
} else {
|
||||
// This should only be needed immediately after createTerminalRenderer is called as
|
||||
// the ExtHostTerminal has not yet been iniitalized
|
||||
timeout(200).then(() => c(this._createGetTerminalPromise(id, retries - 1)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _getTerminalById(id: number): ExtHostTerminal | null {
|
||||
return this._getTerminalObjectById(this._terminals, id);
|
||||
}
|
||||
|
||||
private _getTerminalObjectById<T extends ExtHostTerminal>(array: T[], id: number): T | null {
|
||||
const index = this._getTerminalObjectIndexById(array, id);
|
||||
return index !== null ? array[index] : null;
|
||||
}
|
||||
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: number): number | null {
|
||||
let index: number | null = null;
|
||||
array.some((item, i) => {
|
||||
const thisId = item._id;
|
||||
if (thisId === id) {
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public $requestAvailableShells(): Promise<IShellDefinitionDto[]> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async $requestDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
|
||||
// No-op for web worker ext host as workspace permissions aren't used
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,11 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||
checkProposedApiEnabled(extension);
|
||||
treeView.message = message;
|
||||
},
|
||||
get title() { return treeView.title; },
|
||||
set title(title: string) {
|
||||
checkProposedApiEnabled(extension);
|
||||
treeView.title = title;
|
||||
},
|
||||
reveal: (element: T, options?: IRevealOptions): Promise<void> => {
|
||||
return treeView.reveal(element, options);
|
||||
},
|
||||
@@ -200,6 +205,15 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
|
||||
constructor(private viewId: string, options: vscode.TreeViewOptions<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) {
|
||||
super();
|
||||
if (extension.contributes && extension.contributes.views) {
|
||||
for (const location in extension.contributes.views) {
|
||||
for (const view of extension.contributes.views[location]) {
|
||||
if (view.id === viewId) {
|
||||
this._title = view.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dataProvider = options.treeDataProvider;
|
||||
// {{SQL CARBON EDIT}}
|
||||
if (this.proxy) {
|
||||
@@ -282,6 +296,16 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
this._onDidChangeData.fire({ message: true, element: false });
|
||||
}
|
||||
|
||||
private _title: string = '';
|
||||
get title(): string {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
set title(title: string) {
|
||||
this._title = title;
|
||||
this.proxy.$setTitle(this.viewId, title);
|
||||
}
|
||||
|
||||
setExpanded(treeItemHandle: TreeItemHandle, expanded: boolean): void {
|
||||
const element = this.getExtensionElement(treeItemHandle);
|
||||
if (element) {
|
||||
|
||||
@@ -19,7 +19,7 @@ import { IRange } from 'vs/editor/common/core/range';
|
||||
import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import * as htmlContent from 'vs/base/common/htmlContent';
|
||||
import * as languageSelector from 'vs/editor/common/modes/languageSelector';
|
||||
import { IWorkspaceEditDto, IResourceTextEditDto, IResourceFileEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers';
|
||||
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
@@ -31,6 +31,7 @@ import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
|
||||
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
|
||||
export interface PositionLike {
|
||||
line: number;
|
||||
character: number;
|
||||
@@ -473,8 +474,8 @@ export namespace TextEdit {
|
||||
}
|
||||
|
||||
export namespace WorkspaceEdit {
|
||||
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): IWorkspaceEditDto {
|
||||
const result: IWorkspaceEditDto = {
|
||||
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): extHostProtocol.IWorkspaceEditDto {
|
||||
const result: extHostProtocol.IWorkspaceEditDto = {
|
||||
edits: []
|
||||
};
|
||||
for (const entry of (value as types.WorkspaceEdit)._allEntries()) {
|
||||
@@ -482,28 +483,28 @@ export namespace WorkspaceEdit {
|
||||
if (Array.isArray(uriOrEdits)) {
|
||||
// text edits
|
||||
const doc = documents && uri ? documents.getDocument(uri) : undefined;
|
||||
result.edits.push(<IResourceTextEditDto>{ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) });
|
||||
result.edits.push(<extHostProtocol.IResourceTextEditDto>{ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) });
|
||||
} else {
|
||||
// resource edits
|
||||
result.edits.push(<IResourceFileEditDto>{ oldUri: uri, newUri: uriOrEdits, options: entry[2] });
|
||||
result.edits.push(<extHostProtocol.IResourceFileEditDto>{ oldUri: uri, newUri: uriOrEdits, options: entry[2] });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function to(value: IWorkspaceEditDto) {
|
||||
export function to(value: extHostProtocol.IWorkspaceEditDto) {
|
||||
const result = new types.WorkspaceEdit();
|
||||
for (const edit of value.edits) {
|
||||
if (Array.isArray((<IResourceTextEditDto>edit).edits)) {
|
||||
if (Array.isArray((<extHostProtocol.IResourceTextEditDto>edit).edits)) {
|
||||
result.set(
|
||||
URI.revive((<IResourceTextEditDto>edit).resource),
|
||||
<types.TextEdit[]>(<IResourceTextEditDto>edit).edits.map(TextEdit.to)
|
||||
URI.revive((<extHostProtocol.IResourceTextEditDto>edit).resource),
|
||||
<types.TextEdit[]>(<extHostProtocol.IResourceTextEditDto>edit).edits.map(TextEdit.to)
|
||||
);
|
||||
} else {
|
||||
result.renameFile(
|
||||
URI.revive((<IResourceFileEditDto>edit).oldUri!),
|
||||
URI.revive((<IResourceFileEditDto>edit).newUri!),
|
||||
(<IResourceFileEditDto>edit).options
|
||||
URI.revive((<extHostProtocol.IResourceFileEditDto>edit).oldUri!),
|
||||
URI.revive((<extHostProtocol.IResourceFileEditDto>edit).newUri!),
|
||||
(<extHostProtocol.IResourceFileEditDto>edit).options
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -626,6 +627,32 @@ export namespace DocumentSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace CallHierarchyItem {
|
||||
|
||||
export function from(item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto {
|
||||
return {
|
||||
name: item.name,
|
||||
detail: item.detail,
|
||||
kind: SymbolKind.from(item.kind),
|
||||
uri: item.uri,
|
||||
range: Range.from(item.range),
|
||||
selectionRange: Range.from(item.selectionRange),
|
||||
};
|
||||
}
|
||||
|
||||
export function to(item: extHostProtocol.ICallHierarchyItemDto): vscode.CallHierarchyItem {
|
||||
return new types.CallHierarchyItem(
|
||||
SymbolKind.to(item.kind),
|
||||
item.name,
|
||||
item.detail || '',
|
||||
URI.revive(item.uri),
|
||||
Range.to(item.range),
|
||||
Range.to(item.selectionRange)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export namespace location {
|
||||
export function from(value: vscode.Location): modes.Location {
|
||||
return {
|
||||
@@ -1136,3 +1163,13 @@ export namespace LogLevel {
|
||||
return types.LogLevel.Info;
|
||||
}
|
||||
}
|
||||
export namespace WebviewEditorState {
|
||||
export function from(state: vscode.WebviewEditorState): modes.WebviewEditorState {
|
||||
switch (state) {
|
||||
case types.WebviewEditorState.Readonly: return modes.WebviewEditorState.Readonly;
|
||||
case types.WebviewEditorState.Unchanged: return modes.WebviewEditorState.Unchanged;
|
||||
case types.WebviewEditorState.Dirty: return modes.WebviewEditorState.Dirty;
|
||||
default: throw new Error('Unknown vscode.WebviewEditorState');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1146,12 +1146,6 @@ export class SelectionRange {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export enum CallHierarchyDirection {
|
||||
CallsFrom = 1,
|
||||
CallsTo = 2,
|
||||
}
|
||||
|
||||
export class CallHierarchyItem {
|
||||
kind: SymbolKind;
|
||||
name: string;
|
||||
@@ -1170,6 +1164,27 @@ export class CallHierarchyItem {
|
||||
}
|
||||
}
|
||||
|
||||
export class CallHierarchyIncomingCall {
|
||||
|
||||
source: vscode.CallHierarchyItem;
|
||||
sourceRanges: vscode.Range[];
|
||||
|
||||
constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) {
|
||||
this.sourceRanges = sourceRanges;
|
||||
this.source = item;
|
||||
}
|
||||
}
|
||||
export class CallHierarchyOutgoingCall {
|
||||
|
||||
target: vscode.CallHierarchyItem;
|
||||
sourceRanges: vscode.Range[];
|
||||
|
||||
constructor(item: vscode.CallHierarchyItem, sourceRanges: vscode.Range[]) {
|
||||
this.sourceRanges = sourceRanges;
|
||||
this.target = item;
|
||||
}
|
||||
}
|
||||
|
||||
@es5ClassCompat
|
||||
export class CodeLens {
|
||||
|
||||
@@ -2345,12 +2360,31 @@ export class QuickInputButtons {
|
||||
private constructor() { }
|
||||
}
|
||||
|
||||
export enum ExtensionExecutionContext {
|
||||
Local = 1,
|
||||
Remote = 2
|
||||
}
|
||||
|
||||
export enum ExtensionKind {
|
||||
UI = 1,
|
||||
Workspace = 2
|
||||
}
|
||||
|
||||
export class Decoration {
|
||||
|
||||
static validate(d: Decoration): void {
|
||||
if (d.letter && d.letter.length !== 1) {
|
||||
throw new Error(`The 'letter'-property must be undefined or a single character`);
|
||||
}
|
||||
if (!d.bubble && !d.color && !d.letter && !d.priority && !d.title) {
|
||||
throw new Error(`The decoration is empty`);
|
||||
}
|
||||
}
|
||||
|
||||
letter?: string;
|
||||
title?: string;
|
||||
color?: vscode.ThemeColor;
|
||||
priority?: number;
|
||||
bubble?: boolean;
|
||||
}
|
||||
|
||||
export enum WebviewEditorState {
|
||||
Readonly = 1,
|
||||
Unchanged = 2,
|
||||
Dirty = 3,
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
|
||||
export interface IURITransformerService extends IURITransformer {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
}
|
||||
|
||||
export const IURITransformerService = createDecorator<IURITransformerService>('IURITransformerService');
|
||||
|
||||
export class URITransformerService implements IURITransformerService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
transformIncoming: (uri: UriComponents) => UriComponents;
|
||||
transformOutgoing: (uri: UriComponents) => UriComponents;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -13,7 +13,7 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol';
|
||||
import { Disposable } from './extHostTypes';
|
||||
import { Disposable, WebviewEditorState } from './extHostTypes';
|
||||
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
@@ -40,7 +40,9 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
}
|
||||
|
||||
public get cspSource(): string {
|
||||
return this._initData.webviewCspSource.replace('{{uuid}}', this._handle);
|
||||
return this._initData.webviewCspSource
|
||||
.replace('{{uuid}}', this._handle)
|
||||
.replace('{{commit}}', this._initData.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44');
|
||||
}
|
||||
|
||||
public get html(): string {
|
||||
@@ -79,7 +81,7 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostWebviewPanel implements vscode.WebviewPanel {
|
||||
export class ExtHostWebviewEditor implements vscode.WebviewEditor {
|
||||
|
||||
private readonly _handle: WebviewPanelHandle;
|
||||
private readonly _proxy: MainThreadWebviewsShape;
|
||||
@@ -92,6 +94,7 @@ export class ExtHostWebviewPanel implements vscode.WebviewPanel {
|
||||
private _viewColumn: vscode.ViewColumn | undefined;
|
||||
private _visible: boolean = true;
|
||||
private _active: boolean = true;
|
||||
private _state = WebviewEditorState.Readonly;
|
||||
|
||||
_isDisposed: boolean = false;
|
||||
|
||||
@@ -212,6 +215,15 @@ export class ExtHostWebviewPanel implements vscode.WebviewPanel {
|
||||
this._visible = value;
|
||||
}
|
||||
|
||||
public get state(): vscode.WebviewEditorState {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
public set state(newState: vscode.WebviewEditorState) {
|
||||
this._state = newState;
|
||||
this._proxy.$setState(this._handle, typeConverters.WebviewEditorState.from(newState));
|
||||
}
|
||||
|
||||
public postMessage(message: any): Promise<boolean> {
|
||||
this.assertNotDisposed();
|
||||
return this._proxy.$postMessage(this._handle, message);
|
||||
@@ -239,8 +251,9 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
private readonly _proxy: MainThreadWebviewsShape;
|
||||
private readonly _webviewPanels = new Map<WebviewPanelHandle, ExtHostWebviewPanel>();
|
||||
private readonly _webviewPanels = new Map<WebviewPanelHandle, ExtHostWebviewEditor>();
|
||||
private readonly _serializers = new Map<string, vscode.WebviewPanelSerializer>();
|
||||
private readonly _editorProviders = new Map<string, vscode.WebviewEditorProvider>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
@@ -266,7 +279,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, convertWebviewOptions(options), extension.identifier, extension.extensionLocation);
|
||||
|
||||
const webview = new ExtHostWebview(handle, this._proxy, options, this.initData);
|
||||
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
||||
const panel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
||||
this._webviewPanels.set(handle, panel);
|
||||
return panel;
|
||||
}
|
||||
@@ -288,6 +301,23 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
});
|
||||
}
|
||||
|
||||
public registerWebviewEditorProvider(
|
||||
viewType: string,
|
||||
provider: vscode.WebviewEditorProvider
|
||||
): vscode.Disposable {
|
||||
if (this._editorProviders.has(viewType)) {
|
||||
throw new Error(`Editor provider for '${viewType}' already registered`);
|
||||
}
|
||||
|
||||
this._editorProviders.set(viewType, provider);
|
||||
this._proxy.$registerEditorProvider(viewType);
|
||||
|
||||
return new Disposable(() => {
|
||||
this._editorProviders.delete(viewType);
|
||||
this._proxy.$unregisterEditorProvider(viewType);
|
||||
});
|
||||
}
|
||||
|
||||
public $onMessage(
|
||||
handle: WebviewPanelHandle,
|
||||
message: any
|
||||
@@ -298,6 +328,13 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
}
|
||||
}
|
||||
|
||||
public $onMissingCsp(
|
||||
_handle: WebviewPanelHandle,
|
||||
extensionId: string
|
||||
): void {
|
||||
console.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`);
|
||||
}
|
||||
|
||||
public $onDidChangeWebviewPanelViewStates(newStates: WebviewPanelViewStateData): void {
|
||||
const handles = Object.keys(newStates);
|
||||
// Notify webviews of state changes in the following order:
|
||||
@@ -356,14 +393,35 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData);
|
||||
const revivedPanel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(webviewHandle, revivedPanel);
|
||||
return Promise.resolve(serializer.deserializeWebviewPanel(revivedPanel, state));
|
||||
}
|
||||
|
||||
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewPanel | undefined {
|
||||
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewEditor | undefined {
|
||||
return this._webviewPanels.get(handle);
|
||||
}
|
||||
|
||||
async $resolveWebviewEditor(
|
||||
resource: UriComponents,
|
||||
webviewHandle: WebviewPanelHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
state: any,
|
||||
position: EditorViewColumn,
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
|
||||
): Promise<void> {
|
||||
const provider = this._editorProviders.get(viewType);
|
||||
if (!provider) {
|
||||
return Promise.reject(new Error(`No provider found for '${viewType}'`));
|
||||
}
|
||||
|
||||
const webview = new ExtHostWebview(webviewHandle, this._proxy, options, this.initData);
|
||||
const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(webviewHandle, revivedPanel);
|
||||
return Promise.resolve(provider.resolveWebviewEditor(URI.revive(resource), revivedPanel));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function convertWebviewOptions(
|
||||
|
||||
@@ -156,7 +156,7 @@ class ExtHostWorkspaceImpl extends Workspace {
|
||||
|
||||
export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspaceProvider {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
|
||||
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export interface WebviewInitData {
|
||||
readonly commit?: string;
|
||||
readonly webviewResourceRoot: string;
|
||||
readonly webviewCspSource: string;
|
||||
}
|
||||
@@ -14,11 +15,11 @@ export interface WebviewInitData {
|
||||
export function asWebviewUri(
|
||||
initData: WebviewInitData,
|
||||
uuid: string,
|
||||
resource: vscode.Uri
|
||||
resource: vscode.Uri,
|
||||
): vscode.Uri {
|
||||
const uri = initData.webviewResourceRoot
|
||||
.replace('{{commit}}', initData.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44')
|
||||
.replace('{{resource}}', resource.toString().replace(/^\S+?:/, ''))
|
||||
.replace('{{uuid}}', uuid);
|
||||
|
||||
return URI.parse(uri);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugServic
|
||||
|
||||
export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugServiceShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private _configProviderHandleCounter: number;
|
||||
private _configProviders: ConfigProviderTuple[];
|
||||
@@ -687,6 +687,13 @@ export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugSe
|
||||
this._onDidChangeActiveDebugSession.fire(this._activeDebugSession);
|
||||
}
|
||||
|
||||
public async $acceptDebugSessionNameChanged(sessionDto: IDebugSessionDto, name: string): Promise<void> {
|
||||
const session = await this.getSession(sessionDto);
|
||||
if (session) {
|
||||
session._acceptNameChanged(name);
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise<void> {
|
||||
const session = await this.getSession(sessionDto);
|
||||
const ee: vscode.DebugSessionCustomEvent = {
|
||||
@@ -917,6 +924,15 @@ export class ExtHostDebugSession implements vscode.DebugSession {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public set name(name: string) {
|
||||
this._name = name;
|
||||
this._debugServiceProxy.$setDebugSessionName(this._id, name);
|
||||
}
|
||||
|
||||
_acceptNameChanged(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public get workspaceFolder(): vscode.WorkspaceFolder | undefined {
|
||||
return this._workspaceFolder;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { dirExists, mkdirp } from 'vs/base/node/pfs';
|
||||
import { AbstractExtHostOutputChannel, ExtHostPushOutputChannel, ExtHostOutputService, LazyOutputChannel } from 'vs/workbench/api/common/extHostOutput';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
|
||||
|
||||
@@ -49,6 +50,8 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
|
||||
|
||||
private _logsLocation: URI;
|
||||
private _namePool: number = 1;
|
||||
private readonly _channels: Map<string, AbstractExtHostOutputChannel> = new Map<string, AbstractExtHostOutputChannel>();
|
||||
private readonly _visibleChannelDisposable = new MutableDisposable();
|
||||
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
@@ -58,12 +61,23 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
|
||||
this._logsLocation = initData.logsLocation;
|
||||
}
|
||||
|
||||
$setVisibleChannel(channelId: string): void {
|
||||
if (channelId) {
|
||||
const channel = this._channels.get(channelId);
|
||||
if (channel) {
|
||||
this._visibleChannelDisposable.value = channel.onDidAppend(() => channel.update());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createOutputChannel(name: string): vscode.OutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
}
|
||||
return new LazyOutputChannel(name, this._doCreateOutChannel(name));
|
||||
const extHostOutputChannel = this._doCreateOutChannel(name);
|
||||
extHostOutputChannel.then(channel => channel._id.then(id => this._channels.set(id, channel)));
|
||||
return new LazyOutputChannel(name, extHostOutputChannel);
|
||||
}
|
||||
|
||||
private async _doCreateOutChannel(name: string): Promise<AbstractExtHostOutputChannel> {
|
||||
|
||||
@@ -29,8 +29,8 @@ export class ExtHostSearch implements ExtHostSearchShape {
|
||||
private readonly _fileSearchUsedSchemes = new Set<string>();
|
||||
private _handlePool: number = 0;
|
||||
|
||||
private _internalFileSearchHandle: number;
|
||||
private _internalFileSearchProvider: SearchService | null;
|
||||
private _internalFileSearchHandle: number = -1;
|
||||
private _internalFileSearchProvider: SearchService | null = null;
|
||||
|
||||
private _fileSearchManager: FileSearchManager;
|
||||
|
||||
|
||||
@@ -357,7 +357,7 @@ interface HandlerData {
|
||||
|
||||
export class ExtHostTask implements ExtHostTaskShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _proxy: MainThreadTaskShape;
|
||||
private readonly _workspaceProvider: IExtHostWorkspaceProvider;
|
||||
@@ -662,6 +662,10 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> {
|
||||
return this._terminalService.$requestDefaultShellAndArgs(true);
|
||||
}
|
||||
|
||||
private nextHandle(): number {
|
||||
return this._handleCounter++;
|
||||
}
|
||||
|
||||
@@ -9,223 +9,28 @@ import * as os from 'os';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { BaseExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export class BaseExtHostTerminal {
|
||||
public _id: number | undefined;
|
||||
protected _idPromise: Promise<number>;
|
||||
private _idPromiseComplete: ((value: number) => any) | undefined;
|
||||
private _disposed: boolean = false;
|
||||
private _queuedRequests: ApiRequest[] = [];
|
||||
export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
|
||||
constructor(
|
||||
protected _proxy: MainThreadTerminalServiceShape,
|
||||
id?: number
|
||||
) {
|
||||
this._idPromise = new Promise<number>(c => {
|
||||
if (id !== undefined) {
|
||||
this._id = id;
|
||||
c(id);
|
||||
} else {
|
||||
this._idPromiseComplete = c;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (!this._disposed) {
|
||||
this._disposed = true;
|
||||
this._queueApiRequest(this._proxy.$dispose, []);
|
||||
}
|
||||
}
|
||||
|
||||
protected _checkDisposed() {
|
||||
if (this._disposed) {
|
||||
throw new Error('Terminal has already been disposed');
|
||||
}
|
||||
}
|
||||
|
||||
protected _queueApiRequest(callback: (...args: any[]) => void, args: any[]): void {
|
||||
const request: ApiRequest = new ApiRequest(callback, args);
|
||||
if (!this._id) {
|
||||
this._queuedRequests.push(request);
|
||||
return;
|
||||
}
|
||||
request.run(this._proxy, this._id);
|
||||
}
|
||||
|
||||
public _runQueuedRequests(id: number): void {
|
||||
this._id = id;
|
||||
if (this._idPromiseComplete) {
|
||||
this._idPromiseComplete(id);
|
||||
this._idPromiseComplete = undefined;
|
||||
}
|
||||
this._queuedRequests.forEach((r) => {
|
||||
r.run(this._proxy, id);
|
||||
});
|
||||
this._queuedRequests.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal {
|
||||
private _pidPromise: Promise<number | undefined>;
|
||||
private _cols: number | undefined;
|
||||
private _pidPromiseComplete: ((value: number | undefined) => any) | undefined;
|
||||
private _rows: number | undefined;
|
||||
|
||||
/** @deprecated */
|
||||
private readonly _onData = new Emitter<string>();
|
||||
/** @deprecated */
|
||||
public get onDidWriteData(): Event<string> {
|
||||
// Tell the main side to start sending data if it's not already
|
||||
this._idPromise.then(id => {
|
||||
this._proxy.$registerOnDataListener(id);
|
||||
});
|
||||
return this._onData.event;
|
||||
}
|
||||
|
||||
public isOpen: boolean = false;
|
||||
|
||||
constructor(
|
||||
proxy: MainThreadTerminalServiceShape,
|
||||
private _name?: string,
|
||||
id?: number
|
||||
) {
|
||||
super(proxy, id);
|
||||
this._pidPromise = new Promise<number>(c => this._pidPromiseComplete = c);
|
||||
}
|
||||
|
||||
public async create(
|
||||
shellPath?: string,
|
||||
shellArgs?: string[] | string,
|
||||
cwd?: string | URI,
|
||||
env?: { [key: string]: string | null },
|
||||
waitOnExit?: boolean,
|
||||
strictEnv?: boolean,
|
||||
hideFromUser?: boolean
|
||||
): Promise<void> {
|
||||
const terminal = await this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser });
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
}
|
||||
|
||||
public async createExtensionTerminal(): Promise<number> {
|
||||
const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true });
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
return terminal.id;
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this._name || '';
|
||||
}
|
||||
|
||||
public set name(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public get dimensions(): vscode.TerminalDimensions | undefined {
|
||||
if (this._cols === undefined || this._rows === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
columns: this._cols,
|
||||
rows: this._rows
|
||||
};
|
||||
}
|
||||
|
||||
public setDimensions(cols: number, rows: number): boolean {
|
||||
if (cols === this._cols && rows === this._rows) {
|
||||
// Nothing changed
|
||||
return false;
|
||||
}
|
||||
this._cols = cols;
|
||||
this._rows = rows;
|
||||
return true;
|
||||
}
|
||||
|
||||
public get processId(): Promise<number | undefined> {
|
||||
return this._pidPromise;
|
||||
}
|
||||
|
||||
public sendText(text: string, addNewLine: boolean = true): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$sendText, [text, addNewLine]);
|
||||
}
|
||||
|
||||
public show(preserveFocus: boolean): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$show, [preserveFocus]);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$hide, []);
|
||||
}
|
||||
|
||||
public _setProcessId(processId: number | undefined): void {
|
||||
// The event may fire 2 times when the panel is restored
|
||||
if (this._pidPromiseComplete) {
|
||||
this._pidPromiseComplete(processId);
|
||||
this._pidPromiseComplete = undefined;
|
||||
} else {
|
||||
// Recreate the promise if this is the nth processId set (e.g. reused task terminals)
|
||||
this._pidPromise.then(pid => {
|
||||
if (pid !== processId) {
|
||||
this._pidPromise = Promise.resolve(processId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public _fireOnData(data: string): void {
|
||||
this._onData.fire(data);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
|
||||
private _proxy: MainThreadTerminalServiceShape;
|
||||
private _activeTerminal: ExtHostTerminal | undefined;
|
||||
private _terminals: ExtHostTerminal[] = [];
|
||||
private _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
|
||||
private _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
|
||||
private _variableResolver: ExtHostVariableResolverService | undefined;
|
||||
private _lastActiveWorkspace: IWorkspaceFolder | undefined;
|
||||
|
||||
// TODO: Pull this from main side
|
||||
private _isWorkspaceShellAllowed: boolean = false;
|
||||
|
||||
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
|
||||
public get terminals(): ExtHostTerminal[] { return this._terminals; }
|
||||
|
||||
private readonly _onDidCloseTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
|
||||
public get onDidCloseTerminal(): Event<vscode.Terminal> { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; }
|
||||
private readonly _onDidOpenTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
|
||||
public get onDidOpenTerminal(): Event<vscode.Terminal> { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; }
|
||||
private readonly _onDidChangeActiveTerminal: Emitter<vscode.Terminal | undefined> = new Emitter<vscode.Terminal | undefined>();
|
||||
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
|
||||
private readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
|
||||
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
|
||||
private readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
|
||||
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
|
||||
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
@IExtHostConfiguration private _extHostConfiguration: ExtHostConfiguration,
|
||||
@@ -233,11 +38,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
|
||||
@IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||
@ILogService private _logService: ILogService
|
||||
) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
|
||||
this._onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
|
||||
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
|
||||
onLastListenerRemove: () => this._proxy.$stopSendingDataEvents()
|
||||
});
|
||||
super(extHostRpc);
|
||||
this._updateLastActiveWorkspace();
|
||||
this._updateVariableResolver();
|
||||
this._registerListeners();
|
||||
@@ -257,23 +58,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
|
||||
return terminal;
|
||||
}
|
||||
|
||||
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options.name);
|
||||
const p = new ExtHostPseudoterminal(options.pty);
|
||||
terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p));
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
}
|
||||
|
||||
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
|
||||
const terminal = this._getTerminalByIdEventually(id);
|
||||
if (!terminal) {
|
||||
throw new Error(`Cannot resolve terminal with id ${id} for virtual process`);
|
||||
}
|
||||
const p = new ExtHostPseudoterminal(pty);
|
||||
this._setupExtHostProcessListeners(id, p);
|
||||
}
|
||||
|
||||
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
@@ -305,116 +89,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
|
||||
return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed, useAutomationShell, this._lastActiveWorkspace, this._variableResolver, this._logService);
|
||||
}
|
||||
|
||||
public async $acceptActiveTerminalChanged(id: number | null): Promise<void> {
|
||||
const original = this._activeTerminal;
|
||||
if (id === null) {
|
||||
this._activeTerminal = undefined;
|
||||
if (original !== this._activeTerminal) {
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
this._activeTerminal = terminal;
|
||||
if (original !== this._activeTerminal) {
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
terminal._fireOnData(data);
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalProcessData2(id: number, data: string): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
this._onDidWriteTerminalData.fire({ terminal, data });
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
if (terminal.setDimensions(cols, rows)) {
|
||||
this._onDidChangeTerminalDimensions.fire({
|
||||
terminal: terminal,
|
||||
dimensions: terminal.dimensions as vscode.TerminalDimensions
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
|
||||
if (this._terminalProcesses[id]) {
|
||||
// Extension pty terminal only - when virtual process resize fires it means that the
|
||||
// terminal's maximum dimensions changed
|
||||
this._terminalProcesses[id].resize(cols, rows);
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalTitleChange(id: number, name: string): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
const extHostTerminal = this._getTerminalObjectById(this.terminals, id);
|
||||
if (extHostTerminal) {
|
||||
extHostTerminal.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalClosed(id: number): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
const index = this._getTerminalObjectIndexById(this.terminals, id);
|
||||
if (index !== null) {
|
||||
const terminal = this._terminals.splice(index, 1)[0];
|
||||
this._onDidCloseTerminal.fire(terminal);
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalOpened(id: number, name: string): void {
|
||||
const index = this._getTerminalObjectIndexById(this._terminals, id);
|
||||
if (index !== null) {
|
||||
// The terminal has already been created (via createTerminal*), only fire the event
|
||||
this._onDidOpenTerminal.fire(this.terminals[index]);
|
||||
this.terminals[index].isOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const terminal = new ExtHostTerminal(this._proxy, name, id);
|
||||
this._terminals.push(terminal);
|
||||
this._onDidOpenTerminal.fire(terminal);
|
||||
terminal.isOpen = true;
|
||||
}
|
||||
|
||||
public async $acceptTerminalProcessId(id: number, processId: number): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
terminal._setProcessId(processId);
|
||||
}
|
||||
}
|
||||
|
||||
public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
|
||||
// TODO: Use await this._getTerminalByIdEventually(id);
|
||||
let terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
callback(terminal);
|
||||
} else {
|
||||
// Retry one more time in case the terminal has not yet been initialized.
|
||||
setTimeout(() => {
|
||||
terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
callback(terminal);
|
||||
}
|
||||
}, EXT_HOST_CREATION_DELAY * 2);
|
||||
}
|
||||
}
|
||||
|
||||
private _apiInspectConfigToPlain<T>(
|
||||
config: { key: string; defaultValue?: T; globalValue?: T; workspaceValue?: T, workspaceFolderValue?: T } | undefined
|
||||
): { user: T | undefined, value: T | undefined, default: T | undefined } {
|
||||
@@ -508,7 +182,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
|
||||
this._variableResolver,
|
||||
isWorkspaceShellAllowed,
|
||||
pkg.version,
|
||||
terminalConfig.get<boolean>('setLocaleVariables', false),
|
||||
terminalConfig.get<'auto' | 'off' | 'on'>('detectLocale', 'auto'),
|
||||
baseEnv
|
||||
);
|
||||
|
||||
@@ -521,86 +195,6 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
|
||||
this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService));
|
||||
}
|
||||
|
||||
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<void> {
|
||||
// Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
|
||||
// Pseudoterminal.start
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (!terminal) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for onDidOpenTerminal to fire
|
||||
let openPromise: Promise<void>;
|
||||
if (terminal.isOpen) {
|
||||
openPromise = Promise.resolve();
|
||||
} else {
|
||||
openPromise = new Promise<void>(r => {
|
||||
// Ensure open is called after onDidOpenTerminal
|
||||
const listener = this.onDidOpenTerminal(async e => {
|
||||
if (e === terminal) {
|
||||
listener.dispose();
|
||||
r();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
await openPromise;
|
||||
|
||||
// Processes should be initialized here for normal virtual process terminals, however for
|
||||
// tasks they are responsible for attaching the virtual process to a terminal so this
|
||||
// function may be called before tasks is able to attach to the terminal.
|
||||
let retries = 5;
|
||||
while (retries-- > 0) {
|
||||
if (this._terminalProcesses[id]) {
|
||||
(this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions);
|
||||
return;
|
||||
}
|
||||
await timeout(50);
|
||||
}
|
||||
}
|
||||
|
||||
private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
|
||||
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
|
||||
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
|
||||
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
|
||||
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode));
|
||||
if (p.onProcessOverrideDimensions) {
|
||||
p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e));
|
||||
}
|
||||
this._terminalProcesses[id] = p;
|
||||
}
|
||||
|
||||
public $acceptProcessInput(id: number, data: string): void {
|
||||
this._terminalProcesses[id].input(data);
|
||||
}
|
||||
|
||||
public $acceptProcessResize(id: number, cols: number, rows: number): void {
|
||||
try {
|
||||
this._terminalProcesses[id].resize(cols, rows);
|
||||
} catch (error) {
|
||||
// We tried to write to a closed pipe / channel.
|
||||
if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') {
|
||||
throw (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptProcessShutdown(id: number, immediate: boolean): void {
|
||||
this._terminalProcesses[id].shutdown(immediate);
|
||||
}
|
||||
|
||||
public $acceptProcessRequestInitialCwd(id: number): void {
|
||||
this._terminalProcesses[id].getInitialCwd().then(initialCwd => this._proxy.$sendProcessInitialCwd(id, initialCwd));
|
||||
}
|
||||
|
||||
public $acceptProcessRequestCwd(id: number): void {
|
||||
this._terminalProcesses[id].getCwd().then(cwd => this._proxy.$sendProcessCwd(id, cwd));
|
||||
}
|
||||
|
||||
public $acceptProcessRequestLatency(id: number): number {
|
||||
return id;
|
||||
}
|
||||
|
||||
public $requestAvailableShells(): Promise<IShellDefinitionDto[]> {
|
||||
return detectAvailableShells();
|
||||
}
|
||||
@@ -613,138 +207,7 @@ export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostT
|
||||
});
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number): void {
|
||||
// Remove process reference
|
||||
delete this._terminalProcesses[id];
|
||||
|
||||
// Send exit event to main side
|
||||
this._proxy.$sendProcessExit(id, exitCode);
|
||||
}
|
||||
|
||||
// TODO: This could be improved by using a single promise and resolve it when the terminal is ready
|
||||
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal | undefined> {
|
||||
if (!this._getTerminalPromises[id]) {
|
||||
this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries);
|
||||
} else {
|
||||
this._getTerminalPromises[id].then(c => {
|
||||
return this._createGetTerminalPromise(id, retries);
|
||||
});
|
||||
}
|
||||
return this._getTerminalPromises[id];
|
||||
}
|
||||
|
||||
private _createGetTerminalPromise(id: number, retries: number = 5): Promise<ExtHostTerminal> {
|
||||
return new Promise(c => {
|
||||
if (retries === 0) {
|
||||
c(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
c(terminal);
|
||||
} else {
|
||||
// This should only be needed immediately after createTerminalRenderer is called as
|
||||
// the ExtHostTerminal has not yet been iniitalized
|
||||
timeout(200).then(() => c(this._createGetTerminalPromise(id, retries - 1)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _getTerminalById(id: number): ExtHostTerminal | null {
|
||||
return this._getTerminalObjectById(this._terminals, id);
|
||||
}
|
||||
|
||||
private _getTerminalObjectById<T extends ExtHostTerminal>(array: T[], id: number): T | null {
|
||||
const index = this._getTerminalObjectIndexById(array, id);
|
||||
return index !== null ? array[index] : null;
|
||||
}
|
||||
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: number): number | null {
|
||||
let index: number | null = null;
|
||||
array.some((item, i) => {
|
||||
const thisId = item._id;
|
||||
if (thisId === id) {
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return index;
|
||||
}
|
||||
|
||||
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
|
||||
this._isWorkspaceShellAllowed = isAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
class ApiRequest {
|
||||
private _callback: (...args: any[]) => void;
|
||||
private _args: any[];
|
||||
|
||||
constructor(callback: (...args: any[]) => void, args: any[]) {
|
||||
this._callback = callback;
|
||||
this._args = args;
|
||||
}
|
||||
|
||||
public run(proxy: MainThreadTerminalServiceShape, id: number) {
|
||||
this._callback.apply(proxy, [id].concat(this._args));
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
private readonly _onProcessData = new Emitter<string>();
|
||||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = new Emitter<number>();
|
||||
public readonly onProcessExit: Event<number> = this._onProcessExit.event;
|
||||
private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>();
|
||||
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = new Emitter<string>();
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
|
||||
constructor(private readonly _pty: vscode.Pseudoterminal) { }
|
||||
|
||||
shutdown(): void {
|
||||
this._pty.close();
|
||||
}
|
||||
|
||||
input(data: string): void {
|
||||
if (this._pty.handleInput) {
|
||||
this._pty.handleInput(data);
|
||||
}
|
||||
}
|
||||
|
||||
resize(cols: number, rows: number): void {
|
||||
if (this._pty.setDimensions) {
|
||||
this._pty.setDimensions({ columns: cols, rows });
|
||||
}
|
||||
}
|
||||
|
||||
getInitialCwd(): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
getCwd(): Promise<string> {
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
getLatency(): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
|
||||
// Attach the listeners
|
||||
this._pty.onDidWrite(e => this._onProcessData.fire(e));
|
||||
if (this._pty.onDidClose) {
|
||||
this._pty.onDidClose(e => this._onProcessExit.fire(e || 0));
|
||||
}
|
||||
if (this._pty.onDidOverrideDimensions) {
|
||||
this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
this._pty.open(initialDimensions ? initialDimensions : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,74 +6,10 @@
|
||||
import { createApiFactoryAndRegisterActors } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} replace with ours
|
||||
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||
import { endsWith, startsWith } from 'vs/base/common/strings';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
|
||||
|
||||
class ExportsTrap {
|
||||
|
||||
static readonly Instance = new ExportsTrap();
|
||||
|
||||
private readonly _names: string[] = [];
|
||||
private readonly _exports = new Map<string, any>();
|
||||
|
||||
private constructor() {
|
||||
|
||||
const exportsProxy = new Proxy({}, {
|
||||
set: (target: any, p: PropertyKey, value: any) => {
|
||||
// store in target
|
||||
target[p] = value;
|
||||
// store in named-bucket
|
||||
const name = this._names[this._names.length - 1];
|
||||
this._exports.get(name)![p] = value;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const moduleProxy = new Proxy({}, {
|
||||
|
||||
get: (target: any, p: PropertyKey) => {
|
||||
if (p === 'exports') {
|
||||
return exportsProxy;
|
||||
}
|
||||
|
||||
return target[p];
|
||||
},
|
||||
|
||||
set: (target: any, p: PropertyKey, value: any) => {
|
||||
// store in target
|
||||
target[p] = value;
|
||||
|
||||
// override bucket
|
||||
if (p === 'exports') {
|
||||
const name = this._names[this._names.length - 1];
|
||||
this._exports.set(name, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
(<any>self).exports = exportsProxy;
|
||||
(<any>self).module = moduleProxy;
|
||||
}
|
||||
|
||||
add(name: string) {
|
||||
this._exports.set(name, Object.create(null));
|
||||
this._names.push(name);
|
||||
|
||||
return {
|
||||
claim: () => {
|
||||
const result = this._exports.get(name);
|
||||
this._exports.delete(name);
|
||||
this._names.pop();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class WorkerRequireInterceptor extends RequireInterceptor {
|
||||
|
||||
_installInterceptor() { }
|
||||
@@ -105,43 +41,33 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
||||
await this._fakeModules.install();
|
||||
}
|
||||
|
||||
protected _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||
protected async _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||
|
||||
(<any>self).window = self; // <- that's improper but might help extensions that aren't authored correctly
|
||||
module = module.with({ path: ensureSuffix(module.path, '.js') });
|
||||
const response = await fetch(module.toString(true));
|
||||
|
||||
// FAKE require function that only works for the vscode-module
|
||||
const moduleStack: URI[] = [];
|
||||
(<any>self).require = (mod: string) => {
|
||||
if (response.status !== 200) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
|
||||
const parent = moduleStack[moduleStack.length - 1];
|
||||
const result = this._fakeModules.getModule(mod, parent);
|
||||
// fetch JS sources as text and create a new function around it
|
||||
const initFn = new Function('module', 'exports', 'require', 'window', await response.text());
|
||||
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
// define commonjs globals: `module`, `exports`, and `require`
|
||||
const _exports = {};
|
||||
const _module = { exports: _exports };
|
||||
const _require = (request: string) => {
|
||||
const result = this._fakeModules.getModule(request, module);
|
||||
if (result === undefined) {
|
||||
throw new Error(`Cannot load module '${request}'`);
|
||||
}
|
||||
|
||||
if (!startsWith(mod, '.')) {
|
||||
throw new Error(`Cannot load module '${mod}'`);
|
||||
}
|
||||
|
||||
const next = joinPath(parent, '..', ensureSuffix(mod, '.js'));
|
||||
moduleStack.push(next);
|
||||
const trap = ExportsTrap.Instance.add(next.toString());
|
||||
importScripts(next.toString(true));
|
||||
moduleStack.pop();
|
||||
|
||||
return trap.claim();
|
||||
return result;
|
||||
};
|
||||
|
||||
try {
|
||||
activationTimesBuilder.codeLoadingStart();
|
||||
module = module.with({ path: ensureSuffix(module.path, '.js') });
|
||||
moduleStack.push(module);
|
||||
const trap = ExportsTrap.Instance.add(module.toString());
|
||||
importScripts(module.toString(true));
|
||||
moduleStack.pop();
|
||||
return Promise.resolve<T>(trap.claim());
|
||||
|
||||
initFn(_module, _exports, _require, self);
|
||||
return <T>(_module.exports !== _exports ? _module.exports : _exports);
|
||||
} finally {
|
||||
activationTimesBuilder.codeLoadingStop();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { localize } from 'vs/nls';
|
||||
|
||||
export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape {
|
||||
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _proxy: MainThreadLogShape;
|
||||
private readonly _logFile: UriComponents;
|
||||
|
||||
@@ -234,8 +234,7 @@ export class ToggleEditorVisibilityAction extends Action {
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
const hideEditor = this.layoutService.isVisible(Parts.EDITOR_PART);
|
||||
this.layoutService.setEditorHidden(hideEditor);
|
||||
this.layoutService.toggleMaximizedPanel();
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -701,14 +701,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
if (!start) {
|
||||
scope = undefined;
|
||||
} else {
|
||||
const selectedNode = tree.getNode(start);
|
||||
const parentNode = selectedNode.parent;
|
||||
|
||||
if (!parentNode || !parentNode.parent) { // root
|
||||
scope = undefined;
|
||||
} else {
|
||||
scope = parentNode.element;
|
||||
}
|
||||
scope = tree.getParentElement(start);
|
||||
}
|
||||
|
||||
const newSelection: unknown[] = [];
|
||||
|
||||
@@ -84,8 +84,8 @@ export abstract class Composite extends Component implements IComposite {
|
||||
this.visible = false;
|
||||
}
|
||||
|
||||
getTitle(): string | null {
|
||||
return null;
|
||||
getTitle(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected get telemetryService(): ITelemetryService {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { IWindowsConfiguration } from 'vs/platform/windows/common/windows';
|
||||
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext } from 'vs/workbench/common/editor';
|
||||
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorIsSaveableContext, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -21,6 +21,8 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform';
|
||||
import { PanelPositionContext } from 'vs/workbench/common/panel';
|
||||
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export const IsMacContext = new RawContextKey<boolean>('isMac', isMacintosh);
|
||||
export const IsLinuxContext = new RawContextKey<boolean>('isLinux', isLinux);
|
||||
@@ -52,6 +54,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
private inputFocusedContext: IContextKey<boolean>;
|
||||
|
||||
private activeEditorContext: IContextKey<string | null>;
|
||||
private activeEditorIsSaveable: IContextKey<boolean>;
|
||||
|
||||
private activeEditorGroupEmpty: IContextKey<boolean>;
|
||||
private activeEditorGroupIndex: IContextKey<number>;
|
||||
@@ -80,7 +83,8 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
@IEditorService private editorService: IEditorService,
|
||||
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
|
||||
@IWorkbenchLayoutService private layoutService: IWorkbenchLayoutService,
|
||||
@IViewletService private viewletService: IViewletService
|
||||
@IViewletService private viewletService: IViewletService,
|
||||
@IFileService private fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -142,6 +146,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
|
||||
// Editors
|
||||
this.activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
|
||||
this.activeEditorIsSaveable = ActiveEditorIsSaveableContext.bindTo(this.contextKeyService);
|
||||
this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
|
||||
this.textCompareEditorVisibleContext = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
|
||||
this.textCompareEditorActiveContext = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
|
||||
@@ -209,13 +214,18 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
this.multipleEditorGroupsContext.reset();
|
||||
}
|
||||
|
||||
this.activeEditorGroupIndex.set(activeGroup.index);
|
||||
this.activeEditorGroupIndex.set(activeGroup.index + 1); // not zero-indexed
|
||||
this.activeEditorGroupLast.set(activeGroup.index === groupCount - 1);
|
||||
|
||||
if (activeControl) {
|
||||
this.activeEditorContext.set(activeControl.getId());
|
||||
|
||||
const resource = toResource(activeControl.input, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const canSave = resource ? this.fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled : false;
|
||||
this.activeEditorIsSaveable.set(canSave);
|
||||
} else {
|
||||
this.activeEditorContext.reset();
|
||||
this.activeEditorIsSaveable.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -174,4 +174,4 @@ export const Extensions = {
|
||||
Editors: 'workbench.contributions.editors'
|
||||
};
|
||||
|
||||
Registry.add(Extensions.Editors, new EditorRegistry());
|
||||
Registry.add(Extensions.Editors, new EditorRegistry());
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IDecorationsService, IResourceDecorationChangeEvent, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
import { IDecorationsService, IResourceDecorationChangeEvent } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { FileKind, FILES_ASSOCIATIONS_CONFIG, IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
@@ -34,7 +34,7 @@ export interface IResourceLabelProps {
|
||||
|
||||
export interface IResourceLabelOptions extends IIconLabelValueOptions {
|
||||
fileKind?: FileKind;
|
||||
fileDecorations?: { colors: boolean, badges: boolean, data?: IDecorationData };
|
||||
fileDecorations?: { colors: boolean, badges: boolean };
|
||||
descriptionVerbosity?: Verbosity;
|
||||
}
|
||||
|
||||
@@ -468,8 +468,7 @@ class ResourceLabelWidget extends IconLabel {
|
||||
if (this.options && this.options.fileDecorations && resource) {
|
||||
const deco = this.decorationsService.getDecoration(
|
||||
resource,
|
||||
this.options.fileKind !== FileKind.FILE,
|
||||
this.options.fileDecorations.data
|
||||
this.options.fileKind !== FileKind.FILE
|
||||
);
|
||||
|
||||
if (deco) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
|
||||
import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { LifecyclePhase, StartupKind, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
@@ -60,6 +60,8 @@ enum Storage {
|
||||
PANEL_SIZE = 'workbench.panel.size',
|
||||
PANEL_SIZE_BEFORE_MAXIMIZED = 'workbench.panel.sizeBeforeMaximized',
|
||||
|
||||
EDITOR_HIDDEN = 'workbench.editor.hidden',
|
||||
|
||||
ZEN_MODE_ENABLED = 'workbench.zenmode.active',
|
||||
CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active',
|
||||
|
||||
@@ -78,7 +80,7 @@ enum Classes {
|
||||
|
||||
export abstract class Layout extends Disposable implements IWorkbenchLayoutService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onTitleBarVisibilityChange: Event<void> = this._onTitleBarVisibilityChange.event;
|
||||
@@ -220,8 +222,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
private registerLayoutListeners(): void {
|
||||
|
||||
// Restore editor if hidden and it changes
|
||||
this._register(this.editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false)));
|
||||
this._register(this.editorGroupService.onDidActivateGroup(() => this.setEditorHidden(false)));
|
||||
const showEditorIfHidden = () => {
|
||||
if (this.state.editor.hidden) {
|
||||
this.toggleMaximizedPanel();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this._register(this.editorService.onDidVisibleEditorsChange(showEditorIfHidden));
|
||||
this._register(this.editorGroupService.onDidActivateGroup(showEditorIfHidden));
|
||||
|
||||
// Configuration changes
|
||||
this._register(this.configurationService.onDidChangeConfiguration(() => this.doUpdateLayoutConfiguration()));
|
||||
@@ -601,6 +610,23 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
return offset;
|
||||
}
|
||||
|
||||
getMaximumEditorDimensions(): Dimension {
|
||||
const takenWidth =
|
||||
(this.isVisible(Parts.ACTIVITYBAR_PART) ? this.activityBarPartView.minimumWidth : 0) +
|
||||
(this.isVisible(Parts.SIDEBAR_PART) ? this.sideBarPartView.minimumWidth : 0) +
|
||||
(this.isVisible(Parts.PANEL_PART) && this.state.panel.position === Position.RIGHT ? this.panelPartView.minimumWidth : 0);
|
||||
|
||||
const takenHeight =
|
||||
(this.isVisible(Parts.TITLEBAR_PART) ? this.titleBarPartView.minimumHeight : 0) +
|
||||
(this.isVisible(Parts.STATUSBAR_PART) ? this.statusBarPartView.minimumHeight : 0) +
|
||||
(this.isVisible(Parts.PANEL_PART) && this.state.panel.position === Position.BOTTOM ? this.panelPartView.minimumHeight : 0);
|
||||
|
||||
const availableWidth = this.dimension.width - takenWidth;
|
||||
const availableHeight = this.dimension.height - takenHeight;
|
||||
|
||||
return { width: availableWidth, height: availableHeight };
|
||||
}
|
||||
|
||||
getWorkbenchContainer(): HTMLElement {
|
||||
return this.parent;
|
||||
}
|
||||
@@ -617,7 +643,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
// To properly reset line numbers we need to read the configuration for each editor respecting it's uri.
|
||||
if (!lineNumbers && isCodeEditor(editor) && editor.hasModel()) {
|
||||
const model = editor.getModel();
|
||||
lineNumbers = this.configurationService.getValue('editor.lineNumbers', { resource: model.uri });
|
||||
lineNumbers = this.configurationService.getValue('editor.lineNumbers', { resource: model.uri, overrideIdentifier: model.getModeId() });
|
||||
}
|
||||
if (!lineNumbers) {
|
||||
lineNumbers = this.configurationService.getValue('editor.lineNumbers');
|
||||
@@ -769,16 +795,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
const sideBar = this.getPart(Parts.SIDEBAR_PART);
|
||||
const statusBar = this.getPart(Parts.STATUSBAR_PART);
|
||||
|
||||
// View references for all parts
|
||||
this.titleBarPartView = titleBar;
|
||||
this.sideBarPartView = sideBar;
|
||||
this.activityBarPartView = activityBar;
|
||||
this.editorPartView = editorPart;
|
||||
this.panelPartView = panelPart;
|
||||
this.statusBarPartView = statusBar;
|
||||
|
||||
if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
|
||||
|
||||
// View references for all parts
|
||||
this.titleBarPartView = titleBar;
|
||||
this.sideBarPartView = sideBar;
|
||||
this.activityBarPartView = activityBar;
|
||||
this.editorPartView = editorPart;
|
||||
this.panelPartView = panelPart;
|
||||
this.statusBarPartView = statusBar;
|
||||
|
||||
const viewMap = {
|
||||
[Parts.ACTIVITYBAR_PART]: this.activityBarPartView,
|
||||
[Parts.TITLEBAR_PART]: this.titleBarPartView,
|
||||
@@ -985,6 +1010,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
// Propagate to grid
|
||||
this.workbenchGrid.setViewVisible(this.editorPartView, !hidden);
|
||||
|
||||
// Remember in settings
|
||||
if (hidden) {
|
||||
this.storageService.store(Storage.EDITOR_HIDDEN, true, StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(Storage.EDITOR_HIDDEN, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
// The editor and panel cannot be hidden at the same time
|
||||
if (hidden && this.state.panel.hidden) {
|
||||
this.setPanelHidden(false, true);
|
||||
@@ -1110,7 +1142,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
if (this.workbenchGrid instanceof Grid) {
|
||||
const size = this.workbenchGrid.getViewSize(this.panelPartView);
|
||||
if (!this.isPanelMaximized()) {
|
||||
this.state.panel.sizeBeforeMaximize = this.state.panel.position === Position.BOTTOM ? size.height : size.width;
|
||||
if (this.state.panel.hidden) {
|
||||
this.state.panel.sizeBeforeMaximize = this.workbenchGrid.getViewCachedVisibleSize(this.panelPartView) || this.panelPartView.minimumHeight;
|
||||
} else {
|
||||
this.state.panel.sizeBeforeMaximize = this.state.panel.position === Position.BOTTOM ? size.height : size.width;
|
||||
}
|
||||
|
||||
this.storageService.store(Storage.PANEL_SIZE_BEFORE_MAXIMIZED, this.state.panel.sizeBeforeMaximize, StorageScope.GLOBAL);
|
||||
this.setEditorHidden(true);
|
||||
} else {
|
||||
@@ -1215,6 +1252,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
// At some point, we will not fall back to old keys from legacy layout, but for now, let's migrate the keys
|
||||
const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, this.storageService.getNumber('workbench.sidebar.width', StorageScope.GLOBAL, Math.min(workbenchDimensions.width / 4, 300))!);
|
||||
const panelSize = this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, this.storageService.getNumber(this.state.panel.position === Position.BOTTOM ? 'workbench.panel.height' : 'workbench.panel.width', StorageScope.GLOBAL, workbenchDimensions.height / 3));
|
||||
const wasEditorHidden = this.storageService.getBoolean(Storage.EDITOR_HIDDEN, StorageScope.WORKSPACE, false);
|
||||
|
||||
const titleBarHeight = this.titleBarPartView.minimumHeight;
|
||||
const statusBarHeight = this.statusBarPartView.minimumHeight;
|
||||
@@ -1246,7 +1284,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
const panelNode: ISerializedLeafNode = {
|
||||
type: 'leaf',
|
||||
data: { type: Parts.PANEL_PART },
|
||||
size: panelSize,
|
||||
size: wasEditorHidden ? this.state.panel.sizeBeforeMaximize : panelSize,
|
||||
visible: !this.state.panel.hidden
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
.monaco-workbench .part {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench .part > .title {
|
||||
|
||||
@@ -33,8 +33,8 @@ export abstract class Part extends Component implements ISerializableView {
|
||||
get dimension(): Dimension { return this._dimension; }
|
||||
|
||||
private parent: HTMLElement;
|
||||
private titleArea: HTMLElement | null;
|
||||
private contentArea: HTMLElement | null;
|
||||
private titleArea: HTMLElement | null = null;
|
||||
private contentArea: HTMLElement | null = null;
|
||||
private partLayout: PartLayout;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -14,7 +14,7 @@ import { GlobalActivityActionViewItem, ViewletActivityAction, ToggleViewletActio
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
@@ -48,7 +48,7 @@ interface ICachedViewlet {
|
||||
|
||||
export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private static readonly ACTION_HEIGHT = 48;
|
||||
private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets';
|
||||
@@ -198,6 +198,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
this.createGlobalActivityActionBar(globalActivities);
|
||||
|
||||
this.element.style.display = this.layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? null : 'none';
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -368,6 +370,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
.map(v => v.id);
|
||||
}
|
||||
|
||||
setVisible(visible: boolean): void {
|
||||
if (this.element) {
|
||||
this.element.style.display = visible ? null : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
layout(width: number, height: number): void {
|
||||
if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) {
|
||||
return;
|
||||
|
||||
@@ -32,7 +32,6 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { Dimension, append, $, addClass, hide, show, addClasses } from 'vs/base/browser/dom';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export interface ICompositeTitleLabel {
|
||||
|
||||
@@ -240,7 +239,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
// Update title with composite title if it differs from descriptor
|
||||
const descriptor = this.registry.getComposite(composite.getId());
|
||||
if (descriptor && descriptor.name !== composite.getTitle()) {
|
||||
this.updateTitle(composite.getId(), withNullAsUndefined(composite.getTitle()));
|
||||
this.updateTitle(composite.getId(), composite.getTitle());
|
||||
}
|
||||
|
||||
// Handle Composite Actions
|
||||
|
||||
@@ -41,8 +41,8 @@ export abstract class BaseEditor extends Panel implements IEditor {
|
||||
|
||||
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined> = Event.None;
|
||||
|
||||
protected _input: EditorInput | null;
|
||||
protected _options: EditorOptions | null;
|
||||
protected _input: EditorInput | undefined;
|
||||
protected _options: EditorOptions | undefined;
|
||||
|
||||
private _group?: IEditorGroup;
|
||||
|
||||
@@ -55,11 +55,11 @@ export abstract class BaseEditor extends Panel implements IEditor {
|
||||
super(id, telemetryService, themeService, storageService);
|
||||
}
|
||||
|
||||
get input(): EditorInput | null {
|
||||
get input(): EditorInput | undefined {
|
||||
return this._input;
|
||||
}
|
||||
|
||||
get options(): EditorOptions | null {
|
||||
get options(): EditorOptions | undefined {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ export abstract class BaseEditor extends Panel implements IEditor {
|
||||
* The provided cancellation token should be used to test if the operation
|
||||
* was cancelled.
|
||||
*/
|
||||
setInput(input: EditorInput, options: EditorOptions | null, token: CancellationToken): Promise<void> {
|
||||
setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
this._input = input;
|
||||
this._options = options;
|
||||
|
||||
@@ -90,8 +90,8 @@ export abstract class BaseEditor extends Panel implements IEditor {
|
||||
* resources associated with the input should be freed.
|
||||
*/
|
||||
clearInput(): void {
|
||||
this._input = null;
|
||||
this._options = null;
|
||||
this._input = undefined;
|
||||
this._options = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +101,7 @@ export abstract class BaseEditor extends Panel implements IEditor {
|
||||
* Sets the given options to the editor. Clients should apply the options
|
||||
* to the current input.
|
||||
*/
|
||||
setOptions(options: EditorOptions | null): void {
|
||||
setOptions(options: EditorOptions | undefined): void {
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
@@ -160,8 +160,8 @@ export abstract class BaseEditor extends Panel implements IEditor {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._input = null;
|
||||
this._options = null;
|
||||
this._input = undefined;
|
||||
this._options = undefined;
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
@@ -172,7 +172,7 @@ interface MapGroupToMemento<T> {
|
||||
}
|
||||
|
||||
export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
private cache: LRUCache<string, MapGroupToMemento<T>>;
|
||||
private cache: LRUCache<string, MapGroupToMemento<T>> | undefined;
|
||||
private cleanedUp = false;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -23,7 +23,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export interface IOpenCallbacks {
|
||||
openInternal: (input: EditorInput, options: EditorOptions) => Promise<void>;
|
||||
openInternal: (input: EditorInput, options: EditorOptions | undefined) => Promise<void>;
|
||||
openExternal: (uri: URI) => void;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
parent.appendChild(this.scrollbar.getDomNode());
|
||||
}
|
||||
|
||||
async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
await super.setInput(input, options, token);
|
||||
const model = await input.resolve();
|
||||
|
||||
@@ -102,7 +102,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
}, this.instantiationService);
|
||||
}
|
||||
|
||||
private async handleOpenInternalCallback(input: EditorInput, options: EditorOptions): Promise<void> {
|
||||
private async handleOpenInternalCallback(input: EditorInput, options: EditorOptions | undefined): Promise<void> {
|
||||
await this.callbacks.openInternal(input, options);
|
||||
|
||||
// Signal to listeners that the binary editor has been opened in-place
|
||||
|
||||
@@ -11,7 +11,7 @@ import { localize } from 'vs/nls';
|
||||
import { IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
|
||||
@@ -19,7 +19,7 @@ export const IBreadcrumbsService = createDecorator<IBreadcrumbsService>('IEditor
|
||||
|
||||
export interface IBreadcrumbsService {
|
||||
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
register(group: GroupIdentifier, widget: BreadcrumbsWidget): IDisposable;
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface IBreadcrumbsService {
|
||||
|
||||
export class BreadcrumbsService implements IBreadcrumbsService {
|
||||
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _map = new Map<number, BreadcrumbsWidget>();
|
||||
|
||||
|
||||
@@ -374,7 +374,7 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
|
||||
const labels = this._instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER /* TODO@Jo visibility propagation */);
|
||||
this._disposables.add(labels);
|
||||
|
||||
return this._instantiationService.createInstance(WorkbenchAsyncDataTree, container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), {
|
||||
return this._instantiationService.createInstance(WorkbenchAsyncDataTree, 'BreadcrumbsFilePicker', container, new FileVirtualDelegate(), [this._instantiationService.createInstance(FileRenderer, labels)], this._instantiationService.createInstance(FileDataSource), {
|
||||
multipleSelectionSupport: false,
|
||||
sorter: new FileSorter(),
|
||||
filter: this._instantiationService.createInstance(FileFilter),
|
||||
@@ -440,6 +440,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker {
|
||||
protected _createTree(container: HTMLElement) {
|
||||
return this._instantiationService.createInstance(
|
||||
WorkbenchDataTree,
|
||||
'BreadcrumbsOutlinePicker',
|
||||
container,
|
||||
new OutlineVirtualDelegate(),
|
||||
[new OutlineGroupRenderer(), this._instantiationService.createInstance(OutlineElementRenderer)],
|
||||
|
||||
@@ -52,6 +52,7 @@ import { toLocalResource } from 'vs/base/common/resources';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
|
||||
|
||||
// Register String Editor
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
@@ -234,7 +235,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEOLAction, Chang
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding');
|
||||
|
||||
export class QuickOpenActionContributor extends ActionBarContributor {
|
||||
private openToSideActionInstance: OpenToSideFromQuickOpenAction;
|
||||
private openToSideActionInstance: OpenToSideFromQuickOpenAction | undefined;
|
||||
|
||||
constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) {
|
||||
super();
|
||||
@@ -417,12 +418,12 @@ editorCommands.setup();
|
||||
// Touch Bar
|
||||
if (isMacintosh) {
|
||||
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
|
||||
command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/back-tb.png')) } },
|
||||
command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconLocation: { dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/back-tb.png')) } },
|
||||
group: 'navigation'
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
|
||||
command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/forward-tb.png')) } },
|
||||
command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconLocation: { dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/forward-tb.png')) } },
|
||||
group: 'navigation'
|
||||
});
|
||||
}
|
||||
@@ -452,7 +453,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
|
||||
|
||||
interface IEditorToolItem { id: string; title: string; iconDark: string; iconLight: string; }
|
||||
interface IEditorToolItem { id: string; title: string; iconDark: URI; iconLight: URI; }
|
||||
|
||||
function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | undefined, order: number, alternative?: IEditorToolItem): void {
|
||||
const item: IMenuItem = {
|
||||
@@ -460,8 +461,8 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u
|
||||
id: primary.id,
|
||||
title: primary.title,
|
||||
iconLocation: {
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${primary.iconDark}`)),
|
||||
light: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${primary.iconLight}`))
|
||||
dark: primary.iconDark,
|
||||
light: primary.iconLight
|
||||
}
|
||||
},
|
||||
group: 'navigation',
|
||||
@@ -474,8 +475,8 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u
|
||||
id: alternative.id,
|
||||
title: alternative.title,
|
||||
iconLocation: {
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${alternative.iconDark}`)),
|
||||
light: URI.parse(require.toUrl(`vs/workbench/browser/parts/editor/media/${alternative.iconLight}`))
|
||||
dark: alternative.iconDark,
|
||||
light: alternative.iconLight
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -483,21 +484,26 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | u
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, item);
|
||||
}
|
||||
|
||||
const SPLIT_EDITOR_HORIZONTAL_DARK_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-dark.svg'));
|
||||
const SPLIT_EDITOR_HORIZONTAL_LIGHT_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-horizontal-light.svg'));
|
||||
const SPLIT_EDITOR_VERTICAL_DARK_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-dark.svg'));
|
||||
const SPLIT_EDITOR_VERTICAL_LIGHT_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/split-editor-vertical-light.svg'));
|
||||
|
||||
// Editor Title Menu: Split Editor
|
||||
appendEditorToolItem(
|
||||
{
|
||||
id: SplitEditorAction.ID,
|
||||
title: nls.localize('splitEditorRight', "Split Editor Right"),
|
||||
iconDark: 'split-editor-horizontal-dark.svg',
|
||||
iconLight: 'split-editor-horizontal-light.svg'
|
||||
iconDark: SPLIT_EDITOR_HORIZONTAL_DARK_ICON,
|
||||
iconLight: SPLIT_EDITOR_HORIZONTAL_LIGHT_ICON
|
||||
},
|
||||
ContextKeyExpr.not('splitEditorsVertically'),
|
||||
100000, // towards the end
|
||||
{
|
||||
id: editorCommands.SPLIT_EDITOR_DOWN,
|
||||
title: nls.localize('splitEditorDown', "Split Editor Down"),
|
||||
iconDark: 'split-editor-vertical-dark.svg',
|
||||
iconLight: 'split-editor-vertical-light.svg'
|
||||
iconDark: SPLIT_EDITOR_VERTICAL_DARK_ICON,
|
||||
iconLight: SPLIT_EDITOR_VERTICAL_LIGHT_ICON
|
||||
}
|
||||
);
|
||||
|
||||
@@ -505,34 +511,37 @@ appendEditorToolItem(
|
||||
{
|
||||
id: SplitEditorAction.ID,
|
||||
title: nls.localize('splitEditorDown', "Split Editor Down"),
|
||||
iconDark: 'split-editor-vertical-dark.svg',
|
||||
iconLight: 'split-editor-vertical-light.svg'
|
||||
iconDark: SPLIT_EDITOR_VERTICAL_DARK_ICON,
|
||||
iconLight: SPLIT_EDITOR_VERTICAL_LIGHT_ICON
|
||||
},
|
||||
ContextKeyExpr.has('splitEditorsVertically'),
|
||||
100000, // towards the end
|
||||
{
|
||||
id: editorCommands.SPLIT_EDITOR_RIGHT,
|
||||
title: nls.localize('splitEditorRight', "Split Editor Right"),
|
||||
iconDark: 'split-editor-horizontal-dark.svg',
|
||||
iconLight: 'split-editor-horizontal-light.svg'
|
||||
iconDark: SPLIT_EDITOR_HORIZONTAL_DARK_ICON,
|
||||
iconLight: SPLIT_EDITOR_HORIZONTAL_LIGHT_ICON
|
||||
}
|
||||
);
|
||||
|
||||
const CLOSE_ALL_DARK_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-dark.svg'));
|
||||
const CLOSE_ALL_LIGHT_ICON = URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-all-light.svg'));
|
||||
|
||||
// Editor Title Menu: Close Group (tabs disabled)
|
||||
appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('close', "Close"),
|
||||
iconDark: 'close-dark-alt.svg',
|
||||
iconLight: 'close-light-alt.svg'
|
||||
iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dark-alt.svg')),
|
||||
iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-light-alt.svg'))
|
||||
},
|
||||
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ContextKeyExpr.not('groupActiveEditorDirty')),
|
||||
1000000, // towards the far end
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
|
||||
title: nls.localize('closeAll', "Close All"),
|
||||
iconDark: 'close-all-dark.svg',
|
||||
iconLight: 'close-all-light.svg'
|
||||
iconDark: CLOSE_ALL_DARK_ICON,
|
||||
iconLight: CLOSE_ALL_LIGHT_ICON
|
||||
}
|
||||
);
|
||||
|
||||
@@ -540,16 +549,16 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
|
||||
title: nls.localize('close', "Close"),
|
||||
iconDark: 'close-dirty-dark-alt.svg',
|
||||
iconLight: 'close-dirty-light-alt.svg'
|
||||
iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dirty-dark-alt.svg')),
|
||||
iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/close-dirty-light-alt.svg'))
|
||||
},
|
||||
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ContextKeyExpr.has('groupActiveEditorDirty')),
|
||||
1000000, // towards the far end
|
||||
{
|
||||
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
|
||||
title: nls.localize('closeAll', "Close All"),
|
||||
iconDark: 'close-all-dark.svg',
|
||||
iconLight: 'close-all-light.svg'
|
||||
iconDark: CLOSE_ALL_DARK_ICON,
|
||||
iconLight: CLOSE_ALL_LIGHT_ICON
|
||||
}
|
||||
);
|
||||
|
||||
@@ -558,8 +567,8 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.GOTO_PREVIOUS_CHANGE,
|
||||
title: nls.localize('navigate.prev.label', "Previous Change"),
|
||||
iconDark: 'previous-diff-dark.svg',
|
||||
iconLight: 'previous-diff-light.svg'
|
||||
iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/previous-diff-dark.svg')),
|
||||
iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/previous-diff-light.svg'))
|
||||
},
|
||||
TextCompareEditorActiveContext,
|
||||
10
|
||||
@@ -570,8 +579,8 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.GOTO_NEXT_CHANGE,
|
||||
title: nls.localize('navigate.next.label', "Next Change"),
|
||||
iconDark: 'next-diff-dark.svg',
|
||||
iconLight: 'next-diff-light.svg'
|
||||
iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/next-diff-dark.svg')),
|
||||
iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/next-diff-light.svg'))
|
||||
},
|
||||
TextCompareEditorActiveContext,
|
||||
11
|
||||
@@ -582,8 +591,8 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
|
||||
title: nls.localize('ignoreTrimWhitespace.label', "Ignore Trim Whitespace"),
|
||||
iconDark: 'paragraph-dark.svg',
|
||||
iconLight: 'paragraph-light.svg'
|
||||
iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-dark.svg')),
|
||||
iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-light.svg'))
|
||||
},
|
||||
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', true)),
|
||||
20
|
||||
@@ -594,8 +603,8 @@ appendEditorToolItem(
|
||||
{
|
||||
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
|
||||
title: nls.localize('showTrimWhitespace.label', "Show Trim Whitespace"),
|
||||
iconDark: 'paragraph-disabled-dark.svg',
|
||||
iconLight: 'paragraph-disabled-light.svg'
|
||||
iconDark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-dark.svg')),
|
||||
iconLight: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/editor/media/paragraph-disabled-light.svg'))
|
||||
},
|
||||
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', false)),
|
||||
20
|
||||
|
||||
@@ -263,7 +263,10 @@ function registerDiffEditorCommands(): void {
|
||||
const candidates = [editorService.activeControl, ...editorService.visibleControls].filter(e => e instanceof TextDiffEditor);
|
||||
|
||||
if (candidates.length > 0) {
|
||||
next ? (<TextDiffEditor>candidates[0]).getDiffNavigator().next() : (<TextDiffEditor>candidates[0]).getDiffNavigator().previous();
|
||||
const navigator = (<TextDiffEditor>candidates[0]).getDiffNavigator();
|
||||
if (navigator) {
|
||||
next ? navigator.next() : navigator.previous();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progre
|
||||
import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
|
||||
export interface IOpenEditorResult {
|
||||
readonly control: BaseEditor;
|
||||
@@ -35,11 +34,11 @@ export class EditorControl extends Disposable {
|
||||
private _onDidSizeConstraintsChange = this._register(new Emitter<{ width: number; height: number; } | undefined>());
|
||||
get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return this._onDidSizeConstraintsChange.event; }
|
||||
|
||||
private _activeControl: BaseEditor | null;
|
||||
private _activeControl: BaseEditor | null = null;
|
||||
private controls: BaseEditor[] = [];
|
||||
|
||||
private readonly activeControlDisposables = this._register(new DisposableStore());
|
||||
private dimension: Dimension;
|
||||
private dimension: Dimension | undefined;
|
||||
private editorOperation: LongRunningOperation;
|
||||
|
||||
constructor(
|
||||
@@ -68,7 +67,7 @@ export class EditorControl extends Disposable {
|
||||
const control = this.doShowEditorControl(descriptor);
|
||||
|
||||
// Set input
|
||||
const editorChanged = await this.doSetInput(control, editor, withUndefinedAsNull(options));
|
||||
const editorChanged = await this.doSetInput(control, editor, options);
|
||||
return { control, editorChanged };
|
||||
}
|
||||
|
||||
@@ -151,7 +150,7 @@ export class EditorControl extends Disposable {
|
||||
this._onDidSizeConstraintsChange.fire(undefined);
|
||||
}
|
||||
|
||||
private async doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions | null): Promise<boolean> {
|
||||
private async doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions | undefined): Promise<boolean> {
|
||||
|
||||
// If the input did not change, return early and only apply the options
|
||||
// unless the options instruct us to force open it even if it is the same
|
||||
|
||||
@@ -25,11 +25,11 @@ class DropOverlay extends Themable {
|
||||
|
||||
private static OVERLAY_ID = 'monaco-workbench-editor-drop-overlay';
|
||||
|
||||
private container: HTMLElement;
|
||||
private overlay: HTMLElement;
|
||||
private container!: HTMLElement;
|
||||
private overlay!: HTMLElement;
|
||||
|
||||
private currentDropOperation?: IDropOperation;
|
||||
private _disposed: boolean;
|
||||
private currentDropOperation: IDropOperation | undefined;
|
||||
private _disposed: boolean | undefined;
|
||||
|
||||
private cleanupOverlayScheduler: RunOnceScheduler;
|
||||
|
||||
@@ -50,7 +50,7 @@ class DropOverlay extends Themable {
|
||||
}
|
||||
|
||||
get disposed(): boolean {
|
||||
return this._disposed;
|
||||
return !!this._disposed;
|
||||
}
|
||||
|
||||
private create(): void {
|
||||
|
||||
@@ -817,7 +817,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
this._onWillOpenEditor.fire(event);
|
||||
const prevented = event.isPrevented();
|
||||
if (prevented) {
|
||||
return prevented();
|
||||
return withUndefinedAsNull(await prevented());
|
||||
}
|
||||
|
||||
// Proceed with opening
|
||||
@@ -846,9 +846,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
if (options && options.activation === EditorActivation.ACTIVATE) {
|
||||
// Respect option to force activate an editor group.
|
||||
activateGroup = true;
|
||||
} else if (options && options.activation === EditorActivation.RESTORE) {
|
||||
// Respect option to force restore an editor group.
|
||||
restoreGroup = true;
|
||||
} else if (options && options.activation === EditorActivation.PRESERVE) {
|
||||
// Respect option to preserve active editor group.
|
||||
activateGroup = false;
|
||||
restoreGroup = false;
|
||||
} else if (openEditorOptions.active) {
|
||||
// Finally, we only activate/restore an editor which is
|
||||
// opening as active editor.
|
||||
@@ -1524,7 +1528,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
}
|
||||
|
||||
class EditorOpeningEvent implements IEditorOpeningEvent {
|
||||
private override: () => Promise<IEditor>;
|
||||
private override: () => Promise<IEditor | undefined>;
|
||||
|
||||
constructor(
|
||||
private _group: GroupIdentifier,
|
||||
@@ -1545,11 +1549,11 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
prevent(callback: () => Promise<IEditor>): void {
|
||||
prevent(callback: () => Promise<IEditor | undefined>): void {
|
||||
this.override = callback;
|
||||
}
|
||||
|
||||
isPrevented(): () => Promise<IEditor> {
|
||||
isPrevented(): () => Promise<IEditor | undefined> {
|
||||
return this.override;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Dimension, isAncestor, toggleClass, addClass, $ } from 'vs/base/browser
|
||||
import { Event, Emitter, Relay } from 'vs/base/common/event';
|
||||
import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, ICopyEditorOptions, GroupsOrder, GroupChangeKind, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid';
|
||||
import { GroupIdentifier, IWorkbenchEditorConfiguration, IEditorPartOptions } from 'vs/workbench/common/editor';
|
||||
import { values } from 'vs/base/common/map';
|
||||
@@ -81,7 +81,7 @@ class GridWidgetView<T extends IView> implements IView {
|
||||
|
||||
export class EditorPart extends Part implements IEditorGroupsService, IEditorGroupsAccessor {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private static readonly EDITOR_PART_UI_STATE_STORAGE_KEY = 'editorpart.state';
|
||||
private static readonly EDITOR_PART_CENTERED_VIEW_STORAGE_KEY = 'editorpart.centeredview';
|
||||
@@ -140,7 +140,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
|
||||
) {
|
||||
super(Parts.EDITOR_PART, { hasTitle: false }, themeService, storageService, layoutService);
|
||||
|
||||
@@ -780,14 +780,15 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
|
||||
//#region Part
|
||||
|
||||
get minimumWidth(): number { return this.centeredLayoutWidget.minimumWidth; }
|
||||
// TODO @sbatten @joao find something better to prevent editor taking over #79897
|
||||
get minimumWidth(): number { return Math.min(this.centeredLayoutWidget.minimumWidth, this.layoutService.getMaximumEditorDimensions().width); }
|
||||
get maximumWidth(): number { return this.centeredLayoutWidget.maximumWidth; }
|
||||
get minimumHeight(): number { return this.centeredLayoutWidget.minimumHeight; }
|
||||
get minimumHeight(): number { return Math.min(this.centeredLayoutWidget.minimumHeight, this.layoutService.getMaximumEditorDimensions().height); }
|
||||
get maximumHeight(): number { return this.centeredLayoutWidget.maximumHeight; }
|
||||
|
||||
readonly snap = true;
|
||||
|
||||
get onDidChange(): Event<IViewSize | undefined> { return this.centeredLayoutWidget.onDidChange; }
|
||||
get onDidChange(): Event<IViewSize | undefined> { return Event.any(this.centeredLayoutWidget.onDidChange, this.onDidSetGridWidget.event); }
|
||||
readonly priority: LayoutPriority = LayoutPriority.High;
|
||||
|
||||
private get gridSeparatorBorder(): Color {
|
||||
|
||||
@@ -35,7 +35,7 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c
|
||||
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ITextFileService, SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { ConfigurationChangedEvent, IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
@@ -328,7 +328,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
||||
if (!this.screenReaderNotification) {
|
||||
this.screenReaderNotification = this.notificationService.prompt(
|
||||
Severity.Info,
|
||||
nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate Azure Data Studio? (Certain features like folding, minimap or word wrap are disabled when using a screen reader)"),
|
||||
nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate Azure Data Studio? (Certain features like word wrap are disabled when using a screen reader)"), // {{SQL CARBON EDIT}} change vscode to ads
|
||||
[{
|
||||
label: nls.localize('screenReaderDetectedExplanation.answerYes', "Yes"),
|
||||
run: () => {
|
||||
@@ -586,8 +586,8 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
||||
if (activeCodeEditor) {
|
||||
|
||||
// Hook Listener for Configuration changes
|
||||
this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: IConfigurationChangedEvent) => {
|
||||
if (event.accessibilitySupport) {
|
||||
this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: ConfigurationChangedEvent) => {
|
||||
if (event.hasChanged(EditorOption.accessibilitySupport)) {
|
||||
this.onScreenReaderModeChange(activeCodeEditor);
|
||||
}
|
||||
}));
|
||||
@@ -711,7 +711,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
|
||||
screenReaderMode = (editorWidget.getConfiguration().accessibilitySupport === AccessibilitySupport.Enabled);
|
||||
screenReaderMode = (editorWidget.getOption(EditorOption.accessibilitySupport) === AccessibilitySupport.Enabled);
|
||||
}
|
||||
|
||||
if (screenReaderMode === false && this.screenReaderNotification) {
|
||||
@@ -761,7 +761,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
||||
private onEOLChange(editorWidget: ICodeEditor | undefined): void {
|
||||
const info: StateDelta = { EOL: undefined };
|
||||
|
||||
if (editorWidget && !editorWidget.getConfiguration().readOnly) {
|
||||
if (editorWidget && !editorWidget.getOption(EditorOption.readOnly)) {
|
||||
const codeEditorModel = editorWidget.getModel();
|
||||
if (codeEditorModel) {
|
||||
info.EOL = codeEditorModel.getEOL();
|
||||
@@ -822,8 +822,7 @@ function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean {
|
||||
if (!codeEditor) {
|
||||
return false;
|
||||
}
|
||||
const config = codeEditor.getConfiguration();
|
||||
return (!config.readOnly);
|
||||
return !codeEditor.getOption(EditorOption.readOnly);
|
||||
}
|
||||
|
||||
function isWritableBaseEditor(e: IBaseEditor): boolean {
|
||||
@@ -1169,7 +1168,7 @@ export class ChangeEncodingAction extends Action {
|
||||
|
||||
let guessedEncoding: string | undefined = undefined;
|
||||
if (this.fileService.canHandleResource(resource)) {
|
||||
const content = await this.textFileService.read(resource, { autoGuessEncoding: true, acceptTextOnly: true });
|
||||
const content = await this.textFileService.read(resource, { autoGuessEncoding: true });
|
||||
guessedEncoding = content.encoding;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle fill="#C5C5C5" cx="8" cy="8" r="4"/></svg>
|
||||
|
Before Width: | Height: | Size: 167 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle fill="#C5C5C5" cx="8" cy="8" r="4"/></svg>
|
||||
|
Before Width: | Height: | Size: 167 B |
@@ -81,6 +81,7 @@
|
||||
display: flex;
|
||||
flex: initial;
|
||||
opacity: 0.5;
|
||||
padding-right: 8px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,52 +12,6 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.monaco-resource-viewer.image {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.monaco-resource-viewer.image img {
|
||||
padding: 0;
|
||||
background-position: 0 0, 8px 8px;
|
||||
background-size: 16px 16px;
|
||||
}
|
||||
|
||||
.vs .monaco-resource-viewer.image img {
|
||||
background-image:
|
||||
linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)),
|
||||
linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230));
|
||||
}
|
||||
|
||||
.vs-dark .monaco-resource-viewer.image img {
|
||||
background-image:
|
||||
linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)),
|
||||
linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20));
|
||||
}
|
||||
|
||||
.monaco-resource-viewer img.pixelated {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.monaco-resource-viewer img.scale-to-fit {
|
||||
max-width: calc(100% - 20px);
|
||||
max-height: calc(100% - 20px);
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.monaco-resource-viewer img {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.monaco-resource-viewer.zoom-in {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.monaco-resource-viewer.zoom-out {
|
||||
cursor: zoom-out;
|
||||
}
|
||||
|
||||
.monaco-resource-viewer .embedded-link,
|
||||
.monaco-resource-viewer .embedded-link:hover {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions {
|
||||
cursor: default;
|
||||
flex: initial;
|
||||
padding-left: 4px;
|
||||
padding: 0 8px 0 4px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,25 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/resourceviewer';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as mimes from 'vs/base/common/mime';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IDisposable, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import 'vs/css!./media/resourceviewer';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { ICssStyleCollector, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { IMAGE_PREVIEW_BORDER } from 'vs/workbench/common/theme';
|
||||
|
||||
export interface IResourceDescriptor {
|
||||
@@ -94,11 +85,6 @@ export class ResourceViewer {
|
||||
// Ensure CSS class
|
||||
container.className = 'monaco-resource-viewer';
|
||||
|
||||
// Images
|
||||
if (ResourceViewer.isImageResource(descriptor)) {
|
||||
return ImageView.create(container, descriptor, fileService, scrollbar, delegate, instantiationService);
|
||||
}
|
||||
|
||||
// Large Files
|
||||
if (descriptor.size > ResourceViewer.MAX_OPEN_INTERNAL_SIZE) {
|
||||
return FileTooLargeFileView.create(container, descriptor, scrollbar, delegate);
|
||||
@@ -110,82 +96,8 @@ export class ResourceViewer {
|
||||
}
|
||||
}
|
||||
|
||||
private static isImageResource(descriptor: IResourceDescriptor) {
|
||||
const mime = getMime(descriptor);
|
||||
|
||||
// Chrome does not support tiffs
|
||||
return mime.indexOf('image/') >= 0 && mime !== 'image/tiff';
|
||||
}
|
||||
}
|
||||
|
||||
class ImageView {
|
||||
private static readonly MAX_IMAGE_SIZE = BinarySize.MB * 10; // showing images inline is memory intense, so we have a limit
|
||||
private static readonly BASE64_MARKER = 'base64,';
|
||||
|
||||
static create(
|
||||
container: HTMLElement,
|
||||
descriptor: IResourceDescriptor,
|
||||
fileService: IFileService,
|
||||
scrollbar: DomScrollableElement,
|
||||
delegate: ResourceViewerDelegate,
|
||||
instantiationService: IInstantiationService,
|
||||
): ResourceViewerContext {
|
||||
if (ImageView.shouldShowImageInline(descriptor)) {
|
||||
return InlineImageView.create(container, descriptor, fileService, scrollbar, delegate, instantiationService);
|
||||
}
|
||||
|
||||
return LargeImageView.create(container, descriptor, delegate);
|
||||
}
|
||||
|
||||
private static shouldShowImageInline(descriptor: IResourceDescriptor): boolean {
|
||||
let skipInlineImage: boolean;
|
||||
|
||||
// Data URI
|
||||
if (descriptor.resource.scheme === Schemas.data) {
|
||||
const base64MarkerIndex = descriptor.resource.path.indexOf(ImageView.BASE64_MARKER);
|
||||
const hasData = base64MarkerIndex >= 0 && descriptor.resource.path.substring(base64MarkerIndex + ImageView.BASE64_MARKER.length).length > 0;
|
||||
|
||||
skipInlineImage = !hasData || descriptor.size > ImageView.MAX_IMAGE_SIZE || descriptor.resource.path.length > ImageView.MAX_IMAGE_SIZE;
|
||||
}
|
||||
|
||||
// File URI
|
||||
else {
|
||||
skipInlineImage = typeof descriptor.size !== 'number' || descriptor.size > ImageView.MAX_IMAGE_SIZE;
|
||||
}
|
||||
|
||||
return !skipInlineImage;
|
||||
}
|
||||
}
|
||||
|
||||
class LargeImageView {
|
||||
static create(
|
||||
container: HTMLElement,
|
||||
descriptor: IResourceDescriptor,
|
||||
delegate: ResourceViewerDelegate
|
||||
) {
|
||||
const size = BinarySize.formatSize(descriptor.size);
|
||||
delegate.metadataClb(size);
|
||||
|
||||
DOM.clearNode(container);
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const label = document.createElement('p');
|
||||
label.textContent = nls.localize('largeImageError', "The image is not displayed in the editor because it is too large ({0}).", size);
|
||||
container.appendChild(label);
|
||||
|
||||
const openExternal = delegate.openExternalClb;
|
||||
if (descriptor.resource.scheme === Schemas.file && openExternal) {
|
||||
const link = DOM.append(label, DOM.$('a.embedded-link'));
|
||||
link.setAttribute('role', 'button');
|
||||
link.textContent = nls.localize('resourceOpenExternalButton', "Open image using external program?");
|
||||
|
||||
disposables.add(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => openExternal(descriptor.resource)));
|
||||
}
|
||||
|
||||
return disposables;
|
||||
}
|
||||
}
|
||||
|
||||
class FileTooLargeFileView {
|
||||
static create(
|
||||
@@ -239,349 +151,3 @@ class FileSeemsBinaryFileView {
|
||||
return disposables;
|
||||
}
|
||||
}
|
||||
|
||||
type Scale = number | 'fit';
|
||||
|
||||
export class ZoomStatusbarItem extends Disposable {
|
||||
|
||||
private statusbarItem?: IStatusbarEntryAccessor;
|
||||
|
||||
constructor(
|
||||
private readonly onSelectScale: (scale: Scale) => void,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IStatusbarService private readonly statusbarService: IStatusbarService,
|
||||
) {
|
||||
super();
|
||||
this._register(editorService.onDidActiveEditorChange(() => {
|
||||
if (this.statusbarItem) {
|
||||
this.statusbarItem.dispose();
|
||||
this.statusbarItem = undefined;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
updateStatusbar(scale: Scale): void {
|
||||
const entry: IStatusbarEntry = {
|
||||
text: this.zoomLabel(scale)
|
||||
};
|
||||
|
||||
if (!this.statusbarItem) {
|
||||
this.statusbarItem = this.statusbarService.addEntry(entry, 'status.imageZoom', nls.localize('status.imageZoom', "Image Zoom"), StatusbarAlignment.RIGHT, 101 /* to the left of editor status (100) */);
|
||||
|
||||
this._register(this.statusbarItem);
|
||||
|
||||
const element = document.getElementById('status.imageZoom')!;
|
||||
this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, (e: MouseEvent) => {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => element,
|
||||
getActions: () => this.zoomActions
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
this.statusbarItem.update(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@memoize
|
||||
private get zoomActions(): Action[] {
|
||||
const scales: Scale[] = [10, 5, 2, 1, 0.5, 0.2, 'fit'];
|
||||
return scales.map(scale =>
|
||||
new Action(`zoom.${scale}`, this.zoomLabel(scale), undefined, undefined, () => {
|
||||
this.updateStatusbar(scale);
|
||||
if (this.onSelectScale) {
|
||||
this.onSelectScale(scale);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}));
|
||||
}
|
||||
|
||||
private zoomLabel(scale: Scale): string {
|
||||
return scale === 'fit'
|
||||
? nls.localize('zoom.action.fit.label', 'Whole Image')
|
||||
: `${Math.round(scale * 100)}%`;
|
||||
}
|
||||
}
|
||||
|
||||
interface ImageState {
|
||||
scale: Scale;
|
||||
offsetX: number;
|
||||
offsetY: number;
|
||||
}
|
||||
|
||||
class InlineImageView {
|
||||
private static readonly SCALE_PINCH_FACTOR = 0.075;
|
||||
private static readonly MAX_SCALE = 20;
|
||||
private static readonly MIN_SCALE = 0.1;
|
||||
|
||||
private static readonly zoomLevels: Scale[] = [
|
||||
0.1,
|
||||
0.2,
|
||||
0.3,
|
||||
0.4,
|
||||
0.5,
|
||||
0.6,
|
||||
0.7,
|
||||
0.8,
|
||||
0.9,
|
||||
1,
|
||||
1.5,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
10,
|
||||
15,
|
||||
20
|
||||
];
|
||||
|
||||
/**
|
||||
* Enable image-rendering: pixelated for images scaled by more than this.
|
||||
*/
|
||||
private static readonly PIXELATION_THRESHOLD = 3;
|
||||
|
||||
/**
|
||||
* Store the scale and position of an image so it can be restored when changing editor tabs
|
||||
*/
|
||||
private static readonly imageStateCache = new LRUCache<string, ImageState>(100);
|
||||
|
||||
static create(
|
||||
container: HTMLElement,
|
||||
descriptor: IResourceDescriptor,
|
||||
fileService: IFileService,
|
||||
scrollbar: DomScrollableElement,
|
||||
delegate: ResourceViewerDelegate,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
) {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const zoomStatusbarItem = disposables.add(instantiationService.createInstance(ZoomStatusbarItem,
|
||||
newScale => updateScale(newScale)));
|
||||
|
||||
const context: ResourceViewerContext = {
|
||||
layout(dimension: DOM.Dimension) { },
|
||||
dispose: () => disposables.dispose()
|
||||
};
|
||||
|
||||
const cacheKey = `${descriptor.resource.toString()}:${descriptor.etag}`;
|
||||
|
||||
let ctrlPressed = false;
|
||||
let altPressed = false;
|
||||
|
||||
const initialState: ImageState = InlineImageView.imageStateCache.get(cacheKey) || { scale: 'fit', offsetX: 0, offsetY: 0 };
|
||||
let scale = initialState.scale;
|
||||
let image: HTMLImageElement | null = null;
|
||||
|
||||
function updateScale(newScale: Scale) {
|
||||
if (!image || !image.parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newScale === 'fit') {
|
||||
scale = 'fit';
|
||||
DOM.addClass(image, 'scale-to-fit');
|
||||
DOM.removeClass(image, 'pixelated');
|
||||
image.style.minWidth = 'auto';
|
||||
image.style.width = 'auto';
|
||||
InlineImageView.imageStateCache.delete(cacheKey);
|
||||
} else {
|
||||
const oldWidth = image.width;
|
||||
const oldHeight = image.height;
|
||||
|
||||
scale = clamp(newScale, InlineImageView.MIN_SCALE, InlineImageView.MAX_SCALE);
|
||||
if (scale >= InlineImageView.PIXELATION_THRESHOLD) {
|
||||
DOM.addClass(image, 'pixelated');
|
||||
} else {
|
||||
DOM.removeClass(image, 'pixelated');
|
||||
}
|
||||
|
||||
const { scrollTop, scrollLeft } = image.parentElement;
|
||||
const dx = (scrollLeft + image.parentElement.clientWidth / 2) / image.parentElement.scrollWidth;
|
||||
const dy = (scrollTop + image.parentElement.clientHeight / 2) / image.parentElement.scrollHeight;
|
||||
|
||||
DOM.removeClass(image, 'scale-to-fit');
|
||||
image.style.minWidth = `${(image.naturalWidth * scale)}px`;
|
||||
image.style.width = `${(image.naturalWidth * scale)}px`;
|
||||
|
||||
const newWidth = image.width;
|
||||
const scaleFactor = (newWidth - oldWidth) / oldWidth;
|
||||
|
||||
const newScrollLeft = ((oldWidth * scaleFactor * dx) + scrollLeft);
|
||||
const newScrollTop = ((oldHeight * scaleFactor * dy) + scrollTop);
|
||||
scrollbar.setScrollPosition({
|
||||
scrollLeft: newScrollLeft,
|
||||
scrollTop: newScrollTop,
|
||||
});
|
||||
|
||||
InlineImageView.imageStateCache.set(cacheKey, { scale: scale, offsetX: newScrollLeft, offsetY: newScrollTop });
|
||||
}
|
||||
|
||||
zoomStatusbarItem.updateStatusbar(scale);
|
||||
scrollbar.scanDomNode();
|
||||
}
|
||||
|
||||
function firstZoom() {
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
scale = image.clientWidth / image.naturalWidth;
|
||||
updateScale(scale);
|
||||
}
|
||||
|
||||
disposables.add(DOM.addDisposableListener(window, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
ctrlPressed = e.ctrlKey;
|
||||
altPressed = e.altKey;
|
||||
|
||||
if (platform.isMacintosh ? altPressed : ctrlPressed) {
|
||||
DOM.removeClass(container, 'zoom-in');
|
||||
DOM.addClass(container, 'zoom-out');
|
||||
}
|
||||
}));
|
||||
|
||||
disposables.add(DOM.addDisposableListener(window, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctrlPressed = e.ctrlKey;
|
||||
altPressed = e.altKey;
|
||||
|
||||
if (!(platform.isMacintosh ? altPressed : ctrlPressed)) {
|
||||
DOM.removeClass(container, 'zoom-out');
|
||||
DOM.addClass(container, 'zoom-in');
|
||||
}
|
||||
}));
|
||||
|
||||
disposables.add(DOM.addDisposableListener(container, DOM.EventType.CLICK, (e: MouseEvent) => {
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.button !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// left click
|
||||
if (scale === 'fit') {
|
||||
firstZoom();
|
||||
}
|
||||
|
||||
if (!(platform.isMacintosh ? altPressed : ctrlPressed)) { // zoom in
|
||||
let i = 0;
|
||||
for (; i < InlineImageView.zoomLevels.length; ++i) {
|
||||
if (InlineImageView.zoomLevels[i] > scale) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateScale(InlineImageView.zoomLevels[i] || InlineImageView.MAX_SCALE);
|
||||
} else {
|
||||
let i = InlineImageView.zoomLevels.length - 1;
|
||||
for (; i >= 0; --i) {
|
||||
if (InlineImageView.zoomLevels[i] < scale) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateScale(InlineImageView.zoomLevels[i] || InlineImageView.MIN_SCALE);
|
||||
}
|
||||
}));
|
||||
|
||||
disposables.add(DOM.addDisposableListener(container, DOM.EventType.WHEEL, (e: WheelEvent) => {
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isScrollWheelKeyPressed = platform.isMacintosh ? altPressed : ctrlPressed;
|
||||
if (!isScrollWheelKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (scale === 'fit') {
|
||||
firstZoom();
|
||||
}
|
||||
|
||||
let delta = e.deltaY > 0 ? 1 : -1;
|
||||
|
||||
updateScale(scale as number * (1 - delta * InlineImageView.SCALE_PINCH_FACTOR));
|
||||
}));
|
||||
|
||||
disposables.add(DOM.addDisposableListener(container, DOM.EventType.SCROLL, () => {
|
||||
if (!image || !image.parentElement || scale === 'fit') {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = InlineImageView.imageStateCache.get(cacheKey);
|
||||
if (entry) {
|
||||
const { scrollTop, scrollLeft } = image.parentElement;
|
||||
InlineImageView.imageStateCache.set(cacheKey, { scale: entry.scale, offsetX: scrollLeft, offsetY: scrollTop });
|
||||
}
|
||||
}));
|
||||
|
||||
DOM.clearNode(container);
|
||||
DOM.addClasses(container, 'image', 'zoom-in');
|
||||
|
||||
image = DOM.append(container, DOM.$<HTMLImageElement>('img.scale-to-fit'));
|
||||
image.style.visibility = 'hidden';
|
||||
|
||||
disposables.add(DOM.addDisposableListener(image, DOM.EventType.LOAD, e => {
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
if (typeof descriptor.size === 'number') {
|
||||
delegate.metadataClb(nls.localize('imgMeta', '{0}x{1} {2}', image.naturalWidth, image.naturalHeight, BinarySize.formatSize(descriptor.size)));
|
||||
} else {
|
||||
delegate.metadataClb(nls.localize('imgMetaNoSize', '{0}x{1}', image.naturalWidth, image.naturalHeight));
|
||||
}
|
||||
|
||||
scrollbar.scanDomNode();
|
||||
image.style.visibility = 'visible';
|
||||
updateScale(scale);
|
||||
if (initialState.scale !== 'fit') {
|
||||
scrollbar.setScrollPosition({
|
||||
scrollLeft: initialState.offsetX,
|
||||
scrollTop: initialState.offsetY,
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
InlineImageView.imageSrc(descriptor, fileService).then(src => {
|
||||
const img = container.querySelector('img');
|
||||
if (img) {
|
||||
if (typeof src === 'string') {
|
||||
img.src = src;
|
||||
} else {
|
||||
const url = URL.createObjectURL(src);
|
||||
disposables.add(toDisposable(() => URL.revokeObjectURL(url)));
|
||||
img.src = url;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private static async imageSrc(descriptor: IResourceDescriptor, fileService: IFileService): Promise<string | Blob> {
|
||||
if (descriptor.resource.scheme === Schemas.data) {
|
||||
return descriptor.resource.toString(true /* skip encoding */);
|
||||
}
|
||||
|
||||
const { value } = await fileService.readFile(descriptor.resource);
|
||||
return new Blob([value.buffer], { type: getMime(descriptor) });
|
||||
}
|
||||
}
|
||||
|
||||
function getMime(descriptor: IResourceDescriptor) {
|
||||
let mime: string | undefined = descriptor.mime;
|
||||
if (!mime && descriptor.resource.scheme !== Schemas.data) {
|
||||
mime = mimes.getMediaMime(descriptor.resource.path);
|
||||
}
|
||||
|
||||
return mime || mimes.MIME_BINARY;
|
||||
}
|
||||
|
||||
@@ -93,20 +93,20 @@ export class SideBySideEditor extends BaseEditor {
|
||||
this.updateStyles();
|
||||
}
|
||||
|
||||
async setInput(newInput: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
async setInput(newInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
const oldInput = this.input as SideBySideEditorInput;
|
||||
await super.setInput(newInput, options, token);
|
||||
|
||||
return this.updateInput(oldInput, (newInput as SideBySideEditorInput), options, token);
|
||||
}
|
||||
|
||||
setOptions(options: EditorOptions): void {
|
||||
setOptions(options: EditorOptions | undefined): void {
|
||||
if (this.masterEditor) {
|
||||
this.masterEditor.setOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
protected setEditorVisible(visible: boolean, group: IEditorGroup): void {
|
||||
protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
|
||||
if (this.masterEditor) {
|
||||
this.masterEditor.setVisible(visible, group);
|
||||
}
|
||||
@@ -159,7 +159,7 @@ export class SideBySideEditor extends BaseEditor {
|
||||
return this.detailsEditor;
|
||||
}
|
||||
|
||||
private async updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
private async updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
if (!newInput.matches(oldInput)) {
|
||||
if (oldInput) {
|
||||
this.disposeEditors();
|
||||
@@ -173,12 +173,12 @@ export class SideBySideEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
this.detailsEditor.setInput(newInput.details, null, token),
|
||||
this.detailsEditor.setInput(newInput.details, undefined, token),
|
||||
this.masterEditor.setInput(newInput.master, options, token)
|
||||
]);
|
||||
}
|
||||
|
||||
private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
const detailsEditor = this.doCreateEditor(newInput.details, this.detailsEditorContainer);
|
||||
const masterEditor = this.doCreateEditor(newInput.master, this.masterEditorContainer);
|
||||
|
||||
@@ -198,7 +198,7 @@ export class SideBySideEditor extends BaseEditor {
|
||||
return editor;
|
||||
}
|
||||
|
||||
private async onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
private async onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
this.detailsEditor = details;
|
||||
this.masterEditor = master;
|
||||
|
||||
@@ -210,7 +210,7 @@ export class SideBySideEditor extends BaseEditor {
|
||||
this.onDidCreateEditors.fire(undefined);
|
||||
|
||||
await Promise.all([
|
||||
this.detailsEditor.setInput(detailsInput, null, token),
|
||||
this.detailsEditor.setInput(detailsInput, undefined, token),
|
||||
this.masterEditor.setInput(masterInput, options, token)]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { isFunction, isObject, isArray } from 'vs/base/common/types';
|
||||
import { IDiffEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
@@ -31,7 +31,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { EditorActivation } from 'vs/platform/editor/common/editor';
|
||||
import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
/**
|
||||
* The text editor that leverages the diff text editor for the editing experience.
|
||||
@@ -40,7 +41,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
|
||||
static readonly ID = TEXT_DIFF_EDITOR_ID;
|
||||
|
||||
private diffNavigator: DiffNavigator;
|
||||
private diffNavigator: DiffNavigator | undefined;
|
||||
private readonly diffNavigatorDisposables = this._register(new DisposableStore());
|
||||
|
||||
private reverseColor: boolean; // {{SQL CARBON EDIT}} add property
|
||||
@@ -54,7 +55,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IEditorGroupsService editorGroupService: IEditorGroupsService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWindowService windowService: IWindowService
|
||||
@IWindowService windowService: IWindowService,
|
||||
@IClipboardService private _clipboardService: IClipboardService,
|
||||
) {
|
||||
super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService);
|
||||
}
|
||||
@@ -63,7 +65,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
return new EditorMemento(this.getId(), key, Object.create(null), limit, editorGroupService); // do not persist in storage as diff editors are never persisted
|
||||
}
|
||||
|
||||
getTitle(): string | null {
|
||||
getTitle(): string | undefined {
|
||||
if (this.input) {
|
||||
return this.input.getName();
|
||||
}
|
||||
@@ -77,15 +79,13 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
}
|
||||
|
||||
createEditorControl(parent: HTMLElement, configuration: ICodeEditorOptions): IDiffEditor {
|
||||
// {{SQL CARBON EDIT}}
|
||||
if (this.reverseColor) {
|
||||
if (this.reverseColor) { // {{SQL CARBON EDIT}}
|
||||
(configuration as IDiffEditorOptions).reverse = true;
|
||||
}
|
||||
|
||||
return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration);
|
||||
return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration, this._clipboardService);
|
||||
}
|
||||
|
||||
async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
|
||||
// Dispose previous diff navigator
|
||||
this.diffNavigatorDisposables.clear();
|
||||
@@ -116,7 +116,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
|
||||
// Apply Options from TextOptions
|
||||
let optionsGotApplied = false;
|
||||
if (options && types.isFunction((<TextEditorOptions>options).apply)) {
|
||||
if (options && isFunction((<TextEditorOptions>options).apply)) {
|
||||
optionsGotApplied = (<TextEditorOptions>options).apply(diffEditor, ScrollType.Immediate);
|
||||
}
|
||||
|
||||
@@ -145,9 +145,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
}
|
||||
}
|
||||
|
||||
setOptions(options: EditorOptions): void {
|
||||
setOptions(options: EditorOptions | undefined): void {
|
||||
const textOptions = <TextEditorOptions>options;
|
||||
if (textOptions && types.isFunction(textOptions.apply)) {
|
||||
if (textOptions && isFunction(textOptions.apply)) {
|
||||
textOptions.apply(this.getControl(), ScrollType.Smooth);
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
return false;
|
||||
}
|
||||
|
||||
private openAsBinary(input: EditorInput, options: EditorOptions): boolean {
|
||||
private openAsBinary(input: EditorInput, options: EditorOptions | undefined): boolean {
|
||||
if (input instanceof DiffEditorInput) {
|
||||
const originalInput = input.originalInput;
|
||||
const modifiedInput = input.modifiedInput;
|
||||
@@ -189,7 +189,12 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
// because we are triggering another openEditor() call
|
||||
// and do not control the initial intent that resulted
|
||||
// in us now opening as binary.
|
||||
options.overwrite({ activation: EditorActivation.PRESERVE });
|
||||
const preservingOptions: IEditorOptions = { activation: EditorActivation.PRESERVE };
|
||||
if (options) {
|
||||
options.overwrite(preservingOptions);
|
||||
} else {
|
||||
options = EditorOptions.create(preservingOptions);
|
||||
}
|
||||
|
||||
this.editorService.openEditor(binaryDiffInput, options, this.group);
|
||||
|
||||
@@ -203,7 +208,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
const editorConfiguration = super.computeConfiguration(configuration);
|
||||
|
||||
// Handle diff editor specially by merging in diffEditor configuration
|
||||
if (types.isObject(configuration.diffEditor)) {
|
||||
if (isObject(configuration.diffEditor)) {
|
||||
objects.mixin(editorConfiguration, configuration.diffEditor);
|
||||
}
|
||||
|
||||
@@ -245,7 +250,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
private isFileBinaryError(error: Error[]): boolean;
|
||||
private isFileBinaryError(error: Error): boolean;
|
||||
private isFileBinaryError(error: Error | Error[]): boolean {
|
||||
if (types.isArray(error)) {
|
||||
if (isArray(error)) {
|
||||
const errors = <Error[]>error;
|
||||
|
||||
return errors.some(e => this.isFileBinaryError(e));
|
||||
@@ -269,7 +274,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
super.clearInput();
|
||||
}
|
||||
|
||||
getDiffNavigator(): DiffNavigator {
|
||||
getDiffNavigator(): DiffNavigator | undefined {
|
||||
return this.diffNavigator;
|
||||
}
|
||||
|
||||
@@ -281,7 +286,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
||||
return super.loadTextEditorViewState(resource) as IDiffEditorViewState; // overridden for text diff editor support
|
||||
}
|
||||
|
||||
private saveTextDiffEditorViewState(input: EditorInput | null): void {
|
||||
private saveTextDiffEditorViewState(input: EditorInput | undefined): void {
|
||||
if (!(input instanceof DiffEditorInput)) {
|
||||
return; // only supported for diff editor inputs
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface IEditorConfiguration {
|
||||
export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
|
||||
private editorControl: IEditor;
|
||||
private _editorContainer: HTMLElement;
|
||||
private hasPendingConfigurationChange: boolean;
|
||||
private hasPendingConfigurationChange: boolean | undefined;
|
||||
private lastAppliedEditorOptions?: IEditorOptions;
|
||||
private editorMemento: IEditorMemento<IEditorViewState>;
|
||||
|
||||
@@ -191,7 +191,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
|
||||
return this.instantiationService.createInstance(CodeEditorWidget, parent, configuration, {});
|
||||
}
|
||||
|
||||
async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
await super.setInput(input, options, token);
|
||||
|
||||
// Update editor options after having set the input. We do this because there can be
|
||||
@@ -200,7 +200,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
|
||||
this._editorContainer.setAttribute('aria-label', this.computeAriaLabel());
|
||||
}
|
||||
|
||||
protected setEditorVisible(visible: boolean, group: IEditorGroup): void {
|
||||
protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
|
||||
|
||||
// Pass on to Editor
|
||||
if (visible) {
|
||||
|
||||
@@ -46,7 +46,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
|
||||
super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, windowService);
|
||||
}
|
||||
|
||||
getTitle(): string | null {
|
||||
getTitle(): string | undefined {
|
||||
if (this.input) {
|
||||
return this.input.getName();
|
||||
}
|
||||
@@ -54,7 +54,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
|
||||
return nls.localize('textEditor', "Text Editor");
|
||||
}
|
||||
|
||||
async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
|
||||
// Remember view settings if input changes
|
||||
this.saveTextResourceEditorViewState(this.input);
|
||||
@@ -100,7 +100,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
|
||||
}
|
||||
}
|
||||
|
||||
setOptions(options: EditorOptions): void {
|
||||
setOptions(options: EditorOptions | undefined): void {
|
||||
const textOptions = <TextEditorOptions>options;
|
||||
if (textOptions && types.isFunction(textOptions.apply)) {
|
||||
textOptions.apply(this.getControl(), ScrollType.Smooth);
|
||||
@@ -164,7 +164,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
|
||||
super.saveState();
|
||||
}
|
||||
|
||||
private saveTextResourceEditorViewState(input: EditorInput | null): void {
|
||||
private saveTextResourceEditorViewState(input: EditorInput | undefined): void {
|
||||
if (!(input instanceof UntitledEditorInput) && !(input instanceof ResourceEditorInput)) {
|
||||
return; // only enabled for untitled and resource inputs
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export abstract class TitleControl extends Themable {
|
||||
private currentPrimaryEditorActionIds: string[] = [];
|
||||
private currentSecondaryEditorActionIds: string[] = [];
|
||||
|
||||
protected editorActionsToolbar: ToolBar;
|
||||
private editorActionsToolbar: ToolBar;
|
||||
|
||||
private resourceContext: ResourceContextKey;
|
||||
private editorPinnedContext: IContextKey<boolean>;
|
||||
@@ -275,7 +275,7 @@ export abstract class TitleControl extends Themable {
|
||||
label = localize('draggedEditorGroup', "{0} (+{1})", label, this.group.count - 1);
|
||||
}
|
||||
|
||||
applyDragImage(e, label, 'monaco-editor-group-drag-image');
|
||||
applyDragImage(e, withUndefinedAsNull(label), 'monaco-editor-group-drag-image');
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export class NotificationsList extends Themable {
|
||||
private listContainer: HTMLElement;
|
||||
private list: WorkbenchList<INotificationViewItem>;
|
||||
private viewModel: INotificationViewItem[];
|
||||
private isVisible: boolean;
|
||||
private isVisible: boolean | undefined;
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
@@ -72,6 +72,7 @@ export class NotificationsList extends Themable {
|
||||
// List
|
||||
this.list = this._register(this.instantiationService.createInstance(
|
||||
WorkbenchList,
|
||||
'NotificationsList',
|
||||
this.listContainer,
|
||||
new NotificationsListDelegate(this.listContainer),
|
||||
[renderer],
|
||||
|
||||
@@ -54,7 +54,7 @@ export class NotificationsToasts extends Themable {
|
||||
|
||||
private notificationsToastsContainer: HTMLElement;
|
||||
private workbenchDimensions: Dimension;
|
||||
private isNotificationsCenterVisible: boolean;
|
||||
private isNotificationsCenterVisible: boolean | undefined;
|
||||
private mapNotificationToToast: Map<INotificationViewItem, INotificationToast>;
|
||||
private notificationsToastsVisibleContextKey: IContextKey<boolean>;
|
||||
|
||||
@@ -236,12 +236,11 @@ export class NotificationsToasts extends Themable {
|
||||
|
||||
purgeTimeoutHandle = setTimeout(() => {
|
||||
|
||||
// If the notification is sticky or prompting and the window does not have
|
||||
// focus, we wait for the window to gain focus again before triggering
|
||||
// the timeout again. This prevents an issue where focussing the window
|
||||
// could immediately hide the notification because the timeout was triggered
|
||||
// again.
|
||||
if ((item.sticky || item.hasPrompt()) && !this.windowService.hasFocus) {
|
||||
// If the window does not have focus, we wait for the window to gain focus
|
||||
// again before triggering the timeout again. This prevents an issue where
|
||||
// focussing the window could immediately hide the notification because the
|
||||
// timeout was triggered again.
|
||||
if (!this.windowService.hasFocus) {
|
||||
if (!listener) {
|
||||
listener = this.windowService.onDidChangeFocus(focus => {
|
||||
if (focus) {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
}
|
||||
|
||||
.monaco-workbench .part.panel .title {
|
||||
padding-right: 0px;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -17,7 +17,7 @@ import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ClosePanelAction, TogglePanelPositionAction, PanelActivityAction, ToggleMaximizedPanelAction, TogglePanelAction } from 'vs/workbench/browser/parts/panel/panelActions';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND, PANEL_INPUT_BORDER } from 'vs/workbench/common/theme';
|
||||
@@ -48,7 +48,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
private static readonly PINNED_PANELS = 'workbench.panel.pinnedPanels';
|
||||
private static readonly MIN_COMPOSITE_BAR_WIDTH = 50;
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
//#region IView
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Component } from 'vs/workbench/common/component';
|
||||
import { IQuickInputService, IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { QUICK_INPUT_BACKGROUND, QUICK_INPUT_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
@@ -44,6 +44,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -51,8 +52,8 @@ type Writeable<T> = { -readonly [P in keyof T]: T[P] };
|
||||
|
||||
const backButton = {
|
||||
iconPath: {
|
||||
dark: URI.parse(require.toUrl('vs/workbench/browser/parts/quickinput/media/arrow-left-dark.svg')),
|
||||
light: URI.parse(require.toUrl('vs/workbench/browser/parts/quickinput/media/arrow-left-light.svg'))
|
||||
dark: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/quickinput/media/arrow-left-dark.svg')),
|
||||
light: URI.parse(registerAndGetAmdImageURL('vs/workbench/browser/parts/quickinput/media/arrow-left-light.svg'))
|
||||
},
|
||||
tooltip: localize('quickInput.back', "Back"),
|
||||
handle: -1 // TODO
|
||||
@@ -880,7 +881,7 @@ class InputBox extends QuickInput implements IInputBox {
|
||||
|
||||
export class QuickInputService extends Component implements IQuickInputService {
|
||||
|
||||
public _serviceBrand!: ServiceIdentifier<any>;
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
private static readonly ID = 'workbench.component.quickinput';
|
||||
private static readonly MAX_WIDTH = 600; // Max total width of quick open widget
|
||||
|
||||
@@ -246,7 +246,7 @@ export class QuickInputList {
|
||||
this.id = id;
|
||||
this.container = dom.append(this.parent, $('.quick-input-list'));
|
||||
const delegate = new ListElementDelegate();
|
||||
this.list = this.instantiationService.createInstance(WorkbenchList, this.container, delegate, [new ListElementRenderer()], {
|
||||
this.list = this.instantiationService.createInstance(WorkbenchList, 'QuickInput', this.container, delegate, [new ListElementRenderer()], {
|
||||
identityProvider: { getId: element => element.saneLabel },
|
||||
openController: { shouldOpen: () => false }, // Workaround #58124
|
||||
setRowLineHeight: false,
|
||||
|
||||
@@ -30,7 +30,7 @@ import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Exten
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { IQuickOpenService, IShowOptions } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
@@ -61,7 +61,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
|
||||
private static readonly MAX_SHORT_RESPONSE_TIME = 500;
|
||||
private static readonly ID = 'workbench.component.quickopen';
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _onShow: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onShow: Event<void> = this._onShow.event;
|
||||
@@ -183,10 +183,10 @@ export class QuickOpenController extends Component implements IQuickOpenService
|
||||
onHide: (reason) => this.handleOnHide(reason),
|
||||
onFocusLost: () => !this.closeOnFocusLost
|
||||
}, {
|
||||
inputPlaceHolder: this.hasHandler(HELP_PREFIX) ? nls.localize('quickOpenInput', "Type '?' to get help on the actions you can take from here") : '',
|
||||
keyboardSupport: false,
|
||||
treeCreator: (container, config, opts) => this.instantiationService.createInstance(WorkbenchTree, container, config, opts)
|
||||
}
|
||||
inputPlaceHolder: this.hasHandler(HELP_PREFIX) ? nls.localize('quickOpenInput', "Type '?' to get help on the actions you can take from here") : '',
|
||||
keyboardSupport: false,
|
||||
treeCreator: (container, config, opts) => this.instantiationService.createInstance(WorkbenchTree, container, config, opts)
|
||||
}
|
||||
));
|
||||
this._register(attachQuickOpenStyler(this.quickOpenWidget, this.themeService, { background: QUICK_INPUT_BACKGROUND, foreground: QUICK_INPUT_FOREGROUND }));
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -35,7 +35,7 @@ import { LayoutPriority } from 'vs/base/browser/ui/grid/grid';
|
||||
|
||||
export class SidebarPart extends CompositePart<Viewlet> implements IViewletService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
static readonly activeViewletSettingsKey = 'workbench.sidebar.activeviewletid';
|
||||
|
||||
|
||||
@@ -12,6 +12,18 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.statusbar.status-border-top::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
background-color: var(--status-border-top-color);
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.statusbar > .left-items,
|
||||
.monaco-workbench .part.statusbar > .right-items {
|
||||
display: flex;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -57,7 +57,7 @@ class StatusbarViewModel extends Disposable {
|
||||
private readonly _entries: IStatusbarViewModelEntry[] = [];
|
||||
get entries(): IStatusbarViewModelEntry[] { return this._entries; }
|
||||
|
||||
private hidden: Set<string>;
|
||||
private hidden!: Set<string>;
|
||||
|
||||
constructor(private storageService: IStorageService) {
|
||||
super();
|
||||
@@ -323,7 +323,7 @@ class HideStatusbarEntryAction extends Action {
|
||||
|
||||
export class StatusbarPart extends Part implements IStatusbarService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<IStatusbarService>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
//#region IView
|
||||
|
||||
@@ -334,14 +334,14 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
|
||||
//#endregion
|
||||
|
||||
private styleElement: HTMLStyleElement;
|
||||
private styleElement!: HTMLStyleElement;
|
||||
|
||||
private pendingEntries: IPendingStatusbarEntry[] = [];
|
||||
|
||||
private readonly viewModel: StatusbarViewModel;
|
||||
|
||||
private leftItemsContainer: HTMLElement;
|
||||
private rightItemsContainer: HTMLElement;
|
||||
private leftItemsContainer!: HTMLElement;
|
||||
private rightItemsContainer!: HTMLElement;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@@ -580,9 +580,13 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
|
||||
// Border color
|
||||
const borderColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER) || this.getColor(contrastBorder);
|
||||
container.style.borderTopWidth = borderColor ? '1px' : null;
|
||||
container.style.borderTopStyle = borderColor ? 'solid' : null;
|
||||
container.style.borderTopColor = borderColor;
|
||||
if (borderColor) {
|
||||
addClass(container, 'status-border-top');
|
||||
container.style.setProperty('--status-border-top-color', borderColor.toString());
|
||||
} else {
|
||||
removeClass(container, 'status-border-top');
|
||||
container.style.removeProperty('--status-border-top-color');
|
||||
}
|
||||
|
||||
// Notification Beak
|
||||
if (!this.styleElement) {
|
||||
@@ -623,10 +627,10 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
}
|
||||
|
||||
class StatusbarEntryItem extends Disposable {
|
||||
private entry: IStatusbarEntry;
|
||||
private entry!: IStatusbarEntry;
|
||||
|
||||
private labelContainer: HTMLElement;
|
||||
private label: OcticonLabel;
|
||||
private labelContainer!: HTMLElement;
|
||||
private label!: OcticonLabel;
|
||||
|
||||
private readonly foregroundListener = this._register(new MutableDisposable());
|
||||
private readonly backgroundListener = this._register(new MutableDisposable());
|
||||
|
||||
@@ -254,6 +254,7 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
private menubar: MenuBar;
|
||||
private container: HTMLElement;
|
||||
private alwaysOnMnemonics: boolean;
|
||||
private focusInsideMenubar: boolean;
|
||||
|
||||
private readonly _onVisibilityChange: Emitter<boolean>;
|
||||
private readonly _onFocusStateChange: Emitter<boolean>;
|
||||
@@ -469,11 +470,11 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
if (firstTime) {
|
||||
this.menubar = this._register(new MenuBar(
|
||||
this.container, {
|
||||
enableMnemonics: this.currentEnableMenuBarMnemonics,
|
||||
disableAltFocus: this.currentDisableMenuBarAltFocus,
|
||||
visibility: this.currentMenubarVisibility,
|
||||
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
|
||||
}
|
||||
enableMnemonics: this.currentEnableMenuBarMnemonics,
|
||||
disableAltFocus: this.currentDisableMenuBarAltFocus,
|
||||
visibility: this.currentMenubarVisibility,
|
||||
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
|
||||
}
|
||||
));
|
||||
|
||||
this.accessibilityService.alwaysUnderlineAccessKeys().then(val => {
|
||||
@@ -481,9 +482,27 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics });
|
||||
});
|
||||
|
||||
this._register(this.menubar.onFocusStateChange(e => this._onFocusStateChange.fire(e)));
|
||||
this._register(this.menubar.onFocusStateChange(focused => {
|
||||
this._onFocusStateChange.fire(focused);
|
||||
|
||||
// When the menubar loses focus, update it to clear any pending updates
|
||||
if (!focused) {
|
||||
this.updateMenubar();
|
||||
this.focusInsideMenubar = false;
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.menubar.onVisibilityChange(e => this._onVisibilityChange.fire(e)));
|
||||
|
||||
// Before we focus the menubar, stop updates to it so that focus-related context keys will work
|
||||
this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_IN, () => {
|
||||
this.focusInsideMenubar = true;
|
||||
}));
|
||||
|
||||
this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_OUT, () => {
|
||||
this.focusInsideMenubar = false;
|
||||
}));
|
||||
|
||||
this._register(attachMenuStyler(this.menubar, this.themeService));
|
||||
} else {
|
||||
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics });
|
||||
@@ -503,9 +522,11 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
this.menus[action.item.submenu] = this.menuService.createMenu(action.item.submenu, this.contextKeyService);
|
||||
const submenu = this.menus[action.item.submenu];
|
||||
this._register(submenu!.onDidChange(() => {
|
||||
const actions: IAction[] = [];
|
||||
updateActions(menu, actions, topLevelTitle);
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) });
|
||||
if (!this.focusInsideMenubar) {
|
||||
const actions: IAction[] = [];
|
||||
updateActions(menu, actions, topLevelTitle);
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) });
|
||||
}
|
||||
}, this));
|
||||
}
|
||||
|
||||
@@ -529,9 +550,11 @@ export class CustomMenubarControl extends MenubarControl {
|
||||
const menu = this.menus[title];
|
||||
if (firstTime && menu) {
|
||||
this._register(menu.onDidChange(() => {
|
||||
const actions: IAction[] = [];
|
||||
updateActions(menu, actions, title);
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
if (!this.focusInsideMenubar) {
|
||||
const actions: IAction[] = [];
|
||||
updateActions(menu, actions, title);
|
||||
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import { Color } from 'vs/base/common/color';
|
||||
import { trim } from 'vs/base/common/strings';
|
||||
import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
|
||||
import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { template, getBaseLabel } from 'vs/base/common/labels';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
@@ -58,7 +58,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
private _onMenubarVisibilityChange = this._register(new Emitter<boolean>());
|
||||
readonly onMenubarVisibilityChange: Event<boolean> = this._onMenubarVisibilityChange.event;
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private title: HTMLElement;
|
||||
private dragRegion: HTMLElement;
|
||||
@@ -554,7 +554,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
rightMarker < (this.element.clientWidth + this.title.clientWidth) / 2) {
|
||||
this.title.style.position = null;
|
||||
this.title.style.left = null;
|
||||
this.title.style.transform = null;
|
||||
this.title.style.transform = '';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ export class CustomTreeViewPanel extends ViewletPanel {
|
||||
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
|
||||
this.treeView = treeView;
|
||||
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));
|
||||
this._register(this.treeView.onDidChangeTitle((newTitle) => this.updateTitle(newTitle)));
|
||||
this._register(toDisposable(() => this.treeView.setVisibility(false)));
|
||||
this._register(this.onDidChangeBodyVisibility(() => this.updateTreeVisibility()));
|
||||
this.updateTreeVisibility();
|
||||
@@ -190,9 +191,12 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
private readonly _onDidChangeActions: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeActions: Event<void> = this._onDidChangeActions.event;
|
||||
|
||||
private readonly _onDidChangeTitle: Emitter<string> = this._register(new Emitter<string>());
|
||||
readonly onDidChangeTitle: Event<string> = this._onDidChangeTitle.event;
|
||||
|
||||
constructor(
|
||||
private id: string,
|
||||
private title: string,
|
||||
private _title: string,
|
||||
private viewContainer: ViewContainer,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService,
|
||||
@@ -201,7 +205,8 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IProgressService private readonly progressService: IProgressService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super();
|
||||
this.root = new Root();
|
||||
@@ -228,6 +233,10 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
}
|
||||
|
||||
set dataProvider(dataProvider: ITreeViewDataProvider | undefined) {
|
||||
if (this.tree === undefined) {
|
||||
this.createTree();
|
||||
}
|
||||
|
||||
if (dataProvider) {
|
||||
this._dataProvider = new class implements ITreeViewDataProvider {
|
||||
async getChildren(node: ITreeItem): Promise<ITreeItem[]> {
|
||||
@@ -257,6 +266,15 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
this.updateMessage();
|
||||
}
|
||||
|
||||
get title(): string {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
set title(name: string) {
|
||||
this._title = name;
|
||||
this._onDidChangeTitle.fire(this._title);
|
||||
}
|
||||
|
||||
get canSelectMany(): boolean {
|
||||
return this._canSelectMany;
|
||||
}
|
||||
@@ -366,28 +384,28 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
const aligner = new Aligner(this.themeService);
|
||||
const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner);
|
||||
|
||||
this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new CustomTreeDelegate(), [renderer],
|
||||
this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CustomView', this.treeContainer, new CustomTreeDelegate(), [renderer],
|
||||
dataSource, {
|
||||
identityProvider: new CustomViewIdentityProvider(),
|
||||
accessibilityProvider: {
|
||||
getAriaLabel(element: ITreeItem): string {
|
||||
return element.label ? element.label.label : '';
|
||||
}
|
||||
},
|
||||
ariaLabel: this.title,
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (item: ITreeItem) => {
|
||||
return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined);
|
||||
}
|
||||
},
|
||||
expandOnlyOnTwistieClick: (e: ITreeItem) => !!e.command,
|
||||
collapseByDefault: (e: ITreeItem): boolean => {
|
||||
return e.collapsibleState !== TreeItemCollapsibleState.Expanded;
|
||||
},
|
||||
multipleSelectionSupport: this.canSelectMany,
|
||||
}) as WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>);
|
||||
identityProvider: new CustomViewIdentityProvider(),
|
||||
accessibilityProvider: {
|
||||
getAriaLabel(element: ITreeItem): string {
|
||||
return element.tooltip ? element.tooltip : element.label ? element.label.label : '';
|
||||
}
|
||||
},
|
||||
ariaLabel: this._title,
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (item: ITreeItem) => {
|
||||
return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined);
|
||||
}
|
||||
},
|
||||
expandOnlyOnTwistieClick: (e: ITreeItem) => !!e.command,
|
||||
collapseByDefault: (e: ITreeItem): boolean => {
|
||||
return e.collapsibleState !== TreeItemCollapsibleState.Expanded;
|
||||
},
|
||||
multipleSelectionSupport: this.canSelectMany,
|
||||
}) as WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>);
|
||||
aligner.tree = this.tree;
|
||||
const actionRunner = new MultipleSelectionActionRunner(() => this.tree!.getSelection());
|
||||
const actionRunner = new MultipleSelectionActionRunner(this.notificationService, () => this.tree!.getSelection());
|
||||
renderer.actionRunner = actionRunner;
|
||||
|
||||
this.tree.contextKeyService.createKey<boolean>(this.id, true);
|
||||
@@ -578,7 +596,6 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
|
||||
private activate() {
|
||||
if (!this.activated) {
|
||||
this.createTree();
|
||||
this.progressService.withProgress({ location: this.viewContainer.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
|
||||
.then(() => timeout(2000))
|
||||
.then(() => {
|
||||
@@ -593,16 +610,8 @@ export class CustomTreeView extends Disposable implements ITreeView {
|
||||
const tree = this.tree;
|
||||
if (tree) {
|
||||
this.refreshing = true;
|
||||
const parents: Set<ITreeItem> = new Set<ITreeItem>();
|
||||
elements.forEach(element => {
|
||||
if (element !== this.root) {
|
||||
const parent = tree.getParentElement(element);
|
||||
parents.add(parent);
|
||||
} else {
|
||||
parents.add(element);
|
||||
}
|
||||
});
|
||||
await Promise.all(Array.from(parents.values()).map(element => tree.updateChildren(element, true)));
|
||||
await Promise.all(elements.map(element => tree.updateChildren(element, true)));
|
||||
elements.map(element => tree.rerender(element));
|
||||
this.refreshing = false;
|
||||
this.updateContentAreas();
|
||||
if (this.focused) {
|
||||
@@ -845,22 +854,32 @@ class Aligner extends Disposable {
|
||||
|
||||
class MultipleSelectionActionRunner extends ActionRunner {
|
||||
|
||||
constructor(private getSelectedResources: (() => ITreeItem[])) {
|
||||
constructor(notificationService: INotificationService, private getSelectedResources: (() => ITreeItem[])) {
|
||||
super();
|
||||
this._register(this.onDidRun(e => {
|
||||
if (e.error) {
|
||||
notificationService.error(localize('command-error', 'Error running command {1}: {0}. This is likely caused by the extension that contributes {1}.', e.error.message, e.action.id));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
runAction(action: IAction, context: TreeViewItemHandleArg): Promise<any> {
|
||||
const selection = this.getSelectedResources();
|
||||
let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined;
|
||||
let actionInSelected: boolean = false;
|
||||
if (selection.length > 1) {
|
||||
selectionHandleArgs = [];
|
||||
selection.forEach(selected => {
|
||||
if (selected.handle !== context.$treeItemHandle) {
|
||||
selectionHandleArgs!.push({ $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle });
|
||||
selectionHandleArgs = selection.map(selected => {
|
||||
if (selected.handle === context.$treeItemHandle) {
|
||||
actionInSelected = true;
|
||||
}
|
||||
return { $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle };
|
||||
});
|
||||
}
|
||||
|
||||
if (!actionInSelected) {
|
||||
selectionHandleArgs = undefined;
|
||||
}
|
||||
|
||||
return action.run(...[context, selectionHandleArgs]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { toggleClass, addClass } from 'vs/base/browser/dom';
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
function filterViewRegisterEvent(container: ViewContainer, event: Event<{ viewContainer: ViewContainer, views: IViewDescriptor[] }>): Event<IViewDescriptor[]> {
|
||||
@@ -382,7 +381,7 @@ export class ContributableViewsModel extends Disposable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (this.getViewOrder(a) - this.getViewOrder(b)) || this.getGroupOrderResult(a, b) || (a.id < b.id ? -1 : 1);
|
||||
return (this.getViewOrder(a) - this.getViewOrder(b)) || this.getGroupOrderResult(a, b);
|
||||
}
|
||||
|
||||
private getGroupOrderResult(a: IViewDescriptor, b: IViewDescriptor) {
|
||||
@@ -434,7 +433,7 @@ export class ContributableViewsModel extends Disposable {
|
||||
const splices = sortedDiff<IViewDescriptor>(
|
||||
this.viewDescriptors,
|
||||
viewDescriptors,
|
||||
this.compareViewDescriptors.bind(this)
|
||||
(a, b) => a.id === b.id ? 0 : a.id < b.id ? -1 : 1
|
||||
).reverse();
|
||||
|
||||
const toRemove: { index: number, viewDescriptor: IViewDescriptor }[] = [];
|
||||
@@ -522,9 +521,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
|
||||
}
|
||||
|
||||
private saveWorkspaceViewsStates(): void {
|
||||
const storedViewsStates: { [id: string]: IStoredWorkspaceViewState } = {};
|
||||
|
||||
let hasState = false;
|
||||
const storedViewsStates: { [id: string]: IStoredWorkspaceViewState } = JSON.parse(this.storageService.get(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE, '{}'));
|
||||
for (const viewDescriptor of this.viewDescriptors) {
|
||||
const viewState = this.viewStates.get(viewDescriptor.id);
|
||||
if (viewState) {
|
||||
@@ -534,11 +531,10 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
|
||||
size: viewState.size,
|
||||
order: viewDescriptor.workspace && viewState ? viewState.order : undefined
|
||||
};
|
||||
hasState = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasState) {
|
||||
if (Object.keys(storedViewsStates).length > 0) {
|
||||
this.storageService.store(this.workspaceViewsStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(this.workspaceViewsStateStorageId, StorageScope.WORKSPACE);
|
||||
@@ -638,7 +634,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
|
||||
|
||||
export class ViewsService extends Disposable implements IViewsService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly viewDescriptorCollections: Map<ViewContainer, { viewDescriptorCollection: IViewDescriptorCollection, disposable: IDisposable }>;
|
||||
private readonly viewDisposable: Map<IViewDescriptor, IDisposable>;
|
||||
|
||||
@@ -39,7 +39,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView
|
||||
|
||||
private readonly viewletState: MementoObject;
|
||||
private didLayout = false;
|
||||
private dimension: DOM.Dimension;
|
||||
private dimension: DOM.Dimension | undefined;
|
||||
private areExtensionsReady: boolean = false;
|
||||
|
||||
private readonly visibleViewsCountFromCache: number | undefined;
|
||||
|
||||
@@ -13,7 +13,8 @@ import { Workbench } from 'vs/workbench/browser/workbench';
|
||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IProductService, IProductConfiguration } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import product from 'vs/platform/product/browser/product';
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl';
|
||||
import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remoteAuthorityResolverService';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
@@ -121,7 +122,7 @@ class CodeRendererMain extends Disposable {
|
||||
|
||||
// Log
|
||||
const logsPath = URI.file(toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')).with({ scheme: 'vscode-log' });
|
||||
const logService = new BufferLogService();
|
||||
const logService = new BufferLogService(this.configuration.logLevel);
|
||||
serviceCollection.set(ILogService, logService);
|
||||
|
||||
const payload = this.resolveWorkspaceInitializationPayload();
|
||||
@@ -131,11 +132,17 @@ class CodeRendererMain extends Disposable {
|
||||
serviceCollection.set(IWorkbenchEnvironmentService, environmentService);
|
||||
|
||||
// Product
|
||||
const productService = this.createProductService();
|
||||
const productService = {
|
||||
_serviceBrand: undefined,
|
||||
...{
|
||||
...product, // dev or built time config
|
||||
...{ urlProtocol: '' } // web related overrides from us
|
||||
}
|
||||
};
|
||||
serviceCollection.set(IProductService, productService);
|
||||
|
||||
// Remote
|
||||
const remoteAuthorityResolverService = new RemoteAuthorityResolverService();
|
||||
const remoteAuthorityResolverService = new RemoteAuthorityResolverService(this.configuration.resourceUriProvider);
|
||||
serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);
|
||||
|
||||
// Signing
|
||||
@@ -220,18 +227,6 @@ class CodeRendererMain extends Disposable {
|
||||
fileService.registerProvider(Schemas.userData, this.configuration.userDataProvider);
|
||||
}
|
||||
|
||||
private createProductService(): IProductService {
|
||||
const productConfiguration = {
|
||||
...this.configuration.productConfiguration ? this.configuration.productConfiguration : {
|
||||
version: '1.38.0-unknown',
|
||||
nameLong: 'Unknown',
|
||||
extensionAllowedProposedApi: [],
|
||||
}, ...{ urlProtocol: '' }
|
||||
} as IProductConfiguration;
|
||||
|
||||
return { _serviceBrand: undefined, ...productConfiguration };
|
||||
}
|
||||
|
||||
private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise<BrowserStorageService> {
|
||||
const storageService = new BrowserStorageService(environmentService, fileService);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user