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

+ button and context menu for terminal tabs #120878

Merged
merged 45 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
0203f8e
add plus button and terminalTabsContext
meganrogge Apr 8, 2021
7c2007b
Merge branch 'main' into merogge/tabs-button
meganrogge Apr 8, 2021
9bcf5a5
try to modify tabsMenu actions
meganrogge Apr 8, 2021
99868a3
get profiles to appear in context menu, not working yet
meganrogge Apr 8, 2021
4c02536
get context menu to work
meganrogge Apr 8, 2021
4d1131b
revert a change
meganrogge Apr 8, 2021
fbf86d3
on create, focus active instance
meganrogge Apr 9, 2021
5cadd12
Merge remote-tracking branch 'origin/main' into merogge/tabs-button
Tyriar Apr 9, 2021
18c0f5a
add context menu groups
meganrogge Apr 9, 2021
6fe8914
remember split across sessions and set sane default
meganrogge Apr 9, 2021
c6d0c11
add check for show tabs and return min_width isntead of 0
meganrogge Apr 9, 2021
261862e
make private readonly vars
meganrogge Apr 9, 2021
5c7879c
Merge branch 'main' into merogge/tabs-button
meganrogge Apr 9, 2021
c15d1c3
remove one command via consolidation
meganrogge Apr 9, 2021
ee4bfad
use custom icons on reconnect/reload 😄
meganrogge Apr 9, 2021
8a8e233
move + button to the top
meganrogge Apr 9, 2021
41861dc
switch tabs when instance is clicked on in tabs widget
meganrogge Apr 9, 2021
4c78efd
add snap when in no-man's land
meganrogge Apr 9, 2021
8e41cc0
test commit signing
meganrogge Apr 12, 2021
82a5fe0
test 2
meganrogge Apr 12, 2021
08a9de6
add rename to context menu
meganrogge Apr 12, 2021
f880276
fix #120906 panel issues
meganrogge Apr 12, 2021
2864eba
get rid of twisties
meganrogge Apr 12, 2021
9de2551
add actions to items
meganrogge Apr 12, 2021
7dd9fe7
only show actions on terminal isntances
meganrogge Apr 12, 2021
1132a8a
only show rows on hover
meganrogge Apr 12, 2021
48e7505
reformat
meganrogge Apr 12, 2021
ed139c1
hide label text when min view Co-Authored-By: Daniel Imms <daimms@mic…
meganrogge Apr 13, 2021
75bce49
fix css
meganrogge Apr 13, 2021
80dba2b
set min width Co-Authored-By: Daniel Imms <daimms@microsoft.com>
meganrogge Apr 13, 2021
cb6a3cc
add rename Co-Authored-By: Daniel Imms <daimms@microsoft.com>
meganrogge Apr 13, 2021
bacfb76
localize action names
meganrogge Apr 13, 2021
b3ff207
get text to show or hide appropriately
meganrogge Apr 13, 2021
ab65074
add instance connectors
meganrogge Apr 13, 2021
abf4835
use tab instead of terminals
meganrogge Apr 13, 2021
7123044
get button to stay on the page
meganrogge Apr 13, 2021
a009997
align button
meganrogge Apr 13, 2021
51451d8
get rid of unused menu
meganrogge Apr 13, 2021
4dfa06c
snap right or left based on midpt
meganrogge Apr 13, 2021
3357bf2
fix hideText
meganrogge Apr 13, 2021
6e5a0a5
Update src/vs/workbench/contrib/terminal/browser/media/terminal.css
meganrogge Apr 13, 2021
388a0c8
change type of icon to string | undefined
meganrogge Apr 13, 2021
294e3eb
make private readonly in constructor
meganrogge Apr 13, 2021
9cd8ff4
🧹
meganrogge Apr 13, 2021
066dae2
Merge remote-tracking branch 'origin/main' into merogge/tabs-button
Tyriar Apr 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export class MenuId {
static readonly AccountsContext = new MenuId('AccountsContext');
static readonly PanelTitle = new MenuId('PanelTitle');
static readonly TerminalContext = new MenuId('TerminalContext');
static readonly TerminalTabsContext = new MenuId('TerminalTabsContext');

readonly id: number;
readonly _debugName: string;
Expand Down
3 changes: 2 additions & 1 deletion src/vs/platform/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface IPtyHostAttachTarget {
workspaceId: string;
workspaceName: string;
isOrphan: boolean;
icon?: string;
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
}

export type ITerminalsLayoutInfo = IRawTerminalsLayoutInfo<IPtyHostAttachTarget | null>;
Expand Down Expand Up @@ -251,7 +252,7 @@ export interface IShellLaunchConfig {
/**
* This is a terminal that attaches to an already running terminal.
*/
attachPersistentProcess?: { id: number; pid: number; title: string; cwd: string; };
attachPersistentProcess?: { id: number; pid: number; title: string; cwd: string; icon?: string; };

/**
* Whether the terminal process environment should be exactly as provided in
Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/terminal/common/terminalProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface IProcessDetails {
workspaceId: string;
workspaceName: string;
isOrphan: boolean;
icon?: string;
}

export type ITerminalTabLayoutInfoDto = IRawTerminalTabLayoutInfo<IProcessDetails>;
Expand Down
9 changes: 6 additions & 3 deletions src/vs/platform/terminal/node/ptyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class PtyService extends Disposable implements IPtyService {
if (process.onProcessResolvedShellLaunchConfig) {
process.onProcessResolvedShellLaunchConfig(event => this._onProcessResolvedShellLaunchConfig.fire({ id, event }));
}
const persistentProcess = new PersistentTerminalProcess(id, process, workspaceId, workspaceName, shouldPersist, cols, rows, this._logService);
const persistentProcess = new PersistentTerminalProcess(id, process, workspaceId, workspaceName, shouldPersist, cols, rows, this._logService, shellLaunchConfig.icon,);
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
process.onProcessExit(() => {
persistentProcess.dispose();
this._ptys.delete(id);
Expand Down Expand Up @@ -217,7 +217,8 @@ export class PtyService extends Disposable implements IPtyService {
workspaceId: persistentProcess.workspaceId,
workspaceName: persistentProcess.workspaceName,
cwd,
isOrphan
isOrphan,
icon: persistentProcess.icon
};
}

Expand Down Expand Up @@ -267,6 +268,7 @@ export class PersistentTerminalProcess extends Disposable {

get pid(): number { return this._pid; }
get title(): string { return this._terminalProcess.currentTitle; }
get icon(): string | undefined { return this._icon; }

constructor(
private _persistentProcessId: number,
Expand All @@ -275,7 +277,8 @@ export class PersistentTerminalProcess extends Disposable {
public readonly workspaceName: string,
public readonly shouldPersistTerminal: boolean,
cols: number, rows: number,
private readonly _logService: ILogService
private readonly _logService: ILogService,
private readonly _icon?: string
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
) {
super();
this._recorder = new TerminalRecorder(cols, rows);
Expand Down
44 changes: 44 additions & 0 deletions src/vs/workbench/contrib/terminal/browser/media/terminal.css
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,50 @@
padding: 0 22px 0 6px;
}

#terminal-tabs-plus-button {
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
min-height: 10;
flex-grow: 0;
text-align: center;
z-index: 10;
}

#terminal-tabs-plus-button.align-left {
padding-left: 10px;
text-align: left;
z-index: 10;
}

.tabs-container {
display: flex;
flex-direction: column;
}

.tabs-widget .terminal-tabs-entry {
text-align: center;
}

.tabs-widget .terminal-tabs-entry.has-text {
padding-left: 10px;
text-align: left;
}

.monaco-workbench .tabs-widget .codicon {
vertical-align: text-bottom;
}

.tabs-widget .monaco-tl-twistie.force-no-twistie {
display: none !important;
}

.tabs-widget .actions {
display: none;
}

.tabs-widget .actions .action-label {
padding: 2px;
}

.tabs-widget .monaco-list-row:hover .actions
{
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
display: block;
}
2 changes: 2 additions & 0 deletions src/vs/workbench/contrib/terminal/browser/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ export interface ITerminalService {
*/
getAvailableProfiles(): ITerminalProfile[];

getTabForInstance(instance: ITerminalInstance): ITerminalTab | undefined;

setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
manageWorkspaceShellPermissions(): void;

Expand Down
60 changes: 55 additions & 5 deletions src/vs/workbench/contrib/terminal/browser/terminalActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/w
import { FindInFilesCommand, IFindInFilesArgs } from 'vs/workbench/contrib/search/browser/searchActions';
import { Direction, IRemoteTerminalService, ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalQuickAccessProvider } from 'vs/workbench/contrib/terminal/browser/terminalQuickAccess';
import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_ACTION_CATEGORY, TERMINAL_COMMAND_ID, TERMINAL_VIEW_ID, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal';
import { IRemoteTerminalAttachTarget, ITerminalConfigHelper, ITerminalProfile, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, KEYBINDING_CONTEXT_TERMINAL_ALT_BUFFER_ACTIVE, KEYBINDING_CONTEXT_TERMINAL_FIND_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_ACTION_CATEGORY, TERMINAL_COMMAND_ID, TERMINAL_VIEW_ID, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalContributionService } from 'vs/workbench/contrib/terminal/common/terminalExtensionPoints';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
Expand All @@ -48,6 +48,12 @@ const enum ContextMenuGroup {
Kill = '4_kill'
}

export const enum ContextMenuTabsGroup {
Default = '1_create_default',
Profile = '2_create_profile',
Configure = '3_configure'
}

async function getCwdForSplit(configHelper: ITerminalConfigHelper, instance: ITerminalInstance, folders?: IWorkspaceFolder[], commandService?: ICommandService): Promise<string | URI | undefined> {
switch (configHelper.config.splitCwd) {
case 'workspaceRoot':
Expand Down Expand Up @@ -135,13 +141,30 @@ export function registerTerminalActions() {
id: TERMINAL_COMMAND_ID.NEW_WITH_PROFILE,
title: { value: localize('workbench.action.terminal.newWithProfile', "Create New Integrated Terminal (With Profile)"), original: 'Create New Integrated Terminal (With Profile)' },
f1: true,
category
category,
description: {
description: 'workbench.action.terminal.newWithProfile',
args: [{
name: 'profile',
schema: {
type: 'object'
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
}
}]
},
});
}
async run(accessor: ServicesAccessor) {
await accessor.get(ITerminalService).showProfileQuickPick('createInstance');
async run(accessor: ServicesAccessor, profile?: ITerminalProfile) {
const terminalService = accessor.get(ITerminalService);
if (profile) {
const instance = await terminalService.createTerminal(profile);
terminalService.setActiveInstance(instance);
return terminalService.showPanel(true);
} else {
await terminalService.showProfileQuickPick('createInstance');
}
}
});

registerAction2(class extends Action2 {
constructor() {
super({
Expand Down Expand Up @@ -629,6 +652,13 @@ export function registerTerminalActions() {
});
}
});
MenuRegistry.appendMenuItem(MenuId.TerminalContext, {
command: {
id: TERMINAL_COMMAND_ID.RENAME,
title: localize('workbench.action.terminal.rename', "Rename")
},
group: ContextMenuGroup.Edit
});
registerAction2(class extends Action2 {
constructor() {
super({
Expand Down Expand Up @@ -1288,6 +1318,13 @@ export function registerTerminalActions() {
},
group: ContextMenuGroup.Create
});
MenuRegistry.appendMenuItem(MenuId.TerminalTabsContext, {
command: {
id: TERMINAL_COMMAND_ID.NEW,
title: localize('workbench.action.terminal.new.short', "New Terminal")
},
group: ContextMenuTabsGroup.Default
});
registerAction2(class extends Action2 {
constructor() {
super({
Expand Down Expand Up @@ -1365,6 +1402,13 @@ export function registerTerminalActions() {
await accessor.get(ITerminalService).showProfileQuickPick('setDefault');
}
});
MenuRegistry.appendMenuItem(MenuId.TerminalTabsContext, {
command: {
id: TERMINAL_COMMAND_ID.SELECT_DEFAULT_PROFILE,
title: { value: localize('workbench.action.terminal.selectDefaultProfile', "Select Default Profile"), original: 'Select Default Profile' }
},
group: ContextMenuTabsGroup.Configure
});
registerAction2(class extends Action2 {
constructor() {
super({
Expand All @@ -1379,7 +1423,13 @@ export function registerTerminalActions() {
await accessor.get(IPreferencesService).openSettings(false, '@feature:terminal');
}
});

MenuRegistry.appendMenuItem(MenuId.TerminalTabsContext, {
command: {
id: TERMINAL_COMMAND_ID.CONFIGURE_TERMINAL_SETTINGS,
title: localize(configureTerminalSettingsTitle, 'Configure Terminal Settings')
},
group: ContextMenuTabsGroup.Configure
});
// Some commands depend on platform features
if (BrowserFeatures.clipboard.writeText) {
registerAction2(class extends Action2 {
Expand Down
11 changes: 10 additions & 1 deletion src/vs/workbench/contrib/terminal/browser/terminalInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
public get commandTracker(): CommandTrackerAddon | undefined { return this._commandTrackerAddon; }
public get navigationMode(): INavigationMode | undefined { return this._navigationModeAddon; }
public get isDisconnected(): boolean { return this._processManager.isDisconnected; }
public get icon(): Codicon { return this.shellLaunchConfig.icon ? (iconRegistry.get(this.shellLaunchConfig.icon) || Codicon.terminal) : Codicon.terminal; }
public get icon(): Codicon { return this._getIcon(); }

private readonly _onExit = new Emitter<number | undefined>();
public get onExit(): Event<number | undefined> { return this._onExit.event; }
Expand Down Expand Up @@ -295,6 +295,15 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
});
}

private _getIcon(): Codicon {
if (this.shellLaunchConfig.icon) {
return iconRegistry.get(this.shellLaunchConfig.icon) || Codicon.terminal;
} else if (this.shellLaunchConfig?.attachPersistentProcess?.icon) {
return iconRegistry.get(this.shellLaunchConfig.attachPersistentProcess.icon) || Codicon.terminal;
}
return Codicon.terminal;
}

public addDisposable(disposable: IDisposable): void {
this._register(disposable);
}
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/contrib/terminal/browser/terminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ export class TerminalService implements ITerminalService {
if (!terminalInstance) {
// create tab and terminal
terminalInstance = this.createTerminal({ attachPersistentProcess: terminalLayout.terminal! });
tab = this._getTabForInstance(terminalInstance);
tab = this.getTabForInstance(terminalInstance);
if (tabLayout.isActive) {
activeTab = tab;
}
Expand Down Expand Up @@ -650,7 +650,7 @@ export class TerminalService implements ITerminalService {
public splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfig?: IShellLaunchConfig): ITerminalInstance | null;
public splitInstance(instanceToSplit: ITerminalInstance, profile: ITerminalProfile): ITerminalInstance | null
public splitInstance(instanceToSplit: ITerminalInstance, shellLaunchConfigOrProfile: IShellLaunchConfig | ITerminalProfile = {}): ITerminalInstance | null {
const tab = this._getTabForInstance(instanceToSplit);
const tab = this.getTabForInstance(instanceToSplit);
if (!tab) {
return null;
}
Expand Down Expand Up @@ -715,7 +715,7 @@ export class TerminalService implements ITerminalService {
}
}

private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | undefined {
public getTabForInstance(instance: ITerminalInstance): ITerminalTab | undefined {
return this._terminalTabs.find(tab => tab.terminalInstances.indexOf(instance) !== -1);
}

Expand Down