Skip to content

Commit

Permalink
[lsp] Implement textDocument/selectionRange.
Browse files Browse the repository at this point in the history
We return the range of the Coq sentence underlying the cursor. In
VSCode, this is triggered by the "Expand Selection" command.

Note the current implementation is partial: we only take into account
the first position, and we only return a single range (Coq sentence)
without parents.

This could be of help for #580.
  • Loading branch information
ejgallego committed Oct 25, 2023
1 parent 9365291 commit ca71d74
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
- Export Query Goals API in VSCode client; this way other extensions
can implement their own commands that query Coq goals (@amblafont,
@ejgallego, #576, closes #558)
- Implement `textDocument/selectionRange` request, that will return
the range of the Coq sentence underlying the cursor. In VSCode,
this is triggered by the "Expand Selection" command. The
implementation is partial: we only take into account the first
position, and we only return a single range (Coq sentence) without
parents. (@ejgallego, #582)

# coq-lsp 0.1.7: Just-in-time
-----------------------------
Expand Down
30 changes: 27 additions & 3 deletions controller/lsp_core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ module U = Yojson.Safe.Util

let field name dict = List.(assoc name dict)
let int_field name dict = U.to_int (field name dict)
let dict_field name dict = U.to_assoc (field name dict)
let list_field name dict = U.to_list (field name dict)
let string_field name dict = U.to_string (field name dict)
let ofield name dict = List.(assoc_opt name dict)
Expand Down Expand Up @@ -70,10 +69,18 @@ module Helpers = struct
let Lsp.Doc.VersionedTextDocumentIdentifier.{ uri; version } = document in
(uri, version)

let get_position params =
let pos = dict_field "position" params in
let lsp_position_to_tuple (pos : J.t) =
let pos = U.to_assoc pos in
let line, character = (int_field "line" pos, int_field "character" pos) in
(line, character)

let get_position params =
let pos = field "position" params in
lsp_position_to_tuple pos

let get_position_array params =
let pos_list = list_field "positions" params in
List.map lsp_position_to_tuple pos_list
end

(** LSP loop internal state: mainly the data needed to create a new document. In
Expand Down Expand Up @@ -276,8 +283,24 @@ let do_position_request ~postpone ~params ~handler =
Rq.Action.Data
(Request.Data.PosRequest { uri; handler; point; version; postpone })

(* For now we only pick the first item *)
let do_position_list_request ~postpone ~params ~handler =
let uri, version = Helpers.get_uri_oversion params in
let points = Helpers.get_position_array params in
match points with
| [] ->
let point, handler = ((0, 0), Request.empty) in
Rq.Action.Data
(Request.Data.PosRequest { uri; handler; point; version; postpone })
| point :: _ ->
Rq.Action.Data
(Request.Data.PosRequest { uri; handler; point; version; postpone })

let do_hover = do_position_request ~postpone:false ~handler:Rq_hover.hover

let do_selectionRange =
do_position_list_request ~postpone:false ~handler:Rq_selectionRange.request

(* We get the format from the params *)
let get_pp_format_from_config () =
match !Fleche.Config.v.pp_type with
Expand Down Expand Up @@ -420,6 +443,7 @@ let dispatch_request ~method_ ~params : Rq.Action.t =
| "textDocument/documentSymbol" -> do_symbols ~params
| "textDocument/hover" -> do_hover ~params
| "textDocument/codeLens" -> do_lens ~params
| "textDocument/selectionRange" -> do_selectionRange ~params
(* Proof-specific stuff *)
| "proof/goals" -> do_goals ~params
(* Proof-specific stuff *)
Expand Down
2 changes: 2 additions & 0 deletions controller/request.ml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ module Data = struct
| PosRequest { uri = _; point; version = _; postpone = _; handler } ->
handler ~point ~doc
end

let empty ~doc:_ ~point:_ = Ok (`List [])
2 changes: 2 additions & 0 deletions controller/request.mli
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ module Data : sig
val dm_request : t -> Fleche.Theory.Request.request
val serve : doc:Fleche.Doc.t -> t -> R.t
end

val empty : position
2 changes: 1 addition & 1 deletion controller/rq_hover.ml
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ module type HoverProvider = sig
end

module Loc_info : HoverProvider = struct
let enabled = false
let enabled = true

let h ~contents:_ ~point:_ ~node =
match node with
Expand Down
1 change: 1 addition & 0 deletions controller/rq_init.ml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ let do_initialize ~params =
] )
; ("definitionProvider", `Bool true)
; ("codeLensProvider", `Assoc [])
; ("selectionRangeProvider", `Bool true)
; ( "workspace"
, `Assoc
[ ( "workspaceFolders"
Expand Down
26 changes: 26 additions & 0 deletions controller/rq_selectionRange.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(************************************************************************)
(* * The Coq Proof Assistant / The Coq Development Team *)
(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
(* <O___,, * (see CREDITS file for the list of authors) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)

(************************************************************************)
(* Coq Language Server Protocol *)
(* Copyright 2019 MINES ParisTech -- Dual License LGPL 2.1 / GPL3+ *)
(* Copyright 2019-2023 Inria -- Dual License LGPL 2.1 / GPL3+ *)
(* Written by: Emilio J. Gallego Arias *)
(************************************************************************)

let request ~doc ~point =
let approx = Fleche.Info.Exact in
match Fleche.Info.LC.node ~doc ~point approx with
| None -> Ok `Null
| Some node ->
let range = Fleche.Doc.Node.range node in
let parent = None in
let answer = Lsp.Core.SelectionRange.({ range; parent } |> to_yojson) in
Ok (`List [ answer ])
18 changes: 18 additions & 0 deletions controller/rq_selectionRange.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
(************************************************************************)
(* * The Coq Proof Assistant / The Coq Development Team *)
(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
(* <O___,, * (see CREDITS file for the list of authors) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)

(************************************************************************)
(* Coq Language Server Protocol *)
(* Copyright 2019 MINES ParisTech -- Dual License LGPL 2.1 / GPL3+ *)
(* Copyright 2019-2023 Inria -- Dual License LGPL 2.1 / GPL3+ *)
(* Written by: Emilio J. Gallego Arias *)
(************************************************************************)

val request : Request.position
1 change: 1 addition & 0 deletions etc/doc/PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ If a feature doesn't appear here it usually means it is not planned in the short
| `textDocument/publishDiagnostics` | Yes | |
| `textDocument/diagnostic` | No | Planned, issue #49 |
| `textDocument/codeAction` | No | Planned |
| `textDocument/selectionRange` | Partial | We only take into account the first selection; no parents |
|---------------------------------------|---------|------------------------------------------------------------|
| `workspace/workspaceFolders` | Yes | Each folder should have a `_CoqProject` file at the root. |
| `workspace/didChangeWorkspaceFolders` | Yes | |
Expand Down
9 changes: 9 additions & 0 deletions lsp/core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ module CodeLens = struct
[@@deriving yojson]
end

(** SelectionRange *)
module SelectionRange = struct
type t =
{ range : Lang.Range.t
; parent : t option [@default None]
}
[@@deriving yojson]
end

(** Pull Diagnostics *)
module DocumentDiagnosticParams = struct
type t =
Expand Down
9 changes: 9 additions & 0 deletions lsp/core.mli
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,15 @@ module CodeLens : sig
[@@deriving yojson]
end

(** SelectionRange *)
module SelectionRange : sig
type t =
{ range : Lang.Range.t
; parent : t option [@default None]
}
[@@deriving yojson]
end

(** Pull Diagnostics *)
module DocumentDiagnosticParams : sig
type t =
Expand Down

0 comments on commit ca71d74

Please sign in to comment.