mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-27 06:49:53 +00:00
.
This commit is contained in:
parent
7a4806bcc9
commit
0abe1fbc9d
@ -5,6 +5,7 @@ export { ConfigProvider } from './configProvider'
|
|||||||
export { HotkeyProvider, IHotkeyDescription } from './hotkeyProvider'
|
export { HotkeyProvider, IHotkeyDescription } from './hotkeyProvider'
|
||||||
|
|
||||||
export { AppService } from 'services/app'
|
export { AppService } from 'services/app'
|
||||||
|
export { ConfigService } from 'services/config'
|
||||||
export { PluginsService } from 'services/plugins'
|
export { PluginsService } from 'services/plugins'
|
||||||
export { ElectronService } from 'services/electron'
|
export { ElectronService } from 'services/electron'
|
||||||
export { HotkeysService } from 'services/hotkeys'
|
export { HotkeysService } from 'services/hotkeys'
|
||||||
|
@ -49,7 +49,6 @@
|
|||||||
height: @tabs-height;
|
height: @tabs-height;
|
||||||
background: @body-bg;
|
background: @body-bg;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
&>button {
|
&>button {
|
||||||
line-height: @tabs-height - 2px;
|
line-height: @tabs-height - 2px;
|
||||||
@ -63,7 +62,7 @@
|
|||||||
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #888;
|
color: #aaa;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
@ -72,12 +71,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active-tab-0 .btn-new-tab {
|
&>.tabs-container {
|
||||||
border-bottom-right-radius: @tab-border-radius;
|
flex: auto;
|
||||||
}
|
display: flex;
|
||||||
|
|
||||||
tab-header.active + button {
|
|
||||||
border-bottom-left-radius: @tab-border-radius;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,27 +3,30 @@ title-bar(*ngIf='!config.full().appearance.useNativeFrame && config.store.appear
|
|||||||
.content(
|
.content(
|
||||||
[class.tabs-on-top]='config.full().appearance.tabsOnTop'
|
[class.tabs-on-top]='config.full().appearance.tabsOnTop'
|
||||||
)
|
)
|
||||||
.tabs(
|
.tabs
|
||||||
[class.active-tab-0]='app.tabs[0] == app.activeTab',
|
|
||||||
)
|
|
||||||
button.btn.btn-secondary(
|
button.btn.btn-secondary(
|
||||||
*ngFor='let button of getToolbarButtons(false)',
|
*ngFor='let button of getLeftToolbarButtons()',
|
||||||
[title]='button.title',
|
[title]='button.title',
|
||||||
(click)='button.click()',
|
(click)='button.click()',
|
||||||
)
|
)
|
||||||
i.fa([class]='"fa fa-" + button.icon')
|
i.fa([class]='"fa fa-" + button.icon')
|
||||||
tab-header(
|
|
||||||
*ngFor='let tab of app.tabs; let idx = index; trackBy: tab?.id',
|
.tabs-container
|
||||||
[index]='idx',
|
tab-header(
|
||||||
[model]='tab',
|
*ngFor='let tab of app.tabs; let idx = index; trackBy: tab?.id',
|
||||||
[active]='tab == app.activeTab',
|
[class.pre-selected]='idx == app.tabs.indexOf(app.activeTab) - 1',
|
||||||
[hasActivity]='tab.hasActivity',
|
[class.post-selected]='idx == app.tabs.indexOf(app.activeTab) + 1',
|
||||||
@animateTab,
|
[index]='idx',
|
||||||
(click)='app.selectTab(tab)',
|
[model]='tab',
|
||||||
(closeClicked)='app.closeTab(tab)',
|
[active]='tab == app.activeTab',
|
||||||
)
|
[hasActivity]='tab.hasActivity',
|
||||||
|
@animateTab,
|
||||||
|
(click)='app.selectTab(tab)',
|
||||||
|
(closeClicked)='app.closeTab(tab)',
|
||||||
|
)
|
||||||
|
|
||||||
button.btn.btn-secondary(
|
button.btn.btn-secondary(
|
||||||
*ngFor='let button of getToolbarButtons(true)',
|
*ngFor='let button of getRightToolbarButtons()',
|
||||||
[title]='button.title',
|
[title]='button.title',
|
||||||
(click)='button.click()',
|
(click)='button.click()',
|
||||||
)
|
)
|
||||||
|
@ -127,15 +127,9 @@ export class AppRootComponent {
|
|||||||
this.docking.dock()
|
this.docking.dock()
|
||||||
}
|
}
|
||||||
|
|
||||||
getToolbarButtons (aboveZero: boolean): IToolbarButton[] {
|
getLeftToolbarButtons (): IToolbarButton[] { return this.getToolbarButtons(false); }
|
||||||
let buttons: IToolbarButton[] = []
|
|
||||||
this.toolbarButtonProviders.forEach((provider) => {
|
getRightToolbarButtons (): IToolbarButton[] { return this.getToolbarButtons(true); }
|
||||||
buttons = buttons.concat(provider.provide())
|
|
||||||
})
|
|
||||||
return buttons
|
|
||||||
.filter((button) => (button.weight > 0) === aboveZero)
|
|
||||||
.sort((a: IToolbarButton, b: IToolbarButton) => (a.weight || 0) - (b.weight || 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
/*
|
/*
|
||||||
@ -151,4 +145,15 @@ export class AppRootComponent {
|
|||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getToolbarButtons (aboveZero: boolean): IToolbarButton[] {
|
||||||
|
let buttons: IToolbarButton[] = []
|
||||||
|
this.toolbarButtonProviders.forEach((provider) => {
|
||||||
|
buttons = buttons.concat(provider.provide())
|
||||||
|
})
|
||||||
|
return buttons
|
||||||
|
.filter((button) => (button.weight > 0) === aboveZero)
|
||||||
|
.sort((a: IToolbarButton, b: IToolbarButton) => (a.weight || 0) - (b.weight || 0))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,3 +26,14 @@ export abstract class SessionPersistenceProvider {
|
|||||||
abstract async startSession (options: SessionOptions): Promise<any>
|
abstract async startSession (options: SessionOptions): Promise<any>
|
||||||
abstract async terminateSession (recoveryId: string): Promise<void>
|
abstract async terminateSession (recoveryId: string): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ITerminalColorScheme {
|
||||||
|
name: string
|
||||||
|
foreground: string
|
||||||
|
background: string
|
||||||
|
colors: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class TerminalColorSchemeProvider {
|
||||||
|
abstract async getSchemes (): Promise<ITerminalColorScheme[]>
|
||||||
|
}
|
||||||
|
50
app/src/terminal/colorSchemes.ts
Normal file
50
app/src/terminal/colorSchemes.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import * as fs from 'fs-promise'
|
||||||
|
import * as path from 'path'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { TerminalColorSchemeProvider, ITerminalColorScheme } from './api'
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class HyperColorSchemes extends TerminalColorSchemeProvider {
|
||||||
|
async getSchemes (): Promise<ITerminalColorScheme[]> {
|
||||||
|
let pluginsPath = path.join(process.env.HOME, '.hyper_plugins', 'node_modules')
|
||||||
|
if (!(await fs.exists(pluginsPath))) return []
|
||||||
|
let plugins = await fs.readdir(pluginsPath)
|
||||||
|
|
||||||
|
let themes: ITerminalColorScheme[] = []
|
||||||
|
|
||||||
|
plugins.forEach(plugin => {
|
||||||
|
let module = (<any>global).require(path.join(pluginsPath, plugin))
|
||||||
|
if (module.decorateConfig) {
|
||||||
|
let config = module.decorateConfig({})
|
||||||
|
if (config.colors) {
|
||||||
|
themes.push({
|
||||||
|
name: plugin,
|
||||||
|
foreground: config.foregroundColor,
|
||||||
|
background: config.backgroundColor,
|
||||||
|
colors: config.colors.black ? [
|
||||||
|
config.colors.black,
|
||||||
|
config.colors.red,
|
||||||
|
config.colors.green,
|
||||||
|
config.colors.yellow,
|
||||||
|
config.colors.blue,
|
||||||
|
config.colors.magenta,
|
||||||
|
config.colors.cyan,
|
||||||
|
config.colors.white,
|
||||||
|
config.colors.lightBlack,
|
||||||
|
config.colors.lightRed,
|
||||||
|
config.colors.lightGreen,
|
||||||
|
config.colors.lightYellow,
|
||||||
|
config.colors.lightBlue,
|
||||||
|
config.colors.lightMagenta,
|
||||||
|
config.colors.lightCyan,
|
||||||
|
config.colors.lightWhite,
|
||||||
|
] : config.colors,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return themes
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,46 @@
|
|||||||
.appearance-preview(
|
.appearance-preview(
|
||||||
[style.font-family]='config.full().terminal.font',
|
[style.font-family]='config.full().terminal.font',
|
||||||
[style.font-size]='config.full().terminal.fontSize + "px"',
|
[style.font-size]='config.full().terminal.fontSize + "px"',
|
||||||
|
[style.background-color]='config.full().terminal.colorScheme.background',
|
||||||
|
[style.color]='config.full().terminal.colorScheme.foreground',
|
||||||
)
|
)
|
||||||
.text john@doe-pc$ ls
|
div
|
||||||
.text foo bar
|
span john@doe-pc
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[1]') $
|
||||||
|
span webpack
|
||||||
|
div
|
||||||
|
span Asset Size
|
||||||
|
div
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[2]') main.js
|
||||||
|
span 234 kB
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[2]') [emitted]
|
||||||
|
div
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[3]') big.js
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[3]') 1.2 MB
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[2]') [emitted]
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[3]') [big]
|
||||||
|
div
|
||||||
|
span
|
||||||
|
div
|
||||||
|
span john@doe-pc
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[1]') $
|
||||||
|
span ls -l
|
||||||
|
div
|
||||||
|
span drwxr-xr-x 1 root root
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[4]') directory
|
||||||
|
div
|
||||||
|
span -rw-r--r-- 1 root root file
|
||||||
|
div
|
||||||
|
span -rwxr-xr-x 1 root root
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[2]') executable
|
||||||
|
div
|
||||||
|
span -rwxr-xr-x 1 root root
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[6]') sym
|
||||||
|
span ->
|
||||||
|
span([style.color]='config.full().terminal.colorScheme.colors[1]') link
|
||||||
|
div
|
||||||
|
|
||||||
|
|
||||||
.col-lg-6
|
.col-lg-6
|
||||||
.form-group
|
.form-group
|
||||||
label Font
|
label Font
|
||||||
@ -27,6 +64,15 @@
|
|||||||
(ngModelChange)='config.save()',
|
(ngModelChange)='config.save()',
|
||||||
)
|
)
|
||||||
small.form-text.text-muted Text size to be used in the terminal
|
small.form-text.text-muted Text size to be used in the terminal
|
||||||
|
|
||||||
|
.form-group
|
||||||
|
label Color scheme
|
||||||
|
select.form-control(
|
||||||
|
[compareWith]='equalComparator',
|
||||||
|
'[(ngModel)]'='config.store.terminal.colorScheme',
|
||||||
|
(ngModelChange)='config.save()',
|
||||||
|
)
|
||||||
|
option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}}
|
||||||
|
|
||||||
.form-group
|
.form-group
|
||||||
label Terminal bell
|
label Terminal bell
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
.appearance-preview {
|
.appearance-preview {
|
||||||
background: black;
|
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin: 0 0 10px;
|
margin: 0 0 10px;
|
||||||
|
span {
|
||||||
.text {
|
white-space: pre;
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@ import { Observable } from 'rxjs/Observable'
|
|||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
import 'rxjs/add/operator/debounceTime'
|
import 'rxjs/add/operator/debounceTime'
|
||||||
import 'rxjs/add/operator/distinctUntilChanged'
|
import 'rxjs/add/operator/distinctUntilChanged'
|
||||||
import { Component } from '@angular/core'
|
const childProcessPromise = require('child-process-promise')
|
||||||
const childProcessPromise = nodeRequire('child-process-promise')
|
const equal = require('deep-equal')
|
||||||
|
|
||||||
|
import { Component, Inject } from '@angular/core'
|
||||||
|
import { TerminalColorSchemeProvider, ITerminalColorScheme } from '../api'
|
||||||
import { ConfigService } from 'services/config'
|
import { ConfigService } from 'services/config'
|
||||||
|
|
||||||
|
|
||||||
@ -14,12 +16,15 @@ import { ConfigService } from 'services/config'
|
|||||||
})
|
})
|
||||||
export class SettingsComponent {
|
export class SettingsComponent {
|
||||||
fonts: string[] = []
|
fonts: string[] = []
|
||||||
|
colorSchemes: ITerminalColorScheme[] = []
|
||||||
|
equalComparator = equal
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
|
@Inject(TerminalColorSchemeProvider) private colorSchemeProviders: TerminalColorSchemeProvider[],
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit () {
|
async ngOnInit () {
|
||||||
childProcessPromise.exec('fc-list :spacing=mono').then((result) => {
|
childProcessPromise.exec('fc-list :spacing=mono').then((result) => {
|
||||||
this.fonts = result.stdout
|
this.fonts = result.stdout
|
||||||
.split('\n')
|
.split('\n')
|
||||||
@ -28,6 +33,8 @@ export class SettingsComponent {
|
|||||||
.map((x) => x.split(',')[0].trim())
|
.map((x) => x.split(',')[0].trim())
|
||||||
this.fonts.sort()
|
this.fonts.sort()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.colorSchemes = (await Promise.all(this.colorSchemeProviders.map(x => x.getSchemes()))).reduce((a, b) => a.concat(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
fontAutocomplete = (text$: Observable<string>) => {
|
fontAutocomplete = (text$: Observable<string>) => {
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
:host {
|
:host {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
position: relative;
|
display: flex;
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 15px;
|
|
||||||
|
&> .content {
|
||||||
|
flex: auto;
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 15px;
|
||||||
|
|
||||||
div[style]:last-child {
|
div[style]:last-child {
|
||||||
background: black !important;
|
background: black !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
import { BehaviorSubject, ReplaySubject, Subject, Subscription } from 'rxjs'
|
import { BehaviorSubject, ReplaySubject, Subject, Subscription } from 'rxjs'
|
||||||
import { Component, NgZone, Inject, ElementRef } from '@angular/core'
|
import { Component, NgZone, Inject, ViewChild, HostBinding } from '@angular/core'
|
||||||
|
|
||||||
import { ConfigService } from 'services/config'
|
|
||||||
|
|
||||||
import { BaseTabComponent } from 'components/baseTab'
|
import { BaseTabComponent } from 'components/baseTab'
|
||||||
import { TerminalTab } from '../tab'
|
import { TerminalTab } from '../tab'
|
||||||
import { TerminalDecorator, ResizeEvent } from '../api'
|
import { TerminalDecorator, ResizeEvent } from '../api'
|
||||||
|
import { AppService, ConfigService } from 'api'
|
||||||
|
|
||||||
import { hterm, preferenceManager } from '../hterm'
|
import { hterm, preferenceManager } from '../hterm'
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'terminalTab',
|
selector: 'terminalTab',
|
||||||
template: '',
|
template: '<div #content class="content"></div>',
|
||||||
styles: [require('./terminalTab.scss')],
|
styles: [require('./terminalTab.scss')],
|
||||||
})
|
})
|
||||||
export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||||
@ -26,11 +25,13 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
|||||||
contentUpdated$ = new Subject<void>()
|
contentUpdated$ = new Subject<void>()
|
||||||
alternateScreenActive$ = new BehaviorSubject(false)
|
alternateScreenActive$ = new BehaviorSubject(false)
|
||||||
mouseEvent$ = new Subject<Event>()
|
mouseEvent$ = new Subject<Event>()
|
||||||
|
@ViewChild('content') content
|
||||||
|
@HostBinding('style.background-color') backgroundColor: string
|
||||||
private io: any
|
private io: any
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private zone: NgZone,
|
private zone: NgZone,
|
||||||
private elementRef: ElementRef,
|
private app: AppService,
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
@Inject(TerminalDecorator) private decorators: TerminalDecorator[],
|
@Inject(TerminalDecorator) private decorators: TerminalDecorator[],
|
||||||
) {
|
) {
|
||||||
@ -56,20 +57,19 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
|||||||
this.hterm.installKeyboard()
|
this.hterm.installKeyboard()
|
||||||
this.io = this.hterm.io.push()
|
this.io = this.hterm.io.push()
|
||||||
this.attachIOHandlers(this.io)
|
this.attachIOHandlers(this.io)
|
||||||
const dataSubscription = this.model.session.dataAvailable.subscribe((data) => {
|
this.model.session.output$.subscribe((data) => {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
this.output$.next(data)
|
this.output$.next(data)
|
||||||
})
|
})
|
||||||
this.write(data)
|
this.write(data)
|
||||||
})
|
})
|
||||||
const closedSubscription = this.model.session.closed.subscribe(() => {
|
this.model.session.closed$.first().subscribe(() => {
|
||||||
dataSubscription.unsubscribe()
|
this.app.closeTab(this.model)
|
||||||
closedSubscription.unsubscribe()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.model.session.releaseInitialDataBuffer()
|
this.model.session.releaseInitialDataBuffer()
|
||||||
}
|
}
|
||||||
this.hterm.decorate(this.elementRef.nativeElement)
|
this.hterm.decorate(this.content.nativeElement)
|
||||||
this.configure()
|
this.configure()
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -156,7 +156,7 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
|||||||
this.io.writeUTF8(data)
|
this.io.writeUTF8(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
configure () {
|
async configure (): Promise<void> {
|
||||||
let config = this.config.full()
|
let config = this.config.full()
|
||||||
preferenceManager.set('font-family', config.terminal.font)
|
preferenceManager.set('font-family', config.terminal.font)
|
||||||
preferenceManager.set('font-size', config.terminal.fontSize)
|
preferenceManager.set('font-size', config.terminal.fontSize)
|
||||||
@ -165,6 +165,18 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
|||||||
preferenceManager.set('enable-clipboard-notice', false)
|
preferenceManager.set('enable-clipboard-notice', false)
|
||||||
preferenceManager.set('receive-encoding', 'raw')
|
preferenceManager.set('receive-encoding', 'raw')
|
||||||
preferenceManager.set('send-encoding', 'raw')
|
preferenceManager.set('send-encoding', 'raw')
|
||||||
|
|
||||||
|
if (config.terminal.colorScheme.foreground) {
|
||||||
|
preferenceManager.set('foreground-color', config.terminal.colorScheme.foreground)
|
||||||
|
}
|
||||||
|
if (config.terminal.colorScheme.background) {
|
||||||
|
preferenceManager.set('background-color', config.terminal.colorScheme.background)
|
||||||
|
this.backgroundColor = config.terminal.colorScheme.background
|
||||||
|
}
|
||||||
|
if (config.terminal.colorScheme.colors) {
|
||||||
|
preferenceManager.set('color-palette-overrides', config.terminal.colorScheme.colors)
|
||||||
|
}
|
||||||
|
|
||||||
this.hterm.setBracketedPaste(config.terminal.bracketedPaste)
|
this.hterm.setBracketedPaste(config.terminal.bracketedPaste)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,11 @@ export class TerminalConfigProvider extends ConfigProvider {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
bell: 'off',
|
bell: 'off',
|
||||||
bracketedPaste: true,
|
bracketedPaste: true,
|
||||||
|
colorScheme: {
|
||||||
|
foreground: null,
|
||||||
|
background: null,
|
||||||
|
colors: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
hotkeys: {
|
hotkeys: {
|
||||||
'new-tab': [
|
'new-tab': [
|
||||||
@ -19,7 +24,9 @@ export class TerminalConfigProvider extends ConfigProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configStructure: any = {
|
configStructure: any = {
|
||||||
terminal: {},
|
terminal: {
|
||||||
|
colorScheme: {},
|
||||||
|
},
|
||||||
hotkeys: {},
|
hotkeys: {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,10 @@ import { SessionsService } from './services/sessions'
|
|||||||
import { ScreenPersistenceProvider } from './persistenceProviders'
|
import { ScreenPersistenceProvider } from './persistenceProviders'
|
||||||
import { ButtonProvider } from './buttonProvider'
|
import { ButtonProvider } from './buttonProvider'
|
||||||
import { RecoveryProvider } from './recoveryProvider'
|
import { RecoveryProvider } from './recoveryProvider'
|
||||||
import { SessionPersistenceProvider } from './api'
|
import { SessionPersistenceProvider, TerminalColorSchemeProvider } from './api'
|
||||||
import { TerminalSettingsProvider } from './settings'
|
import { TerminalSettingsProvider } from './settings'
|
||||||
import { TerminalConfigProvider } from './config'
|
import { TerminalConfigProvider } from './config'
|
||||||
|
import { HyperColorSchemes } from './colorSchemes'
|
||||||
import { hterm } from './hterm'
|
import { hterm } from './hterm'
|
||||||
|
|
||||||
|
|
||||||
@ -26,13 +27,14 @@ import { hterm } from './hterm'
|
|||||||
NgbModule,
|
NgbModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
SessionsService,
|
||||||
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||||
SessionsService,
|
|
||||||
{ provide: SessionPersistenceProvider, useClass: ScreenPersistenceProvider },
|
{ provide: SessionPersistenceProvider, useClass: ScreenPersistenceProvider },
|
||||||
// { provide: SessionPersistenceProvider, useValue: null },
|
// { provide: SessionPersistenceProvider, useValue: null },
|
||||||
{ provide: SettingsTabProvider, useClass: TerminalSettingsProvider, multi: true },
|
{ provide: SettingsTabProvider, useClass: TerminalSettingsProvider, multi: true },
|
||||||
{ provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true },
|
{ provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true },
|
||||||
|
{ provide: TerminalColorSchemeProvider, useClass: HyperColorSchemes, multi: true }
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
TerminalTabComponent,
|
TerminalTabComponent,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import * as nodePTY from 'node-pty'
|
import * as nodePTY from 'node-pty'
|
||||||
import * as fs from 'fs-promise'
|
import * as fs from 'fs-promise'
|
||||||
|
|
||||||
import { Injectable, EventEmitter } from '@angular/core'
|
import { Subject } from 'rxjs'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
import { Logger, LogService } from 'services/log'
|
import { Logger, LogService } from 'services/log'
|
||||||
import { SessionOptions, SessionPersistenceProvider } from '../api'
|
import { SessionOptions, SessionPersistenceProvider } from '../api'
|
||||||
|
|
||||||
@ -9,9 +10,9 @@ import { SessionOptions, SessionPersistenceProvider } from '../api'
|
|||||||
export class Session {
|
export class Session {
|
||||||
open: boolean
|
open: boolean
|
||||||
name: string
|
name: string
|
||||||
dataAvailable = new EventEmitter()
|
output$ = new Subject<string>()
|
||||||
closed = new EventEmitter()
|
closed$ = new Subject<void>()
|
||||||
destroyed = new EventEmitter()
|
destroyed$ = new Subject<void>()
|
||||||
recoveryId: string
|
recoveryId: string
|
||||||
truePID: number
|
truePID: number
|
||||||
private pty: any
|
private pty: any
|
||||||
@ -50,19 +51,18 @@ export class Session {
|
|||||||
if (!this.initialDataBufferReleased) {
|
if (!this.initialDataBufferReleased) {
|
||||||
this.initialDataBuffer += data
|
this.initialDataBuffer += data
|
||||||
} else {
|
} else {
|
||||||
this.dataAvailable.emit(data)
|
this.output$.next(data)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.pty.on('close', () => {
|
this.pty.on('close', () => {
|
||||||
this.open = false
|
this.close()
|
||||||
this.closed.emit()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseInitialDataBuffer () {
|
releaseInitialDataBuffer () {
|
||||||
this.initialDataBufferReleased = true
|
this.initialDataBufferReleased = true
|
||||||
this.dataAvailable.emit(this.initialDataBuffer)
|
this.output$.next(this.initialDataBuffer)
|
||||||
this.initialDataBuffer = null
|
this.initialDataBuffer = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ export class Session {
|
|||||||
|
|
||||||
close () {
|
close () {
|
||||||
this.open = false
|
this.open = false
|
||||||
this.closed.emit()
|
this.closed$.next()
|
||||||
this.pty.end()
|
this.pty.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +106,9 @@ export class Session {
|
|||||||
if (open) {
|
if (open) {
|
||||||
this.close()
|
this.close()
|
||||||
}
|
}
|
||||||
this.destroyed.emit()
|
this.destroyed$.next()
|
||||||
this.pty.destroy()
|
this.pty.destroy()
|
||||||
|
this.output$.complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
async getWorkingDirectory (): Promise<string> {
|
async getWorkingDirectory (): Promise<string> {
|
||||||
@ -142,12 +143,11 @@ export class SessionsService {
|
|||||||
this.lastID++
|
this.lastID++
|
||||||
options.name = `session-${this.lastID}`
|
options.name = `session-${this.lastID}`
|
||||||
let session = new Session(options)
|
let session = new Session(options)
|
||||||
const destroySubscription = session.destroyed.subscribe(() => {
|
session.destroyed$.first().subscribe(() => {
|
||||||
delete this.sessions[session.name]
|
delete this.sessions[session.name]
|
||||||
if (this.persistence) {
|
if (this.persistence) {
|
||||||
this.persistence.terminateSession(session.recoveryId)
|
this.persistence.terminateSession(session.recoveryId)
|
||||||
}
|
}
|
||||||
destroySubscription.unsubscribe()
|
|
||||||
})
|
})
|
||||||
this.sessions[session.name] = session
|
this.sessions[session.name] = session
|
||||||
return session
|
return session
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
"awesome-typescript-loader": "3.0.8",
|
"awesome-typescript-loader": "3.0.8",
|
||||||
"css-loader": "0.26.1",
|
"css-loader": "0.26.1",
|
||||||
"dataurl": "^0.1.0",
|
"dataurl": "^0.1.0",
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
"electron": "1.6.2",
|
"electron": "1.6.2",
|
||||||
"electron-builder": "10.6.1",
|
"electron-builder": "10.6.1",
|
||||||
"electron-osx-sign": "electron-userland/electron-osx-sign#f092181a1bffa2b3248a23ee28447a47e14a8f04",
|
"electron-osx-sign": "electron-userland/electron-osx-sign#f092181a1bffa2b3248a23ee28447a47e14a8f04",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user