keep deleted chat messages around until command is entered
This commit is contained in:
@@ -25,3 +25,21 @@ export function Hints({hints, showHidden, step, selected, toggleSelection} : {hi
|
|||||||
{showHidden && hiddenHints.map((hint, j) => <HiddenHint key={`hidden-hint-${step}-${j}`} hint={hint} step={step} selected={selected} toggleSelection={toggleSelection}/>)}
|
{showHidden && hiddenHints.map((hint, j) => <HiddenHint key={`hidden-hint-${step}-${j}`} hint={hint} step={step} selected={selected} toggleSelection={toggleSelection}/>)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function DeletedHint({hint} : {hint: GameHint}) {
|
||||||
|
return <div className="message information deleted-hint">
|
||||||
|
<Markdown>{hint.text}</Markdown>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DeletedHints({hints, showHidden} : {hints: GameHint[], showHidden: boolean}) {
|
||||||
|
|
||||||
|
const openHints = hints.filter(hint => !hint.hidden)
|
||||||
|
const hiddenHints = hints.filter(hint => hint.hidden)
|
||||||
|
|
||||||
|
// TODO: Should not use index as key.
|
||||||
|
return <>
|
||||||
|
{openHints.map((hint, i) => <DeletedHint key={`deleted-hint-${i}`} hint={hint} />)}
|
||||||
|
{showHidden && hiddenHints.map((hint, i) => <DeletedHint key={`deleted-hidden-hint-${i}`} hint={hint}/>)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { InteractiveDiagnostic, getInteractiveDiagnostics } from '@leanprover/in
|
|||||||
import { Diagnostic } from 'vscode-languageserver-types';
|
import { Diagnostic } from 'vscode-languageserver-types';
|
||||||
import { DocumentPosition } from '../../../../node_modules/lean4-infoview/src/infoview/util';
|
import { DocumentPosition } from '../../../../node_modules/lean4-infoview/src/infoview/util';
|
||||||
import { useRpcSessionAtPos } from '../../../../node_modules/lean4-infoview/src/infoview/rpcSessions';
|
import { useRpcSessionAtPos } from '../../../../node_modules/lean4-infoview/src/infoview/rpcSessions';
|
||||||
import { InputModeContext, MonacoEditorContext, ProofContext, ProofStep } from './context'
|
import { DeletedChatContext, InputModeContext, MonacoEditorContext, ProofContext, ProofStep } from './context'
|
||||||
import { goalsToString } from './goals'
|
import { goalsToString } from './goals'
|
||||||
import { InteractiveGoals } from './rpc_api'
|
import { InteractiveGoals } from './rpc_api'
|
||||||
|
|
||||||
@@ -81,6 +81,9 @@ export function CommandLine({proofPanelRef}: {proofPanelRef: React.MutableRefObj
|
|||||||
// The context storing all information about the current proof
|
// The context storing all information about the current proof
|
||||||
const {proof, setProof} = React.useContext(ProofContext)
|
const {proof, setProof} = React.useContext(ProofContext)
|
||||||
|
|
||||||
|
// state to store the last batch of deleted messages
|
||||||
|
const {setDeletedChat} = React.useContext(DeletedChatContext)
|
||||||
|
|
||||||
// TODO: does the position matter at all?
|
// TODO: does the position matter at all?
|
||||||
const rpcSess = useRpcSessionAtPos({uri: uri, line: 1, character: 1})
|
const rpcSess = useRpcSessionAtPos({uri: uri, line: 1, character: 1})
|
||||||
|
|
||||||
@@ -184,6 +187,10 @@ export function CommandLine({proofPanelRef}: {proofPanelRef: React.MutableRefObj
|
|||||||
// Run the command
|
// Run the command
|
||||||
const runCommand = React.useCallback(() => {
|
const runCommand = React.useCallback(() => {
|
||||||
if (processing) {return}
|
if (processing) {return}
|
||||||
|
|
||||||
|
// TODO: Desired logic is to only reset this after a new *error-free* command has been entered
|
||||||
|
setDeletedChat([])
|
||||||
|
|
||||||
const pos = editor.getPosition()
|
const pos = editor.getPosition()
|
||||||
if (commandLineInput) {
|
if (commandLineInput) {
|
||||||
setProcessing(true)
|
setProcessing(true)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'
|
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'
|
||||||
import { InteractiveDiagnostic, InteractiveTermGoal } from '@leanprover/infoview-api';
|
import { InteractiveDiagnostic, InteractiveTermGoal } from '@leanprover/infoview-api';
|
||||||
import { InteractiveGoal, InteractiveGoals } from './rpc_api';
|
import { GameHint, InteractiveGoal, InteractiveGoals } from './rpc_api';
|
||||||
|
|
||||||
export const MonacoEditorContext = React.createContext<monaco.editor.IStandaloneCodeEditor>(
|
export const MonacoEditorContext = React.createContext<monaco.editor.IStandaloneCodeEditor>(
|
||||||
null as any)
|
null as any)
|
||||||
@@ -18,7 +18,7 @@ export type ProofStep = {
|
|||||||
/** List of goals *after* this command */
|
/** List of goals *after* this command */
|
||||||
goals: InteractiveGoal[] // TODO: Add correct type
|
goals: InteractiveGoal[] // TODO: Add correct type
|
||||||
/** Story relevant messages */
|
/** Story relevant messages */
|
||||||
hints: any // TODO: Add correct type
|
hints: GameHint[] // TODO: Add correct type
|
||||||
/** Errors and warnings */
|
/** Errors and warnings */
|
||||||
errors: InteractiveDiagnostic[] // TODO: Add correct type
|
errors: InteractiveDiagnostic[] // TODO: Add correct type
|
||||||
}
|
}
|
||||||
@@ -71,6 +71,14 @@ export const SelectionContext = React.createContext<{
|
|||||||
setSelectedStep: () => {}
|
setSelectedStep: () => {}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** Context for deleted Hints that are visible just a bit after they've been deleted */
|
||||||
|
export const DeletedChatContext = React.createContext<{
|
||||||
|
deletedChat : GameHint[],
|
||||||
|
setDeletedChat: React.Dispatch<React.SetStateAction<Array<GameHint>>>
|
||||||
|
}>({
|
||||||
|
deletedChat: undefined,
|
||||||
|
setDeletedChat: () => {}
|
||||||
|
})
|
||||||
|
|
||||||
export const InputModeContext = React.createContext<{
|
export const InputModeContext = React.createContext<{
|
||||||
commandLineMode: boolean,
|
commandLineMode: boolean,
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
background-color: #FFBABA;
|
background-color: #FFBABA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message.deleted-hint {
|
||||||
|
background-color: #eee;
|
||||||
|
color: #777;
|
||||||
|
box-shadow: .0em .0em .5em .2em #eee;
|
||||||
|
}
|
||||||
|
|
||||||
.hyp-group {
|
.hyp-group {
|
||||||
margin-bottom: 0.3em;
|
margin-bottom: 0.3em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ import Markdown from '../markdown';
|
|||||||
import { Infos } from './infos';
|
import { Infos } from './infos';
|
||||||
import { AllMessages, Errors, WithLspDiagnosticsContext } from './messages';
|
import { AllMessages, Errors, WithLspDiagnosticsContext } from './messages';
|
||||||
import { Goal } from './goals';
|
import { Goal } from './goals';
|
||||||
import { InputModeContext, MonacoEditorContext, ProofContext, ProofStep, SelectionContext } from './context';
|
import { DeletedChatContext, InputModeContext, MonacoEditorContext, ProofContext, ProofStep, SelectionContext } from './context';
|
||||||
import { CommandLine, hasErrors, hasInteractiveErrors } from './command_line';
|
import { CommandLine, hasErrors, hasInteractiveErrors } from './command_line';
|
||||||
import { InteractiveDiagnostic } from '@leanprover/infoview/*';
|
import { InteractiveDiagnostic } from '@leanprover/infoview/*';
|
||||||
import { Button } from '../button';
|
import { Button } from '../button';
|
||||||
import { CircularProgress } from '@mui/material';
|
import { CircularProgress } from '@mui/material';
|
||||||
|
import { GameHint } from './rpc_api';
|
||||||
|
|
||||||
/** Wrapper for the two editors. It is important that the `div` with `codeViewRef` is
|
/** Wrapper for the two editors. It is important that the `div` with `codeViewRef` is
|
||||||
* always present, or the monaco editor cannot start.
|
* always present, or the monaco editor cannot start.
|
||||||
@@ -275,6 +276,7 @@ export function CommandLineInterface(props: {world: string, level: number, data:
|
|||||||
const gameId = React.useContext(GameIdContext)
|
const gameId = React.useContext(GameIdContext)
|
||||||
const {proof} = React.useContext(ProofContext)
|
const {proof} = React.useContext(ProofContext)
|
||||||
const {selectedStep, setSelectedStep} = React.useContext(SelectionContext)
|
const {selectedStep, setSelectedStep} = React.useContext(SelectionContext)
|
||||||
|
const {setDeletedChat} = React.useContext(DeletedChatContext)
|
||||||
|
|
||||||
const proofPanelRef = React.useRef<HTMLDivElement>(null)
|
const proofPanelRef = React.useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
@@ -302,6 +304,12 @@ export function CommandLineInterface(props: {world: string, level: number, data:
|
|||||||
*/
|
*/
|
||||||
function deleteProof(line: number) {
|
function deleteProof(line: number) {
|
||||||
return (ev) => {
|
return (ev) => {
|
||||||
|
let deletedChat: Array<GameHint> = []
|
||||||
|
proof.slice(line).map(step => {
|
||||||
|
deletedChat = [...deletedChat, ...step.hints]
|
||||||
|
})
|
||||||
|
setDeletedChat(deletedChat)
|
||||||
|
|
||||||
editor.executeEdits("command-line", [{
|
editor.executeEdits("command-line", [{
|
||||||
range: monaco.Selection.fromPositions(
|
range: monaco.Selection.fromPositions(
|
||||||
{lineNumber: line, column: 1},
|
{lineNumber: line, column: 1},
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ import {Inventory, Documentation} from './inventory';
|
|||||||
import { useGetGameInfoQuery, useLoadLevelQuery } from '../state/api';
|
import { useGetGameInfoQuery, useLoadLevelQuery } from '../state/api';
|
||||||
import { changedSelection, codeEdited, selectCode, selectSelections, progressSlice, selectCompleted } from '../state/progress';
|
import { changedSelection, codeEdited, selectCode, selectSelections, progressSlice, selectCompleted } from '../state/progress';
|
||||||
import { DualEditor } from './infoview/main'
|
import { DualEditor } from './infoview/main'
|
||||||
import { Hints } from './hints';
|
import { DeletedHint, DeletedHints, Hints } from './hints';
|
||||||
import { InputModeContext, MonacoEditorContext, ProofContext, ProofStep, SelectionContext } from './infoview/context';
|
import { DeletedChatContext, InputModeContext, MonacoEditorContext, ProofContext, ProofStep, SelectionContext } from './infoview/context';
|
||||||
import { hasInteractiveErrors } from './infoview/command_line';
|
import { hasInteractiveErrors } from './infoview/command_line';
|
||||||
|
import { GameHint } from './infoview/rpc_api';
|
||||||
|
|
||||||
function Level() {
|
function Level() {
|
||||||
|
|
||||||
@@ -67,6 +68,10 @@ function PlayableLevel({worldId, levelId}) {
|
|||||||
// The state variables for the `ProofContext`
|
// The state variables for the `ProofContext`
|
||||||
const [proof, setProof] = useState<Array<ProofStep>>([])
|
const [proof, setProof] = useState<Array<ProofStep>>([])
|
||||||
|
|
||||||
|
// When deleting the proof, we want to keep to old messages around until
|
||||||
|
// a new proof has been entered. e.g. to consult messages coming from dead ends
|
||||||
|
const [deletedChat, setDeletedChat] = useState<Array<GameHint>>([])
|
||||||
|
|
||||||
const initialCode = useAppSelector(selectCode(gameId, worldId, levelId))
|
const initialCode = useAppSelector(selectCode(gameId, worldId, levelId))
|
||||||
const initialSelections = useAppSelector(selectSelections(gameId, worldId, levelId))
|
const initialSelections = useAppSelector(selectSelections(gameId, worldId, levelId))
|
||||||
|
|
||||||
@@ -216,6 +221,7 @@ function PlayableLevel({worldId, levelId}) {
|
|||||||
|
|
||||||
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>
|
||||||
|
<DeletedChatContext.Provider value={{deletedChat, setDeletedChat}}>
|
||||||
<SelectionContext.Provider value={{selectedStep, setSelectedStep}}>
|
<SelectionContext.Provider value={{selectedStep, setSelectedStep}}>
|
||||||
<InputModeContext.Provider value={{commandLineMode, setCommandLineMode, commandLineInput, setCommandLineInput}}>
|
<InputModeContext.Provider value={{commandLineMode, setCommandLineMode, commandLineInput, setCommandLineInput}}>
|
||||||
<ProofContext.Provider value={{proof, setProof}}>
|
<ProofContext.Provider value={{proof, setProof}}>
|
||||||
@@ -238,6 +244,7 @@ function PlayableLevel({worldId, levelId}) {
|
|||||||
selected={selectedStep} toggleSelection={toggleSelection(i)}/>
|
selected={selectedStep} toggleSelection={toggleSelection(i)}/>
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
<DeletedHints hints={deletedChat} showHidden={showHiddenHints}/>
|
||||||
{completed &&
|
{completed &&
|
||||||
<>
|
<>
|
||||||
<div className={`message information step-${k}${selectedStep == k ? ' selected' : ''}`} onClick={toggleSelection(k)}>
|
<div className={`message information step-${k}${selectedStep == k ? ' selected' : ''}`} onClick={toggleSelection(k)}>
|
||||||
@@ -284,6 +291,7 @@ function PlayableLevel({worldId, levelId}) {
|
|||||||
</ProofContext.Provider>
|
</ProofContext.Provider>
|
||||||
</InputModeContext.Provider>
|
</InputModeContext.Provider>
|
||||||
</SelectionContext.Provider>
|
</SelectionContext.Provider>
|
||||||
|
</DeletedChatContext.Provider>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user