mirror of
https://github.com/Eugeny/tabby.git
synced 2024-12-22 18:11:43 +03:00
strict null checks
This commit is contained in:
parent
9b904856fa
commit
181c523020
@ -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 = ''
|
|||||||
;(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[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(window as any).installedPlugins = foundPlugins
|
foundPlugins.sort((a, b) => a.name > b.name ? 1 : -1)
|
||||||
|
|
||||||
|
;(window as any).installedPlugins = foundPlugins
|
||||||
return foundPlugins
|
return foundPlugins
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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 {
|
|||||||
* @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 {
|
|||||||
/**
|
/**
|
||||||
* Raw SVG icon code
|
* Raw SVG icon code
|
||||||
*/
|
*/
|
||||||
icon: string
|
icon?: string
|
||||||
|
|
||||||
title: string
|
title: string
|
||||||
|
|
||||||
|
@ -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 {
|
|||||||
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 {
|
|||||||
/**
|
/**
|
||||||
* 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 {
|
|||||||
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 {
|
|||||||
*
|
*
|
||||||
* @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 {
|
|||||||
/**
|
/**
|
||||||
* 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 {
|
|||||||
/**
|
/**
|
||||||
* @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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
/**
|
/**
|
||||||
* 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
|
|||||||
) {
|
) {
|
||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @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
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
/** @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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
/** @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 {
|
|||||||
})
|
})
|
||||||
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 {
|
|||||||
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 {
|
|||||||
*
|
*
|
||||||
* @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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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[] {
|
|||||||
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 {
|
|||||||
'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 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
/**
|
/**
|
||||||
* 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'
|
|||||||
|
|
||||||
@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 {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
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',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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 @@
|
|||||||
"@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 @@
|
|||||||
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 @@
|
|||||||
(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
|
|||||||
|
|
||||||
|
|
||||||
.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
|
|||||||
)
|
)
|
||||||
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}}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
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'
|
|||||||
BrowserModule,
|
BrowserModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
NgbModule,
|
NgbModule,
|
||||||
NgPipesModule,
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: SettingsTabProvider, useClass: PluginsSettingsTabProvider, multi: true },
|
{ provide: SettingsTabProvider, useClass: PluginsSettingsTabProvider, multi: true },
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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 @@
|
|||||||
"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 @@
|
|||||||
"@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 {
|
|||||||
@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 {
|
|||||||
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')
|
|||||||
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')
|
|||||||
.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')
|
|||||||
[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')
|
|||||||
| 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')
|
|||||||
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')
|
|||||||
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'
|
|||||||
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'
|
|||||||
BrowserModule,
|
BrowserModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
NgbModule,
|
NgbModule,
|
||||||
NgPipesModule,
|
|
||||||
TerminusCorePlugin,
|
TerminusCorePlugin,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
@ -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 @@
|
|||||||
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==
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
)).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 {
|
|||||||
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'
|
|||||||
/** @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 {
|
|||||||
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 {
|
|||||||
) 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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"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
|
|||||||
@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 {
|
|||||||
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'
|
|||||||
@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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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/
|
|||||||
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 {
|
|||||||
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'
|
|||||||
/** @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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.pauseAfterExit = options.pauseAfterExit
|
this.pauseAfterExit = options.pauseAfterExit || false
|
||||||
}
|
}
|
||||||
|
|
||||||
processOSC1337 (data: string) {
|
processOSC1337 (data: string) {
|
||||||
@ -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 {
|
|||||||
* 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 {
|
|||||||
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 {
|
|||||||
this.getFrontend(),
|
this.getFrontend(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return this.containers.get(session)
|
return this.containers.get(session)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
"es5",
|
"es5",
|
||||||
|
Loading…
Reference in New Issue
Block a user