mirror of
https://github.com/Eugeny/tabby.git
synced 2024-10-26 12:43:50 +03:00
.
This commit is contained in:
parent
c894410fdb
commit
7a4806bcc9
@ -7,8 +7,6 @@ import { Inject, Injectable } from '@angular/core'
|
||||
import { LinkHandler } from './api'
|
||||
import { TerminalDecorator, TerminalTabComponent } from '../terminal/api'
|
||||
|
||||
const debounceDelay = 500
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class LinkHighlighterDecorator extends TerminalDecorator {
|
||||
@ -17,40 +15,11 @@ export class LinkHighlighterDecorator extends TerminalDecorator {
|
||||
}
|
||||
|
||||
attach (terminal: TerminalTabComponent): void {
|
||||
const Screen = terminal.hterm.screen_.constructor
|
||||
if (Screen._linkHighlighterInstalled) {
|
||||
return
|
||||
}
|
||||
Screen._linkHighlighterInstalled = true
|
||||
|
||||
const oldInsertString = Screen.prototype.insertString
|
||||
const oldDeleteChars = Screen.prototype.deleteChars
|
||||
let self = this
|
||||
Screen.prototype.insertString = function (content) {
|
||||
let ret = oldInsertString.bind(this)(content)
|
||||
self.debounceInsertLinks(this)
|
||||
return ret
|
||||
}
|
||||
Screen.prototype.deleteChars = function (count) {
|
||||
let ret = oldDeleteChars.bind(this)(count)
|
||||
self.debounceInsertLinks(this)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
debounceInsertLinks (screen) {
|
||||
if (screen.__insertLinksTimeout) {
|
||||
screen.__insertLinksRebounce = true
|
||||
} else {
|
||||
screen.__insertLinksTimeout = window.setTimeout(() => {
|
||||
this.insertLinks(screen)
|
||||
screen.__insertLinksTimeout = null
|
||||
if (screen.__insertLinksRebounce) {
|
||||
screen.__insertLinksRebounce = false
|
||||
this.debounceInsertLinks(screen)
|
||||
}
|
||||
}, debounceDelay)
|
||||
}
|
||||
terminal.contentUpdated$
|
||||
.debounceTime(1000)
|
||||
.subscribe(() => {
|
||||
this.insertLinks(terminal.hterm.screen_)
|
||||
})
|
||||
}
|
||||
|
||||
insertLinks (screen) {
|
||||
|
@ -19,12 +19,14 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
hterm: any
|
||||
configSubscription: Subscription
|
||||
focusedSubscription: Subscription
|
||||
startupTime: number
|
||||
title$ = new BehaviorSubject('')
|
||||
size$ = new ReplaySubject<ResizeEvent>(1)
|
||||
input$ = new Subject<string>()
|
||||
output$ = new Subject<string>()
|
||||
contentUpdated$ = new Subject<void>()
|
||||
alternateScreenActive$ = new BehaviorSubject(false)
|
||||
mouseEvent$ = new Subject<Event>()
|
||||
private io: any
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
@ -33,7 +35,6 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
@Inject(TerminalDecorator) private decorators: TerminalDecorator[],
|
||||
) {
|
||||
super()
|
||||
this.startupTime = performance.now()
|
||||
this.configSubscription = config.change.subscribe(() => {
|
||||
this.configure()
|
||||
})
|
||||
@ -53,18 +54,13 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
|
||||
this.hterm.onTerminalReady = () => {
|
||||
this.hterm.installKeyboard()
|
||||
let io = this.hterm.io.push()
|
||||
this.attachIOHandlers(io)
|
||||
this.io = this.hterm.io.push()
|
||||
this.attachIOHandlers(this.io)
|
||||
const dataSubscription = this.model.session.dataAvailable.subscribe((data) => {
|
||||
if (performance.now() - this.startupTime > 500) {
|
||||
this.zone.run(() => {
|
||||
this.model.displayActivity()
|
||||
})
|
||||
}
|
||||
this.zone.run(() => {
|
||||
this.output$.next(data)
|
||||
})
|
||||
io.writeUTF8(data)
|
||||
this.write(data)
|
||||
})
|
||||
const closedSubscription = this.model.session.closed.subscribe(() => {
|
||||
dataSubscription.unsubscribe()
|
||||
@ -75,6 +71,12 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
}
|
||||
this.hterm.decorate(this.elementRef.nativeElement)
|
||||
this.configure()
|
||||
|
||||
setTimeout(() => {
|
||||
this.output$.subscribe(() => {
|
||||
this.model.displayActivity()
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
attachHTermHandlers (hterm: any) {
|
||||
@ -85,23 +87,54 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
})
|
||||
}
|
||||
|
||||
const oldInsertString = hterm.screen_.insertString.bind(hterm.screen_)
|
||||
hterm.screen_.insertString = (data) => {
|
||||
oldInsertString(data)
|
||||
this.contentUpdated$.next()
|
||||
const _decorate = hterm.scrollPort_.decorate.bind(hterm.scrollPort_)
|
||||
hterm.scrollPort_.decorate = (...args) => {
|
||||
_decorate(...args)
|
||||
hterm.scrollPort_.screen_.style.cssText += `; padding-right: ${hterm.scrollPort_.screen_.offsetWidth - hterm.scrollPort_.screen_.clientWidth}px;`
|
||||
}
|
||||
|
||||
const oldDeleteChars = hterm.screen_.deleteChars.bind(hterm.screen_)
|
||||
hterm.screen_.deleteChars = (count) => {
|
||||
let ret = oldDeleteChars(count)
|
||||
this.contentUpdated$.next()
|
||||
return ret
|
||||
const _setAlternateMode = hterm.setAlternateMode.bind(hterm)
|
||||
hterm.setAlternateMode = (state) => {
|
||||
_setAlternateMode(state)
|
||||
this.alternateScreenActive$.next(state)
|
||||
}
|
||||
|
||||
const _onPaste_ = hterm.onPaste_.bind(hterm)
|
||||
hterm.onPaste_ = (event) => {
|
||||
event.text = event.text.trim()
|
||||
_onPaste_(event)
|
||||
}
|
||||
|
||||
const _onMouse_ = hterm.onMouse_.bind(hterm)
|
||||
hterm.onMouse_ = (event) => {
|
||||
this.mouseEvent$.next(event)
|
||||
if ((event.ctrlKey || event.metaKey) && event.type === 'mousewheel') {
|
||||
event.preventDefault()
|
||||
let delta = Math.round(event.wheelDeltaY / 50)
|
||||
this.sendInput(((delta > 0) ? '\u001bOA' : '\u001bOB').repeat(Math.abs(delta)))
|
||||
}
|
||||
_onMouse_(event)
|
||||
}
|
||||
|
||||
for (let screen of [hterm.primaryScreen_, hterm.alternateScreen_]) {
|
||||
const _insertString = screen.insertString.bind(screen)
|
||||
screen.insertString = (data) => {
|
||||
_insertString(data)
|
||||
this.contentUpdated$.next()
|
||||
}
|
||||
|
||||
const _deleteChars = screen.deleteChars.bind(screen)
|
||||
screen.deleteChars = (count) => {
|
||||
let ret = _deleteChars(count)
|
||||
this.contentUpdated$.next()
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attachIOHandlers (io: any) {
|
||||
io.onVTKeystroke = io.sendString = (data) => {
|
||||
this.model.session.write(data)
|
||||
this.sendInput(data)
|
||||
this.zone.run(() => {
|
||||
this.input$.next(data)
|
||||
})
|
||||
@ -115,6 +148,14 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
}
|
||||
}
|
||||
|
||||
sendInput (data: string) {
|
||||
this.model.session.write(data)
|
||||
}
|
||||
|
||||
write (data: string) {
|
||||
this.io.writeUTF8(data)
|
||||
}
|
||||
|
||||
configure () {
|
||||
let config = this.config.full()
|
||||
preferenceManager.set('font-family', config.terminal.font)
|
||||
@ -133,5 +174,12 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
||||
})
|
||||
this.focusedSubscription.unsubscribe()
|
||||
this.configSubscription.unsubscribe()
|
||||
this.title$.complete()
|
||||
this.size$.complete()
|
||||
this.input$.complete()
|
||||
this.output$.complete()
|
||||
this.contentUpdated$.complete()
|
||||
this.alternateScreenActive$.complete()
|
||||
this.mouseEvent$.complete()
|
||||
}
|
||||
}
|
||||
|
@ -27,16 +27,4 @@ preferenceManager.set('color-palette-overrides', {
|
||||
0: '#1D272D',
|
||||
})
|
||||
|
||||
const oldDecorate = hterm.hterm.ScrollPort.prototype.decorate
|
||||
hterm.hterm.ScrollPort.prototype.decorate = function (...args) {
|
||||
oldDecorate.bind(this)(...args)
|
||||
this.screen_.style.cssText += `; padding-right: ${this.screen_.offsetWidth - this.screen_.clientWidth}px;`
|
||||
}
|
||||
|
||||
const oldPaste = hterm.hterm.Terminal.prototype.onPaste_
|
||||
hterm.hterm.Terminal.prototype.onPaste_ = function (e) {
|
||||
e.text = e.text.trim()
|
||||
oldPaste.bind(this)(e)
|
||||
}
|
||||
|
||||
hterm.hterm.Terminal.prototype.showOverlay = () => null
|
||||
|
@ -30,6 +30,7 @@ import { hterm } from './hterm'
|
||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||
SessionsService,
|
||||
{ provide: SessionPersistenceProvider, useClass: ScreenPersistenceProvider },
|
||||
// { provide: SessionPersistenceProvider, useValue: null },
|
||||
{ provide: SettingsTabProvider, useClass: TerminalSettingsProvider, multi: true },
|
||||
{ provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true },
|
||||
],
|
||||
|
@ -47,9 +47,12 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
|
||||
term xterm-color
|
||||
bindkey "^[OH" beginning-of-line
|
||||
bindkey "^[OF" end-of-line
|
||||
bindkey "\\027[?1049h" stuff ----alternate enter-----
|
||||
bindkey "\\027[?1049l" stuff ----alternate leave-----
|
||||
termcapinfo xterm* 'hs:ts=\\E]0;:fs=\\007:ds=\\E]0;\\007'
|
||||
defhstatus "^Et"
|
||||
hardstatus off
|
||||
altscreen on
|
||||
`, 'utf-8')
|
||||
let recoveryId = `term-tab-${Date.now()}`
|
||||
let args = ['-d', '-m', '-c', configPath, '-U', '-S', recoveryId, '--', options.command].concat(options.args || [])
|
||||
|
@ -130,8 +130,10 @@ export class SessionsService {
|
||||
}
|
||||
|
||||
async createNewSession (options: SessionOptions) : Promise<Session> {
|
||||
let recoveryId = await this.persistence.startSession(options)
|
||||
options = await this.persistence.attachSession(recoveryId)
|
||||
if (this.persistence) {
|
||||
let recoveryId = await this.persistence.startSession(options)
|
||||
options = await this.persistence.attachSession(recoveryId)
|
||||
}
|
||||
let session = this.addSession(options)
|
||||
return session
|
||||
}
|
||||
@ -142,7 +144,9 @@ export class SessionsService {
|
||||
let session = new Session(options)
|
||||
const destroySubscription = session.destroyed.subscribe(() => {
|
||||
delete this.sessions[session.name]
|
||||
this.persistence.terminateSession(session.recoveryId)
|
||||
if (this.persistence) {
|
||||
this.persistence.terminateSession(session.recoveryId)
|
||||
}
|
||||
destroySubscription.unsubscribe()
|
||||
})
|
||||
this.sessions[session.name] = session
|
||||
@ -150,6 +154,9 @@ export class SessionsService {
|
||||
}
|
||||
|
||||
async recover (recoveryId: string) : Promise<Session> {
|
||||
if (!this.persistence) {
|
||||
return null
|
||||
}
|
||||
const options = await this.persistence.attachSession(recoveryId)
|
||||
if (!options) {
|
||||
return null
|
||||
|
Loading…
Reference in New Issue
Block a user