1
1
open Hh_prelude
2
2
3
- type candidate = {
4
- tast_env : Tast_env .t ;
5
- (* the function or class containing the shape expression *)
6
- container_pos : Pos .t ;
7
- shape_ty : Typing_defs .locl_ty ;
8
- }
3
+ type candidate =
4
+ | Of_expr of {
5
+ tast_env : Tast_env .t ;
6
+ (* the function or class containing the shape expression *)
7
+ expr_container_pos : Pos .t ;
8
+ shape_ty : Typing_defs .locl_ty ;
9
+ }
10
+ | Of_hint of {
11
+ hint_container_pos : Pos .t ;
12
+ hint_pos : Pos .t ;
13
+ }
14
+
15
+ (* * We use distinct titles so we can tell the refactors apart in analytics *)
16
+ let title_of_candidate = function
17
+ | Of_expr _ -> " Extract shape type"
18
+ | Of_hint _ -> " Extract shape type to alias"
9
19
10
20
type state =
11
21
| Searching of (Pos .t * candidate ) option
@@ -54,6 +64,13 @@ let find_candidate ~(selection : Pos.t) ~entry ctx : candidate option =
54
64
) else
55
65
Searching None
56
66
67
+ method! on_type_hint_ env hint_ =
68
+ match Option. both hint_ ! container_pos with
69
+ | Some ((hint_pos, Aast_defs. Hshape _), hint_container_pos)
70
+ when Pos. contains selection hint_pos ->
71
+ Searching (Some (hint_pos, Of_hint { hint_container_pos; hint_pos }))
72
+ | _ -> super#on_type_hint_ env hint_
73
+
57
74
method! on_fun_def env fd =
58
75
let pos = Aast_defs. (fd.fd_fun.f_span) in
59
76
if Pos. contains pos selection then (
@@ -67,9 +84,12 @@ let find_candidate ~(selection : Pos.t) ~entry ctx : candidate option =
67
84
if Pos. contains selection expr_pos then
68
85
let ty_ = Typing_defs_core. get_node ty in
69
86
match (ty_, ! container_pos) with
70
- | (Typing_defs_core. Tshape _ , Some container_pos ) ->
87
+ | (Typing_defs_core. Tshape _ , Some expr_container_pos ) ->
71
88
Searching
72
- (Some (expr_pos, { tast_env = env; container_pos; shape_ty = ty }))
89
+ (Some
90
+ ( expr_pos,
91
+ Of_expr { tast_env = env; expr_container_pos; shape_ty = ty }
92
+ ))
73
93
| _ -> Selected_non_shape_type expr_pos
74
94
else
75
95
super#on_expr env expr
@@ -81,24 +101,52 @@ let find_candidate ~(selection : Pos.t) ~entry ctx : candidate option =
81
101
| Selected_non_shape_type _ ->
82
102
None
83
103
84
- let edit_of_candidate ~path { shape_ty; container_pos; tast_env } :
85
- Lsp.WorkspaceEdit. t =
86
- let edit =
87
- let pos = Pos. shrink_to_start container_pos in
88
- let range =
89
- Lsp_helpers. hack_pos_to_lsp_range ~equal: Relative_path. equal pos
90
- in
91
- let tenv = Tast_env. tast_env_as_typing_env tast_env in
92
- let ty_text = Typing_print. full_strip_ns tenv shape_ty in
93
- let text = Printf. sprintf " type T${0:placeholder_} = %s;\n\n " ty_text in
94
- Lsp.TextEdit. { range; newText = text }
104
+ let snippet_for_decl_of : string -> string =
105
+ Printf. sprintf " type T${0:placeholder_} = %s;\n\n "
106
+
107
+ let snippet_for_use = " T${0:placeholder_}"
108
+
109
+ let range_of_container_pos container_pos : Lsp.range =
110
+ let pos = Pos. shrink_to_start container_pos in
111
+ Lsp_helpers. hack_pos_to_lsp_range ~equal: Relative_path. equal pos
112
+
113
+ let edit_of_candidate source_text ~path candidate : Lsp.WorkspaceEdit.t =
114
+ let sub_of_pos = Full_fidelity_source_text. sub_of_pos source_text in
115
+ let edits =
116
+ match candidate with
117
+ | Of_expr { shape_ty; expr_container_pos; tast_env } ->
118
+ let range = range_of_container_pos expr_container_pos in
119
+ let text =
120
+ let ty_text =
121
+ let tenv = Tast_env. tast_env_as_typing_env tast_env in
122
+ Typing_print. full_strip_ns tenv shape_ty
123
+ in
124
+ snippet_for_decl_of ty_text
125
+ in
126
+ [Lsp.TextEdit. { range; newText = text }]
127
+ | Of_hint { hint_container_pos; hint_pos } ->
128
+ let decl_edit =
129
+ let range = range_of_container_pos hint_container_pos in
130
+ let text =
131
+ let ty_text = sub_of_pos hint_pos in
132
+ snippet_for_decl_of ty_text
133
+ in
134
+ Lsp.TextEdit. { range; newText = text }
135
+ in
136
+ let use_edit =
137
+ let range =
138
+ Lsp_helpers. hack_pos_to_lsp_range ~equal: Relative_path. equal hint_pos
139
+ in
140
+ Lsp.TextEdit. { range; newText = snippet_for_use }
141
+ in
142
+ [decl_edit; use_edit]
95
143
in
96
- let changes = SMap. singleton (Relative_path. to_absolute path) [edit] in
144
+ let changes = SMap. singleton (Relative_path. to_absolute path) edits in
97
145
Lsp.WorkspaceEdit. { changes }
98
146
99
- let to_refactor ~path candidate =
100
- let edit = lazy (edit_of_candidate ~path candidate) in
101
- Code_action_types.Refactor. { title = " Extract shape type " ; edit }
147
+ let to_refactor source_text ~path candidate =
148
+ let edit = lazy (edit_of_candidate source_text ~path candidate) in
149
+ Code_action_types.Refactor. { title = title_of_candidate candidate ; edit }
102
150
103
151
let find ~entry ~(range : Lsp.range ) ctx =
104
152
let source_text = Ast_provider. compute_source_text ~entry in
@@ -108,5 +156,5 @@ let find ~entry ~(range : Lsp.range) ctx =
108
156
let path = entry.Provider_context. path in
109
157
let selection = Lsp_helpers. lsp_range_to_pos ~line_to_offset path range in
110
158
find_candidate ~selection ~entry ctx
111
- |> Option. map ~f: (to_refactor ~path )
159
+ |> Option. map ~f: (to_refactor source_text ~path )
112
160
|> Option. to_list
0 commit comments