added OSC52 support (remote copy)

This commit is contained in:
Eugene Pankov 2021-09-19 17:02:42 +02:00
parent d319a54fee
commit 02b7b12ea5
No known key found for this signature in database
GPG Key ID: 5896FCBBDD1CF4F4
3 changed files with 40 additions and 21 deletions

View File

@ -701,6 +701,11 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.attachSessionHandler(this.session.destroyed$, () => { this.attachSessionHandler(this.session.destroyed$, () => {
this.setSession(null) this.setSession(null)
}) })
this.attachSessionHandler(this.session.oscProcessor.copyRequested$, content => {
this.platform.setClipboard({ text: content })
this.notifications.notice('Copied')
})
} }
protected detachSessionHandlers (): void { protected detachSessionHandlers (): void {

View File

@ -1,32 +1,46 @@
import * as os from 'os' import * as os from 'os'
import { Subject, Observable } from 'rxjs' import { Subject, Observable } from 'rxjs'
const OSC1337Prefix = Buffer.from('\x1b]1337;') const OSCPrefix = Buffer.from('\x1b]')
const OSC1337Suffix = Buffer.from('\x07') const OSCSuffix = Buffer.from('\x07')
export class OSC1337Processor { export class OSCProcessor {
get cwdReported$ (): Observable<string> { return this.cwdReported } get cwdReported$ (): Observable<string> { return this.cwdReported }
get copyRequested$ (): Observable<string> { return this.copyRequested }
private cwdReported = new Subject<string>() private cwdReported = new Subject<string>()
private copyRequested = new Subject<string>()
process (data: Buffer): Buffer { process (data: Buffer): Buffer {
if (data.includes(OSC1337Prefix)) { let startIndex = 0
const preData = data.subarray(0, data.indexOf(OSC1337Prefix)) while (data.includes(OSCPrefix, startIndex) && data.includes(OSCSuffix, startIndex)) {
const params = data.subarray(data.indexOf(OSC1337Prefix) + OSC1337Prefix.length) const params = data.subarray(data.indexOf(OSCPrefix, startIndex) + OSCPrefix.length)
const postData = params.subarray(params.indexOf(OSC1337Suffix) + OSC1337Suffix.length) const oscString = params.subarray(0, params.indexOf(OSCSuffix)).toString()
const paramString = params.subarray(0, params.indexOf(OSC1337Suffix)).toString()
if (paramString.startsWith('CurrentDir=')) { startIndex = data.indexOf(OSCSuffix, startIndex) + OSCSuffix.length
let reportedCWD = paramString.split('=')[1]
if (reportedCWD.startsWith('~')) { const [oscCodeString, ...oscParams] = oscString.split(';')
reportedCWD = os.homedir() + reportedCWD.substring(1) const oscCode = parseInt(oscCodeString)
if (oscCode === 1337) {
const paramString = oscParams.join(';')
if (paramString.startsWith('CurrentDir=')) {
let reportedCWD = paramString.split('=')[1]
if (reportedCWD.startsWith('~')) {
reportedCWD = os.homedir() + reportedCWD.substring(1)
}
this.cwdReported.next(reportedCWD)
} else {
console.debug('Unsupported OSC 1337 parameter:', paramString)
}
} else if (oscCode === 52) {
if (oscParams[0] === 'c') {
const content = Buffer.from(oscParams[1], 'base64')
this.copyRequested.next(content.toString())
} }
this.cwdReported.next(reportedCWD)
} else { } else {
console.debug('Unsupported OSC 1337 parameter:', paramString) continue
} }
data = Buffer.concat([preData, postData])
} }
return data return data
} }

View File

@ -1,7 +1,7 @@
import { Observable, Subject } from 'rxjs' import { Observable, Subject } from 'rxjs'
import { Logger } from 'tabby-core' import { Logger } from 'tabby-core'
import { LoginScriptProcessor, LoginScriptsOptions } from './api/loginScriptProcessing' import { LoginScriptProcessor, LoginScriptsOptions } from './api/loginScriptProcessing'
import { OSC1337Processor } from './api/osc1337Processing' import { OSCProcessor } from './api/osc1337Processing'
/** /**
* A session object for a [[BaseTerminalTabComponent]] * A session object for a [[BaseTerminalTabComponent]]
@ -10,13 +10,13 @@ import { OSC1337Processor } from './api/osc1337Processing'
export abstract class BaseSession { export abstract class BaseSession {
open: boolean open: boolean
truePID?: number truePID?: number
oscProcessor = new OSCProcessor()
protected output = new Subject<string>() protected output = new Subject<string>()
protected binaryOutput = new Subject<Buffer>() protected binaryOutput = new Subject<Buffer>()
protected closed = new Subject<void>() protected closed = new Subject<void>()
protected destroyed = new Subject<void>() protected destroyed = new Subject<void>()
protected loginScriptProcessor: LoginScriptProcessor | null = null protected loginScriptProcessor: LoginScriptProcessor | null = null
protected reportedCWD?: string protected reportedCWD?: string
protected osc1337Processor = new OSC1337Processor()
private initialDataBuffer = Buffer.from('') private initialDataBuffer = Buffer.from('')
private initialDataBufferReleased = false private initialDataBufferReleased = false
@ -26,13 +26,13 @@ export abstract class BaseSession {
get destroyed$ (): Observable<void> { return this.destroyed } get destroyed$ (): Observable<void> { return this.destroyed }
constructor (protected logger: Logger) { constructor (protected logger: Logger) {
this.osc1337Processor.cwdReported$.subscribe(cwd => { this.oscProcessor.cwdReported$.subscribe(cwd => {
this.reportedCWD = cwd this.reportedCWD = cwd
}) })
} }
emitOutput (data: Buffer): void { emitOutput (data: Buffer): void {
data = this.osc1337Processor.process(data) data = this.oscProcessor.process(data)
if (!this.initialDataBufferReleased) { if (!this.initialDataBufferReleased) {
this.initialDataBuffer = Buffer.concat([this.initialDataBuffer, data]) this.initialDataBuffer = Buffer.concat([this.initialDataBuffer, data])
} else { } else {
@ -64,7 +64,7 @@ export abstract class BaseSession {
this.destroyed.next() this.destroyed.next()
await this.gracefullyKillProcess() await this.gracefullyKillProcess()
} }
this.osc1337Processor.close() this.oscProcessor.close()
this.closed.complete() this.closed.complete()
this.destroyed.complete() this.destroyed.complete()
this.output.complete() this.output.complete()