dnd terminals bw windows in panel and fix moving from editor to panel (#128875)
This commit is contained in:
parent
cfc48e81aa
commit
a7c466d649
|
@ -401,6 +401,11 @@ export interface ICreateTerminalOptions {
|
|||
* Where to create the terminal, when not specified the default target will be used.
|
||||
*/
|
||||
target?: TerminalLocation;
|
||||
|
||||
/**
|
||||
* The terminal's resource, passed when the terminal has moved windows.
|
||||
*/
|
||||
resource?: URI;
|
||||
}
|
||||
|
||||
export interface ICreateContributedTerminalProfileOptions {
|
||||
|
|
|
@ -113,8 +113,20 @@ export function extractEditorsDropData(e: DragEvent, externalOnly?: boolean): Ar
|
|||
// Invalid transfer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for terminals transfer
|
||||
const terminals = e.dataTransfer.getData(DataTransfers.TERMINALS);
|
||||
if (terminals) {
|
||||
try {
|
||||
const terminalEditors: string[] = JSON.parse(terminals);
|
||||
for (const terminalEditor of terminalEditors) {
|
||||
editors.push({ resource: URI.parse(terminalEditor), isExternal: true });
|
||||
}
|
||||
} catch (error) {
|
||||
// Invalid transfer
|
||||
}
|
||||
}
|
||||
}
|
||||
return editors;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import { ICompleteTerminalConfiguration } from 'vs/workbench/contrib/terminal/co
|
|||
import { Orientation } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { IEditableData } from 'vs/workbench/common/views';
|
||||
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
|
||||
import { SerializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer';
|
||||
import { DeserializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer';
|
||||
|
||||
export const ITerminalService = createDecorator<ITerminalService>('terminalService');
|
||||
export const ITerminalEditorService = createDecorator<ITerminalEditorService>('terminalEditorService');
|
||||
|
@ -54,7 +54,7 @@ export interface ITerminalInstanceService {
|
|||
*/
|
||||
preparePathForTerminalAsync(path: string, executable: string | undefined, title: string, shellType: TerminalShellType, isRemote: boolean): Promise<string>;
|
||||
|
||||
createInstance(launchConfig: IShellLaunchConfig, target?: TerminalLocation): ITerminalInstance;
|
||||
createInstance(launchConfig: IShellLaunchConfig, target?: TerminalLocation, resource?: URI): ITerminalInstance;
|
||||
}
|
||||
|
||||
export interface IBrowserTerminalConfigHelper extends ITerminalConfigHelper {
|
||||
|
@ -140,7 +140,8 @@ export interface ITerminalService extends ITerminalInstanceHost {
|
|||
*/
|
||||
getInstanceFromId(terminalId: number): ITerminalInstance | undefined;
|
||||
getInstanceFromIndex(terminalIndex: number): ITerminalInstance;
|
||||
getInstanceFromResource(resource: URI | undefined): ITerminalInstance | undefined;
|
||||
|
||||
|
||||
getActiveOrCreateInstance(): ITerminalInstance;
|
||||
splitInstance(instance: ITerminalInstance, shell?: IShellLaunchConfig, cwd?: string | URI): ITerminalInstance | null;
|
||||
splitInstance(instance: ITerminalInstance, profile: ITerminalProfile): ITerminalInstance | null;
|
||||
|
@ -198,7 +199,7 @@ export interface ITerminalEditorService extends ITerminalInstanceHost, ITerminal
|
|||
readonly instances: readonly ITerminalInstance[];
|
||||
|
||||
openEditor(instance: ITerminalInstance): Promise<void>;
|
||||
getOrCreateEditorInput(instance: ITerminalInstance | SerializedTerminalEditorInput): TerminalEditorInput;
|
||||
getOrCreateEditorInput(instance: ITerminalInstance | DeserializedTerminalEditorInput | URI): TerminalEditorInput;
|
||||
detachActiveEditorInstance(): ITerminalInstance;
|
||||
detachInstance(instance: ITerminalInstance): void;
|
||||
splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance;
|
||||
|
@ -271,6 +272,11 @@ export interface ITerminalInstanceHost {
|
|||
readonly onDidChangeInstances: Event<void>;
|
||||
|
||||
setActiveInstance(instance: ITerminalInstance): void;
|
||||
/**
|
||||
* Gets an instance from a resource if it exists. This MUST be used instead of getInstanceFromId
|
||||
* when you only know about a terminal's URI. (a URI's instance ID may not be this window's instance ID)
|
||||
*/
|
||||
getInstanceFromResource(resource: URI | undefined): ITerminalInstance | undefined;
|
||||
}
|
||||
|
||||
export interface ITerminalFindHost {
|
||||
|
@ -341,6 +347,8 @@ export interface ITerminalInstance {
|
|||
* A unique URI for this terminal instance with the following encoding:
|
||||
* path: /<workspace ID>/<instance ID>
|
||||
* fragment: Title
|
||||
* Note that when dragging terminals across windows, this will retain the original workspace ID /instance ID
|
||||
* from the other window.
|
||||
*/
|
||||
readonly resource: URI;
|
||||
|
||||
|
|
|
@ -19,9 +19,13 @@ import { ConfirmOnKill } from 'vs/workbench/contrib/terminal/common/terminal';
|
|||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export class TerminalEditorInput extends EditorInput {
|
||||
|
||||
protected readonly _onDidRequestAttach = this._register(new Emitter<ITerminalInstance>());
|
||||
readonly onDidRequestAttach = this._onDidRequestAttach.event;
|
||||
|
||||
static readonly ID = 'workbench.editors.terminal';
|
||||
|
||||
private _isDetached = false;
|
||||
|
@ -47,11 +51,26 @@ export class TerminalEditorInput extends EditorInput {
|
|||
return TerminalEditor.ID;
|
||||
}
|
||||
|
||||
setTerminalInstance(instance: ITerminalInstance): void {
|
||||
if (this._terminalInstance) {
|
||||
throw new Error('cannot set instance that has already been set');
|
||||
}
|
||||
this._terminalInstance = instance;
|
||||
this._setupInstanceListeners();
|
||||
|
||||
// Refresh dirty state when the confirm on kill setting is changed
|
||||
this._configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(TerminalSettingId.ConfirmOnKill)) {
|
||||
this._onDidChangeDirty.fire();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
override copy(): IEditorInput {
|
||||
const instance = this._copyInstance || this._terminalInstanceService.createInstance({}, TerminalLocation.Editor);
|
||||
instance.focusWhenReady();
|
||||
this._copyInstance = undefined;
|
||||
return this._instantiationService.createInstance(TerminalEditorInput, instance);
|
||||
return this._instantiationService.createInstance(TerminalEditorInput, instance.resource, instance);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,47 +88,27 @@ export class TerminalEditorInput extends EditorInput {
|
|||
return this._isDetached ? undefined : this._terminalInstance;
|
||||
}
|
||||
|
||||
get resource(): URI {
|
||||
return this._terminalInstance.resource;
|
||||
}
|
||||
|
||||
override isDirty(): boolean {
|
||||
const confirmOnKill = this._configurationService.getValue<ConfirmOnKill>(TerminalSettingId.ConfirmOnKill);
|
||||
if (confirmOnKill === 'editor' || confirmOnKill === 'always') {
|
||||
return this._terminalInstance.hasChildProcesses;
|
||||
return this._terminalInstance?.hasChildProcesses || false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _terminalInstance: ITerminalInstance,
|
||||
public readonly resource: URI,
|
||||
private _terminalInstance: ITerminalInstance | undefined,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IContextKeyService _contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._terminalEditorFocusContextKey = TerminalContextKeys.editorFocus.bindTo(contextKeyService);
|
||||
|
||||
this._register(toDisposable(() => {
|
||||
if (!this._isDetached && !this._isShuttingDown) {
|
||||
this._terminalInstance.dispose();
|
||||
}
|
||||
}));
|
||||
|
||||
const disposeListeners = [
|
||||
this._terminalInstance.onExit(() => this.dispose()),
|
||||
this._terminalInstance.onDisposed(() => this.dispose()),
|
||||
this._terminalInstance.onTitleChanged(() => this._onDidChangeLabel.fire()),
|
||||
this._terminalInstance.onIconChanged(() => this._onDidChangeLabel.fire()),
|
||||
this._terminalInstance.onDidFocus(() => this._terminalEditorFocusContextKey.set(true)),
|
||||
this._terminalInstance.onDidBlur(() => this._terminalEditorFocusContextKey.reset()),
|
||||
this._terminalInstance.onDidChangeHasChildProcesses(() => this._onDidChangeDirty.fire()),
|
||||
this._terminalInstance.statusList.onDidChangePrimaryStatus(() => this._onDidChangeLabel.fire())
|
||||
];
|
||||
this._terminalEditorFocusContextKey = TerminalContextKeys.editorFocus.bindTo(_contextKeyService);
|
||||
|
||||
// Refresh dirty state when the confirm on kill setting is changed
|
||||
this._configurationService.onDidChangeConfiguration(e => {
|
||||
|
@ -117,20 +116,50 @@ export class TerminalEditorInput extends EditorInput {
|
|||
this._onDidChangeDirty.fire();
|
||||
}
|
||||
});
|
||||
if (_terminalInstance) {
|
||||
this._setupInstanceListeners();
|
||||
}
|
||||
}
|
||||
|
||||
private _setupInstanceListeners(): void {
|
||||
const instance = this._terminalInstance;
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._register(toDisposable(() => {
|
||||
if (!this._isDetached && !this._isShuttingDown) {
|
||||
instance.dispose();
|
||||
}
|
||||
}));
|
||||
|
||||
const disposeListeners = [
|
||||
instance.onExit(() => this.dispose()),
|
||||
instance.onDisposed(() => this.dispose()),
|
||||
instance.onTitleChanged(() => this._onDidChangeLabel.fire()),
|
||||
instance.onIconChanged(() => this._onDidChangeLabel.fire()),
|
||||
instance.onDidFocus(() => this._terminalEditorFocusContextKey.set(true)),
|
||||
instance.onDidBlur(() => this._terminalEditorFocusContextKey.reset()),
|
||||
instance.onDidChangeHasChildProcesses(() => this._onDidChangeDirty.fire()),
|
||||
instance.statusList.onDidChangePrimaryStatus(() => this._onDidChangeLabel.fire())
|
||||
];
|
||||
|
||||
// Don't dispose editor when instance is torn down on shutdown to avoid extra work and so
|
||||
// the editor/tabs don't disappear
|
||||
lifecycleService.onWillShutdown(() => {
|
||||
this._lifecycleService.onWillShutdown(() => {
|
||||
this._isShuttingDown = true;
|
||||
dispose(disposeListeners);
|
||||
});
|
||||
}
|
||||
|
||||
override getName() {
|
||||
return this._terminalInstance.title;
|
||||
return this._terminalInstance?.title || this.resource.fragment;
|
||||
}
|
||||
|
||||
override getLabelExtraClasses(): string[] {
|
||||
if (!this._terminalInstance) {
|
||||
return [];
|
||||
}
|
||||
const extraClasses: string[] = ['terminal-tab'];
|
||||
const colorClass = getColorClass(this._terminalInstance);
|
||||
if (colorClass) {
|
||||
|
@ -152,7 +181,7 @@ export class TerminalEditorInput extends EditorInput {
|
|||
*/
|
||||
detachInstance() {
|
||||
if (!this._isShuttingDown) {
|
||||
this._terminalInstance.detachFromElement();
|
||||
this._terminalInstance?.detachFromElement();
|
||||
this._isDetached = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal';
|
||||
import { IEditorSerializer } from 'vs/workbench/common/editor';
|
||||
|
@ -29,6 +30,7 @@ export class TerminalInputSerializer implements IEditorSerializer {
|
|||
|
||||
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | undefined {
|
||||
const terminalInstance = JSON.parse(serializedEditorInput);
|
||||
terminalInstance.resource = URI.parse(terminalInstance.resource);
|
||||
const editor = this._terminalEditorService.getOrCreateEditorInput(terminalInstance);
|
||||
return editor;
|
||||
}
|
||||
|
@ -41,12 +43,13 @@ export class TerminalInputSerializer implements IEditorSerializer {
|
|||
titleSource: instance.titleSource,
|
||||
cwd: '',
|
||||
icon: instance.icon,
|
||||
color: instance.color
|
||||
color: instance.color,
|
||||
resource: instance.resource.toString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface SerializedTerminalEditorInput {
|
||||
interface TerminalEditorInputObject {
|
||||
readonly id: number;
|
||||
readonly pid: number;
|
||||
readonly title: string;
|
||||
|
@ -55,3 +58,11 @@ export interface SerializedTerminalEditorInput {
|
|||
readonly icon: TerminalIcon | undefined;
|
||||
readonly color: string | undefined;
|
||||
}
|
||||
|
||||
export interface SerializedTerminalEditorInput extends TerminalEditorInputObject {
|
||||
readonly resource: string
|
||||
}
|
||||
|
||||
export interface DeserializedTerminalEditorInput extends TerminalEditorInputObject {
|
||||
readonly resource: URI
|
||||
}
|
||||
|
|
|
@ -5,17 +5,21 @@
|
|||
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { EditorActivation } from 'vs/platform/editor/common/editor';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IShellLaunchConfig, TerminalLocation } from 'vs/platform/terminal/common/terminal';
|
||||
import { IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { ITerminalEditorService, ITerminalInstance, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteTerminalService, ITerminalEditorService, ITerminalInstance, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEditor';
|
||||
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
|
||||
import { SerializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer';
|
||||
import { DeserializedTerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorSerializer';
|
||||
import { parseTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri';
|
||||
import { ILocalTerminalService, IOffProcessTerminalService } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
|
||||
export class TerminalEditorService extends Disposable implements ITerminalEditorService {
|
||||
|
@ -25,8 +29,10 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor
|
|||
private _activeInstanceIndex: number = -1;
|
||||
private _isShuttingDown = false;
|
||||
|
||||
private _editorInputs: Map</*instanceId*/number, TerminalEditorInput> = new Map();
|
||||
private _instanceDisposables: Map</*instanceId*/number, IDisposable[]> = new Map();
|
||||
private _editorInputs: Map</*resource*/string, TerminalEditorInput> = new Map();
|
||||
private _instanceDisposables: Map</*resource*/string, IDisposable[]> = new Map();
|
||||
|
||||
private readonly _primaryOffProcessTerminalService: IOffProcessTerminalService;
|
||||
|
||||
private readonly _onDidDisposeInstance = new Emitter<ITerminalInstance>();
|
||||
readonly onDidDisposeInstance = this._onDidDisposeInstance.event;
|
||||
|
@ -42,9 +48,13 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor
|
|||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ILifecycleService lifecycleService: ILifecycleService
|
||||
@IRemoteTerminalService private readonly _remoteTerminalService: IRemoteTerminalService,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@optional(ILocalTerminalService) private readonly _localTerminalService: ILocalTerminalService
|
||||
) {
|
||||
super();
|
||||
this._primaryOffProcessTerminalService = !!environmentService.remoteAuthority ? this._remoteTerminalService : (this._localTerminalService || this._remoteTerminalService);
|
||||
this._register(toDisposable(() => {
|
||||
for (const d of this._instanceDisposables.values()) {
|
||||
dispose(d);
|
||||
|
@ -65,7 +75,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor
|
|||
const terminalEditors = this._getActiveTerminalEditors();
|
||||
const unknownEditor = terminalEditors.find(input => !knownIds.includes((input as any).terminalInstance.instanceId));
|
||||
if (unknownEditor instanceof TerminalEditorInput && unknownEditor.terminalInstance) {
|
||||
this._editorInputs.set(unknownEditor.terminalInstance.instanceId, unknownEditor);
|
||||
this._editorInputs.set(unknownEditor.terminalInstance.resource.path, unknownEditor);
|
||||
this.instances.push(unknownEditor.terminalInstance);
|
||||
}
|
||||
}));
|
||||
|
@ -153,31 +163,72 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor
|
|||
input.setGroup(editorPane?.group);
|
||||
}
|
||||
|
||||
getOrCreateEditorInput(instance: ITerminalInstance | SerializedTerminalEditorInput, isFutureSplit: boolean = false): TerminalEditorInput {
|
||||
let cachedEditor;
|
||||
if ('id' in instance) {
|
||||
cachedEditor = this._editorInputs.get(instance.id);
|
||||
} else if ('instanceId' in instance) {
|
||||
cachedEditor = this._editorInputs.get(instance.instanceId);
|
||||
}
|
||||
getOrCreateEditorInput(instanceOrUri: ITerminalInstance | DeserializedTerminalEditorInput | URI, isFutureSplit: boolean = false): TerminalEditorInput {
|
||||
const resource: URI = URI.isUri(instanceOrUri) ? instanceOrUri : instanceOrUri.resource;
|
||||
const inputKey = resource.path;
|
||||
const cachedEditor = this._editorInputs.get(inputKey);
|
||||
if (cachedEditor) {
|
||||
return cachedEditor;
|
||||
}
|
||||
|
||||
if ('pid' in instance) {
|
||||
instance = this._terminalInstanceService.createInstance({ attachPersistentProcess: instance }, TerminalLocation.Editor);
|
||||
if ('pid' in instanceOrUri) {
|
||||
instanceOrUri = this._terminalInstanceService.createInstance({ attachPersistentProcess: instanceOrUri }, TerminalLocation.Editor);
|
||||
}
|
||||
|
||||
const input = this._instantiationService.createInstance(TerminalEditorInput, instance);
|
||||
instance.target = TerminalLocation.Editor;
|
||||
this._editorInputs.set(instance.instanceId, input);
|
||||
this._instanceDisposables.set(instance.instanceId, [
|
||||
instance.onDisposed(this._onDidDisposeInstance.fire, this._onDidDisposeInstance),
|
||||
instance.onDidFocus(this._onDidFocusInstance.fire, this._onDidFocusInstance)
|
||||
// Terminal from a different window
|
||||
if (URI.isUri(instanceOrUri)) {
|
||||
const terminalIdentifier = parseTerminalUri(instanceOrUri);
|
||||
if (terminalIdentifier.instanceId) {
|
||||
this._primaryOffProcessTerminalService.requestDetachInstance(terminalIdentifier.workspaceId, terminalIdentifier.instanceId).then(attachPersistentProcess => {
|
||||
const instance = this._terminalInstanceService.createInstance({ attachPersistentProcess }, TerminalLocation.Editor, resource);
|
||||
input.setTerminalInstance(instance);
|
||||
// trigger setInput on TerminalEditor setInput
|
||||
// which attaches to the element and updates the input
|
||||
this._editorService.openEditor(input, {
|
||||
pinned: true,
|
||||
forceReload: true
|
||||
},
|
||||
input.group
|
||||
);
|
||||
this._registerInstance(inputKey, input, instance);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let input: TerminalEditorInput;
|
||||
if ('instanceId' in instanceOrUri) {
|
||||
instanceOrUri.target = TerminalLocation.Editor;
|
||||
input = this._instantiationService.createInstance(TerminalEditorInput, resource, instanceOrUri);
|
||||
this._registerInstance(inputKey, input, instanceOrUri);
|
||||
} else {
|
||||
input = this._instantiationService.createInstance(TerminalEditorInput, instanceOrUri, undefined);
|
||||
this._editorInputs.set(inputKey, input);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private _registerInstance(inputKey: string, input: TerminalEditorInput, instance: ITerminalInstance): void {
|
||||
this._editorInputs.set(inputKey, input);
|
||||
this._instanceDisposables.set(inputKey, [
|
||||
instance.onDidFocus(this._onDidFocusInstance.fire, this._onDidFocusInstance),
|
||||
toDisposable(() => this._editorInputs.delete(inputKey)),
|
||||
instance.onDisposed(this._onDidDisposeInstance.fire, this._onDidDisposeInstance)
|
||||
]);
|
||||
this.instances.push(instance);
|
||||
this._onDidChangeInstances.fire();
|
||||
return input;
|
||||
}
|
||||
|
||||
getInstanceFromResource(resource: URI | undefined): ITerminalInstance | undefined {
|
||||
if (URI.isUri(resource)) {
|
||||
// note that the uri and and instance id might
|
||||
// not match this window
|
||||
for (const instance of this.instances) {
|
||||
if (instance.resource.path === resource.path) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig: IShellLaunchConfig = {}): ITerminalInstance {
|
||||
|
@ -202,9 +253,10 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor
|
|||
}
|
||||
|
||||
detachInstance(instance: ITerminalInstance) {
|
||||
const editorInput = this._editorInputs.get(instance.instanceId);
|
||||
const inputKey = instance.resource.path;
|
||||
const editorInput = this._editorInputs.get(inputKey);
|
||||
editorInput?.detachInstance();
|
||||
this._editorInputs.delete(instance.instanceId);
|
||||
this._editorInputs.delete(inputKey);
|
||||
const instanceIndex = this.instances.findIndex(e => e === instance);
|
||||
if (instanceIndex !== -1) {
|
||||
this.instances.splice(instanceIndex, 1);
|
||||
|
@ -213,8 +265,8 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor
|
|||
if (!this._isShuttingDown) {
|
||||
editorInput?.dispose();
|
||||
}
|
||||
const disposables = this._instanceDisposables.get(instance.instanceId);
|
||||
this._instanceDisposables.delete(instance.instanceId);
|
||||
const disposables = this._instanceDisposables.get(inputKey);
|
||||
this._instanceDisposables.delete(inputKey);
|
||||
if (disposables) {
|
||||
dispose(disposables);
|
||||
}
|
||||
|
@ -227,7 +279,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor
|
|||
return;
|
||||
}
|
||||
|
||||
const editorInput = this._editorInputs.get(instance.instanceId)!;
|
||||
const editorInput = this._editorInputs.get(instance.resource.path)!;
|
||||
this._editorService.openEditor(
|
||||
editorInput,
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
|||
import { timeout } from 'vs/base/common/async';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
@ -175,6 +176,19 @@ export class TerminalGroupService extends Disposable implements ITerminalGroupSe
|
|||
}
|
||||
}
|
||||
|
||||
getInstanceFromResource(resource: URI | undefined): ITerminalInstance | undefined {
|
||||
if (URI.isUri(resource)) {
|
||||
// note that the uri and and instance id might
|
||||
// not match this window
|
||||
for (const instance of this.instances) {
|
||||
if (instance.resource.path === resource.path) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
findNext(): void {
|
||||
const pane = this._viewsService.getActiveViewWithId<TerminalViewPane>(TERMINAL_VIEW_ID);
|
||||
if (pane?.terminalTabbedView) {
|
||||
|
|
|
@ -66,6 +66,7 @@ import { Color } from 'vs/base/common/color';
|
|||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { TerminalStorageKeys } from 'vs/workbench/contrib/terminal/common/terminalStorageKeys';
|
||||
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
|
||||
import { getTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri';
|
||||
|
||||
// How long in milliseconds should an average frame take to render for a notification to appear
|
||||
// which suggests the fallback DOM-based renderer
|
||||
|
@ -152,6 +153,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
|||
private _navigationModeAddon: INavigationMode & ITerminalAddon | undefined;
|
||||
private _dndObserver: IDisposable | undefined;
|
||||
|
||||
private readonly _resource: URI;
|
||||
|
||||
private _lastLayoutDimensions: dom.Dimension | undefined;
|
||||
|
||||
private _hasHadInput: boolean;
|
||||
|
@ -160,13 +163,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
|||
disableLayout: boolean = false;
|
||||
target?: TerminalLocation;
|
||||
get instanceId(): number { return this._instanceId; }
|
||||
get resource(): URI {
|
||||
return URI.from({
|
||||
scheme: Schemas.vscodeTerminal,
|
||||
path: `/${this._workspaceContextService.getWorkspace().id}/${this.instanceId}`,
|
||||
fragment: this.title,
|
||||
});
|
||||
}
|
||||
get resource(): URI { return this._resource; }
|
||||
get cols(): number {
|
||||
if (this._dimensionsOverride && this._dimensionsOverride.cols) {
|
||||
if (this._dimensionsOverride.forceExactSize) {
|
||||
|
@ -253,6 +250,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
|||
private readonly _terminalAltBufferActiveContextKey: IContextKey<boolean>,
|
||||
private readonly _configHelper: TerminalConfigHelper,
|
||||
private _shellLaunchConfig: IShellLaunchConfig,
|
||||
resource: URI | undefined,
|
||||
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
|
||||
@ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
|
@ -287,6 +285,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
|||
this._titleReadyComplete = c;
|
||||
});
|
||||
|
||||
// the resource is already set when it's been moved from another window
|
||||
this._resource = resource || getTerminalUri(this._workspaceContextService.getWorkspace().id, this.instanceId, this.title);
|
||||
|
||||
this._terminalHasTextContextKey = TerminalContextKeys.textSelected.bindTo(this._contextKeyService);
|
||||
this._terminalA11yTreeFocusContextKey = TerminalContextKeys.a11yTreeFocus.bindTo(this._contextKeyService);
|
||||
this._terminalAltBufferActiveContextKey = TerminalContextKeys.altBufferActive.bindTo(this._contextKeyService);
|
||||
|
|
|
@ -53,16 +53,17 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
|
|||
this._configHelper = _instantiationService.createInstance(TerminalConfigHelper);
|
||||
}
|
||||
|
||||
createInstance(profile: ITerminalProfile, target?: TerminalLocation): ITerminalInstance;
|
||||
createInstance(shellLaunchConfig: IShellLaunchConfig, target?: TerminalLocation): ITerminalInstance;
|
||||
createInstance(config: IShellLaunchConfig | ITerminalProfile, target?: TerminalLocation): ITerminalInstance {
|
||||
createInstance(profile: ITerminalProfile, target?: TerminalLocation, resource?: URI): ITerminalInstance;
|
||||
createInstance(shellLaunchConfig: IShellLaunchConfig, target?: TerminalLocation, resource?: URI): ITerminalInstance;
|
||||
createInstance(config: IShellLaunchConfig | ITerminalProfile, target?: TerminalLocation, resource?: URI): ITerminalInstance {
|
||||
const shellLaunchConfig = this._convertProfileToShellLaunchConfig(config);
|
||||
const instance = this._instantiationService.createInstance(TerminalInstance,
|
||||
this._terminalFocusContextKey,
|
||||
this._terminalShellTypeContextKey,
|
||||
this._terminalAltBufferActiveContextKey,
|
||||
this._configHelper,
|
||||
shellLaunchConfig
|
||||
shellLaunchConfig,
|
||||
resource
|
||||
);
|
||||
instance.target = target;
|
||||
this._onDidCreateInstance.fire(instance);
|
||||
|
|
|
@ -11,7 +11,6 @@ import { Emitter, Event } from 'vs/base/common/event';
|
|||
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { equals } from 'vs/base/common/objects';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { isMacintosh, isWeb, isWindows, OperatingSystem, OS } from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
|
@ -30,14 +29,14 @@ import { iconForeground } from 'vs/platform/theme/common/colorRegistry';
|
|||
import { IconDefinition } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { ColorScheme } from 'vs/platform/theme/common/theme';
|
||||
import { IThemeService, Themable, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { VirtualWorkspaceContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { IEditableData, IViewsService } from 'vs/workbench/common/views';
|
||||
import { IRemoteTerminalService, ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalFindHost, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalInstanceService, ITerminalProfileProvider, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteTerminalService, IRequestAddInstanceToGroupEvent, ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalFindHost, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceHost, ITerminalInstanceService, ITerminalProfileProvider, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
||||
import { TerminalEditor } from 'vs/workbench/contrib/terminal/browser/terminalEditor';
|
||||
import { getColorClass, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
|
||||
import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons';
|
||||
import { getTerminalUri, parseTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri';
|
||||
import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView';
|
||||
import { ILocalTerminalService, IOffProcessTerminalService, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalProcessExtHostProxy, ITerminalProfileContribution, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
|
||||
|
@ -160,7 +159,6 @@ export class TerminalService implements ITerminalService {
|
|||
@IEditorResolverService editorResolverService: IEditorResolverService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||
@optional(ILocalTerminalService) localTerminalService: ILocalTerminalService
|
||||
) {
|
||||
this._localTerminalService = localTerminalService;
|
||||
|
@ -187,11 +185,9 @@ export class TerminalService implements ITerminalService {
|
|||
if (sourceGroup) {
|
||||
sourceGroup.removeInstance(instance);
|
||||
}
|
||||
} else {
|
||||
instance = _terminalInstanceService.createInstance({});
|
||||
}
|
||||
return {
|
||||
editor: this._terminalEditorService.getOrCreateEditorInput(instance),
|
||||
editor: this._terminalEditorService.getOrCreateEditorInput(instance || resource),
|
||||
options: {
|
||||
...options,
|
||||
pinned: true,
|
||||
|
@ -262,10 +258,11 @@ export class TerminalService implements ITerminalService {
|
|||
: Promise.resolve();
|
||||
this._primaryOffProcessTerminalService = !!this._environmentService.remoteAuthority ? this._remoteTerminalService : (this._localTerminalService || this._remoteTerminalService);
|
||||
this._primaryOffProcessTerminalService.onDidRequestDetach(async (e) => {
|
||||
if (e.workspaceId && this._workspaceContextService.getWorkspace().id === e.workspaceId) {
|
||||
const instanceToDetach = this.getInstanceFromId(e.instanceId);
|
||||
const instanceToDetach = this.getInstanceFromResource(getTerminalUri(e.workspaceId, e.instanceId));
|
||||
if (instanceToDetach) {
|
||||
const persistentProcessId = instanceToDetach?.persistentProcessId;
|
||||
if (persistentProcessId && !instanceToDetach.shellLaunchConfig.isFeatureTerminal && !instanceToDetach.shellLaunchConfig.customPtyImplementation) {
|
||||
this._terminalEditorService.detachInstance(instanceToDetach);
|
||||
await instanceToDetach.detachFromProcess();
|
||||
await this._primaryOffProcessTerminalService?.acceptDetachInstanceReply(e.requestId, persistentProcessId);
|
||||
} else {
|
||||
|
@ -274,6 +271,7 @@ export class TerminalService implements ITerminalService {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
initPromise.then(() => this._setConnected());
|
||||
|
||||
// Wait up to 5 seconds for profiles to be ready so it's assured that we know the actual
|
||||
|
@ -609,25 +607,17 @@ export class TerminalService implements ITerminalService {
|
|||
|
||||
getInstanceFromResource(resource: URI | undefined): ITerminalInstance | undefined {
|
||||
if (URI.isUri(resource)) {
|
||||
const instanceId = this._getInstanceIdFromUri(resource);
|
||||
if (instanceId) {
|
||||
return this.getInstanceFromId(instanceId);
|
||||
// note that the uri and and instance id might
|
||||
// not match this window
|
||||
for (const instance of this.instances) {
|
||||
if (instance.resource.path === resource.path) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _getInstanceIdFromUri(resource: URI): number | undefined {
|
||||
if (resource.scheme !== Schemas.vscodeTerminal) {
|
||||
return undefined;
|
||||
}
|
||||
const base = basename(resource.path);
|
||||
if (base === '') {
|
||||
return undefined;
|
||||
}
|
||||
return parseInt(base);
|
||||
}
|
||||
|
||||
isAttachedToTerminal(remoteTerm: IRemoteTerminalAttachTarget): boolean {
|
||||
return this.instances.some(term => term.processId === remoteTerm.pid);
|
||||
}
|
||||
|
@ -673,7 +663,6 @@ export class TerminalService implements ITerminalService {
|
|||
break;
|
||||
}
|
||||
|
||||
this._initInstanceListeners(instance);
|
||||
|
||||
if (instanceToSplit.target !== TerminalLocation.Editor) {
|
||||
this._terminalGroupService.groups.forEach((g, i) => g.setVisible(i === this._terminalGroupService.activeGroupIndex));
|
||||
|
@ -753,25 +742,41 @@ export class TerminalService implements ITerminalService {
|
|||
}));
|
||||
instance.addDisposable(instance.onMaximumDimensionsChanged(() => this._onDidMaxiumumDimensionsChange.fire(instance)));
|
||||
instance.addDisposable(instance.onDidFocus(this._onDidChangeActiveInstance.fire, this._onDidChangeActiveInstance));
|
||||
instance.addDisposable(instance.onRequestAddInstanceToGroup(e => {
|
||||
const instanceId = this._getInstanceIdFromUri(e.uri);
|
||||
if (instanceId === undefined) {
|
||||
return;
|
||||
}
|
||||
instance.addDisposable(instance.onRequestAddInstanceToGroup(async e => await this._addInstanceToGroup(instance, e)));
|
||||
}
|
||||
|
||||
// View terminals
|
||||
let sourceInstance = this._terminalGroupService.instances.find(e => e.instanceId === instanceId);
|
||||
if (sourceInstance) {
|
||||
private async _addInstanceToGroup(instance: ITerminalInstance, e: IRequestAddInstanceToGroupEvent): Promise<void> {
|
||||
const terminalIdentifier = parseTerminalUri(e.uri);
|
||||
if (terminalIdentifier.instanceId === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sourceInstance: ITerminalInstance | undefined = this.getInstanceFromResource(e.uri);
|
||||
|
||||
// Terminal from a different window
|
||||
if (!sourceInstance) {
|
||||
const attachPersistentProcess = await this._primaryOffProcessTerminalService?.requestDetachInstance(terminalIdentifier.workspaceId, terminalIdentifier.instanceId);
|
||||
if (attachPersistentProcess) {
|
||||
sourceInstance = this.createTerminal({ config: { attachPersistentProcess }, resource: e.uri });
|
||||
this._terminalGroupService.moveInstance(sourceInstance, instance, e.side);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminal editors
|
||||
sourceInstance = this._terminalEditorService.instances.find(e => e.instanceId === instanceId);
|
||||
if (sourceInstance) {
|
||||
this.moveToTerminalView(sourceInstance, instance, e.side);
|
||||
}
|
||||
}));
|
||||
// View terminals
|
||||
sourceInstance = this._terminalGroupService.getInstanceFromResource(e.uri);
|
||||
if (sourceInstance) {
|
||||
this._terminalGroupService.moveInstance(sourceInstance, instance, e.side);
|
||||
return;
|
||||
}
|
||||
|
||||
// Terminal editors
|
||||
sourceInstance = this._terminalEditorService.getInstanceFromResource(e.uri);
|
||||
if (sourceInstance) {
|
||||
this.moveToTerminalView(sourceInstance, instance, e.side);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
registerProcessSupport(isSupported: boolean): void {
|
||||
|
@ -1073,12 +1078,11 @@ export class TerminalService implements ITerminalService {
|
|||
throw new Error('Could not create terminal when process support is not registered');
|
||||
}
|
||||
if (shellLaunchConfig.hideFromUser) {
|
||||
const instance = this._terminalInstanceService.createInstance(shellLaunchConfig);
|
||||
const instance = this._terminalInstanceService.createInstance(shellLaunchConfig, undefined, options?.resource);
|
||||
this._backgroundedTerminalInstances.push(instance);
|
||||
this._backgroundedTerminalDisposables.set(instance.instanceId, [
|
||||
instance.onDisposed(this._onDidDisposeInstance.fire, this._onDidDisposeInstance)
|
||||
]);
|
||||
this._initInstanceListeners(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
@ -1087,14 +1091,14 @@ export class TerminalService implements ITerminalService {
|
|||
let instance: ITerminalInstance;
|
||||
const target = options?.target || this.configHelper.config.defaultLocation;
|
||||
if (target === TerminalLocation.Editor) {
|
||||
instance = this._terminalInstanceService.createInstance(shellLaunchConfig);
|
||||
instance = this._terminalInstanceService.createInstance(shellLaunchConfig, undefined, options?.resource);
|
||||
instance.target = TerminalLocation.Editor;
|
||||
this._terminalEditorService.openEditor(instance);
|
||||
} else {
|
||||
// TODO: pass resource?
|
||||
const group = this._terminalGroupService.createGroup(shellLaunchConfig);
|
||||
instance = group.terminalInstances[0];
|
||||
}
|
||||
this._initInstanceListeners(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecy
|
|||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IProcessDetails } from 'vs/platform/terminal/common/terminalProcess';
|
||||
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
|
||||
import { parseTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
|
@ -577,8 +578,8 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop<ITerminalInstance> {
|
|||
// Attach terminals type to event
|
||||
const terminals: ITerminalInstance[] = dndData.filter(e => 'instanceId' in (e as any));
|
||||
if (terminals.length > 0) {
|
||||
originalEvent.dataTransfer.setData(DataTransfers.TERMINALS, JSON.stringify(terminals.map(e => e.resource.toString())));
|
||||
originalEvent.dataTransfer.setData(DataTransfers.RESOURCES, JSON.stringify(terminals.map(e => e.resource.toString())));
|
||||
originalEvent.dataTransfer.setData(DataTransfers.TERMINALS, JSON.stringify(terminals.map(e => e.instanceId)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,21 +619,22 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop<ITerminalInstance> {
|
|||
this._autoFocusInstance = undefined;
|
||||
|
||||
let sourceInstances: ITerminalInstance[] | undefined;
|
||||
const terminalResources = originalEvent.dataTransfer?.getData(DataTransfers.RESOURCES);
|
||||
const terminals = originalEvent.dataTransfer?.getData(DataTransfers.TERMINALS);
|
||||
let promises: Promise<IProcessDetails | undefined>[] = [];
|
||||
if (terminals && terminalResources) {
|
||||
const json = JSON.parse(terminalResources);
|
||||
const resources = originalEvent.dataTransfer?.getData(DataTransfers.TERMINALS);
|
||||
if (resources) {
|
||||
const json = JSON.parse(resources);
|
||||
for (const entry of json) {
|
||||
const uri = URI.parse(entry);
|
||||
const [, workspaceId, instanceId] = uri.path.split('/');
|
||||
if (workspaceId && instanceId) {
|
||||
const instance = this._terminalService.instances.find(e => e.resource.path === instanceId);
|
||||
if (instance) {
|
||||
sourceInstances = [instance];
|
||||
this._terminalService.moveToTerminalView(instance);
|
||||
} else if (this._offProcessTerminalService && workspaceId !== this._workspaceContextService.getWorkspace().id) {
|
||||
promises.push(this._offProcessTerminalService.requestDetachInstance(workspaceId, Number.parseInt(instanceId)));
|
||||
|
||||
const instance = this._terminalService.getInstanceFromResource(uri);
|
||||
if (instance) {
|
||||
sourceInstances = [instance];
|
||||
this._terminalService.moveToTerminalView(instance);
|
||||
} else if (this._offProcessTerminalService) {
|
||||
// why is this undefined
|
||||
const terminalIdentifier = parseTerminalUri(uri);
|
||||
if (terminalIdentifier.instanceId) {
|
||||
promises.push(this._offProcessTerminalService.requestDetachInstance(terminalIdentifier.workspaceId, terminalIdentifier.instanceId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
28
src/vs/workbench/contrib/terminal/browser/terminalUri.ts
Normal file
28
src/vs/workbench/contrib/terminal/browser/terminalUri.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export function parseTerminalUri(resource: URI): ITerminalIdentifier {
|
||||
const [, workspaceId, instanceId] = resource.path.split('/');
|
||||
if (!workspaceId || !Number.parseInt(instanceId)) {
|
||||
throw new Error(`Could not parse terminal uri for resource ${resource}`);
|
||||
}
|
||||
return { workspaceId, instanceId: Number.parseInt(instanceId) };
|
||||
}
|
||||
|
||||
export function getTerminalUri(workspaceId: string, instanceId: number, title?: string): URI {
|
||||
return URI.from({
|
||||
scheme: Schemas.vscodeTerminal,
|
||||
path: `/${workspaceId}/${instanceId}`,
|
||||
fragment: title || undefined,
|
||||
});
|
||||
}
|
||||
|
||||
export interface ITerminalIdentifier {
|
||||
workspaceId: string;
|
||||
instanceId: number | undefined;
|
||||
}
|
|
@ -481,7 +481,7 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem {
|
|||
const instance = this._terminalGroupService.activeInstance;
|
||||
if (e.dataTransfer && instance) {
|
||||
e.dataTransfer.setData(DataTransfers.RESOURCES, JSON.stringify([instance.resource.toString()]));
|
||||
e.dataTransfer.setData(DataTransfers.TERMINALS, JSON.stringify([instance.instanceId]));
|
||||
e.dataTransfer.setData(DataTransfers.TERMINALS, JSON.stringify([instance.resource.toString()]));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -1667,9 +1667,7 @@ export class TestLocalTerminalService implements ILocalTerminalService {
|
|||
onDidMoveWindowInstance = Event.None;
|
||||
onDidRequestDetach = Event.None;
|
||||
|
||||
async createProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean, shouldPersist: boolean): Promise<ITerminalChildProcess> {
|
||||
return new TestTerminalChildProcess(shouldPersist);
|
||||
}
|
||||
async createProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean, shouldPersist: boolean): Promise<ITerminalChildProcess> { return new TestTerminalChildProcess(shouldPersist); }
|
||||
async attachToProcess(id: number): Promise<ITerminalChildProcess | undefined> { throw new Error('Method not implemented.'); }
|
||||
async listProcesses(): Promise<IProcessDetails[]> { throw new Error('Method not implemented.'); }
|
||||
getDefaultSystemShell(osOverride?: OperatingSystem): Promise<string> { throw new Error('Method not implemented.'); }
|
||||
|
|
Loading…
Reference in a new issue