@@ -822,6 +822,15 @@ def add_whitespace_indentation(view, region, string, replace="\t", add_whitespac
822822 string = re .sub ("([" + replace + "]+)" , whitespace + r"\1" , string )
823823 return string
824824
825+ @staticmethod
826+ def convert_tabs_using_tab_size (view , string ):
827+ tab_size = view .settings ().get ("tab_size" )
828+
829+ if tab_size :
830+ return string .replace ("\t " , " " * tab_size )
831+
832+ return string .replace ("\t " , " " )
833+
825834 @staticmethod
826835 def go_to_centered (view , row , col ):
827836 while view .is_loading () :
@@ -3827,7 +3836,8 @@ def run_auto_complete(self):
38273836 'disable_auto_insert' : True ,
38283837 'api_completions_only' : False ,
38293838 'next_completion_if_showing' : False ,
3830- 'auto_complete_commit_on_tab' : True
3839+ 'auto_complete_commit_on_tab' : True ,
3840+ 'auto_complete_delay' : 0
38313841 })
38323842
38333843 def on_query_completions (self , view , prefix , locations ):
@@ -6027,7 +6037,7 @@ def run(self, edit, **args):
60276037 if view .sel ()[0 ].begin () == view .sel ()[0 ].end ():
60286038 return
60296039
6030- select_options = ['Global scope' , 'Current Scope ' , 'Class method' ]
6040+ select_options = ['Global scope' , 'Current scope ' , 'Class method' ]
60316041 if not view .match_selector (view .sel ()[0 ].begin (), 'meta.class.js' ):
60326042 select_options .remove ('Class method' )
60336043 if len (scope .split (" " )) < 2 :
@@ -6059,6 +6069,24 @@ def run(self, edit, **args):
60596069
60606070 self .view .run_command ("refactor_extract_variable" )
60616071
6072+ elif case == "extract_field" :
6073+ if view .sel ()[0 ].begin () == view .sel ()[0 ].end () or not view .match_selector (view .sel ()[0 ].begin (), 'meta.class.js' ):
6074+ return
6075+
6076+ select_options = ["Current method" , "Field declaration" , "Class constructor" ]
6077+
6078+ windowView = WindowView (title = "Refactor - Extract Field" , use_compare_layout = True )
6079+ windowView .addTitle (text = "Refactor - Extract Field" )
6080+ windowView .add (text = "\n \n " )
6081+ windowView .addInput (value = "new_field" , label = "Field Name: " , region_id = "field_name" )
6082+ windowView .add (text = "\n " )
6083+ windowView .addSelect (default_option = 0 , options = select_options , label = "Scope: " , region_id = "scope" )
6084+ windowView .add (text = "\n \n " )
6085+ windowView .addCloseButton (text = "OK" , scope = "javascriptenhancements.button_ok" , callback = lambda view : self .view .run_command ("refactor_extract_field" , args = {"inputs" : windowView .getInputs ()}))
6086+ windowView .add (text = " " )
6087+ windowView .addCloseButton (text = "CANCEL" , scope = "javascriptenhancements.button_cancel" )
6088+ windowView .add (text = " \n " )
6089+
60626090 def is_enabled (self , ** args ) :
60636091
60646092 view = self .view
@@ -6963,6 +6991,284 @@ def is_visible(self, **args) :
69636991 return selection .begin () != selection .end ()
69646992
69656993
6994+ import sublime , sublime_plugin
6995+
6996+ class RefactorExtractFieldCommand (sublime_plugin .TextCommand ):
6997+ def run (self , edit , ** args ):
6998+ view = self .view
6999+ selection = view .sel ()[0 ]
7000+ inputs = args .get ("inputs" )
7001+ content = view .substr (selection ).strip ()
7002+ content = content [:- 1 ] if content [- 1 ] == ";" else content
7003+ field_name = inputs ["field_name" ]
7004+
7005+ flow_cli = "flow"
7006+ is_from_bin = True
7007+ chdir = ""
7008+ use_node = True
7009+ bin_path = ""
7010+
7011+ settings = get_project_settings ()
7012+ if settings and settings ["project_settings" ]["flow_cli_custom_path" ]:
7013+ flow_cli = os .path .basename (settings ["project_settings" ]["flow_cli_custom_path" ])
7014+ bin_path = os .path .dirname (settings ["project_settings" ]["flow_cli_custom_path" ])
7015+ is_from_bin = False
7016+ chdir = settings ["project_dir_name" ]
7017+ use_node = False
7018+
7019+ node = NodeJS (check_local = True )
7020+
7021+ result = node .execute_check_output (
7022+ flow_cli ,
7023+ [
7024+ 'ast' ,
7025+ '--from' , 'sublime_text'
7026+ ],
7027+ is_from_bin = is_from_bin ,
7028+ use_fp_temp = True ,
7029+ fp_temp_contents = content ,
7030+ is_output_json = True ,
7031+ chdir = chdir ,
7032+ bin_path = bin_path ,
7033+ use_node = use_node
7034+ )
7035+
7036+ if result [0 ] and not result [1 ]["errors" ] and result [1 ]["body" ] and "type" in result [1 ]["body" ][0 ] and result [1 ]["body" ][0 ]["type" ] == "ExpressionStatement" :
7037+
7038+ result = node .execute_check_output (
7039+ flow_cli ,
7040+ [
7041+ 'ast' ,
7042+ '--from' , 'sublime_text'
7043+ ],
7044+ is_from_bin = is_from_bin ,
7045+ use_fp_temp = True ,
7046+ fp_temp_contents = view .substr (sublime .Region (0 , view .size ())),
7047+ is_output_json = True ,
7048+ chdir = chdir ,
7049+ bin_path = bin_path ,
7050+ use_node = use_node
7051+ )
7052+
7053+ if result [0 ]:
7054+ if "body" in result [1 ]:
7055+ body = result [1 ]["body" ]
7056+ classes = Util .nested_lookup ("type" , ["ClassDeclaration" ], body )
7057+ _class = None
7058+ class_region = None
7059+
7060+ for c in classes :
7061+ r = sublime .Region (int (c ["range" ][0 ]), int (c ["range" ][1 ]))
7062+ if r .contains (selection ):
7063+ _class = c
7064+ class_region = r
7065+ break
7066+
7067+ if class_region :
7068+
7069+ items = Util .nested_lookup ("type" , ["BlockStatement" ], _class )
7070+ last_block_statement = None
7071+ last_item = None
7072+ region = None
7073+ constructor_region = None
7074+ constructor_method = None
7075+
7076+ method_definitions = Util .nested_lookup ("type" , ["MethodDefinition" ], _class )
7077+
7078+ for method in method_definitions :
7079+ if method ["kind" ] == "constructor" :
7080+ constructor_method = method
7081+ constructor_region = sublime .Region (int (method ["value" ]["body" ]["range" ][0 ]), int (method ["value" ]["body" ]["range" ][1 ]))
7082+ break
7083+
7084+ for item in items :
7085+ r = sublime .Region (int (item ["range" ][0 ]), int (item ["range" ][1 ]))
7086+ if r .contains (selection ):
7087+ last_block_statement = r
7088+ last_item = item
7089+
7090+ if last_block_statement :
7091+ for item in last_item ["body" ]:
7092+ r = sublime .Region (int (item ["range" ][0 ]), int (item ["range" ][1 ]))
7093+ if r .contains (selection ):
7094+ region = r
7095+ break
7096+
7097+ if region :
7098+
7099+ class_properties = Util .nested_lookup ("type" , ["ClassProperty" ], _class )
7100+ last_class_property = None
7101+ region_last_class_property = None
7102+ if len (class_properties ) > 0 :
7103+ last_class_property = class_properties [- 1 ]
7104+ region_last_class_property = sublime .Region (int (last_class_property ["range" ][0 ]), int (last_class_property ["range" ][1 ]))
7105+
7106+ if not constructor_region and inputs ["scope" ] == "Class constructor" :
7107+ if region_last_class_property :
7108+ view .insert (edit , region_last_class_property .end (), "\n \n \t constructor () {\n \t }" )
7109+ else :
7110+ view .insert (edit , int (_class ["body" ]["range" ][0 ]) + 1 , "\n \n \t constructor () {\n \t }" )
7111+
7112+ # create the constructor method and then execute this command again
7113+ view .run_command ("refactor_extract_field" , args = {"inputs" : inputs })
7114+ return
7115+
7116+ prev_line_is_empty = Util .prev_line_is_empty (view , region )
7117+
7118+ space = ""
7119+ if inputs ["scope" ] == "Current method" or inputs ["scope" ] == "Class constructor" :
7120+ space = Util .get_whitespace_from_line_begin (
7121+ view ,
7122+ (
7123+ region
7124+ if inputs ["scope" ] == "Current method"
7125+ else sublime .Region (int (constructor_method ["range" ][0 ]), int (constructor_method ["range" ][1 ]))
7126+ )
7127+ )
7128+ if inputs ["scope" ] == "Class constructor" :
7129+ space += Util .convert_tabs_using_tab_size (view , "\t " )
7130+
7131+ str_assignement = "this." + (field_name + " = " + content if inputs ["scope" ] == "Current method" or inputs ["scope" ] == "Class constructor" else field_name )
7132+
7133+ is_line_empty = view .substr (view .line (selection )).strip ().replace (view .substr (selection ), "" ) == ""
7134+
7135+ view .erase (edit , selection )
7136+
7137+ if not is_line_empty :
7138+ view .insert (edit , selection .begin (), "this." + field_name )
7139+ if inputs ["scope" ] == "Current method" :
7140+ str_assignement = ("\n " + space if not prev_line_is_empty else "" ) + "this." + field_name + " = " + content + "\n " + space
7141+ view .insert (edit , region .begin (), str_assignement )
7142+ else :
7143+ str_assignement = ""
7144+ else :
7145+ if inputs ["scope" ] == "Class constructor" :
7146+ view .insert (edit , selection .begin (), "this." + field_name )
7147+ else :
7148+ view .insert (edit , selection .begin (), str_assignement )
7149+
7150+ if inputs ["scope" ] == "Class constructor" :
7151+ str_assignement = "\n " + space + "this." + field_name + " = " + content + ("\n " + space if view .substr (constructor_region ).splitlines ()[0 ].strip ().replace ("{" , "" ) != "" else "" )
7152+ view .insert (edit , constructor_region .begin () + 1 , str_assignement )
7153+
7154+ str_class_property = ""
7155+ if region_last_class_property :
7156+ str_class_property = "\n \t " + (field_name if inputs ["scope" ] == "Current method" or inputs ["scope" ] == "Class constructor" else field_name + " = " + content ) + ";"
7157+ view .insert (edit , region_last_class_property .end (), str_class_property )
7158+ else :
7159+ str_class_property = "\n \n \t " + (field_name if inputs ["scope" ] == "Current method" or inputs ["scope" ] == "Class constructor" else field_name + " = " + content ) + ";"
7160+ view .insert (edit , int (_class ["body" ]["range" ][0 ])+ 1 , str_class_property )
7161+
7162+ str_class_property = Util .convert_tabs_using_tab_size (view , str_class_property )
7163+
7164+ view .sel ().clear ()
7165+
7166+ if not is_line_empty :
7167+
7168+ view .sel ().add (
7169+ sublime .Region (
7170+ selection .begin ()+ len ("this." )+ len (str_assignement )+ len (str_class_property ),
7171+ selection .begin ()+ len ("this." )+ len (str_assignement )+ len (field_name )+ len (str_class_property )
7172+ )
7173+ )
7174+
7175+ if inputs ["scope" ] == "Current method" or inputs ["scope" ] == "Class constructor" :
7176+
7177+ view .sel ().add (
7178+ sublime .Region (
7179+ (
7180+ region .begin ()
7181+ if inputs ["scope" ] == "Current method"
7182+ else constructor_region .begin () + 1
7183+ ) +
7184+ len (("\n " + space if not prev_line_is_empty else "" ) + "this." ) +
7185+ len (str_class_property )
7186+
7187+ ,
7188+
7189+ (
7190+ region .begin ()
7191+ if inputs ["scope" ] == "Current method"
7192+ else constructor_region .begin () + 1
7193+ ) +
7194+ len (("\n " + space if not prev_line_is_empty else "" ) + "this." ) +
7195+ len (field_name ) +
7196+ len (str_class_property )
7197+ )
7198+ )
7199+
7200+ else :
7201+ view .sel ().add (
7202+ sublime .Region (
7203+ selection .begin () +
7204+ len ("this." ) +
7205+ len (str_class_property ) +
7206+ (len (str_assignement ) if inputs ["scope" ] == "Class constructor" else 0 )
7207+
7208+ ,
7209+
7210+ selection .begin () +
7211+ len ("this." ) +
7212+ len (field_name ) +
7213+ len (str_class_property ) +
7214+ (len (str_assignement ) if inputs ["scope" ] == "Class constructor" else 0 )
7215+ )
7216+ )
7217+
7218+ if inputs ["scope" ] == "Class constructor" :
7219+ view .sel ().add (
7220+ sublime .Region (
7221+ constructor_region .begin () + 1 +
7222+ len (("\n " + space if not prev_line_is_empty else "" ) + "this." ) +
7223+ len (str_class_property )
7224+
7225+ ,
7226+
7227+ constructor_region .begin () + 1 +
7228+ len (("\n " + space if not prev_line_is_empty else "" ) + "this." ) +
7229+ len (field_name ) +
7230+ len (str_class_property )
7231+ )
7232+ )
7233+
7234+ tab_to_string = Util .convert_tabs_using_tab_size (view , "\t " )
7235+
7236+ if region_last_class_property :
7237+ view .sel ().add (
7238+ sublime .Region (
7239+ region_last_class_property .end ()+ len ("\n " + tab_to_string ),
7240+ region_last_class_property .end ()+ len ("\n " + tab_to_string )+ len (field_name )
7241+ )
7242+ )
7243+ else :
7244+ view .sel ().add (
7245+ sublime .Region (
7246+ int (_class ["body" ]["range" ][0 ])+ 1 + len ("\n \n " + tab_to_string ),
7247+ int (_class ["body" ]["range" ][0 ])+ 1 + len ("\n \n " + tab_to_string )+ len (field_name )
7248+ )
7249+ )
7250+
7251+ else :
7252+ sublime .error_message ("Cannot introduce property. Some problems occured." )
7253+
7254+ else :
7255+ sublime .error_message ("Cannot introduce property. Selection does not form an ExpressionStatement." )
7256+
7257+ def is_enabled (self , ** args ) :
7258+ view = self .view
7259+ if not Util .selection_in_js_scope (view ) :
7260+ return False
7261+ selection = view .sel ()[0 ]
7262+ return selection .begin () != selection .end ()
7263+
7264+ def is_visible (self , ** args ) :
7265+ view = self .view
7266+ if not Util .selection_in_js_scope (view ) :
7267+ return False
7268+ selection = view .sel ()[0 ]
7269+ return selection .begin () != selection .end ()
7270+
7271+
69667272import sublime , sublime_plugin
69677273import os
69687274
0 commit comments