1
1
mirror of https://github.com/Eugeny/tabby.git synced 2024-12-25 11:33:35 +03:00

made context menu extensible

This commit is contained in:
Eugene Pankov 2018-12-24 19:41:27 +01:00
parent fe31131fc1
commit 524550f6e3
4 changed files with 128 additions and 75 deletions

View File

@ -41,6 +41,12 @@ export abstract class TerminalColorSchemeProvider {
abstract async getSchemes (): Promise<ITerminalColorScheme[]>
}
export abstract class TerminalContextMenuItemProvider {
weight: number
abstract async getItems (tab: TerminalTabComponent): Promise<Electron.MenuItemConstructorOptions[]>
}
export interface IShell {
id: string
name?: string

View File

@ -5,11 +5,9 @@ import { Component, NgZone, Inject, Optional, ViewChild, HostBinding, Input } fr
import { AppService, ConfigService, BaseTabComponent, BaseTabProcess, ElectronService, HostAppService, HotkeysService, Platform } from 'terminus-core'
import { Session, SessionsService } from '../services/sessions.service'
import { TerminalService } from '../services/terminal.service'
import { TerminalFrontendService } from '../services/terminalFrontend.service'
import { UACService } from '../services/uac.service'
import { TerminalDecorator, ResizeEvent, SessionOptions } from '../api'
import { TerminalDecorator, ResizeEvent, SessionOptions, TerminalContextMenuItemProvider } from '../api'
import { Frontend } from '../frontends/frontend'
@Component({
@ -49,12 +47,11 @@ export class TerminalTabComponent extends BaseTabComponent {
private hotkeys: HotkeysService,
private sessions: SessionsService,
private electron: ElectronService,
private terminalService: TerminalService,
private terminalContainersService: TerminalFrontendService,
public config: ConfigService,
private toastr: ToastrService,
private uac: UACService,
@Optional() @Inject(TerminalDecorator) private decorators: TerminalDecorator[],
@Optional() @Inject(TerminalContextMenuItemProvider) private contextMenuProviders: TerminalContextMenuItemProvider[],
) {
super()
this.decorators = this.decorators || []
@ -117,6 +114,8 @@ export class TerminalTabComponent extends BaseTabComponent {
})
this.bellPlayer = document.createElement('audio')
this.bellPlayer.src = require<string>('../bell.ogg')
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
}
initializeSession (columns: number, rows: number) {
@ -206,76 +205,12 @@ export class TerminalTabComponent extends BaseTabComponent {
}
async buildContextMenu (): Promise<Electron.MenuItemConstructorOptions[]> {
let shells = await this.terminalService.shells$.toPromise()
let items: Electron.MenuItemConstructorOptions[] = [
{
label: 'New terminal',
click: () => this.zone.run(() => {
this.terminalService.openTabWithOptions(this.sessionOptions)
})
},
{
label: 'New with shell',
submenu: shells.map(shell => ({
label: shell.name,
click: () => this.zone.run(async () => {
this.terminalService.openTab(shell, await this.session.getWorkingDirectory())
}),
})),
},
]
if (this.uac.isAvailable) {
items.push({
label: 'New as admin',
submenu: shells.map(shell => ({
label: shell.name,
click: () => this.zone.run(async () => {
let options = this.terminalService.optionsFromShell(shell)
options.runAsAdministrator = true
this.terminalService.openTabWithOptions(options)
}),
})),
})
let items: Electron.MenuItemConstructorOptions[] = []
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this)))) {
items = items.concat(section)
items.push({ type: 'separator' })
}
items = items.concat([
{
label: 'New with profile',
submenu: this.config.store.terminal.profiles.length ? this.config.store.terminal.profiles.map(profile => ({
label: profile.name,
click: () => this.zone.run(() => {
this.terminalService.openTabWithOptions(profile.sessionOptions)
}),
})) : [{
label: 'No profiles saved',
enabled: false,
}],
},
{
type: 'separator',
},
{
label: 'Copy',
click: () => {
this.zone.run(() => {
setTimeout(() => {
this.frontend.copySelection()
this.toastr.info('Copied')
})
})
}
},
{
label: 'Paste',
click: () => {
this.zone.run(() => {
this.paste()
})
}
},
])
items.splice(items.length - 1, 1)
return items
}

View File

@ -0,0 +1,108 @@
import { NgZone, Injectable } from '@angular/core'
import { ToastrService } from 'ngx-toastr'
import { ConfigService } from 'terminus-core'
import { UACService } from './services/uac.service'
import { TerminalService } from './services/terminal.service'
import { TerminalTabComponent } from './components/terminalTab.component'
import { TerminalContextMenuItemProvider } from './api'
@Injectable()
export class NewTabContextMenu extends TerminalContextMenuItemProvider {
weight = 0
constructor (
public config: ConfigService,
private zone: NgZone,
private terminalService: TerminalService,
private uac: UACService,
) {
super()
}
async getItems (tab: TerminalTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
let shells = await this.terminalService.shells$.toPromise()
let items: Electron.MenuItemConstructorOptions[] = [
{
label: 'New terminal',
click: () => this.zone.run(() => {
this.terminalService.openTabWithOptions(tab.sessionOptions)
})
},
{
label: 'New with shell',
submenu: shells.map(shell => ({
label: shell.name,
click: () => this.zone.run(async () => {
this.terminalService.openTab(shell, await tab.session.getWorkingDirectory())
}),
})),
},
]
if (this.uac.isAvailable) {
items.push({
label: 'New as admin',
submenu: shells.map(shell => ({
label: shell.name,
click: () => this.zone.run(async () => {
let options = this.terminalService.optionsFromShell(shell)
options.runAsAdministrator = true
this.terminalService.openTabWithOptions(options)
}),
})),
})
}
items = items.concat([
{
label: 'New with profile',
submenu: this.config.store.terminal.profiles.length ? this.config.store.terminal.profiles.map(profile => ({
label: profile.name,
click: () => this.zone.run(() => {
this.terminalService.openTabWithOptions(profile.sessionOptions)
}),
})) : [{
label: 'No profiles saved',
enabled: false,
}],
},
])
return items
}
}
@Injectable()
export class CopyPasteContextMenu extends TerminalContextMenuItemProvider {
weight = 1
constructor (
private zone: NgZone,
private toastr: ToastrService,
) {
super()
}
async getItems (tab: TerminalTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
return [
{
label: 'Copy',
click: () => {
this.zone.run(() => {
setTimeout(() => {
tab.frontend.copySelection()
this.toastr.info('Copied')
})
})
}
},
{
label: 'Paste',
click: () => {
this.zone.run(() => tab.paste())
}
},
]
}
}

View File

@ -24,12 +24,13 @@ import { DockMenuService } from './services/dockMenu.service'
import { ButtonProvider } from './buttonProvider'
import { RecoveryProvider } from './recoveryProvider'
import { TerminalColorSchemeProvider, TerminalDecorator, ShellProvider } from './api'
import { TerminalColorSchemeProvider, TerminalDecorator, ShellProvider, TerminalContextMenuItemProvider } from './api'
import { TerminalSettingsTabProvider, AppearanceSettingsTabProvider, ShellSettingsTabProvider } from './settings'
import { PathDropDecorator } from './pathDrop'
import { TerminalConfigProvider } from './config'
import { TerminalHotkeyProvider } from './hotkeys'
import { HyperColorSchemes } from './colorSchemes'
import { NewTabContextMenu, CopyPasteContextMenu } from './contextMenu'
import { CmderShellProvider } from './shells/cmder'
import { CustomShellProvider } from './shells/custom'
@ -79,6 +80,9 @@ import { hterm } from './hterm'
{ provide: ShellProvider, useClass: PowerShellCoreShellProvider, multi: true },
{ provide: ShellProvider, useClass: WSLShellProvider, multi: true },
{ provide: TerminalContextMenuItemProvider, useClass: NewTabContextMenu, multi: true },
{ provide: TerminalContextMenuItemProvider, useClass: CopyPasteContextMenu, multi: true },
// For WindowsDefaultShellProvider
PowerShellCoreShellProvider,
WSLShellProvider,