Add code formatting button, Python/Haskell support
This commit is contained in:
parent
3fd5bd32d8
commit
68bb853fa0
|
@ -35,6 +35,12 @@ export class Session {
|
||||||
writer: rpc.StreamMessageWriter;
|
writer: rpc.StreamMessageWriter;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
daemon: { proc: ChildProcess } | null = null;
|
daemon: { proc: ChildProcess } | null = null;
|
||||||
|
formatter: {
|
||||||
|
proc: ChildProcess;
|
||||||
|
live: boolean;
|
||||||
|
input: string;
|
||||||
|
output: string;
|
||||||
|
} | null = null;
|
||||||
|
|
||||||
get homedir() {
|
get homedir() {
|
||||||
return `/tmp/riju/${this.uuid}`;
|
return `/tmp/riju/${this.uuid}`;
|
||||||
|
@ -224,6 +230,13 @@ export class Session {
|
||||||
}
|
}
|
||||||
await this.runCode(msg.code);
|
await this.runCode(msg.code);
|
||||||
break;
|
break;
|
||||||
|
case "formatCode":
|
||||||
|
if (typeof msg.code !== "string") {
|
||||||
|
this.logBadMessage(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await this.formatCode(msg.code);
|
||||||
|
break;
|
||||||
case "lspInput":
|
case "lspInput":
|
||||||
if (typeof msg.input !== "object" || !msg) {
|
if (typeof msg.input !== "object" || !msg) {
|
||||||
this.logBadMessage(msg);
|
this.logBadMessage(msg);
|
||||||
|
@ -257,12 +270,11 @@ export class Session {
|
||||||
compile,
|
compile,
|
||||||
run,
|
run,
|
||||||
template,
|
template,
|
||||||
hacks,
|
|
||||||
} = this.config;
|
} = this.config;
|
||||||
if (this.term) {
|
if (this.term) {
|
||||||
const pid = this.term.pty.pid;
|
const pid = this.term.pty.pid;
|
||||||
const args = this.privilegedSpawn(
|
const args = this.privilegedSpawn(
|
||||||
bash(`kill -SIGTERM ${pid}; sleep 3; kill -SIGKILL ${pid}`)
|
bash(`kill -SIGTERM ${pid}; sleep 1; kill -SIGKILL ${pid}`)
|
||||||
);
|
);
|
||||||
spawn(args[0], args.slice(1));
|
spawn(args[0], args.slice(1));
|
||||||
// Signal to terminalOutput message generator using closure.
|
// Signal to terminalOutput message generator using closure.
|
||||||
|
@ -304,18 +316,6 @@ export class Session {
|
||||||
]),
|
]),
|
||||||
{ input: code }
|
{ input: code }
|
||||||
);
|
);
|
||||||
if (hacks && hacks.includes("ghci-config") && run) {
|
|
||||||
if (code) {
|
|
||||||
await this.run(
|
|
||||||
this.privilegedSpawn(["sh", "-c", `cat > ${this.homedir}/.ghci`]),
|
|
||||||
{ input: ":load Main\nmain\n" }
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await this.run(
|
|
||||||
this.privilegedSpawn(["rm", "-f", `${this.homedir}/.ghci`])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const termArgs = this.privilegedSpawn(bash(cmdline));
|
const termArgs = this.privilegedSpawn(bash(cmdline));
|
||||||
const term = {
|
const term = {
|
||||||
pty: pty.spawn(termArgs[0], termArgs.slice(1), {
|
pty: pty.spawn(termArgs[0], termArgs.slice(1), {
|
||||||
|
@ -338,6 +338,66 @@ export class Session {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
formatCode = async (code: string) => {
|
||||||
|
if (!this.config.format) {
|
||||||
|
this.log("formatCode ignored because format is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.formatter) {
|
||||||
|
const pid = this.formatter.proc.pid;
|
||||||
|
const args = this.privilegedSpawn(
|
||||||
|
bash(`kill -SIGTERM ${pid}; sleep 1; kill -SIGKILL ${pid}`)
|
||||||
|
);
|
||||||
|
spawn(args[0], args.slice(1));
|
||||||
|
this.formatter.live = false;
|
||||||
|
this.formatter = null;
|
||||||
|
}
|
||||||
|
const args = this.privilegedSpawn(bash(this.config.format));
|
||||||
|
const formatter = {
|
||||||
|
proc: spawn(args[0], args.slice(1)),
|
||||||
|
live: true,
|
||||||
|
input: code,
|
||||||
|
output: "",
|
||||||
|
};
|
||||||
|
formatter.proc.stdout!.on("data", (data) => {
|
||||||
|
if (formatter.live) {
|
||||||
|
formatter.output += data.toString("utf8");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
formatter.proc.stderr!.on("data", (data) => {
|
||||||
|
if (formatter.live) {
|
||||||
|
this.send({
|
||||||
|
event: "serviceLog",
|
||||||
|
service: "formatter",
|
||||||
|
output: data.toString("utf8"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
formatter.proc.on("exit", (code, signal) => {
|
||||||
|
if (code === 0) {
|
||||||
|
this.send({
|
||||||
|
event: "formattedCode",
|
||||||
|
code: formatter.output,
|
||||||
|
originalCode: formatter.input,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.send({
|
||||||
|
event: "serviceFailed",
|
||||||
|
service: "formatter",
|
||||||
|
error: `Exited with status ${signal || code}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
formatter.proc.on("error", (err) =>
|
||||||
|
this.send({
|
||||||
|
event: "serviceFailed",
|
||||||
|
service: "formatter",
|
||||||
|
error: `${err}`,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.formatter = formatter;
|
||||||
|
};
|
||||||
|
|
||||||
teardown = async () => {
|
teardown = async () => {
|
||||||
try {
|
try {
|
||||||
if (this.tearingDown) {
|
if (this.tearingDown) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ export interface LangConfig {
|
||||||
createEmpty?: string;
|
createEmpty?: string;
|
||||||
compile?: string;
|
compile?: string;
|
||||||
run: string;
|
run: string;
|
||||||
|
format?: string;
|
||||||
pkg?: {
|
pkg?: {
|
||||||
install: string;
|
install: string;
|
||||||
uninstall?: string;
|
uninstall?: string;
|
||||||
|
@ -24,7 +25,6 @@ export interface LangConfig {
|
||||||
lspConfig?: any;
|
lspConfig?: any;
|
||||||
lspLang?: string;
|
lspLang?: string;
|
||||||
template: string;
|
template: string;
|
||||||
hacks?: "ghci-config"[];
|
|
||||||
test?: {
|
test?: {
|
||||||
ensure?: string;
|
ensure?: string;
|
||||||
};
|
};
|
||||||
|
@ -764,9 +764,10 @@ function main(): void {
|
||||||
haskell: {
|
haskell: {
|
||||||
aliases: ["ghc", "ghci", "hs"],
|
aliases: ["ghc", "ghci", "hs"],
|
||||||
name: "Haskell",
|
name: "Haskell",
|
||||||
repl: "ghci",
|
repl: "rm -f .ghci && ghci",
|
||||||
main: "Main.hs",
|
main: "Main.hs",
|
||||||
run: "ghci",
|
run: "(echo ':load Main' && echo 'main') > .ghci && ghci",
|
||||||
|
format: "brittany Main.hs",
|
||||||
lspSetup: "cp /opt/haskell/hie.yaml hie.yaml",
|
lspSetup: "cp /opt/haskell/hie.yaml hie.yaml",
|
||||||
lsp: "HIE_HOOGLE_DATABASE=/opt/haskell/hoogle.hoo hie --lsp",
|
lsp: "HIE_HOOGLE_DATABASE=/opt/haskell/hoogle.hoo hie --lsp",
|
||||||
lspInit: {
|
lspInit: {
|
||||||
|
@ -1337,6 +1338,7 @@ main = do
|
||||||
repl: "python3 -u",
|
repl: "python3 -u",
|
||||||
main: "main.py",
|
main: "main.py",
|
||||||
run: "python3 -u -i main.py",
|
run: "python3 -u -i main.py",
|
||||||
|
format: "cat main.py | black -",
|
||||||
pkg: {
|
pkg: {
|
||||||
install: "pip3 install --user NAME",
|
install: "pip3 install --user NAME",
|
||||||
uninstall: "pip3 uninstall NAME",
|
uninstall: "pip3 uninstall NAME",
|
||||||
|
@ -1350,7 +1352,7 @@ main = do
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
template: `print("Hello, world!")
|
template: `print('Hello, world!')
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
قلب: {
|
قلب: {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<div id="editor" class="column"></div>
|
<div id="editor" class="column"></div>
|
||||||
<div id="terminal" class="column"></div>
|
<div id="terminal" class="column"></div>
|
||||||
<button type="button" class="btn btn-success" id="runButton">Run</button>
|
<button type="button" class="btn btn-success" id="runButton">Run</button>
|
||||||
|
<button type="button" class="btn btn-info" id="formatButton">Prettify</button>
|
||||||
<a href="/" class="btn btn-secondary" id="backButton">Switch to a different language</a>
|
<a href="/" class="btn btn-secondary" id="backButton">Switch to a different language</a>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -25,6 +25,7 @@ interface RijuConfig {
|
||||||
id: string;
|
id: string;
|
||||||
monacoLang?: string;
|
monacoLang?: string;
|
||||||
main: string;
|
main: string;
|
||||||
|
format?: string;
|
||||||
lspDisableDynamicRegistration?: boolean;
|
lspDisableDynamicRegistration?: boolean;
|
||||||
lspInit?: any;
|
lspInit?: any;
|
||||||
lspConfig?: any;
|
lspConfig?: any;
|
||||||
|
@ -133,7 +134,7 @@ async function main() {
|
||||||
|
|
||||||
function sendMessage(message: any) {
|
function sendMessage(message: any) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
console.log("SEND", message);
|
console.log("SEND:", message);
|
||||||
}
|
}
|
||||||
if (socket) {
|
if (socket) {
|
||||||
socket.send(JSON.stringify(message));
|
socket.send(JSON.stringify(message));
|
||||||
|
@ -165,8 +166,7 @@ async function main() {
|
||||||
DEBUG &&
|
DEBUG &&
|
||||||
message &&
|
message &&
|
||||||
message.event !== "lspOutput" &&
|
message.event !== "lspOutput" &&
|
||||||
message.event !== "lspLog" &&
|
message.event !== "serviceLog"
|
||||||
message.event !== "daemonLog"
|
|
||||||
) {
|
) {
|
||||||
console.log("RECEIVE:", message);
|
console.log("RECEIVE:", message);
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,18 @@ async function main() {
|
||||||
}
|
}
|
||||||
term.write(message.output);
|
term.write(message.output);
|
||||||
return;
|
return;
|
||||||
|
case "formattedCode":
|
||||||
|
if (
|
||||||
|
typeof message.code !== "string" ||
|
||||||
|
typeof message.originalCode !== "string"
|
||||||
|
) {
|
||||||
|
console.error("Unexpected message from server:", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (editor.getValue() === message.originalCode) {
|
||||||
|
editor.setValue(message.code);
|
||||||
|
}
|
||||||
|
return;
|
||||||
case "lspStarted":
|
case "lspStarted":
|
||||||
if (typeof message.root !== "string") {
|
if (typeof message.root !== "string") {
|
||||||
console.error("Unexpected message from server:", message);
|
console.error("Unexpected message from server:", message);
|
||||||
|
@ -308,6 +320,12 @@ async function main() {
|
||||||
document.getElementById("runButton")!.addEventListener("click", () => {
|
document.getElementById("runButton")!.addEventListener("click", () => {
|
||||||
sendMessage({ event: "runCode", code: editor.getValue() });
|
sendMessage({ event: "runCode", code: editor.getValue() });
|
||||||
});
|
});
|
||||||
|
if (config.format) {
|
||||||
|
document.getElementById("formatButton")!.classList.add("visible");
|
||||||
|
document.getElementById("formatButton")!.addEventListener("click", () => {
|
||||||
|
sendMessage({ event: "formatCode", code: editor.getValue() });
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(console.error);
|
main().catch(console.error);
|
||||||
|
|
|
@ -27,6 +27,17 @@ body {
|
||||||
right: calc(50% + 25px);
|
right: calc(50% + 25px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#formatButton {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 25px;
|
||||||
|
right: calc(50% + 25px);
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#formatButton.visible {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
#backButton {
|
#backButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 25px;
|
left: 25px;
|
||||||
|
|
|
@ -82,6 +82,9 @@ npm install -g pug-cli
|
||||||
# PureScript
|
# PureScript
|
||||||
npm install -g purescript spago
|
npm install -g purescript spago
|
||||||
|
|
||||||
|
# Python
|
||||||
|
pip3 install black
|
||||||
|
|
||||||
# ReasonML
|
# ReasonML
|
||||||
npm install -g bs-platform
|
npm install -g bs-platform
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,9 @@ tar -xf linux-x86_64-static.tar.gz
|
||||||
mv stack-*-linux-x86_64-static/stack /usr/bin/stack
|
mv stack-*-linux-x86_64-static/stack /usr/bin/stack
|
||||||
rm -rf stack-*-linux-x86_64-static linux-x86_64-static.tar.gz
|
rm -rf stack-*-linux-x86_64-static linux-x86_64-static.tar.gz
|
||||||
|
|
||||||
|
wget "https://drive.google.com/uc?export=download&id=1MpozlNLmWeUaQuT-5t6gyE3Yv56gUbea" -O /usr/local/bin/brittany
|
||||||
|
chmod +x /usr/local/bin/brittany
|
||||||
|
|
||||||
mkdir -p /opt/haskell
|
mkdir -p /opt/haskell
|
||||||
gdown "https://drive.google.com/uc?export=download&id=1GPoR_ja4ns16KCamRgwB-JVag4HK0igz" /usr/bin/hie
|
gdown "https://drive.google.com/uc?export=download&id=1GPoR_ja4ns16KCamRgwB-JVag4HK0igz" /usr/bin/hie
|
||||||
gdown "https://drive.google.com/uc?export=download&id=1qSxj8JjAeetAmNjUGayX0RBARgr5R4Ij" /opt/haskell/hoogle.hoo
|
gdown "https://drive.google.com/uc?export=download&id=1qSxj8JjAeetAmNjUGayX0RBARgr5R4Ij" /opt/haskell/hoogle.hoo
|
||||||
|
|
Loading…
Reference in New Issue