Moved the Editor to separate component

This commit is contained in:
inaseem 2021-10-05 14:37:38 +05:30
parent 40cd66eae0
commit 43bc2f24e5
5 changed files with 141 additions and 128 deletions

View File

@ -0,0 +1,111 @@
import MonacoEditor from "@monaco-editor/react";
import {
createConnection,
MonacoLanguageClient,
MonacoServices,
Services,
} from "monaco-languageclient";
import React from "react";
import { createMessageConnection } from "vscode-jsonrpc";
import RijuMessageReader from "../services/RijuMessageReader";
import RijuMessageWriter from "../services/RijuMessageWriter";
import { EventEmitter } from "../utils/EventEmitter";
let clientDisposable = null;
let servicesDisposable = null;
const RijuEditor = (props) => {
const { onEditorValueChange, config, splitType, onEditorMount } = props;
const editorRef = React.useRef();
const monacoRef = React.useRef();
React.useEffect(() => {
EventEmitter.subscribe("lspStarted", (data) => {
const { message, socket } = data;
initLSP(socket, message, monacoRef.current, editorRef.current);
});
EventEmitter.subscribe("lspStopped", () => {
if (clientDisposable) {
clientDisposable.dispose();
clientDisposable = null;
}
if (servicesDisposable) {
servicesDisposable.dispose();
servicesDisposable = null;
}
});
}, []);
const initLSP = (socket, message, monaco, editor) => {
const services = MonacoServices.create(editor, {
rootUri: `file://${message.root}`,
});
servicesDisposable = Services.install(services);
const newURI = `file://${message.root}/${config.main}`;
const oldModel = editor.getModel();
if (oldModel.uri.toString() !== newURI) {
// This code is likely to be buggy as it will probably
// never run and has thus never been tested.
editor.setModel(
monaco.editor.createModel(
oldModel.getValue(),
undefined,
monaco.Uri.parse(newURI)
)
);
oldModel.dispose();
}
const connection = createMessageConnection(
new RijuMessageReader(socket),
new RijuMessageWriter(socket, config)
);
const client = new MonacoLanguageClient({
name: "Riju",
clientOptions: {
documentSelector: [{ pattern: "**" }],
middleware: {
workspace: {
configuration: (params, token, configuration) => {
return Array(configuration(params, token).length).fill(
config.lsp.config !== undefined ? config.lsp.config : {}
);
},
},
},
initializationOptions: config.lsp.init || {},
},
connectionProvider: {
get: (errorHandler, closeHandler) =>
Promise.resolve(
createConnection(connection, errorHandler, closeHandler)
),
},
});
clientDisposable = client.start();
};
return (
<>
<MonacoEditor
wrapperClassName={"rijuEditor"}
onChange={onEditorValueChange}
language={config.monacoLang || "plaintext"}
value={config.template + "\n"}
options={{
minimap: { enabled: splitType == "horizontal" ? false : true },
scrollbar: { verticalScrollbarSize: 0 },
fontLigatures: true,
fontFamily: "Fira Code",
}}
onMount={(editor, monaco) => {
editorRef.current = editor;
monacoRef.current = monaco;
if (onEditorMount) onEditorMount(editor, monaco);
}}
/>
</>
);
};
export default RijuEditor;

View File

@ -18,7 +18,7 @@ Router.events.on("routeChangeComplete", () => {
}); });
Router.events.on("routeChangeError", () => { Router.events.on("routeChangeError", () => {
console.log("routeChangeError"); console.log("routeChangeError");
NProgress.done(); // NProgress.done();
}); });
function MyApp({ Component, pageProps }) { function MyApp({ Component, pageProps }) {

View File

@ -1,4 +1,3 @@
import MonacoEditor, { useMonaco } from "@monaco-editor/react";
import { import {
Circle, Circle,
Code as Format, Code as Format,
@ -22,7 +21,6 @@ import dynamic from "next/dynamic";
import Head from "next/head"; import Head from "next/head";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { createMessageConnection } from "vscode-jsonrpc";
import Layouts from "../../components/Layouts"; import Layouts from "../../components/Layouts";
import langs from "../../static/langs.json"; import langs from "../../static/langs.json";
import { EventEmitter } from "../../utils/EventEmitter"; import { EventEmitter } from "../../utils/EventEmitter";
@ -32,10 +30,11 @@ ansi.rgb = {
const RijuTerminal = dynamic(() => import("../../components/RijuTerminal"), { const RijuTerminal = dynamic(() => import("../../components/RijuTerminal"), {
ssr: false, ssr: false,
}); });
const RijuEditor = dynamic(() => import("../../components/RijuEditor"), {
ssr: false,
});
const DEBUG = true; const DEBUG = true;
let clientDisposable = null;
let servicesDisposable = null;
let serviceLogBuffers = {}; let serviceLogBuffers = {};
let serviceLogLines = {}; let serviceLogLines = {};
@ -43,7 +42,6 @@ const CodeRunner = (props) => {
const router = useRouter(); const router = useRouter();
const { langConfig } = props; const { langConfig } = props;
const editorRef = useRef(null); const editorRef = useRef(null);
const paneRef = useRef(null);
const [config, setConfig] = useState(langConfig); const [config, setConfig] = useState(langConfig);
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
const [isRunning, setRunning] = useState(false); const [isRunning, setRunning] = useState(false);
@ -51,7 +49,7 @@ const CodeRunner = (props) => {
const [isLspStarted, setLspStarted] = useState(false); const [isLspStarted, setLspStarted] = useState(false);
const [isLspRequested, setIsLspRequested] = useState(false); const [isLspRequested, setIsLspRequested] = useState(false);
const [splitType, setSplitType] = useState("horizontal"); const [splitType, setSplitType] = useState("horizontal");
const monaco = useMonaco();
const [status, setStatus] = useState("connecting"); const [status, setStatus] = useState("connecting");
function sendToTerminal(type, data) { function sendToTerminal(type, data) {
@ -59,6 +57,8 @@ const CodeRunner = (props) => {
} }
function connect() { function connect() {
serviceLogBuffers = {};
serviceLogLines = {};
setStatus("connecting"); setStatus("connecting");
const socket = new WebSocket( const socket = new WebSocket(
// (document.location.protocol === "http:" ? "ws://" : "wss://") + // (document.location.protocol === "http:" ? "ws://" : "wss://") +
@ -126,14 +126,7 @@ const CodeRunner = (props) => {
case "lspStopped": case "lspStopped":
setIsLspRequested(false); setIsLspRequested(false);
setLspStarted(false); setLspStarted(false);
if (clientDisposable) { EventEmitter.dispatch("lspStopped");
clientDisposable.dispose();
clientDisposable = null;
}
if (servicesDisposable) {
servicesDisposable.dispose();
servicesDisposable = null;
}
break; break;
case "lspStarted": case "lspStarted":
setLspStarted(true); setLspStarted(true);
@ -143,68 +136,10 @@ const CodeRunner = (props) => {
return; return;
} }
console.log("Started", message.root, config.main); EventEmitter.dispatch("lspStarted", { message, socket });
// EventEmitter.dispatch("lspStarted", message);
const {
createConnection,
MonacoLanguageClient,
MonacoServices,
Services,
} = await import("monaco-languageclient");
const services = MonacoServices.create(editorRef.current, {
rootUri: `file://${message.root}`,
});
servicesDisposable = Services.install(services);
const newURI = `file://${message.root}/${config.main}`;
const oldModel = editorRef.current.getModel();
console.log("Check 4", oldModel.uri, newURI);
if (oldModel.uri.toString() !== newURI) {
// This code is likely to be buggy as it will probably
// never run and has thus never been tested.
editorRef.current.setModel(
monaco.editor.createModel(
oldModel.getValue(),
undefined,
monaco.Uri.parse(newURI)
)
);
oldModel.dispose();
}
const RijuMessageReader = ( setTimeout(() => {}, 3000);
await import("../../services/RijuMessageReader")
).default;
const RijuMessageWriter = (
await import("../../services/RijuMessageWriter")
).default;
const connection = createMessageConnection(
new RijuMessageReader(socket),
new RijuMessageWriter(socket, config)
);
const client = new MonacoLanguageClient({
name: "Riju",
clientOptions: {
documentSelector: [{ pattern: "**" }],
middleware: {
workspace: {
configuration: (params, token, configuration) => {
return Array(configuration(params, token).length).fill(
config.lsp.config !== undefined ? config.lsp.config : {}
);
},
},
},
initializationOptions: config.lsp.init || {},
},
connectionProvider: {
get: (errorHandler, closeHandler) =>
Promise.resolve(
createConnection(connection, errorHandler, closeHandler)
),
},
});
clientDisposable = client.start();
return; return;
case "lspOutput": case "lspOutput":
// Should be handled by RijuMessageReader // Should be handled by RijuMessageReader
@ -251,6 +186,7 @@ const CodeRunner = (props) => {
case "lsp": case "lsp":
setLspStarted(false); setLspStarted(false);
setIsLspRequested(false); setIsLspRequested(false);
EventEmitter.dispatch("lspStopped");
break; break;
case "terminal": case "terminal":
sendToTerminal( sendToTerminal(
@ -260,6 +196,12 @@ const CodeRunner = (props) => {
break; break;
} }
return; return;
case "langConfig":
console.log("Lang Config", message);
// We could use this message instead of hardcoding the
// language config into the HTML page returned from the
// server, but for now we just ignore it.
return;
default: default:
console.error("Unexpected message from server:", message); console.error("Unexpected message from server:", message);
} }
@ -270,14 +212,7 @@ const CodeRunner = (props) => {
} else { } else {
console.error("Connection died"); console.error("Connection died");
} }
if (clientDisposable) { EventEmitter.dispatch("lspStopped");
clientDisposable.dispose();
clientDisposable = null;
}
if (servicesDisposable) {
servicesDisposable.dispose();
servicesDisposable = null;
}
setRunning(false); setRunning(false);
setLspStarted(false); setLspStarted(false);
setIsLspRequested(false); setIsLspRequested(false);
@ -313,7 +248,6 @@ const CodeRunner = (props) => {
function editorDidMount(editor, monaco) { function editorDidMount(editor, monaco) {
editorRef.current = editor; editorRef.current = editor;
editor.addAction({ editor.addAction({
id: "runCode", id: "runCode",
label: "Run", label: "Run",
@ -323,37 +257,6 @@ const CodeRunner = (props) => {
showValue(); showValue();
}, },
}); });
// Below code is just for adding an empty line in editor
monaco.languages.registerCodeLensProvider(
config.monacoLang || "plaintext",
{
provideCodeLenses: function (model, token) {
return {
lenses: [
{
range: {
startLineNumber: 1,
startColumn: 1,
endLineNumber: 2,
endColumn: 1,
},
id: "Format",
command: {
// id: commandId,
// title: "Format",
title: "",
},
},
],
dispose: () => {},
};
},
resolveCodeLens: function (model, codeLens, token) {
return codeLens;
},
}
);
setMounted(true); setMounted(true);
} }
@ -415,7 +318,7 @@ const CodeRunner = (props) => {
sx={{ sx={{
boxShadow: `0 2px 4px rgb(0 0 0 / 10%)`, boxShadow: `0 2px 4px rgb(0 0 0 / 10%)`,
zIndex: (t) => t.zIndex.appBar, zIndex: (t) => t.zIndex.appBar,
height: "48px", minHeight: "48px",
p: "0 24px", p: "0 24px",
}} }}
> >
@ -524,18 +427,11 @@ const CodeRunner = (props) => {
</Stack> </Stack>
<Layouts splitType={splitType}> <Layouts splitType={splitType}>
<Box className="panel editor"> <Box className="panel editor">
<MonacoEditor <RijuEditor
wrapperClassName={"rijuEditor"} onEditorValueChange={handleChange}
onChange={handleChange} config={config}
language={config.monacoLang || "plaintext"} splitType={splitType}
value={config.template + "\n"} onEditorMount={editorDidMount}
options={{
minimap: { enabled: splitType == "horizontal" ? false : true },
scrollbar: { verticalScrollbarSize: 0 },
fontLigatures: true,
fontFamily: "Fira Code",
}}
onMount={editorDidMount}
/> />
</Box> </Box>
<Box className="panel" sx={{ bgcolor: "#292D3E", p: 2 }}> <Box className="panel" sx={{ bgcolor: "#292D3E", p: 2 }}>

View File

@ -41,6 +41,7 @@
"historic-readline": "^1.0.8", "historic-readline": "^1.0.8",
"jsonschema": "^1.4.0", "jsonschema": "^1.4.0",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"monaco-editor": "^0.28.1",
"monaco-editor-webpack-plugin": "^4.1.2", "monaco-editor-webpack-plugin": "^4.1.2",
"monaco-languageclient": "0.13.0", "monaco-languageclient": "0.13.0",
"next": "11.0.1", "next": "11.0.1",

View File

@ -4181,6 +4181,11 @@ monaco-editor-webpack-plugin@^4.1.2:
dependencies: dependencies:
loader-utils "^2.0.0" loader-utils "^2.0.0"
monaco-editor@^0.28.1:
version "0.28.1"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.28.1.tgz#732788ff2172d59e6d436b206da8cac715413940"
integrity sha512-P1vPqxB4B1ZFzTeR1ScggSp9/5NoQrLCq88fnlNUsuRAP1usEBN4TIpI2lw0AYIZNVIanHk0qwjze2uJwGOHUw==
monaco-languageclient@0.13.0: monaco-languageclient@0.13.0:
version "0.13.0" version "0.13.0"
resolved "https://registry.yarnpkg.com/monaco-languageclient/-/monaco-languageclient-0.13.0.tgz#59b68b42fb7633171502d6557f597c2752f6c266" resolved "https://registry.yarnpkg.com/monaco-languageclient/-/monaco-languageclient-0.13.0.tgz#59b68b42fb7633171502d6557f597c2752f6c266"