Fix conflict in listener.ts
Improve matters Complete first version.
This commit is contained in:
parent
a47bf78a95
commit
735e807488
13
help.txt
Normal file
13
help.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Ludus CLI (v0.1.0)
|
||||||
|
|
||||||
|
The Ludus CLI has five modes: `help`, `version`, `run`, `listen`, and `send`.
|
||||||
|
|
||||||
|
* `help`: Output this text and exit.
|
||||||
|
|
||||||
|
* `version`: Ouput the current version number.
|
||||||
|
|
||||||
|
* `run`: Runs a Ludus script: `ludus run {script}`.
|
||||||
|
|
||||||
|
* `listen`: Starts a Ludus "listener" server, which receives Ludus source code on a given port and outputs the results. Similar to a REPL, intended to be used in conjunction with `send`, from a text editor.
|
||||||
|
|
||||||
|
* `send`: Sends text from `stdin` to a listening server. Any text editor that can send highlighted text to a command line program can evaluate Ludus source.
|
19
index.ts
Normal file
19
index.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { listen } from "./listener"
|
||||||
|
import { run_file } from "./runner"
|
||||||
|
import { send } from "./sender"
|
||||||
|
|
||||||
|
const help_text = await Bun.file("./help.txt").text()
|
||||||
|
|
||||||
|
export async function main() {
|
||||||
|
const cmd = Bun.argv[2]
|
||||||
|
switch (cmd) {
|
||||||
|
case "listen": { return listen() }
|
||||||
|
case "send": { return send() }
|
||||||
|
case "run": { return run_file(Bun.argv[3]) }
|
||||||
|
case "help": { return console.log(help_text) }
|
||||||
|
case "version": { return console.log("0.1.0") }
|
||||||
|
default: console.log("Usage: ludus {help | version | run | listen | send}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await main()
|
67
listener.ts
67
listener.ts
|
@ -1,29 +1,38 @@
|
||||||
import { run } from "@ludus/ludus-js-pure"
|
import { run } from "@ludus/ludus-js-pure"
|
||||||
|
import { unlinkSync, readFileSync } from "node:fs"
|
||||||
|
|
||||||
async function listen() {
|
export async function listen () {
|
||||||
const port = Math.floor((Math.random() * 1000) + 50000)
|
const port = Math.floor((Math.random() * 1000) + 50000)
|
||||||
|
const session_token = crypto.randomUUID();
|
||||||
const repl_info = { port }
|
const repl_file_path = ".lrepl"
|
||||||
|
const repl_info = { port, session: session_token }
|
||||||
const repl_file = Bun.file("./.lrepl")
|
const repl_file = Bun.file(repl_file_path)
|
||||||
|
|
||||||
await Bun.write(repl_file, JSON.stringify(repl_info))
|
await Bun.write(repl_file, JSON.stringify(repl_info))
|
||||||
|
|
||||||
console.log(`Ludus REPL listening on localhost:${port}`)
|
console.log(`Ludus REPL listening on localhost:${port}`)
|
||||||
|
console.log(`Session token: ${session_token}`)
|
||||||
|
|
||||||
Bun.listen({
|
Bun.listen({
|
||||||
hostname: "localhost",
|
hostname: "localhost",
|
||||||
port,
|
port,
|
||||||
socket: {
|
socket: {
|
||||||
data: (socket, data) => {
|
data: (_, data) => {
|
||||||
console.log("I got data!")
|
const payload = data.toString("utf-8")
|
||||||
const source = data.toString("utf-8")
|
let session, source
|
||||||
const result = run(source)
|
try {
|
||||||
const msgs = result.console
|
const json_msg = JSON.parse(payload)
|
||||||
for (const msg of msgs) {
|
session = json_msg.session
|
||||||
console.log(msg)
|
source = json_msg.source
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Received malformed message.")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (!result.errors) console.log(result.result)
|
if (session !== session_token) {
|
||||||
|
console.log("Received message not from this REPL session.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const result = run(source)
|
||||||
|
if (!result.errors) console.log("=>", result.result)
|
||||||
else {
|
else {
|
||||||
console.log("Ludus had some errors:")
|
console.log("Ludus had some errors:")
|
||||||
console.log(result.errors)
|
console.log(result.errors)
|
||||||
|
@ -32,9 +41,33 @@ async function listen() {
|
||||||
error: (socket, error) => { console.log(error); socket.end() }
|
error: (socket, error) => { console.log(error); socket.end() }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
process.on("exit", async function () {
|
||||||
|
try { cleanup(repl_file_path, session_token) } catch (e) {}
|
||||||
|
console.log("\nGoodbye.")
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on("SIGINT", () => process.exit())
|
||||||
|
|
||||||
|
// Below here, I'm trying to get ctrl-d to work to close the listener
|
||||||
|
// the while (true) loop locks the listener
|
||||||
|
// see: https://github.com/oven-sh/bun/issues/3255
|
||||||
|
// this should be doable with process.stdin.on("close"...)
|
||||||
|
//const mystdin = Bun.file("/dev/stdin").stream().getReader()
|
||||||
|
|
||||||
|
// while (true) {
|
||||||
|
// const {done, value} = await mystdin.read()
|
||||||
|
// if (done) process.exit()
|
||||||
|
// console.log(value)
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await listen()
|
// Don't delete an .lrepl we don't own
|
||||||
|
function cleanup (path: string, session_token: string) {
|
||||||
|
const repl_file = readFileSync(path).toString("utf-8")
|
||||||
|
const {session} = JSON.parse(repl_file)
|
||||||
|
if (session === session_token) unlinkSync(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "ludus-repl",
|
"name": "@ludus/cli",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "A CLI interface to Ludus.",
|
||||||
|
"main": "index.ts",
|
||||||
"module": "index.ts",
|
"module": "index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"license": "GPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest"
|
"@types/bun": "latest"
|
||||||
},
|
},
|
||||||
|
|
29
runner.ts
29
runner.ts
|
@ -1,13 +1,20 @@
|
||||||
import {run} from "@ludus/ludus-js-pure"
|
import { run } from "@ludus/ludus-js-pure"
|
||||||
|
|
||||||
const script = Bun.argv[2]
|
export async function run_file (path: string): Promise<void> {
|
||||||
const file = Bun.file(script)
|
const handle = Bun.file(path)
|
||||||
const source = await file.text()
|
const file_exists = await handle.exists()
|
||||||
console.log(`Source to run:
|
if (!file_exists) {
|
||||||
${source}`)
|
console.log(`File not found: ${path}`)
|
||||||
|
return
|
||||||
const result = run(source)
|
}
|
||||||
|
const source = await handle.text()
|
||||||
if (!result.errors) console.log(result.result)
|
const output = run(source)
|
||||||
else console.log(result.errors)
|
|
||||||
|
|
||||||
|
if (output.errors) {
|
||||||
|
for (const error of output.errors) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(output.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
42
sender.ts
42
sender.ts
|
@ -1,19 +1,31 @@
|
||||||
const repl_file = Bun.file("./.lrepl")
|
export async function send() {
|
||||||
const repl_info = await repl_file.json()
|
const repl_file = Bun.file("./.lrepl")
|
||||||
const port = repl_info.port
|
let repl_info
|
||||||
|
try {
|
||||||
const socket = await Bun.connect({
|
repl_info = await repl_file.json()
|
||||||
hostname: "localhost",
|
} catch (e) {
|
||||||
port,
|
console.log("No .lrepl file found.")
|
||||||
socket: {
|
process.exit(1)
|
||||||
data: (_, data) => process.exit()
|
|
||||||
}
|
}
|
||||||
})
|
const port = repl_info.port
|
||||||
|
const session = repl_info.session
|
||||||
|
|
||||||
for await (const input of Bun.stdin.stream()) {
|
const socket = await Bun.connect({
|
||||||
const chunk = Buffer.from(input).toString("utf-8")
|
hostname: "localhost",
|
||||||
socket.write(chunk)
|
port,
|
||||||
socket.end()
|
socket: {
|
||||||
process.exit()
|
data: () => process.exit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for await (const input of Bun.stdin.stream()) {
|
||||||
|
const chunk = Buffer.from(input).toString("utf-8")
|
||||||
|
const payload = {source: chunk, session}
|
||||||
|
// console.log("Sending:", payload)
|
||||||
|
// console.log(`To: ${port}`)
|
||||||
|
socket.write(JSON.stringify(payload))
|
||||||
|
socket.end()
|
||||||
|
process.exit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user