Skip to content

Commit

Permalink
mpy/alerts: implement compiler error
Browse files Browse the repository at this point in the history
This shows the output from mpy-cross and has a button to go to the
error.
  • Loading branch information
dlech committed Oct 19, 2022
1 parent e5ab52b commit 7e726ff
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import alerts from './alerts/alerts';
import ble from './ble/alerts';
import explorer from './explorer/alerts';
import firmware from './firmware/alerts';
import mpy from './mpy/alerts';
import type { CreateToast } from './toasterTypes';

/** This collects alerts from all of the subsystems of the app */
Expand All @@ -14,6 +15,7 @@ const alertDomains = {
ble,
explorer,
firmware,
mpy,
};

/** Gets the type of available alert domains. */
Expand Down
9 changes: 9 additions & 0 deletions src/editor/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,12 @@ export const editorDidFailToActivateFile = createAction((uuid: UUID, error: Erro
uuid,
error,
}));

/**
* Requests to activate a file and show line.
*/
export const editorGoto = createAction((uuid: UUID, line: number) => ({
type: 'editor.action.goto',
uuid,
line,
}));
30 changes: 30 additions & 0 deletions src/editor/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
editorDidOpenFile,
editorGetValueRequest,
editorGetValueResponse,
editorGoto,
editorOpenFile,
} from './actions';
import { EditorError } from './error';
Expand Down Expand Up @@ -265,6 +266,34 @@ function* handleEditorActivateFile(
}
}

function* handleEditorGoto(
editor: monaco.editor.ICodeEditor,
action: ReturnType<typeof editorGoto>,
): Generator {
yield* put(editorActivateFile(action.uuid));

const { didActivate, didFailToActivate } = yield* race({
didActivate: take(editorDidActivateFile.when((a) => a.uuid === action.uuid)),
didFailToActivate: take(
editorDidFailToActivateFile.when((a) => a.uuid === action.uuid),
),
});

if (didFailToActivate) {
return;
}

defined(didActivate);

editor.revealLineInCenterIfOutsideViewport(action.line);
editor.setSelection({
startColumn: 1,
startLineNumber: action.line,
endColumn: Infinity,
endLineNumber: action.line,
});
}

function* handleEditorDidCloseFile(
activeFileHistory: ActiveFileHistoryManager,
action: ReturnType<typeof editorDidCloseFile>,
Expand Down Expand Up @@ -356,6 +385,7 @@ function* handleDidCreateEditor(editor: monaco.editor.ICodeEditor): Generator {
openFiles,
activeFileHistory,
);
yield* takeEvery(editorGoto, handleEditorGoto, editor);
yield* takeEvery(editorDidCloseFile, handleEditorDidCloseFile, activeFileHistory);
yield* fork(monitorViewState, editor);

Expand Down
15 changes: 15 additions & 0 deletions src/fileStorage/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,18 @@ export function useFileStoragePath(uuid: UUID): string | undefined {
const db = useContext(FileStorageContext);
return useLiveQuery(() => db.metadata.get(uuid, (x) => x?.path));
}

/**
* Gets the file path for a file UUID.
*
* If the file is renamed, the returned value will be automatically updated.
*/
export function useFileStorageUuid(path: string): UUID | undefined {
const db = useContext(FileStorageContext);
return useLiveQuery(() =>
db.metadata
.where('path')
.equals(path)
.first((x) => x?.uuid),
);
}
10 changes: 10 additions & 0 deletions src/hub/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,16 @@ function* handleDownloadAndRun(action: ReturnType<typeof downloadAndRun>): Gener
});

if (didFailToCompile) {
yield* put(
alertsShowAlert(
'mpy',
'compilerError',
{
error: didFailToCompile.error,
},
'mpy.compilerError',
),
);
return;
}

Expand Down
58 changes: 58 additions & 0 deletions src/mpy/alerts/CompilerError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors

import { Button, Intent } from '@blueprintjs/core';
import React, { useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { editorGoto } from '../../editor/actions';
import { useFileStorageUuid } from '../../fileStorage/hooks';
import type { CreateToast } from '../../toasterTypes';
import { useI18n } from './i18n';

type CompilerErrorProps = {
error: string[];
};

const CompilerError: React.VoidFunctionComponent<CompilerErrorProps> = ({ error }) => {
const dispatch = useDispatch();
const i18n = useI18n();

const [file, line] = useMemo(() => {
for (const line of error) {
const match = line.match(/^ {2}File "(.*)", line (\d+)/);

if (match) {
return [match[1], Number(match[2])];
}
}

return [undefined, undefined];
}, [error]);

const uuid = useFileStorageUuid(file ?? '');

return (
<>
<p>{i18n.translate('compilerError.message')}</p>
<pre className="pb-mpy-alerts-compile-error">{error.join('\n')}</pre>
{file && uuid && (
<Button icon="code" onClick={() => dispatch(editorGoto(uuid, line))}>
{i18n.translate('compilerError.gotoErrorButton')}
</Button>
)}
</>
);
};

export const compilerError: CreateToast<CompilerErrorProps, 'dismiss' | 'gotoError'> = (
onAction,
props,
) => {
return {
message: <CompilerError {...props} />,
icon: 'error',
intent: Intent.DANGER,
timeout: 0,
onDismiss: () => onAction('dismiss'),
};
};
12 changes: 12 additions & 0 deletions src/mpy/alerts/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors

import { useI18n as useShopifyI18n } from '@shopify/react-i18n';
import type { TypedI18n } from '../../i18n';
import type translations from './translations/en.json';

export function useI18n(): TypedI18n<typeof translations> {
// istanbul ignore next: babel-loader rewrites this line
const [i18n] = useShopifyI18n();
return i18n;
}
7 changes: 7 additions & 0 deletions src/mpy/alerts/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors

pre.pb-mpy-alerts-compile-error {
white-space: pre-wrap;
word-break: keep-all;
}
10 changes: 10 additions & 0 deletions src/mpy/alerts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors

import './index.scss';
import { compilerError } from './CompilerError';

// gathers all of the alert creation functions for passing up to the top level
export default {
compilerError,
};
6 changes: 6 additions & 0 deletions src/mpy/alerts/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerError": {
"message": "Failed to compile MicroPython file.",
"gotoErrorButton": "Goto error"
}
}

0 comments on commit 7e726ff

Please sign in to comment.