diff --git a/src/components/ide/Ide/Ide.js b/src/components/ide/Ide/Ide.js index bffe0112..52f98c52 100644 --- a/src/components/ide/Ide/Ide.js +++ b/src/components/ide/Ide/Ide.js @@ -57,6 +57,7 @@ import initHedgehogSdk from '../../../sdk/hedgehog'; import PluginManager from '../../../sdk/PluginManager'; import useProjectInfo from './projectInfo'; +import useProjectCache from './projectCache'; import usePersistentState from './persistentState'; import useLayoutModel from './layoutModel'; @@ -120,10 +121,13 @@ type Props = {| |}; function Ide({ projectName }: Props) { - const [projectInfo, refreshProject] = useProjectInfo(projectName); + const projectInfo = useProjectInfo(projectName); const [pluginsLoaded, setPluginsLoaded] = React.useState(false); const [runningTask, setRunningTask] = React.useState(null); + const [projectCache, refreshProject] = useProjectCache( + projectInfo && projectInfo.project, + ); const [state, dispatch] = usePersistentState( projectInfo && projectInfo.projectUid, ); @@ -148,7 +152,13 @@ function Ide({ projectName }: Props) { // TODO this has a potential race condition with the initialization // of executorRef.current. React.useEffect(() => { - if (projectInfo === null || layoutModel === null || pluginsLoaded) return; + if ( + projectInfo === null || + projectCache === null || + layoutModel === null || + pluginsLoaded + ) + return; (async () => { const pluginManager = new PluginManager( @@ -161,10 +171,10 @@ function Ide({ projectName }: Props) { pluginManagerRef.current = pluginManager; setPluginsLoaded(true); })(); - }, [projectInfo, layoutModel, pluginsLoaded]); + }, [projectInfo, projectCache, layoutModel, pluginsLoaded]); // load the project's simulator schema if it or the simulator changes - const simulatorXml = projectInfo && projectInfo.simulatorXml; + const simulatorXml = projectCache && projectCache.simulatorXml; function refreshSimulatorFromSchema( schema: SimulationSchema.SimulatorJson | null, @@ -198,7 +208,7 @@ function Ide({ projectName }: Props) { function getFile(path: string): FileReference { // eslint-disable-next-line no-throw-literal - if (projectInfo === null) throw 'unreachable'; + if (projectCache === null) throw 'unreachable'; const [_root, ...fragments] = path.split('/'); @@ -217,7 +227,7 @@ function Ide({ projectName }: Props) { return child; }; - const file = fragments.reduce(reducer, projectInfo.files); + const file = fragments.reduce(reducer, projectCache.files); return { path, file }; } @@ -535,9 +545,9 @@ function Ide({ projectName }: Props) { const path = file.path.split('/').slice(1, -1); // eslint-disable-next-line no-throw-literal - if (projectInfo === null) throw 'unreachable'; + if (projectCache === null) throw 'unreachable'; - const root = projectInfo.files; + const root = projectCache.files; // the project root is always a directory. assert and cast // eslint-disable-next-line no-throw-literal @@ -775,7 +785,8 @@ function Ide({ projectName }: Props) { useStyles(FlexLayoutTheme); const classes = useStylesMaterial(); - if (projectInfo === null || state === null) return null; + if (projectInfo === null || projectCache === null || state === null) + return null; const { fileTreeState, showMetadataFolder } = state; @@ -920,7 +931,7 @@ function Ide({ projectName }: Props) {
void] { + const [state, setState] = React.useState(null); + + function refreshProject() { + if (project === null) { + setState(null); + return; + } + + async function loadSimulatorXml(): Promise { + const absolutePath = project.resolve('./.metadata/simulator'); + try { + const workspaceXml = await fs.promises.readFile(absolutePath, 'utf8'); + if (workspaceXml === '') return null; + return workspaceXml; + } catch (ex) { + if (!(ex instanceof filer.Errors.ENOENT)) { + throw ex; + } + return null; + } + } + + (async () => { + // load project from the file system + const files = await project.getFiles(); + const simulatorXml = await loadSimulatorXml(); + + setState({ files, simulatorXml }); + })(); + } + + // refresh project when projectName changes + React.useEffect(() => { + refreshProject(); + }, [project]); + + return [state, refreshProject]; +} diff --git a/src/components/ide/Ide/projectInfo.js b/src/components/ide/Ide/projectInfo.js index 892e5553..89101ceb 100644 --- a/src/components/ide/Ide/projectInfo.js +++ b/src/components/ide/Ide/projectInfo.js @@ -2,55 +2,28 @@ import * as React from 'react'; -import filer, { fs } from 'filer'; - -import { - type FilerRecursiveStatInfo, - Project, -} from '../../../core/store/projects'; +import { Project } from '../../../core/store/projects'; type ProjectInfo = {| project: Project, - files: FilerRecursiveStatInfo, projectUid: string, - simulatorXml: string | null, |}; export default function useProjectInfo( projectName: string, -): [ProjectInfo | null, () => void] { +): ProjectInfo | null { const [state, setState] = React.useState(null); - function refreshProject() { - async function loadSimulatorXml(project: Project): Promise { - const absolutePath = project.resolve('./.metadata/simulator'); - try { - const workspaceXml = await fs.promises.readFile(absolutePath, 'utf8'); - if (workspaceXml === '') return null; - return workspaceXml; - } catch (ex) { - if (!(ex instanceof filer.Errors.ENOENT)) { - throw ex; - } - return null; - } - } - + // refresh project when projectName changes + React.useEffect(() => { (async () => { // load project from the file system const project = await Project.getProject(projectName); - const files = await project.getFiles(); const projectUid = await project.getUid(); - const simulatorXml = await loadSimulatorXml(project); - setState({ project, files, projectUid, simulatorXml }); + setState({ project, projectUid }); })(); - } - - // refresh project when projectName changes - React.useEffect(() => { - refreshProject(); }, [projectName]); - return [state, refreshProject]; + return state; }