@@ -6,26 +6,26 @@ import React, {
66 useMemo
77} from 'react' ;
88import PropTypes from 'prop-types' ;
9- import { EditorState , StateEffect , Prec , StateField } from '@codemirror/state' ;
9+ import { EditorState , StateEffect , Prec } from '@codemirror/state' ;
1010import {
1111 EditorView ,
1212 keymap ,
1313 highlightActiveLine ,
1414 lineNumbers ,
15- Decoration ,
16- DecorationSet
15+ Decoration
1716} from '@codemirror/view' ;
1817import Fuse from 'fuse.js' ;
1918import { javascript } from '@codemirror/lang-javascript' ;
2019import { css } from '@codemirror/lang-css' ;
21- import { bracketMatching , foldGutter } from '@codemirror/language' ;
20+ import {
21+ bracketMatching ,
22+ foldGutter ,
23+ syntaxHighlighting ,
24+ codeFolding
25+ } from '@codemirror/language' ;
2226import { autocompletion , closeBrackets } from '@codemirror/autocomplete' ;
2327import { linter , lintGutter } from '@codemirror/lint' ;
2428import { standardKeymap } from '@codemirror/commands' ;
25- import {
26- colorPicker ,
27- wrapperClassName
28- } from '@replit/codemirror-css-color-picker' ;
2929import MediaQuery from 'react-responsive' ;
3030import prettier from 'prettier/standalone' ;
3131import babelParser from 'prettier/parser-babel' ;
@@ -67,6 +67,16 @@ import { selectActiveFile } from '../../selectors/files';
6767import { EditorContainer , EditorHolder } from './MobileEditor' ;
6868import { FolderIcon } from '../../../../common/icons' ;
6969import IconButton from '../../../../common/IconButton' ;
70+ import {
71+ lightHighlightStyle ,
72+ p5LightTheme
73+ } from '../../utils/p5-light-cm-theme' ;
74+ import { darkHighlightStyle , p5DarkTheme } from '../../utils/p5-dark-cm-theme' ;
75+ import {
76+ contrastHighlightStyle ,
77+ p5ContrastTheme
78+ } from '../../utils/p5-contrast-cm-theme' ;
79+ import p5ViewPlugin from '../../utils/p5ViewPlugin' ;
7080
7181import * as FileActions from '../../actions/files' ;
7282import * as IDEActions from '../../actions/ide' ;
@@ -109,39 +119,29 @@ const prettierFormatWithCursor = (view, parser, plugins) => {
109119 }
110120} ;
111121
112- const createThemeExtension = ( themeName ) => {
113- const themeClass = themeName === 'dark' ? 'cm-s-p5-dark' : 'cm-s-p5-light' ;
114- return EditorView . theme ( { } , { dark : themeName === 'dark' , themeClass } ) ;
122+ const getThemeByName = ( themeName ) => {
123+ switch ( themeName ) {
124+ case 'dark' :
125+ return p5DarkTheme ;
126+ case 'contrast' :
127+ return p5ContrastTheme ;
128+ case 'light' :
129+ default :
130+ return p5LightTheme ;
131+ }
115132} ;
116133
117- // Create an effect to add or remove decorations
118- const addDecorationEffect = StateEffect . define ( ) ;
119- const removeDecorationEffect = StateEffect . define ( ) ;
120-
121- // Define a StateField to manage decorations
122- const decorationsField =
123- StateField . define <
124- DecorationSet >
125- {
126- create ( ) {
127- return Decoration . none ;
128- } ,
129- update ( decorations , tr ) {
130- let newDecorations = decorations ; // Create a new variable to hold the updated decorations
131-
132- tr . effects . forEach ( ( effect ) => {
133- if ( effect . is ( addDecorationEffect ) ) {
134- newDecorations = newDecorations . update ( { add : [ effect . value ] } ) ;
135- }
136- if ( effect . is ( removeDecorationEffect ) ) {
137- newDecorations = Decoration . none ;
138- }
139- } ) ;
140-
141- return newDecorations ; // Return the new variable instead of reassigning the parameter
142- } ,
143- provide : ( f ) => EditorView . decorations . from ( f )
144- } ;
134+ const getHighlightStyleByName = ( themeName ) => {
135+ switch ( themeName ) {
136+ case 'dark' :
137+ return darkHighlightStyle ;
138+ case 'contrast' :
139+ return contrastHighlightStyle ;
140+ case 'light' :
141+ default :
142+ return lightHighlightStyle ;
143+ }
144+ } ;
145145
146146const Editor = ( props ) => {
147147 const {
@@ -195,7 +195,7 @@ const Editor = (props) => {
195195 beepRef . current . play ( ) ;
196196 }
197197 } , 2000 ) ,
198- [ ]
198+ [ lintMessages ]
199199 ) ;
200200
201201 const editorRef = useRef ( null ) ;
@@ -219,7 +219,7 @@ const Editor = (props) => {
219219
220220 const replaceCommand = metaKey === 'Ctrl' ? `Mod-h` : `Mod-Alt-f` ;
221221
222- // Handle document changes (debounced)
222+ // TODO: test debounce
223223 const handleEditorChange = useCallback ( ( ) => {
224224 setUnsavedChanges ( true ) ;
225225 hideRuntimeErrorWarning ( ) ;
@@ -249,51 +249,45 @@ const Editor = (props) => {
249249 }
250250 } ;
251251
252- const showFind = useCallback ( ( ) => {
252+ const showFind = ( ) => {
253253 viewRef . current . dispatch ( { effect : EditorView . findPersistent . of ( ) } ) ;
254- } , [ ] ) ;
254+ } ;
255255
256- const showReplace = useCallback ( ( ) => {
256+ const showReplace = ( ) => {
257257 viewRef . current . dispatch ( { effect : EditorView . replacePersistent . of ( ) } ) ;
258- } , [ ] ) ;
258+ } ;
259259
260- const getContent = useCallback (
261- ( ) => viewRef . current . state . doc . toString ( ) ,
262- [ ]
263- ) ;
260+ const getContent = ( ) => viewRef . current . state . doc . toString ( ) ;
264261
265- const handleKeyUp = useCallback ( ( ) => {
262+ const handleKeyUp = ( ) => {
266263 const lineNumber = viewRef . current . state . doc . lineAt (
267264 viewRef . current . state . selection . main . head
268265 ) . number ;
269266 setCurrentLine ( lineNumber ) ;
270- } , [ ] ) ;
267+ } ;
271268
272269 const customLinterFunction = ( view ) => {
273270 const diagnostics = [ ] ;
274- const content = view . state . doc . toString ( ) ; // Get the content of the editor
271+ const content = view . state . doc . toString ( ) ;
275272
276- // Pass the content through JSHint (or any other linter)
277273 JSHINT ( content , {
278- asi : true , // Allow missing semicolons
279- eqeqeq : false , // Allow non-strict equality (== and !=)
280- '-W041' : false , // Disable warning for 'use of == null'
281- esversion : 11 // Use ECMAScript version 11 (ES2020)
274+ asi : true ,
275+ eqeqeq : false ,
276+ '-W041' : false ,
277+ esversion : 11
282278 } ) ;
283279
284- // Process JSHint results and convert them into CodeMirror diagnostics
285280 JSHINT . errors . forEach ( ( error ) => {
286281 if ( ! error ) return ;
287282
288283 diagnostics . push ( {
289- from : view . state . doc . line ( error . line ) . from + ( error . character - 1 ) , // Position of the error
290- to : view . state . doc . line ( error . line ) . from + error . character , // End position of the error
291- severity : error . code . startsWith ( 'W' ) ? 'warning' : 'error' , // 'W' indicates a warning in JSHint
292- message : error . reason // The error message
284+ from : view . state . doc . line ( error . line ) . from + ( error . character - 1 ) ,
285+ to : view . state . doc . line ( error . line ) . from + error . character ,
286+ severity : error . code . startsWith ( 'W' ) ? 'warning' : 'error' ,
287+ message : error . reason
293288 } ) ;
294289 } ) ;
295290
296- // Call the onUpdateLinting function to handle linting messages
297291 updateLintingMessageAccessibility ( diagnostics ) ;
298292
299293 return diagnostics ;
@@ -303,7 +297,7 @@ const Editor = (props) => {
303297 const view = viewRef . current ;
304298 if ( view ) {
305299 // TODO: fix this use persistent using codemirror search
306- view . dispatch ( { effects : findNext } ) ; // Dispatch the find effect
300+ view . dispatch ( { effects : findNext } ) ;
307301 }
308302 } ;
309303
@@ -340,6 +334,7 @@ const Editor = (props) => {
340334 run : ( ) => null // No action, handle shift + meta + Enter
341335 } ,
342336 {
337+ // TODO: connect search widget
343338 key : `Mod-f` , // Meta + F to trigger findPersistent
344339 run : ( ) => {
345340 triggerFindPersistent ( ) ; // Trigger the findPersistent functionality
@@ -364,7 +359,7 @@ const Editor = (props) => {
364359 } ,
365360 {
366361 key : `Mod-k` , // TODO: need to find a way to create custom color picker since codemirror 6 doesn't have one
367- run : ( ) => null
362+ run : ( view ) => view . state . colorpicker . popup_color_picker ( { length : 0 } )
368363 }
369364 ] ) ;
370365
@@ -454,21 +449,21 @@ const Editor = (props) => {
454449 const getCommonExtensions = ( ) => [
455450 javascript ( ) ,
456451 autocompletion ( ) ,
457- linter ( customLinterFunction ) , // Linter extension
452+ linter ( customLinterFunction ) ,
458453 lintGutter ( ) ,
459454 abbreviationTracker ( ) ,
460- lineNumbers ( ) , // Line numbers
461- highlightActiveLine ( ) , // Highlight active line
462- foldGutter ( ) , // Fold gutter
463- bracketMatching ( ) , // Match brackets
464- closeBrackets ( ) , // Automatically close brackets
465- highlightSelectionMatches ( ) , // Highlight search matches
466- css ( ) , // CSS support
455+ lineNumbers ( ) ,
456+ highlightActiveLine ( ) ,
457+ foldGutter ( ) ,
458+ bracketMatching ( ) ,
459+ closeBrackets ( ) ,
460+ highlightSelectionMatches ( ) ,
461+ css ( ) ,
467462 keymap . of ( standardKeymap ) ,
468- Prec . highest ( customKeymap ) , // Ensure custom keymap has the highest precedence
463+ Prec . highest ( customKeymap ) ,
469464 EditorView . updateListener . of ( ( update ) => {
470465 if ( update . docChanged ) {
471- handleEditorChange ( ) ; // Handle document changes
466+ handleEditorChange ( ) ;
472467 }
473468 } ) ,
474469 EditorView . updateListener . of ( ( update ) => {
@@ -478,21 +473,16 @@ const Editor = (props) => {
478473 } ) ,
479474 EditorView . lineWrapping ,
480475 hintExtension ,
481- // colorPicker,
482- EditorView . theme ( {
483- [ `.${ wrapperClassName } ` ] : {
484- outlineColor : 'transparent'
485- }
486- } )
487- // decorationsField
476+ codeFolding ( ) ,
477+ p5ViewPlugin
488478 ] ;
489479
490480 useEffect ( ( ) => {
491481 if ( ! editorRef . current ) return ;
492482
493483 const startState = EditorState . create ( {
494484 doc : file . content ,
495- extensions : [ ...getCommonExtensions ( ) , createThemeExtension ( theme ) ]
485+ extensions : [ ...getCommonExtensions ( ) ]
496486 } ) ;
497487
498488 const view = new EditorView ( {
@@ -549,7 +539,6 @@ const Editor = (props) => {
549539 const prevConsoleEventsLength = prevConsoleEventsLengthRef . current ;
550540
551541 if ( consoleEvents . length !== prevConsoleEventsLength ) {
552- // Process new console events
553542 consoleEvents . forEach ( ( consoleEvent ) => {
554543 if ( consoleEvent . method === 'error' ) {
555544 const errorObj = { stack : consoleEvent . data [ 0 ] . toString ( ) } ;
@@ -571,21 +560,18 @@ const Editor = (props) => {
571560 if ( fileWithError ) {
572561 setSelectedFile ( fileWithError . id ) ;
573562
574- // Create a line decoration for the error
575563 const decoration = Decoration . line ( {
576564 class : 'line-runtime-error'
577565 } ) . range (
578566 viewRef . current . state . doc . line ( line . lineNumber - 1 ) . from
579567 ) ;
580568
581- // Apply the decoration to highlight the line
582569 viewRef . current . dispatch ( {
583570 effects : StateEffect . appendConfig . of (
584571 EditorView . decorations . of ( Decoration . set ( [ decoration ] ) )
585572 )
586573 } ) ;
587574
588- // Store the decoration so it can be cleared later
589575 errorDecoration . current = Decoration . set ( [ decoration ] ) ;
590576 }
591577 } ) ;
@@ -597,7 +583,7 @@ const Editor = (props) => {
597583 EditorView . decorations . of ( Decoration . none )
598584 )
599585 } ) ;
600- errorDecoration . current = Decoration . none ; // Clear the stored decorations
586+ errorDecoration . current = Decoration . none ;
601587 }
602588
603589 prevConsoleEventsLengthRef . current = consoleEvents . length ;
@@ -644,12 +630,19 @@ const Editor = (props) => {
644630 // Handle theme change
645631 useEffect ( ( ) => {
646632 if ( ! viewRef . current ) return ;
647-
648633 const view = viewRef . current ;
649- const newTheme = createThemeExtension ( theme ) ;
634+ const newTheme = getThemeByName ( theme ) ;
635+ const newHighLightStyle = syntaxHighlighting (
636+ getHighlightStyleByName ( theme )
637+ ) ;
638+ console . log ( 'theme' , newTheme , newHighLightStyle ) ;
650639
651640 view . dispatch ( {
652- effects : StateEffect . reconfigure . of ( [ ...getCommonExtensions ( ) , newTheme ] )
641+ effects : StateEffect . reconfigure . of ( [
642+ ...getCommonExtensions ( ) ,
643+ newTheme ,
644+ newHighLightStyle
645+ ] )
653646 } ) ;
654647 } , [ props . file . content , theme ] ) ;
655648
@@ -691,7 +684,6 @@ const Editor = (props) => {
691684 'editor-holder--hidden' : file . fileType === 'folder' || file . url
692685 } ) }
693686 />
694- < div id = "color-picker" />
695687 { file . url ? < AssetPreview url = { file . url } name = { file . name } /> : null }
696688 < EditorAccessibility
697689 lintMessages = { lintMessages }
0 commit comments