Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add actual IWorkspaceFolder to terminal instance #142116

Merged
merged 2 commits into from
Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/vs/workbench/contrib/terminal/browser/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/termi
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { ITerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';

export const ITerminalService = createDecorator<ITerminalService>('terminalService');
export const ITerminalEditorService = createDecorator<ITerminalEditorService>('terminalEditorService');
Expand Down Expand Up @@ -417,7 +418,7 @@ export interface ITerminalInstance {
readonly processName: string;
readonly sequence?: string;
readonly staticTitle?: string;
readonly workspaceFolder?: string;
readonly workspaceFolder?: IWorkspaceFolder;
readonly cwd?: string;
readonly initialCwd?: string;
readonly capabilities: ITerminalCapabilityStore;
Expand Down
37 changes: 28 additions & 9 deletions src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { DataTransfers } from 'vs/base/browser/dnd';
import { CodeDataTransfers, containsDragType, DragAndDropObserver, IDragAndDropObserverCallbacks } from 'vs/workbench/browser/dnd';
import { getColorClass, getColorStyleElement, getStandardColors } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
import { Orientation } from 'vs/base/browser/ui/sash/sash';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
import { getTerminalResourcesFromDragEvent, getTerminalUri } from 'vs/workbench/contrib/terminal/browser/terminalUri';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
Expand All @@ -76,6 +76,7 @@ import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/s
import { IDialogService, IConfirmationResult } from 'vs/platform/dialogs/common/dialogs';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { Schemas } from 'vs/base/common/network';
import { withNullAsUndefined } from 'vs/base/common/types';

const enum Constants {
/**
Expand Down Expand Up @@ -196,7 +197,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
private _processName: string = '';
private _sequence?: string;
private _staticTitle?: string;
private _workspaceFolder?: string;
private _workspaceFolder?: IWorkspaceFolder;
private _labelComputer?: TerminalLabelComputer;
private _userHome?: string;
private _hasScrollBar?: boolean;
Expand Down Expand Up @@ -271,7 +272,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
get processName(): string { return this._processName; }
get sequence(): string | undefined { return this._sequence; }
get staticTitle(): string | undefined { return this._staticTitle; }
get workspaceFolder(): string | undefined { return this._workspaceFolder; }
get workspaceFolder(): IWorkspaceFolder | undefined { return this._workspaceFolder; }
get cwd(): string | undefined { return this._cwd; }
get initialCwd(): string | undefined { return this._initialCwd; }
get description(): string | undefined {
Expand Down Expand Up @@ -375,6 +376,20 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// 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);

if (this.shellLaunchConfig.cwd) {
const cwdUri = typeof this._shellLaunchConfig.cwd === 'string' ? URI.from({
scheme: Schemas.file,
path: this._shellLaunchConfig.cwd
}) : this._shellLaunchConfig.cwd;
if (cwdUri) {
this._workspaceFolder = withNullAsUndefined(this._workspaceContextService.getWorkspaceFolder(cwdUri));
}
}
if (!this._workspaceFolder) {
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
this._workspaceFolder = activeWorkspaceRootUri ? withNullAsUndefined(this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined;
}

this._terminalHasTextContextKey = TerminalContextKeys.textSelected.bindTo(this._contextKeyService);
this._terminalA11yTreeFocusContextKey = TerminalContextKeys.a11yTreeFocus.bindTo(this._contextKeyService);
this._terminalAltBufferActiveContextKey = TerminalContextKeys.altBufferActive.bindTo(this._contextKeyService);
Expand Down Expand Up @@ -989,7 +1004,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._widgetManager.attachToElement(xterm.raw.element);
this._processManager.onProcessReady((e) => {
this._linkManager?.setWidgetManager(this._widgetManager);
this._workspaceFolder = path.basename(e.cwd.toString());
});

// const computedStyle = window.getComputedStyle(this._container);
Expand Down Expand Up @@ -2336,7 +2350,7 @@ export class TerminalLabelComputer extends Disposable {
const templateProperties: ITerminalLabelTemplateProperties = {
cwd: this._instance.cwd || this._instance.initialCwd || '',
cwdFolder: '',
workspaceFolder: this._instance.workspaceFolder,
workspaceFolder: this._instance.workspaceFolder ? path.basename(this._instance.workspaceFolder.uri.fsPath) : undefined,
local: this._instance.shellLaunchConfig.type === 'Local' ? this._instance.shellLaunchConfig.type : undefined,
process: this._instance.processName,
sequence: this._instance.sequence,
Expand All @@ -2355,11 +2369,16 @@ export class TerminalLabelComputer extends Disposable {
}
const detection = this._instance.capabilities.has(TerminalCapability.CwdDetection) || this._instance.capabilities.has(TerminalCapability.NaiveCwdDetection);
const folders = this._workspaceContextService.getWorkspace().folders;
const zeroRootWorkspace = folders.length === 0 && this.pathsEqual(templateProperties.cwd, this._instance.userHome || this._configHelper.config.cwd);
const singleRootWorkspace = folders.length === 1 && this.pathsEqual(templateProperties.cwd, this._configHelper.config.cwd || folders[0]?.uri.fsPath);
const multiRootWorkspace = folders.length > 1;
if (this._instance.cwd !== this._instance.initialCwd || multiRootWorkspace) {
templateProperties.cwdFolder = (!templateProperties.cwd || !detection || zeroRootWorkspace || singleRootWorkspace) ? '' : path.basename(templateProperties.cwd);

// Only set cwdFolder if detection is on
if (templateProperties.cwd && detection) {
const cwdUri = URI.from({ scheme: this._instance.workspaceFolder?.uri.scheme || Schemas.file, path: this._instance.cwd });
// Multi-root workspaces always show cwdFolder to disambiguate them, otherwise only show
// when it differs from the workspace folder in which it was launched from
if (multiRootWorkspace || cwdUri.fsPath !== this._instance.workspaceFolder?.uri.fsPath) {
templateProperties.cwdFolder = path.basename(templateProperties.cwd);
}
}

//Remove special characters that could mess with rendering
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { deepStrictEqual, strictEqual } from 'assert';
import { isWindows } from 'vs/base/common/platform';
import { TerminalLabelComputer, parseExitResult } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
import { IWorkspaceContextService, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceContextService, IWorkspaceFolder, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { Workspace } from 'vs/platform/workspace/test/common/testWorkspace';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
Expand All @@ -16,8 +16,10 @@ import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/term
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ProcessState } from 'vs/workbench/contrib/terminal/common/terminal';
import { basename } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { Schemas } from 'vs/base/common/network';

function createInstance(partial?: Partial<ITerminalInstance>): Pick<ITerminalInstance, 'shellLaunchConfig' | 'userHome' | 'cwd' | 'initialCwd' | 'processName' | 'sequence' | 'workspaceFolder' | 'staticTitle' | 'capabilities' | 'title' | 'description'> {
const capabilities = new TerminalCapabilityStore();
Expand Down Expand Up @@ -225,7 +227,7 @@ suite('Workbench - TerminalInstance', () => {
test('should resolve workspaceFolder', () => {
configurationService = new TestConfigurationService({ terminal: { integrated: { tabs: { separator: ' - ', title: '${workspaceFolder}', description: '${workspaceFolder}' } } } });
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'zsh', workspaceFolder: 'folder' }), mockContextService);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'zsh', workspaceFolder: { uri: URI.from({ scheme: Schemas.file, path: 'folder' }) } as IWorkspaceFolder }), mockContextService);
terminalLabelComputer.refreshLabel();
strictEqual(terminalLabelComputer.title, 'folder');
strictEqual(terminalLabelComputer.description, 'folder');
Expand Down Expand Up @@ -273,23 +275,23 @@ suite('Workbench - TerminalInstance', () => {
test('should always return static title when specified', () => {
configurationService = new TestConfigurationService({ terminal: { integrated: { tabs: { separator: ' ~ ', title: '${process}', description: '${workspaceFolder}' } } } });
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: 'folder', staticTitle: 'my-title' }), mockContextService);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: { uri: URI.from({ scheme: Schemas.file, path: 'folder' }) } as IWorkspaceFolder, staticTitle: 'my-title' }), mockContextService);
terminalLabelComputer.refreshLabel();
strictEqual(terminalLabelComputer.title, 'my-title');
strictEqual(terminalLabelComputer.description, 'folder');
});
test('should provide cwdFolder for all cwds only when in multi-root', () => {
configurationService = new TestConfigurationService({ terminal: { integrated: { tabs: { separator: ' ~ ', title: '${process}${separator}${cwdFolder}', description: '${cwdFolder}' } }, cwd: ROOT_1 } });
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: 'folder', cwd: ROOT_1 }), mockContextService);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: { uri: URI.from({ scheme: Schemas.file, path: 'folder' }) } as IWorkspaceFolder, cwd: ROOT_1 }), mockContextService);
terminalLabelComputer.refreshLabel();
// single-root, cwd is same as root
strictEqual(terminalLabelComputer.title, 'process');
strictEqual(terminalLabelComputer.description, '');
// multi-root
configurationService = new TestConfigurationService({ terminal: { integrated: { tabs: { separator: ' ~ ', title: '${process}${separator}${cwdFolder}', description: '${cwdFolder}' } }, cwd: ROOT_1 } });
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: 'folder', cwd: ROOT_2 }), mockMultiRootContextService);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: { uri: URI.from({ scheme: Schemas.file, path: 'folder' }) } as IWorkspaceFolder, cwd: ROOT_2 }), mockMultiRootContextService);
terminalLabelComputer.refreshLabel();
if (isWindows) {
strictEqual(terminalLabelComputer.title, 'process');
Expand All @@ -302,12 +304,12 @@ suite('Workbench - TerminalInstance', () => {
test('should hide cwdFolder in single folder workspaces when cwd matches the workspace\'s default cwd even when slashes differ', async () => {
configurationService = new TestConfigurationService({ terminal: { integrated: { tabs: { separator: ' ~ ', title: '${process}${separator}${cwdFolder}', description: '${cwdFolder}' } }, cwd: '\\foo\\root1' } });
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: 'folder', cwd: ROOT_1 }), mockContextService);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: { uri: URI.from({ scheme: Schemas.file, path: 'folder' }) } as IWorkspaceFolder, cwd: ROOT_1 }), mockContextService);
terminalLabelComputer.refreshLabel();
strictEqual(terminalLabelComputer.title, 'process');
strictEqual(terminalLabelComputer.description, '');
if (!isWindows) {
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: 'folder', cwd: ROOT_2 }), mockContextService);
terminalLabelComputer = new TerminalLabelComputer(configHelper, createInstance({ capabilities, processName: 'process', workspaceFolder: { uri: URI.from({ scheme: Schemas.file, path: 'folder' }) } as IWorkspaceFolder, cwd: ROOT_2 }), mockContextService);
terminalLabelComputer.refreshLabel();
strictEqual(terminalLabelComputer.title, 'process ~ root2');
strictEqual(terminalLabelComputer.description, 'root2');
Expand Down