Skip to content

Commit 1213a43

Browse files
committed
use more idiomatic rescript bindings
1 parent 5ee2f10 commit 1213a43

File tree

1 file changed

+64
-101
lines changed

1 file changed

+64
-101
lines changed

src/components/CodeMirror.res

Lines changed: 64 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,14 @@ module CM6 = {
9696
type editorView
9797
type compartment
9898
type effect
99-
type transaction
100-
type languageSupport
99+
101100
type keymapSpec
102101

102+
module Extension = {
103+
type t = extension
104+
external fromArray: array<t> => t = "%identity"
105+
}
106+
103107
module Text = {
104108
type t
105109
type line
@@ -111,40 +115,42 @@ module CM6 = {
111115
}
112116

113117
module EditorState = {
114-
@module("@codemirror/state") @scope("EditorState")
115-
external create: {"doc": string, "extensions": array<extension>} => editorState = "create"
118+
type createConfig = {doc: string, extensions: array<extension>}
116119

117-
@module("@codemirror/state") @scope("EditorState") @val
118-
external readOnly: {"of": bool => extension} = "readOnly"
120+
@module("@codemirror/state") @scope("EditorState")
121+
external create: createConfig => editorState = "create"
119122

123+
module ReadOnly = {
124+
@module("@codemirror/state") @scope(("EditorState", "readOnly")) @val
125+
external of_: bool => extension = "of"
126+
}
120127
@get external doc: editorState => Text.t = "doc"
121128
}
122129

123130
module Compartment = {
124131
@module("@codemirror/state") @new
125-
external make: unit => compartment = "Compartment"
126-
127-
@send external of_: (compartment, extension) => extension = "of"
132+
external create: unit => compartment = "Compartment"
133+
@send external make: (compartment, extension) => extension = "of"
128134
@send external reconfigure: (compartment, extension) => effect = "reconfigure"
129135
}
130136

131137
module EditorView = {
138+
type createConfig = {state: editorState, parent: WebAPI.DOMAPI.element}
132139
@module("@codemirror/view") @new
133-
external create: {"state": editorState, "parent": WebAPI.DOMAPI.element} => editorView =
134-
"EditorView"
140+
external create: createConfig => editorView = "EditorView"
135141

136142
@send external destroy: editorView => unit = "destroy"
137143
@get external state: editorView => editorState = "state"
138144
@get external dom: editorView => WebAPI.DOMAPI.htmlElement = "dom"
139145

146+
type change = {from: int, to: int, insert: string}
147+
type dispatchArg = {changes: change}
140148
@send
141-
external dispatch: (
142-
editorView,
143-
{"changes": {"from": int, "to": int, "insert": string}},
144-
) => unit = "dispatch"
149+
external dispatch: (editorView, dispatchArg) => unit = "dispatch"
145150

151+
type dispatchEffectsArg = {effects: effect}
146152
@send
147-
external dispatchEffects: (editorView, {"effects": effect}) => unit = "dispatch"
153+
external dispatchEffects: (editorView, dispatchEffectsArg) => unit = "dispatch"
148154

149155
@module("@codemirror/view") @scope("EditorView") @val
150156
external lineWrapping: extension = "lineWrapping"
@@ -169,8 +175,8 @@ module CM6 = {
169175
@get external view: update => editorView = "view"
170176
@get external docChanged: update => bool = "docChanged"
171177

172-
@module("@codemirror/view") @scope("EditorView")
173-
external of_: (update => unit) => extension = "updateListener"
178+
@module("@codemirror/view") @scope(("EditorView", "updateListener"))
179+
external of_: (update => unit) => extension = "of"
174180
}
175181
}
176182

@@ -197,16 +203,18 @@ module CM6 = {
197203
@module("@codemirror/language")
198204
external bracketMatching: unit => extension = "bracketMatching"
199205

206+
type syntaxConfig = {fallback: bool}
207+
200208
@module("@codemirror/language")
201-
external syntaxHighlighting: (extension, {"fallback": bool}) => extension = "syntaxHighlighting"
209+
external syntaxHighlighting: (extension, syntaxConfig) => extension = "syntaxHighlighting"
202210

203-
@module("@lezer/highlight") @val
211+
@module("@codemirror/language") @val
204212
external defaultHighlightStyle: extension = "defaultHighlightStyle"
205213
}
206214

207215
module Keymap = {
208-
@module("@codemirror/state")
209-
external of_: array<keymapSpec> => extension = "keymap"
216+
@module("@codemirror/view") @scope("keymap") @val
217+
external of_: array<keymapSpec> => extension = "of"
210218
}
211219

212220
module Lint = {
@@ -228,7 +236,7 @@ module CM6 = {
228236

229237
module JavaScript = {
230238
@module("@codemirror/lang-javascript")
231-
external javascript: unit => languageSupport = "javascript"
239+
external javascript: unit => extension = "javascript"
232240
}
233241

234242
module Vim = {
@@ -237,11 +245,11 @@ module CM6 = {
237245
}
238246

239247
module CustomLanguages = {
240-
@module("../plugins/cm6-rescript-mode") @val
241-
external rescriptLanguage: languageSupport = "rescriptLanguage"
248+
@module("../../plugins/cm6-rescript-mode.js") @val
249+
external rescriptLanguage: extension = "rescriptLanguage"
242250

243-
@module("../plugins/cm6-reason-mode") @val
244-
external reasonLanguage: languageSupport = "reasonLanguage"
251+
@module("../../plugins/cm6-reason-mode.js") @val
252+
external reasonLanguage: extension = "reasonLanguage"
245253
}
246254
}
247255

@@ -268,7 +276,7 @@ type editorConfig = {
268276
maxHeight: option<string>,
269277
}
270278

271-
let createLinterExtension = (errors: array<Error.t>, lintConf: CM6.compartment): CM6.extension => {
279+
let createLinterExtension = (errors: array<Error.t>): CM6.extension => {
272280
let linterSource = (view: CM6.editorView): array<CM6.Lint.diagnostic> => {
273281
if Array.length(errors) === 0 {
274282
[]
@@ -296,7 +304,7 @@ let createLinterExtension = (errors: array<Error.t>, lintConf: CM6.compartment):
296304
message: err.text,
297305
}
298306

299-
Array.push(diagnostics, diagnostic)->ignore
307+
Array.push(diagnostics, diagnostic)
300308
} catch {
301309
| _ => Console.warn("Error creating lint marker")
302310
}
@@ -306,7 +314,7 @@ let createLinterExtension = (errors: array<Error.t>, lintConf: CM6.compartment):
306314
}
307315
}
308316

309-
CM6.Compartment.of_(lintConf, CM6.Lint.linter(linterSource))
317+
CM6.Lint.linter(linterSource)
310318
}
311319

312320
let createEditor = (config: editorConfig): editorInstance => {
@@ -318,41 +326,41 @@ let createEditor = (config: editorConfig): editorInstance => {
318326
}
319327

320328
// Setup compartments for dynamic config
321-
let languageConf = CM6.Compartment.make()
322-
let readOnlyConf = CM6.Compartment.make()
323-
let keymapConf = CM6.Compartment.make()
324-
let lintConf = CM6.Compartment.make()
329+
let languageConf = CM6.Compartment.create()
330+
let readOnlyConf = CM6.Compartment.create()
331+
let keymapConf = CM6.Compartment.create()
332+
let lintConf = CM6.Compartment.create()
325333

326334
// Basic extensions
327335
let extensions = [
328-
CM6.Compartment.of_(languageConf, (Obj.magic(language): CM6.extension)),
336+
CM6.Compartment.make(languageConf, (language: CM6.extension)),
329337
CM6.Commands.history(),
330338
CM6.EditorView.drawSelection(),
331339
CM6.EditorView.dropCursor(),
332340
CM6.Language.bracketMatching(),
333341
CM6.Search.highlightSelectionMatches(),
334-
CM6.Language.syntaxHighlighting(CM6.Language.defaultHighlightStyle, {"fallback": true}),
342+
CM6.Language.syntaxHighlighting(CM6.Language.defaultHighlightStyle, {fallback: true}),
335343
]
336344

337345
// Add optional extensions
338346
if config.lineNumbers {
339-
Array.push(extensions, CM6.EditorView.lineNumbers())->ignore
340-
Array.push(extensions, CM6.EditorView.highlightActiveLineGutter())->ignore
347+
Array.push(extensions, CM6.EditorView.lineNumbers())
348+
Array.push(extensions, CM6.EditorView.highlightActiveLineGutter())
341349
}
342350

343351
if !config.readOnly {
344-
Array.push(extensions, CM6.EditorView.highlightActiveLine())->ignore
352+
Array.push(extensions, CM6.EditorView.highlightActiveLine())
345353
}
346354

347355
if config.lineWrapping {
348-
Array.push(extensions, CM6.EditorView.lineWrapping)->ignore
356+
Array.push(extensions, CM6.EditorView.lineWrapping)
349357
}
350358

351359
// Add readonly conf
352360
Array.push(
353361
extensions,
354-
CM6.Compartment.of_(readOnlyConf, CM6.EditorState.readOnly["of"](config.readOnly)),
355-
)->ignore
362+
CM6.Compartment.make(readOnlyConf, CM6.EditorState.ReadOnly.of_(config.readOnly)),
363+
)
356364

357365
// Add keymap
358366
let keymapExtension = if config.keyMap === "vim" {
@@ -362,17 +370,16 @@ let createEditor = (config: editorConfig): editorInstance => {
362370
let searchKeymapExt = CM6.Keymap.of_(CM6.Search.searchKeymap)
363371
// Return vim extension combined with keymap extensions
364372
// We need to wrap them in an array and convert to extension
365-
let combined = Array.concat([vimExt], [defaultKeymapExt, historyKeymapExt, searchKeymapExt])
366-
(Obj.magic(combined): CM6.extension)
373+
/* combine extensions into a JS array value */
374+
[vimExt, defaultKeymapExt, historyKeymapExt, searchKeymapExt]->CM6.Extension.fromArray
367375
} else {
368376
let defaultKeymapExt = CM6.Keymap.of_(CM6.Commands.defaultKeymap)
369377
let historyKeymapExt = CM6.Keymap.of_(CM6.Commands.historyKeymap)
370378
let searchKeymapExt = CM6.Keymap.of_(CM6.Search.searchKeymap)
371-
// Return combined keymap extensions
372-
let combined = [defaultKeymapExt, historyKeymapExt, searchKeymapExt]
373-
(Obj.magic(combined): CM6.extension)
379+
// Return combined keymap extensions as a JS array
380+
[defaultKeymapExt, historyKeymapExt, searchKeymapExt]->CM6.Extension.fromArray
374381
}
375-
Array.push(extensions, CM6.Compartment.of_(keymapConf, keymapExtension))->ignore
382+
Array.push(extensions, CM6.Compartment.make(keymapConf, keymapExtension))
376383

377384
// Add change listener
378385
switch config.onChange {
@@ -384,24 +391,18 @@ let createEditor = (config: editorConfig): editorInstance => {
384391
onChange(newValue)
385392
}
386393
})
387-
Array.push(extensions, updateListener)->ignore
394+
Array.push(extensions, updateListener)
388395
| None => ()
389396
}
390397

391-
// Add linter for errors
392-
Array.push(extensions, createLinterExtension(config.errors, lintConf))->ignore
393-
Array.push(extensions, CM6.Lint.lintGutter())->ignore
398+
// Add linter for errors (wrap the raw linter extension in the compartment)
399+
Array.push(extensions, CM6.Compartment.make(lintConf, createLinterExtension(config.errors)))
400+
Array.push(extensions, CM6.Lint.lintGutter())
394401

395402
// Create editor
396-
let state = CM6.EditorState.create({
397-
"doc": config.initialValue,
398-
"extensions": extensions,
399-
})
403+
let state = CM6.EditorState.create({doc: config.initialValue, extensions})
400404

401-
let view = CM6.EditorView.create({
402-
"state": state,
403-
"parent": config.parent,
404-
})
405+
let view = CM6.EditorView.create({state, parent: config.parent})
405406

406407
// Apply custom styling
407408
let dom = CM6.EditorView.dom(view)
@@ -429,13 +430,7 @@ let editorSetValue = (instance: editorInstance, value: string): unit => {
429430
let doc = CM6.EditorView.state(instance.view)->CM6.EditorState.doc
430431
CM6.EditorView.dispatch(
431432
instance.view,
432-
{
433-
"changes": {
434-
"from": 0,
435-
"to": CM6.Text.toString(doc)->String.length,
436-
"insert": value,
437-
},
438-
},
433+
{changes: {from: 0, to: CM6.Text.toString(doc)->String.length, insert: value}},
439434
)
440435
}
441436

@@ -456,47 +451,15 @@ let editorSetMode = (instance: editorInstance, mode: string): unit => {
456451

457452
CM6.EditorView.dispatchEffects(
458453
instance.view,
459-
{
460-
"effects": CM6.Compartment.reconfigure(
461-
instance.languageConf,
462-
(Obj.magic(language): CM6.extension),
463-
),
464-
},
465-
)
466-
}
467-
468-
let editorSetKeyMap = (instance: editorInstance, keyMap: string): unit => {
469-
let keymapExtension = if keyMap === "vim" {
470-
let vimExt = CM6.Vim.vim()
471-
let defaultKeymapExt = CM6.Keymap.of_(CM6.Commands.defaultKeymap)
472-
let historyKeymapExt = CM6.Keymap.of_(CM6.Commands.historyKeymap)
473-
let searchKeymapExt = CM6.Keymap.of_(CM6.Search.searchKeymap)
474-
let combined = Array.concat([vimExt], [defaultKeymapExt, historyKeymapExt, searchKeymapExt])
475-
(Obj.magic(combined): CM6.extension)
476-
} else {
477-
let defaultKeymapExt = CM6.Keymap.of_(CM6.Commands.defaultKeymap)
478-
let historyKeymapExt = CM6.Keymap.of_(CM6.Commands.historyKeymap)
479-
let searchKeymapExt = CM6.Keymap.of_(CM6.Search.searchKeymap)
480-
let combined = [defaultKeymapExt, historyKeymapExt, searchKeymapExt]
481-
(Obj.magic(combined): CM6.extension)
482-
}
483-
484-
CM6.EditorView.dispatchEffects(
485-
instance.view,
486-
{
487-
"effects": CM6.Compartment.reconfigure(instance.keymapConf, keymapExtension),
488-
},
454+
{effects: CM6.Compartment.reconfigure(instance.languageConf, (language: CM6.extension))},
489455
)
490456
}
491457

492458
let editorSetErrors = (instance: editorInstance, errors: array<Error.t>): unit => {
493459
CM6.EditorView.dispatchEffects(
494460
instance.view,
495461
{
496-
"effects": CM6.Compartment.reconfigure(
497-
instance.lintConf,
498-
createLinterExtension(errors, instance.lintConf),
499-
),
462+
effects: CM6.Compartment.reconfigure(instance.lintConf, createLinterExtension(errors)),
500463
},
501464
)
502465
}

0 commit comments

Comments
 (0)