Skip to content

Commit

Permalink
Merge branch 'master' of github.com:ocamllabs/vscode-ocaml-platform i…
Browse files Browse the repository at this point in the history
…nto typed_holes
  • Loading branch information
PizieDust committed Dec 2, 2024
2 parents 87e7775 + 4734290 commit 590018a
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

# Unreleased

- Add `ocaml.jump` to jump to a specific target. (#1654)

## 1.22.0

- Fix formatting of cwd path on windows (#1650)
Expand Down
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@
"category": "OCaml",
"title": "List values that can fill the selected typed-hole"
},
{
"command": "ocaml.jump",
"category": "OCaml",
"title": "List possible parent targets for jumping"
},
{
"command": "ocaml.navigate-typed-holes",
"category": "OCaml",
Expand Down Expand Up @@ -731,6 +736,14 @@
},
"when": "editorLangId == ocaml || editorLangId == reason"
},
{
"command": "ocaml.jump",
"key": "Alt+J",
"args": {
"kind": "jump"
},
"when": "editorLangId == ocaml || editorLangId == ocaml.interface || editorLangId == reason"
},
{
"command": "editor.action.codeAction",
"key": "Alt+P",
Expand Down
32 changes: 32 additions & 0 deletions src/custom_requests.ml
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,35 @@ module Construct = struct
let request =
{ meth = ocamllsp_prefixed "construct"; encode_params; decode_response }
end

module Merlin_jump = struct
type params =
{ uri : Uri.t
; position : Position.t
}

type response = (string * Position.t) list

let encode_params { uri; position } =
let open Jsonoo.Encode in
let uri =
("textDocument", object_ [ ("uri", string @@ Uri.toString uri ()) ])
in
let position = ("position", Position.json_of_t position) in
object_ [ uri; position ]

let decode_response (response : Jsonoo.t) : response =
let open Jsonoo.Decode in
field
"jumps"
(list (fun item ->
let target = field "target" string item in
let position = field "position" Position.t_of_json item in
(target, position)))
response

let make ~uri ~position = { uri; position }

let request =
{ meth = ocamllsp_prefixed "jump"; encode_params; decode_response }
end
10 changes: 10 additions & 0 deletions src/custom_requests.mli
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,13 @@ module Construct : sig

val request : (params, response) custom_request
end

module Merlin_jump : sig
type params

type response = (string * Position.t) list

val make : uri:Uri.t -> position:Position.t -> params

val request : (params, response) custom_request
end
102 changes: 102 additions & 0 deletions src/extension_commands.ml
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,108 @@ module Construct = struct
command Extension_consts.Commands.construct handler
end

module MerlinJump = struct
let extension_name = "MerlinJump"

let is_valid_text_doc textdoc =
match TextDocument.languageId textdoc with
| "ocaml" | "ocaml.interface" | "reason" | "ocaml.ocamllex" -> true
| _ -> false

let ocaml_lsp_doesnt_support_merlin_jump ocaml_lsp =
not (Ocaml_lsp.can_handle_merlin_jump ocaml_lsp)

let request_possible_targets position text_editor client =
let doc = TextEditor.document text_editor in
let uri = TextDocument.uri doc in
Custom_requests.(
send_request client Merlin_jump.request (Merlin_jump.make ~uri ~position))

let display_results (results : Custom_requests.Merlin_jump.response) =
let quickPickItems =
match results with
| [] ->
show_message `Info "No available targets to jump to.";
[]
| results ->
List.map results ~f:(fun (target, pos) ->
( (QuickPickItem.create ~label:("Jump to nearest " ^ target)) ()
, (target, pos) ))
in
let quickPickOptions =
QuickPickOptions.create ~title:"Available Jump Targets" ()
in
Window.showQuickPickItems
~choices:quickPickItems
~options:quickPickOptions
()

let jump_to_position text_editor position =
let open Promise.Syntax in
let+ _ =
Window.showTextDocument
~document:(TextEditor.document text_editor)
~preserveFocus:true
()
in
TextEditor.set_selection
text_editor
(Selection.makePositions ~anchor:position ~active:position);
TextEditor.revealRange
text_editor
~range:(Range.makePositions ~start:position ~end_:position)
~revealType:TextEditorRevealType.InCenterIfOutsideViewport
()

let process_jump position text_editor client =
let open Promise.Syntax in
let* successful_targets =
request_possible_targets position text_editor client
in
let* selected_target = display_results successful_targets in
match selected_target with
| Some (_res, position) -> jump_to_position text_editor position
| None -> Promise.return ()

let _jump =
let handler (instance : Extension_instance.t) ~args:_ =
let jump () =
match Window.activeTextEditor () with
| None ->
Extension_consts.Command_errors.text_editor_must_be_active
extension_name
~expl:
"The cursor position is used to determine the correct \
environment for the jump."
|> show_message `Error "%s"
| Some text_editor
when not (is_valid_text_doc (TextEditor.document text_editor)) ->
show_message
`Error
"Invalid file type. This command only works in ocaml files, ocaml \
interface files or reason files.."
| Some text_editor -> (
match Extension_instance.lsp_client instance with
| None -> show_message `Warn "ocamllsp is not running"
| Some (_client, ocaml_lsp)
when ocaml_lsp_doesnt_support_merlin_jump ocaml_lsp ->
show_message
`Warn
"The installed version of `ocamllsp` does not support Merlin \
jump custom requests"
| Some (client, _) ->
let position =
TextEditor.selection text_editor |> Selection.active
in
let _ = process_jump position text_editor client in
())
in
let (_ : unit) = jump () in
()
in
command Extension_consts.Commands.merlin_jump handler
end

module Navigate_holes = struct
let extension_name = "Navigate between Typed Holes"

Expand Down
2 changes: 2 additions & 0 deletions src/extension_consts.ml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ module Commands = struct

let construct = ocaml_prefixed "construct"

let merlin_jump = ocaml_prefixed "jump"

let navigate_typed_holes = ocaml_prefixed "navigate-typed-holes"
end

Expand Down
6 changes: 6 additions & 0 deletions src/ocaml_lsp.ml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ module Experimental_capabilities = struct
; handleTypedHoles : bool
; handleTypeEnclosing : bool
; handleConstruct : bool
; handleJump : bool
}

let default =
Expand All @@ -53,6 +54,7 @@ module Experimental_capabilities = struct
; handleTypedHoles = false
; handleTypeEnclosing = false
; handleConstruct = false
; handleJump = false
}

(** Creates [t] given a JSON of form [{ 'handleSwitchImplIntf' : true, .... }] *)
Expand All @@ -68,11 +70,13 @@ module Experimental_capabilities = struct
let handleTypedHoles = has_capability "handleTypedHoles" in
let handleTypeEnclosing = has_capability "handleTypeEnclosing" in
let handleConstruct = has_capability "handleConstruct" in
let handleJump = has_capability "handleJump" in
{ handleSwitchImplIntf
; handleInferIntf
; handleTypedHoles
; handleTypeEnclosing
; handleConstruct
; handleJump
}
with Jsonoo.Decode_error err ->
show_message
Expand Down Expand Up @@ -242,3 +246,5 @@ let can_handle_type_enclosing t =
t.experimental_capabilities.handleTypeEnclosing

let can_handle_construct t = t.experimental_capabilities.handleConstruct

let can_handle_merlin_jump t = t.experimental_capabilities.handleJump
2 changes: 2 additions & 0 deletions src/ocaml_lsp.mli
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ val can_handle_type_enclosing : t -> bool

val can_handle_construct : t -> bool

val can_handle_merlin_jump : t -> bool

module OcamllspSettingEnable : sig
include Ojs.T

Expand Down
21 changes: 20 additions & 1 deletion src/treeview_commands.ml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ let construct_item =
Vscode.TreeItem.set_command item command;
item

let jump_item =
let icon = `ThemeIcon (Vscode.ThemeIcon.make ~id:"fold-up" ()) in
let label =
`TreeItemLabel
(Vscode.TreeItemLabel.create ~label:"Jump to a specific target" ())
in
let item = Vscode.TreeItem.make_label ~label () in
let command =
Vscode.Command.create ~title:"MerlinJump" ~command:"ocaml.jump" ()
in
Vscode.TreeItem.set_iconPath item icon;
Vscode.TreeItem.set_command item command;
item

let navigate_holes_item =
let icon = `ThemeIcon (Vscode.ThemeIcon.make ~id:"arrow-up" ()) in
let label =
Expand All @@ -79,7 +93,12 @@ let navigate_holes_item =
item

let items =
[ select_sandbox_item; terminal_item; construct_item; navigate_holes_item ]
[ select_sandbox_item
; terminal_item
; construct_item
; jump_item
; navigate_holes_item
]

let getTreeItem ~element = `Value element

Expand Down

0 comments on commit 590018a

Please sign in to comment.