|
|
|
@ -1,54 +1,50 @@
|
|
|
|
/* Mostly copied from https://github.com/leanprover/vscode-lean4/blob/master/lean4-infoview/src/infoview/info.tsx */
|
|
|
|
/* Mostly copied from https://github.com/leanprover/vscode-lean4/blob/master/lean4-infoview/src/infoview/info.tsx */
|
|
|
|
|
|
|
|
|
|
|
|
import * as React from 'react';
|
|
|
|
import * as React from 'react'
|
|
|
|
import { CircularProgress } from '@mui/material';
|
|
|
|
import { CircularProgress } from '@mui/material'
|
|
|
|
|
|
|
|
import type { Location, Diagnostic } from 'vscode-languageserver-protocol'
|
|
|
|
|
|
|
|
import { getInteractiveTermGoal, InteractiveDiagnostic, UserWidgetInstance, Widget_getWidgets, RpcSessionAtPos, isRpcError,
|
|
|
|
import type { Location, Diagnostic } from 'vscode-languageserver-protocol';
|
|
|
|
RpcErrorCode, getInteractiveDiagnostics, InteractiveTermGoal } from '@leanprover/infoview-api'
|
|
|
|
|
|
|
|
|
|
|
|
import { getInteractiveTermGoal, InteractiveDiagnostic,
|
|
|
|
|
|
|
|
UserWidgetInstance, Widget_getWidgets, RpcSessionAtPos, isRpcError,
|
|
|
|
|
|
|
|
RpcErrorCode, getInteractiveDiagnostics, InteractiveTermGoal } from '@leanprover/infoview-api';
|
|
|
|
|
|
|
|
import { basename, DocumentPosition, RangeHelpers, useEvent, usePausableState, discardMethodNotFound,
|
|
|
|
import { basename, DocumentPosition, RangeHelpers, useEvent, usePausableState, discardMethodNotFound,
|
|
|
|
mapRpcError, useAsyncWithTrigger, PausableProps } from '../../../../node_modules/lean4-infoview/src/infoview/util';
|
|
|
|
mapRpcError, useAsyncWithTrigger, PausableProps } from '../../../../node_modules/lean4-infoview/src/infoview/util'
|
|
|
|
import { ConfigContext, EditorContext, LspDiagnosticsContext, ProgressContext } from '../../../../node_modules/lean4-infoview/src/infoview/contexts';
|
|
|
|
import { ConfigContext, EditorContext, LspDiagnosticsContext, ProgressContext } from '../../../../node_modules/lean4-infoview/src/infoview/contexts'
|
|
|
|
import { PanelWidgetDisplay } from '../../../../node_modules/lean4-infoview/src/infoview/userWidget'
|
|
|
|
import { PanelWidgetDisplay } from '../../../../node_modules/lean4-infoview/src/infoview/userWidget'
|
|
|
|
import { RpcContext, useRpcSessionAtPos } from '../../../../node_modules/lean4-infoview/src/infoview/rpcSessions';
|
|
|
|
import { RpcContext, useRpcSessionAtPos } from '../../../../node_modules/lean4-infoview/src/infoview/rpcSessions'
|
|
|
|
import { GoalsLocation, Locations, LocationsContext } from '../../../../node_modules/lean4-infoview/src/infoview/goalLocation';
|
|
|
|
import { GoalsLocation, Locations, LocationsContext } from '../../../../node_modules/lean4-infoview/src/infoview/goalLocation'
|
|
|
|
|
|
|
|
|
|
|
|
import { AllMessages, lspDiagToInteractive, MessagesList } from './messages';
|
|
|
|
import { AllMessages, lspDiagToInteractive } from './messages'
|
|
|
|
import { goalsToString, Goal, MainAssumptions, OtherGoals, FilteredGoals, ProofDisplay } from './goals'
|
|
|
|
import { goalsToString, Goal, MainAssumptions, OtherGoals, ProofDisplay } from './goals'
|
|
|
|
import { InteractiveGoal, InteractiveGoals } from './rpc_api';
|
|
|
|
import { InteractiveGoals } from './rpc_api'
|
|
|
|
import { InputModeContext, MonacoEditorContext, HintContext, ProofStateProps, InfoStatus, ProofStateContext } from './context'
|
|
|
|
import { MonacoEditorContext, ProofStateProps, InfoStatus, ProofContext } from './context'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: All about pinning could probably be removed
|
|
|
|
type InfoKind = 'cursor' | 'pin';
|
|
|
|
type InfoKind = 'cursor' | 'pin'
|
|
|
|
|
|
|
|
|
|
|
|
interface InfoPinnable {
|
|
|
|
interface InfoPinnable {
|
|
|
|
kind: InfoKind;
|
|
|
|
kind: InfoKind
|
|
|
|
/** Takes an argument for caching reasons, but should only ever (un)pin itself. */
|
|
|
|
/** Takes an argument for caching reasons, but should only ever (un)pin itself. */
|
|
|
|
onPin: (pos: DocumentPosition) => void;
|
|
|
|
onPin: (pos: DocumentPosition) => void
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface InfoStatusBarProps extends InfoPinnable, PausableProps {
|
|
|
|
interface InfoStatusBarProps extends InfoPinnable, PausableProps {
|
|
|
|
pos: DocumentPosition;
|
|
|
|
pos: DocumentPosition
|
|
|
|
status: InfoStatus;
|
|
|
|
status: InfoStatus
|
|
|
|
triggerUpdate: () => Promise<void>;
|
|
|
|
triggerUpdate: () => Promise<void>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const InfoStatusBar = React.memo((props: InfoStatusBarProps) => {
|
|
|
|
const InfoStatusBar = React.memo((props: InfoStatusBarProps) => {
|
|
|
|
const { kind, onPin, status, pos, isPaused, setPaused, triggerUpdate } = props;
|
|
|
|
const { kind, onPin, status, pos, isPaused, setPaused, triggerUpdate } = props
|
|
|
|
|
|
|
|
|
|
|
|
const ec = React.useContext(EditorContext);
|
|
|
|
const ec = React.useContext(EditorContext)
|
|
|
|
|
|
|
|
|
|
|
|
const statusColTable: {[T in InfoStatus]: string} = {
|
|
|
|
const statusColTable: {[T in InfoStatus]: string} = {
|
|
|
|
'updating': 'gold ',
|
|
|
|
'updating': 'gold ',
|
|
|
|
'error': 'dark-red ',
|
|
|
|
'error': 'dark-red ',
|
|
|
|
'ready': '',
|
|
|
|
'ready': '',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const statusColor = statusColTable[status];
|
|
|
|
const statusColor = statusColTable[status]
|
|
|
|
const locationString = `${basename(pos.uri)}:${pos.line+1}:${pos.character}`;
|
|
|
|
const locationString = `${basename(pos.uri)}:${pos.line+1}:${pos.character}`
|
|
|
|
const isPinned = kind === 'pin';
|
|
|
|
const isPinned = kind === 'pin'
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<summary style={{transition: 'color 0.5s ease'}} className={'mv2 pointer ' + statusColor}>
|
|
|
|
<summary style={{transition: 'color 0.5s ease'}} className={'mv2 pointer ' + statusColor}>
|
|
|
|
@ -68,36 +64,36 @@ const InfoStatusBar = React.memo((props: InfoStatusBarProps) => {
|
|
|
|
title={isPinned ? 'unpin' : 'pin'} />
|
|
|
|
title={isPinned ? 'unpin' : 'pin'} />
|
|
|
|
<a className={'link pointer mh2 dim codicon ' + (isPaused ? 'codicon-debug-continue ' : 'codicon-debug-pause ')}
|
|
|
|
<a className={'link pointer mh2 dim codicon ' + (isPaused ? 'codicon-debug-continue ' : 'codicon-debug-pause ')}
|
|
|
|
data-id='toggle-paused'
|
|
|
|
data-id='toggle-paused'
|
|
|
|
onClick={e => { e.preventDefault(); setPaused(!isPaused); }}
|
|
|
|
onClick={e => { e.preventDefault(); setPaused(!isPaused) }}
|
|
|
|
title={isPaused ? 'continue updating' : 'pause updating'} />
|
|
|
|
title={isPaused ? 'continue updating' : 'pause updating'} />
|
|
|
|
<a className='link pointer mh2 dim codicon codicon-refresh'
|
|
|
|
<a className='link pointer mh2 dim codicon codicon-refresh'
|
|
|
|
data-id='update'
|
|
|
|
data-id='update'
|
|
|
|
onClick={e => { e.preventDefault(); void triggerUpdate(); }}
|
|
|
|
onClick={e => { e.preventDefault(); void triggerUpdate() }}
|
|
|
|
title='update'/>
|
|
|
|
title='update'/>
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
</summary>
|
|
|
|
</summary>
|
|
|
|
);
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
interface InfoDisplayContentProps extends PausableProps {
|
|
|
|
interface InfoDisplayContentProps extends PausableProps {
|
|
|
|
pos: DocumentPosition;
|
|
|
|
pos: DocumentPosition
|
|
|
|
messages: InteractiveDiagnostic[];
|
|
|
|
messages: InteractiveDiagnostic[]
|
|
|
|
goals?: InteractiveGoals;
|
|
|
|
goals?: InteractiveGoals
|
|
|
|
termGoal?: InteractiveTermGoal;
|
|
|
|
termGoal?: InteractiveTermGoal
|
|
|
|
error?: string;
|
|
|
|
error?: string
|
|
|
|
userWidgets: UserWidgetInstance[];
|
|
|
|
userWidgets: UserWidgetInstance[]
|
|
|
|
triggerUpdate: () => Promise<void>;
|
|
|
|
triggerUpdate: () => Promise<void>
|
|
|
|
proof? : string;
|
|
|
|
proof? : string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => {
|
|
|
|
const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => {
|
|
|
|
const {pos, messages, goals, termGoal, error, userWidgets, triggerUpdate, isPaused, setPaused, proof} = props;
|
|
|
|
const {pos, messages, goals, termGoal, error, userWidgets, triggerUpdate, isPaused, setPaused, proof} = props
|
|
|
|
|
|
|
|
|
|
|
|
const hasWidget = userWidgets.length > 0;
|
|
|
|
const hasWidget = userWidgets.length > 0
|
|
|
|
const hasError = !!error;
|
|
|
|
const hasError = !!error
|
|
|
|
const hasMessages = messages.length !== 0;
|
|
|
|
const hasMessages = messages.length !== 0
|
|
|
|
|
|
|
|
|
|
|
|
const nothingToShow = !hasError && !goals && !termGoal && !hasMessages && !hasWidget;
|
|
|
|
const nothingToShow = !hasError && !goals && !termGoal && !hasMessages && !hasWidget
|
|
|
|
|
|
|
|
|
|
|
|
const [selectedLocs, setSelectedLocs] = React.useState<GoalsLocation[]>([])
|
|
|
|
const [selectedLocs, setSelectedLocs] = React.useState<GoalsLocation[]>([])
|
|
|
|
React.useEffect(() => setSelectedLocs([]), [pos.uri, pos.line, pos.character])
|
|
|
|
React.useEffect(() => setSelectedLocs([]), [pos.uri, pos.line, pos.character])
|
|
|
|
@ -122,12 +118,13 @@ const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => {
|
|
|
|
{hasError &&
|
|
|
|
{hasError &&
|
|
|
|
<div className='error' key='errors'>
|
|
|
|
<div className='error' key='errors'>
|
|
|
|
Error updating:{' '}{error}.
|
|
|
|
Error updating:{' '}{error}.
|
|
|
|
<a className='link pointer dim' onClick={e => { e.preventDefault(); void triggerUpdate(); }}>{' '}Try again.</a>
|
|
|
|
<a className='link pointer dim' onClick={e => { e.preventDefault(); void triggerUpdate() }}>{' '}Try again.</a>
|
|
|
|
</div>}
|
|
|
|
</div>}
|
|
|
|
<LocationsContext.Provider value={locs}>
|
|
|
|
<LocationsContext.Provider value={locs}>
|
|
|
|
<div className="goals-section">
|
|
|
|
<div className="goals-section">
|
|
|
|
{ goals && goals.goals.length > 0 && <>
|
|
|
|
{ goals && goals.goals.length > 0 && <>
|
|
|
|
<MainAssumptions filter={goalFilter} key='mainGoal' goals={goals.goals} />
|
|
|
|
<MainAssumptions filter={goalFilter} key='mainGoal' goals={goals.goals} />
|
|
|
|
|
|
|
|
<ProofDisplay proof={proof}/>
|
|
|
|
<OtherGoals filter={goalFilter} goals={goals.goals} />
|
|
|
|
<OtherGoals filter={goalFilter} goals={goals.goals} />
|
|
|
|
</>}
|
|
|
|
</>}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@ -149,8 +146,8 @@ const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => {
|
|
|
|
isPaused ?
|
|
|
|
isPaused ?
|
|
|
|
/* Adding {' '} to manage string literals properly: https://reactjs.org/docs/jsx-in-depth.html#string-literals-1 */
|
|
|
|
/* Adding {' '} to manage string literals properly: https://reactjs.org/docs/jsx-in-depth.html#string-literals-1 */
|
|
|
|
<span>Updating is paused.{' '}
|
|
|
|
<span>Updating is paused.{' '}
|
|
|
|
<a className='link pointer dim' onClick={e => { e.preventDefault(); void triggerUpdate(); }}>Refresh</a>
|
|
|
|
<a className='link pointer dim' onClick={e => { e.preventDefault(); void triggerUpdate() }}>Refresh</a>
|
|
|
|
{' '}or <a className='link pointer dim' onClick={e => { e.preventDefault(); setPaused(false); }}>resume updating</a>
|
|
|
|
{' '}or <a className='link pointer dim' onClick={e => { e.preventDefault(); setPaused(false) }}>resume updating</a>
|
|
|
|
{' '}to see information.
|
|
|
|
{' '}to see information.
|
|
|
|
</span> :
|
|
|
|
</span> :
|
|
|
|
<><CircularProgress /><div>Loading goal...</div></>)}
|
|
|
|
<><CircularProgress /><div>Loading goal...</div></>)}
|
|
|
|
@ -167,44 +164,49 @@ const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
interface InfoDisplayProps {
|
|
|
|
interface InfoDisplayProps {
|
|
|
|
pos: DocumentPosition;
|
|
|
|
pos: DocumentPosition,
|
|
|
|
userWidgets: UserWidgetInstance[];
|
|
|
|
status: InfoStatus,
|
|
|
|
rpcSess: RpcSessionAtPos;
|
|
|
|
messages: InteractiveDiagnostic[],
|
|
|
|
triggerUpdate: () => Promise<void>;
|
|
|
|
goals?: InteractiveGoals,
|
|
|
|
|
|
|
|
termGoal?: InteractiveTermGoal,
|
|
|
|
|
|
|
|
error?: string,
|
|
|
|
|
|
|
|
userWidgets: UserWidgetInstance[],
|
|
|
|
|
|
|
|
rpcSess: RpcSessionAtPos,
|
|
|
|
|
|
|
|
triggerUpdate: () => Promise<void>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Displays goal state and messages. Can be paused. */
|
|
|
|
/** Displays goal state and messages. Can be paused. */
|
|
|
|
function InfoDisplay(props0: ProofStateProps & InfoDisplayProps & InfoPinnable) {
|
|
|
|
function InfoDisplay(props0: ProofStateProps & InfoDisplayProps & InfoPinnable) {
|
|
|
|
// Used to update the paused state *just once* if it is paused,
|
|
|
|
// Used to update the paused state *just once* if it is paused,
|
|
|
|
// but a display update is triggered
|
|
|
|
// but a display update is triggered
|
|
|
|
const [shouldRefresh, setShouldRefresh] = React.useState<boolean>(false);
|
|
|
|
const [shouldRefresh, setShouldRefresh] = React.useState<boolean>(false)
|
|
|
|
const [{ isPaused, setPaused }, props, propsRef] = usePausableState(false, props0);
|
|
|
|
const [{ isPaused, setPaused }, props, propsRef] = usePausableState(false, props0)
|
|
|
|
if (shouldRefresh) {
|
|
|
|
if (shouldRefresh) {
|
|
|
|
propsRef.current = props0;
|
|
|
|
propsRef.current = props0
|
|
|
|
setShouldRefresh(false);
|
|
|
|
setShouldRefresh(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const triggerDisplayUpdate = async () => {
|
|
|
|
const triggerDisplayUpdate = async () => {
|
|
|
|
await props0.triggerUpdate();
|
|
|
|
await props0.triggerUpdate()
|
|
|
|
setShouldRefresh(true);
|
|
|
|
setShouldRefresh(true)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const {kind, goals, rpcSess} = props;
|
|
|
|
const {kind, goals, rpcSess} = props
|
|
|
|
|
|
|
|
|
|
|
|
const ec = React.useContext(EditorContext);
|
|
|
|
const ec = React.useContext(EditorContext)
|
|
|
|
|
|
|
|
|
|
|
|
// If we are the cursor infoview, then we should subscribe to
|
|
|
|
// If we are the cursor infoview, then we should subscribe to
|
|
|
|
// some commands from the editor extension
|
|
|
|
// some commands from the editor extension
|
|
|
|
const isCursor = kind === 'cursor';
|
|
|
|
const isCursor = kind === 'cursor'
|
|
|
|
useEvent(ec.events.requestedAction, act => {
|
|
|
|
useEvent(ec.events.requestedAction, act => {
|
|
|
|
if (!isCursor) return;
|
|
|
|
if (!isCursor) return
|
|
|
|
if (act.kind !== 'copyToComment') return;
|
|
|
|
if (act.kind !== 'copyToComment') return
|
|
|
|
if (goals) void ec.copyToComment(goalsToString(goals));
|
|
|
|
if (goals) void ec.copyToComment(goalsToString(goals))
|
|
|
|
}, [goals]);
|
|
|
|
}, [goals])
|
|
|
|
useEvent(ec.events.requestedAction, act => {
|
|
|
|
useEvent(ec.events.requestedAction, act => {
|
|
|
|
if (!isCursor) return;
|
|
|
|
if (!isCursor) return
|
|
|
|
if (act.kind !== 'togglePaused') return;
|
|
|
|
if (act.kind !== 'togglePaused') return
|
|
|
|
setPaused(isPaused => !isPaused);
|
|
|
|
setPaused(isPaused => !isPaused)
|
|
|
|
});
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const editor = React.useContext(MonacoEditorContext)
|
|
|
|
const editor = React.useContext(MonacoEditorContext)
|
|
|
|
|
|
|
|
|
|
|
|
@ -217,7 +219,7 @@ function InfoDisplay(props0: ProofStateProps & InfoDisplayProps & InfoPinnable)
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{/* </details> */}
|
|
|
|
{/* </details> */}
|
|
|
|
</RpcContext.Provider>
|
|
|
|
</RpcContext.Provider>
|
|
|
|
);
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
@ -225,7 +227,7 @@ function InfoDisplay(props0: ProofStateProps & InfoDisplayProps & InfoPinnable)
|
|
|
|
* to avoid flickering when the cursor moved. Otherwise, the component is re-initialised and the
|
|
|
|
* to avoid flickering when the cursor moved. Otherwise, the component is re-initialised and the
|
|
|
|
* goal states reset to `undefined` on cursor moves.
|
|
|
|
* goal states reset to `undefined` on cursor moves.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export type InfoProps = InfoPinnable & { pos?: DocumentPosition };
|
|
|
|
export type InfoProps = InfoPinnable & { pos?: DocumentPosition }
|
|
|
|
|
|
|
|
|
|
|
|
/** Fetches info from the server and renders an {@link InfoDisplay}. */
|
|
|
|
/** Fetches info from the server and renders an {@link InfoDisplay}. */
|
|
|
|
export function Info(props: InfoProps) {
|
|
|
|
export function Info(props: InfoProps) {
|
|
|
|
@ -234,28 +236,24 @@ export function Info(props: InfoProps) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function InfoAtCursor(props: InfoProps) {
|
|
|
|
function InfoAtCursor(props: InfoProps) {
|
|
|
|
const ec = React.useContext(EditorContext);
|
|
|
|
const ec = React.useContext(EditorContext)
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
|
|
const [curLoc, setCurLoc] = React.useState<Location>(ec.events.changedCursorLocation.current!);
|
|
|
|
const [curLoc, setCurLoc] = React.useState<Location>(ec.events.changedCursorLocation.current!)
|
|
|
|
useEvent(ec.events.changedCursorLocation, loc => loc && setCurLoc(loc), []);
|
|
|
|
useEvent(ec.events.changedCursorLocation, loc => loc && setCurLoc(loc), [])
|
|
|
|
const pos = { uri: curLoc.uri, ...curLoc.range.start };
|
|
|
|
const pos = { uri: curLoc.uri, ...curLoc.range.start }
|
|
|
|
return <InfoAux {...props} pos={pos} />
|
|
|
|
return <InfoAux {...props} pos={pos} />
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function useIsProcessingAt(p: DocumentPosition): boolean {
|
|
|
|
function useIsProcessingAt(p: DocumentPosition): boolean {
|
|
|
|
const allProgress = React.useContext(ProgressContext);
|
|
|
|
const allProgress = React.useContext(ProgressContext)
|
|
|
|
const processing = allProgress.get(p.uri);
|
|
|
|
const processing = allProgress.get(p.uri)
|
|
|
|
if (!processing) return false;
|
|
|
|
if (!processing) return false
|
|
|
|
return processing.some(i => RangeHelpers.contains(i.range, p));
|
|
|
|
return processing.some(i => RangeHelpers.contains(i.range, p))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function InfoAux(props: InfoProps) {
|
|
|
|
function InfoAux(props: InfoProps) {
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: proofStateContext is not quite implemented correctly yet.
|
|
|
|
const proofContext = React.useContext(ProofContext)
|
|
|
|
// i.e. there is an asynchronous state in this file that seems to partally overlap
|
|
|
|
|
|
|
|
// search for `const [state, triggerUpdateCore]`
|
|
|
|
|
|
|
|
const hintContext = React.useContext(HintContext)
|
|
|
|
|
|
|
|
const proofStateContext = React.useContext(ProofStateContext)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const config = React.useContext(ConfigContext)
|
|
|
|
const config = React.useContext(ConfigContext)
|
|
|
|
|
|
|
|
|
|
|
|
@ -291,9 +289,9 @@ function InfoAux(props: InfoProps) {
|
|
|
|
// Besides what the server replies with, we also include the inputs (deps) in this type so
|
|
|
|
// Besides what the server replies with, we also include the inputs (deps) in this type so
|
|
|
|
// that the displayed state cannot ever get out of sync by showing an old reply together
|
|
|
|
// that the displayed state cannot ever get out of sync by showing an old reply together
|
|
|
|
// with e.g. a new `pos`.
|
|
|
|
// with e.g. a new `pos`.
|
|
|
|
type InfoRequestResult = Omit<ProofStateProps & InfoDisplayProps, 'triggerUpdate'>
|
|
|
|
type InfoRequestResult = Omit<InfoDisplayProps, 'triggerUpdate'>
|
|
|
|
const [state, triggerUpdateCore] = useAsyncWithTrigger(() => new Promise<InfoRequestResult>((resolve, reject) => {
|
|
|
|
const [state, triggerUpdateCore] = useAsyncWithTrigger(() => new Promise<InfoRequestResult>((resolve, reject) => {
|
|
|
|
const goalsReq = rpcSess.call('Game.getInteractiveGoals', DocumentPosition.toTdpp(pos));
|
|
|
|
const goalsReq = rpcSess.call('Game.getInteractiveGoals', DocumentPosition.toTdpp(pos))
|
|
|
|
const termGoalReq = getInteractiveTermGoal(rpcSess, DocumentPosition.toTdpp(pos))
|
|
|
|
const termGoalReq = getInteractiveTermGoal(rpcSess, DocumentPosition.toTdpp(pos))
|
|
|
|
const widgetsReq = Widget_getWidgets(rpcSess, pos).catch(discardMethodNotFound)
|
|
|
|
const widgetsReq = Widget_getWidgets(rpcSess, pos).catch(discardMethodNotFound)
|
|
|
|
const messagesReq = getInteractiveDiagnostics(rpcSess, {start: pos.line, end: pos.line+1})
|
|
|
|
const messagesReq = getInteractiveDiagnostics(rpcSess, {start: pos.line, end: pos.line+1})
|
|
|
|
@ -390,6 +388,11 @@ function InfoAux(props: InfoProps) {
|
|
|
|
|
|
|
|
|
|
|
|
const [displayProps, setDisplayProps] = React.useState<InfoDisplayProps>({
|
|
|
|
const [displayProps, setDisplayProps] = React.useState<InfoDisplayProps>({
|
|
|
|
pos,
|
|
|
|
pos,
|
|
|
|
|
|
|
|
status: 'updating',
|
|
|
|
|
|
|
|
messages: [],
|
|
|
|
|
|
|
|
goals: undefined,
|
|
|
|
|
|
|
|
termGoal: undefined,
|
|
|
|
|
|
|
|
error: undefined,
|
|
|
|
userWidgets: [],
|
|
|
|
userWidgets: [],
|
|
|
|
rpcSess,
|
|
|
|
rpcSess,
|
|
|
|
triggerUpdate
|
|
|
|
triggerUpdate
|
|
|
|
@ -403,14 +406,12 @@ function InfoAux(props: InfoProps) {
|
|
|
|
if (state.state === 'notStarted')
|
|
|
|
if (state.state === 'notStarted')
|
|
|
|
void triggerUpdate()
|
|
|
|
void triggerUpdate()
|
|
|
|
else if (state.state === 'loading') {
|
|
|
|
else if (state.state === 'loading') {
|
|
|
|
proofStateContext.setProofState(dp => ({ ...dp, status: 'updating' }))
|
|
|
|
|
|
|
|
setDisplayProps(dp => ({ ...dp, status: 'updating' }))
|
|
|
|
setDisplayProps(dp => ({ ...dp, status: 'updating' }))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (state.state === 'resolved') {
|
|
|
|
else if (state.state === 'resolved') {
|
|
|
|
// if (state.value.goals?.goals?.length) {
|
|
|
|
// if (state.value.goals?.goals?.length) {
|
|
|
|
// hintContext.setHints(state.value.goals.goals[0].hints)
|
|
|
|
// hintContext.setHints(state.value.goals.goals[0].hints)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
proofStateContext.setProofState({ ...state.value })
|
|
|
|
|
|
|
|
setDisplayProps({ ...state.value, triggerUpdate })
|
|
|
|
setDisplayProps({ ...state.value, triggerUpdate })
|
|
|
|
} else if (state.state === 'rejected' && state.error !== 'retry') {
|
|
|
|
} else if (state.state === 'rejected' && state.error !== 'retry') {
|
|
|
|
// The code inside `useAsyncWithTrigger` may only ever reject with a `retry` exception.
|
|
|
|
// The code inside `useAsyncWithTrigger` may only ever reject with a `retry` exception.
|
|
|
|
@ -418,5 +419,5 @@ function InfoAux(props: InfoProps) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [state])
|
|
|
|
}, [state])
|
|
|
|
|
|
|
|
|
|
|
|
return <InfoDisplay kind={props.kind} onPin={props.onPin} {...proofStateContext.proofState} {...displayProps} />
|
|
|
|
return <InfoDisplay kind={props.kind} onPin={props.onPin} {...displayProps} />
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|