diff --git a/terminus-core/src/components/appRoot.component.pug b/terminus-core/src/components/appRoot.component.pug index 9cdb3eeb..e9ac6404 100644 --- a/terminus-core/src/components/appRoot.component.pug +++ b/terminus-core/src/components/appRoot.component.pug @@ -44,11 +44,13 @@ title-bar( ngbDropdownToggle, ) div(*ngIf='button.submenu', ngbDropdownMenu) - button.dropdown-item( + button.dropdown-item.d-flex.align-items-center( *ngFor='let item of button.submenuItems', (click)='item.click()', ngbDropdownItem, - ) {{item.title}} + ) + .icon-wrapper([innerHTML]='item.icon') + .ml-3 {{item.title}} .drag-space.background([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS') @@ -65,11 +67,13 @@ title-bar( ngbDropdownToggle, ) div(*ngIf='button.submenu', ngbDropdownMenu) - button.dropdown-item( + button.dropdown-item.d-flex.align-items-center( *ngFor='let item of button.submenuItems', (click)='item.click()', ngbDropdownItem, - ) {{item.title}} + ) + .icon-wrapper([innerHTML]='item.icon') + .ml-3 {{item.title}} button.btn.btn-secondary.btn-tab-bar.btn-update( *ngIf='updatesAvailable', diff --git a/terminus-core/src/components/appRoot.component.scss b/terminus-core/src/components/appRoot.component.scss index fa10e61a..9c8f3370 100644 --- a/terminus-core/src/components/appRoot.component.scss +++ b/terminus-core/src/components/appRoot.component.scss @@ -88,12 +88,20 @@ hotkey-hint { max-width: 300px; } -::ng-deep .btn-tab-bar svg { +::ng-deep .btn-tab-bar svg, +::ng-deep .btn-tab-bar + .dropdown-menu svg { + width: 16px; height: 16px; fill: white; fill-opacity: 0.75; } +.icon-wrapper { + display: flex; + width: 16px; + height: 17px; +} + ::ng-deep .btn-update svg { fill: cyan; } diff --git a/terminus-terminal/src/api.ts b/terminus-terminal/src/api.ts index 0b81a208..6f1f4bbb 100644 --- a/terminus-terminal/src/api.ts +++ b/terminus-terminal/src/api.ts @@ -1,3 +1,4 @@ +import { SafeHtml } from '@angular/platform-browser' import { BaseTerminalTabComponent } from './components/baseTerminalTab.component' /** @@ -36,6 +37,7 @@ export interface Profile { name: string, sessionOptions: SessionOptions, isBuiltin?: boolean + icon?: SafeHtml } export interface ITerminalColorScheme { @@ -74,6 +76,13 @@ export interface IShell { * Currently used for WSL only */ fsBase?: string + + /** + * SVG icon + */ + icon?: SafeHtml + + hidden?: boolean } /** diff --git a/terminus-terminal/src/buttonProvider.ts b/terminus-terminal/src/buttonProvider.ts index ba72033a..6d0b58eb 100644 --- a/terminus-terminal/src/buttonProvider.ts +++ b/terminus-terminal/src/buttonProvider.ts @@ -46,7 +46,7 @@ export class ButtonProvider extends ToolbarButtonProvider { submenu: async () => { let profiles = await this.terminal.getProfiles() return profiles.map(profile => ({ - icon: null, + icon: profile.icon, title: profile.name, click: () => this.terminal.openTab(profile), })) diff --git a/terminus-terminal/src/components/shellSettingsTab.component.pug b/terminus-terminal/src/components/shellSettingsTab.component.pug index c8d8df93..294970a0 100644 --- a/terminus-terminal/src/components/shellSettingsTab.component.pug +++ b/terminus-terminal/src/components/shellSettingsTab.component.pug @@ -11,7 +11,7 @@ h3.mb-3 Shell ) option( *ngFor='let profile of profiles', - [ngValue]='slug(profile.name)' + [ngValue]='slug(profile.name).toLowerCase()' ) {{profile.name}} diff --git a/terminus-terminal/src/components/shellSettingsTab.component.ts b/terminus-terminal/src/components/shellSettingsTab.component.ts index 904ee839..b2a22491 100644 --- a/terminus-terminal/src/components/shellSettingsTab.component.ts +++ b/terminus-terminal/src/components/shellSettingsTab.component.ts @@ -47,7 +47,7 @@ export class ShellSettingsTabComponent { } async reload () { - this.profiles = await this.terminalService.getProfiles() + this.profiles = await this.terminalService.getProfiles(true) } pickWorkingDirectory () { diff --git a/terminus-terminal/src/hotkeys.ts b/terminus-terminal/src/hotkeys.ts index f79f4b6b..4c99bf1a 100644 --- a/terminus-terminal/src/hotkeys.ts +++ b/terminus-terminal/src/hotkeys.ts @@ -74,7 +74,7 @@ export class TerminalHotkeyProvider extends HotkeyProvider { return [ ...this.hotkeys, ...profiles.map(profile => ({ - id: `profile.${slug(profile.name)}`, + id: `profile.${slug(profile.name).toLowerCase()}`, name: `New tab: ${profile.name}` })), ] diff --git a/terminus-terminal/src/icons/clink.svg b/terminus-terminal/src/icons/clink.svg new file mode 100644 index 00000000..b6b04d5d --- /dev/null +++ b/terminus-terminal/src/icons/clink.svg @@ -0,0 +1 @@ + diff --git a/terminus-terminal/src/icons/cmd.svg b/terminus-terminal/src/icons/cmd.svg new file mode 100644 index 00000000..5d954144 --- /dev/null +++ b/terminus-terminal/src/icons/cmd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/terminus-terminal/src/icons/cmder-powershell.svg b/terminus-terminal/src/icons/cmder-powershell.svg new file mode 100644 index 00000000..1147deca --- /dev/null +++ b/terminus-terminal/src/icons/cmder-powershell.svg @@ -0,0 +1 @@ + diff --git a/terminus-terminal/src/icons/cmder.svg b/terminus-terminal/src/icons/cmder.svg new file mode 100644 index 00000000..3c2fc656 --- /dev/null +++ b/terminus-terminal/src/icons/cmder.svg @@ -0,0 +1 @@ + diff --git a/terminus-terminal/src/icons/cygwin.svg b/terminus-terminal/src/icons/cygwin.svg new file mode 100644 index 00000000..bda71929 --- /dev/null +++ b/terminus-terminal/src/icons/cygwin.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/terminus-terminal/src/icons/git-bash.svg b/terminus-terminal/src/icons/git-bash.svg new file mode 100644 index 00000000..3bb9db89 --- /dev/null +++ b/terminus-terminal/src/icons/git-bash.svg @@ -0,0 +1 @@ + diff --git a/terminus-terminal/src/icons/powershell-core.svg b/terminus-terminal/src/icons/powershell-core.svg new file mode 100644 index 00000000..5ba9285d --- /dev/null +++ b/terminus-terminal/src/icons/powershell-core.svg @@ -0,0 +1 @@ + diff --git a/terminus-terminal/src/icons/powershell.svg b/terminus-terminal/src/icons/powershell.svg new file mode 100644 index 00000000..8d2a74ed --- /dev/null +++ b/terminus-terminal/src/icons/powershell.svg @@ -0,0 +1 @@ + diff --git a/terminus-terminal/src/index.ts b/terminus-terminal/src/index.ts index 7f691dd7..d10b3215 100644 --- a/terminus-terminal/src/index.ts +++ b/terminus-terminal/src/index.ts @@ -75,13 +75,13 @@ import { hterm } from './frontends/hterm' { provide: ShellProvider, useClass: MacOSDefaultShellProvider, multi: true }, { provide: ShellProvider, useClass: LinuxDefaultShellProvider, multi: true }, { provide: ShellProvider, useClass: WindowsStockShellsProvider, multi: true }, + { provide: ShellProvider, useClass: PowerShellCoreShellProvider, multi: true }, { provide: ShellProvider, useClass: CmderShellProvider, multi: true }, { provide: ShellProvider, useClass: CustomShellProvider, multi: true }, { provide: ShellProvider, useClass: Cygwin32ShellProvider, multi: true }, { provide: ShellProvider, useClass: Cygwin64ShellProvider, multi: true }, { provide: ShellProvider, useClass: GitBashShellProvider, multi: true }, { provide: ShellProvider, useClass: POSIXShellsProvider, multi: true }, - { provide: ShellProvider, useClass: PowerShellCoreShellProvider, multi: true }, { provide: ShellProvider, useClass: WSLShellProvider, multi: true }, { provide: TerminalContextMenuItemProvider, useClass: NewTabContextMenu, multi: true }, @@ -163,7 +163,7 @@ export default class TerminalModule { } if (hotkey.startsWith('profile.')) { let profiles = await config.store.terminal.getProfiles() - let profile = profiles.find(x => slug(x.name) === hotkey.split('.')[1]) + let profile = profiles.find(x => slug(x.name).toLowerCase() === hotkey.split('.')[1]) if (profile) { terminal.openTabWithOptions(profile.sessionOptions) } diff --git a/terminus-terminal/src/services/terminal.service.ts b/terminus-terminal/src/services/terminal.service.ts index ab8d90d9..946cd9f7 100644 --- a/terminus-terminal/src/services/terminal.service.ts +++ b/terminus-terminal/src/services/terminal.service.ts @@ -38,12 +38,13 @@ export class TerminalService { return shellLists.reduce((a, b) => a.concat(b), []) } - async getProfiles (): Promise { + async getProfiles (includeHidden?: boolean): Promise { let shells = await this.shells$.toPromise() return [ ...this.config.store.terminal.profiles, - ...shells.map(shell => ({ + ...shells.filter(x => includeHidden || !x.hidden).map(shell => ({ name: shell.name, + icon: shell.icon, sessionOptions: this.optionsFromShell(shell), isBuiltin: true })) @@ -65,7 +66,7 @@ export class TerminalService { async openTab (profile?: Profile, cwd?: string, pause?: boolean): Promise { if (!profile) { let profiles = await this.getProfiles() - profile = profiles.find(x => slug(x.name) === this.config.store.terminal.profile) || profiles[0] + profile = profiles.find(x => slug(x.name).toLowerCase() === this.config.store.terminal.profile) || profiles[0] } cwd = cwd || profile.sessionOptions.cwd diff --git a/terminus-terminal/src/shells/cmder.ts b/terminus-terminal/src/shells/cmder.ts index dc38c590..7c20185b 100644 --- a/terminus-terminal/src/shells/cmder.ts +++ b/terminus-terminal/src/shells/cmder.ts @@ -1,5 +1,6 @@ import * as path from 'path' import { Injectable } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' import { HostAppService, Platform } from 'terminus-core' import { ShellProvider, IShell } from '../api' @@ -8,6 +9,7 @@ import { ShellProvider, IShell } from '../api' @Injectable() export class CmderShellProvider extends ShellProvider { constructor ( + private domSanitizer: DomSanitizer, private hostApp: HostAppService, ) { super() @@ -31,6 +33,7 @@ export class CmderShellProvider extends ShellProvider { '/k', path.join(process.env.CMDER_ROOT, 'vendor', 'init.bat'), ], + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/cmder.svg')), env: { TERM: 'cygwin', } @@ -48,6 +51,7 @@ export class CmderShellProvider extends ShellProvider { '-command', `Invoke-Expression '. ''${path.join(process.env.CMDER_ROOT, 'vendor', 'profile.ps1')}'''` ], + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/cmder-powershell.svg')), env: {}, }, ] diff --git a/terminus-terminal/src/shells/cygwin32.ts b/terminus-terminal/src/shells/cygwin32.ts index 1402d798..af5ff9c2 100644 --- a/terminus-terminal/src/shells/cygwin32.ts +++ b/terminus-terminal/src/shells/cygwin32.ts @@ -1,5 +1,6 @@ import * as path from 'path' import { Injectable } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' import { HostAppService, Platform } from 'terminus-core' import { ShellProvider, IShell } from '../api' @@ -12,6 +13,7 @@ try { @Injectable() export class Cygwin32ShellProvider extends ShellProvider { constructor ( + private domSanitizer: DomSanitizer, private hostApp: HostAppService, ) { super() @@ -32,6 +34,7 @@ export class Cygwin32ShellProvider extends ShellProvider { id: 'cygwin32', name: 'Cygwin (32 bit)', command: path.join(cygwinPath, 'bin', 'bash.exe'), + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/cygwin.svg')), env: { TERM: 'cygwin', } diff --git a/terminus-terminal/src/shells/cygwin64.ts b/terminus-terminal/src/shells/cygwin64.ts index 33fc5f80..1b07ab25 100644 --- a/terminus-terminal/src/shells/cygwin64.ts +++ b/terminus-terminal/src/shells/cygwin64.ts @@ -1,5 +1,6 @@ import * as path from 'path' import { Injectable } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' import { HostAppService, Platform } from 'terminus-core' import { ShellProvider, IShell } from '../api' @@ -12,6 +13,7 @@ try { @Injectable() export class Cygwin64ShellProvider extends ShellProvider { constructor ( + private domSanitizer: DomSanitizer, private hostApp: HostAppService, ) { super() @@ -32,6 +34,7 @@ export class Cygwin64ShellProvider extends ShellProvider { id: 'cygwin64', name: 'Cygwin', command: path.join(cygwinPath, 'bin', 'bash.exe'), + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/cygwin.svg')), env: { TERM: 'cygwin', } diff --git a/terminus-terminal/src/shells/gitBash.ts b/terminus-terminal/src/shells/gitBash.ts index e98ef923..fd451dc6 100644 --- a/terminus-terminal/src/shells/gitBash.ts +++ b/terminus-terminal/src/shells/gitBash.ts @@ -1,5 +1,6 @@ import * as path from 'path' import { Injectable } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' import { HostAppService, Platform } from 'terminus-core' import { ShellProvider, IShell } from '../api' @@ -12,6 +13,7 @@ try { @Injectable() export class GitBashShellProvider extends ShellProvider { constructor ( + private domSanitizer: DomSanitizer, private hostApp: HostAppService, ) { super() @@ -37,6 +39,7 @@ export class GitBashShellProvider extends ShellProvider { name: 'Git-Bash', command: path.join(gitBashPath, 'bin', 'bash.exe'), args: [ '--login', '-i' ], + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/git-bash.svg')), env: { TERM: 'cygwin', } diff --git a/terminus-terminal/src/shells/linuxDefault.ts b/terminus-terminal/src/shells/linuxDefault.ts index e6aef68b..391021b8 100644 --- a/terminus-terminal/src/shells/linuxDefault.ts +++ b/terminus-terminal/src/shells/linuxDefault.ts @@ -37,6 +37,7 @@ export class LinuxDefaultShellProvider extends ShellProvider { name: 'User default', command: line.split(':')[6], args: ['--login'], + hidden: true, env: {}, }] } diff --git a/terminus-terminal/src/shells/macDefault.ts b/terminus-terminal/src/shells/macDefault.ts index ee110b51..3cb1f50f 100644 --- a/terminus-terminal/src/shells/macDefault.ts +++ b/terminus-terminal/src/shells/macDefault.ts @@ -23,6 +23,7 @@ export class MacOSDefaultShellProvider extends ShellProvider { name: 'User default', command: shellEntry.split(' ')[1].trim(), args: ['--login'], + hidden: true, env: {}, }] } diff --git a/terminus-terminal/src/shells/powershellCore.ts b/terminus-terminal/src/shells/powershellCore.ts index 525d0d87..bf30e905 100644 --- a/terminus-terminal/src/shells/powershellCore.ts +++ b/terminus-terminal/src/shells/powershellCore.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' import { HostAppService, Platform } from 'terminus-core' import { ShellProvider, IShell } from '../api' @@ -10,6 +11,7 @@ try { @Injectable() export class PowerShellCoreShellProvider extends ShellProvider { constructor ( + private domSanitizer: DomSanitizer, private hostApp: HostAppService, ) { super() @@ -31,6 +33,7 @@ export class PowerShellCoreShellProvider extends ShellProvider { name: 'PowerShell Core', command: pwshPath, args: ['-nologo'], + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/powershell-core.svg')), env: { TERM: 'cygwin', } diff --git a/terminus-terminal/src/shells/winDefault.ts b/terminus-terminal/src/shells/winDefault.ts index 3f08e986..aa63fd45 100644 --- a/terminus-terminal/src/shells/winDefault.ts +++ b/terminus-terminal/src/shells/winDefault.ts @@ -39,7 +39,8 @@ export class WindowsDefaultShellProvider extends ShellProvider { return [{ ...shell, id: 'default', - name: 'User default', + name: `Default (${shell.name})`, + hidden: true, env: {}, }] } diff --git a/terminus-terminal/src/shells/windowsStock.ts b/terminus-terminal/src/shells/windowsStock.ts index 5691ec6a..565a7b66 100644 --- a/terminus-terminal/src/shells/windowsStock.ts +++ b/terminus-terminal/src/shells/windowsStock.ts @@ -1,5 +1,6 @@ import * as path from 'path' import { Injectable } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' import { HostAppService, Platform, ElectronService } from 'terminus-core' import { ShellProvider, IShell } from '../api' @@ -8,6 +9,7 @@ import { ShellProvider, IShell } from '../api' @Injectable() export class WindowsStockShellsProvider extends ShellProvider { constructor ( + private domSanitizer: DomSanitizer, private hostApp: HostAppService, private electron: ElectronService, ) { @@ -35,13 +37,21 @@ export class WindowsStockShellsProvider extends ShellProvider { 'inject', ], env: {}, + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/clink.svg')), + }, + { + id: 'cmd', + name: 'CMD (stock)', + command: 'cmd.exe', + env: {}, + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/cmd.svg')), }, - { id: 'cmd', name: 'CMD (stock)', command: 'cmd.exe', env: {} }, { id: 'powershell', name: 'PowerShell', command: 'powershell.exe', args: ['-nologo'], + icon: this.domSanitizer.bypassSecurityTrustHtml(require('../icons/powershell.svg')), env: { TERM: 'cygwin', }