Prechádzať zdrojové kódy

[display] always send a `replaceRange`

oh boy...

see #7296
see #8659
Simon Krajewski 6 rokov pred
rodič
commit
c305ea4d02

+ 1 - 1
src/compiler/displayOutput.ml

@@ -786,4 +786,4 @@ let handle_syntax_completion com kind p =
 			raise (Completion s)
 		| Some(f,_,jsonrpc) ->
 			let ctx = Genjson.create_context ~jsonrpc:jsonrpc GMFull in
-			f(fields_to_json ctx l kind None None)
+			f(fields_to_json ctx l kind (make_subject None p))

+ 1 - 1
src/compiler/main.ml

@@ -1143,7 +1143,7 @@ with
 					| [] -> [],""
 				in
 				let kind = CRField ((CompletionItem.make_ci_module path,pos,None,None)) in
-				f (DisplayException.fields_to_json ctx fields kind None None);
+				f (DisplayException.fields_to_json ctx fields kind (DisplayTypes.make_subject None pos));
 			| _ -> raise (DisplayOutput.Completion (DisplayOutput.print_fields fields))
 			end
 		end

+ 1 - 1
src/context/display/display.ml

@@ -43,7 +43,7 @@ module ExprPreprocessing = struct
 		let annotate_marked e = annotate e DKMarked in
 		let mk_null p = annotate_marked ((EConst(Ident "null")),p) in
 		let loop_el el =
-			let pr = DisplayPosition.display_position#get in
+			let pr = DisplayPosition.display_position#with_pos (pos e) in
 			let rec loop el = match el with
 				| [] -> [mk_null pr]
 				| e :: el ->

+ 3 - 2
src/context/display/displayEmitter.ml

@@ -270,7 +270,8 @@ let display_meta com meta p = match com.display.dms_kind with
 	| DMDefault ->
 		let all = Meta.get_all() in
 		let all = List.map make_ci_metadata all in
-		raise_fields all CRMetadata (Some p)
+		let subject = if meta = Meta.Last then None else Some (Meta.to_string meta) in
+		raise_fields all CRMetadata (make_subject subject p);
 	| _ ->
 		()
 
@@ -305,5 +306,5 @@ let check_field_modifiers ctx c cf override display_modifier =
 				make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct) :: fields
 			) missing_fields [] in
 			let l = sort_fields l NoValue TKOverride in
-			raise_fields l CROverride None
+			raise_fields l CROverride (make_subject (Some cf.cf_name) p)
 		| _ -> ()

+ 12 - 16
src/context/display/displayException.ml

@@ -14,8 +14,7 @@ type hover_result = {
 type fields_result = {
 	fitems : CompletionItem.t list;
 	fkind : CompletionResultKind.t;
-	finsert_pos : pos option;
-	fsubject : placed_name option;
+	fsubject : completion_subject;
 }
 
 type signature_kind =
@@ -42,8 +41,7 @@ let raise_metadata s = raise (DisplayException(Metadata s))
 let raise_signatures l isig iarg kind = raise (DisplayException(DisplaySignatures(Some(l,isig,iarg,kind))))
 let raise_hover item expected p = raise (DisplayException(DisplayHover(Some {hitem = item;hpos = p;hexpected = expected})))
 let raise_positions pl = raise (DisplayException(DisplayPositions pl))
-let raise_fields ckl cr po = raise (DisplayException(DisplayFields(Some({fitems = ckl;fkind = cr;finsert_pos = po;fsubject = None}))))
-let raise_fields2 ckl cr po subject = raise (DisplayException(DisplayFields(Some({fitems = ckl;fkind = cr;finsert_pos = po;fsubject = Some subject}))))
+let raise_fields ckl cr subj = raise (DisplayException(DisplayFields(Some({fitems = ckl;fkind = cr;fsubject = subj}))))
 let raise_package sl = raise (DisplayException(DisplayPackage sl))
 
 (* global state *)
@@ -51,12 +49,12 @@ let last_completion_result = ref (Array.make 0 (CompletionItem.make (ITModule ([
 let last_completion_pos = ref None
 let max_completion_items = ref 0
 
-let filter_somehow ctx items subject kind po =
+let filter_somehow ctx items kind subj =
 	let ret = DynArray.create () in
 	let acc_types = DynArray.create () in
-	let subject = match subject with
+	let subject = match subj.s_name with
 		| None -> ""
-		| Some(subject,_) -> String.lowercase subject
+		| Some name-> String.lowercase name
 	in
 	let subject_matches s =
 		let rec loop i o =
@@ -99,24 +97,22 @@ let filter_somehow ctx items subject kind po =
 	) acc_types;
 	DynArray.to_list ret,DynArray.length ret = !max_completion_items
 
-let fields_to_json ctx fields kind po subject =
+let fields_to_json ctx fields kind subj =
 	last_completion_result := Array.of_list fields;
 	let needs_filtering = !max_completion_items > 0 && Array.length !last_completion_result > !max_completion_items in
 	let ja,did_filter = if needs_filtering then
-		filter_somehow ctx fields subject kind po
+		filter_somehow ctx fields kind subj
 	else
 		List.mapi (fun i item -> CompletionItem.to_json ctx (Some i) item) fields,false
  	in
-	if did_filter then begin match subject with
-		| Some(_,p) -> last_completion_pos := Some p;
-		| None -> last_completion_pos := None
-	end;
+	if did_filter then last_completion_pos := Some subj.s_start_pos;
 	let fl =
 		("items",jarray ja) ::
 		("isIncomplete",jbool did_filter) ::
 		("mode",CompletionResultKind.to_json ctx kind) ::
-		("filterString",(match subject with None -> jnull | Some(name,_) -> jstring name)) ::
-		(match po with None -> [] | Some p -> ["replaceRange",generate_pos_as_range (Parser.cut_pos_at_display p)])
+		("filterString",(match subj.s_name with None -> jnull | Some name -> jstring name)) ::
+		("replaceRange",generate_pos_as_range (Parser.cut_pos_at_display subj.s_insert_pos)) ::
+		[]
 	in
 	jobject fl
 
@@ -185,6 +181,6 @@ let to_json ctx de =
 	| DisplayFields None ->
 		jnull
 	| DisplayFields Some r ->
-		fields_to_json ctx r.fitems r.fkind r.finsert_pos r.fsubject
+		fields_to_json ctx r.fitems r.fkind r.fsubject
 	| DisplayPackage pack ->
 		jarray (List.map jstring pack)

+ 3 - 3
src/context/display/displayToplevel.ml

@@ -439,14 +439,14 @@ let collect ctx tk with_type =
 	t();
 	l
 
-let collect_and_raise ctx tk with_type cr subject pinsert =
+let collect_and_raise ctx tk with_type cr (name,pname) pinsert =
 	let fields = match !DisplayException.last_completion_pos with
-	| Some p' when (pos subject).pmin = p'.pmin ->
+	| Some p' when pname.pmin = p'.pmin ->
 		Array.to_list (!DisplayException.last_completion_result)
 	| _ ->
 		collect ctx tk with_type
 	in
-	DisplayException.raise_fields2 fields cr pinsert subject
+	DisplayException.raise_fields fields cr (make_subject (Some name) ~start_pos:(Some pname) pinsert)
 
 let handle_unresolved_identifier ctx i p only_types =
 	let l = collect ctx (if only_types then TKType else TKExpr p) NoValue in

+ 6 - 0
src/core/display/displayPosition.ml

@@ -53,6 +53,12 @@ class display_position_container =
 			let display_pos = self#get in
 			self#reset;
 			Std.finally (fun () -> self#set display_pos) fn ()
+
+		(**
+			Creates a new position with the file of [p] and the min/max of the display position.
+		 *)
+		method with_pos p =
+			{p with pmin = last_pos.pmin; pmax = last_pos.pmax}
 	end
 
 let display_position = new display_position_container

+ 13 - 1
src/core/displayTypes.ml

@@ -292,4 +292,16 @@ type reference_kind =
 	| KClassField
 	| KEnumField
 	| KModuleType
-	| KConstructor
+	| KConstructor
+
+type completion_subject = {
+	s_name : string option;
+	s_start_pos : pos;
+	s_insert_pos : pos;
+}
+
+let make_subject name ?(start_pos=None) insert_pos = {
+	s_name = name;
+	s_start_pos = (match start_pos with None -> insert_pos | Some p -> p);
+	s_insert_pos = insert_pos;
+}

+ 6 - 6
src/typing/typeload.ml

@@ -106,7 +106,7 @@ with Error((Module_not_found _ | Type_not_found _),p2) when p = p2 ->
 *)
 let load_type_def ctx p t =
 	let no_pack = t.tpackage = [] in
-	if t = Parser.magic_type_path then raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRTypeHint None;
+	if t = Parser.magic_type_path then raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRTypeHint (DisplayTypes.make_subject None p);
 	(* The type name is the module name or the module sub-type name *)
 	let tname = (match t.tsub with None -> t.tname | Some n -> n) in
 	try
@@ -355,7 +355,7 @@ and load_instance ctx ?(allow_display=false) (t,pn) allow_no_params =
 		t
 	with Error (Module_not_found path,_) when (ctx.com.display.dms_kind = DMDefault) && DisplayPosition.display_position#enclosed_in pn ->
 		let s = s_type_path path in
-		DisplayToplevel.collect_and_raise ctx TKType NoValue CRTypeHint (s,pn) (Some {pn with pmin = pn.pmax - String.length s;})
+		DisplayToplevel.collect_and_raise ctx TKType NoValue CRTypeHint (s,pn) {pn with pmin = pn.pmax - String.length s;}
 
 (*
 	build an instance from a complex type
@@ -375,7 +375,7 @@ and load_complex_type' ctx allow_display (t,p) =
 					| ITType({kind = Struct},_) -> true
 					| _ -> false
 				) r.fitems in
-				raise_fields l (CRStructExtension true) r.finsert_pos
+				raise_fields l (CRStructExtension true) r.fsubject
 		) tl in
 		let tr = ref None in
 		let t = TMono tr in
@@ -417,7 +417,7 @@ and load_complex_type' ctx allow_display (t,p) =
 						| ITType({kind = Struct},_) -> true
 						| _ -> false
 					) r.fitems in
-					raise_fields l (CRStructExtension false) r.finsert_pos
+					raise_fields l (CRStructExtension false) r.fsubject
 			) tl in
 			let tr = ref None in
 			let t = TMono tr in
@@ -846,7 +846,7 @@ let handle_path_display ctx path p =
 	in
 	match ImportHandling.convert_import_to_something_usable DisplayPosition.display_position#get path,ctx.com.display.dms_kind with
 		| (IDKPackage [s],p),DMDefault ->
-			DisplayToplevel.collect_and_raise ctx TKType WithType.no_value CRImport (s,p) (Some p)
+			DisplayToplevel.collect_and_raise ctx TKType WithType.no_value CRImport (s,p) p
 		| (IDKPackage sl,p),DMDefault ->
 			let sl = match List.rev sl with
 				| s :: sl -> List.rev sl
@@ -907,7 +907,7 @@ let handle_using ctx path p =
 		| (s1,_) :: sl ->
 			{ tpackage = List.rev (List.map fst sl); tname = s1; tsub = None; tparams = [] }
 		| [] ->
-			DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRUsing None;
+			DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRUsing (DisplayTypes.make_subject None p);
 	in
 	let types = (match t.tsub with
 		| None ->

+ 2 - 2
src/typing/typeloadCheck.ml

@@ -503,7 +503,7 @@ module Inheritance = struct
 					Typeload.load_instance ~allow_display:true ctx (ct,p) false
 				with DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) ->
 					(* We don't allow `implements` on interfaces. Just raise fields completion with no fields. *)
-					if not is_extends && c.cl_interface then raise_fields [] CRImplements r.finsert_pos;
+					if not is_extends && c.cl_interface then raise_fields [] CRImplements r.fsubject;
 					let l = List.filter (fun item -> match item.ci_kind with
 						| ITType({kind = Interface} as cm,_) -> (not is_extends || c.cl_interface) && CompletionModuleType.get_path cm <> c.cl_path
 						| ITType({kind = Class} as cm,_) ->
@@ -512,7 +512,7 @@ module Inheritance = struct
 							(not (is_basic_class_path (cm.pack,cm.name)) || (c.cl_extern && cm.is_extern))
 						| _ -> false
 					) r.fitems in
-					raise_fields l (if is_extends then CRExtends else CRImplements) r.finsert_pos
+					raise_fields l (if is_extends then CRExtends else CRImplements) r.fsubject
 				in
 				Some (check_herit t is_extends p)
 			with Error(Module_not_found(([],name)),p) when ctx.com.display.dms_kind <> DMNone ->

+ 1 - 1
src/typing/typeloadModule.ml

@@ -377,7 +377,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 				ctx.m.wildcard_packages <- (List.map fst pack,p) :: ctx.m.wildcard_packages
 			| _ ->
 				(match List.rev path with
-				| [] -> DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRImport None;
+				| [] -> DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRImport (DisplayTypes.make_subject None p) (* TODO: p is wrong *);
 				| (_,p) :: _ -> error "Module name must start with an uppercase letter" p))
 		| (tname,p2) :: rest ->
 			let p1 = (match pack with [] -> p2 | (_,p1) :: _ -> p1) in

+ 1 - 1
src/typing/typer.ml

@@ -1366,7 +1366,7 @@ and handle_efield ctx e p mode =
 									(* if there was no module name part, last guess is that we're trying to get package completion *)
 									if ctx.in_display then begin
 										if ctx.com.json_out = None then raise (Parser.TypePath (sl,None,false,p))
-										else DisplayToplevel.collect_and_raise ctx TKType WithType.no_value (CRToplevel None) (String.concat "." sl,p0) (Some p0)
+										else DisplayToplevel.collect_and_raise ctx TKType WithType.no_value (CRToplevel None) (String.concat "." sl,p0) p0
 									end;
 									raise e)
 		in

+ 38 - 18
src/typing/typerDisplay.ml

@@ -140,9 +140,9 @@ let get_expected_type ctx with_type =
 		| None -> None
 		| Some t -> Some (completion_type_of_type ctx t,completion_type_of_type ctx (follow t))
 
-let raise_toplevel ctx dk with_type (subject,psubject) po =
+let raise_toplevel ctx dk with_type (subject,psubject) =
 	let expected_type = get_expected_type ctx with_type in
-	DisplayToplevel.collect_and_raise ctx (match dk with DKPattern _ -> TKPattern psubject | _ -> TKExpr psubject) with_type (CRToplevel expected_type) (subject,psubject) po
+	DisplayToplevel.collect_and_raise ctx (match dk with DKPattern _ -> TKPattern psubject | _ -> TKExpr psubject) with_type (CRToplevel expected_type) (subject,psubject) psubject
 
 let display_dollar_type ctx p make_type =
 	let mono = mk_mono() in
@@ -394,20 +394,22 @@ and display_expr ctx e_ast e dk with_type p =
 		let display_fields e_ast e1 l =
 			let fields = DisplayFields.collect ctx e_ast e1 dk with_type p in
 			let item = completion_item_of_expr ctx e1 in
-			raise_fields fields (CRField(item,e1.epos,None,None)) (Some {e.epos with pmin = e.epos.pmax - l;})
+			raise_fields fields (CRField(item,e1.epos,None,None)) (make_subject None ~start_pos:(Some (pos e_ast)) {e.epos with pmin = e.epos.pmax - l;})
 		in
 		begin match fst e_ast,e.eexpr with
 			| EField(e1,s),TField(e2,_) ->
 				display_fields e1 e2 (String.length s)
 			| EObjectDecl [(name,pn,_),(EConst (Ident "null"),pe)],_ when pe.pmin = -1 ->
 				(* This is what the parser emits for #8651. Bit of a dodgy heuristic but should be fine. *)
-				raise_toplevel ctx dk with_type (name,pn) None
+				raise_toplevel ctx dk with_type (name,pn)
 			| _ ->
 				if dk = DKDot then display_fields e_ast e 0
 				else begin
 					let name = try String.concat "." (string_list_of_expr_path_raise e_ast) with Exit -> "" in
 					let name = if name = "null" then "" else name in
-					raise_toplevel ctx dk with_type (name,pos e_ast) None
+					let p = pos e_ast in
+					let p = if name <> "" then p else (DisplayPosition.display_position#with_pos p) in
+					raise_toplevel ctx dk with_type (name,p)
 				end
 		end
 	| DMDefault | DMNone | DMModuleSymbols _ | DMDiagnostics _ | DMStatistics ->
@@ -434,7 +436,7 @@ and display_expr ctx e_ast e dk with_type p =
 			end with Error _ | Not_found ->
 				None
 		in
-		raise_fields fields (CRField(item,e.epos,iterator,keyValueIterator)) None
+		raise_fields fields (CRField(item,e.epos,iterator,keyValueIterator)) (make_subject None (pos e_ast))
 
 let handle_structure_display ctx e fields origin =
 	let p = pos e in
@@ -444,18 +446,36 @@ let handle_structure_display ctx e fields origin =
 		let ct = DisplayEmitter.completion_type_of_type ctx ~values t in
 		(t,ct)
 	in
+	let make_field_item cf =
+		make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (tpair ~values:(get_value_meta cf.cf_meta) cf.cf_type)
+	in
 	match fst e with
 	| EObjectDecl fl ->
-		let fields = List.fold_left (fun acc cf ->
-			if Expr.field_mem_assoc cf.cf_name fl then acc
-			else (make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (tpair ~values:(get_value_meta cf.cf_meta) cf.cf_type)) :: acc
-		) [] fields in
-		raise_fields fields CRStructureField None
+		let fields = ref fields in
+		let rec loop subj fl = match fl with
+			| [] -> subj
+			| ((n,p,_),_) :: fl ->
+				let subj = if DisplayPosition.display_position#enclosed_in p then
+					Some(n,p)
+				else begin
+					fields := List.filter (fun cf -> cf.cf_name <> n) !fields;
+					subj
+				end in
+				loop subj fl
+		in
+		let subj = loop None fl in
+		let name,pinsert = match subj with
+			| None -> None,DisplayPosition.display_position#with_pos (pos e)
+			| Some(name,p) -> Some name,p
+		in
+		let fields = List.map make_field_item !fields in
+		raise_fields fields CRStructureField (make_subject name pinsert)
 	| EBlock [] ->
 		let fields = List.fold_left (fun acc cf ->
-			make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (tpair ~values:(get_value_meta cf.cf_meta) cf.cf_type) :: acc
+			(make_field_item cf) :: acc
 		) [] fields in
-		raise_fields fields CRStructureField None
+		let pinsert = DisplayPosition.display_position#with_pos (pos e) in
+		raise_fields fields CRStructureField (make_subject None pinsert)
 	| _ ->
 		error "Expected object expression" p
 
@@ -494,14 +514,14 @@ let handle_display ?resume_typing ctx e_ast dk with_type =
 		| Some fn -> fn ctx e_ast with_type
 	with Error (Unknown_ident n,_) when ctx.com.display.dms_kind = DMDefault ->
         if dk = DKDot && ctx.com.json_out = None then raise (Parser.TypePath ([n],None,false,p))
-		else raise_toplevel ctx dk with_type (n,p) (Some p)
+		else raise_toplevel ctx dk with_type (n,p)
 	| Error ((Type_not_found (path,_) | Module_not_found path),_) as err when ctx.com.display.dms_kind = DMDefault ->
 		if ctx.com.json_out = None then	begin try
-			raise_fields (DisplayFields.get_submodule_fields ctx path) (CRField((make_ci_module path),p,None,None)) None
+			raise_fields (DisplayFields.get_submodule_fields ctx path) (CRField((make_ci_module path),p,None,None)) (make_subject None (pos e_ast))
 		with Not_found ->
 			raise err
 		end else
-			raise_toplevel ctx dk with_type (s_type_path path,p) (Some p)
+			raise_toplevel ctx dk with_type (s_type_path path,p)
 	| DisplayException(DisplayFields Some({fkind = CRTypeHint} as r)) when (match fst e_ast with ENew _ -> true | _ -> false) ->
 		let timer = Timer.timer ["display";"toplevel";"filter ctors"] in
 		ctx.pass <- PBuildClass;
@@ -547,7 +567,7 @@ let handle_display ?resume_typing ctx e_ast dk with_type =
 			| _ -> false
 		) r.fitems in
 		timer();
-		raise_fields l CRNew r.finsert_pos
+		raise_fields l CRNew r.fsubject
 	in
 	let e = match e.eexpr with
 		| TField(e1,FDynamic "bind") when (match follow e1.etype with TFun _ -> true | _ -> false) -> e1
@@ -604,6 +624,6 @@ let handle_edisplay ?resume_typing ctx e dk with_type =
 		begin try
 			handle_display ctx e dk with_type
 		with DisplayException(DisplayFields Some({fkind = CRToplevel _} as r)) ->
-			raise_fields r.fitems (CRPattern ((get_expected_type ctx with_type),outermost)) r.finsert_pos
+			raise_fields r.fitems (CRPattern ((get_expected_type ctx with_type),outermost)) r.fsubject
 		end
 	| _ -> handle_display ctx e dk with_type