Skip to content

Commit b462e3b

Browse files
committed
Add syntax doc command
add syntax doc command change syntax_doc output from string to record type parse record to extract and display different fields correctly lint code refactor code add formatting functions and check if syn_doc is activated check if syntax_doc is activated in ocamllsp env variables refactor for proper types include syntax documentation in configuation data check if feature is activated from ocaml.server remove redundant code lint add version refactor code and lint refactor code and lint let merlin work only if syntax doc is activated lint change from italics to code pill lint update changelog update documentation remove configuration via environment variables update docs syntax highlighting for code block make syntax highlighter required add constraint for most recent version of merlin-lib upgrade merlin-lib to latest version add syntax doc to ppx expect Write tests for syntax doc command linting helper function for positions Update README.md Co-authored-by: Ulysse <5031221+voodoos@users.noreply.github.com> Update README.md Co-authored-by: Ulysse <5031221+voodoos@users.noreply.github.com> Update ocaml-lsp-server/src/document.ml Co-authored-by: Ulysse <5031221+voodoos@users.noreply.github.com> Update ocaml-lsp-server/src/document.ml Co-authored-by: Ulysse <5031221+voodoos@users.noreply.github.com> 80 char per line limit use better descriptive function name adjust formatting fix bug fix bug
1 parent ad20957 commit b462e3b

File tree

11 files changed

+367
-24
lines changed

11 files changed

+367
-24
lines changed

CHANGES.md

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
- Support folding of `ifthenelse` expressions (#1031)
1010

11+
- Includes a new optional/configurable option to toggle syntax documentation. If
12+
toggled on, allows display of sytax documentation on hover tooltips. Can be
13+
controlled via environment variables and by GUI for VS code. (#1218)
14+
1115
# 1.17.0
1216

1317
## Fixes

README.md

+30
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,36 @@ of the value needs to be non-polymorphic to construct a meaningful value.
304304
Tip (for VS Code OCaml Platform users): You can construct a value using a keybinding
305305
<kbd>Alt</kbd>+<kbd>C</kbd> or on MacOS <kbd>Option</kbd>+<kbd>C</kbd>
306306

307+
#### Syntax Documentation
308+
309+
> since OCaml-LSP 1.18.0
310+
311+
OCaml-LSP can display documentation about the node under the cursor when
312+
the user hovers over some OCaml code. For example, hovering over the code
313+
snippet below will display some information about what the syntax
314+
is:
315+
316+
```ocaml
317+
type point = {x: int; y: int}
318+
```
319+
Hovering over the above will
320+
display:
321+
```
322+
ocaml type point = { x : int; y : int }
323+
syntax Record type:
324+
Allows you to define variants with a fixed set of fields, and all of the
325+
constructors for a record variant type must have the same fields. See
326+
Manual
327+
```
328+
The documentation is gotten from the Merlin engine which receives
329+
the nodes under the cursor and infers what the syntax may be about, and
330+
displays the required information along with links to the manual for further
331+
reading.
332+
333+
Syntax Documentation is an optional feature and can be activated by
334+
using the LSP config system with the key called `syntaxDocumentation` and can
335+
be enabled via setting it to `{ enable: true }`.
336+
307337
## Debugging
308338

309339
If you use Visual Studio Code, please see OCaml Platform extension

dune-project

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ possible and does not make any assumptions about IO.
6767
(ocamlformat-rpc-lib (>= 0.21.0))
6868
(odoc :with-doc)
6969
(ocaml (and (>= 4.14) (< 5.2)))
70-
(merlin-lib (and (>= 4.9) (< 5.0)))))
70+
(merlin-lib (and (>= 4.14) (< 5.0)))))
7171

7272
(package
7373
(name jsonrpc)

ocaml-lsp-server.opam

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ depends: [
4343
"ocamlformat-rpc-lib" {>= "0.21.0"}
4444
"odoc" {with-doc}
4545
"ocaml" {>= "4.14" & < "5.2"}
46-
"merlin-lib" {>= "4.9" & < "5.0"}
46+
"merlin-lib" {>= "4.14" & < "5.0"}
4747
]
4848
dev-repo: "git+https://github.com/ocaml/ocaml-lsp.git"
4949
build: [

ocaml-lsp-server/docs/ocamllsp/config.md

+7
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,12 @@ interface config {
2828
* @since 1.18
2929
*/
3030
duneDiagnostics: { enable : boolean }
31+
32+
/**
33+
* Enable/Disable Syntax Documentation
34+
* @default false
35+
* @since 1.18
36+
*/
37+
syntaxDocumentation: { enable : boolean }
3138
}
3239
```

ocaml-lsp-server/src/config_data.ml

+112-4
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,80 @@ module DuneDiagnostics = struct
315315
[@@@end]
316316
end
317317

318+
module SyntaxDocumentation = struct
319+
type t = { enable : bool [@default false] }
320+
[@@deriving_inline yojson] [@@yojson.allow_extra_fields]
321+
322+
let _ = fun (_ : t) -> ()
323+
324+
let t_of_yojson =
325+
(let _tp_loc =
326+
"ocaml-lsp-server/src/config_data.ml.SyntaxDocumentation.t"
327+
in
328+
function
329+
| `Assoc field_yojsons as yojson -> (
330+
let enable_field = ref Ppx_yojson_conv_lib.Option.None
331+
and duplicates = ref []
332+
and extra = ref [] in
333+
let rec iter = function
334+
| (field_name, _field_yojson) :: tail ->
335+
(match field_name with
336+
| "enable" -> (
337+
match Ppx_yojson_conv_lib.( ! ) enable_field with
338+
| Ppx_yojson_conv_lib.Option.None ->
339+
let fvalue = bool_of_yojson _field_yojson in
340+
enable_field := Ppx_yojson_conv_lib.Option.Some fvalue
341+
| Ppx_yojson_conv_lib.Option.Some _ ->
342+
duplicates := field_name :: Ppx_yojson_conv_lib.( ! ) duplicates)
343+
| _ -> ());
344+
iter tail
345+
| [] -> ()
346+
in
347+
iter field_yojsons;
348+
match Ppx_yojson_conv_lib.( ! ) duplicates with
349+
| _ :: _ ->
350+
Ppx_yojson_conv_lib.Yojson_conv_error.record_duplicate_fields
351+
_tp_loc
352+
(Ppx_yojson_conv_lib.( ! ) duplicates)
353+
yojson
354+
| [] -> (
355+
match Ppx_yojson_conv_lib.( ! ) extra with
356+
| _ :: _ ->
357+
Ppx_yojson_conv_lib.Yojson_conv_error.record_extra_fields
358+
_tp_loc
359+
(Ppx_yojson_conv_lib.( ! ) extra)
360+
yojson
361+
| [] ->
362+
let enable_value = Ppx_yojson_conv_lib.( ! ) enable_field in
363+
{ enable =
364+
(match enable_value with
365+
| Ppx_yojson_conv_lib.Option.None -> false
366+
| Ppx_yojson_conv_lib.Option.Some v -> v)
367+
}))
368+
| _ as yojson ->
369+
Ppx_yojson_conv_lib.Yojson_conv_error.record_list_instead_atom
370+
_tp_loc
371+
yojson
372+
: Ppx_yojson_conv_lib.Yojson.Safe.t -> t)
373+
374+
let _ = t_of_yojson
375+
376+
let yojson_of_t =
377+
(function
378+
| { enable = v_enable } ->
379+
let bnds : (string * Ppx_yojson_conv_lib.Yojson.Safe.t) list = [] in
380+
let bnds =
381+
let arg = yojson_of_bool v_enable in
382+
("enable", arg) :: bnds
383+
in
384+
`Assoc bnds
385+
: t -> Ppx_yojson_conv_lib.Yojson.Safe.t)
386+
387+
let _ = yojson_of_t
388+
389+
[@@@end]
390+
end
391+
318392
type t =
319393
{ codelens : Lens.t Json.Nullable_option.t
320394
[@default None] [@yojson_drop_default ( = )]
@@ -324,6 +398,10 @@ type t =
324398
[@key "inlayHints"] [@default None] [@yojson_drop_default ( = )]
325399
; dune_diagnostics : DuneDiagnostics.t Json.Nullable_option.t
326400
[@key "duneDiagnostics"] [@default None] [@yojson_drop_default ( = )]
401+
; syntax_documentation : SyntaxDocumentation.t Json.Nullable_option.t
402+
[@key "syntaxDocumentation"]
403+
[@default None]
404+
[@yojson_drop_default ( = )]
327405
}
328406
[@@deriving_inline yojson] [@@yojson.allow_extra_fields]
329407

@@ -337,6 +415,7 @@ let t_of_yojson =
337415
and extended_hover_field = ref Ppx_yojson_conv_lib.Option.None
338416
and inlay_hints_field = ref Ppx_yojson_conv_lib.Option.None
339417
and dune_diagnostics_field = ref Ppx_yojson_conv_lib.Option.None
418+
and syntax_documentation_field = ref Ppx_yojson_conv_lib.Option.None
340419
and duplicates = ref []
341420
and extra = ref [] in
342421
let rec iter = function
@@ -362,6 +441,17 @@ let t_of_yojson =
362441
extended_hover_field := Ppx_yojson_conv_lib.Option.Some fvalue
363442
| Ppx_yojson_conv_lib.Option.Some _ ->
364443
duplicates := field_name :: Ppx_yojson_conv_lib.( ! ) duplicates)
444+
| "syntaxDocumentation" -> (
445+
match Ppx_yojson_conv_lib.( ! ) syntax_documentation_field with
446+
| Ppx_yojson_conv_lib.Option.None ->
447+
let fvalue =
448+
Json.Nullable_option.t_of_yojson
449+
SyntaxDocumentation.t_of_yojson
450+
_field_yojson
451+
in
452+
syntax_documentation_field := Ppx_yojson_conv_lib.Option.Some fvalue
453+
| Ppx_yojson_conv_lib.Option.Some _ ->
454+
duplicates := field_name :: Ppx_yojson_conv_lib.( ! ) duplicates)
365455
| "inlayHints" -> (
366456
match Ppx_yojson_conv_lib.( ! ) inlay_hints_field with
367457
| Ppx_yojson_conv_lib.Option.None ->
@@ -384,7 +474,7 @@ let t_of_yojson =
384474
dune_diagnostics_field := Ppx_yojson_conv_lib.Option.Some fvalue
385475
| Ppx_yojson_conv_lib.Option.Some _ ->
386476
duplicates := field_name :: Ppx_yojson_conv_lib.( ! ) duplicates)
387-
| _ -> ());
477+
| _ -> ());
388478
iter tail
389479
| [] -> ()
390480
in
@@ -406,11 +496,13 @@ let t_of_yojson =
406496
let ( codelens_value
407497
, extended_hover_value
408498
, inlay_hints_value
409-
, dune_diagnostics_value ) =
499+
, dune_diagnostics_value
500+
, syntax_documentation_value ) =
410501
( Ppx_yojson_conv_lib.( ! ) codelens_field
411502
, Ppx_yojson_conv_lib.( ! ) extended_hover_field
412503
, Ppx_yojson_conv_lib.( ! ) inlay_hints_field
413-
, Ppx_yojson_conv_lib.( ! ) dune_diagnostics_field )
504+
, Ppx_yojson_conv_lib.( ! ) dune_diagnostics_field
505+
, Ppx_yojson_conv_lib.( ! ) syntax_documentation_field )
414506
in
415507
{ codelens =
416508
(match codelens_value with
@@ -428,6 +520,10 @@ let t_of_yojson =
428520
(match dune_diagnostics_value with
429521
| Ppx_yojson_conv_lib.Option.None -> None
430522
| Ppx_yojson_conv_lib.Option.Some v -> v)
523+
; syntax_documentation =
524+
(match syntax_documentation_value with
525+
| Ppx_yojson_conv_lib.Option.None -> None
526+
| Ppx_yojson_conv_lib.Option.Some v -> v)
431527
}))
432528
| _ as yojson ->
433529
Ppx_yojson_conv_lib.Yojson_conv_error.record_list_instead_atom
@@ -443,7 +539,8 @@ let yojson_of_t =
443539
; extended_hover = v_extended_hover
444540
; inlay_hints = v_inlay_hints
445541
; dune_diagnostics = v_dune_diagnostics
446-
} ->
542+
; syntax_documentation =
543+
v_syntax_documentation } ->
447544
let bnds : (string * Ppx_yojson_conv_lib.Yojson.Safe.t) list = [] in
448545
let bnds =
449546
if None = v_dune_diagnostics then bnds
@@ -465,6 +562,16 @@ let yojson_of_t =
465562
let bnd = ("inlayHints", arg) in
466563
bnd :: bnds
467564
in
565+
let bnds =
566+
if None = v_syntax_documentation then bnds
567+
else
568+
let arg =
569+
(Json.Nullable_option.yojson_of_t SyntaxDocumentation.yojson_of_t)
570+
v_syntax_documentation
571+
in
572+
let bnd = ("syntaxDocumentation", arg) in
573+
bnd :: bnds
574+
in
468575
let bnds =
469576
if None = v_extended_hover then bnds
470577
else
@@ -497,4 +604,5 @@ let default =
497604
; inlay_hints =
498605
Some { hint_pattern_variables = false; hint_let_bindings = false }
499606
; dune_diagnostics = Some { enable = true }
607+
; syntax_documentation = Some { enable = false }
500608
}

ocaml-lsp-server/src/document.ml

+17-2
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,23 @@ module Merlin = struct
281281
| `Found s | `Builtin s -> Some s
282282
| _ -> None
283283

284+
let syntax_doc pipeline pos =
285+
let res =
286+
let command = Query_protocol.Syntax_document pos in
287+
Query_commands.dispatch pipeline command
288+
in
289+
match res with
290+
| `Found s -> Some s
291+
| `No_documentation -> None
292+
284293
type type_enclosing =
285294
{ loc : Loc.t
286295
; typ : string
287296
; doc : string option
297+
; syntax_doc : Query_protocol.syntax_doc_result option
288298
}
289299

290-
let type_enclosing doc pos verbosity =
300+
let type_enclosing doc pos verbosity ~with_syntax_doc =
291301
with_pipeline_exn doc (fun pipeline ->
292302
let command = Query_protocol.Type_enclosing (None, pos, Some 0) in
293303
let pipeline =
@@ -308,7 +318,12 @@ module Merlin = struct
308318
| [] | (_, `Index _, _) :: _ -> None
309319
| (loc, `String typ, _) :: _ ->
310320
let doc = doc_comment pipeline pos in
311-
Some { loc; typ; doc })
321+
let syntax_doc =
322+
match with_syntax_doc with
323+
| true -> syntax_doc pipeline pos
324+
| false -> None
325+
in
326+
Some { loc; typ; doc; syntax_doc })
312327

313328
let doc_comment doc pos =
314329
with_pipeline_exn doc (fun pipeline -> doc_comment pipeline pos)

ocaml-lsp-server/src/document.mli

+5
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,21 @@ module Merlin : sig
6363
val doc_comment :
6464
t -> Msource.position -> (* doc string *) string option Fiber.t
6565

66+
val syntax_doc :
67+
Mpipeline.t -> Msource.position -> Query_protocol.syntax_doc_result option
68+
6669
type type_enclosing =
6770
{ loc : Loc.t
6871
; typ : string
6972
; doc : string option
73+
; syntax_doc : Query_protocol.syntax_doc_result option
7074
}
7175

7276
val type_enclosing :
7377
t
7478
-> Msource.position
7579
-> (* verbosity *) int
80+
-> with_syntax_doc:bool
7681
-> type_enclosing option Fiber.t
7782

7883
val kind : t -> Kind.t

0 commit comments

Comments
 (0)