170 lines
4.6 KiB
JavaScript
170 lines
4.6 KiB
JavaScript
import test from 'brittle'
|
|
import { readFile } from 'node:fs/promises'
|
|
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
import { attachBareOsTuiSdk } from '../../bare-os-booter/lib/services/bare-os-tui-sdk.js'
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
const lib = (name) => join(__dirname, '../lib', name)
|
|
|
|
async function loadEditTui() {
|
|
const parts = await Promise.all([
|
|
readFile(lib('edit-ansi.js'), 'utf8'),
|
|
readFile(lib('edit-highlight.js'), 'utf8'),
|
|
readFile(lib('edit-buffer.js'), 'utf8'),
|
|
readFile(lib('edit-tui.js'), 'utf8')
|
|
])
|
|
const hook = {}
|
|
new Function(
|
|
'exports',
|
|
parts.join('\n') +
|
|
'\nexports.bareEditCreateTuiApp = bareEditCreateTuiApp;\nexports.bareEditTuiRunOpts = bareEditTuiRunOpts;\nexports.bareEditIsGotoChord = bareEditIsGotoChord;\n'
|
|
)(hook)
|
|
return hook
|
|
}
|
|
|
|
function makeStream(isTTY, writes) {
|
|
return {
|
|
isTTY: !!isTTY,
|
|
raw: false,
|
|
columns: 80,
|
|
rows: 24,
|
|
write(s) {
|
|
writes.push(String(s))
|
|
},
|
|
setRawMode(v) {
|
|
this.raw = !!v
|
|
},
|
|
resume() {},
|
|
pause() {},
|
|
on() {},
|
|
removeListener() {}
|
|
}
|
|
}
|
|
|
|
function makeCtx(extra) {
|
|
const writes = []
|
|
const ctx = {
|
|
env: {},
|
|
console: { error() {}, log() {} },
|
|
replStdin: makeStream(true, writes),
|
|
replStdout: makeStream(true, writes),
|
|
b4a: {
|
|
from(s) {
|
|
return Buffer.from(String(s))
|
|
},
|
|
toString(b) {
|
|
return Buffer.from(b).toString('utf8')
|
|
}
|
|
},
|
|
vfs: {
|
|
async writeFile() {}
|
|
},
|
|
suspendReplForSubprocess() {},
|
|
resumeReplAfterSubprocess() {},
|
|
...(extra || {})
|
|
}
|
|
attachBareOsTuiSdk(ctx)
|
|
return ctx
|
|
}
|
|
|
|
test('edit-tui source prefers ctx.tui.run with cell buffer', async (t) => {
|
|
const src = await readFile(lib('edit-tui.js'), 'utf8')
|
|
t.ok(src.includes('ctx.tui.run'), 'TEA path uses ctx.tui.run')
|
|
t.ok(src.includes("buffer: 'cell'"), 'uses cell buffer')
|
|
t.ok(src.includes('bareEditCreateTuiApp'), 'exports TEA factory')
|
|
t.ok(src.includes('bareOsRunEditTuiLegacy'), 'keeps pre-SDK fallback')
|
|
})
|
|
|
|
test('edit TEA app inserts, marks dirty, and quits on ctrl+x', async (t) => {
|
|
const hook = await loadEditTui()
|
|
const ctx = makeCtx()
|
|
const app = hook.bareEditCreateTuiApp(ctx, {
|
|
path: '/tmp/note.js',
|
|
initialText: 'const x = 1\n',
|
|
argv0: 'edit'
|
|
})
|
|
t.is(app.buf.dirty, false)
|
|
app.update(ctx.tui.decode('a')[0])
|
|
t.ok(app.buf.dirty)
|
|
t.ok(app.buf.lines[0].startsWith('a'))
|
|
const view = ctx.tui.style.stripAnsi(app.view())
|
|
t.ok(view.includes('edit'), 'status shows argv0')
|
|
t.ok(view.includes('[Modified]'))
|
|
|
|
app.update(ctx.tui.decode('\x18')[0])
|
|
t.is(app.mode, 'quit_confirm')
|
|
const no = app.update(ctx.tui.decode('n')[0])
|
|
t.is(typeof no[1], 'function')
|
|
t.is(no[1]().type, 'quit')
|
|
|
|
const clean = hook.bareEditCreateTuiApp(ctx, {
|
|
path: '/tmp/clean.txt',
|
|
initialText: 'ok',
|
|
argv0: 'edit'
|
|
})
|
|
const q = clean.update(ctx.tui.decode('\x18')[0])
|
|
t.is(q[1]().type, 'quit')
|
|
})
|
|
|
|
test('edit TEA app help overlay and search', async (t) => {
|
|
const hook = await loadEditTui()
|
|
const ctx = makeCtx()
|
|
const app = hook.bareEditCreateTuiApp(ctx, {
|
|
path: 'a.js',
|
|
initialText: 'hello\nworld\n',
|
|
argv0: 'edit'
|
|
})
|
|
app.update(ctx.tui.decode('\x07')[0])
|
|
t.is(app.mode, 'help')
|
|
const ovs = app.overlays({ width: 80, height: 24 })
|
|
t.ok(ovs.length >= 1)
|
|
t.ok(ctx.tui.style.stripAnsi(ovs[0].text).includes('Bare OS edit'))
|
|
app.update(ctx.tui.decode('x')[0])
|
|
t.is(app.mode, 'edit')
|
|
|
|
app.update(ctx.tui.decode('\x17')[0])
|
|
t.is(app.mode, 'prompt_search')
|
|
app.update(ctx.tui.decode('w')[0])
|
|
app.update(ctx.tui.decode('o')[0])
|
|
app.update(ctx.tui.decode('\r')[0])
|
|
t.is(app.mode, 'edit')
|
|
t.is(app.buf.row, 1)
|
|
t.is(app.buf.col, 0)
|
|
})
|
|
|
|
test('edit TEA app save command writes vfs', async (t) => {
|
|
const hook = await loadEditTui()
|
|
let written = ''
|
|
const ctx = makeCtx({
|
|
vfs: {
|
|
async writeFile(_p, buf) {
|
|
written = Buffer.from(buf).toString('utf8')
|
|
}
|
|
}
|
|
})
|
|
const app = hook.bareEditCreateTuiApp(ctx, {
|
|
path: '/tmp/a.txt',
|
|
initialText: 'hi',
|
|
argv0: 'edit'
|
|
})
|
|
app.update(ctx.tui.decode('!')[0])
|
|
const pair = app.update(ctx.tui.decode('\x13')[0])
|
|
t.ok(typeof pair[1] === 'function')
|
|
const msg = await pair[1]()
|
|
app.update(msg)
|
|
t.ok(msg.ok)
|
|
t.ok(written.startsWith('!hi'))
|
|
t.absent(app.buf.dirty)
|
|
})
|
|
|
|
test('kernel edit bin includes ctx.tui.run after build', async (t) => {
|
|
const bin = await readFile(
|
|
join(__dirname, '../../../kernel/bin/edit'),
|
|
'utf8'
|
|
)
|
|
t.ok(bin.includes('ctx.tui.run'), 'kernel edit uses ctx.tui.run')
|
|
t.ok(bin.includes("buffer: 'cell'"), 'kernel edit uses cell buffer')
|
|
})
|