mirror of
https://github.com/Eugeny/tabby.git
synced 2025-02-17 14:49:39 +08:00
.
This commit is contained in:
parent
90d7ee21ae
commit
2846637815
@ -9,10 +9,11 @@ export interface SessionOptions {
|
||||
cwd?: string,
|
||||
env?: any,
|
||||
recoveryId?: string
|
||||
recoveredTruePID?: number
|
||||
}
|
||||
|
||||
export abstract class SessionPersistenceProvider {
|
||||
abstract async recoverSession (recoveryId: any): Promise<SessionOptions>
|
||||
abstract async createSession (options: SessionOptions): Promise<SessionOptions>
|
||||
abstract async attachSession (recoveryId: any): Promise<SessionOptions>
|
||||
abstract async startSession (options: SessionOptions): Promise<any>
|
||||
abstract async terminateSession (recoveryId: string): Promise<void>
|
||||
}
|
||||
|
@ -20,7 +20,11 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
}
|
||||
|
||||
async getNewTab (): Promise<TerminalTab> {
|
||||
return new TerminalTab(await this.sessions.createNewSession({ command: 'zsh' }))
|
||||
let cwd = null
|
||||
if (this.app.activeTab instanceof TerminalTab) {
|
||||
cwd = await this.app.activeTab.session.getWorkingDirectory()
|
||||
}
|
||||
return new TerminalTab(await this.sessions.createNewSession({ command: 'zsh', cwd }))
|
||||
}
|
||||
|
||||
provide (): IToolbarButton[] {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Component, NgZone, Output, Inject, EventEmitter, ElementRef } from '@angular/core'
|
||||
import { BehaviorSubject, Subscription } from 'rxjs'
|
||||
import { Component, NgZone, Inject, ElementRef } from '@angular/core'
|
||||
|
||||
import { ConfigService } from 'services/config'
|
||||
|
||||
@ -16,9 +16,8 @@ import { hterm, preferenceManager } from '../hterm'
|
||||
styles: [require('./terminalTab.scss')],
|
||||
})
|
||||
export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
title: string
|
||||
@Output() titleChange = new EventEmitter()
|
||||
terminal: any
|
||||
title$ = new BehaviorSubject('')
|
||||
configSubscription: Subscription
|
||||
focusedSubscription: Subscription
|
||||
startupTime: number
|
||||
@ -47,8 +46,7 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
})
|
||||
this.terminal.setWindowTitle = (title) => {
|
||||
this.zone.run(() => {
|
||||
this.title = title
|
||||
this.titleChange.emit(title)
|
||||
this.model.title = title
|
||||
})
|
||||
}
|
||||
this.terminal.onTerminalReady = () => {
|
||||
|
@ -1,25 +1,12 @@
|
||||
import * as fs from 'fs-promise'
|
||||
const exec = require('child-process-promise').exec
|
||||
const spawn = require('child-process-promise').spawn
|
||||
|
||||
import { SessionOptions, SessionPersistenceProvider } from './api'
|
||||
|
||||
|
||||
export class NullPersistenceProvider extends SessionPersistenceProvider {
|
||||
async recoverSession (_recoveryId: any): Promise<SessionOptions> {
|
||||
return null
|
||||
}
|
||||
|
||||
async createSession (_options: SessionOptions): Promise<SessionOptions> {
|
||||
return null
|
||||
}
|
||||
|
||||
async terminateSession (_recoveryId: string): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ScreenPersistenceProvider extends SessionPersistenceProvider {
|
||||
/*
|
||||
list(): Promise<any[]> {
|
||||
return exec('screen -list').then((result) => {
|
||||
return result.stdout.split('\n')
|
||||
@ -29,17 +16,30 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
|
||||
return []
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
async attachSession (recoveryId: any): Promise<SessionOptions> {
|
||||
let lines = (await exec('screen -list')).stdout.split('\n')
|
||||
let screenPID = lines
|
||||
.filter(line => line.indexOf('.' + recoveryId) !== -1)
|
||||
.map(line => parseInt(line.trim().split('.')[0]))[0]
|
||||
|
||||
if (!screenPID) {
|
||||
return null
|
||||
}
|
||||
|
||||
lines = (await exec(`ps -o pid --ppid ${screenPID}`)).stdout.split('\n')
|
||||
let recoveredTruePID = parseInt(lines[1].split(/\s/).filter(x => !!x)[0])
|
||||
|
||||
async recoverSession (recoveryId: any): Promise<SessionOptions> {
|
||||
// TODO check
|
||||
return {
|
||||
recoveryId,
|
||||
recoveredTruePID,
|
||||
command: 'screen',
|
||||
args: ['-r', recoveryId],
|
||||
}
|
||||
}
|
||||
|
||||
async createSession (options: SessionOptions): Promise<SessionOptions> {
|
||||
async startSession (options: SessionOptions): Promise<any> {
|
||||
let configPath = '/tmp/.termScreenConfig'
|
||||
await fs.writeFile(configPath, `
|
||||
escape ^^^
|
||||
@ -52,10 +52,12 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
|
||||
hardstatus off
|
||||
`, 'utf-8')
|
||||
let recoveryId = `term-tab-${Date.now()}`
|
||||
options.args = ['-c', configPath, '-U', '-S', recoveryId, '--', options.command].concat(options.args || [])
|
||||
options.command = 'screen'
|
||||
options.recoveryId = recoveryId
|
||||
return options
|
||||
let args = ['-d', '-m', '-c', configPath, '-U', '-S', recoveryId, '--', options.command].concat(options.args || [])
|
||||
await spawn('screen', args, {
|
||||
cwd: options.cwd,
|
||||
env: options.env || process.env,
|
||||
})
|
||||
return recoveryId
|
||||
}
|
||||
|
||||
async terminateSession (recoveryId: string): Promise<void> {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import * as nodePTY from 'node-pty'
|
||||
import * as fs from 'fs-promise'
|
||||
|
||||
import { Injectable, EventEmitter } from '@angular/core'
|
||||
import { Logger, LogService } from 'services/log'
|
||||
@ -12,6 +13,7 @@ export class Session {
|
||||
closed = new EventEmitter()
|
||||
destroyed = new EventEmitter()
|
||||
recoveryId: string
|
||||
truePID: number
|
||||
private pty: any
|
||||
private initialDataBuffer = ''
|
||||
private initialDataBufferReleased = false
|
||||
@ -40,6 +42,8 @@ export class Session {
|
||||
env: env,
|
||||
})
|
||||
|
||||
this.truePID = options.recoveredTruePID || (<any>this.pty).pid
|
||||
|
||||
this.open = true
|
||||
|
||||
this.pty.on('data', (data) => {
|
||||
@ -105,6 +109,10 @@ export class Session {
|
||||
this.destroyed.emit()
|
||||
this.pty.destroy()
|
||||
}
|
||||
|
||||
async getWorkingDirectory (): Promise<string> {
|
||||
return await fs.readlink(`/proc/${this.truePID}/cwd`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -122,7 +130,8 @@ export class SessionsService {
|
||||
}
|
||||
|
||||
async createNewSession (options: SessionOptions) : Promise<Session> {
|
||||
options = await this.persistence.createSession(options)
|
||||
let recoveryId = await this.persistence.startSession(options)
|
||||
options = await this.persistence.attachSession(recoveryId)
|
||||
let session = this.addSession(options)
|
||||
return session
|
||||
}
|
||||
@ -141,7 +150,7 @@ export class SessionsService {
|
||||
}
|
||||
|
||||
async recover (recoveryId: string) : Promise<Session> {
|
||||
const options = await this.persistence.recoverSession(recoveryId)
|
||||
const options = await this.persistence.attachSession(recoveryId)
|
||||
if (!options) {
|
||||
return null
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user