提交 181c5230 编写于 作者: E Eugene Pankov

strict null checks

上级 9b904856
...@@ -92,3 +92,4 @@ rules: ...@@ -92,3 +92,4 @@ rules:
- error - error
- single - single
- allowTemplateLiterals: true - allowTemplateLiterals: true
'@typescript-eslint/no-non-null-assertion': off
...@@ -19,7 +19,7 @@ location.hash = '' ...@@ -19,7 +19,7 @@ location.hash = ''
;(process as any).enablePromiseAPI = true ;(process as any).enablePromiseAPI = true
if (process.platform === 'win32' && !('HOME' in process.env)) { if (process.platform === 'win32' && !('HOME' in process.env)) {
process.env.HOME = process.env.HOMEDRIVE + process.env.HOMEPATH process.env.HOME = `${process.env.HOMEDRIVE}${process.env.HOMEPATH}`
} }
if (isDev) { if (isDev) {
......
...@@ -156,7 +156,9 @@ export async function findPlugins (): Promise<PluginInfo[]> { ...@@ -156,7 +156,9 @@ export async function findPlugins (): Promise<PluginInfo[]> {
} }
} }
(window as any).installedPlugins = foundPlugins foundPlugins.sort((a, b) => a.name > b.name ? 1 : -1)
;(window as any).installedPlugins = foundPlugins
return foundPlugins return foundPlugins
} }
......
{ {
"name": "terminus-community-color-schemes", "name": "terminus-community-color-schemes",
"version": "1.0.83-nightly.0", "version": "1.0.92-nightly.0",
"description": "Community color schemes for Terminus", "description": "Community color schemes for Terminus",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
......
{ {
"name": "terminus-core", "name": "terminus-core",
"version": "1.0.83-nightly.4", "version": "1.0.92-nightly.0",
"description": "Terminus core", "description": "Terminus core",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
......
...@@ -34,5 +34,5 @@ export abstract class TabRecoveryProvider { ...@@ -34,5 +34,5 @@ export abstract class TabRecoveryProvider {
* @returns [[RecoveredTab]] descriptor containing tab type and component inputs * @returns [[RecoveredTab]] descriptor containing tab type and component inputs
* or `null` if this token is from a different tab type or is not supported * or `null` if this token is from a different tab type or is not supported
*/ */
abstract async recover (recoveryToken: any): Promise<RecoveredTab | null> abstract async recover (recoveryToken: any): Promise<RecoveredTab|null>
} }
...@@ -5,7 +5,7 @@ export interface ToolbarButton { ...@@ -5,7 +5,7 @@ export interface ToolbarButton {
/** /**
* Raw SVG icon code * Raw SVG icon code
*/ */
icon: string icon?: string
title: string title: string
......
...@@ -144,7 +144,7 @@ export class AppRootComponent { ...@@ -144,7 +144,7 @@ export class AppRootComponent {
config.changed$.subscribe(() => this.updateVibrancy()) config.changed$.subscribe(() => this.updateVibrancy())
this.updateVibrancy() this.updateVibrancy()
let lastProgress = null let lastProgress: number|null = null
this.app.tabOpened$.subscribe(tab => { this.app.tabOpened$.subscribe(tab => {
this.unsortedTabs.push(tab) this.unsortedTabs.push(tab)
tab.progress$.subscribe(progress => { tab.progress$.subscribe(progress => {
...@@ -258,7 +258,7 @@ export class AppRootComponent { ...@@ -258,7 +258,7 @@ export class AppRootComponent {
buttons = buttons.concat(provider.provide()) buttons = buttons.concat(provider.provide())
}) })
return buttons return buttons
.filter(button => button.weight > 0 === aboveZero) .filter(button => (button.weight || 0) > 0 === aboveZero)
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0)) .sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0))
} }
......
...@@ -36,7 +36,7 @@ export abstract class BaseTabComponent { ...@@ -36,7 +36,7 @@ export abstract class BaseTabComponent {
/** /**
* CSS color override for the tab's header * CSS color override for the tab's header
*/ */
color: string = null color: string|null = null
protected hasFocus = false protected hasFocus = false
...@@ -50,14 +50,14 @@ export abstract class BaseTabComponent { ...@@ -50,14 +50,14 @@ export abstract class BaseTabComponent {
private titleChange = new Subject<string>() private titleChange = new Subject<string>()
private focused = new Subject<void>() private focused = new Subject<void>()
private blurred = new Subject<void>() private blurred = new Subject<void>()
private progress = new Subject<number>() private progress = new Subject<number|null>()
private activity = new Subject<boolean>() private activity = new Subject<boolean>()
private destroyed = new Subject<void>() private destroyed = new Subject<void>()
get focused$ (): Observable<void> { return this.focused } get focused$ (): Observable<void> { return this.focused }
get blurred$ (): Observable<void> { return this.blurred } get blurred$ (): Observable<void> { return this.blurred }
get titleChange$ (): Observable<string> { return this.titleChange } get titleChange$ (): Observable<string> { return this.titleChange }
get progress$ (): Observable<number> { return this.progress } get progress$ (): Observable<number|null> { return this.progress }
get activity$ (): Observable<boolean> { return this.activity } get activity$ (): Observable<boolean> { return this.activity }
get destroyed$ (): Observable<void> { return this.destroyed } get destroyed$ (): Observable<void> { return this.destroyed }
get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint } get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint }
...@@ -83,7 +83,7 @@ export abstract class BaseTabComponent { ...@@ -83,7 +83,7 @@ export abstract class BaseTabComponent {
* *
* @param {type} progress: value between 0 and 1, or `null` to remove * @param {type} progress: value between 0 and 1, or `null` to remove
*/ */
setProgress (progress: number) { setProgress (progress: number|null) {
this.progress.next(progress) this.progress.next(progress)
if (progress) { if (progress) {
if (this.progressClearTimeout) { if (this.progressClearTimeout) {
...@@ -125,7 +125,7 @@ export abstract class BaseTabComponent { ...@@ -125,7 +125,7 @@ export abstract class BaseTabComponent {
/** /**
* Override this to enable task completion notifications for the tab * Override this to enable task completion notifications for the tab
*/ */
async getCurrentProcess (): Promise<BaseTabProcess> { async getCurrentProcess (): Promise<BaseTabProcess|null> {
return null return null
} }
......
...@@ -33,8 +33,8 @@ export class SplitContainer { ...@@ -33,8 +33,8 @@ export class SplitContainer {
/** /**
* @return Flat list of all tabs inside this container * @return Flat list of all tabs inside this container
*/ */
getAllTabs () { getAllTabs (): BaseTabComponent[] {
let r = [] let r: BaseTabComponent[] = []
for (const child of this.children) { for (const child of this.children) {
if (child instanceof SplitContainer) { if (child instanceof SplitContainer) {
r = r.concat(child.getAllTabs()) r = r.concat(child.getAllTabs())
...@@ -94,7 +94,7 @@ export class SplitContainer { ...@@ -94,7 +94,7 @@ export class SplitContainer {
} }
async serialize () { async serialize () {
const children = [] const children: any[] = []
for (const child of this.children) { for (const child of this.children) {
if (child instanceof SplitContainer) { if (child instanceof SplitContainer) {
children.push(await child.serialize()) children.push(await child.serialize())
...@@ -292,9 +292,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -292,9 +292,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
/** /**
* Inserts a new `tab` to the `side` of the `relative` tab * Inserts a new `tab` to the `side` of the `relative` tab
*/ */
addTab (tab: BaseTabComponent, relative: BaseTabComponent, side: SplitDirection) { addTab (tab: BaseTabComponent, relative: BaseTabComponent|null, side: SplitDirection) {
let target = this.getParentOf(relative) || this.root let target = (relative ? this.getParentOf(relative) : null) || this.root
let insertIndex = target.children.indexOf(relative) let insertIndex = relative ? target.children.indexOf(relative) : -1
if ( if (
target.orientation === 'v' && ['l', 'r'].includes(side) || target.orientation === 'v' && ['l', 'r'].includes(side) ||
...@@ -302,7 +302,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -302,7 +302,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
) { ) {
const newContainer = new SplitContainer() const newContainer = new SplitContainer()
newContainer.orientation = target.orientation === 'v' ? 'h' : 'v' newContainer.orientation = target.orientation === 'v' ? 'h' : 'v'
newContainer.children = [relative] newContainer.children = relative ? [relative] : []
newContainer.ratios = [1] newContainer.ratios = [1]
target.children[insertIndex] = newContainer target.children[insertIndex] = newContainer
target = newContainer target = newContainer
...@@ -333,6 +333,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -333,6 +333,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
removeTab (tab: BaseTabComponent) { removeTab (tab: BaseTabComponent) {
const parent = this.getParentOf(tab) const parent = this.getParentOf(tab)
if (!parent) {
return
}
const index = parent.children.indexOf(tab) const index = parent.children.indexOf(tab)
parent.ratios.splice(index, 1) parent.ratios.splice(index, 1)
parent.children.splice(index, 1) parent.children.splice(index, 1)
...@@ -356,11 +359,18 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -356,11 +359,18 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
navigate (dir: SplitDirection) { navigate (dir: SplitDirection) {
let rel: BaseTabComponent | SplitContainer = this.focusedTab let rel: BaseTabComponent | SplitContainer = this.focusedTab
let parent = this.getParentOf(rel) let parent = this.getParentOf(rel)
if (!parent) {
return
}
const orientation = ['l', 'r'].includes(dir) ? 'h' : 'v' const orientation = ['l', 'r'].includes(dir) ? 'h' : 'v'
while (parent !== this.root && parent.orientation !== orientation) { while (parent !== this.root && parent.orientation !== orientation) {
rel = parent rel = parent
parent = this.getParentOf(rel) parent = this.getParentOf(rel)
if (!parent) {
return
}
} }
if (parent.orientation !== orientation) { if (parent.orientation !== orientation) {
...@@ -381,13 +391,15 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -381,13 +391,15 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
async splitTab (tab: BaseTabComponent, dir: SplitDirection) { async splitTab (tab: BaseTabComponent, dir: SplitDirection) {
const newTab = await this.tabsService.duplicate(tab) const newTab = await this.tabsService.duplicate(tab)
this.addTab(newTab, tab, dir) if (newTab) {
this.addTab(newTab, tab, dir)
}
} }
/** /**
* @returns the immediate parent of `tab` * @returns the immediate parent of `tab`
*/ */
getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer { getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer|null {
root = root || this.root root = root || this.root
for (const child of root.children) { for (const child of root.children) {
if (child instanceof SplitContainer) { if (child instanceof SplitContainer) {
...@@ -414,8 +426,8 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -414,8 +426,8 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
} }
/** @hidden */ /** @hidden */
async getCurrentProcess (): Promise<BaseTabProcess> { async getCurrentProcess (): Promise<BaseTabProcess|null> {
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x) return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x) || null
} }
/** @hidden */ /** @hidden */
...@@ -443,8 +455,10 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -443,8 +455,10 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
private detachTabView (tab: BaseTabComponent) { private detachTabView (tab: BaseTabComponent) {
const ref = this.viewRefs.get(tab) const ref = this.viewRefs.get(tab)
this.viewRefs.delete(tab) if (ref) {
this.viewContainer.remove(this.viewContainer.indexOf(ref)) this.viewRefs.delete(tab)
this.viewContainer.remove(this.viewContainer.indexOf(ref))
}
} }
private layout () { private layout () {
...@@ -471,7 +485,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -471,7 +485,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
if (child instanceof SplitContainer) { if (child instanceof SplitContainer) {
this.layoutInternal(child, childX, childY, childW, childH) this.layoutInternal(child, childX, childY, childW, childH)
} else { } else {
const element = this.viewRefs.get(child).rootNodes[0] const element = this.viewRefs.get(child)!.rootNodes[0]
element.style.position = 'absolute' element.style.position = 'absolute'
element.style.left = `${childX}%` element.style.left = `${childX}%`
element.style.top = `${childY}%` element.style.top = `${childY}%`
...@@ -518,7 +532,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes ...@@ -518,7 +532,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
/** @hidden */ /** @hidden */
@Injectable() @Injectable()
export class SplitTabRecoveryProvider extends TabRecoveryProvider { export class SplitTabRecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: any): Promise<RecoveredTab> { async recover (recoveryToken: any): Promise<RecoveredTab|null> {
if (recoveryToken && recoveryToken.type === 'app:split-tab') { if (recoveryToken && recoveryToken.type === 'app:split-tab') {
return { return {
type: SplitTabComponent, type: SplitTabComponent,
......
...@@ -67,13 +67,13 @@ export class SplitTabSpannerComponent { ...@@ -67,13 +67,13 @@ export class SplitTabSpannerComponent {
this.container.x, this.container.x,
this.container.y + this.container.h * this.container.getOffsetRatio(this.index), this.container.y + this.container.h * this.container.getOffsetRatio(this.index),
this.container.w, this.container.w,
null 0
) )
} else { } else {
this.setDimensions( this.setDimensions(
this.container.x + this.container.w * this.container.getOffsetRatio(this.index), this.container.x + this.container.w * this.container.getOffsetRatio(this.index),
this.container.y, this.container.y,
null, 0,
this.container.h this.container.h
) )
} }
...@@ -82,7 +82,7 @@ export class SplitTabSpannerComponent { ...@@ -82,7 +82,7 @@ export class SplitTabSpannerComponent {
private setDimensions (x: number, y: number, w: number, h: number) { private setDimensions (x: number, y: number, w: number, h: number) {
this.cssLeft = `${x}%` this.cssLeft = `${x}%`
this.cssTop = `${y}%` this.cssTop = `${y}%`
this.cssWidth = w ? `${w}%` : null this.cssWidth = w ? `${w}%` : 'initial'
this.cssHeight = h ? `${h}%` : null this.cssHeight = h ? `${h}%` : 'initial'
} }
} }
...@@ -25,7 +25,7 @@ export class TabHeaderComponent { ...@@ -25,7 +25,7 @@ export class TabHeaderComponent {
@Input() @HostBinding('class.active') active: boolean @Input() @HostBinding('class.active') active: boolean
@Input() @HostBinding('class.has-activity') hasActivity: boolean @Input() @HostBinding('class.has-activity') hasActivity: boolean
@Input() tab: BaseTabComponent @Input() tab: BaseTabComponent
@Input() progress: number @Input() progress: number|null
@ViewChild('handle') handle: ElementRef @ViewChild('handle') handle: ElementRef
private constructor ( private constructor (
...@@ -83,7 +83,7 @@ export class TabHeaderComponent { ...@@ -83,7 +83,7 @@ export class TabHeaderComponent {
this.app.closeTab(this.tab, true) this.app.closeTab(this.tab, true)
} }
if ($event.which === 3) { if ($event.which === 3) {
event.preventDefault() $event.preventDefault()
const contextMenu = this.electron.remote.Menu.buildFromTemplate(await this.buildContextMenu()) const contextMenu = this.electron.remote.Menu.buildFromTemplate(await this.buildContextMenu())
......
...@@ -12,6 +12,8 @@ export class WindowControlsComponent { ...@@ -12,6 +12,8 @@ export class WindowControlsComponent {
constructor (public hostApp: HostAppService, public app: AppService) { } constructor (public hostApp: HostAppService, public app: AppService) { }
async closeWindow () { async closeWindow () {
await this.app.closeAllTabs() && this.hostApp.closeWindow() if (await this.app.closeAllTabs()) {
this.hostApp.closeWindow()
}
} }
} }
...@@ -25,14 +25,14 @@ class CompletionObserver { ...@@ -25,14 +25,14 @@ class CompletionObserver {
async tick () { async tick () {
if (!await this.tab.getCurrentProcess()) { if (!await this.tab.getCurrentProcess()) {
this.done.next(null) this.done.next()
this.stop() this.stop()
} }
} }
stop () { stop () {
clearInterval(this.interval) clearInterval(this.interval)
this.destroyed.next(null) this.destroyed.next()
this.destroyed.complete() this.destroyed.complete()
this.done.complete() this.done.complete()
} }
...@@ -144,7 +144,7 @@ export class AppService { ...@@ -144,7 +144,7 @@ export class AppService {
if (this.tabs.includes(this._activeTab)) { if (this.tabs.includes(this._activeTab)) {
this.lastTabIndex = this.tabs.indexOf(this._activeTab) this.lastTabIndex = this.tabs.indexOf(this._activeTab)
} else { } else {
this.lastTabIndex = null this.lastTabIndex = 0
} }
if (this._activeTab) { if (this._activeTab) {
this._activeTab.clearActivity() this._activeTab.clearActivity()
...@@ -229,7 +229,7 @@ export class AppService { ...@@ -229,7 +229,7 @@ export class AppService {
/** @hidden */ /** @hidden */
emitReady () { emitReady () {
this.ready.next(null) this.ready.next()
this.ready.complete() this.ready.complete()
this.hostApp.emitReady() this.hostApp.emitReady()
} }
...@@ -246,7 +246,7 @@ export class AppService { ...@@ -246,7 +246,7 @@ export class AppService {
}) })
this.completionObservers.set(tab, observer) this.completionObservers.set(tab, observer)
} }
return this.completionObservers.get(tab).done$ return this.completionObservers.get(tab)!.done$
} }
stopObservingTabCompletion (tab: BaseTabComponent) { stopObservingTabCompletion (tab: BaseTabComponent) {
......
...@@ -95,7 +95,7 @@ export class ConfigService { ...@@ -95,7 +95,7 @@ export class ConfigService {
private changed = new Subject<void>() private changed = new Subject<void>()
private _store: any private _store: any
private defaults: any private defaults: any
private servicesCache: { [id: string]: Function[] } = null private servicesCache: { [id: string]: Function[] }|null = null
get changed$ (): Observable<void> { return this.changed } get changed$ (): Observable<void> { return this.changed }
...@@ -170,7 +170,7 @@ export class ConfigService { ...@@ -170,7 +170,7 @@ export class ConfigService {
* *
* @typeparam T Base provider type * @typeparam T Base provider type
*/ */
enabledServices<T> (services: T[]): T[] { enabledServices<T extends object> (services: T[]): T[] {
if (!this.servicesCache) { if (!this.servicesCache) {
this.servicesCache = {} this.servicesCache = {}
const ngModule = window['rootModule'].ngInjectorDef const ngModule = window['rootModule'].ngInjectorDef
......
...@@ -215,7 +215,7 @@ export class HostAppService { ...@@ -215,7 +215,7 @@ export class HostAppService {
setVibrancy (enable: boolean, type: string) { setVibrancy (enable: boolean, type: string) {
document.body.classList.toggle('vibrant', enable) document.body.classList.toggle('vibrant', enable)
if (this.platform === Platform.macOS) { if (this.platform === Platform.macOS) {
this.getWindow().setVibrancy(enable ? 'dark' : null) this.getWindow().setVibrancy(enable ? 'dark' : null as any) // electron issue 20269
} }
if (this.platform === Platform.Windows) { if (this.platform === Platform.Windows) {
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type) this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)
......
...@@ -93,7 +93,7 @@ export class HotkeysService { ...@@ -93,7 +93,7 @@ export class HotkeysService {
return stringifyKeySequence(this.currentKeystrokes.map(x => x.event)) return stringifyKeySequence(this.currentKeystrokes.map(x => x.event))
} }
getCurrentFullyMatchedHotkey (): string { getCurrentFullyMatchedHotkey (): string|null {
const currentStrokes = this.getCurrentKeystrokes() const currentStrokes = this.getCurrentKeystrokes()
const config = this.getHotkeysConfig() const config = this.getHotkeysConfig()
for (const id in config) { for (const id in config) {
...@@ -116,7 +116,7 @@ export class HotkeysService { ...@@ -116,7 +116,7 @@ export class HotkeysService {
getCurrentPartiallyMatchedHotkeys (): PartialHotkeyMatch[] { getCurrentPartiallyMatchedHotkeys (): PartialHotkeyMatch[] {
const currentStrokes = this.getCurrentKeystrokes() const currentStrokes = this.getCurrentKeystrokes()
const config = this.getHotkeysConfig() const config = this.getHotkeysConfig()
const result = [] const result: PartialHotkeyMatch[] = []
for (const id in config) { for (const id in config) {
for (const sequence of config[id]) { for (const sequence of config[id]) {
for (let matchLength = Math.min(currentStrokes.length, sequence.length); matchLength > 0; matchLength--) { for (let matchLength = Math.min(currentStrokes.length, sequence.length); matchLength > 0; matchLength--) {
......
...@@ -15,7 +15,7 @@ export function stringifyKeySequence (events: KeyboardEvent[]): string[] { ...@@ -15,7 +15,7 @@ export function stringifyKeySequence (events: KeyboardEvent[]): string[] {
events = events.slice() events = events.slice()
while (events.length > 0) { while (events.length > 0) {
const event = events.shift() const event = events.shift()!
if ((event as any).event === 'keydown') { if ((event as any).event === 'keydown') {
const itemKeys: string[] = [] const itemKeys: string[] = []
if (event.ctrlKey) { if (event.ctrlKey) {
......
...@@ -37,7 +37,7 @@ export class ShellIntegrationService { ...@@ -37,7 +37,7 @@ export class ShellIntegrationService {
'extras', 'extras',
'automator-workflows', 'automator-workflows',
) )
this.automatorWorkflowsDestination = path.join(process.env.HOME, 'Library', 'Services') this.automatorWorkflowsDestination = path.join(process.env.HOME as string, 'Library', 'Services')
} }
this.updatePaths() this.updatePaths()
} }
......
...@@ -27,7 +27,7 @@ export class TabRecoveryService { ...@@ -27,7 +27,7 @@ export class TabRecoveryService {
) )
} }
async recoverTab (token: any): Promise<RecoveredTab> { async recoverTab (token: any): 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)
......
...@@ -29,7 +29,7 @@ export class TabsService { ...@@ -29,7 +29,7 @@ export class TabsService {
/** /**
* Duplicates an existing tab instance (using the tab recovery system) * Duplicates an existing tab instance (using the tab recovery system)
*/ */
async duplicate (tab: BaseTabComponent): Promise<BaseTabComponent> { async duplicate (tab: BaseTabComponent): Promise<BaseTabComponent|null> {
const token = await tab.getRecoveryToken() const token = await tab.getRecoveryToken()
if (!token) { if (!token) {
return null return null
......
...@@ -4,7 +4,7 @@ import { Theme } from '../api/theme' ...@@ -4,7 +4,7 @@ import { Theme } from '../api/theme'
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class ThemesService { export class ThemesService {
private styleElement: HTMLElement = null private styleElement: HTMLElement|null = null
/** @hidden */ /** @hidden */
constructor ( constructor (
...@@ -17,22 +17,22 @@ export class ThemesService { ...@@ -17,22 +17,22 @@ export class ThemesService {
}) })
} }
findTheme (name: string): Theme { findTheme (name: string): Theme|null {
return this.config.enabledServices(this.themes).find(x => x.name === name) return this.config.enabledServices(this.themes).find(x => x.name === name) || null
} }
findCurrentTheme (): Theme { findCurrentTheme (): Theme {
return this.findTheme(this.config.store.appearance.theme) || this.findTheme('Standard') return this.findTheme(this.config.store.appearance.theme) || this.findTheme('Standard')!
} }
applyTheme (theme: Theme): void { applyTheme (theme: Theme): void {
if (!this.styleElement) { if (!this.styleElement) {
this.styleElement = document.createElement('style') this.styleElement = document.createElement('style')
this.styleElement.setAttribute('id', 'theme') this.styleElement.setAttribute('id', 'theme')
document.querySelector('head').appendChild(this.styleElement) document.querySelector('head')!.appendChild(this.styleElement)
} }
this.styleElement.textContent = theme.css this.styleElement.textContent = theme.css
document.querySelector('style#custom-css').innerHTML = this.config.store.appearance.css document.querySelector('style#custom-css')!.innerHTML = this.config.store.appearance.css
} }
private applyCurrentTheme (): void { private applyCurrentTheme (): void {
......
...@@ -42,7 +42,7 @@ export class TouchbarService { ...@@ -42,7 +42,7 @@ export class TouchbarService {
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)]
if (segment) { if (segment) {
segment.icon = showIcon ? activityIcon : null segment.icon = showIcon ? activityIcon : undefined
} }
}) })
}) })
...@@ -83,7 +83,9 @@ export class TouchbarService { ...@@ -83,7 +83,9 @@ export class TouchbarService {
segments: buttons.map(button => this.getButton(button)), segments: buttons.map(button => this.getButton(button)),
mode: 'buttons', mode: 'buttons',
change: (selectedIndex) => this.zone.run(() => { change: (selectedIndex) => this.zone.run(() => {
buttons[selectedIndex].click() if (buttons[selectedIndex].click) {
buttons[selectedIndex].click!()
}
}), }),
}) })
...@@ -100,8 +102,8 @@ export class TouchbarService { ...@@ -100,8 +102,8 @@ export class TouchbarService {
private getButton (button: ToolbarButton): Electron.SegmentedControlSegment { private getButton (button: ToolbarButton): Electron.SegmentedControlSegment {
return { return {
label: button.touchBarNSImage ? null : this.shortenTitle(button.touchBarTitle || button.title), label: button.touchBarNSImage ? undefined : this.shortenTitle(button.touchBarTitle || button.title),
icon: button.touchBarNSImage ? this.getCachedNSImage(button.touchBarNSImage) : null, icon: button.touchBarNSImage ? this.getCachedNSImage(button.touchBarNSImage) : undefined,
// click: () => this.zone.run(() => button.click()), // click: () => this.zone.run(() => button.click()),
} }
} }
......
...@@ -78,7 +78,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { ...@@ -78,7 +78,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
return [ return [
{ {
label: 'Rename', label: 'Rename',
click: () => this.zone.run(() => tabHeader.showRenameTabModal()), click: () => this.zone.run(() => tabHeader && tabHeader.showRenameTabModal()),
}, },
{ {
label: 'Duplicate', label: 'Duplicate',
...@@ -86,7 +86,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { ...@@ -86,7 +86,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
}, },
{ {
label: 'Color', label: 'Color',
sublabel: COLORS.find(x => x.value === tab.color).name, sublabel: COLORS.find(x => x.value === tab.color)!.name,
submenu: COLORS.map(color => ({ submenu: COLORS.map(color => ({
label: color.name, label: color.name,
type: 'radio', type: 'radio',
......
{ {
"name": "terminus-plugin-manager", "name": "terminus-plugin-manager",
"version": "1.0.83-nightly.0", "version": "1.0.92-nightly.0",
"description": "Terminus' plugin manager", "description": "Terminus' plugin manager",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
"@types/semver": "^6.0.0", "@types/semver": "^6.0.0",
"axios": "^0.19.0", "axios": "^0.19.0",
"mz": "^2.6.0", "mz": "^2.6.0",
"ngx-pipes": "^1.6.1",
"semver": "^6.1.0" "semver": "^6.1.0"
}, },
"peerDependencies": { "peerDependencies": {
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
button.btn.btn-outline-info.btn-sm.ml-auto((click)='openPluginsFolder()') button.btn.btn-outline-info.btn-sm.ml-auto((click)='openPluginsFolder()')
i.fas.fa-folder i.fas.fa-folder
span Plugins folder span Plugins folder
.list-group.list-group-flush.mt-2 .list-group.list-group-flush.mt-2
.list-group-item.d-flex.align-items-center(*ngFor='let plugin of pluginManager.installedPlugins|orderBy:"name"') .list-group-item.d-flex.align-items-center(*ngFor='let plugin of pluginManager.installedPlugins')
.mr-auto.d-flex.flex-column .mr-auto.d-flex.flex-column
div div
strong {{plugin.name}} strong {{plugin.name}}
...@@ -33,15 +33,15 @@ ...@@ -33,15 +33,15 @@
(click)='enablePlugin(plugin)' (click)='enablePlugin(plugin)'
) )
i.fas.fa-fw.fa-play i.fas.fa-fw.fa-play
button.btn.btn-secondary.ml-2( button.btn.btn-secondary.ml-2(
*ngIf='!config.store.pluginBlacklist.includes(plugin.name)', *ngIf='!config.store.pluginBlacklist.includes(plugin.name)',
(click)='disablePlugin(plugin)' (click)='disablePlugin(plugin)'
) )
i.fas.fa-fw.fa-pause i.fas.fa-fw.fa-pause
button.btn.btn-danger.ml-2( button.btn.btn-danger.ml-2(
(click)='uninstallPlugin(plugin)', (click)='uninstallPlugin(plugin)',
*ngIf='!plugin.isBuiltin', *ngIf='!plugin.isBuiltin',
[disabled]='busy[plugin.name] != undefined' [disabled]='busy[plugin.name] != undefined'
) )
...@@ -65,7 +65,7 @@ div ...@@ -65,7 +65,7 @@ div
.list-group.list-group-flush.mb-4(*ngIf='availablePlugins$') .list-group.list-group-flush.mb-4(*ngIf='availablePlugins$')
ng-container(*ngFor='let plugin of (availablePlugins$|async|orderBy:"name")') ng-container(*ngFor='let plugin of (availablePlugins$|async)')
.list-group-item.d-flex.align-items-center(*ngIf='!isAlreadyInstalled(plugin)') .list-group-item.d-flex.align-items-center(*ngIf='!isAlreadyInstalled(plugin)')
button.btn.btn-primary.mr-3( button.btn.btn-primary.mr-3(
(click)='installPlugin(plugin)', (click)='installPlugin(plugin)',
...@@ -73,7 +73,7 @@ div ...@@ -73,7 +73,7 @@ div
) )
i.fas.fa-fw.fa-download(*ngIf='busy[plugin.name] != BusyState.Installing') i.fas.fa-fw.fa-download(*ngIf='busy[plugin.name] != BusyState.Installing')
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing') i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing')
div((click)='showPluginInfo(plugin)') div((click)='showPluginInfo(plugin)')
div div
strong {{plugin.name}} strong {{plugin.name}}
......
import { BehaviorSubject, Observable } from 'rxjs' import { BehaviorSubject, Observable } from 'rxjs'
import { debounceTime, distinctUntilChanged, first, tap, flatMap } from 'rxjs/operators' import { debounceTime, distinctUntilChanged, first, tap, flatMap, map } from 'rxjs/operators'
import * as semver from 'semver' import * as semver from 'semver'
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
...@@ -18,7 +18,7 @@ export class PluginsSettingsTabComponent { ...@@ -18,7 +18,7 @@ export class PluginsSettingsTabComponent {
@Input() availablePlugins$: Observable<PluginInfo[]> @Input() availablePlugins$: Observable<PluginInfo[]>
@Input() availablePluginsQuery$ = new BehaviorSubject<string>('') @Input() availablePluginsQuery$ = new BehaviorSubject<string>('')
@Input() availablePluginsReady = false @Input() availablePluginsReady = false
@Input() knownUpgrades: {[id: string]: PluginInfo} = {} @Input() knownUpgrades: {[id: string]: PluginInfo|null} = {}
@Input() busy: {[id: string]: BusyState} = {} @Input() busy: {[id: string]: BusyState} = {}
@Input() erroredPlugin: string @Input() erroredPlugin: string
@Input() errorMessage: string @Input() errorMessage: string
...@@ -43,9 +43,12 @@ export class PluginsSettingsTabComponent { ...@@ -43,9 +43,12 @@ export class PluginsSettingsTabComponent {
})) }))
}) })
) )
this.availablePlugins$.pipe(first()).subscribe(available => { this.availablePlugins$.pipe(first(), map((plugins: PluginInfo[]) => {
plugins.sort((a, b) => a.name > b.name ? 1 : -1)
return plugins
})).subscribe(available => {
for (const plugin of this.pluginManager.installedPlugins) { for (const plugin of this.pluginManager.installedPlugins) {
this.knownUpgrades[plugin.name] = available.find(x => x.name === plugin.name && semver.gt(x.version, plugin.version)) this.knownUpgrades[plugin.name] = available.find(x => x.name === plugin.name && semver.gt(x.version, plugin.version)) || null
} }
}) })
} }
...@@ -91,7 +94,7 @@ export class PluginsSettingsTabComponent { ...@@ -91,7 +94,7 @@ export class PluginsSettingsTabComponent {
} }
async upgradePlugin (plugin: PluginInfo): Promise<void> { async upgradePlugin (plugin: PluginInfo): Promise<void> {
return this.installPlugin(this.knownUpgrades[plugin.name]) return this.installPlugin(this.knownUpgrades[plugin.name]!)
} }
showPluginInfo (plugin: PluginInfo) { showPluginInfo (plugin: PluginInfo) {
......
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser' import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { NgPipesModule } from 'ngx-pipes'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { SettingsTabProvider } from 'terminus-settings' import { SettingsTabProvider } from 'terminus-settings'
...@@ -15,7 +14,6 @@ import { PluginsSettingsTabProvider } from './settings' ...@@ -15,7 +14,6 @@ import { PluginsSettingsTabProvider } from './settings'
BrowserModule, BrowserModule,
FormsModule, FormsModule,
NgbModule, NgbModule,
NgPipesModule,
], ],
providers: [ providers: [
{ provide: SettingsTabProvider, useClass: PluginsSettingsTabProvider, multi: true }, { provide: SettingsTabProvider, useClass: PluginsSettingsTabProvider, multi: true },
......
{ {
"name": "terminus-settings", "name": "terminus-settings",
"version": "1.0.83-nightly.4", "version": "1.0.92-nightly.0",
"description": "Terminus terminal settings page", "description": "Terminus terminal settings page",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
...@@ -17,8 +17,7 @@ ...@@ -17,8 +17,7 @@
"author": "Eugene Pankov", "author": "Eugene Pankov",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/deep-equal": "1.0.1", "@types/deep-equal": "1.0.1"
"ngx-pipes": "^1.6.1"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/common": "^7", "@angular/common": "^7",
...@@ -26,7 +25,7 @@ ...@@ -26,7 +25,7 @@
"@angular/forms": "^7", "@angular/forms": "^7",
"@angular/platform-browser": "^7", "@angular/platform-browser": "^7",
"@ng-bootstrap/ng-bootstrap": "^1", "@ng-bootstrap/ng-bootstrap": "^1",
"terminus-core": "*", "rxjs": "^5",
"rxjs": "^5" "terminus-core": "*"
} }
} }
...@@ -41,8 +41,8 @@ export class HotkeyInputModalComponent { ...@@ -41,8 +41,8 @@ export class HotkeyInputModalComponent {
@Input() timeoutProgress = 0 @Input() timeoutProgress = 0
private keySubscription: Subscription private keySubscription: Subscription
private lastKeyEvent: number private lastKeyEvent: number|null = null
private keyTimeoutInterval: number = null private keyTimeoutInterval: number|null = null
constructor ( constructor (
private modalInstance: NgbActiveModal, private modalInstance: NgbActiveModal,
...@@ -78,7 +78,7 @@ export class HotkeyInputModalComponent { ...@@ -78,7 +78,7 @@ export class HotkeyInputModalComponent {
this.keySubscription.unsubscribe() this.keySubscription.unsubscribe()
this.hotkeys.clearCurrentKeystrokes() this.hotkeys.clearCurrentKeystrokes()
this.hotkeys.enable() this.hotkeys.enable()
clearInterval(this.keyTimeoutInterval) clearInterval(this.keyTimeoutInterval!)
} }
close () { close () {
......
...@@ -8,14 +8,14 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab') ...@@ -8,14 +8,14 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
ng-template(ngbTabContent) ng-template(ngbTabContent)
.d-flex.align-items-center.mb-4 .d-flex.align-items-center.mb-4
h1.terminus-title.mb-2.mr-2 Terminus h1.terminus-title.mb-2.mr-2 Terminus
sup α sup α
.text-muted.mr-auto {{homeBase.appVersion}} .text-muted.mr-auto {{homeBase.appVersion}}
button.btn.btn-secondary.mr-3((click)='homeBase.openGitHub()') button.btn.btn-secondary.mr-3((click)='homeBase.openGitHub()')
i.fab.fa-github i.fab.fa-github
span GitHub span GitHub
button.btn.btn-secondary((click)='homeBase.reportBug()') button.btn.btn-secondary((click)='homeBase.reportBug()')
i.fas.fa-bug i.fas.fa-bug
span Report a problem span Report a problem
...@@ -57,7 +57,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab') ...@@ -57,7 +57,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
.title(*ngIf='hostApp.platform === Platform.Windows') Acrylic background .title(*ngIf='hostApp.platform === Platform.Windows') Acrylic background
.title(*ngIf='hostApp.platform === Platform.macOS') Vibrancy .title(*ngIf='hostApp.platform === Platform.macOS') Vibrancy
.description Gives the window a blurred transparent background .description Gives the window a blurred transparent background
toggle( toggle(
[(ngModel)]='config.store.appearance.vibrancy', [(ngModel)]='config.store.appearance.vibrancy',
(ngModelChange)='config.save()' (ngModelChange)='config.save()'
...@@ -85,7 +85,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab') ...@@ -85,7 +85,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
[value]='"fluent"' [value]='"fluent"'
) )
| Fluent | Fluent
.form-line .form-line
.header .header
.title Transparency .title Transparency
...@@ -256,27 +256,28 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab') ...@@ -256,27 +256,28 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
| Hotkeys | Hotkeys
ng-template(ngbTabContent) ng-template(ngbTabContent)
h3.mb-3 Hotkeys h3.mb-3 Hotkeys
.input-group.mb-4 .input-group.mb-4
.input-group-prepend .input-group-prepend
.input-group-text .input-group-text
i.fas.fa-fw.fa-search i.fas.fa-fw.fa-search
input.form-control(type='search', placeholder='Search hotkeys', [(ngModel)]='hotkeyFilter') input.form-control(type='search', placeholder='Search hotkeys', [(ngModel)]='hotkeyFilter')
.form-group .form-group
table.hotkeys-table table.hotkeys-table
tr tr
th Name th Name
th ID th ID
th Hotkey th Hotkey
tr(*ngFor='let hotkey of hotkeyDescriptions|filterBy:["name"]:hotkeyFilter') ng-container(*ngFor='let hotkey of hotkeyDescriptions')
td {{hotkey.name}} tr(*ngIf='!hotkeyFilter || hotkey.name.toLowerCase().includes(hotkeyFilter.toLowerCase())')
td {{hotkey.id}} td {{hotkey.name}}
td.pr-5 td {{hotkey.id}}
multi-hotkey-input( td.pr-5
[model]='getHotkey(hotkey.id)', multi-hotkey-input(
(modelChange)='setHotkey(hotkey.id, $event); config.save(); docking.dock()' [model]='getHotkey(hotkey.id)',
) (modelChange)='setHotkey(hotkey.id, $event); config.save(); docking.dock()'
)
ngb-tab(*ngFor='let provider of settingsProviders', [id]='provider.id') ngb-tab(*ngFor='let provider of settingsProviders', [id]='provider.id')
ng-template(ngbTabTitle) ng-template(ngbTabTitle)
...@@ -285,7 +286,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab') ...@@ -285,7 +286,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
ng-template(ngbTabContent) ng-template(ngbTabContent)
settings-tab-body([provider]='provider') settings-tab-body([provider]='provider')
ngb-tab(id='config-file') ngb-tab(id='config-file')
ng-template(ngbTabTitle) ng-template(ngbTabTitle)
i.fas.fa-fw.fa-code.mr-2 i.fas.fa-fw.fa-code.mr-2
...@@ -303,7 +304,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab') ...@@ -303,7 +304,7 @@ ngb-tabset.vertical(type='pills', [activeId]='activeTab')
textarea.form-control.h-100( textarea.form-control.h-100(
[(ngModel)]='configDefaults', [(ngModel)]='configDefaults',
readonly readonly
) )
.mt-2.mb-2.d-flex .mt-2.mb-2.d-flex
button.btn.btn-primary((click)='saveConfigFile()', *ngIf='isConfigFileValid()') button.btn.btn-primary((click)='saveConfigFile()', *ngIf='isConfigFileValid()')
i.fas.fa-check.mr-2 i.fas.fa-check.mr-2
......
...@@ -2,7 +2,6 @@ import { NgModule } from '@angular/core' ...@@ -2,7 +2,6 @@ import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser' import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { NgPipesModule } from 'ngx-pipes'
import TerminusCorePlugin, { ToolbarButtonProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider } from 'terminus-core' import TerminusCorePlugin, { ToolbarButtonProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider } from 'terminus-core'
...@@ -22,7 +21,6 @@ import { SettingsConfigProvider } from './config' ...@@ -22,7 +21,6 @@ import { SettingsConfigProvider } from './config'
BrowserModule, BrowserModule,
FormsModule, FormsModule,
NgbModule, NgbModule,
NgPipesModule,
TerminusCorePlugin, TerminusCorePlugin,
], ],
providers: [ providers: [
......
...@@ -6,7 +6,7 @@ import { SettingsTabComponent } from './components/settingsTab.component' ...@@ -6,7 +6,7 @@ import { SettingsTabComponent } from './components/settingsTab.component'
/** @hidden */ /** @hidden */
@Injectable() @Injectable()
export class RecoveryProvider extends TabRecoveryProvider { export class RecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: any): Promise<RecoveredTab> { async recover (recoveryToken: any): Promise<RecoveredTab|null> {
if (recoveryToken && recoveryToken.type === 'app:settings') { if (recoveryToken && recoveryToken.type === 'app:settings') {
return { type: SettingsTabComponent } return { type: SettingsTabComponent }
} }
......
...@@ -8,6 +8,6 @@ ...@@ -8,6 +8,6 @@
integrity sha512-mMUu4nWHLBlHtxXY17Fg6+ucS/MnndyOWyOe7MmwkoMYxvfQU2ajtRaEvqSUv+aVkMqH/C0NCI8UoVfRNQ10yg== integrity sha512-mMUu4nWHLBlHtxXY17Fg6+ucS/MnndyOWyOe7MmwkoMYxvfQU2ajtRaEvqSUv+aVkMqH/C0NCI8UoVfRNQ10yg==
ngx-pipes@^1.6.1: ngx-pipes@^1.6.1:
version "1.6.6" version "1.7.0"
resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-1.6.6.tgz#32bb80906c220f1e84d5cce7d6dae002cffead4b" resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-1.7.0.tgz#70e166dc2f59a8b96f69dfbf75b58186c189037b"
integrity sha512-mRV0xOZDd6/Jlvti4W0pDepZRIHLHd3kZ6ZzdqyGCU0dxbKVWWLTR1jlNlxN1ruMk8eO0Y8lNh6a1bEW7dJP1w== integrity sha512-ZTJc0/a+e+8v7pP+tb301So5UlxVOoUEZZtJHMjuvHO/CADqfgF+sOAdq1dZMf2RnJ2QTuxbZ8wf34w3T/f8AA==
{ {
"name": "terminus-ssh", "name": "terminus-ssh",
"version": "1.0.83-nightly.0", "version": "1.0.92-nightly.0",
"description": "SSH connection manager for Terminus", "description": "SSH connection manager for Terminus",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
......
import { BaseSession } from 'terminus-terminal' import { BaseSession } from 'terminus-terminal'
export interface LoginScript { export interface LoginScript {
expect?: string expect: string
send: string send: string
isRegex?: boolean isRegex?: boolean
optional?: boolean optional?: boolean
...@@ -15,7 +15,7 @@ export enum SSHAlgorithmType { ...@@ -15,7 +15,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
...@@ -122,7 +122,7 @@ export class SSHSession extends BaseSession { ...@@ -122,7 +122,7 @@ export class SSHSession extends BaseSession {
this.kill('TERM') this.kill('TERM')
} }
async getWorkingDirectory (): Promise<string> { async getWorkingDirectory (): Promise<string|null> {
return null return null
} }
......
...@@ -85,7 +85,7 @@ export class EditConnectionModalComponent { ...@@ -85,7 +85,7 @@ export class EditConnectionModalComponent {
title: 'Select private key', title: 'Select private key',
} }
).then(result => { ).then(result => {
if (!result.filePaths) { if (result.filePaths) {
this.connection.privateKey = result.filePaths[0] this.connection.privateKey = result.filePaths[0]
} }
}) })
...@@ -93,7 +93,7 @@ export class EditConnectionModalComponent { ...@@ -93,7 +93,7 @@ export class EditConnectionModalComponent {
save () { save () {
for (const k of Object.values(SSHAlgorithmType)) { for (const k of Object.values(SSHAlgorithmType)) {
this.connection.algorithms[k] = Object.entries(this.algorithms[k]) this.connection.algorithms![k] = Object.entries(this.algorithms[k])
.filter(([_k, v]) => !!v) .filter(([_k, v]) => !!v)
.map(([k, _v]) => k) .map(([k, _v]) => k)
} }
...@@ -105,6 +105,9 @@ export class EditConnectionModalComponent { ...@@ -105,6 +105,9 @@ export class EditConnectionModalComponent {
} }
moveScriptUp (script: LoginScript) { moveScriptUp (script: LoginScript) {
if (!this.connection.scripts) {
this.connection.scripts = []
}
const index = this.connection.scripts.indexOf(script) const index = this.connection.scripts.indexOf(script)
if (index > 0) { if (index > 0) {
this.connection.scripts.splice(index, 1) this.connection.scripts.splice(index, 1)
...@@ -113,6 +116,9 @@ export class EditConnectionModalComponent { ...@@ -113,6 +116,9 @@ export class EditConnectionModalComponent {
} }
moveScriptDown (script: LoginScript) { moveScriptDown (script: LoginScript) {
if (!this.connection.scripts) {
this.connection.scripts = []
}
const index = this.connection.scripts.indexOf(script) const index = this.connection.scripts.indexOf(script)
if (index >= 0 && index < this.connection.scripts.length - 1) { if (index >= 0 && index < this.connection.scripts.length - 1) {
this.connection.scripts.splice(index, 1) this.connection.scripts.splice(index, 1)
...@@ -121,7 +127,7 @@ export class EditConnectionModalComponent { ...@@ -121,7 +127,7 @@ export class EditConnectionModalComponent {
} }
async deleteScript (script: LoginScript) { async deleteScript (script: LoginScript) {
if ((await this.electron.showMessageBox( if (this.connection.scripts && (await this.electron.showMessageBox(
this.hostApp.getWindow(), this.hostApp.getWindow(),
{ {
type: 'warning', type: 'warning',
...@@ -136,6 +142,9 @@ export class EditConnectionModalComponent { ...@@ -136,6 +142,9 @@ export class EditConnectionModalComponent {
} }
addScript () { addScript () {
if (!this.connection.scripts) {
this.connection.scripts = []
}
this.connection.scripts.push({ expect: '', send: '' }) this.connection.scripts.push({ expect: '', send: '' })
} }
} }
...@@ -15,7 +15,7 @@ export class SSHModalComponent { ...@@ -15,7 +15,7 @@ export class SSHModalComponent {
connections: SSHConnection[] connections: SSHConnection[]
childFolders: SSHConnectionGroup[] childFolders: SSHConnectionGroup[]
quickTarget: string quickTarget: string
lastConnection: SSHConnection lastConnection: SSHConnection|null = null
childGroups: SSHConnectionGroup[] childGroups: SSHConnectionGroup[]
groupCollapsed: {[id: string]: boolean} = {} groupCollapsed: {[id: string]: boolean} = {}
...@@ -91,14 +91,14 @@ export class SSHModalComponent { ...@@ -91,14 +91,14 @@ export class SSHModalComponent {
} }
for (const connection of connections) { for (const connection of connections) {
connection.group = connection.group || null connection.group = connection.group || undefined
let group = this.childGroups.find(x => x.name === connection.group) let group = this.childGroups.find(x => x.name === connection.group)
if (!group) { if (!group) {
group = { group = {
name: connection.group, name: connection.group!,
connections: [], connections: [],
} }
this.childGroups.push(group) this.childGroups.push(group!)
} }
group.connections.push(connection) group.connections.push(connection)
} }
......
...@@ -97,7 +97,7 @@ export class SSHSettingsTabComponent { ...@@ -97,7 +97,7 @@ export class SSHSettingsTabComponent {
} }
)).response === 1) { )).response === 1) {
for (const connection of this.connections.filter(x => x.group === group.name)) { for (const connection of this.connections.filter(x => x.group === group.name)) {
connection.group = null connection.group = undefined
} }
this.config.save() this.config.save()
this.refresh() this.refresh()
...@@ -109,14 +109,14 @@ export class SSHSettingsTabComponent { ...@@ -109,14 +109,14 @@ export class SSHSettingsTabComponent {
this.childGroups = [] this.childGroups = []
for (const connection of this.connections) { for (const connection of this.connections) {
connection.group = connection.group || null connection.group = connection.group || undefined
let group = this.childGroups.find(x => x.name === connection.group) let group = this.childGroups.find(x => x.name === connection.group)
if (!group) { if (!group) {
group = { group = {
name: connection.group, name: connection.group!,
connections: [], connections: [],
} }
this.childGroups.push(group) this.childGroups.push(group!)
} }
group.connections.push(connection) group.connections.push(connection)
} }
......
...@@ -6,7 +6,7 @@ import { SSHTabComponent } from './components/sshTab.component' ...@@ -6,7 +6,7 @@ import { SSHTabComponent } from './components/sshTab.component'
/** @hidden */ /** @hidden */
@Injectable() @Injectable()
export class RecoveryProvider extends TabRecoveryProvider { export class RecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: any): Promise<RecoveredTab> { async recover (recoveryToken: any): Promise<RecoveredTab|null> {
if (recoveryToken && recoveryToken.type === 'app:ssh-tab') { if (recoveryToken && recoveryToken.type === 'app:ssh-tab') {
return { return {
type: SSHTabComponent, type: SSHTabComponent,
......
...@@ -12,7 +12,7 @@ export class PasswordStorageService { ...@@ -12,7 +12,7 @@ export class PasswordStorageService {
await keytar.deletePassword(`ssh@${connection.host}`, connection.user) await keytar.deletePassword(`ssh@${connection.host}`, connection.user)
} }
async loadPassword (connection: SSHConnection): Promise<string> { async loadPassword (connection: SSHConnection): Promise<string|null> {
return keytar.getPassword(`ssh@${connection.host}`, connection.user) return keytar.getPassword(`ssh@${connection.host}`, connection.user)
} }
} }
...@@ -38,9 +38,9 @@ export class SSHService { ...@@ -38,9 +38,9 @@ export class SSHService {
) as SSHTabComponent) ) as SSHTabComponent)
} }
async connectSession (session: SSHSession, logCallback?: (s: string) => void): Promise<void> { async connectSession (session: SSHSession, logCallback?: (s: any) => void): Promise<void> {
let privateKey: string = null let privateKey: string|null = null
let privateKeyPassphrase: string = null let privateKeyPassphrase: string|null = null
let privateKeyPath = session.connection.privateKey let privateKeyPath = session.connection.privateKey
if (!logCallback) { if (!logCallback) {
...@@ -48,12 +48,12 @@ export class SSHService { ...@@ -48,12 +48,12 @@ export class SSHService {
} }
const log = (s: any) => { const log = (s: any) => {
logCallback(s) logCallback!(s)
this.logger.info(s) this.logger.info(s)
} }
if (!privateKeyPath) { if (!privateKeyPath) {
const userKeyPath = path.join(process.env.HOME, '.ssh', 'id_rsa') const userKeyPath = path.join(process.env.HOME as string, '.ssh', 'id_rsa')
if (await fs.exists(userKeyPath)) { if (await fs.exists(userKeyPath)) {
log(`Using user's default private key: ${userKeyPath}`) log(`Using user's default private key: ${userKeyPath}`)
privateKeyPath = userKeyPath privateKeyPath = userKeyPath
...@@ -92,7 +92,7 @@ export class SSHService { ...@@ -92,7 +92,7 @@ export class SSHService {
const ssh = new Client() const ssh = new Client()
let connected = false let connected = false
let savedPassword: string = null let savedPassword: string|null = null
await new Promise(async (resolve, reject) => { await new Promise(async (resolve, reject) => {
ssh.on('ready', () => { ssh.on('ready', () => {
connected = true connected = true
...@@ -116,7 +116,7 @@ export class SSHService { ...@@ -116,7 +116,7 @@ export class SSHService {
ssh.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => this.zone.run(async () => { ssh.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => this.zone.run(async () => {
log(`Keyboard-interactive auth requested: ${name}`) log(`Keyboard-interactive auth requested: ${name}`)
this.logger.info('Keyboard-interactive auth:', name, instructions, instructionsLang) this.logger.info('Keyboard-interactive auth:', name, instructions, instructionsLang)
const results = [] const results: string[] = []
for (const prompt of prompts) { for (const prompt of prompts) {
const modal = this.ngbModal.open(PromptModalComponent) const modal = this.ngbModal.open(PromptModalComponent)
modal.componentInstance.prompt = prompt.prompt modal.componentInstance.prompt = prompt.prompt
...@@ -135,7 +135,7 @@ export class SSHService { ...@@ -135,7 +135,7 @@ export class SSHService {
log('Banner: \n' + banner) log('Banner: \n' + banner)
}) })
let agent: string = null let agent: string|null = null
if (this.hostApp.platform === Platform.Windows) { if (this.hostApp.platform === Platform.Windows) {
const pageantRunning = new Promise<boolean>(resolve => { const pageantRunning = new Promise<boolean>(resolve => {
windowsProcessTreeNative.getProcessList(list => { // eslint-disable-line block-scoped-var windowsProcessTreeNative.getProcessList(list => { // eslint-disable-line block-scoped-var
...@@ -146,7 +146,7 @@ export class SSHService { ...@@ -146,7 +146,7 @@ export class SSHService {
agent = 'pageant' agent = 'pageant'
} }
} else { } else {
agent = process.env.SSH_AUTH_SOCK agent = process.env.SSH_AUTH_SOCK as string
} }
try { try {
...@@ -155,10 +155,10 @@ export class SSHService { ...@@ -155,10 +155,10 @@ export class SSHService {
port: session.connection.port || 22, port: session.connection.port || 22,
username: session.connection.user, username: session.connection.user,
password: session.connection.privateKey ? undefined : '', password: session.connection.privateKey ? undefined : '',
privateKey, privateKey: privateKey || undefined,
passphrase: privateKeyPassphrase, passphrase: privateKeyPassphrase || undefined,
tryKeyboard: true, tryKeyboard: true,
agent, agent: agent || undefined,
agentForward: !!agent, agentForward: !!agent,
keepaliveInterval: session.connection.keepaliveInterval, keepaliveInterval: session.connection.keepaliveInterval,
keepaliveCountMax: session.connection.keepaliveCountMax, keepaliveCountMax: session.connection.keepaliveCountMax,
......
{ {
"name": "terminus-terminal", "name": "terminus-terminal",
"version": "1.0.83-nightly.4", "version": "1.0.92-nightly.0",
"description": "Terminus' terminal emulation core", "description": "Terminus' terminal emulation core",
"keywords": [ "keywords": [
"terminus-builtin-plugin" "terminus-builtin-plugin"
......
...@@ -43,7 +43,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit ...@@ -43,7 +43,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
@ViewChild('content') content @ViewChild('content') content
/** @hidden */ /** @hidden */
@HostBinding('style.background-color') backgroundColor: string @HostBinding('style.background-color') backgroundColor: string|null = null
/** @hidden */ /** @hidden */
@HostBinding('class.top-padded') topPadded: boolean @HostBinding('class.top-padded') topPadded: boolean
......
...@@ -18,7 +18,7 @@ export class ButtonProvider extends ToolbarButtonProvider { ...@@ -18,7 +18,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
for (const arg of argv.slice(1).concat([electron.remote.process.argv0])) { for (const arg of argv.slice(1).concat([electron.remote.process.argv0])) {
if (await fs.exists(arg)) { if (await fs.exists(arg)) {
if ((await fs.stat(arg)).isDirectory()) { if ((await fs.stat(arg)).isDirectory()) {
this.terminal.openTab(null, arg) this.terminal.openTab(undefined, arg)
} }
} }
} }
......
...@@ -8,7 +8,7 @@ import { TerminalColorScheme } from './api/interfaces' ...@@ -8,7 +8,7 @@ import { TerminalColorScheme } from './api/interfaces'
@Injectable() @Injectable()
export class HyperColorSchemes extends TerminalColorSchemeProvider { export class HyperColorSchemes extends TerminalColorSchemeProvider {
async getSchemes (): Promise<TerminalColorScheme[]> { async getSchemes (): Promise<TerminalColorScheme[]> {
const pluginsPath = path.join(process.env.HOME, '.hyper_plugins', 'node_modules') const pluginsPath = path.join(process.env.HOME as string, '.hyper_plugins', 'node_modules')
if (!await fs.exists(pluginsPath)) { if (!await fs.exists(pluginsPath)) {
return [] return []
} }
......
...@@ -19,7 +19,7 @@ export class AppearanceSettingsTabComponent { ...@@ -19,7 +19,7 @@ export class AppearanceSettingsTabComponent {
fonts: string[] = [] fonts: string[] = []
colorSchemes: TerminalColorScheme[] = [] colorSchemes: TerminalColorScheme[] = []
equalComparator = deepEqual equalComparator = deepEqual
editingColorScheme: TerminalColorScheme editingColorScheme: TerminalColorScheme|null = null
schemeChanged = false schemeChanged = false
constructor ( constructor (
...@@ -68,7 +68,7 @@ export class AppearanceSettingsTabComponent { ...@@ -68,7 +68,7 @@ export class AppearanceSettingsTabComponent {
saveScheme () { saveScheme () {
let schemes = this.config.store.terminal.customColorSchemes let schemes = this.config.store.terminal.customColorSchemes
schemes = schemes.filter(x => x !== this.editingColorScheme && x.name !== this.editingColorScheme.name) schemes = schemes.filter(x => x !== this.editingColorScheme && x.name !== this.editingColorScheme!.name)
schemes.push(this.editingColorScheme) schemes.push(this.editingColorScheme)
this.config.store.terminal.customColorSchemes = schemes this.config.store.terminal.customColorSchemes = schemes
this.config.save() this.config.save()
......
...@@ -52,6 +52,9 @@ export class ShellSettingsTabComponent { ...@@ -52,6 +52,9 @@ export class ShellSettingsTabComponent {
pickWorkingDirectory () { pickWorkingDirectory () {
const shell = this.shells.find(x => x.id === this.config.store.terminal.shell) const shell = this.shells.find(x => x.id === this.config.store.terminal.shell)
if (!shell) {
return
}
const paths = this.electron.dialog.showOpenDialog( const paths = this.electron.dialog.showOpenDialog(
this.hostApp.getWindow(), this.hostApp.getWindow(),
{ {
...@@ -66,7 +69,7 @@ export class ShellSettingsTabComponent { ...@@ -66,7 +69,7 @@ export class ShellSettingsTabComponent {
newProfile (shell: Shell) { newProfile (shell: Shell) {
const profile: Profile = { const profile: Profile = {
name: shell.name, name: shell.name || '',
sessionOptions: this.terminalService.optionsFromShell(shell), sessionOptions: this.terminalService.optionsFromShell(shell),
} }
this.config.store.terminal.profiles = [profile, ...this.config.store.terminal.profiles] this.config.store.terminal.profiles = [profile, ...this.config.store.terminal.profiles]
......
...@@ -16,7 +16,7 @@ export class TerminalSettingsTabComponent { ...@@ -16,7 +16,7 @@ export class TerminalSettingsTabComponent {
openWSLVolumeMixer () { openWSLVolumeMixer () {
this.electron.shell.openItem('sndvol.exe') this.electron.shell.openItem('sndvol.exe')
this.terminal.openTab({ this.terminal.openTab({
name: null, name: '',
sessionOptions: { sessionOptions: {
command: 'wsl.exe', command: 'wsl.exe',
args: ['tput', 'bel'], args: ['tput', 'bel'],
......
...@@ -68,7 +68,7 @@ export class TerminalTabComponent extends BaseTerminalTabComponent { ...@@ -68,7 +68,7 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
} }
} }
async getCurrentProcess (): Promise<BaseTabProcess> { 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
......
...@@ -78,11 +78,11 @@ hterm.hterm.VT.CSI[' q'] = function (parseState) { ...@@ -78,11 +78,11 @@ hterm.hterm.VT.CSI[' q'] = function (parseState) {
} }
hterm.hterm.VT.OSC['4'] = function (parseState) { hterm.hterm.VT.OSC['4'] = function (parseState) {
const args = parseState.args[0].split(';') const args: string[] = parseState.args[0].split(';')
const pairCount = args.length / 2 const pairCount = args.length / 2
const colorPalette = this.terminal.getTextAttributes().colorPalette const colorPalette = this.terminal.getTextAttributes().colorPalette
const responseArray = [] const responseArray: string[] = []
for (let pairNumber = 0; pairNumber < pairCount; ++pairNumber) { for (let pairNumber = 0; pairNumber < pairCount; ++pairNumber) {
const colorIndex = parseInt(args[pairNumber * 2]) const colorIndex = parseInt(args[pairNumber * 2])
...@@ -95,7 +95,7 @@ hterm.hterm.VT.OSC['4'] = function (parseState) { ...@@ -95,7 +95,7 @@ hterm.hterm.VT.OSC['4'] = function (parseState) {
if (colorValue === '?') { if (colorValue === '?') {
colorValue = hterm.lib.colors.rgbToX11(colorPalette[colorIndex]) colorValue = hterm.lib.colors.rgbToX11(colorPalette[colorIndex])
if (colorValue) { if (colorValue) {
responseArray.push(colorIndex + ';' + colorValue) responseArray.push(colorIndex.toString() + ';' + colorValue)
} }
continue continue
} }
......
...@@ -186,7 +186,7 @@ export class HTermFrontend extends Frontend { ...@@ -186,7 +186,7 @@ export class HTermFrontend extends Frontend {
this.io.onTerminalResize = (columns, rows) => { this.io.onTerminalResize = (columns, rows) => {
this.resize.next({ columns, rows }) this.resize.next({ columns, rows })
} }
this.ready.next(null) this.ready.next()
this.ready.complete() this.ready.complete()
this.term.scrollPort_.document_.addEventListener('dragOver', event => { this.term.scrollPort_.document_.addEventListener('dragOver', event => {
......
...@@ -120,7 +120,7 @@ export class XTermFrontend extends Frontend { ...@@ -120,7 +120,7 @@ export class XTermFrontend extends Frontend {
this.xterm.loadAddon(new WebglAddon()) this.xterm.loadAddon(new WebglAddon())
} }
this.ready.next(null) this.ready.next()
this.ready.complete() this.ready.complete()
this.xterm.loadAddon(this.search) this.xterm.loadAddon(this.search)
...@@ -250,7 +250,7 @@ export class XTermFrontend extends Frontend { ...@@ -250,7 +250,7 @@ export class XTermFrontend extends Frontend {
let html = `<div style="font-family: '${this.configService.store.terminal.font}', monospace; white-space: pre">` let html = `<div style="font-family: '${this.configService.store.terminal.font}', monospace; white-space: pre">`
const selection = this.xterm.getSelectionPosition() const selection = this.xterm.getSelectionPosition()
if (!selection) { if (!selection) {
return null return ''
} }
if (selection.startRow === selection.endRow) { if (selection.startRow === selection.endRow) {
html += this.getLineAsHTML(selection.startRow, selection.startColumn, selection.endColumn) html += this.getLineAsHTML(selection.startRow, selection.startColumn, selection.endColumn)
...@@ -278,7 +278,7 @@ export class XTermFrontend extends Frontend { ...@@ -278,7 +278,7 @@ export class XTermFrontend extends Frontend {
private getLineAsHTML (y: number, start: number, end: number): string { private getLineAsHTML (y: number, start: number, end: number): string {
let html = '<div>' let html = '<div>'
let lastStyle = null let lastStyle: string|null = null
const line = (this.xterm.buffer.getLine(y) as any)._line const line = (this.xterm.buffer.getLine(y) as any)._line
const cell = new CellData() const cell = new CellData()
for (let i = start; i < end; i++) { for (let i = start; i < end; i++) {
......
...@@ -188,7 +188,7 @@ export default class TerminalModule { // eslint-disable-line @typescript-eslint/ ...@@ -188,7 +188,7 @@ export default class TerminalModule { // eslint-disable-line @typescript-eslint/
hostApp.cliOpenDirectory$.subscribe(async directory => { hostApp.cliOpenDirectory$.subscribe(async directory => {
if (await fs.exists(directory)) { if (await fs.exists(directory)) {
if ((await fs.stat(directory)).isDirectory()) { if ((await fs.stat(directory)).isDirectory()) {
terminal.openTab(null, directory) terminal.openTab(undefined, directory)
hostApp.bringToFront() hostApp.bringToFront()
} }
} }
......
...@@ -15,7 +15,7 @@ export class PathDropDecorator extends TerminalDecorator { ...@@ -15,7 +15,7 @@ export class PathDropDecorator extends TerminalDecorator {
event.preventDefault() event.preventDefault()
}), }),
terminal.frontend.drop$.subscribe(event => { 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)
} }
event.preventDefault() event.preventDefault()
......
...@@ -6,7 +6,7 @@ import { TerminalTabComponent } from './components/terminalTab.component' ...@@ -6,7 +6,7 @@ import { TerminalTabComponent } from './components/terminalTab.component'
/** @hidden */ /** @hidden */
@Injectable() @Injectable()
export class RecoveryProvider extends TabRecoveryProvider { export class RecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: any): Promise<RecoveredTab> { async recover (recoveryToken: any): Promise<RecoveredTab|null> {
if (recoveryToken && recoveryToken.type === 'app:terminal-tab') { if (recoveryToken && recoveryToken.type === 'app:terminal-tab') {
return { return {
type: TerminalTabComponent, type: TerminalTabComponent,
......
...@@ -30,7 +30,7 @@ export class DockMenuService { ...@@ -30,7 +30,7 @@ export class DockMenuService {
iconPath: process.execPath, iconPath: process.execPath,
iconIndex: 0, iconIndex: 0,
})), })),
}] : null) }] : null as any)
} }
if (this.hostApp.platform === Platform.macOS) { if (this.hostApp.platform === Platform.macOS) {
this.electron.app.dock.setMenu(this.electron.Menu.buildFromTemplate( this.electron.app.dock.setMenu(this.electron.Menu.buildFromTemplate(
......
...@@ -62,7 +62,7 @@ export abstract class BaseSession { ...@@ -62,7 +62,7 @@ export abstract class BaseSession {
releaseInitialDataBuffer () { releaseInitialDataBuffer () {
this.initialDataBufferReleased = true this.initialDataBufferReleased = true
this.output.next(this.initialDataBuffer) this.output.next(this.initialDataBuffer)
this.initialDataBuffer = null this.initialDataBuffer = ''
} }
async destroy (): Promise<void> { async destroy (): Promise<void> {
...@@ -81,14 +81,14 @@ export abstract class BaseSession { ...@@ -81,14 +81,14 @@ export abstract class BaseSession {
abstract kill (signal?: string): void abstract kill (signal?: string): void
abstract async getChildProcesses (): Promise<ChildProcess[]> abstract async getChildProcesses (): Promise<ChildProcess[]>
abstract async gracefullyKillProcess (): Promise<void> abstract async gracefullyKillProcess (): Promise<void>
abstract async getWorkingDirectory (): Promise<string> abstract async getWorkingDirectory (): Promise<string|null>
} }
/** @hidden */ /** @hidden */
export class Session extends BaseSession { export class Session extends BaseSession {
private pty: any private pty: any
private pauseAfterExit = false private pauseAfterExit = false
private guessedCWD: string private guessedCWD: string|null = null
private reportedCWD: string private reportedCWD: string
constructor (private config: ConfigService) { constructor (private config: ConfigService) {
...@@ -96,7 +96,7 @@ export class Session extends BaseSession { ...@@ -96,7 +96,7 @@ export class Session extends BaseSession {
} }
start (options: SessionOptions) { start (options: SessionOptions) {
this.name = options.name this.name = options.name || ''
const env = { const env = {
...process.env, ...process.env,
...@@ -122,7 +122,7 @@ export class Session extends BaseSession { ...@@ -122,7 +122,7 @@ export class Session extends BaseSession {
if (!fs.existsSync(cwd)) { if (!fs.existsSync(cwd)) {
console.warn('Ignoring non-existent CWD:', cwd) console.warn('Ignoring non-existent CWD:', cwd)
cwd = null cwd = undefined
} }
this.pty = nodePTY.spawn(options.command, options.args || [], { this.pty = nodePTY.spawn(options.command, options.args || [], {
...@@ -135,7 +135,7 @@ export class Session extends BaseSession { ...@@ -135,7 +135,7 @@ export class Session extends BaseSession {
experimentalUseConpty: (isWindowsBuild(WIN_BUILD_CONPTY_SUPPORTED) && this.config.store.terminal.useConPTY ? 1 : false) as any, experimentalUseConpty: (isWindowsBuild(WIN_BUILD_CONPTY_SUPPORTED) && this.config.store.terminal.useConPTY ? 1 : false) as any,
}) })
this.guessedCWD = cwd this.guessedCWD = cwd || null
this.truePID = this.pty['pid'] this.truePID = this.pty['pid']
...@@ -174,7 +174,7 @@ export class Session extends BaseSession { ...@@ -174,7 +174,7 @@ export class Session extends BaseSession {
} }
}) })
this.pauseAfterExit = options.pauseAfterExit this.pauseAfterExit = options.pauseAfterExit || false
} }
processOSC1337 (data: string) { processOSC1337 (data: string) {
...@@ -270,7 +270,7 @@ export class Session extends BaseSession { ...@@ -270,7 +270,7 @@ export class Session extends BaseSession {
} }
} }
async getWorkingDirectory (): Promise<string> { async getWorkingDirectory (): Promise<string|null> {
if (this.reportedCWD) { if (this.reportedCWD) {
return this.reportedCWD return this.reportedCWD
} }
......
...@@ -51,7 +51,7 @@ export class TerminalService { ...@@ -51,7 +51,7 @@ export class TerminalService {
* 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, pause?: boolean): Promise<TerminalTabComponent> { async openTab (profile?: Profile, cwd?: string|null, pause?: boolean): Promise<TerminalTabComponent> {
if (!profile) { if (!profile) {
const profiles = await this.getProfiles(true) const profiles = await this.getProfiles(true)
profile = profiles.find(x => slug(x.name).toLowerCase() === this.config.store.terminal.profile) || profiles[0] profile = profiles.find(x => slug(x.name).toLowerCase() === this.config.store.terminal.profile) || profiles[0]
...@@ -85,7 +85,7 @@ export class TerminalService { ...@@ -85,7 +85,7 @@ export class TerminalService {
const sessionOptions = { const sessionOptions = {
...profile.sessionOptions, ...profile.sessionOptions,
pauseAfterExit: pause, pauseAfterExit: pause,
cwd, cwd: cwd || undefined,
} }
return this.openTabWithOptions(sessionOptions) return this.openTabWithOptions(sessionOptions)
......
...@@ -34,6 +34,6 @@ export class TerminalFrontendService { ...@@ -34,6 +34,6 @@ export class TerminalFrontendService {
this.getFrontend(), this.getFrontend(),
) )
} }
return this.containers.get(session) return this.containers.get(session)!
} }
} }
...@@ -23,7 +23,7 @@ export class LinuxDefaultShellProvider extends ShellProvider { ...@@ -23,7 +23,7 @@ export class LinuxDefaultShellProvider extends ShellProvider {
return [] return []
} }
const line = (await fs.readFile('/etc/passwd', { encoding: 'utf-8' })) const line = (await fs.readFile('/etc/passwd', { encoding: 'utf-8' }))
.split('\n').find(x => x.startsWith(process.env.LOGNAME + ':')) .split('\n').find(x => x.startsWith(`${process.env.LOGNAME}:`))
if (!line) { if (!line) {
this.logger.warn('Could not detect user shell') this.logger.warn('Could not detect user shell')
return [{ return [{
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"importHelpers": true, "importHelpers": true,
"strictNullChecks": true,
"lib": [ "lib": [
"dom", "dom",
"es5", "es5",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册