mirror of
https://github.com/He4eT/cheap-glkote.git
synced 2026-05-04 16:37:23 +00:00
Move player.stdio
This commit is contained in:
parent
1a9bf1ad0d
commit
b9e4269aa4
4 changed files with 6 additions and 5 deletions
62
bin/player.stdio.js
Normal file
62
bin/player.stdio.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* @see: https://github.com/curiousdannii/emglken/blob/master/bin/emglken.js
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
const minimist = require('minimist')
|
||||
|
||||
const CheapGlkOte = require('../src/')
|
||||
const { handlers } = require('./stdio')
|
||||
|
||||
const formats = [
|
||||
{
|
||||
id: 'bocfel',
|
||||
extensions: /z([3458]|blorb)$/,
|
||||
engine: 'bocfel.js',
|
||||
},
|
||||
{
|
||||
id: 'glulxe',
|
||||
extensions: /(gblorb|ulx)$/,
|
||||
engine: 'glulxe.js',
|
||||
},
|
||||
{
|
||||
id: 'git',
|
||||
extensions: /(gblorb|ulx)$/,
|
||||
engine: 'git.js',
|
||||
},
|
||||
{
|
||||
id: 'hugo',
|
||||
extensions: /hex$/,
|
||||
engine: 'hugo.js',
|
||||
},
|
||||
{
|
||||
id: 'tads',
|
||||
extensions: /(gam|t3)$/,
|
||||
engine: 'tads.js',
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
const argv = minimist(process.argv.slice(2))
|
||||
const storyfile = argv._[0]
|
||||
|
||||
const format = formats.find(x =>
|
||||
x.extensions.test(storyfile))
|
||||
|
||||
if (!format) {
|
||||
console.error('Unknown storyfile format.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const { glkInterface, sendFn } = CheapGlkOte(handlers)
|
||||
handlers.setSend(sendFn)
|
||||
|
||||
const engine = require('emglken/src/' + format.engine)
|
||||
const vm = new engine()
|
||||
|
||||
vm.prepare(
|
||||
fs.readFileSync(storyfile),
|
||||
glkInterface)
|
||||
vm.start()
|
||||
145
bin/stdio.js
Normal file
145
bin/stdio.js
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* @see: https://github.com/curiousdannii/glkote-term/blob/master/src/glkote-dumb.js
|
||||
*/
|
||||
|
||||
const readline = require('readline')
|
||||
const MuteStream = require('mute-stream')
|
||||
const ansiEscapes = require('ansi-escapes')
|
||||
|
||||
const stdin = process.stdin
|
||||
const stdout = new MuteStream()
|
||||
stdout.pipe(process.stdout)
|
||||
const rl = readline.createInterface({
|
||||
input: stdin,
|
||||
output: stdout,
|
||||
prompt: ''
|
||||
})
|
||||
|
||||
let send = _ => _
|
||||
|
||||
const setSend = fn => {
|
||||
send = fn
|
||||
}
|
||||
|
||||
const onInit = () => {
|
||||
if (stdin.isTTY) {
|
||||
stdin.setRawMode(true)
|
||||
}
|
||||
readline.emitKeypressEvents(stdin)
|
||||
rl.resume()
|
||||
}
|
||||
|
||||
const onUpdateContent = messages =>
|
||||
messages.text.forEach(({ append, content }) => {
|
||||
if (!append) {
|
||||
stdout.write('\n')
|
||||
}
|
||||
|
||||
if (content) {
|
||||
content.forEach(x => {
|
||||
if (x.text === '>') return null
|
||||
|
||||
if (x.style === 'input') {
|
||||
if (stdout.isTTY) {
|
||||
stdout.write(ansiEscapes.eraseLines(2))
|
||||
stdout.write('> ')
|
||||
}
|
||||
}
|
||||
|
||||
stdout.write(
|
||||
typeof x === 'string'
|
||||
? x
|
||||
: x.text)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const onUpdateInputs = type => {
|
||||
type
|
||||
? attach_handlers(type)
|
||||
: detach_handlers()
|
||||
}
|
||||
|
||||
const onExit = () => {
|
||||
detach_handlers()
|
||||
rl.close()
|
||||
stdout.write('\n')
|
||||
}
|
||||
|
||||
const onDisable = disable =>
|
||||
disable
|
||||
? detach_handlers()
|
||||
: attach_handlers()
|
||||
|
||||
const onFileNameRequest = (tosave, usage, gameid, callback) => {
|
||||
stdout.write('\n')
|
||||
rl.question(
|
||||
'Please enter a file name: ',
|
||||
filename => callback(filename
|
||||
? { filename, usage }
|
||||
: null))
|
||||
}
|
||||
|
||||
const onFileRead = (dirent, israw) =>
|
||||
void console.log('onFileRead:', dirent)
|
||||
|
||||
const onFileWrite = (dirent, content, israw) =>
|
||||
void console.log('onFileWrite:', dirent, content.length)
|
||||
|
||||
const handle_char_input = (str, key) => {
|
||||
const key_replacements = {
|
||||
'\x7F': 'delete',
|
||||
'\t': 'tab',
|
||||
}
|
||||
|
||||
detach_handlers()
|
||||
|
||||
// Make sure this char isn't being remembered for the next line input
|
||||
rl._line_buffer = null
|
||||
rl.line = ''
|
||||
|
||||
// Process special keys
|
||||
const res =
|
||||
key_replacements[str] ||
|
||||
str ||
|
||||
key.name.replace(/f(\d+)/, 'func$1')
|
||||
|
||||
send(res)
|
||||
}
|
||||
|
||||
const attach_handlers = type => {
|
||||
if (type === 'char') {
|
||||
stdout.mute()
|
||||
stdin.on('keypress', handle_char_input)
|
||||
}
|
||||
if (type === 'line') {
|
||||
rl.on('line', handle_line_input)
|
||||
}
|
||||
}
|
||||
|
||||
const detach_handlers = () => {
|
||||
stdin.removeListener('keypress', handle_char_input)
|
||||
rl.removeListener('line', handle_line_input)
|
||||
stdout.unmute()
|
||||
}
|
||||
|
||||
const handle_line_input = line => {
|
||||
if (stdout.isTTY) {
|
||||
stdout.write(ansiEscapes.eraseLines(1))
|
||||
}
|
||||
detach_handlers()
|
||||
|
||||
send(line)
|
||||
}
|
||||
|
||||
module.exports.handlers = {
|
||||
onInit,
|
||||
onUpdateContent,
|
||||
onDisable,
|
||||
onUpdateInputs,
|
||||
onFileNameRequest,
|
||||
onFileRead,
|
||||
onFileWrite,
|
||||
onExit,
|
||||
setSend
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue