Skip to content

Commit 91a4052

Browse files
authored
New Problem View (codesandbox#1794)
With this update I move the corrections generated by the linter from the state of our editor to the global state (in case of `app` in Cerebral, in `embed` we use a variable). This way we can show the corrections of the linter in the `Problems` view, which got a small redesign as well to be more useful. In the future we might decide to also include the `corrections`/`errors` generated by VSCode, or we might move the source of truth of this state to VSCode entirely. - [x] Moves lint errors to global state - [x] Removes the need of `moduleId` for corrections and errors - [x] Removes glyphs (we didn't use it) - [x] Adds ability to open specific line of a file ![image](https://user-images.githubusercontent.com/587016/56470576-18eb2f80-6448-11e9-95ae-4cdac0d60c8f.png)
1 parent 7f54ada commit 91a4052

File tree

32 files changed

+545
-293
lines changed

32 files changed

+545
-293
lines changed

packages/app/src/app/components/CodeEditor/CodeMirror/index.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import CodeMirror from 'codemirror';
55
import { withTheme } from 'styled-components';
66

77
import type { ModuleError, Module } from '@codesandbox/common/lib/types';
8+
import { resolveModule } from '@codesandbox/common/lib/sandbox/modules';
89
import { getCodeMirror } from 'app/utils/codemirror';
910

11+
import { listen } from 'codesandbox-api';
12+
1013
import 'codemirror/addon/dialog/dialog';
1114
import 'codemirror/addon/hint/show-hint';
1215
import 'codemirror/addon/tern/tern';
@@ -52,8 +55,28 @@ class CodemirrorEditor extends React.Component<Props, State> implements Editor {
5255
this.sandbox = props.sandbox;
5356
this.currentModule = props.currentModule;
5457
this.settings = props.settings;
58+
59+
this.codeSandboxListener = this.setupCodeSandboxListener();
5560
}
5661

62+
setupCodeSandboxListener = () => listen(this.handleMessage);
63+
64+
handleMessage = action => {
65+
if (action.action === 'editor.open-module') {
66+
try {
67+
const module = resolveModule(
68+
action.path,
69+
this.sandbox.modules,
70+
this.sandbox.directories
71+
);
72+
73+
this.setCurrentModule(module.id);
74+
} catch (e) {
75+
/* Ignore */
76+
}
77+
}
78+
};
79+
5780
shouldComponentUpdate(nextProps: Props) {
5881
if (
5982
this.props.width !== nextProps.width ||
@@ -73,6 +96,9 @@ class CodemirrorEditor extends React.Component<Props, State> implements Editor {
7396
if (this.disposeInitializer) {
7497
this.disposeInitializer();
7598
}
99+
if (this.codeSandboxListener) {
100+
this.codeSandboxListener();
101+
}
76102
}
77103

78104
componentDidMount() {

packages/app/src/app/components/CodeEditor/Monaco/index.js

Lines changed: 32 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { debounce } from 'lodash-es';
55
import { join, dirname } from 'path';
66
import { withTheme } from 'styled-components';
77
import { getModulePath } from '@codesandbox/common/lib/sandbox/modules';
8-
import { listen } from 'codesandbox-api';
8+
import { listen, dispatch, actions } from 'codesandbox-api';
99

1010
import getTemplate from '@codesandbox/common/lib/templates';
1111
import type {
@@ -69,6 +69,9 @@ function getSelection(lines, selection) {
6969

7070
let modelCache = {};
7171

72+
/**
73+
* This editor is like a slim version of our VSCode editor. It's used in the embed.
74+
*/
7275
class MonacoEditor extends React.Component<Props, State> implements Editor {
7376
static defaultProps = {
7477
width: '100%',
@@ -666,18 +669,19 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
666669

667670
setErrors = (errors: Array<ModuleError>) => {
668671
if (errors.length > 0) {
672+
const currentPath = this.editor.getModel().uri.path;
669673
const thisModuleErrors = errors.filter(
670-
error => error.moduleId === this.currentModule.id
674+
error => error.path === currentPath
671675
);
672676
const errorMarkers = thisModuleErrors
673677
.map(error => {
674678
if (error) {
675679
return {
676-
severity: this.monaco.Severity.Error,
680+
severity: this.monaco.MarkerSeverity.Error,
677681
startColumn: 1,
678682
startLineNumber: error.line,
679-
endColumn: error.column,
680-
endLineNumber: error.line + 1,
683+
endColumn: error.columnEnd || error.column,
684+
endLineNumber: error.lineEnd || error.line + 1,
681685
message: error.message,
682686
};
683687
}
@@ -698,19 +702,21 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
698702

699703
setCorrections = (corrections: Array<ModuleCorrection>) => {
700704
if (corrections.length > 0) {
705+
const currentPath = this.editor.getModel().uri.path;
706+
701707
const correctionMarkers = corrections
702-
.filter(correction => correction.moduleId === this.currentModule.id)
708+
.filter(correction => correction.path === currentPath)
703709
.map(correction => {
704710
if (correction) {
705711
return {
706712
severity:
707713
correction.severity === 'warning'
708-
? this.monaco.Severity.Warning
709-
: this.monaco.Severity.Notice,
714+
? this.monaco.MarkerSeverity.Warning
715+
: this.monaco.MarkerSeverity.Notice,
710716
startColumn: correction.column,
711717
startLineNumber: correction.line,
712-
endColumn: 1,
713-
endLineNumber: correction.line + 1,
718+
endColumn: correction.columnEnd || 1,
719+
endLineNumber: correction.lineEnd || correction.line + 1,
714720
message: correction.message,
715721
source: correction.source,
716722
};
@@ -734,30 +740,6 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
734740
}
735741
};
736742

737-
setGlyphs = (glyphs: Array<{ line: number, className: string }>) => {
738-
if (glyphs.length > 0) {
739-
const glyphMarkers = glyphs
740-
.map(glyph => {
741-
if (glyph) {
742-
return {
743-
range: new this.monaco.Range(glyph.line, 1, glyph.line, 1),
744-
options: {
745-
isWholeLine: true,
746-
glyphMarginClassName: glyph.className,
747-
},
748-
};
749-
}
750-
751-
return null;
752-
})
753-
.filter(x => x);
754-
755-
this.editor.deltaDecorations([], glyphMarkers);
756-
} else {
757-
this.editor.deltaDecorations([], []);
758-
}
759-
};
760-
761743
registerAutoCompletions = () => {
762744
this.monaco.languages.registerCompletionItemProvider('typescript', {
763745
triggerCharacters: ['"', "'", '.'],
@@ -900,10 +882,23 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
900882

901883
requestAnimationFrame(() => {
902884
if (this.editor.getModel()) {
885+
const modelPath = this.editor.getModel().uri.path;
886+
dispatch(actions.correction.clear(modelPath, 'eslint'));
887+
903888
if (version === this.editor.getModel().getVersionId()) {
904-
this.updateLintWarnings(markers);
905-
} else {
906-
this.updateLintWarnings([]);
889+
markers.forEach(marker => {
890+
dispatch(
891+
actions.correction.show(marker.message, {
892+
line: marker.startLineNumber,
893+
column: marker.startColumn,
894+
lineEnd: marker.endLineNumber,
895+
columnEnd: marker.endColumn,
896+
source: 'eslint',
897+
severity: marker.severity === 2 ? 'warning' : 'notice',
898+
path: modelPath,
899+
})
900+
);
901+
});
907902
}
908903
}
909904
});
@@ -964,19 +959,6 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
964959
);
965960
};
966961

967-
updateLintWarnings = async (markers: Array<Object>) => {
968-
const currentModule = this.currentModule;
969-
970-
const mode = await getMode(currentModule.title, this.monaco);
971-
if (mode === 'javascript' || mode === 'vue') {
972-
this.monaco.editor.setModelMarkers(
973-
this.editor.getModel(),
974-
'eslint',
975-
markers
976-
);
977-
}
978-
};
979-
980962
disposeModel = (id: string) => {
981963
if (modelCache[id]) {
982964
try {

0 commit comments

Comments
 (0)