@@ -283,6 +283,7 @@ class ScriptLanguage : public Object {
283283	virtual  bool  overrides_external_editor () { return  false ; }
284284	virtual  ScriptNameCasing preferred_file_name_casing () const  { return  SCRIPT_NAME_CASING_SNAKE_CASE; }
285285
286+ 	//  Code completion.
286287	//  Keep enums in sync with:
287288	//  scene/gui/code_edit.h - CodeEdit::CodeCompletionKind
288289	enum  CodeCompletionKind {
@@ -339,6 +340,229 @@ class ScriptLanguage : public Object {
339340
340341	virtual  Error complete_code (const  String &p_code, const  String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool  &r_force, String &r_call_hint) { return  ERR_UNAVAILABLE; }
341342
343+ 	//  Refactoring.
344+ 	//  Keep enums in sync with:
345+ 	//  scene/gui/code_edit.h - CodeEdit::RefactorKind
346+ 	enum  RefactorKind {
347+ 		REFACTOR_KIND_RENAME_SYMBOL,
348+ 	};
349+ 
350+ 	enum  RefactorRenameSymbolResultType {
351+ 		REFACTOR_RENAME_SYMBOL_RESULT_NONE,
352+ 		REFACTOR_RENAME_SYMBOL_RESULT_NATIVE,
353+ 		REFACTOR_RENAME_SYMBOL_RESULT_NOT_EXPOSED,
354+ 		REFACTOR_RENAME_SYMBOL_RESULT_SCRIPT,
355+ 		REFACTOR_RENAME_SYMBOL_RESULT_GLOBAL_CLASS_NAME,
356+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_NAME,
357+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_CONSTANT,
358+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_PROPERTY,
359+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_METHOD,
360+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_SIGNAL,
361+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_ENUM,
362+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_ENUM_VALUE,
363+ 		REFACTOR_RENAME_SYMBOL_RESULT_CLASS_ANNOTATION,
364+ 		REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_CONSTANT,
365+ 		REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_VARIABLE,
366+ 		REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_FOR_VARIABLE,
367+ 		REFACTOR_RENAME_SYMBOL_RESULT_LOCAL_PATTERN_BIND,
368+ 		REFACTOR_RENAME_SYMBOL_RESULT_MAX,
369+ 	};
370+ 
371+ 	struct  RefactorRenameSymbolResult  {
372+ 		struct  Match  {
373+ 			int  start_line = -1 ;
374+ 			int  start_column = -1 ;
375+ 			int  end_line = -1 ;
376+ 			int  end_column = -1 ;
377+ 
378+ 			Match () {}
379+ 			Match (int  p_start_line, int  p_start_column, int  p_end_line, int  p_end_column) {
380+ 				start_line = p_start_line;
381+ 				start_column = p_start_column;
382+ 				end_line = p_end_line;
383+ 				end_column = p_end_column;
384+ 			}
385+ 
386+ 			String to_string () const  {
387+ 				return  vformat (" Match{(%s,%s)=>(%s,%s)}"  , start_line, start_column, end_line, end_column);
388+ 			}
389+ 
390+ 			struct  Compare  {
391+ 				_FORCE_INLINE_ bool  operator ()(const  Match &l, const  Match &r) const  {
392+ 					if  (l.start_line  != r.start_line ) {
393+ 						return  l.start_line  < r.start_line ;
394+ 					}
395+ 					if  (l.start_column  != r.start_column ) {
396+ 						return  l.start_column  < r.start_column ;
397+ 					}
398+ 					return  false ;
399+ 				}
400+ 			};
401+ 		};
402+ 
403+ 		String symbol;
404+ 		String new_symbol;
405+ 		String code;
406+ 		Error error = FAILED;
407+ 		bool  outside_refactor = false ;
408+ 		RefactorRenameSymbolResultType type = RefactorRenameSymbolResultType::REFACTOR_RENAME_SYMBOL_RESULT_NONE;
409+ 		HashMap<String, LocalVector<Match>> matches;
410+ 
411+ 	private: 
412+ 		void  _deep_copy (const  RefactorRenameSymbolResult &p_result) {
413+ 			symbol = p_result.symbol ;
414+ 			new_symbol = p_result.new_symbol ;
415+ 			code = p_result.code ;
416+ 			outside_refactor = p_result.outside_refactor ;
417+ 			error = p_result.error ;
418+ 			type = p_result.type ;
419+ 			matches.clear ();
420+ 			for  (const  KeyValue<String, LocalVector<Match>> &KV : p_result.matches ) {
421+ 				for  (const  Match &match : KV.value ) {
422+ 					matches[KV.key ].push_back (match);
423+ 				}
424+ 			}
425+ 		}
426+ 
427+ 	public: 
428+ 		String to_string () const  {
429+ 			String matches_string;
430+ 			for  (const  KeyValue<String, LocalVector<Match>> &KV : matches) {
431+ 				LocalVector<String> match_entries;
432+ 				for  (const  Match &match : KV.value ) {
433+ 					match_entries.push_back (match.to_string ());
434+ 				}
435+ 				matches_string += vformat (" \t\t %s: %s,\n "  , KV.key , String (" , "  ).join (match_entries));
436+ 			}
437+ 			matches_string = matches_string.trim_suffix (" \n "  );
438+ 
439+ 			return  vformat (R"( RefactorRenameSymbolResult{
440+ 	"%s" -> "%s", 
441+ 	( 
442+ %s 
443+ 	) 
444+ })"  ,
445+ 					symbol, new_symbol, matches_string);
446+ 		}
447+ 
448+ 		void  add_match (const  String &p_path, int  p_start_line, int  p_start_column, int  p_end_line, int  p_end_column) {
449+ 			matches[p_path].push_back ({ p_start_line,
450+ 					p_start_column,
451+ 					p_end_line,
452+ 					p_end_column });
453+ 			matches[p_path].sort_custom <RefactorRenameSymbolResult::Match::Compare>();
454+ 		}
455+ 
456+ 		Dictionary to_dictionary () {
457+ 			Dictionary result;
458+ 			result[" symbol"  ] = symbol;
459+ 			result[" new_symbol"  ] = new_symbol;
460+ 			result[" code"  ] = code;
461+ 			result[" outside_refactor"  ] = outside_refactor;
462+ 			result[" error"  ] = error;
463+ 			result[" type"  ] = type;
464+ 
465+ 			Dictionary dictionary_matches;
466+ 			for  (KeyValue<String, LocalVector<Match>> &KV : matches) {
467+ 				TypedArray<Dictionary> dictionary_matches_entries;
468+ 				for  (Match &match : KV.value ) {
469+ 					Dictionary dictionary_match;
470+ 					dictionary_match[" start_line"  ] = match.start_line ;
471+ 					dictionary_match[" start_column"  ] = match.start_column ;
472+ 					dictionary_match[" end_line"  ] = match.end_line ;
473+ 					dictionary_match[" end_column"  ] = match.end_column ;
474+ 					dictionary_matches_entries.push_back (dictionary_match);
475+ 				}
476+ 				dictionary_matches[KV.key ] = dictionary_matches_entries;
477+ 			}
478+ 			result[" matches"  ] = dictionary_matches;
479+ 
480+ 			return  result;
481+ 		}
482+ 
483+ 		RefactorRenameSymbolResult get_undo () {
484+ 			RefactorRenameSymbolResult undo_result;
485+ 			undo_result.symbol  = new_symbol;
486+ 			undo_result.new_symbol  = symbol;
487+ 			undo_result.code  = code;
488+ 			undo_result.outside_refactor  = outside_refactor;
489+ 			undo_result.error  = error;
490+ 			undo_result.type  = type;
491+ 
492+ 			for  (const  KeyValue<String, LocalVector<Match>> &KV : matches) {
493+ 				int  last_line = 0 ;
494+ 				int  offset = 0 ;
495+ 				for  (const  Match &match : KV.value ) {
496+ 					if  (last_line < match.start_line ) {
497+ 						offset = 0 ;
498+ 						last_line = match.start_line ;
499+ 					}
500+ 					Match new_match = {
501+ 						match.start_line ,
502+ 						match.start_column  + offset,
503+ 						match.end_line ,
504+ 						match.end_column ,
505+ 					};
506+ 					offset += new_symbol.length () - symbol.length ();
507+ 					undo_result.matches [KV.key ].push_back (new_match);
508+ 				}
509+ 			}
510+ 
511+ 			return  undo_result;
512+ 		}
513+ 
514+ 		bool  has_failed () const  {
515+ 			return  error != OK || outside_refactor == true ;
516+ 		}
517+ 
518+ 		void  reset (bool  p_keep_context = false ) {
519+ 			matches.clear ();
520+ 			outside_refactor = false ;
521+ 			error = FAILED;
522+ 			type = REFACTOR_RENAME_SYMBOL_RESULT_NONE;
523+ 			if  (!p_keep_context) {
524+ 				symbol = " "  ;
525+ 				new_symbol = " "  ;
526+ 				code = " "  ;
527+ 			}
528+ 		}
529+ 
530+ 		void  operator =(const  RefactorRenameSymbolResult &p_result) {
531+ 			_deep_copy (p_result);
532+ 		}
533+ 
534+ 		RefactorRenameSymbolResult (const  RefactorRenameSymbolResult &p_result) {
535+ 			_deep_copy (p_result);
536+ 		}
537+ 
538+ 		RefactorRenameSymbolResult (const  Dictionary &p_result) {
539+ 			ERR_FAIL_COND (!p_result.has (" symbol"  ) || !p_result.has (" new_symbol"  ) || !p_result.has (" code"  ) || !p_result.has (" error"  ) || !p_result.has (" outside_refactor"  ) || !p_result.has (" type"  ) || !p_result.has (" matches"  ));
540+ 			symbol = p_result[" symbol"  ];
541+ 			new_symbol = p_result[" new_symbol"  ];
542+ 			code = p_result[" code"  ];
543+ 			outside_refactor = p_result[" outside_refactor"  ];
544+ 			error = (Error)(int )p_result[" error"  ];
545+ 			type = (RefactorRenameSymbolResultType)(int )p_result[" type"  ];
546+ 			matches.clear ();
547+ 			Dictionary dictionary_matches = p_result[" matches"  ];
548+ 			for  (const  String key : dictionary_matches.keys ()) {
549+ 				TypedArray<Dictionary> dictionary_match_entries = dictionary_matches[key];
550+ 				for  (int  i = 0 ; i < dictionary_match_entries.size (); i++) {
551+ 					Dictionary dictionar_match_entry = dictionary_match_entries[i];
552+ 					matches[key].push_back ({ dictionar_match_entry[" start_line"  ],
553+ 							dictionar_match_entry[" start_column"  ],
554+ 							dictionar_match_entry[" end_line"  ],
555+ 							dictionar_match_entry[" end_column"  ] });
556+ 				}
557+ 			}
558+ 		}
559+ 
560+ 		RefactorRenameSymbolResult () = default ;
561+ 	};
562+ 
563+ 	virtual  Error refactor_rename_symbol_code (const  String &p_code, const  String &p_symbol, const  String &p_path, Object *p_owner, const  HashMap<String, String> &p_unsaved_scripts_source_code, RefactorRenameSymbolResult &r_result) { return  ERR_UNAVAILABLE; }
564+ 
565+ 	//  Lookup.
342566	enum  LookupResultType {
343567		LOOKUP_RESULT_SCRIPT_LOCATION, //  Use if none of the options below apply.
344568		LOOKUP_RESULT_CLASS,
0 commit comments