def cleanup_completion(view, post_remove): expression = Context.get_context(view) # remove path query completely final_path = Completion.get_final_path(expression["needle"], post_remove) log("post cleanup path:'", expression.get("needle"), "' ~~> '", final_path, "'") # replace current query with final path view.run_command("ffp_replace_region", { "a": expression["region"].a, "b": expression["region"].b, "string": final_path })
def get_final_path(path, path_needle): # print("cleanup path", path, "needle:", path_needle) #st2 - remove path_needle fragments #remove anything before last word separator? part_to_remove = re.escape(re.sub("[^\/]*$", "", path_needle)) # print("remove:", part_to_remove) path = re.sub("^" + part_to_remove, "", path) # print("cleanup #1", path) # st2 - sanitize if re.search("\/\.\/", path): path = re.sub("^(\.\.\/)*", "", path) path = re.sub("^(\.\/)+", "./", path) path = re.sub("^(\/\/)+", "/", path) # hack reverse path = re.sub(config["ESCAPE_DOLLAR"], "$", path) for replace in Completion.replaceOnInsert: path = re.sub(replace[0], replace[1], path) if Completion.base_directory and path.startswith("/"): path = re.sub("^\/" + Completion.base_directory, "", path) path = Path.sanitize(path) log("final filepath: '{0}'".format(path)) return path
def update_settings(): """ restart projectFiles with new plugin and project settings """ global project_files, scope_cache scope_cache.clear() settings = sublime.load_settings(config["FFP_SETTINGS_FILE"]) # st2 - has to check window project_settings = False current_window = sublime.active_window() if current_window: project_settings = current_window.active_view().settings().get('FuzzyFilePath', False) # sync settings to config for key in config: config[key] = settings.get(key.lower(), config[key]) # mapping config["TRIGGER"] = settings.get("scopes", config["TRIGGER"]) # merge project settings stored in "settings: { FuzzyFilePath: ..." if project_settings: # mapping config["TRIGGER"] = project_settings.get("scopes", config["TRIGGER"]) for key in config: config[key] = project_settings.get(key.lower(), config[key]) # build extensions to suggest extensionsToSuggest = [] for scope in config["TRIGGER"]: ext = scope.get("extensions", []) extensionsToSuggest += ext # remove duplicates extensionsToSuggest = list(set(extensionsToSuggest)) project_files = ProjectFiles() project_files.update_settings(extensionsToSuggest, config["EXCLUDE_FOLDERS"]) # validate directories if config["BASE_DIRECTORY"]: config["BASE_DIRECTORY"] = Path.sanitize_base_directory(config["BASE_DIRECTORY"]) if config["PROJECT_DIRECTORY"]: config["PROJECT_DIRECTORY"] = Path.sanitize_base_directory(config["PROJECT_DIRECTORY"]) log("logging enabled") log("project base directory set to '{0}'".format(config["BASE_DIRECTORY"])) log("{0} scope triggers loaded".format(len(config["TRIGGER"])))
def query_completions(view, project_folder, current_folder): global Context, Selection current_scope = Selection.get_scope(view) if not Query.by_command(): triggers = get_matching_autotriggers(current_scope, config["TRIGGER"]) else: triggers = config["TRIGGER"] if not bool(triggers): log("abort query, no valid scope-regex for current context") return False # parse current context, may contain 'is_valid: False' expression = Context.get_context(view) # check if there is a trigger for the current expression trigger = Context.find_trigger(expression, current_scope, triggers) # expression | trigger | force | ACTION | CURRENT # -----------|----------|-------|-------------------|-------- # invalid | False | False | abort | abort # invalid | False | True | query needle | abort # invalid | True | False | query | # invalid | True | True | query +override | # valid | False | False | abort | abort # valid | False | True | query needle | abort # valid | True | False | query | # valid | True | True | query +override | # currently trigger is required in Query.build if trigger is False: log("abort completion, no trigger found") return False if not expression["valid_needle"]: word = Selection.get_word(view) expression["needle"] = re.sub("[^\.A-Za-z0-9\-\_$]", "", word) log("changed invalid needle to {0}".format(expression["needle"])) else: log("context evaluation {0}".format(expression)) if Query.build(expression.get("needle"), trigger, current_folder, project_folder) is False: # query is valid, but may not be triggered: not forced, no auto-options log("abort valid query: auto trigger disabled") return False if Query.base_path: Query.base_path = str(Query.base_path) completions = project_files.search_completions(Query.needle, project_folder, Query.extensions, Query.base_path) if completions and len(completions[0]) > 0: Completion.start(Query.replace_on_insert) view.run_command('_enter_insert_mode') # vintageous log("=> {0} completions found".format(len(completions))) else: sublime.status_message("FFP no filepaths found for '" + Query.needle + "'") Completion.stop() log("=> no valid files found for needle: {0}".format(Query.needle)) log("") Query.reset() return completions
def build(needle, trigger, current_folder, project_folder): force_type = Query.get("filepath_type", False) triggered = Query.by_command() filepath_type = "relative" needle = Path.sanitize(needle) needle_is_absolute = Path.is_absolute(needle) needle_is_relative = Path.is_relative(needle) needle_is_path = needle_is_absolute or needle_is_relative # abort if autocomplete is not available if not triggered and trigger.get("auto", False) is False and needle_is_path is False: return False # test path to trigger auto-completion by needle if not triggered and trigger["auto"] is False and config["AUTO_TRIGGER"] and needle_is_absolute: force_type = "absolute" # base_directory: override - trigger - False base_directory = trigger.get("base_directory", False) base_directory = Query.get("base_directory", base_directory) # # set current directory by force, else by trigger: # # trigger | # --------------|-------------------- # False | use current file's directory # True | use settings: base_directory # String | use string as base_directory # change base folder to base directory # # st2? - fix missing or bugged base_directory adjusted_basepath = current_folder if base_directory is True: adjusted_basepath = config["BASE_DIRECTORY"] elif base_directory: adjusted_basepath = Path.sanitize_base_directory(base_directory) # notify completion to replace path if base_directory and needle_is_absolute: Completion.base_directory = current_folder # st2? - fix missing or bugged base_directory if adjusted_basepath is False: adjusted_basepath = current_folder # # filepath_type # # needle | trigger rel | force | RESULT # ----------|---------------|-----------|--------- # ? | relative | False | relative # ? | absolute | False | absolute # absolute | * | False | absolute # relative | * | False | relative # * | * | relative | relative # * | * | absolute | absolute # if force_type: filepath_type = force_type elif needle_is_absolute: filepath_type = "absolute" elif needle_is_relative: filepath_type = "relative" elif trigger.get("relative") is True: filepath_type = "relative" elif trigger.get("relative") is False: filepath_type = "absolute" Query.base_path = current_folder if filepath_type == "relative" else False # replacements: override - trigger - None Query.replace_on_insert = trigger.get("replace_on_insert", []) Query.replace_on_insert = Query.get("replace_on_insert", Query.replace_on_insert) # extensions: override - trigger - "js" Query.extensions = trigger.get("extensions", ["*"]) Query.extensions = Query.get("extensions", Query.extensions) Query.needle = Query.build_needle_query(needle, current_folder) log("\nfilepath type\n--------") log("type:", filepath_type) log("base_path:", Query.base_path) log("needle:", Query.needle) log("current folder", current_folder) return triggered or (config["AUTO_TRIGGER"] if needle_is_path else trigger.get("auto", config["AUTO_TRIGGER"]))