1
- import { javascript } from "@codemirror/lang-javascript" ;
2
- import { python } from "@codemirror/lang-python" ;
3
- import { indentUnit } from "@codemirror/language" ;
4
- import { lintGutter , linter } from "@codemirror/lint" ;
5
- import { dracula } from "@uiw/codemirror-theme-dracula" ;
6
- import CodeMirror from "@uiw/react-codemirror" ;
7
- import type { LintOptions } from "jshint" ;
8
- import { JSHINT as jshint } from "jshint" ;
1
+ import CodeMirror , {
2
+ type Extension ,
3
+ type ReactCodeMirrorRef ,
4
+ } from "@uiw/react-codemirror" ;
5
+ import { useEffect , useRef , useState } from "react" ;
9
6
import type { OnChange } from "~/app" ;
10
7
import { InputLabel , useGooeyStringInput } from "~/gooeyInput" ;
8
+ import { EditorView } from "@codemirror/view" ;
9
+ import { vscodeLightInit as theme } from "@uiw/codemirror-theme-vscode" ;
11
10
12
- const jsLinter = ( lintOptions : LintOptions ) => {
13
- return linter ( ( view ) => {
14
- const diagnostics : any = [ ] ;
15
- const codeText = view . state . doc . toJSON ( ) ;
16
- jshint ( codeText , lintOptions ) ;
17
- const errors = jshint ?. data ( ) ?. errors ;
18
-
19
- if ( errors && errors . length > 0 ) {
20
- errors . forEach ( ( error ) => {
21
- const selectedLine = view . state . doc . line ( error . line ) ;
22
-
23
- const diagnostic = {
24
- from : selectedLine . from ,
25
- to : selectedLine . to ,
26
- severity : "error" ,
27
- message : error . reason ,
28
- } ;
29
-
30
- diagnostics . push ( diagnostic ) ;
31
- } ) ;
32
- }
33
- return diagnostics ;
34
- } ) ;
11
+ const linterDelay = 300 ;
12
+
13
+ const codeEditorExtensions : Record < string , ( ) => Promise < Extension [ ] > > = {
14
+ async jinja ( ) {
15
+ const { jinja } = await import ( "@codemirror/lang-jinja" ) ;
16
+ const { markdown } = await import ( "@codemirror/lang-markdown" ) ;
17
+
18
+ return [ jinja ( { base : markdown ( ) } ) ] ;
19
+ } ,
20
+ async json ( ) {
21
+ const { json, jsonParseLinter } = await import ( "@codemirror/lang-json" ) ;
22
+ const { linter, lintGutter } = await import ( "@codemirror/lint" ) ;
23
+
24
+ return [
25
+ lintGutter ( ) ,
26
+ json ( ) ,
27
+ linter ( jsonParseLinter ( ) , { delay : linterDelay } ) ,
28
+ ] ;
29
+ } ,
30
+ async python ( ) {
31
+ const { python } = await import ( "@codemirror/lang-python" ) ;
32
+ const { indentUnit } = await import ( "@codemirror/language" ) ;
33
+
34
+ return [ python ( ) , indentUnit . of ( " " ) ] ;
35
+ } ,
36
+ async javascript ( ) {
37
+ const { javascript } = await import ( "@codemirror/lang-javascript" ) ;
38
+ const { linter, lintGutter } = await import ( "@codemirror/lint" ) ;
39
+ const { JSHINT } = ( await import ( "jshint" ) ) . default ;
40
+
41
+ let lintOptions = {
42
+ esversion : 11 ,
43
+ browser : true ,
44
+ lastsemic : true ,
45
+ asi : true ,
46
+ expr : true ,
47
+ } ;
48
+
49
+ return [
50
+ lintGutter ( ) ,
51
+ javascript ( ) ,
52
+ linter (
53
+ ( view : EditorView ) => {
54
+ const diagnostics : any = [ ] ;
55
+ const codeText = view . state . doc . toJSON ( ) ;
56
+ JSHINT ( codeText , lintOptions ) ;
57
+ const errors = JSHINT . data ( ) ?. errors ;
58
+ errors ?. forEach ( ( error ) => {
59
+ const selectedLine = view . state . doc . line ( error . line ) ;
60
+
61
+ const diagnostic = {
62
+ from : selectedLine . from ,
63
+ to : selectedLine . to ,
64
+ severity : "error" ,
65
+ message : error . reason ,
66
+ } ;
67
+
68
+ diagnostics . push ( diagnostic ) ;
69
+ } ) ;
70
+ return diagnostics ;
71
+ } ,
72
+ { delay : linterDelay }
73
+ ) ,
74
+ ] ;
75
+ } ,
35
76
} ;
36
77
37
78
export default function CodeEditor ( {
@@ -59,6 +100,7 @@ export default function CodeEditor({
59
100
defaultValue,
60
101
args,
61
102
} ) ;
103
+
62
104
const handleChange = ( val : string ) => {
63
105
setValue ( val ) ;
64
106
// trigger the onChange event for Root Form
@@ -68,20 +110,21 @@ export default function CodeEditor({
68
110
} ) ;
69
111
} ;
70
112
71
- const lintOptions : LintOptions = {
72
- esversion : 11 ,
73
- browser : true ,
74
- lastsemic : true ,
75
- asi : true ,
76
- expr : true ,
77
- } ;
113
+ let [ extensions , setExtensions ] = useState < Extension [ ] > ( [ ] ) ;
114
+
115
+ useEffect ( ( ) => {
116
+ codeEditorExtensions [ language ] ?. call ( null ) . then ( setExtensions ) ;
117
+ } , [ language ] ) ;
118
+
119
+ extensions . push ( EditorView . lineWrapping ) ;
120
+
121
+ const ref = useRef < ReactCodeMirrorRef > ( null ) ;
78
122
79
- let extensions = [ lintGutter ( ) ] ;
80
- if ( language === "javascript" ) {
81
- extensions . push ( javascript ( ) , jsLinter ( lintOptions ) ) ;
82
- } else if ( language === "python" ) {
83
- extensions . push ( python ( ) , indentUnit . of ( " " ) ) ;
84
- }
123
+ useEffect ( ( ) => {
124
+ ref . current ?. editor
125
+ ?. querySelector ( ".cm-content" )
126
+ ?. setAttribute ( "data-gramm" , "false" ) ;
127
+ } , [ ref . current ] ) ;
85
128
86
129
return (
87
130
< div className = "gui-input code-editor-wrapper position-relative" >
@@ -91,9 +134,6 @@ export default function CodeEditor({
91
134
tooltipPlacement = { tooltipPlacement }
92
135
/>
93
136
< textarea
94
- data-gramm = "false"
95
- data-gramm_editor = "false"
96
- data-enable-grammarly = "false"
97
137
ref = { inputRef }
98
138
name = { name }
99
139
value = { value }
@@ -102,13 +142,17 @@ export default function CodeEditor({
102
142
} }
103
143
/>
104
144
< CodeMirror
105
- data-gramm = "false"
106
- data-gramm_editor = "false"
107
- data-enable-grammarly = "false"
108
- theme = { dracula }
145
+ ref = { ref }
146
+ theme = { theme ( {
147
+ settings : {
148
+ fontFamily : "monospace" ,
149
+ fontSize : "14px" ,
150
+ } ,
151
+ } ) }
109
152
value = { value }
110
153
onChange = { handleChange }
111
154
extensions = { extensions }
155
+ basicSetup = { { foldGutter : false } }
112
156
{ ...args }
113
157
/>
114
158
</ div >
0 commit comments