pybricksMicropython: add support for peer file code completion

This allows importing user-created files and getting code completion
for those imports. This is done by mirroring the dexie-based file
system used by the editor to the emscripten based file system used
by pyodide. In the future, ideally we would have some sort of shared
file system, but this works for now.

Note: completing `from ` doesn't list user files/modules because of
filters in the pybricks-jedi python package but completing
`from my_file import ` does work as expected.
This commit is contained in:
David Lechner
2022-09-13 14:19:29 -05:00
parent be36e8e73a
commit 7e2404d583
3 changed files with 149 additions and 1 deletions
+17
View File
@@ -99,3 +99,20 @@ export const pythonMessageDidFailToGetSignature = createAction((error: Error) =>
type: 'python.message.didFailToGetSignature',
error,
}));
export const pythonMessageWriteUserFile = createAction(
(path: string, contents: string) => ({
type: 'python.message.writeUserFile',
path,
contents,
}),
);
export const pythonMessageDeleteUserFile = createAction((path: string) => ({
type: 'python.message.deleteUserFile',
path,
}));
export const pythonMessageDidMountUserFileSystem = createAction(() => ({
type: 'python.message.didMountUserFileSystem',
}));
+31
View File
@@ -11,15 +11,18 @@ import pyodidePackage from 'pyodide/package.json';
import { ensureError } from '../utils';
import {
pythonMessageComplete,
pythonMessageDeleteUserFile,
pythonMessageDidComplete,
pythonMessageDidFailToComplete,
pythonMessageDidFailToGetSignature,
pythonMessageDidFailToInit,
pythonMessageDidGetSignature,
pythonMessageDidInit,
pythonMessageDidMountUserFileSystem,
pythonMessageGetSignature,
pythonMessageInit,
pythonMessageSetInterruptBuffer,
pythonMessageWriteUserFile,
} from './python-message';
/**
@@ -61,6 +64,34 @@ async function init(): Promise<void> {
lockFileURL: new URL('pyodide/repodata.json', import.meta.url).toString(),
});
// REVISIT: it would be nice if we could make a custom driver to mount
// the custom Pybricks Code Dexie-based file system directly instead of
// mirroring it
const mountDir = '/user';
pyodide.FS.mkdir(mountDir);
pyodide.FS.mount(pyodide.FS.filesystems.MEMFS, { root: '.' }, mountDir);
self.addEventListener('message', async (e) => {
if (pythonMessageWriteUserFile.matches(e.data)) {
pyodide.FS.writeFile(`${mountDir}/${e.data.path}`, e.data.contents);
console.debug('copied', e.data.path, 'to emscripten fs');
return;
}
if (pythonMessageDeleteUserFile.matches(e.data)) {
pyodide.FS.unlink(`${mountDir}/${e.data.path}`);
console.debug('removed', e.data.path, ' from emscripten fs');
return;
}
});
// separate message for file system ready since it takes a long time for
// the rest of the init
self.postMessage(pythonMessageDidMountUserFileSystem());
// add user directory to sys.path for code completion
await pyodide.runPythonAsync(`import sys; sys.path.append("${mountDir}")`);
// NB: using URL+import.meta.url for webpack magic - don't try to optimize it
await pyodide.loadPackage(
new URL('@pybricks/jedi/docstring-parser.whl', import.meta.url).toString(),