|
|
|
@ -18,7 +18,6 @@ import { EditorConnection, EditorEvents } from '../../../node_modules/lean4-info
|
|
|
|
import { EventEmitter } from '../../../node_modules/lean4-infoview/src/infoview/event'
|
|
|
|
import { EventEmitter } from '../../../node_modules/lean4-infoview/src/infoview/event'
|
|
|
|
|
|
|
|
|
|
|
|
import { GameIdContext } from '../app'
|
|
|
|
import { GameIdContext } from '../app'
|
|
|
|
import { ConnectionContext, connection, useLeanClient } from '../connection'
|
|
|
|
|
|
|
|
import { useAppDispatch, useAppSelector } from '../hooks'
|
|
|
|
import { useAppDispatch, useAppSelector } from '../hooks'
|
|
|
|
import { useGetGameInfoQuery, useLoadInventoryOverviewQuery, useLoadLevelQuery } from '../state/api'
|
|
|
|
import { useGetGameInfoQuery, useLoadInventoryOverviewQuery, useLoadLevelQuery } from '../state/api'
|
|
|
|
import { changedSelection, codeEdited, selectCode, selectSelections, selectCompleted, helpEdited,
|
|
|
|
import { changedSelection, codeEdited, selectCode, selectSelections, selectCompleted, helpEdited,
|
|
|
|
@ -44,6 +43,15 @@ import 'lean4web/client/src/editor/infoview.css'
|
|
|
|
import 'lean4web/client/src/editor/vscode.css'
|
|
|
|
import 'lean4web/client/src/editor/vscode.css'
|
|
|
|
import '../css/level.css'
|
|
|
|
import '../css/level.css'
|
|
|
|
import { LevelAppBar } from './app_bar'
|
|
|
|
import { LevelAppBar } from './app_bar'
|
|
|
|
|
|
|
|
import { LeanClient } from 'lean4web/client/src/editor/leanclient'
|
|
|
|
|
|
|
|
import { DisposingWebSocketMessageReader } from 'lean4web/client/src/reader'
|
|
|
|
|
|
|
|
import { WebSocketMessageWriter, toSocket } from 'vscode-ws-jsonrpc'
|
|
|
|
|
|
|
|
import { IConnectionProvider } from 'monaco-languageclient'
|
|
|
|
|
|
|
|
import { monacoSetup } from 'lean4web/client/src/monacoSetup'
|
|
|
|
|
|
|
|
import { onigasmH } from 'onigasm/lib/onigasmH'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
monacoSetup()
|
|
|
|
|
|
|
|
|
|
|
|
function Level() {
|
|
|
|
function Level() {
|
|
|
|
const params = useParams()
|
|
|
|
const params = useParams()
|
|
|
|
@ -293,11 +301,11 @@ function PlayableLevel({impressum, setImpressum}) {
|
|
|
|
// a hint at the beginning of the proof...
|
|
|
|
// a hint at the beginning of the proof...
|
|
|
|
const [selectedStep, setSelectedStep] = useState<number>()
|
|
|
|
const [selectedStep, setSelectedStep] = useState<number>()
|
|
|
|
|
|
|
|
|
|
|
|
// if the user inventory changes, notify the server
|
|
|
|
// TODO: if the user inventory changes, notify the server
|
|
|
|
useEffect(() => {
|
|
|
|
// useEffect(() => {
|
|
|
|
let leanClient = connection.getLeanClient(gameId)
|
|
|
|
// let leanClient = connection.getLeanClient(gameId)
|
|
|
|
leanClient.sendNotification('$/game/setInventory', {inventory: inventory, difficulty: difficulty})
|
|
|
|
// leanClient.sendNotification('$/game/setInventory', {inventory: inventory, difficulty: difficulty})
|
|
|
|
}, [inventory])
|
|
|
|
// }, [inventory])
|
|
|
|
|
|
|
|
|
|
|
|
useEffect (() => {
|
|
|
|
useEffect (() => {
|
|
|
|
// Lock editor mode
|
|
|
|
// Lock editor mode
|
|
|
|
@ -372,7 +380,7 @@ function PlayableLevel({impressum, setImpressum}) {
|
|
|
|
|
|
|
|
|
|
|
|
// Effect when command line mode gets enabled
|
|
|
|
// Effect when command line mode gets enabled
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
if (editor && typewriterMode) {
|
|
|
|
if (onigasmH && editor && typewriterMode) {
|
|
|
|
let code = editor.getModel().getLinesContent().filter(line => line.trim())
|
|
|
|
let code = editor.getModel().getLinesContent().filter(line => line.trim())
|
|
|
|
editor.executeEdits("typewriter", [{
|
|
|
|
editor.executeEdits("typewriter", [{
|
|
|
|
range: editor.getModel().getFullModelRange(),
|
|
|
|
range: editor.getModel().getFullModelRange(),
|
|
|
|
@ -395,7 +403,7 @@ function PlayableLevel({impressum, setImpressum}) {
|
|
|
|
// editor.setSelection(monaco.Selection.fromPositions(endPos, endPos))
|
|
|
|
// editor.setSelection(monaco.Selection.fromPositions(endPos, endPos))
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [editor, typewriterMode])
|
|
|
|
}, [editor, typewriterMode, onigasmH == null])
|
|
|
|
|
|
|
|
|
|
|
|
return <>
|
|
|
|
return <>
|
|
|
|
<div style={level.isLoading ? null : {display: "none"}} className="app-content loading"><CircularProgress /></div>
|
|
|
|
<div style={level.isLoading ? null : {display: "none"}} className="app-content loading"><CircularProgress /></div>
|
|
|
|
@ -531,21 +539,29 @@ function Introduction({impressum, setImpressum}) {
|
|
|
|
|
|
|
|
|
|
|
|
function useLevelEditor(codeviewRef, initialCode, initialSelections, onDidChangeContent, onDidChangeSelection) {
|
|
|
|
function useLevelEditor(codeviewRef, initialCode, initialSelections, onDidChangeContent, onDidChangeSelection) {
|
|
|
|
|
|
|
|
|
|
|
|
const connection = React.useContext(ConnectionContext)
|
|
|
|
|
|
|
|
const gameId = React.useContext(GameIdContext)
|
|
|
|
const gameId = React.useContext(GameIdContext)
|
|
|
|
const {worldId, levelId} = useContext(WorldLevelIdContext)
|
|
|
|
const {worldId, levelId} = useContext(WorldLevelIdContext)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor|null>(null)
|
|
|
|
const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor|null>(null)
|
|
|
|
const [infoProvider, setInfoProvider] = useState<null|InfoProvider>(null)
|
|
|
|
const [infoProvider, setInfoProvider] = useState<null|InfoProvider>(null)
|
|
|
|
const [infoviewApi, setInfoviewApi] = useState<null|InfoviewApi>(null)
|
|
|
|
|
|
|
|
const [editorConnection, setEditorConnection] = useState<null|EditorConnection>(null)
|
|
|
|
const [editorConnection, setEditorConnection] = useState<null|EditorConnection>(null)
|
|
|
|
|
|
|
|
|
|
|
|
// Create Editor
|
|
|
|
const uriStr = `file:///${worldId}/${levelId}`
|
|
|
|
|
|
|
|
const uri = monaco.Uri.parse(uriStr)
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
|
|
const model = monaco.editor.createModel(initialCode ?? '', 'lean4', uri)
|
|
|
|
|
|
|
|
if (onDidChangeContent) {
|
|
|
|
|
|
|
|
model.onDidChangeContent(() => onDidChangeContent(model.getValue()))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const editor = monaco.editor.create(codeviewRef.current!, {
|
|
|
|
const editor = monaco.editor.create(codeviewRef.current!, {
|
|
|
|
|
|
|
|
model,
|
|
|
|
glyphMargin: true,
|
|
|
|
glyphMargin: true,
|
|
|
|
quickSuggestions: false,
|
|
|
|
quickSuggestions: false,
|
|
|
|
|
|
|
|
lineDecorationsWidth: 5,
|
|
|
|
|
|
|
|
folding: false,
|
|
|
|
|
|
|
|
lineNumbers: 'on',
|
|
|
|
lightbulb: {
|
|
|
|
lightbulb: {
|
|
|
|
enabled: true
|
|
|
|
enabled: true
|
|
|
|
},
|
|
|
|
},
|
|
|
|
@ -557,11 +573,61 @@ function useLevelEditor(codeviewRef, initialCode, initialSelections, onDidChange
|
|
|
|
enabled: false
|
|
|
|
enabled: false
|
|
|
|
},
|
|
|
|
},
|
|
|
|
lineNumbersMinChars: 3,
|
|
|
|
lineNumbersMinChars: 3,
|
|
|
|
|
|
|
|
tabSize: 2,
|
|
|
|
'semanticHighlighting.enabled': true,
|
|
|
|
'semanticHighlighting.enabled': true,
|
|
|
|
theme: 'vs-code-theme-converted'
|
|
|
|
theme: 'vs-code-theme-converted'
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
if (onDidChangeSelection) {
|
|
|
|
|
|
|
|
editor.onDidChangeCursorSelection(() => onDidChangeSelection(editor.getSelections()))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (initialSelections) {
|
|
|
|
|
|
|
|
console.debug("Initial Selection: ", initialSelections)
|
|
|
|
|
|
|
|
// BUG: Somehow I get an `invalid arguments` bug here
|
|
|
|
|
|
|
|
// editor.setSelections(initialSelections)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
setEditor(editor)
|
|
|
|
|
|
|
|
const abbrevRewriter = new AbbreviationRewriter(new AbbreviationProvider(), model, editor)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const socketUrl = ((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + '/websocket/' + gameId
|
|
|
|
|
|
|
|
|
|
|
|
const infoProvider = new InfoProvider(connection.getLeanClient(gameId))
|
|
|
|
const connectionProvider : IConnectionProvider = {
|
|
|
|
|
|
|
|
get: async () => {
|
|
|
|
|
|
|
|
return await new Promise((resolve, reject) => {
|
|
|
|
|
|
|
|
console.log(`connecting ${socketUrl}`)
|
|
|
|
|
|
|
|
const websocket = new WebSocket(socketUrl)
|
|
|
|
|
|
|
|
websocket.addEventListener('error', (ev) => {
|
|
|
|
|
|
|
|
reject(ev)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
websocket.addEventListener('message', (msg) => {
|
|
|
|
|
|
|
|
// console.log(msg.data)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
websocket.addEventListener('open', () => {
|
|
|
|
|
|
|
|
const socket = toSocket(websocket)
|
|
|
|
|
|
|
|
const reader = new DisposingWebSocketMessageReader(socket)
|
|
|
|
|
|
|
|
const writer = new WebSocketMessageWriter(socket)
|
|
|
|
|
|
|
|
resolve({
|
|
|
|
|
|
|
|
reader,
|
|
|
|
|
|
|
|
writer
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Following `vscode-lean4/webview/index.ts`
|
|
|
|
|
|
|
|
const client = new LeanClient(connectionProvider, showRestartMessage)
|
|
|
|
|
|
|
|
const infoProvider = new InfoProvider(client)
|
|
|
|
|
|
|
|
// const div: HTMLElement = infoviewRef.current!
|
|
|
|
|
|
|
|
const imports = {
|
|
|
|
|
|
|
|
'@leanprover/infoview': `${window.location.origin}/index.production.min.js`,
|
|
|
|
|
|
|
|
'react': `${window.location.origin}/react.production.min.js`,
|
|
|
|
|
|
|
|
'react/jsx-runtime': `${window.location.origin}/react-jsx-runtime.production.min.js`,
|
|
|
|
|
|
|
|
'react-dom': `${window.location.origin}/react-dom.production.min.js`,
|
|
|
|
|
|
|
|
'react-popper': `${window.location.origin}/react-popper.production.min.js`
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadRenderInfoview(imports, [infoProvider.getApi(), div], setInfoviewApi)
|
|
|
|
|
|
|
|
setInfoProvider(infoProvider)
|
|
|
|
|
|
|
|
client.restart()
|
|
|
|
|
|
|
|
|
|
|
|
const editorApi = infoProvider.getApi()
|
|
|
|
const editorApi = infoProvider.getApi()
|
|
|
|
|
|
|
|
|
|
|
|
@ -606,54 +672,27 @@ function useLevelEditor(codeviewRef, initialCode, initialSelections, onDidChange
|
|
|
|
|
|
|
|
|
|
|
|
setEditor(editor)
|
|
|
|
setEditor(editor)
|
|
|
|
setInfoProvider(infoProvider)
|
|
|
|
setInfoProvider(infoProvider)
|
|
|
|
setInfoviewApi(infoviewApi)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return () => { infoProvider.dispose(); editor.dispose() }
|
|
|
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const {leanClient, leanClientStarted} = useLeanClient(gameId)
|
|
|
|
infoProvider.openPreview(editor, infoviewApi)
|
|
|
|
const uriStr = `file:///${worldId}/${levelId}`
|
|
|
|
const taskgutter = new LeanTaskGutter(infoProvider.client, editor)
|
|
|
|
const uri = monaco.Uri.parse(uriStr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create model when level changes
|
|
|
|
// TODO:
|
|
|
|
useEffect(() => {
|
|
|
|
// setRestart(() => restart)
|
|
|
|
if (editor && leanClientStarted) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let model = monaco.editor.getModel(uri)
|
|
|
|
|
|
|
|
if (!model) {
|
|
|
|
|
|
|
|
model = monaco.editor.createModel(initialCode, 'lean4', uri)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
model.onDidChangeContent(() => onDidChangeContent(model.getValue()))
|
|
|
|
|
|
|
|
editor.onDidChangeCursorSelection(() => onDidChangeSelection(editor.getSelections()))
|
|
|
|
|
|
|
|
editor.setModel(model)
|
|
|
|
|
|
|
|
if (initialSelections) {
|
|
|
|
|
|
|
|
console.debug("Initial Selection: ", initialSelections)
|
|
|
|
|
|
|
|
// BUG: Somehow I get an `invalid arguments` bug here
|
|
|
|
|
|
|
|
// editor.setSelections(initialSelections)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
return () => {
|
|
|
|
editorConnection.api.sendClientNotification(uriStr, "textDocument/didClose", {textDocument: {uri: uriStr}})
|
|
|
|
editor.dispose();
|
|
|
|
model.dispose();
|
|
|
|
model.dispose();
|
|
|
|
|
|
|
|
abbrevRewriter.dispose();
|
|
|
|
|
|
|
|
taskgutter.dispose();
|
|
|
|
|
|
|
|
infoProvider.dispose();
|
|
|
|
|
|
|
|
client.dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [gameId, worldId, levelId])
|
|
|
|
}, [editor, levelId, connection, leanClientStarted])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
|
|
if (editor && leanClientStarted) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let model = monaco.editor.getModel(uri)
|
|
|
|
|
|
|
|
infoviewApi.serverRestarted(leanClient.initializeResult)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
infoProvider.openPreview(editor, infoviewApi)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const taskGutter = new LeanTaskGutter(infoProvider.client, editor)
|
|
|
|
|
|
|
|
const abbrevRewriter = new AbbreviationRewriter(new AbbreviationProvider(), model, editor)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return () => { abbrevRewriter.dispose(); taskGutter.dispose(); }
|
|
|
|
const showRestartMessage = () => {
|
|
|
|
|
|
|
|
// setRestartMessage(true)
|
|
|
|
|
|
|
|
console.log("TODO: SHOW RESTART MESSAGE")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [editor, connection, leanClientStarted])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {editor, infoProvider, editorConnection}
|
|
|
|
return {editor, infoProvider, editorConnection}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|