mirror of
https://github.com/OliveTin/OliveTin
synced 2025-12-11 16:45:42 +00:00
78 lines
1.7 KiB
JavaScript
78 lines
1.7 KiB
JavaScript
import { Terminal } from '@xterm/xterm'
|
|
import { FitAddon } from '@xterm/addon-fit'
|
|
import { Mutex } from './Mutex.js'
|
|
|
|
/**
|
|
* xterm.js based terminal output for the execution dialog.
|
|
*
|
|
* the xterm.js methods for write(), reset() and clear() appear to be async,
|
|
* but they do not return a Promise and instead use a callback. When calling
|
|
* these methods in quick succession, the output can get garbled due to race
|
|
* conditions.
|
|
*
|
|
* To avoid this, this class uses Mutex around those methods to ensure that
|
|
* only one write OR reset is executed at a time, is completed, and the calls
|
|
* occour in sequential order.
|
|
*/
|
|
export class OutputTerminal {
|
|
constructor (executionTrackingId) {
|
|
this.executionTrackingId = executionTrackingId
|
|
this.writeMutex = new Mutex()
|
|
this.terminal = new Terminal({
|
|
convertEol: true
|
|
})
|
|
|
|
const fitAddon = new FitAddon()
|
|
this.terminal.loadAddon(fitAddon)
|
|
this.terminal.fit = fitAddon
|
|
}
|
|
|
|
async write (out, then) {
|
|
const unlock = await this.writeMutex.lock()
|
|
|
|
try {
|
|
await new Promise(resolve => {
|
|
this.terminal.write(out, () => {
|
|
resolve()
|
|
})
|
|
})
|
|
} finally {
|
|
unlock()
|
|
|
|
if (then != null && then !== undefined) {
|
|
then()
|
|
}
|
|
}
|
|
}
|
|
|
|
async reset () {
|
|
const unlock = await this.writeMutex.lock()
|
|
|
|
try {
|
|
await new Promise(resolve => {
|
|
this.terminal.clear()
|
|
this.terminal.reset()
|
|
resolve()
|
|
})
|
|
} finally {
|
|
unlock()
|
|
}
|
|
}
|
|
|
|
fit () {
|
|
this.terminal.fit.fit()
|
|
}
|
|
|
|
open (el) {
|
|
this.terminal.open(el)
|
|
}
|
|
|
|
close () {
|
|
this.terminal.dispose()
|
|
}
|
|
|
|
resize (cols, rows) {
|
|
this.terminal.resize(cols, rows)
|
|
}
|
|
}
|