import { Screen } from './screen.js'
export class Program {
constructor (model, opts = {}) {
this.model = model
this.screen = new Screen()
this.running = false
this._pollInterval = opts.pollInterval || 2000
this._pollTimer = null
this._onPoll = opts.onPoll || null
}
run () {
this.running = true
this.screen.enterAltScreen()
this.screen.hideCursor()
this.screen.enableRawMode()
this.screen.on('key', (key) => this.dispatch({ type: 'key', key }))
this.screen.on('resize', (size) => {
this.dispatch({ type: 'resize', ...size })
})
// Initial size into model
this.dispatch({
type: 'resize',
width: this.screen.width,
height: this.screen.height
})
this.render()
this._startPoll()
}
dispatch (msg) {
if (!this.running) return
// Ctrl+C always quits
if (msg.type === 'key' && msg.key.name === 'c' && msg.key.ctrl) {
this.quit()
return
}
const result = this.model.update(msg)
if (result && result.quit) {
this.quit()
return
}
this.render()
}
render () {
if (!this.running) return
const w = this.screen.width
const h = this.screen.height
const lines = this.model.view(w, h)
this.screen.render(lines)
}
quit () {
if (!this.running) return
this.running = false
this._stopPoll()
this.screen.destroy()
Bare.exit(0)
}
_startPoll () {
if (!this._onPoll) return
const tick = async () => {
if (!this.running) return
try {
await this._onPoll(this)
this.render()
} catch {}
if (this.running) {
this._pollTimer = setTimeout(tick, this._pollInterval)
}
}
this._pollTimer = setTimeout(tick, 100)
}
_stopPoll () {
if (this._pollTimer) {
clearTimeout(this._pollTimer)
this._pollTimer = null
}
}
}