reenabled @typescript-eslint/no-unnecessary-condition

This commit is contained in:
Eugene Pankov
2021-01-02 20:10:00 +01:00
parent 946f4292ef
commit 4d9cc91e91
36 changed files with 197 additions and 164 deletions

View File

@@ -97,7 +97,9 @@ rules:
- allowTemplateLiterals: true - allowTemplateLiterals: true
'@typescript-eslint/no-confusing-void-expression': off '@typescript-eslint/no-confusing-void-expression': off
'@typescript-eslint/no-non-null-assertion': off '@typescript-eslint/no-non-null-assertion': off
'@typescript-eslint/no-unnecessary-condition': off '@typescript-eslint/no-unnecessary-condition':
- error
- allowConstantLoopConditions: true
'@typescript-eslint/no-untyped-public-signature': off # bugs out on constructors '@typescript-eslint/no-untyped-public-signature': off # bugs out on constructors
'@typescript-eslint/restrict-template-expressions': off '@typescript-eslint/restrict-template-expressions': off
'@typescript-eslint/no-dynamic-delete': off '@typescript-eslint/no-dynamic-delete': off

View File

@@ -5,7 +5,7 @@ import { Window, WindowOptions } from './window'
import { pluginManager } from './pluginManager' import { pluginManager } from './pluginManager'
export class Application { export class Application {
private tray: Tray private tray?: Tray
private windows: Window[] = [] private windows: Window[] = []
constructor () { constructor () {
@@ -131,10 +131,8 @@ export class Application {
} }
disableTray (): void { disableTray (): void {
if (this.tray) { this.tray?.destroy()
this.tray.destroy() this.tray = null
this.tray = null
}
} }
hasWindows (): boolean { hasWindows (): boolean {

View File

@@ -8,17 +8,15 @@ try {
appPath = path.dirname(require('electron').remote.app.getPath('exe')) appPath = path.dirname(require('electron').remote.app.getPath('exe'))
} }
if (null != appPath) { if (fs.existsSync(path.join(appPath, 'terminus-data'))) {
if (fs.existsSync(path.join(appPath, 'terminus-data'))) { fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data')) }
} const portableData = path.join(appPath, 'data')
const portableData = path.join(appPath, 'data') if (fs.existsSync(portableData)) {
if (fs.existsSync(portableData)) { console.log('reset user data to ' + portableData)
console.log('reset user data to ' + portableData) try {
try { require('electron').app.setPath('userData', portableData)
require('electron').app.setPath('userData', portableData) } catch {
} catch { require('electron').remote.app.setPath('userData', portableData)
require('electron').remote.app.setPath('userData', portableData)
}
} }
} }

View File

@@ -35,9 +35,9 @@ export class Window {
ready: Promise<void> ready: Promise<void>
private visible = new Subject<boolean>() private visible = new Subject<boolean>()
private closed = new Subject<void>() private closed = new Subject<void>()
private window: GlasstronWindow private window?: GlasstronWindow
private windowConfig: ElectronConfig private windowConfig: ElectronConfig
private windowBounds: Rectangle private windowBounds?: Rectangle
private closing = false private closing = false
private lastVibrancy: {enabled: boolean, type?: string} | null = null private lastVibrancy: {enabled: boolean, type?: string} | null = null
private disableVibrancyWhileDragging = false private disableVibrancyWhileDragging = false

View File

@@ -8,7 +8,5 @@ export interface HotkeyDescription {
* must also provide the `hotkeys.foo` config options with the default values * must also provide the `hotkeys.foo` config options with the default values
*/ */
export abstract class HotkeyProvider { export abstract class HotkeyProvider {
hotkeys: HotkeyDescription[] = []
abstract provide (): Promise<HotkeyDescription[]> abstract provide (): Promise<HotkeyDescription[]>
} }

View File

@@ -72,7 +72,7 @@ export class SelectorModalComponent<T> {
this.modalInstance.dismiss() this.modalInstance.dismiss()
} }
iconIsSVG (icon: string): boolean { iconIsSVG (icon?: string): boolean {
return icon?.startsWith('<') return icon?.startsWith('<') ?? false
} }
} }

View File

@@ -161,7 +161,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
_allFocusMode = false _allFocusMode = false
/** @hidden */ /** @hidden */
private focusedTab: BaseTabComponent private focusedTab: BaseTabComponent|null = null
private maximizedTab: BaseTabComponent|null = null private maximizedTab: BaseTabComponent|null = null
private hotkeysSubscription: Subscription private hotkeysSubscription: Subscription
private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map() private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
@@ -211,7 +211,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred())) this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => { this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
if (!this.hasFocus) { if (!this.hasFocus || !this.focusedTab) {
return return
} }
switch (hotkey) { switch (hotkey) {
@@ -280,7 +280,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
return this.root.getAllTabs() return this.root.getAllTabs()
} }
getFocusedTab (): BaseTabComponent { getFocusedTab (): BaseTabComponent|null {
return this.focusedTab return this.focusedTab
} }
@@ -295,10 +295,8 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
x.emitBlurred() x.emitBlurred()
} }
} }
if (tab) { tab.emitFocused()
tab.emitFocused() this.focusChanged.next(tab)
this.focusChanged.next(tab)
}
if (this.maximizedTab !== tab) { if (this.maximizedTab !== tab) {
this.maximizedTab = null this.maximizedTab = null
@@ -314,7 +312,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
/** /**
* Focuses the first available tab inside the given [[SplitContainer]] * Focuses the first available tab inside the given [[SplitContainer]]
*/ */
focusAnyIn (parent: BaseTabComponent | SplitContainer): void { focusAnyIn (parent?: BaseTabComponent | SplitContainer): void {
if (!parent) { if (!parent) {
return return
} }
@@ -398,6 +396,10 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
* Moves focus in the given direction * Moves focus in the given direction
*/ */
navigate (dir: SplitDirection): void { navigate (dir: SplitDirection): void {
if (!this.focusedTab) {
return
}
let rel: BaseTabComponent | SplitContainer = this.focusedTab let rel: BaseTabComponent | SplitContainer = this.focusedTab
let parent = this.getParentOf(rel) let parent = this.getParentOf(rel)
if (!parent) { if (!parent) {
@@ -598,7 +600,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
@Injectable() @Injectable()
export class SplitTabRecoveryProvider extends TabRecoveryProvider { export class SplitTabRecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> { async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
if (recoveryToken && recoveryToken.type === 'app:split-tab') { if (recoveryToken.type === 'app:split-tab') {
return { return {
type: SplitTabComponent, type: SplitTabComponent,
options: { _recoveredState: recoveryToken }, options: { _recoveredState: recoveryToken },

View File

@@ -29,7 +29,7 @@ export class StartPageComponent {
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0)) .sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0))
} }
sanitizeIcon (icon: string): any { sanitizeIcon (icon?: string): any {
return this.domSanitizer.bypassSecurityTrustHtml(icon ?? '') return this.domSanitizer.bypassSecurityTrustHtml(icon ?? '')
} }
} }

View File

@@ -46,10 +46,10 @@ class CompletionObserver {
export class AppService { export class AppService {
tabs: BaseTabComponent[] = [] tabs: BaseTabComponent[] = []
get activeTab (): BaseTabComponent { return this._activeTab } get activeTab (): BaseTabComponent|null { return this._activeTab ?? null }
private lastTabIndex = 0 private lastTabIndex = 0
private _activeTab: BaseTabComponent private _activeTab?: BaseTabComponent
private closedTabsStack: RecoveryToken[] = [] private closedTabsStack: RecoveryToken[] = []
private activeTabChange = new Subject<BaseTabComponent>() private activeTabChange = new Subject<BaseTabComponent>()
@@ -190,7 +190,7 @@ export class AppService {
this._activeTab.emitFocused() this._activeTab.emitFocused()
return return
} }
if (this.tabs.includes(this._activeTab)) { if (this._activeTab && this.tabs.includes(this._activeTab)) {
this.lastTabIndex = this.tabs.indexOf(this._activeTab) this.lastTabIndex = this.tabs.indexOf(this._activeTab)
} else { } else {
this.lastTabIndex = 0 this.lastTabIndex = 0
@@ -201,12 +201,10 @@ export class AppService {
} }
this._activeTab = tab this._activeTab = tab
this.activeTabChange.next(tab) this.activeTabChange.next(tab)
if (this._activeTab) { setImmediate(() => {
setImmediate(() => { this._activeTab?.emitFocused()
this._activeTab.emitFocused() })
}) this.hostApp.setTitle(this._activeTab.title)
this.hostApp.setTitle(this._activeTab.title)
}
} }
getParentTab (tab: BaseTabComponent): SplitTabComponent|null { getParentTab (tab: BaseTabComponent): SplitTabComponent|null {
@@ -229,6 +227,9 @@ export class AppService {
} }
nextTab (): void { nextTab (): void {
if (!this._activeTab) {
return
}
if (this.tabs.length > 1) { if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab) const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex < this.tabs.length - 1) { if (tabIndex < this.tabs.length - 1) {
@@ -240,6 +241,9 @@ export class AppService {
} }
previousTab (): void { previousTab (): void {
if (!this._activeTab) {
return
}
if (this.tabs.length > 1) { if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab) const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex > 0) { if (tabIndex > 0) {
@@ -251,6 +255,9 @@ export class AppService {
} }
moveSelectedTabLeft (): void { moveSelectedTabLeft (): void {
if (!this._activeTab) {
return
}
if (this.tabs.length > 1) { if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab) const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex > 0) { if (tabIndex > 0) {
@@ -262,6 +269,9 @@ export class AppService {
} }
moveSelectedTabRight (): void { moveSelectedTabRight (): void {
if (!this._activeTab) {
return
}
if (this.tabs.length > 1) { if (this.tabs.length > 1) {
const tabIndex = this.tabs.indexOf(this._activeTab) const tabIndex = this.tabs.indexOf(this._activeTab)
if (tabIndex < this.tabs.length - 1) { if (tabIndex < this.tabs.length - 1) {

View File

@@ -109,10 +109,7 @@ export class ConfigService {
) { ) {
this.path = path.join(electron.app.getPath('userData'), 'config.yaml') this.path = path.join(electron.app.getPath('userData'), 'config.yaml')
this.defaults = configProviders.map(provider => { this.defaults = configProviders.map(provider => {
let defaults = {} let defaults = provider.platformDefaults[hostApp.platform] || {}
if (provider.platformDefaults) {
defaults = configMerge(defaults, provider.platformDefaults[hostApp.platform] || {})
}
if (provider.defaults) { if (provider.defaults) {
defaults = configMerge(defaults, provider.defaults) defaults = configMerge(defaults, provider.defaults)
} }

View File

@@ -26,6 +26,7 @@ export class DockingService {
let display = this.electron.screen.getAllDisplays() let display = this.electron.screen.getAllDisplays()
.filter(x => x.id === this.config.store.appearance.dockScreen)[0] .filter(x => x.id === this.config.store.appearance.dockScreen)[0]
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!display) { if (!display) {
display = this.getCurrentScreen() display = this.getCurrentScreen()
} }

View File

@@ -172,7 +172,7 @@ export class HotkeysService {
return ( return (
await Promise.all( await Promise.all(
this.config.enabledServices(this.hotkeyProviders) this.config.enabledServices(this.hotkeyProviders)
.map(async x => x.provide ? x.provide() : x.hotkeys) .map(async x => x.provide())
) )
).reduce((a, b) => a.concat(b)) ).reduce((a, b) => a.concat(b))
} }
@@ -222,7 +222,7 @@ export class HotkeysService {
if (!(value instanceof Array)) { if (!(value instanceof Array)) {
continue continue
} }
if (value) { if (value.length > 0) {
value = value.map((item: string | string[]) => typeof item === 'string' ? [item] : item) value = value.map((item: string | string[]) => typeof item === 'string' ? [item] : item)
keys[key] = value keys[key] = value
} }

View File

@@ -54,9 +54,7 @@ export class Logger {
private doLog (level: string, ...args: any[]): void { private doLog (level: string, ...args: any[]): void {
console[level](`%c[${this.name}]`, 'color: #aaa', ...args) console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
if (this.winstonLogger) { this.winstonLogger[level](...args)
this.winstonLogger[level](...args)
}
} }
} }

View File

@@ -11,7 +11,7 @@ export class TabRecoveryService {
enabled = false enabled = false
private constructor ( private constructor (
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[], @Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[]|null,
private config: ConfigService, private config: ConfigService,
log: LogService log: LogService
) { ) {
@@ -23,30 +23,23 @@ export class TabRecoveryService {
return return
} }
window.localStorage.tabsRecovery = JSON.stringify( window.localStorage.tabsRecovery = JSON.stringify(
await Promise.all( (await Promise.all(
tabs tabs
.map(tab => { .map(async tab => tab.getRecoveryToken().then(r => {
let token = tab.getRecoveryToken() if (r) {
if (token) { r.tabTitle = tab.title
token = token.then(r => { if (tab.color) {
if (r) { r.tabColor = tab.color
r.tabTitle = tab.title }
if (tab.color) {
r.tabColor = tab.color
}
}
return r
})
} }
return token return r
}) }))
.filter(token => !!token) )).filter(token => !!token)
)
) )
} }
async recoverTab (token: RecoveryToken): Promise<RecoveredTab|null> { async recoverTab (token: RecoveryToken): Promise<RecoveredTab|null> {
for (const provider of this.config.enabledServices(this.tabRecoveryProviders)) { for (const provider of this.config.enabledServices(this.tabRecoveryProviders ?? [])) {
try { try {
const tab = await provider.recover(token) const tab = await provider.recover(token)
if (tab !== null) { if (tab !== null) {

View File

@@ -33,6 +33,7 @@ export class TouchbarService {
app.tabOpened$.subscribe(tab => { app.tabOpened$.subscribe(tab => {
tab.titleChange$.subscribe(title => { tab.titleChange$.subscribe(title => {
const segment = this.tabSegments[app.tabs.indexOf(tab)] const segment = this.tabSegments[app.tabs.indexOf(tab)]
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (segment) { if (segment) {
segment.label = this.shortenTitle(title) segment.label = this.shortenTitle(title)
this.tabsSegmentedControl.segments = this.tabSegments this.tabsSegmentedControl.segments = this.tabSegments
@@ -41,6 +42,7 @@ export class TouchbarService {
tab.activity$.subscribe(hasActivity => { tab.activity$.subscribe(hasActivity => {
const showIcon = this.app.activeTab !== tab && hasActivity const showIcon = this.app.activeTab !== tab && hasActivity
const segment = this.tabSegments[app.tabs.indexOf(tab)] const segment = this.tabSegments[app.tabs.indexOf(tab)]
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (segment) { if (segment) {
segment.icon = showIcon ? activityIcon : undefined segment.icon = showIcon ? activityIcon : undefined
} }
@@ -53,7 +55,7 @@ export class TouchbarService {
label: this.shortenTitle(tab.title), label: this.shortenTitle(tab.title),
})) }))
this.tabsSegmentedControl.segments = this.tabSegments this.tabsSegmentedControl.segments = this.tabSegments
this.tabsSegmentedControl.selectedIndex = this.app.tabs.indexOf(this.app.activeTab) this.tabsSegmentedControl.selectedIndex = this.app.activeTab ? this.app.tabs.indexOf(this.app.activeTab) : 0
} }
update (): void { update (): void {
@@ -73,7 +75,7 @@ export class TouchbarService {
this.tabsSegmentedControl = new this.electron.TouchBar.TouchBarSegmentedControl({ this.tabsSegmentedControl = new this.electron.TouchBar.TouchBarSegmentedControl({
segments: this.tabSegments, segments: this.tabSegments,
selectedIndex: this.app.tabs.indexOf(this.app.activeTab), selectedIndex: this.app.activeTab ? this.app.tabs.indexOf(this.app.activeTab) : undefined,
change: (selectedIndex) => this.zone.run(() => { change: (selectedIndex) => this.zone.run(() => {
this.app.selectTab(this.app.tabs[selectedIndex]) this.app.selectTab(this.app.tabs[selectedIndex])
}), }),
@@ -109,6 +111,7 @@ export class TouchbarService {
} }
private getCachedNSImage (name: string) { private getCachedNSImage (name: string) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!this.nsImageCache[name]) { if (!this.nsImageCache[name]) {
this.nsImageCache[name] = this.electron.nativeImage.createFromNamedImage(name, [0, 0, 1]) this.nsImageCache[name] = this.electron.nativeImage.createFromNamedImage(name, [0, 0, 1])
} }

View File

@@ -113,7 +113,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
...items, ...items,
{ {
label: 'Rename', label: 'Rename',
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()), click: () => this.zone.run(() => tabHeader.showRenameTabModal()),
}, },
{ {
label: 'Duplicate', label: 'Duplicate',

View File

@@ -16,8 +16,8 @@ import { Subscription } from 'rxjs'
animations: BaseTerminalTabComponent.animations, animations: BaseTerminalTabComponent.animations,
}) })
export class SerialTabComponent extends BaseTerminalTabComponent { export class SerialTabComponent extends BaseTerminalTabComponent {
connection: SerialConnection connection?: SerialConnection
session: SerialSession session?: SerialSession
serialPort: any serialPort: any
private homeEndSubscription: Subscription private homeEndSubscription: Subscription

View File

@@ -7,7 +7,7 @@ import { SerialTabComponent } from './components/serialTab.component'
@Injectable() @Injectable()
export class RecoveryProvider extends TabRecoveryProvider { export class RecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> { async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
if (recoveryToken?.type === 'app:serial-tab') { if (recoveryToken.type === 'app:serial-tab') {
return { return {
type: SerialTabComponent, type: SerialTabComponent,
options: { options: {

View File

@@ -10,7 +10,7 @@ import { HotkeyInputModalComponent } from './hotkeyInputModal.component'
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class MultiHotkeyInputComponent { export class MultiHotkeyInputComponent {
@Input() model: string[][] @Input() model: string[][] = []
@Output() modelChange = new EventEmitter() @Output() modelChange = new EventEmitter()
constructor ( constructor (
@@ -18,9 +18,6 @@ export class MultiHotkeyInputComponent {
) { } ) { }
ngOnInit (): void { ngOnInit (): void {
if (!this.model) {
this.model = []
}
if (typeof this.model === 'string') { if (typeof this.model === 'string') {
this.model = [this.model] this.model = [this.model]
} }

View File

@@ -24,7 +24,7 @@ export enum SSHAlgorithmType {
export interface SSHConnection { export interface SSHConnection {
name: string name: string
host: string host: string
port: number port?: number
user: string user: string
auth?: null|'password'|'publicKey'|'agent'|'keyboardInteractive' auth?: null|'password'|'publicKey'|'agent'|'keyboardInteractive'
password?: string password?: string
@@ -112,7 +112,7 @@ export class ForwardedPort {
export class SSHSession extends BaseSession { export class SSHSession extends BaseSession {
scripts?: LoginScript[] scripts?: LoginScript[]
shell: ClientChannel shell?: ClientChannel
ssh: Client ssh: Client
forwardedPorts: ForwardedPort[] = [] forwardedPorts: ForwardedPort[] = []
logger: Logger logger: Logger
@@ -282,17 +282,15 @@ export class SSHSession extends BaseSession {
this.emitServiceMessage(colors.bgRed.black(' X ') + ` Remote has rejected the forwarded connection to ${targetAddress}:${targetPort} via ${fw}: ${err}`) this.emitServiceMessage(colors.bgRed.black(' X ') + ` Remote has rejected the forwarded connection to ${targetAddress}:${targetPort} via ${fw}: ${err}`)
return reject() return reject()
} }
if (stream) { const socket = accept()
const socket = accept() stream.pipe(socket)
stream.pipe(socket) socket.pipe(stream)
socket.pipe(stream) stream.on('close', () => {
stream.on('close', () => { socket.destroy()
socket.destroy() })
}) socket.on('close', () => {
socket.on('close', () => { stream.close()
stream.close() })
})
}
} }
) )
}).then(() => { }).then(() => {

View File

@@ -52,6 +52,7 @@ export class EditConnectionModalComponent {
this.connection.auth = this.connection.auth ?? null this.connection.auth = this.connection.auth ?? null
for (const k of Object.values(SSHAlgorithmType)) { for (const k of Object.values(SSHAlgorithmType)) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!this.connection.algorithms[k]) { if (!this.connection.algorithms[k]) {
this.connection.algorithms[k] = this.defaultAlgorithms[k] this.connection.algorithms[k] = this.defaultAlgorithms[k]
} }

View File

@@ -19,8 +19,8 @@ import { Subscription } from 'rxjs'
animations: BaseTerminalTabComponent.animations, animations: BaseTerminalTabComponent.animations,
}) })
export class SSHTabComponent extends BaseTerminalTabComponent { export class SSHTabComponent extends BaseTerminalTabComponent {
connection: SSHConnection connection?: SSHConnection
session: SSHSession session?: SSHSession
private sessionStack: SSHSession[] = [] private sessionStack: SSHSession[] = []
private homeEndSubscription: Subscription private homeEndSubscription: Subscription
@@ -72,7 +72,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
jumpSession.destroyed$.subscribe(() => session.destroy()) jumpSession.destroyed$.subscribe(() => session.destroy())
session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut( session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut(
'127.0.0.1', 0, session.connection.host, session.connection.port, '127.0.0.1', 0, session.connection.host, session.connection.port ?? 22,
(err, stream) => { (err, stream) => {
if (err) { if (err) {
jumpSession.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not set up port forward on ${jumpConnection.name}`) jumpSession.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not set up port forward on ${jumpConnection.name}`)
@@ -156,7 +156,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
async reconnect (): Promise<void> { async reconnect (): Promise<void> {
this.session?.destroy() this.session?.destroy()
await this.initializeSession() await this.initializeSession()
this.session.releaseInitialDataBuffer() this.session?.releaseInitialDataBuffer()
} }
async canClose (): Promise<boolean> { async canClose (): Promise<boolean> {

View File

@@ -7,7 +7,7 @@ import { SSHTabComponent } from './components/sshTab.component'
@Injectable() @Injectable()
export class RecoveryProvider extends TabRecoveryProvider { export class RecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> { async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
if (recoveryToken?.type === 'app:ssh-tab') { if (recoveryToken.type === 'app:ssh-tab') {
return { return {
type: SSHTabComponent, type: SSHTabComponent,
options: { options: {

View File

@@ -35,8 +35,8 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
]), ]),
])] ])]
session: BaseSession session?: BaseSession
savedState: any savedState?: any
@Input() zoom = 0 @Input() zoom = 0
@@ -51,7 +51,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
/** @hidden */ /** @hidden */
@HostBinding('class.top-padded') topPadded: boolean @HostBinding('class.top-padded') topPadded: boolean
frontend: Frontend frontend?: Frontend
/** @hidden */ /** @hidden */
frontendIsReady = false frontendIsReady = false
@@ -83,7 +83,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
protected terminalContainersService: TerminalFrontendService protected terminalContainersService: TerminalFrontendService
protected toastr: ToastrServiceProxy protected toastr: ToastrServiceProxy
protected log: LogService protected log: LogService
protected decorators: TerminalDecorator[] protected decorators: TerminalDecorator[] = []
protected contextMenuProviders: TabContextMenuItemProvider[] protected contextMenuProviders: TabContextMenuItemProvider[]
// Deps end // Deps end
@@ -95,10 +95,29 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
private termContainerSubscriptions: Subscription[] = [] private termContainerSubscriptions: Subscription[] = []
private allFocusModeSubscription: Subscription|null = null private allFocusModeSubscription: Subscription|null = null
get input$ (): Observable<Buffer> { return this.frontend.input$ } get input$ (): Observable<Buffer> {
if (!this.frontend) {
throw new Error('Frontend not ready')
}
return this.frontend.input$
}
get output$ (): Observable<string> { return this.output } get output$ (): Observable<string> { return this.output }
get resize$ (): Observable<ResizeEvent> { return this.frontend.resize$ }
get alternateScreenActive$ (): Observable<boolean> { return this.frontend.alternateScreenActive$ } get resize$ (): Observable<ResizeEvent> {
if (!this.frontend) {
throw new Error('Frontend not ready')
}
return this.frontend.resize$
}
get alternateScreenActive$ (): Observable<boolean> {
if (!this.frontend) {
throw new Error('Frontend not ready')
}
return this.frontend.alternateScreenActive$
}
get frontendReady$ (): Observable<void> { return this.frontendReady } get frontendReady$ (): Observable<void> { return this.frontendReady }
constructor (protected injector: Injector) { constructor (protected injector: Injector) {
@@ -119,7 +138,6 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.contextMenuProviders = injector.get<any>(TabContextMenuItemProvider, null, InjectFlags.Optional) as TabContextMenuItemProvider[] this.contextMenuProviders = injector.get<any>(TabContextMenuItemProvider, null, InjectFlags.Optional) as TabContextMenuItemProvider[]
this.logger = this.log.create('baseTerminalTab') this.logger = this.log.create('baseTerminalTab')
this.decorators = this.decorators || []
this.setTitle('Terminal') this.setTitle('Terminal')
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => { this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
@@ -128,7 +146,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
} }
switch (hotkey) { switch (hotkey) {
case 'ctrl-c': case 'ctrl-c':
if (this.frontend.getSelection()) { if (this.frontend?.getSelection()) {
this.frontend.copySelection() this.frontend.copySelection()
this.frontend.clearSelection() this.frontend.clearSelection()
this.toastr.info('Copied') this.toastr.info('Copied')
@@ -137,15 +155,15 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
} }
break break
case 'copy': case 'copy':
this.frontend.copySelection() this.frontend?.copySelection()
this.frontend.clearSelection() this.frontend?.clearSelection()
this.toastr.info('Copied') this.toastr.info('Copied')
break break
case 'paste': case 'paste':
this.paste() this.paste()
break break
case 'clear': case 'clear':
this.frontend.clear() this.frontend?.clear()
break break
case 'zoom-in': case 'zoom-in':
this.zoomIn() this.zoomIn()
@@ -199,9 +217,13 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
/** @hidden */ /** @hidden */
ngOnInit (): void { ngOnInit (): void {
if (!this.session) {
throw new Error('No session set on the tab object by the time ngOnInit is called')
}
this.focused$.subscribe(() => { this.focused$.subscribe(() => {
this.configure() this.configure()
this.frontend.focus() this.frontend?.focus()
}) })
this.frontend = this.terminalContainersService.getFrontend(this.session) this.frontend = this.terminalContainersService.getFrontend(this.session)
@@ -223,10 +245,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
}) })
setTimeout(() => { setTimeout(() => {
this.session.resize(columns, rows) this.session?.resize(columns, rows)
}, 1000) }, 1000)
this.session.releaseInitialDataBuffer() this.session?.releaseInitialDataBuffer()
}) })
this.alternateScreenActive$.subscribe(x => { this.alternateScreenActive$.subscribe(x => {
@@ -242,12 +264,12 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
setImmediate(() => { setImmediate(() => {
if (this.hasFocus) { if (this.hasFocus) {
this.frontend.attach(this.content.nativeElement) this.frontend!.attach(this.content.nativeElement)
this.frontend.configure() this.frontend!.configure()
} else { } else {
this.focused$.pipe(first()).subscribe(() => { this.focused$.pipe(first()).subscribe(() => {
this.frontend.attach(this.content.nativeElement) this.frontend!.attach(this.content.nativeElement)
this.frontend.configure() this.frontend!.configure()
}) })
} }
}) })
@@ -264,7 +286,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.frontend.bell$.subscribe(() => { this.frontend.bell$.subscribe(() => {
if (this.config.store.terminal.bell === 'visual') { if (this.config.store.terminal.bell === 'visual') {
this.frontend.visualBell() this.frontend?.visualBell()
} }
if (this.config.store.terminal.bell === 'audible') { if (this.config.store.terminal.bell === 'audible') {
this.bellPlayer.play() this.bellPlayer.play()
@@ -295,9 +317,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
if (!(data instanceof Buffer)) { if (!(data instanceof Buffer)) {
data = Buffer.from(data, 'utf-8') data = Buffer.from(data, 'utf-8')
} }
this.session.write(data) this.session?.write(data)
if (this.config.store.terminal.scrollOnInput) { if (this.config.store.terminal.scrollOnInput) {
this.frontend.scrollToBottom() this.frontend?.scrollToBottom()
} }
} }
@@ -305,6 +327,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
* Feeds input into the terminal frontend * Feeds input into the terminal frontend
*/ */
write (data: string): void { write (data: string): void {
if (!this.frontend) {
throw new Error('Frontend not ready')
}
const percentageMatch = /(^|[^\d])(\d+(\.\d+)?)%([^\d]|$)/.exec(data) const percentageMatch = /(^|[^\d])(\d+(\.\d+)?)%([^\d]|$)/.exec(data)
if (!this.alternateScreenActive && percentageMatch) { if (!this.alternateScreenActive && percentageMatch) {
const percentage = percentageMatch[3] ? parseFloat(percentageMatch[2]) : parseInt(percentageMatch[2]) const percentage = percentageMatch[3] ? parseFloat(percentageMatch[2]) : parseInt(percentageMatch[2])
@@ -357,7 +383,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
* Applies the user settings to the terminal * Applies the user settings to the terminal
*/ */
configure (): void { configure (): void {
this.frontend.configure() this.frontend?.configure()
this.topPadded = this.hostApp.platform === Platform.macOS this.topPadded = this.hostApp.platform === Platform.macOS
&& this.config.store.appearance.frame === 'thin' && this.config.store.appearance.frame === 'thin'
@@ -374,17 +400,17 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
zoomIn (): void { zoomIn (): void {
this.zoom++ this.zoom++
this.frontend.setZoom(this.zoom) this.frontend?.setZoom(this.zoom)
} }
zoomOut (): void { zoomOut (): void {
this.zoom-- this.zoom--
this.frontend.setZoom(this.zoom) this.frontend?.setZoom(this.zoom)
} }
resetZoom (): void { resetZoom (): void {
this.zoom = 0 this.zoom = 0
this.frontend.setZoom(this.zoom) this.frontend?.setZoom(this.zoom)
} }
focusAllPanes (): void { focusAllPanes (): void {
@@ -394,13 +420,13 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
if (this.parent instanceof SplitTabComponent) { if (this.parent instanceof SplitTabComponent) {
this.parent._allFocusMode = true this.parent._allFocusMode = true
this.parent.layout() this.parent.layout()
this.allFocusModeSubscription = this.frontend.input$.subscribe(data => { this.allFocusModeSubscription = this.frontend?.input$.subscribe(data => {
for (const tab of (this.parent as SplitTabComponent).getAllTabs()) { for (const tab of (this.parent as SplitTabComponent).getAllTabs()) {
if (tab !== this && tab instanceof BaseTerminalTabComponent) { if (tab !== this && tab instanceof BaseTerminalTabComponent) {
tab.sendInput(data) tab.sendInput(data)
} }
} }
}) }) ?? null
} }
} }
@@ -418,7 +444,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
/** @hidden */ /** @hidden */
ngOnDestroy (): void { ngOnDestroy (): void {
this.frontend.detach(this.content.nativeElement) this.frontend?.detach(this.content.nativeElement)
this.detachTermContainerHandlers() this.detachTermContainerHandlers()
this.config.enabledServices(this.decorators).forEach(decorator => { this.config.enabledServices(this.decorators).forEach(decorator => {
try { try {
@@ -451,6 +477,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
protected attachTermContainerHandlers (): void { protected attachTermContainerHandlers (): void {
this.detachTermContainerHandlers() this.detachTermContainerHandlers()
if (!this.frontend) {
throw new Error('Frontend not ready')
}
const maybeConfigure = () => { const maybeConfigure = () => {
if (this.hasFocus) { if (this.hasFocus) {
setTimeout(() => this.configure(), 250) setTimeout(() => this.configure(), 250)
@@ -464,8 +494,8 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
} }
})), })),
this.focused$.subscribe(() => this.frontend.enableResizing = true), this.focused$.subscribe(() => this.frontend && (this.frontend.enableResizing = true)),
this.blurred$.subscribe(() => this.frontend.enableResizing = false), this.blurred$.subscribe(() => this.frontend && (this.frontend.enableResizing = false)),
this.frontend.mouseEvent$.subscribe(async event => { this.frontend.mouseEvent$.subscribe(async event => {
if (event.type === 'mousedown') { if (event.type === 'mousedown') {
@@ -525,6 +555,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
} }
protected attachSessionHandlers (destroyOnSessionClose = false): void { protected attachSessionHandlers (destroyOnSessionClose = false): void {
if (!this.session) {
throw new Error('Session not set')
}
// this.session.output$.bufferTime(10).subscribe((datas) => { // this.session.output$.bufferTime(10).subscribe((datas) => {
this.session.output$.subscribe(data => { this.session.output$.subscribe(data => {
if (this.enablePassthrough) { if (this.enablePassthrough) {
@@ -537,7 +571,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
if (destroyOnSessionClose) { if (destroyOnSessionClose) {
this.sessionCloseSubscription = this.session.closed$.subscribe(() => { this.sessionCloseSubscription = this.session.closed$.subscribe(() => {
this.frontend.destroy() this.frontend?.destroy()
this.destroy() this.destroy()
}) })
} }

View File

@@ -26,7 +26,10 @@ export abstract class TerminalDecorator {
/** /**
* Automatically cancel @subscription once detached from @terminal * Automatically cancel @subscription once detached from @terminal
*/ */
protected subscribeUntilDetached (terminal: BaseTerminalTabComponent, subscription: Subscription): void { protected subscribeUntilDetached (terminal: BaseTerminalTabComponent, subscription?: Subscription): void {
if (!subscription) {
return
}
if (!this.smartSubscriptions.has(terminal)) { if (!this.smartSubscriptions.has(terminal)) {
this.smartSubscriptions.set(terminal, []) this.smartSubscriptions.set(terminal, [])
} }

View File

@@ -6,7 +6,7 @@ export interface ResizeEvent {
export interface SessionOptions { export interface SessionOptions {
name?: string name?: string
command: string command: string
args: string[] args?: string[]
cwd?: string cwd?: string
env?: Record<string, string> env?: Record<string, string>
width?: number width?: number

View File

@@ -60,9 +60,7 @@ export class ShellSettingsTabComponent {
properties: ['openDirectory', 'showHiddenFiles'], properties: ['openDirectory', 'showHiddenFiles'],
} }
)).filePaths )).filePaths
if (paths) { this.config.store.terminal.workingDirectory = paths[0]
this.config.store.terminal.workingDirectory = paths[0]
}
} }
newProfile (shell: Shell): void { newProfile (shell: Shell): void {

View File

@@ -53,7 +53,7 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
initializeSession (columns: number, rows: number): void { initializeSession (columns: number, rows: number): void {
this.sessions.addSession( this.sessions.addSession(
this.session, this.session!,
Object.assign({}, this.sessionOptions, { Object.assign({}, this.sessionOptions, {
width: columns, width: columns,
height: rows, height: rows,
@@ -76,8 +76,8 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
} }
async getCurrentProcess (): Promise<BaseTabProcess|null> { async getCurrentProcess (): Promise<BaseTabProcess|null> {
const children = await this.session.getChildProcesses() const children = await this.session?.getChildProcesses()
if (!children.length) { if (!children?.length) {
return null return null
} }
return { return {
@@ -86,8 +86,8 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
} }
async canClose (): Promise<boolean> { async canClose (): Promise<boolean> {
const children = await this.session.getChildProcesses() const children = await this.session?.getChildProcesses()
if (children.length === 0) { if (!children?.length) {
return true return true
} }
return (await this.electron.showMessageBox( return (await this.electron.showMessageBox(
@@ -104,6 +104,6 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
ngOnDestroy (): void { ngOnDestroy (): void {
this.homeEndSubscription.unsubscribe() this.homeEndSubscription.unsubscribe()
super.ngOnDestroy() super.ngOnDestroy()
this.session.destroy() this.session?.destroy()
} }
} }

View File

@@ -18,7 +18,7 @@ export class DebugDecorator extends TerminalDecorator {
let sessionOutputBuffer = '' let sessionOutputBuffer = ''
const bufferLength = 8192 const bufferLength = 8192
this.subscribeUntilDetached(terminal, terminal.session.output$.subscribe(data => { this.subscribeUntilDetached(terminal, terminal.session!.output$.subscribe(data => {
sessionOutputBuffer += data sessionOutputBuffer += data
if (sessionOutputBuffer.length > bufferLength) { if (sessionOutputBuffer.length > bufferLength) {
sessionOutputBuffer = sessionOutputBuffer.substring(sessionOutputBuffer.length - bufferLength) sessionOutputBuffer = sessionOutputBuffer.substring(sessionOutputBuffer.length - bufferLength)
@@ -88,18 +88,18 @@ export class DebugDecorator extends TerminalDecorator {
} }
private doSaveState (terminal: TerminalTabComponent) { private doSaveState (terminal: TerminalTabComponent) {
this.saveFile(terminal.frontend.saveState(), 'state.txt') this.saveFile(terminal.frontend!.saveState(), 'state.txt')
} }
private async doCopyState (terminal: TerminalTabComponent) { private async doCopyState (terminal: TerminalTabComponent) {
const data = '```' + JSON.stringify(terminal.frontend.saveState()) + '```' const data = '```' + JSON.stringify(terminal.frontend!.saveState()) + '```'
this.electron.clipboard.writeText(data) this.electron.clipboard.writeText(data)
} }
private async doLoadState (terminal: TerminalTabComponent) { private async doLoadState (terminal: TerminalTabComponent) {
const data = await this.loadFile() const data = await this.loadFile()
if (data) { if (data) {
terminal.frontend.restoreState(data) terminal.frontend!.restoreState(data)
} }
} }
@@ -109,7 +109,7 @@ export class DebugDecorator extends TerminalDecorator {
if (data.startsWith('`')) { if (data.startsWith('`')) {
data = data.substring(3, data.length - 3) data = data.substring(3, data.length - 3)
} }
terminal.frontend.restoreState(JSON.parse(data)) terminal.frontend!.restoreState(JSON.parse(data))
} }
} }
@@ -125,7 +125,7 @@ export class DebugDecorator extends TerminalDecorator {
private async doLoadOutput (terminal: TerminalTabComponent) { private async doLoadOutput (terminal: TerminalTabComponent) {
const data = await this.loadFile() const data = await this.loadFile()
if (data) { if (data) {
terminal.frontend.write(data) terminal.frontend?.write(data)
} }
} }
@@ -135,7 +135,7 @@ export class DebugDecorator extends TerminalDecorator {
if (data.startsWith('`')) { if (data.startsWith('`')) {
data = data.substring(3, data.length - 3) data = data.substring(3, data.length - 3)
} }
terminal.frontend.write(JSON.parse(data)) terminal.frontend?.write(JSON.parse(data))
} }
} }
} }

View File

@@ -7,10 +7,10 @@ import { TerminalTabComponent } from '../components/terminalTab.component'
export class PathDropDecorator extends TerminalDecorator { export class PathDropDecorator extends TerminalDecorator {
attach (terminal: TerminalTabComponent): void { attach (terminal: TerminalTabComponent): void {
setTimeout(() => { setTimeout(() => {
this.subscribeUntilDetached(terminal, terminal.frontend.dragOver$.subscribe(event => { this.subscribeUntilDetached(terminal, terminal.frontend?.dragOver$.subscribe(event => {
event.preventDefault() event.preventDefault()
})) }))
this.subscribeUntilDetached(terminal, terminal.frontend.drop$.subscribe(event => { this.subscribeUntilDetached(terminal, terminal.frontend?.drop$.subscribe(event => {
for (const file of event.dataTransfer!.files as any) { for (const file of event.dataTransfer!.files as any) {
this.injectPath(terminal, file.path) this.injectPath(terminal, file.path)
} }

View File

@@ -36,7 +36,7 @@ export class ZModemDecorator extends TerminalDecorator {
terminal.write(data) terminal.write(data)
} }
}, },
sender: data => terminal.session.write(Buffer.from(data)), sender: data => terminal.session!.write(Buffer.from(data)),
on_detect: async detection => { on_detect: async detection => {
try { try {
terminal.enablePassthrough = false terminal.enablePassthrough = false
@@ -50,7 +50,7 @@ export class ZModemDecorator extends TerminalDecorator {
}, },
}) })
setTimeout(() => { setTimeout(() => {
this.subscribeUntilDetached(terminal, terminal.session.binaryOutput$.subscribe(data => { this.subscribeUntilDetached(terminal, terminal.session!.binaryOutput$.subscribe(data => {
const chunkSize = 1024 const chunkSize = 1024
for (let i = 0; i <= Math.floor(data.length / chunkSize); i++) { for (let i = 0; i <= Math.floor(data.length / chunkSize); i++) {
try { try {
@@ -153,6 +153,7 @@ export class ZModemDecorator extends TerminalDecorator {
this.cancelEvent.toPromise(), this.cancelEvent.toPromise(),
]) ])
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (canceled) { if (canceled) {
this.showMessage(terminal, colors.bgRed.black(' Canceled ') + ' ' + details.name) this.showMessage(terminal, colors.bgRed.black(' Canceled ') + ' ' + details.name)
} else { } else {
@@ -207,6 +208,7 @@ export class ZModemDecorator extends TerminalDecorator {
await xfer.end() await xfer.end()
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (canceled) { if (canceled) {
this.showMessage(terminal, colors.bgRed.black(' Canceled ') + ' ' + offer.name) this.showMessage(terminal, colors.bgRed.black(' Canceled ') + ' ' + offer.name)
} else { } else {

View File

@@ -33,7 +33,7 @@ export class XTermFrontend extends Frontend {
private search = new SearchAddon() private search = new SearchAddon()
private fitAddon = new FitAddon() private fitAddon = new FitAddon()
private serializeAddon = new SerializeAddon() private serializeAddon = new SerializeAddon()
private ligaturesAddon: LigaturesAddon private ligaturesAddon?: LigaturesAddon
private opened = false private opened = false
constructor () { constructor () {

View File

@@ -7,7 +7,7 @@ import { TerminalTabComponent } from './components/terminalTab.component'
@Injectable() @Injectable()
export class RecoveryProvider extends TabRecoveryProvider { export class RecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> { async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
if (recoveryToken?.type === 'app:terminal-tab') { if (recoveryToken.type === 'app:terminal-tab') {
return { return {
type: TerminalTabComponent, type: TerminalTabComponent,
options: { options: {

View File

@@ -53,16 +53,16 @@ export class TerminalService {
return slugify(profile.name, { remove: /[:.]/g }).toLowerCase() return slugify(profile.name, { remove: /[:.]/g }).toLowerCase()
} }
async getProfileByID (id: string): Promise<Profile> { async getProfileByID (id: string): Promise<Profile|null> {
const profiles = await this.getProfiles({ includeHidden: true }) const profiles = await this.getProfiles({ includeHidden: true })
return profiles.find(x => this.getProfileID(x) === id) ?? profiles[0] return profiles.find(x => this.getProfileID(x) === id) ?? null
} }
/** /**
* Launches a new terminal with a specific shell and CWD * Launches a new terminal with a specific shell and CWD
* @param pause Wait for a keypress when the shell exits * @param pause Wait for a keypress when the shell exits
*/ */
async openTab (profile?: Profile, cwd?: string|null, pause?: boolean): Promise<TerminalTabComponent> { async openTab (profile?: Profile|null, cwd?: string|null, pause?: boolean): Promise<TerminalTabComponent> {
if (!profile) { if (!profile) {
profile = await this.getProfileByID(this.config.store.terminal.profile) profile = await this.getProfileByID(this.config.store.terminal.profile)
if (!profile) { if (!profile) {
@@ -101,7 +101,7 @@ export class TerminalService {
} }
const tab = this.openTabWithOptions(sessionOptions) const tab = this.openTabWithOptions(sessionOptions)
if (profile?.color) { if (profile.color) {
(this.app.getParentTab(tab) ?? tab).color = profile.color (this.app.getParentTab(tab) ?? tab).color = profile.color
} }
return tab return tab

View File

@@ -32,7 +32,7 @@ export class UACService {
} }
const options = { ...sessionOptions } const options = { ...sessionOptions }
options.args = [options.command, ...options.args] options.args = [options.command, ...options.args ?? []]
options.command = helperPath options.command = helperPath
return options return options
} }

View File

@@ -30,7 +30,7 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
const profile = { const profile = {
sessionOptions: { sessionOptions: {
...tab.sessionOptions, ...tab.sessionOptions,
cwd: await tab.session.getWorkingDirectory() ?? tab.sessionOptions.cwd, cwd: await tab.session?.getWorkingDirectory() ?? tab.sessionOptions.cwd,
}, },
name: tab.sessionOptions.command, name: tab.sessionOptions.command,
} }
@@ -79,7 +79,7 @@ export class NewTabContextMenu extends TabContextMenuItemProvider {
click: () => this.zone.run(async () => { click: () => this.zone.run(async () => {
let workingDirectory = this.config.store.terminal.workingDirectory let workingDirectory = this.config.store.terminal.workingDirectory
if (this.config.store.terminal.alwaysUseWorkingDirectory !== true && tab instanceof TerminalTabComponent) { if (this.config.store.terminal.alwaysUseWorkingDirectory !== true && tab instanceof TerminalTabComponent) {
workingDirectory = await tab.session.getWorkingDirectory() workingDirectory = await tab.session?.getWorkingDirectory()
} }
await this.terminalService.openTab(profile, workingDirectory) await this.terminalService.openTab(profile, workingDirectory)
}), }),
@@ -150,7 +150,7 @@ export class CopyPasteContextMenu extends TabContextMenuItemProvider {
click: (): void => { click: (): void => {
this.zone.run(() => { this.zone.run(() => {
setTimeout(() => { setTimeout(() => {
tab.frontend.copySelection() tab.frontend?.copySelection()
this.toastr.info('Copied') this.toastr.info('Copied')
}) })
}) })
@@ -174,7 +174,7 @@ export class LegacyContextMenu extends TabContextMenuItemProvider {
weight = 1 weight = 1
constructor ( constructor (
@Optional() @Inject(TerminalContextMenuItemProvider) protected contextMenuProviders: TerminalContextMenuItemProvider[], @Optional() @Inject(TerminalContextMenuItemProvider) protected contextMenuProviders: TerminalContextMenuItemProvider[]|null,
) { ) {
super() super()
} }