Skip to content

[WIP] React FC conversion for editor file retry + codemirror update #3230

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Draft
wants to merge 14 commits into
base: develop
Choose a base branch
from
1,206 changes: 649 additions & 557 deletions client/modules/IDE/components/Editor/index.jsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ describe('<EditorAccessibility />', () => {
it('renders empty message with no lines', () => {
render(<EditorAccessibility lintMessages={[]} currentLine={0} />);

expect(
screen.getByRole('listitem', {
description: 'There are no lint messages'
})
).toBeInTheDocument();
expect(screen.getByText(/there are no lint messages/i)).toBeInTheDocument();
});

it('renders lint message', () => {
Expand Down
48 changes: 48 additions & 0 deletions client/modules/IDE/utils/highlightStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { HighlightStyle } from '@codemirror/language';
import { tags } from '@lezer/highlight';

const createHighlightStyle = (colors) =>
HighlightStyle.define([
{ tag: tags.link, class: 'cm-link' },
{ tag: tags.heading, class: 'cm-heading' },
{ tag: tags.emphasis, class: 'cm-emphasis' },
{ tag: tags.strong, class: 'cm-strong' },
{ tag: tags.keyword, color: colors.keyword },
{ tag: tags.atom, color: colors.atom },
{ tag: tags.bool, class: 'cm-bool' },
{ tag: tags.url, class: 'cm-url' },
{ tag: tags.labelName, class: 'cm-labelName' },
{ tag: tags.inserted, class: 'cm-inserted' },
{ tag: tags.deleted, class: 'cm-deleted' },
{ tag: tags.literal, class: 'cm-literal' },
{ tag: tags.string, color: colors.string },
{ tag: tags.number, color: colors.number },
{
tag: [tags.regexp, tags.escape, tags.special(tags.string)],
color: colors.regexp
},
{ tag: tags.variableName, color: colors.variable },
{ tag: tags.local(tags.variableName), class: 'cm-variableName cm-local' },
{
tag: tags.definition(tags.variableName),
class: 'cm-variableName cm-definition'
},
{ tag: tags.special(tags.variableName), color: colors.specialVariable },
{
tag: tags.definition(tags.propertyName),
class: 'cm-propertyName cm-definition'
},
{ tag: tags.typeName, color: colors.typeName },
{ tag: tags.namespace, class: 'cm-namespace' },
{ tag: tags.className, class: 'cm-className' },
{ tag: tags.macroName, class: 'cm-macroName' },
{ tag: tags.propertyName, class: 'cm-propertyName' },
{ tag: tags.operator, color: colors.operator },
{ tag: tags.comment, color: colors.comment },
{ tag: tags.meta, class: 'cm-meta' },
{ tag: tags.invalid, class: 'cm-invalid' },
{ tag: tags.punctuation, class: 'cm-punctuation' },
{ tag: tags.special(tags.variableName), class: 'p5-variable' }
]);

export default createHighlightStyle;
68 changes: 68 additions & 0 deletions client/modules/IDE/utils/p5-contrast-cm-theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { EditorView } from '@codemirror/view';
import createHighlightStyle from './highlightStyle';
import {
createGutterStyles,
createLineStyles,
createSelectionStyles,
createCursorAndBracketStyles,
createErrorAndSearchStyles,
createHighlightClasses
} from './sharedStyles';

const contrastColors = {
background: '#1C1C1C',
text: '#FDFDFD',
gutterBackground: '#454545',
lineNumber: '#FDFDFD',
selection: 'rgba(45, 123, 182, 0.25)',
activeLine: '#999999',
activeLineGutter: '#333333',
cursor: '#FDFDFD',
bracket: '#C1C1C1',
error: '#f00',
searchMatch: '#333333',
searchSelectedTextOutline: '#FDFDFD',
qualifier: '#F5DC23',
tag: '#FFA95D',
builtin: '#F5DC23',
attribute: '#FDFDFD',
function: '#00FFFF',
variable: '#FFA9D9',
foldPlaceholderBackground: '#FDFDFD',
foldPlaceholderColor: '#333333',
keyword: '#F5DC23',
atom: '#FFA9D9',
string: '#2DE9B6',
number: '#FDFDFD',
regexp: '#2DE9B6',
specialVariable: '#FDFDFD',
typeName: '#F5DC23',
comment: '#C1C1C1',
operator: '#C1C1C1'
};

const contrastHighlightStyle = createHighlightStyle(contrastColors);
const contrastThemeStyles = {
'&': {
backgroundColor: contrastColors.background,
color: contrastColors.text,
fontFamily: 'Inconsolata, monospace',
height: '100%'
},
'&.cm-focused': {
outline: 'none'
},
...createGutterStyles(contrastColors),
...createLineStyles(),
...createSelectionStyles(contrastColors),
...createCursorAndBracketStyles(contrastColors),
...createErrorAndSearchStyles(contrastColors),
...createHighlightClasses(contrastColors),
'.CodeMirror-selectedtext': {
backgroundColor: contrastColors.activeLineGutter,
outline: `${contrastColors.searchSelectedTextOutline}`
}
};

const p5ContrastTheme = EditorView.theme(contrastThemeStyles, { dark: true });
export { p5ContrastTheme, contrastHighlightStyle };
70 changes: 70 additions & 0 deletions client/modules/IDE/utils/p5-dark-cm-theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { EditorView } from '@codemirror/view';
import createHighlightStyle from './highlightStyle';
import {
createGutterStyles,
createLineStyles,
createSelectionStyles,
createCursorAndBracketStyles,
createErrorAndSearchStyles,
createHighlightClasses
} from './sharedStyles';

const darkColors = {
background: '#1C1C1C',
text: '#FDFDFD',
gutterBackground: '#f4f4f4',
lineNumber: '#b5b5b5',
selection: 'rgba(45, 123, 182, 0.25)',
activeLine: '#CFCFCF',
activeLineGutter: '#666666',
cursor: '#FDFDFD',
bracket: '#9B9B9B',
error: '#df3a3d',
searchMatch: 'rgba(217, 50, 143, 0.5)',
qualifier: '#0F9DD7',
tag: '#DE4A9B',
builtin: '#0F9DD7',
attribute: '#FDFDFD',
function: '#0F9DD7',
variable: '#DE4A9B',
foldPlaceholderBackground: '#FDFDFD',
foldPlaceholderColor: '#1C1C1C',
keyword: '#b58318',
atom: '#DE4A9B',
string: '#58a10b',
number: '#FDFDFD',
regexp: '#EE9900',
specialVariable: '#666666',
typeName: '#DE4A9B',
comment: '#9B9B9B',
operator: '#A67F59'
};

const darkHighlightStyle = createHighlightStyle(darkColors);
const darkThemeStyles = {
'&': {
backgroundColor: darkColors.background,
color: darkColors.text,
fontFamily: 'Inconsolata, monospace',
height: '100%'
},
'&.cm-focused': {
outline: 'none'
},
...createGutterStyles(darkColors),
...createLineStyles(),
...createSelectionStyles(darkColors),
...createCursorAndBracketStyles(darkColors),
...createErrorAndSearchStyles(darkColors),
...createHighlightClasses(darkColors),
'.CodeMirror-selectedtext': {
backgroundColor: darkColors.activeLineGutter
}
};

const p5DarkTheme = EditorView.theme(darkThemeStyles, {
dark: true,
themeClass: 'cm-s-p5-dark'
});

export { p5DarkTheme, darkHighlightStyle };
72 changes: 72 additions & 0 deletions client/modules/IDE/utils/p5-light-cm-theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { EditorView } from '@codemirror/view';
import createHighlightStyle from './highlightStyle';
import {
createGutterStyles,
createLineStyles,
createSelectionStyles,
createCursorAndBracketStyles,
createErrorAndSearchStyles,
createHighlightClasses
} from './sharedStyles';

const lightColors = {
background: '#FDFDFD',
text: '#333333',
gutterBackground: '#F4F4F4',
lineNumber: '#B5B5B5',
selection: 'rgba(45, 123, 182, 0.25)',
activeLine: '#CFCFCF',
activeLineGutter: '#999999',
cursor: '#333333',
bracket: '#666666',
error: '#f00',
searchMatch: 'rgba(213, 40, 137, 0.5)',
qualifier: '#0B7CA9',
tag: '#D52889',
builtin: '#0B7CA9',
attribute: '#666666',
function: '#0B7CA9',
variable: '#D52889',
foldPlaceholderBackground: '#333333',
foldPlaceholderColor: '#FDFDFD',
keyword: '#7A5A3A',
atom: '#D52889',
string: '#47820A',
number: '#B5B5B5',
regexp: '#A06801',
specialVariable: '#666666',
typeName: '#D52889',
comment: '#666666',
operator: '#7A5A3A',
lintError: 'rgb(255, 95, 82)',
lintWarning: 'rgb(255, 190, 5)',
foldGutter: 'rgba(0, 0, 0, 0.2)'
};

const lightHighlightStyle = createHighlightStyle(lightColors);
const lightThemeStyles = {
'&': {
backgroundColor: lightColors.background,
color: lightColors.text,
fontFamily: 'Inconsolata, monospace',
height: '100%'
},
'&.cm-focused': {
outline: 'none'
},
...createGutterStyles(lightColors),
...createLineStyles(),
...createSelectionStyles(lightColors),
...createCursorAndBracketStyles(lightColors),
...createErrorAndSearchStyles(lightColors),
...createHighlightClasses(lightColors),
'.CodeMirror-selectedtext': {
backgroundColor: lightColors.activeLineGutter
}
};

const p5LightTheme = EditorView.theme(lightThemeStyles, {
dark: false,
themeClass: 'cm-s-p5-light'
});
export { p5LightTheme, lightHighlightStyle };
64 changes: 64 additions & 0 deletions client/modules/IDE/utils/p5ViewPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { syntaxTree } from '@codemirror/language';
import { Decoration, EditorView, ViewPlugin } from '@codemirror/view';
import {
p5FunctionKeywords,
p5VariableKeywords
} from '../../../utils/p5-keywords';

function createP5Decoration(node, text) {
const isFunction = text in p5FunctionKeywords;
const isVariable = text in p5VariableKeywords;

if (isFunction || isVariable) {
const className = isFunction ? 'cm-p5-function' : 'cm-p5-variable';
return [Decoration.mark({ class: className }).range(node.from, node.to)];
}

return [];
}

function createDecorations(view) {
const decorations = [];

view.visibleRanges.forEach(({ from, to }) => {
syntaxTree(view.state).iterate({
from,
to,
enter: (node) => {
const text = view.state.doc.sliceString(node.from, node.to);

if (
node.name === 'VariableName' ||
node.name === 'VariableDefinition'
) {
decorations.push(...createP5Decoration(node, text));
}
}
});
});

return Decoration.set(decorations);
}

const p5ViewPlugin = ViewPlugin.fromClass(
class {
constructor(view) {
this.decorations = createDecorations(view);
}

update(update) {
if (update.docChanged || update.viewportChanged) {
this.decorations = createDecorations(update.view);
}
}
},
{
decorations: (instance) => instance.decorations,
provide: (plugin) =>
EditorView.atomicRanges.of(
(view) => view.plugin(plugin)?.decorations || Decoration.none
)
}
);

export default p5ViewPlugin;
Loading
Loading