diff --git a/app/src/plugins.ts b/app/src/plugins.ts index f32677b2..1ceff693 100644 --- a/app/src/plugins.ts +++ b/app/src/plugins.ts @@ -20,7 +20,7 @@ if (process.env.DEV) { nodeModule.globalPaths.unshift(path.join( path.dirname(require('electron').remote.app.getPath('exe')), - (process.platform == 'darwin') ? '../Resources' : 'resources', + (process.platform === 'darwin') ? '../Resources' : 'resources', 'builtin-plugins/node_modules', )) nodeModule.globalPaths.unshift(path.join( diff --git a/package.json b/package.json index 3e558892..22da74b6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "awesome-typescript-loader": "3.1.2", "cross-env": "^4.0.0", "css-loader": "0.26.1", - "electron": "1.6.2", + "electron": "1.6.7", "electron-builder": "^17.1.1", "electron-builder-squirrel-windows": "^17.0.1", "electron-osx-sign": "electron-userland/electron-osx-sign#f092181a1bffa2b3248a23ee28447a47e14a8f04", @@ -66,7 +66,7 @@ "scripts": { "build": "webpack --progress --color", "watch": "webpack --progress --color --watch", - "start": "cross-env DEV=1 electron app --debug", + "start": "cross-env DEV=1 electron --js-flags='--ignition' app --debug", "lint": "tslint -c tslint.json -t stylish terminus-*/src/**/*.ts terminus-*/src/*.ts app/src/*.ts", "postinstall": "install-app-deps" } diff --git a/terminus-clickable-links/src/decorator.ts b/terminus-clickable-links/src/decorator.ts index 62a9329a..c70dd46f 100644 --- a/terminus-clickable-links/src/decorator.ts +++ b/terminus-clickable-links/src/decorator.ts @@ -1,3 +1,4 @@ +import { Observable } from 'rxjs' import { Inject, Injectable } from '@angular/core' import { TerminalDecorator, TerminalTabComponent } from 'terminus-terminal' @@ -10,10 +11,11 @@ export class LinkHighlighterDecorator extends TerminalDecorator { } attach (terminal: TerminalTabComponent): void { + return terminal.contentUpdated$ - .debounceTime(1000) + .throttle(() => Observable.from([500])) .subscribe(() => { - this.insertLinks(terminal.hterm.screen_) + //this.insertLinks(terminal.hterm.screen_) }) } diff --git a/terminus-terminal/package.json b/terminus-terminal/package.json index 43637da3..3c43c609 100644 --- a/terminus-terminal/package.json +++ b/terminus-terminal/package.json @@ -42,7 +42,7 @@ "dependencies": { "font-manager": "0.2.2", "fs-promise": "2.0.2", - "hterm-commonjs": "1.0.0", + "hterm-umdjs": "1.1.3", "mz": "^2.6.0", "node-pty": "0.6.2", "winreg": "^1.2.3" diff --git a/terminus-terminal/src/api.ts b/terminus-terminal/src/api.ts index 0cb3a1e5..36163305 100644 --- a/terminus-terminal/src/api.ts +++ b/terminus-terminal/src/api.ts @@ -20,6 +20,8 @@ export interface SessionOptions { args?: string[] cwd?: string env?: any + width?: number + height?: number recoveryId?: string recoveredTruePID$?: Observable } diff --git a/terminus-terminal/src/buttonProvider.ts b/terminus-terminal/src/buttonProvider.ts index 14041ef8..975709b1 100644 --- a/terminus-terminal/src/buttonProvider.ts +++ b/terminus-terminal/src/buttonProvider.ts @@ -36,16 +36,17 @@ export class ButtonProvider extends ToolbarButtonProvider { '/k', path.join( path.dirname(this.electron.app.getPath('exe')), - (process.platform == 'darwin') ? '../Resources' : 'resources', + (process.platform === 'darwin') ? '../Resources' : 'resources', 'clink', `clink_${process.arch}.exe`, ), 'inject', ] } + let sessionOptions = await this.sessions.prepareNewSession({ command, args, cwd }) this.app.openNewTab( TerminalTabComponent, - { session: await this.sessions.createNewSession({ command, args, cwd }) } + { sessionOptions } ) } diff --git a/terminus-terminal/src/components/terminalTab.component.ts b/terminus-terminal/src/components/terminalTab.component.ts index 09320a89..7edc6427 100644 --- a/terminus-terminal/src/components/terminalTab.component.ts +++ b/terminus-terminal/src/components/terminalTab.component.ts @@ -1,10 +1,11 @@ -import { BehaviorSubject, ReplaySubject, Subject, Subscription } from 'rxjs' +import { Observable, BehaviorSubject, ReplaySubject, Subject, Subscription } from 'rxjs' +import 'rxjs/add/operator/bufferTime' import { Component, NgZone, Inject, Optional, ViewChild, HostBinding, Input } from '@angular/core' import { AppService, ConfigService, BaseTabComponent, ThemesService, HostAppService, Platform } from 'terminus-core' -import { Session } from '../services/sessions.service' +import { Session, SessionsService } from '../services/sessions.service' -import { TerminalDecorator, ResizeEvent } from '../api' +import { TerminalDecorator, ResizeEvent, SessionOptions } from '../api' import { hterm, preferenceManager } from '../hterm' @Component({ @@ -13,7 +14,8 @@ import { hterm, preferenceManager } from '../hterm' styles: [require('./terminalTab.component.scss')], }) export class TerminalTabComponent extends BaseTabComponent { - @Input() session: Session + session: Session + @Input() sessionOptions: SessionOptions @ViewChild('content') content @HostBinding('style.background-color') backgroundColor: string hterm: any @@ -21,6 +23,7 @@ export class TerminalTabComponent extends BaseTabComponent { sessionCloseSubscription: Subscription bell$ = new Subject() size$ = new ReplaySubject(1) + resize$ = new Subject() input$ = new Subject() output$ = new Subject() contentUpdated$ = new Subject() @@ -34,6 +37,7 @@ export class TerminalTabComponent extends BaseTabComponent { private app: AppService, private themes: ThemesService, private hostApp: HostAppService, + private sessions: SessionsService, public config: ConfigService, @Optional() @Inject(TerminalDecorator) private decorators: TerminalDecorator[], ) { @@ -43,12 +47,28 @@ export class TerminalTabComponent extends BaseTabComponent { this.configSubscription = config.change.subscribe(() => { this.configure() }) + this.resize$.first().subscribe(async (resizeEvent) => { + this.session = this.sessions.addSession( + Object.assign({}, this.sessionOptions, resizeEvent) + ) + this.session.output$.bufferTime(10).subscribe((datas) => { + let data = datas.join('') + this.zone.run(() => { + this.output$.next(data) + }) + this.write(data) + }) + this.sessionCloseSubscription = this.session.closed$.subscribe(() => { + this.app.closeTab(this) + }) + this.session.releaseInitialDataBuffer() + }) } getRecoveryToken (): any { return { type: 'app:terminal', - recoveryId: this.session.recoveryId, + recoveryId: this.sessionOptions.recoveryId, } } @@ -70,17 +90,6 @@ export class TerminalTabComponent extends BaseTabComponent { this.hterm.installKeyboard() this.io = this.hterm.io.push() this.attachIOHandlers(this.io) - this.session.output$.subscribe((data) => { - this.zone.run(() => { - this.output$.next(data) - }) - this.write(data) - }) - this.sessionCloseSubscription = this.session.closed$.subscribe(() => { - this.app.closeTab(this) - }) - - this.session.releaseInitialDataBuffer() } this.hterm.decorate(this.content.nativeElement) this.configure() @@ -116,6 +125,9 @@ export class TerminalTabComponent extends BaseTabComponent { this.alternateScreenActive$.next(state) } + hterm.primaryScreen_.syncSelectionCaret = () => null + hterm.alternateScreen_.syncSelectionCaret = () => null + const _onPaste = hterm.scrollPort_.onPaste_.bind(hterm.scrollPort_) hterm.scrollPort_.onPaste_ = (event) => { hterm.scrollPort_.pasteTarget_.value = event.clipboardData.getData('text/plain').trim() @@ -172,8 +184,11 @@ export class TerminalTabComponent extends BaseTabComponent { io.onTerminalResize = (columns, rows) => { // console.log(`Resizing to ${columns}x${rows}`) this.zone.run(() => { - this.session.resize(columns, rows) this.size$.next({ width: columns, height: rows }) + this.resize$.next({ width: columns, height: rows }) + if (this.session) { + this.session.resize(columns, rows) + } }) } } @@ -230,6 +245,7 @@ export class TerminalTabComponent extends BaseTabComponent { this.configSubscription.unsubscribe() this.sessionCloseSubscription.unsubscribe() this.size$.complete() + this.resize$.complete() this.input$.complete() this.output$.complete() this.contentUpdated$.complete() diff --git a/terminus-terminal/src/hterm.ts b/terminus-terminal/src/hterm.ts index 18dcae50..5e03c23c 100644 --- a/terminus-terminal/src/hterm.ts +++ b/terminus-terminal/src/hterm.ts @@ -1,5 +1,5 @@ const dataurl = require('dataurl') -export const hterm = require('hterm-commonjs') +export const hterm = require('hterm-umdjs') hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory() export const preferenceManager = new hterm.hterm.PreferenceManager('default') diff --git a/terminus-terminal/src/recoveryProvider.ts b/terminus-terminal/src/recoveryProvider.ts index 702a9f9a..3dc128ad 100644 --- a/terminus-terminal/src/recoveryProvider.ts +++ b/terminus-terminal/src/recoveryProvider.ts @@ -15,11 +15,11 @@ export class RecoveryProvider extends TabRecoveryProvider { async recover (recoveryToken: any): Promise { if (recoveryToken.type === 'app:terminal') { - let session = await this.sessions.recover(recoveryToken.recoveryId) - if (!session) { + let sessionOptions = await this.sessions.recover(recoveryToken.recoveryId) + if (!sessionOptions) { return } - this.app.openNewTab(TerminalTabComponent, { session }) + this.app.openNewTab(TerminalTabComponent, { sessionOptions }) } } } diff --git a/terminus-terminal/src/services/sessions.service.ts b/terminus-terminal/src/services/sessions.service.ts index 37e8d7be..8441502f 100644 --- a/terminus-terminal/src/services/sessions.service.ts +++ b/terminus-terminal/src/services/sessions.service.ts @@ -34,8 +34,8 @@ export class Session { } this.pty = nodePTY.spawn(options.command, options.args || [], { name: 'xterm-256color', - cols: 80, - rows: 30, + cols: options.width || 80, + rows: options.height || 30, cwd: options.cwd || process.env.HOME, env: env, }) @@ -140,13 +140,12 @@ export class SessionsService { this.logger = log.create('sessions') } - async createNewSession (options: SessionOptions): Promise { + async prepareNewSession (options: SessionOptions): Promise { if (this.persistence) { let recoveryId = await this.persistence.startSession(options) options = await this.persistence.attachSession(recoveryId) } - let session = this.addSession(options) - return session + return options } addSession (options: SessionOptions): Session { @@ -163,14 +162,10 @@ export class SessionsService { return session } - async recover (recoveryId: string): Promise { + async recover (recoveryId: string): Promise { if (!this.persistence) { return null } - const options = await this.persistence.attachSession(recoveryId) - if (!options) { - return null - } - return this.addSession(options) + return await this.persistence.attachSession(recoveryId) } }