convert tabs to spaces

pull/43/head
Alexander Bentkamp 2 years ago
parent 054e28c1ec
commit d2fd1c5915

@ -16,67 +16,67 @@ import GoodBye from './components/GoodBye';
import useWebSocket from 'react-use-websocket'; import useWebSocket from 'react-use-websocket';
function App() { function App() {
const [title, setTitle] = useState("") const [title, setTitle] = useState("")
const [conclusion, setConclusion] = useState("") const [conclusion, setConclusion] = useState("")
const [levelTitle, setLevelTitle] = useState("") const [levelTitle, setLevelTitle] = useState("")
const [nbLevels, setNbLevels] = useState(0) const [nbLevels, setNbLevels] = useState(0)
const [curLevel, setCurLevel] = useState(0) const [curLevel, setCurLevel] = useState(0)
const [finished, setFinished] = useState(false) const [finished, setFinished] = useState(false)
const [rpcConnection, setRpcConnection] = useState<null|rpc.MessageConnection>(null) const [rpcConnection, setRpcConnection] = useState<null|rpc.MessageConnection>(null)
const socketUrl = 'ws://' + window.location.host + '/websocket/' const socketUrl = 'ws://' + window.location.host + '/websocket/'
useWebSocket(socketUrl, { useWebSocket(socketUrl, {
onOpen: function (ev) { onOpen: function (ev) {
const logger = new rpc.ConsoleLogger(); const logger = new rpc.ConsoleLogger();
const socket = rpc.toSocket(ev.target as WebSocket); const socket = rpc.toSocket(ev.target as WebSocket);
let rpcConnection = rpc.createWebSocketConnection(socket, logger) let rpcConnection = rpc.createWebSocketConnection(socket, logger)
setRpcConnection(rpcConnection); setRpcConnection(rpcConnection);
rpcConnection.listen(); rpcConnection.listen();
} }
}) })
const mathJaxConfig = { const mathJaxConfig = {
loader: { loader: {
load: ['input/tex-base', 'output/svg'] load: ['input/tex-base', 'output/svg']
}, },
tex: { tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']] inlineMath: [['$', '$'], ['\\(', '\\)']]
}, },
svg: { svg: {
fontCache: 'global' fontCache: 'global'
} }
} }
function startGame() { function startGame() {
setCurLevel(1) setCurLevel(1)
} }
let mainComponent; let mainComponent;
if (finished) { if (finished) {
mainComponent = <GoodBye message={conclusion} /> mainComponent = <GoodBye message={conclusion} />
} else if (curLevel > 0) { } else if (curLevel > 0) {
mainComponent = <Level rpcConnection={rpcConnection} nbLevels={nbLevels} level={curLevel} setCurLevel={setCurLevel} setLevelTitle={setLevelTitle} setFinished={setFinished}/> mainComponent = <Level rpcConnection={rpcConnection} nbLevels={nbLevels} level={curLevel} setCurLevel={setCurLevel} setLevelTitle={setLevelTitle} setFinished={setFinished}/>
} else { } else {
mainComponent = <Welcome rpcConnection={rpcConnection} setNbLevels={setNbLevels} setTitle={setTitle} startGame={startGame} setConclusion={setConclusion}/> mainComponent = <Welcome rpcConnection={rpcConnection} setNbLevels={setNbLevels} setTitle={setTitle} startGame={startGame} setConclusion={setConclusion}/>
} }
return ( return (
<div className="App"> <div className="App">
<MathJaxContext config={mathJaxConfig}> <MathJaxContext config={mathJaxConfig}>
<CssBaseline /> <CssBaseline />
<AppBar position="sticky" sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}> <AppBar position="sticky" sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}>
<Toolbar sx={{ justifyContent: "space-between" }}> <Toolbar sx={{ justifyContent: "space-between" }}>
<Typography variant="h6" noWrap component="div"> <Typography variant="h6" noWrap component="div">
{title} {title}
</Typography> </Typography>
<Typography variant="h6" noWrap component="div"> <Typography variant="h6" noWrap component="div">
{levelTitle} {levelTitle}
</Typography> </Typography>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
{mainComponent} {mainComponent}
</MathJaxContext> </MathJaxContext>
</div> </div>
) )
} }

@ -8,16 +8,16 @@ import { Box, Typography, Grid } from '@mui/material';
function GoodBye({ message }) { function GoodBye({ message }) {
return (<Grid container return (<Grid container
direction="row" direction="row"
justifyContent="center" justifyContent="center"
alignItems="center"> alignItems="center">
<Grid item xs={12} sm={6}> <Grid item xs={12} sm={6}>
<Box sx={{ m: 3 }}> <Box sx={{ m: 3 }}>
<Typography variant="body1" component="div">{message}</Typography> <Typography variant="body1" component="div">{message}</Typography>
</Box> </Box>
</Grid> </Grid>
</Grid>) </Grid>)
} }
export default GoodBye export default GoodBye

@ -12,72 +12,72 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
function TacticDoc(props) { function TacticDoc(props) {
return ( return (
<Accordion> <Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>{props.tactic.name}</Typography> <Typography>{props.tactic.name}</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<MathJax> <MathJax>
<ReactMarkdown>{props.tactic.content}</ReactMarkdown> <ReactMarkdown>{props.tactic.content}</ReactMarkdown>
</MathJax> </MathJax>
</AccordionDetails> </AccordionDetails>
</Accordion>) </Accordion>)
} }
function LemmaDoc({ lemma }) { function LemmaDoc({ lemma }) {
return ( return (
<Accordion> <Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>{lemma.userName}</Typography> <Typography>{lemma.userName}</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<MathJax> <MathJax>
<ReactMarkdown>{lemma.content}</ReactMarkdown> <ReactMarkdown>{lemma.content}</ReactMarkdown>
</MathJax> </MathJax>
</AccordionDetails> </AccordionDetails>
</Accordion>) </Accordion>)
} }
function LemmaDocs({ lemmas }) { function LemmaDocs({ lemmas }) {
const [categories, setCategories] = useState(new Map()) const [categories, setCategories] = useState(new Map())
const [curCategory, setCurCategory] = useState("") const [curCategory, setCurCategory] = useState("")
useEffect(() => { useEffect(() => {
const cats = new Map() const cats = new Map()
lemmas.forEach(function (item) { lemmas.forEach(function (item) {
const category = item.category const category = item.category
cats.set(category, (cats.get(category) || []).concat([item])) cats.set(category, (cats.get(category) || []).concat([item]))
}); });
setCategories(cats) setCategories(cats)
setCurCategory(cats.keys().next().value) setCurCategory(cats.keys().next().value)
}, [lemmas]); }, [lemmas]);
return ( return (
<Paper sx={{ px: 2, py: 1, mt: 2 }}> <Paper sx={{ px: 2, py: 1, mt: 2 }}>
<Typography variant="h5">Inventory</Typography> <Typography variant="h5">Inventory</Typography>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs <Tabs
value={curCategory} value={curCategory}
aria-label="Categories" variant="scrollable" scrollButtons="auto"> aria-label="Categories" variant="scrollable" scrollButtons="auto">
{(Array.from(categories)).map(([category, _]) => <Tab value={category} label={category} key={category} wrapped />)} {(Array.from(categories)).map(([category, _]) => <Tab value={category} label={category} key={category} wrapped />)}
</Tabs> </Tabs>
</Box> </Box>
{curCategory && categories.get(curCategory).map((lemma) => <LemmaDoc lemma={lemma} key={lemma.name} />)} {curCategory && categories.get(curCategory).map((lemma) => <LemmaDoc lemma={lemma} key={lemma.name} />)}
</Paper> </Paper>
) )
} }
function LeftPanel({ spells, inventory }) { function LeftPanel({ spells, inventory }) {
return ( return (
<Box> <Box>
{spells.length > 0 && {spells.length > 0 &&
<Paper sx={{ px: 2, py: 1 }}> <Paper sx={{ px: 2, py: 1 }}>
<Typography variant="h5" sx={{ mb: 2 }}>Spell book</Typography> <Typography variant="h5" sx={{ mb: 2 }}>Spell book</Typography>
{spells.map((spell) => <TacticDoc key={spell.name} tactic={spell} />)} {spells.map((spell) => <TacticDoc key={spell.name} tactic={spell} />)}
</Paper>} </Paper>}
{inventory.length > 0 && <LemmaDocs lemmas={inventory} />} {inventory.length > 0 && <LemmaDocs lemmas={inventory} />}
</Box>) </Box>)
} }
export default LeftPanel; export default LeftPanel;

@ -16,102 +16,102 @@ import * as rpc from 'vscode-ws-jsonrpc';
interface LevelProps { interface LevelProps {
rpcConnection: null|rpc.MessageConnection; rpcConnection: null|rpc.MessageConnection;
nbLevels: any; nbLevels: any;
level: any; level: any;
setCurLevel: any; setCurLevel: any;
setLevelTitle: any; setLevelTitle: any;
setFinished: any setFinished: any
} }
function Level({ rpcConnection, nbLevels, level, setCurLevel, setLevelTitle, setFinished }: LevelProps) { function Level({ rpcConnection, nbLevels, level, setCurLevel, setLevelTitle, setFinished }: LevelProps) {
const [index, setIndex] = useState(level) // Level number const [index, setIndex] = useState(level) // Level number
const [tacticDocs, setTacticDocs] = useState([]) const [tacticDocs, setTacticDocs] = useState([])
const [lemmaDocs, setLemmaDocs] = useState([]) const [lemmaDocs, setLemmaDocs] = useState([])
const [leanData, setLeanData] = useState({goals: []}) const [leanData, setLeanData] = useState({goals: []})
const [history, setHistory] = useState([]) const [history, setHistory] = useState([])
const [lastTactic, setLastTactic] = useState("") const [lastTactic, setLastTactic] = useState("")
const [errors, setErrors] = useState([]) const [errors, setErrors] = useState([])
const [message, setMessage] = useState("") const [message, setMessage] = useState("")
const [messageOpen, setMessageOpen] = useState(false) const [messageOpen, setMessageOpen] = useState(false)
const [completed, setCompleted] = useState(false) const [completed, setCompleted] = useState(false)
const processResponse = (res:any) => { const processResponse = (res:any) => {
setLeanData(res); setLeanData(res);
setErrors(res.errors); setErrors(res.errors);
if (res.message !== "" && res.errors?.length === 0) { if (res.message !== "" && res.errors?.length === 0) {
setMessage(res.message) setMessage(res.message)
setMessageOpen(true) setMessageOpen(true)
} }
if (res.goals?.length === 0 && res.errors?.length === 0) { if (res.goals?.length === 0 && res.errors?.length === 0) {
setCompleted(true) setCompleted(true)
} }
} }
// The next function will be called when the level changes // The next function will be called when the level changes
useEffect(() => { useEffect(() => {
if (rpcConnection) { if (rpcConnection) {
rpcConnection.sendRequest("loadLevel", {number: level}).then((res) => { rpcConnection.sendRequest("loadLevel", {number: level}).then((res) => {
setLevelTitle("Level " + res["index"] + ": " + res["title"]) setLevelTitle("Level " + res["index"] + ": " + res["title"])
setIndex(parseInt(res["index"])) setIndex(parseInt(res["index"]))
setTacticDocs(res["tactics"]) setTacticDocs(res["tactics"])
setLemmaDocs(res["lemmas"]) setLemmaDocs(res["lemmas"])
processResponse(res) processResponse(res)
}); });
} }
}, [level, rpcConnection]) }, [level, rpcConnection])
function sendTactic(input) { function sendTactic(input) {
rpcConnection.sendRequest("runTactic", {tactic: input}).then(processResponse); rpcConnection.sendRequest("runTactic", {tactic: input}).then(processResponse);
setLastTactic(input); setLastTactic(input);
setHistory(history.concat([input])); setHistory(history.concat([input]));
} }
function undo() { function undo() {
if (errors.length === 0) { if (errors.length === 0) {
rpcConnection.sendRequest('undo').then(processResponse); rpcConnection.sendRequest('undo').then(processResponse);
} }
if (history.length > 1) { if (history.length > 1) {
setLastTactic(history[history.length - 1]); setLastTactic(history[history.length - 1]);
} else { } else {
setLastTactic(""); setLastTactic("");
}; };
setErrors([]); setErrors([]);
setHistory(history.slice(0, -1)); setHistory(history.slice(0, -1));
} }
function loadNextLevel() { function loadNextLevel() {
setCompleted(false) setCompleted(false)
setHistory([]) setHistory([])
setCurLevel(index + 1) setCurLevel(index + 1)
} }
function closeMessage() { function closeMessage() {
setMessageOpen(false) setMessageOpen(false)
} }
function finishGame() { function finishGame() {
setLevelTitle("") setLevelTitle("")
setFinished(true) setFinished(true)
} }
return ( return (
<Grid container sx={{ mt: 3, ml: 1, mr: 1 }} columnSpacing={{ xs: 1, sm: 2, md: 3 }}> <Grid container sx={{ mt: 3, ml: 1, mr: 1 }} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid xs={4}> <Grid xs={4}>
<LeftPanel spells={tacticDocs} inventory={lemmaDocs} /> <LeftPanel spells={tacticDocs} inventory={lemmaDocs} />
</Grid> </Grid>
<Grid xs={4}> <Grid xs={4}>
<InputZone index={index} history={history} messageOpen={messageOpen} setMessageOpen={setMessageOpen} completed={completed} sendTactic={sendTactic} nbLevels={nbLevels} loadNextLevel={loadNextLevel} <InputZone index={index} history={history} messageOpen={messageOpen} setMessageOpen={setMessageOpen} completed={completed} sendTactic={sendTactic} nbLevels={nbLevels} loadNextLevel={loadNextLevel}
errors={errors} lastTactic={lastTactic} undo={undo} finishGame={finishGame} /> errors={errors} lastTactic={lastTactic} undo={undo} finishGame={finishGame} />
<Message isOpen={messageOpen} content={message} close={closeMessage} /> <Message isOpen={messageOpen} content={message} close={closeMessage} />
</Grid> </Grid>
<Grid xs={4}> <Grid xs={4}>
<TacticState goals={leanData.goals} errors={errors} lastTactic={lastTactic} completed={completed} /> <TacticState goals={leanData.goals} errors={errors} lastTactic={lastTactic} completed={completed} />
</Grid> </Grid>
</Grid> </Grid>
) )
} }
export default Level export default Level

@ -11,59 +11,59 @@ import { Paper, Box, Typography } from '@mui/material';
const errorRegex = /<stdin>:1:(?<col>[^:]*): (?<msg>.*)/; const errorRegex = /<stdin>:1:(?<col>[^:]*): (?<msg>.*)/;
function Goal({ goal }) { function Goal({ goal }) {
const hasObject = typeof goal.objects === "object" && goal.objects.length > 0 const hasObject = typeof goal.objects === "object" && goal.objects.length > 0
const hasAssumption = typeof goal.assumptions === "object" && goal.assumptions.length > 0 const hasAssumption = typeof goal.assumptions === "object" && goal.assumptions.length > 0
return ( return (
<Box sx={{ pl: 2 }}> <Box sx={{ pl: 2 }}>
{hasObject && <Box><Typography>Objects</Typography> {hasObject && <Box><Typography>Objects</Typography>
<List> <List>
{goal.objects.map((item) => {goal.objects.map((item) =>
<ListItem key={item[0]}> <ListItem key={item[0]}>
<Typography color="primary" sx={{ mr: 1 }}>{item[0]}</Typography> : <Typography color="primary" sx={{ mr: 1 }}>{item[0]}</Typography> :
<Typography color="secondary" sx={{ ml: 1 }}>{item[1]}</Typography> <Typography color="secondary" sx={{ ml: 1 }}>{item[1]}</Typography>
</ListItem>)} </ListItem>)}
</List></Box>} </List></Box>}
{hasAssumption && <Box><Typography>Assumptions</Typography> {hasAssumption && <Box><Typography>Assumptions</Typography>
<List> <List>
{goal.assumptions.map((item) => <ListItem key={item}><Typography color="primary" sx={{ mr: 1 }}>{item[0]}</Typography> : {goal.assumptions.map((item) => <ListItem key={item}><Typography color="primary" sx={{ mr: 1 }}>{item[0]}</Typography> :
<Typography color="secondary" sx={{ ml: 1 }}>{item[1]}</Typography></ListItem>)} <Typography color="secondary" sx={{ ml: 1 }}>{item[1]}</Typography></ListItem>)}
</List></Box>} </List></Box>}
<Typography>Prove:</Typography> <Typography>Prove:</Typography>
<Typography color="primary" sx={{ ml: 2 }}>{goal.goal}</Typography> <Typography color="primary" sx={{ ml: 2 }}>{goal.goal}</Typography>
</Box>) </Box>)
} }
function TacticState({ goals, errors, lastTactic, completed }) { function TacticState({ goals, errors, lastTactic, completed }) {
const hasError = typeof errors === "object" && errors.length > 0 const hasError = typeof errors === "object" && errors.length > 0
const hasGoal = typeof goals === "object" && goals.length > 0 const hasGoal = typeof goals === "object" && goals.length > 0
const hasManyGoal = hasGoal && goals.length > 1 const hasManyGoal = hasGoal && goals.length > 1
var col = "" var col = ""
var msg = "" var msg = ""
if (hasError) { if (hasError) {
const m = errors[0].match(errorRegex) const m = errors[0].match(errorRegex)
if (m) { if (m) {
col = `Column ${m.groups.col}: ` col = `Column ${m.groups.col}: `
msg = m.groups.msg msg = m.groups.msg
} else { } else {
msg = errors[0] msg = errors[0]
if (msg === "Unrecognized tactic") { msg = "Unknown spell!" } if (msg === "Unrecognized tactic") { msg = "Unknown spell!" }
} }
} }
return ( return (
<Box sx={{ height: "100%" }}> <Box sx={{ height: "100%" }}>
{hasGoal && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}><Typography variant="h5">Current goal</Typography> <Goal goal={goals[0]} /></Paper>} {hasGoal && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}><Typography variant="h5">Current goal</Typography> <Goal goal={goals[0]} /></Paper>}
{completed && <Typography variant="h6">Level completed ! 🎉</Typography>} {completed && <Typography variant="h6">Level completed ! 🎉</Typography>}
{hasError && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}><Typography variant="h5" color="error">Spell invocation failed</Typography> {hasError && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}><Typography variant="h5" color="error">Spell invocation failed</Typography>
<Typography sx={{ my: 1 }}>{lastTactic}</Typography> <Typography sx={{ my: 1 }}>{lastTactic}</Typography>
<Typography component="pre" sx={{ my: 1 }}>{col}{msg}</Typography> <Typography component="pre" sx={{ my: 1 }}>{col}{msg}</Typography>
<Typography>Use the undo button to go back to a sane state.</Typography> <Typography>Use the undo button to go back to a sane state.</Typography>
</Paper>} </Paper>}
{hasManyGoal && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, mt: 1 }}> {hasManyGoal && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, mt: 1 }}>
<Typography variant="h6" sx={{ mb: 2 }}>Other goals</Typography> <Typography variant="h6" sx={{ mb: 2 }}>Other goals</Typography>
{goals.slice(1).map((goal, index) => <Paper><Goal key={index} goal={goal} /></Paper>)} {goals.slice(1).map((goal, index) => <Paper><Goal key={index} goal={goal} /></Paper>)}
</Paper>} </Paper>}
</Box> </Box>
) )
} }
export default TacticState export default TacticState

@ -13,53 +13,53 @@ import { Box, Typography, Button, CircularProgress, Grid } from '@mui/material';
interface WelcomeProps { interface WelcomeProps {
rpcConnection: null|rpc.MessageConnection; rpcConnection: null|rpc.MessageConnection;
setNbLevels: any; setNbLevels: any;
setTitle: any; setTitle: any;
startGame: any; startGame: any;
setConclusion: any; setConclusion: any;
} }
type infoResultType = { type infoResultType = {
title: string, title: string,
nb_levels: any[], nb_levels: any[],
conclusion: string conclusion: string
} }
const infoRequestType = new rpc.RequestType0<infoResultType, void>("info") const infoRequestType = new rpc.RequestType0<infoResultType, void>("info")
function Welcome({ rpcConnection, setNbLevels, setTitle, startGame, setConclusion }: WelcomeProps) { function Welcome({ rpcConnection, setNbLevels, setTitle, startGame, setConclusion }: WelcomeProps) {
const [leanData, setLeanData] = useState<null|infoResultType>(null) const [leanData, setLeanData] = useState<null|infoResultType>(null)
useEffect(() => { useEffect(() => {
if (rpcConnection) { // Will run in the beginning as soon as RPC connection is established if (rpcConnection) { // Will run in the beginning as soon as RPC connection is established
rpcConnection.sendRequest(infoRequestType).then((res: infoResultType) =>{ rpcConnection.sendRequest(infoRequestType).then((res: infoResultType) =>{
setLeanData(res) setLeanData(res)
setNbLevels(res.nb_levels) setNbLevels(res.nb_levels)
setTitle(res.title) setTitle(res.title)
document.title = res.title document.title = res.title
setConclusion(res.conclusion) setConclusion(res.conclusion)
}); });
} }
}, [rpcConnection, setLeanData, setNbLevels, setTitle, setConclusion]) }, [rpcConnection, setLeanData, setNbLevels, setTitle, setConclusion])
let content let content
if (leanData) { if (leanData) {
content = (<Box sx={{ m: 3 }}> content = (<Box sx={{ m: 3 }}>
<Typography variant="body1" component="div"> <Typography variant="body1" component="div">
<MathJax> <MathJax>
<ReactMarkdown>{leanData["introduction"]}</ReactMarkdown> <ReactMarkdown>{leanData["introduction"]}</ReactMarkdown>
</MathJax> </MathJax>
</Typography> </Typography>
<Box textAlign='center' sx={{ m: 5 }}> <Box textAlign='center' sx={{ m: 5 }}>
<Button onClick={startGame} variant="contained">Start rescue mission</Button> <Button onClick={startGame} variant="contained">Start rescue mission</Button>
</Box> </Box>
</Box>) </Box>)
} else { } else {
content = <Box display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box> content = <Box display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
} }
return <Grid container direction="row" justifyContent="center" alignItems="center"> return <Grid container direction="row" justifyContent="center" alignItems="center">
<Grid item xs={12} sm={6}>{content}</Grid> <Grid item xs={12} sm={6}>{content}</Grid>
</Grid> </Grid>
} }
export default Welcome export default Welcome

Loading…
Cancel
Save