Skip to content

Commit dae3d9b

Browse files
committed
add back hover hints
1 parent 8667184 commit dae3d9b

File tree

3 files changed

+163
-74
lines changed

3 files changed

+163
-74
lines changed

src/Playground.res

Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,68 @@ let make = (~bundleBaseUrl: string, ~versions: array<string>) => {
16971697
Some(editorInstance),
16981698
) =>
16991699
CodeMirror.editorSetValue(editorInstance, code)
1700+
| (
1701+
Ready({
1702+
result: Comp(Fail(
1703+
SyntaxErr(locMsgs)
1704+
| TypecheckErr(locMsgs)
1705+
| OtherErr(locMsgs),
1706+
)),
1707+
}),
1708+
Some(editorInstance),
1709+
) =>
1710+
CodeMirror.editorSetErrors(
1711+
editorInstance,
1712+
Array.map(locMsgs, locMsgToCmError(~kind=#Error, ...)),
1713+
)
1714+
| (Ready({result: Comp(Fail(WarningErr(warnings)))}), Some(editorInstance)) =>
1715+
CodeMirror.editorSetErrors(
1716+
editorInstance,
1717+
Array.map(warnings, warning => {
1718+
switch warning {
1719+
| Api.Warning.Warn({details})
1720+
| WarnErr({details}) =>
1721+
locMsgToCmError(~kind=#Warning, details)
1722+
}
1723+
}),
1724+
)
1725+
| (Ready({result: Comp(Success({warnings, typeHints}))}), Some(editorInstance)) =>
1726+
CodeMirror.editorSetErrors(
1727+
editorInstance,
1728+
Array.map(warnings, warning => {
1729+
switch warning {
1730+
| Api.Warning.Warn({details})
1731+
| WarnErr({details}) =>
1732+
locMsgToCmError(~kind=#Warning, details)
1733+
}
1734+
}),
1735+
)
1736+
CodeMirror.editorSetHoverHints(
1737+
editorInstance,
1738+
Array.map(typeHints, hint => {
1739+
switch hint {
1740+
| TypeDeclaration({start, end, hint})
1741+
| Binding({start, end, hint})
1742+
| CoreType({start, end, hint})
1743+
| Expression({start, end, hint}) => {
1744+
CodeMirror.HoverHint.start: {
1745+
line: start.line,
1746+
col: start.col,
1747+
},
1748+
end: {
1749+
line: end.line,
1750+
col: end.col,
1751+
},
1752+
hint,
1753+
}
1754+
}
1755+
}),
1756+
)
1757+
| (Ready({result: Conv(Fail({details}))}), Some(editorInstance)) =>
1758+
CodeMirror.editorSetErrors(
1759+
editorInstance,
1760+
Array.map(details, locMsgToCmError(~kind=#Error, ...)),
1761+
)
17001762
| _ => ()
17011763
}
17021764
None
@@ -1844,64 +1906,6 @@ let make = (~bundleBaseUrl: string, ~versions: array<string>) => {
18441906
)
18451907
}, [layout])
18461908

1847-
let cmErrors = switch compilerState {
1848-
| Ready({result}) =>
1849-
switch result {
1850-
| FinalResult.Comp(Fail(result)) =>
1851-
switch result {
1852-
| SyntaxErr(locMsgs)
1853-
| TypecheckErr(locMsgs)
1854-
| OtherErr(locMsgs) =>
1855-
Array.map(locMsgs, locMsgToCmError(~kind=#Error, ...))
1856-
| WarningErr(warnings) =>
1857-
Array.map(warnings, warning => {
1858-
switch warning {
1859-
| Api.Warning.Warn({details})
1860-
| WarnErr({details}) =>
1861-
locMsgToCmError(~kind=#Warning, details)
1862-
}
1863-
})
1864-
| WarningFlagErr(_) => []
1865-
}
1866-
| Comp(Success({warnings})) =>
1867-
Array.map(warnings, warning => {
1868-
switch warning {
1869-
| Api.Warning.Warn({details})
1870-
| WarnErr({details}) =>
1871-
locMsgToCmError(~kind=#Warning, details)
1872-
}
1873-
})
1874-
| Conv(Fail({details})) => Array.map(details, locMsgToCmError(~kind=#Error, ...))
1875-
| Comp(_)
1876-
| Conv(_)
1877-
| Nothing => []
1878-
}
1879-
| _ => []
1880-
}
1881-
1882-
let cmHoverHints = switch compilerState {
1883-
| Ready({result: FinalResult.Comp(Success({typeHints}))}) =>
1884-
Array.map(typeHints, hint => {
1885-
switch hint {
1886-
| TypeDeclaration({start, end, hint})
1887-
| Binding({start, end, hint})
1888-
| CoreType({start, end, hint})
1889-
| Expression({start, end, hint}) => {
1890-
CodeMirror.HoverHint.start: {
1891-
line: start.line,
1892-
col: start.col,
1893-
},
1894-
end: {
1895-
line: end.line,
1896-
col: end.col,
1897-
},
1898-
hint,
1899-
}
1900-
}
1901-
})
1902-
| _ => []
1903-
}
1904-
19051909
let (currentTab, setCurrentTab) = React.useState(_ => JavaScript)
19061910

19071911
let disabled = false

src/components/CodeMirror.res

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ module KeyMap = {
2525
}
2626
}
2727

28+
module Side = {
29+
@@warning("-37")
30+
type t =
31+
| @as(-1) BeforePointer
32+
| @as(1) AfterPointer
33+
}
34+
2835
module Error = {
2936
type kind = [#Error | #Warning]
3037

@@ -66,14 +73,21 @@ module CM6 = {
6673
external fromArray: array<t> => t = "%identity"
6774
}
6875

76+
module Line = {
77+
type t = {
78+
from: int,
79+
@as("to") to_: int,
80+
number: int,
81+
text: string,
82+
length: int,
83+
}
84+
}
85+
6986
module Text = {
70-
type t
71-
type line
87+
type t = {lines: int}
7288
@send external toString: t => string = "toString"
73-
@get external lines: t => int = "lines"
74-
@send external line: (t, int) => line = "line"
75-
@get external lineFrom: line => int = "from"
76-
@get external lineLength: line => int = "length"
89+
@send external line: (t, int) => Line.t = "line"
90+
@send external lineAt: (t, int) => Line.t = "lineAt"
7791
}
7892

7993
module EditorSelection = {
@@ -108,6 +122,21 @@ module CM6 = {
108122
}
109123

110124
module EditorView = {
125+
module Tooltip = {
126+
module View = {
127+
type t = {dom: WebAPI.DOMAPI.element, offset?: {x: int, y: int}}
128+
}
129+
type t = {
130+
pos: int,
131+
end?: int,
132+
create: editorView => View.t,
133+
above?: bool,
134+
strictSide?: bool,
135+
arrow?: bool,
136+
clip?: bool,
137+
}
138+
}
139+
111140
type createConfig = {state: editorState, parent: WebAPI.DOMAPI.element}
112141
@module("@codemirror/view") @new
113142
external create: createConfig => editorView = "EditorView"
@@ -146,6 +175,10 @@ module CM6 = {
146175
@module("@codemirror/view")
147176
external dropCursor: unit => extension = "dropCursor"
148177

178+
@module("@codemirror/view")
179+
external hoverTooltip: ((editorView, int, Side.t) => null<Tooltip.t>) => extension =
180+
"hoverTooltip"
181+
149182
module UpdateListener = {
150183
type update
151184
@get external view: update => editorView = "view"
@@ -449,10 +482,16 @@ module CM6 = {
449482
}
450483

451484
module Lint = {
485+
type severity =
486+
| @as("error") Error
487+
// | @as("hint") Hint
488+
// | @as("info") Info
489+
| @as("warning") Warning
490+
452491
type diagnostic = {
453492
from: int,
454493
to: int,
455-
severity: string,
494+
severity: severity,
456495
message: string,
457496
}
458497

@@ -487,6 +526,7 @@ type editorInstance = {
487526
readOnlyConf: CM6.compartment,
488527
keymapConf: CM6.compartment,
489528
lintConf: CM6.compartment,
529+
hintConf: CM6.compartment,
490530
}
491531

492532
type editorConfig = {
@@ -514,21 +554,24 @@ let createLinterExtension = (errors: array<Error.t>): CM6.extension => {
514554

515555
Array.forEach(errors, err => {
516556
try {
517-
// Error row/endRow are 1-based (same as CodeMirror 5)
518-
// Error column/endColumn are 0-based (same as CodeMirror 5)
519-
let fromLine = Math.Int.max(1, Math.Int.min(err.row, CM6.Text.lines(doc)))
520-
let toLine = Math.Int.max(1, Math.Int.min(err.endRow, CM6.Text.lines(doc)))
557+
// Error row/endRow are 1-based (same as CodeMirror 6)
558+
// Error column/endColumn are 0-based (same as CodeMirror 6)
559+
let fromLine = Math.Int.max(1, Math.Int.min(err.row, doc.lines))
560+
let toLine = Math.Int.max(1, Math.Int.min(err.endRow, doc.lines))
521561

522562
let startLine = CM6.Text.line(doc, fromLine)
523563
let endLine = CM6.Text.line(doc, toLine)
524564

525-
let fromCol = Math.Int.max(0, Math.Int.min(err.column, CM6.Text.lineLength(startLine)))
526-
let toCol = Math.Int.max(0, Math.Int.min(err.endColumn, CM6.Text.lineLength(endLine)))
565+
let fromCol = Math.Int.max(0, Math.Int.min(err.column, startLine.length))
566+
let toCol = Math.Int.max(0, Math.Int.min(err.endColumn, endLine.length))
527567

528568
let diagnostic = {
529-
CM6.Lint.from: CM6.Text.lineFrom(startLine) + fromCol,
530-
to: CM6.Text.lineFrom(endLine) + toCol,
531-
severity: err.kind === #Error ? "error" : "warning",
569+
CM6.Lint.from: startLine.from + fromCol,
570+
to: endLine.from + toCol,
571+
severity: switch err.kind {
572+
| #Error => Error
573+
| #Warning => Warning
574+
},
532575
message: err.text,
533576
}
534577

@@ -545,6 +588,32 @@ let createLinterExtension = (errors: array<Error.t>): CM6.extension => {
545588
CM6.Lint.linter(linterSource)
546589
}
547590

591+
let createHoverHintExtension = (hoverHints: array<HoverHint.t>) => {
592+
CM6.EditorView.hoverTooltip((view, pos, _side) => {
593+
let doc = view->CM6.EditorView.state->CM6.EditorState.doc
594+
let {number: line, from} = doc->CM6.Text.lineAt(pos)
595+
let col = pos - from
596+
let found = hoverHints->Array.find(({start, end}) => {
597+
line >= start.line && line <= end.line && col >= start.col && col <= end.col
598+
})
599+
switch found {
600+
| Some({hint, start, end}) =>
601+
let pos = CM6.Text.line(doc, start.line).from + start.col
602+
let end = CM6.Text.line(doc, end.line).from + end.col
603+
let dom = WebAPI.Global.document->WebAPI.Document.createElement("div")
604+
dom.textContent = Value(hint)
605+
dom.className = "p-1 border"
606+
Value({
607+
pos,
608+
end,
609+
above: true,
610+
create: _view => {dom: dom},
611+
})
612+
| None => Null
613+
}
614+
})
615+
}
616+
548617
module ReScript = {
549618
@module("@tsnobip/rescript-lezer")
550619
external parser: CM6.Language.LRParser.t = "parser"
@@ -589,6 +658,7 @@ let createEditor = (config: editorConfig): editorInstance => {
589658
let readOnlyConf = CM6.Compartment.create()
590659
let keymapConf = CM6.Compartment.create()
591660
let lintConf = CM6.Compartment.create()
661+
let hintConf = CM6.Compartment.create()
592662

593663
// Basic extensions
594664
let extensions = [
@@ -651,6 +721,10 @@ let createEditor = (config: editorConfig): editorInstance => {
651721

652722
// Add linter for errors (wrap the raw linter extension in the compartment)
653723
Array.push(extensions, CM6.Compartment.make(lintConf, createLinterExtension(config.errors)))
724+
Array.push(
725+
extensions,
726+
CM6.Compartment.make(hintConf, createHoverHintExtension(config.hoverHints)),
727+
)
654728
Array.push(extensions, CM6.Lint.lintGutter())
655729

656730
// Create editor
@@ -677,6 +751,7 @@ let createEditor = (config: editorConfig): editorInstance => {
677751
readOnlyConf,
678752
keymapConf,
679753
lintConf,
754+
hintConf,
680755
}
681756
}
682757

@@ -798,3 +873,12 @@ let editorSetErrors = (instance: editorInstance, errors: array<Error.t>): unit =
798873
},
799874
)
800875
}
876+
877+
let editorSetHoverHints = (instance: editorInstance, hints: array<HoverHint.t>): unit => {
878+
CM6.EditorView.dispatchEffects(
879+
instance.view,
880+
{
881+
effects: CM6.Compartment.reconfigure(instance.hintConf, createHoverHintExtension(hints)),
882+
},
883+
)
884+
}

src/components/CodeMirror.resi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ let editorSetKeyMap: (editorInstance, KeyMap.t) => unit
5555
let editorDestroy: editorInstance => unit
5656
let editorSetValue: (editorInstance, string) => unit
5757
let editorGetValue: editorInstance => string
58+
let editorSetHoverHints: (editorInstance, array<HoverHint.t>) => unit

0 commit comments

Comments
 (0)