/ concept-collection / numbl-web-ide
Sign in
concept-collection / numbl-web-ide
numbl-web-ide / src / ide.ts
98 lines · 3.3 KBBlameHistoryRaw
1import { attachGitHubSourceControl, createIndexedDBFileSystem, createWorkbench, transplantGitHubWorkspace, type Workbench, type WorkbenchTheme, type WorkspaceFileSystem } from 'minwebide';
2import { githubWorkspaceDbName } from './githubOpen';
3import { createMipSystem } from './numbl/mipSystem';
4import { createNumblRunner } from './numbl/runner';
5import { openProjectFileSystem, touchProject, type ProjectInfo } from './projects';
7export interface NumblWorkbench {
8 readonly workbench: Workbench;
9 dispose(): void;
12/**
13 * Assembles the numbl workbench (mip system + runner) on a file system.
14 * Shared by project IDEs and GitHub repo IDEs; does not own `fs` — the
15 * caller disposes it.
16 */
17export async function openNumblWorkbench(container: HTMLElement, fs: WorkspaceFileSystem, workspaceName: string, theme: WorkbenchTheme): Promise<NumblWorkbench> {
18 const mip = await createMipSystem();
19 // fetch/refresh mip core in the background; runs await it (and say so
20 // in the output channel if they actually have to wait)
21 void mip.ensureCore().catch(() => { /* retried on the next run */ });
23 const workbench = createWorkbench(container, {
24 fileSystem: fs,
25 theme,
26 workspaceName,
27 });
29 const numbl = createNumblRunner(fs, workbench, mip);
30 workbench.registerRunner(numbl.runner);
32 return {
33 workbench,
34 dispose() {
35 numbl.dispose();
36 workbench.dispose();
37 mip.dispose();
38 },
39 };
42/** Opens the most useful starting file, if any. */
43export async function openStartingFile(fs: WorkspaceFileSystem, workbench: Workbench): Promise<void> {
44 for (const path of ['/waves.m', '/main.m', '/README.md']) {
45 const uri = fs.root.with({ path });
46 if (await fs.fileService.exists(uri)) {
47 await workbench.openFile(uri);
48 return;
49 }
50 }
53/** Opens the IDE for a project. Returns a disposable view. */
54export async function openIde(container: HTMLElement, project: ProjectInfo, theme: WorkbenchTheme): Promise<{ dispose(): void }> {
55 touchProject(project.id);
56 document.title = `${project.name} — numbl web IDE`;
58 const fs = await openProjectFileSystem(project.id);
59 const ide = await openNumblWorkbench(container, fs, project.name, theme);
61 // the project indicator: click to go back to the project list
62 ide.workbench.statusBar.setItem('project', 'left', project.name, {
63 icon: 'folder-opened',
64 title: 'Back to projects',
65 onClick: () => { location.hash = '#/'; },
66 });
67 // replace the default branding item with the project indicator
68 ide.workbench.statusBar.removeItem('branding');
70 // source control: publish this project to a new GitHub repo, or — once
71 // published — track changes and push
72 const sourceControl = await attachGitHubSourceControl(ide.workbench, fs, {
73 appName: 'numbl web IDE',
74 defaultRepoName: project.name,
75 // after publishing, seed the repo's own workspace from the local copy
76 // (no re-download — the local state IS the pushed state) and make its
77 // route the canonical place to work
78 onPublished: async ({ owner, repo }) => {
79 const ghFs = await createIndexedDBFileSystem({ dbName: githubWorkspaceDbName({ owner, repo }) });
80 try {
81 await transplantGitHubWorkspace(fs, ghFs);
82 } finally {
83 ghFs.dispose();
84 }
85 location.hash = `#/github/${owner}/${repo}`;
86 },
87 });
89 await openStartingFile(fs, ide.workbench);
91 return {
92 dispose() {
93 sourceControl.dispose();
94 ide.dispose();
95 fs.dispose();
96 },
97 };
moveopenescclose