1- import { Component , createEffect , onMount , onCleanup } from 'solid-js' ;
1+ import { Component , createEffect , onMount , onCleanup , on } from 'solid-js' ;
22import { Uri , languages , editor as mEditor , KeyMod , KeyCode } from 'monaco-editor' ;
33import { liftOff } from './setupSolid' ;
44import { useZoom } from '../../hooks/useZoom' ;
55import type { Repl } from 'solid-repl/lib/repl' ;
6+ import type { LinterWorkerPayload , LinterWorkerResponse } from '../../workers/linter' ;
7+ import { throttle } from '@solid-primitives/scheduled' ;
68
79const Editor : Component < {
810 url : string ;
911 disabled ?: true ;
1012 isDark ?: boolean ;
1113 withMinimap ?: boolean ;
1214 formatter ?: Worker ;
15+ linter ?: Worker ;
1316 displayErrors ?: boolean ;
17+ displayLintMessages ?: boolean ;
1418 onDocChange ?: ( code : string ) => void ;
1519 onEditorReady ?: Parameters < Repl > [ 0 ] [ 'onEditorReady' ] ;
1620} > = ( props ) => {
@@ -47,6 +51,33 @@ const Editor: Component<{
4751 } ,
4852 } ) ;
4953 }
54+ if ( props . linter ) {
55+ const listener = ( { data } : MessageEvent < LinterWorkerResponse > ) => {
56+ if ( props . displayLintMessages ) {
57+ const { event } = data ;
58+ if ( event === 'LINT' ) {
59+ const m = model ( ) ;
60+ m && mEditor . setModelMarkers ( m , 'eslint' , data . markers ) ;
61+ } else if ( event === 'FIX' ) {
62+ const m = model ( ) ;
63+ m && mEditor . setModelMarkers ( m , 'eslint' , data . markers ) ;
64+ data . fixed && model ( ) ?. setValue ( data . output ) ;
65+ }
66+ }
67+ } ;
68+ props . linter . addEventListener ( 'message' , listener ) ;
69+ onCleanup ( ( ) => props . linter ?. removeEventListener ( 'message' , listener ) ) ;
70+ }
71+
72+ const runLinter = throttle ( ( code : string ) => {
73+ if ( props . linter && props . displayLintMessages ) {
74+ const payload : LinterWorkerPayload = {
75+ event : 'LINT' ,
76+ code,
77+ } ;
78+ props . linter . postMessage ( payload ) ;
79+ }
80+ } , 250 ) ;
5081
5182 // Initialize Monaco
5283 onMount ( ( ) => {
@@ -63,13 +94,39 @@ const Editor: Component<{
6394 } ,
6495 } ) ;
6596
97+ if ( props . linter ) {
98+ editor . addAction ( {
99+ id : 'eslint.executeAutofix' ,
100+ label : 'Fix all auto-fixable problems' ,
101+ contextMenuGroupId : '1_modification' ,
102+ contextMenuOrder : 3.5 ,
103+ run : ( ed ) => {
104+ const code = ed . getValue ( ) ;
105+ if ( code ) {
106+ const payload : LinterWorkerPayload = {
107+ event : 'FIX' ,
108+ code,
109+ } ;
110+ props . linter ?. postMessage ( payload ) ;
111+ }
112+ } ,
113+ } ) ;
114+ }
115+
66116 editor . addCommand ( KeyMod . CtrlCmd | KeyCode . KeyS , ( ) => {
67- editor ?. getAction ( 'editor.action.formatDocument' ) . run ( ) ;
68- editor ?. focus ( ) ;
117+ if ( editor ) {
118+ // auto-format
119+ editor . getAction ( 'editor.action.formatDocument' ) ?. run ( ) ;
120+ // auto-fix problems
121+ props . displayLintMessages && editor . getAction ( 'eslint.executeAutofix' ) ?. run ( ) ;
122+ editor . focus ( ) ;
123+ }
69124 } ) ;
70125
71126 editor . onDidChangeModelContent ( ( ) => {
72- props . onDocChange ?.( editor . getValue ( ) ) ;
127+ const code = editor . getValue ( ) ;
128+ props . onDocChange ?.( code ) ;
129+ runLinter ( code ) ;
73130 } ) ;
74131 } ) ;
75132 onCleanup ( ( ) => editor ?. dispose ( ) ) ;
@@ -95,6 +152,17 @@ const Editor: Component<{
95152 } ) ;
96153 } ) ;
97154
155+ createEffect ( ( ) => {
156+ if ( props . displayLintMessages ) {
157+ // run on mount and when displayLintMessages is turned on
158+ runLinter ( editor . getValue ( ) ) ;
159+ } else {
160+ // reset eslint markers when displayLintMessages is turned off
161+ const m = model ( ) ;
162+ m && mEditor . setModelMarkers ( m , 'eslint' , [ ] ) ;
163+ }
164+ } ) ;
165+
98166 onMount ( ( ) => {
99167 props . onEditorReady ?.( editor , { Uri, editor : mEditor } ) ;
100168 } ) ;
0 commit comments