This repository was archived by the owner on Apr 2, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 47
Refactor so that all vscode-specific infoview stuff is in vscode_info_server.ts
#204
Draft
EdAyers
wants to merge
9
commits into
leanprover:master
Choose a base branch
from
EdAyers:refactor
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 3 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
99e4e74
Refactor all vscode code in to one file
EdAyers 0fea8ec
Restrict the exports from ../src/shared
EdAyers 5be03b4
Add docstrings for the exported members of extension.ts
EdAyers db9655c
Make trythis code optional
EdAyers 677b3d2
Make Main.tsx lower case
EdAyers 0c82b1a
Encapsulate extension comms in InfoServer
EdAyers 6d2a555
Create InfoServer
EdAyers 9a551f6
Remove some obsolete includes from tsconfig
EdAyers 8a87f84
Refactor
EdAyers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| import { PositionEvent, ConfigEvent, SyncPinEvent, TogglePinEvent, currentConfig, globalCurrentLoc, | ||
| ToggleAllMessagesEvent, syncPin, ServerStatus, Location, Config, defaultConfig, currentAllMessages, | ||
| AllMessagesEvent, PinnedLocation, locationEq} from './extension'; | ||
| import * as React from 'react'; | ||
| import { Message } from 'lean-client-js-core'; | ||
| import { Info } from './info'; | ||
| import { Messages, processMessages, ProcessedMessage } from './messages'; | ||
| import { Details } from './collapsing'; | ||
| import { useEvent } from './util'; | ||
| import { ContinueIcon, PauseIcon } from './svg_icons'; | ||
| import './tachyons.css' // stylesheet assumed by Lean widgets. See https://tachyons.io/ for documentation | ||
| import './index.css' | ||
|
|
||
| export const ConfigContext = React.createContext<Config>(defaultConfig); | ||
| export const LocationContext = React.createContext<Location | null>(null); | ||
|
|
||
| function StatusView(props: ServerStatus) { | ||
| return <Details> | ||
| <summary className="mv2 pointer">Tasks</summary> | ||
| <p>Running: {props.isRunning}</p> | ||
| <table> <tbody> | ||
| <tr key="header"><th>File Name</th> | ||
| <th>Pos start</th> | ||
| <th>Pos end</th> | ||
| <th>Desc</th></tr> | ||
| {props.tasks.map(t => <tr key={`${t.file_name}:${t.pos_col}:${t.pos_line}:${t.desc}`}> | ||
| <td>{t.file_name}</td> | ||
| <td>{t.pos_line}:{t.pos_col}</td> | ||
| <td>{t.end_pos_line}:{t.end_pos_col}</td> | ||
| <td>{t.desc}</td> | ||
| </tr>)} | ||
| </tbody> | ||
| </table> | ||
| </Details> | ||
| } | ||
|
|
||
| interface InfoViewProps { | ||
| config?: Config; | ||
| messages: Message[]; | ||
| curLoc?: Location; | ||
| } | ||
|
|
||
| export function InfoView(props: InfoViewProps) { | ||
| if (!props) { return null } | ||
| const {config, curLoc, messages} = props; | ||
| if (!curLoc) return <p>Click somewhere in the Lean file to enable the info view.</p>; | ||
| const allMessages = processMessages(messages.filter((m) => curLoc && m.file_name === curLoc.file_name)); | ||
| return <div className="ma1"> | ||
| <ConfigContext.Provider value={config}> | ||
| <Infos curLoc={curLoc}/> | ||
| <div className="mv2"><AllMessages allMessages={allMessages}/></div> | ||
| </ConfigContext.Provider> | ||
| </div> | ||
| } | ||
|
|
||
| export function Main(props: {}) { | ||
| const [config, setConfig] = React.useState(currentConfig); | ||
| useEvent(ConfigEvent, (cfg) => setConfig(cfg), []); | ||
|
|
||
| const [messages, setMessages] = React.useState<Message[]>(currentAllMessages); | ||
| useEvent(AllMessagesEvent, (msgs) => setMessages(msgs), []); | ||
|
|
||
| const [curLoc, setCurLoc] = React.useState<Location>(globalCurrentLoc); | ||
| useEvent(PositionEvent, (loc) => setCurLoc(loc), []); | ||
|
|
||
| return <InfoView {...{config, messages, curLoc}}/>; | ||
| } | ||
|
|
||
| interface InfosProps { | ||
| curLoc: Location; | ||
| } | ||
|
|
||
| function Infos(props: InfosProps): JSX.Element { | ||
| const {curLoc} = props; | ||
| useEvent(SyncPinEvent, (syncMsg) => setPinnedLocs(syncMsg.pins), []); | ||
| useEvent(TogglePinEvent, () => isPinned(curLoc) ? unpin()() : pin()); | ||
| const [pinnedLocs, setPinnedLocs] = React.useState<PinnedLocation[]>([]); | ||
| const isPinned = (loc: Location) => pinnedLocs.some((l) => locationEq(l, loc)); | ||
| const pinKey = React.useRef<number>(0); | ||
| const pin = () => { | ||
| if (isPinned(curLoc)) {return; } | ||
| pinKey.current += 1; | ||
| const pins = [...pinnedLocs, { ...curLoc, key: pinKey.current }]; | ||
| setPinnedLocs(pins); | ||
| syncPin(pins); | ||
| } | ||
| const unpin = (key?: number) => () => { | ||
| if (key === undefined) { | ||
| const pinned = pinnedLocs.find(p => locationEq(p, curLoc)); | ||
| if (pinned) { | ||
| key = pinned.key; | ||
| } else { | ||
| return; | ||
| } | ||
| } | ||
| const pins = pinnedLocs.filter((l) => l.key !== key); | ||
| setPinnedLocs(pins); | ||
| syncPin(pins); | ||
| } | ||
| return <> | ||
| <div> | ||
| {pinnedLocs.map((loc) => | ||
| <Info key={loc.key} loc={loc} isPinned={true} isCursor={false} onPin={unpin(loc.key)}/>)} | ||
| </div> | ||
| <Info loc={curLoc} isPinned={false} isCursor={true} onPin={pin}/> | ||
| </>; | ||
| } | ||
|
|
||
| function usePaused<T>(isPaused: boolean, t: T): T { | ||
| const old = React.useRef<T>(t); | ||
| if (!isPaused) old.current = t; | ||
| return old.current; | ||
| } | ||
|
|
||
| function AllMessages({allMessages: allMessages0}: {allMessages: ProcessedMessage[]}): JSX.Element { | ||
| const config = React.useContext(ConfigContext); | ||
| const [isPaused, setPaused] = React.useState<boolean>(false); | ||
| const allMessages = usePaused(isPaused, allMessages0); | ||
| const setOpenRef = React.useRef<React.Dispatch<React.SetStateAction<boolean>>>(); | ||
| useEvent(ToggleAllMessagesEvent, () => setOpenRef.current((t) => !t)); | ||
| return <Details setOpenRef={setOpenRef} initiallyOpen={!config.infoViewAutoOpenShowGoal}> | ||
| <summary> | ||
| All Messages ({allMessages.length}) | ||
| <span className="fr"> | ||
| <a className="link pointer mh2 dim" | ||
| onClick={e => { e.preventDefault(); setPaused(!isPaused)}} | ||
| title={isPaused ? 'continue updating' : 'pause updating'}> | ||
| {isPaused ? <ContinueIcon/> : <PauseIcon/>} | ||
| </a> | ||
| </span> | ||
| </summary> | ||
| <div className="ml1"> <Messages messages={allMessages}/> </div> | ||
| </Details>; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,118 +1,6 @@ | ||
| import { post, PositionEvent, ConfigEvent, SyncPinEvent, TogglePinEvent, AllMessagesEvent, currentAllMessages, currentConfig, globalCurrentLoc, ToggleAllMessagesEvent } from './server'; | ||
| import * as React from 'react'; | ||
| import * as ReactDOM from 'react-dom'; | ||
| import { ServerStatus, Config, defaultConfig, Location, locationEq, PinnedLocation } from '../src/shared'; | ||
| import { Message } from 'lean-client-js-core'; | ||
| import './tachyons.css' // stylesheet assumed by Lean widgets. See https://tachyons.io/ for documentation | ||
| import './index.css' | ||
| import { Info } from './info'; | ||
| import { Messages, processMessages, ProcessedMessage } from './messages'; | ||
| import { Details } from './collapsing'; | ||
| import { useEvent } from './util'; | ||
| import { ContinueIcon, PauseIcon } from './svg_icons'; | ||
| import { Main } from './Main'; | ||
|
|
||
| export const ConfigContext = React.createContext<Config>(defaultConfig); | ||
| export const LocationContext = React.createContext<Location | null>(null); | ||
|
|
||
| function StatusView(props: ServerStatus) { | ||
| return <Details> | ||
| <summary className="mv2 pointer">Tasks</summary> | ||
| <p>Running: {props.isRunning}</p> | ||
| <table> <tbody> | ||
| <tr key="header"><th>File Name</th> | ||
| <th>Pos start</th> | ||
| <th>Pos end</th> | ||
| <th>Desc</th></tr> | ||
| {props.tasks.map(t => <tr key={`${t.file_name}:${t.pos_col}:${t.pos_line}:${t.desc}`}> | ||
| <td>{t.file_name}</td> | ||
| <td>{t.pos_line}:{t.pos_col}</td> | ||
| <td>{t.end_pos_line}:{t.end_pos_col}</td> | ||
| <td>{t.desc}</td> | ||
| </tr>)} | ||
| </tbody> | ||
| </table> | ||
| </Details> | ||
| } | ||
|
|
||
| function Main(props: {}) { | ||
| if (!props) { return null } | ||
| const [config, setConfig] = React.useState(currentConfig); | ||
| const [messages, setMessages] = React.useState<Message[]>(currentAllMessages); | ||
| const [curLoc, setCurLoc] = React.useState<Location>(globalCurrentLoc); | ||
| useEvent(AllMessagesEvent, (msgs) => setMessages(msgs), []); | ||
| useEvent(PositionEvent, (loc) => setCurLoc(loc), []); | ||
| useEvent(ConfigEvent, (cfg) => setConfig(cfg), []); | ||
| if (!curLoc) return <p>Click somewhere in the Lean file to enable the info view.</p>; | ||
| const allMessages = processMessages(messages.filter((m) => curLoc && m.file_name === curLoc.file_name)); | ||
| return <div className="ma1"> | ||
| <ConfigContext.Provider value={config}> | ||
| <Infos curLoc={curLoc}/> | ||
| <div className="mv2"><AllMessages allMessages={allMessages}/></div> | ||
| </ConfigContext.Provider> | ||
| </div> | ||
| } | ||
|
|
||
| function Infos({curLoc}: {curLoc: Location}): JSX.Element { | ||
| useEvent(SyncPinEvent, (syncMsg) => setPinnedLocs(syncMsg.pins), []); | ||
| useEvent(TogglePinEvent, () => isPinned(curLoc) ? unpin()() : pin()); | ||
| const [pinnedLocs, setPinnedLocs] = React.useState<PinnedLocation[]>([]); | ||
| const isPinned = (loc: Location) => pinnedLocs.some((l) => locationEq(l, loc)); | ||
| const pinKey = React.useRef<number>(0); | ||
| const pin = () => { | ||
| if (isPinned(curLoc)) {return; } | ||
| pinKey.current += 1; | ||
| const pins = [...pinnedLocs, { ...curLoc, key: pinKey.current }]; | ||
| setPinnedLocs(pins); | ||
| post({command:'sync_pin', pins}); | ||
| } | ||
| const unpin = (key?: number) => () => { | ||
| if (key === undefined) { | ||
| const pinned = pinnedLocs.find(p => locationEq(p, curLoc)); | ||
| if (pinned) { | ||
| key = pinned.key; | ||
| } else { | ||
| return; | ||
| } | ||
| } | ||
| const pins = pinnedLocs.filter((l) => l.key !== key); | ||
| setPinnedLocs(pins); | ||
| post({command:'sync_pin', pins}); | ||
| } | ||
| return <> | ||
| <div> | ||
| {pinnedLocs.map((loc) => | ||
| <Info key={loc.key} loc={loc} isPinned={true} isCursor={false} onPin={unpin(loc.key)}/>)} | ||
| </div> | ||
| <Info loc={curLoc} isPinned={false} isCursor={true} onPin={pin}/> | ||
| </>; | ||
| } | ||
|
|
||
| function usePaused<T>(isPaused: boolean, t: T): T { | ||
| const old = React.useRef<T>(t); | ||
| if (!isPaused) old.current = t; | ||
| return old.current; | ||
| } | ||
|
|
||
| function AllMessages({allMessages: allMessages0}: {allMessages: ProcessedMessage[]}): JSX.Element { | ||
| const config = React.useContext(ConfigContext); | ||
| const [isPaused, setPaused] = React.useState<boolean>(false); | ||
| const allMessages = usePaused(isPaused, allMessages0); | ||
| const setOpenRef = React.useRef<React.Dispatch<React.SetStateAction<boolean>>>(); | ||
| useEvent(ToggleAllMessagesEvent, () => setOpenRef.current((t) => !t)); | ||
| return <Details setOpenRef={setOpenRef} initiallyOpen={!config.infoViewAutoOpenShowGoal}> | ||
| <summary> | ||
| All Messages ({allMessages.length}) | ||
| <span className="fr"> | ||
| <a className="link pointer mh2 dim" | ||
| onClick={e => { e.preventDefault(); setPaused(!isPaused)}} | ||
| title={isPaused ? 'continue updating' : 'pause updating'}> | ||
| {isPaused ? <ContinueIcon/> : <PauseIcon/>} | ||
| </a> | ||
| </span> | ||
| </summary> | ||
| <div className="ml1"> <Messages messages={allMessages}/> </div> | ||
| </Details>; | ||
| } | ||
|
|
||
| const domContainer = document.querySelector('#react_root'); | ||
| const domContainer = document.querySelector('#infoview_root'); | ||
| ReactDOM.render(<Main/>, domContainer); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.