def update_inserted_filepath(view, post_remove): """ post completion: adjusts inserted filepath """ expression = Context.get_context(view) # diff of previous needle and inserted needle diff = get_diff(post_remove, expression["needle"]) # cleanup string result = re.sub("^" + diff["start"], "", expression["needle"]) # do not replace current word if diff["end"] != start_expression["word"]: result = re.sub(diff["end"] + "$", "", result) # remove path query completely result = apply_post_replacements(result, state.get("base_directory"), state.get("replace_on_insert")) log("post cleanup path:'", expression.get("needle"), "' ~~> '", result, "'") # replace current query with final path view.run_command( "ffp_replace_region", { "a": expression["region"].a, "b": expression["region"].b, "string": result, "move_cursor": True })
def on_post_insert_completion(view, post_remove): start_expression = FuzzyFilePath.start_expression expression = Context.get_context(view) # diff of previous needle and inserted needle diff = get_diff(post_remove, expression["needle"]) # cleanup string final_path = re.sub("^" + diff["start"], "", expression["needle"]) # do not replace current word if diff["end"] != start_expression["word"]: final_path = re.sub(diff["end"] + "$", "", final_path) # remove path query completely final_path = Completion.get_final_path(final_path) 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, "move_cursor": True })
def update(): """ call me anytime a new view has gained focus. This includes activation of a new window, which should have an active view """ global valid, is_enabled if not is_enabled: return False temp = False window = sublime.active_window() if window is None: logger.log(ID, "Abort -- no active window") valid = False return valid view = window.active_view() if view is None: logger.log(ID, "Abort -- no active view") valid = False return valid file = Path.posix(view.file_name()) if not file: logger.log(ID, "Abort -- view has not yet been saved to file") temp = True return valid if state.get("file") == file: logger.log(ID, "Abort -- view already updated") return valid folders = list(map(lambda f: Path.posix(f), window.folders())) project_folder = get_closest_folder(file, folders) if project_folder is False: logger.log(ID, "Abort -- file not part of a project (folder)") valid = False return valid # notify settings of new project folder if state.get("project_folder") != project_folder: settings.update_project_settings() settings.update_project_folder_settings(project_folder) valid = True # @TODO cache state["file"] = file state["directory"] = sanitize_directory(file, project_folder) state["folders"] = folders state["project_folder"] = project_folder state["cache"] = get_file_cache(project_folder) logger.start_block() logger.verbose(ID, "Updated", state) return valid
def get_filepaths(view, query): global start_expression trigger = resolve_trigger(view, query) log(ID_TRIGGER, trigger) if query.build(start_expression.get("needle"), trigger, current_state.get_directory()) is False: # query is valid, but may not be triggered: not forced, no auto-options verbose(ID, "abort - no auto trigger found") return False # remembed the path for `update_inserted_filepath`, query will be reset... state["base_directory"] = query.get_post_remove_path() return current_state.search_completions( query.get_needle(), current_state.get_project_directory(), query.get_extensions(), query.get_base_path())
def rebuild_filecache(folder=None): if not folder: if state.get("cache"): logger.verbose( ID, "rebuild current filecache of folder " + state.get("project_folder")) state.get("cache").rebuild() return folder = Path.posix(folder) if not folder in file_caches: logger.log( ID, "Abort rebuild filecache -- folder " + folder + " not cached") return False logger.verbose(ID, "rebuild current filecache of folder " + folder) file_caches.get(folder).rebuild()
def run(self, edit): current_directory = os.path.dirname(self.view.file_name()) context = Context.get_context(self.view) if context.get("valid") is False: return log(ID, "abort, no valid path given:", context.get("needle")) path = context.get("needle") project_folder = state.get_project_directory() if not (path and project_folder): return log(ID, "path or project invalid", path, project_folder) is_relative = Path.is_relative(path) if is_relative: path = Path.get_absolute_path(current_directory, path) path = re.sub(project_folder, "", path) path = re.sub("^[\\\\/\.]", "", path) realpath = path # cleanup string, in case there are special characters for a path # e.g. webpack uses ~, which is not part of path path = re.sub("[^A-Za-z0-9 \-_\\\\/.%?#]*", "", path) files = state.find_file(path) if len(files) == 0: # it may be an uncached file, try to open it by using the real path if self.filepath_exists(os.path.join(project_folder, realpath)): return self.open_file(project_folder, realpath) return log(ID, "failed finding file", path, "it is not within the cache and not a realpath") if len(files) == 1: self.open_file(project_folder, files[0]) else: # if javascript, search for index.js current_scope = self.view.scope_name(Selection.get_position(self.view)) if re.search("\.js ", current_scope): for file in files: if "index.js" in file: return self.open_file(project_folder, file) self.files = files self.project_folder = project_folder self.view.show_popup_menu(files, self.select_file)
def get_filepath_completions(view): if not state.is_valid(): Query.reset() return False verbose(ID, "get filepath completions") completions = Completion.get_filepaths(view, Query) if completions and len(completions[0]) > 0: Completion.start(Query.get_replacements()) view.run_command('_enter_insert_mode') # vintageous log("{0} completions found".format(len(completions))) else: if Query.get_needle() is not None: sublime.status_message("FFP no filepaths found for '" + Query.get_needle() + "'") Completion.stop() Query.reset() return completions
def run(self, edit): current_directory = os.path.dirname(self.view.file_name()) context = Context.get_context(self.view) if context.get("valid") is False: return log(ID, "abort, no valid path given:", context.get("needle")) path = context.get("needle") project_folder = state.get_project_directory() if not (path and project_folder): return log(ID, "path or project invalid", path, project_folder) is_relative = Path.is_relative(path) if is_relative: path = Path.get_absolute_path(current_directory, path) path = re.sub(project_folder, "", path) path = re.sub("^[\\\\/\.]", "", path) files = state.find_file(path) if len(files) == 0: return log(ID, "failed finding file", path) if len(files) == 1: self.open_file(project_folder, files[0]) else: # if javascript, search for index.js current_scope = self.view.scope_name( Selection.get_position(self.view)) if re.search("\.js ", current_scope): for file in files: if "index.js" in file: return self.open_file(project_folder, file) self.files = files self.project_folder = project_folder self.view.show_popup_menu(files, self.select_file)
def on_post_insert_completion(view, post_remove): start_expression = FuzzyFilePath.start_expression expression = Context.get_context(view) # diff of previous needle and inserted needle diff = get_diff(post_remove, expression["needle"]) # cleanup string final_path = re.sub("^" + diff["start"], "", expression["needle"]) # do not replace current word if diff["end"] != start_expression["word"]: final_path = re.sub(diff["end"] + "$", "", final_path) # remove path query completely final_path = Completion.get_final_path(final_path) 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, "move_cursor": True })
def run(self, edit): current_directory = os.path.dirname(self.view.file_name()) context = Context.get_context(self.view) if context.get("valid") is False: return log(ID, "abort, no valid path given:", context.get("needle")) path = context.get("needle") project = ProjectManager.get_current_project() if not (path and project): return log(ID, "path or project invalid", path, project) is_relative = Path.is_relative(path) if is_relative: path = Path.get_absolute_path(current_directory, path) path = re.sub(project.get_directory(), "", path) path = re.sub("^[\\\\/\.]", "", path) files = project.find_file(path) if len(files) == 0: return log(ID, "failed finding file", path) if len(files) == 1: self.open_file(project.get_directory(), files[0]) else: # if javascript, search for index.js current_scope = self.view.scope_name(Selection.get_position(self.view)) if re.search("\.js ", current_scope): for file in files: if "index.js" in file: return self.open_file(project.get_directory(), file) self.files = files self.project_folder = project.get_directory() self.view.show_popup_menu(files, self.select_file)
def sanitize_base_directory(base_directory, project_directory, base_project_directory): """ validate possible base directory """ if not base_directory: return "" base_directory = get_valid_path(base_directory) # base_project_directory | /path/to/sublime/project # project_directory | /path/to/sublime/project/project_directory # - path_to_base_directory | /path/to/sublime/project/base_directory # + path_to_base_directory | /path/to/sublime/project/project_directory/base_directory path_to_base_directory = os.path.join(project_directory, base_directory) if not os.path.isdir(path_to_base_directory): # BASE_DIRECTORY is NOT a valid folder relative to (possibly modified) project_directory path_to_base_directory = os.path.join(base_project_directory, base_directory) if not os.path.isdir(path_to_base_directory): log("Error: setting's base_directory is not a valid directory in project" ) log("=> changing base_directory {0} to ''".format(base_directory)) return "" elif path_to_base_directory in project_directory: # change BASE_DIRECTORY to be '' since its outside of project directory log("Error: setting's base_directory is within project directory") log("=> changing base_directory {0} to ''".format(base_directory)) return "" else: # change BASE_DIRECTORY to be relative to modified project directory path_to_base_directory = path_to_base_directory.replace( project_directory, "") log("Error: setting's base_directory is not relative to project directory" ) log("=> changing base_directory '{0}' to '{1}'".format( base_directory, path_to_base_directory)) return get_valid_path(path_to_base_directory) return base_directory
def on_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): verbose(ID, "abort query, no valid scope-regex for current context") return False # parse current context, may contain 'is_valid: False' expression = Context.get_context(view) if expression["error"] and not Query.by_command(): verbose(ID, "abort not a valid context") return False # check if there is a trigger for the current expression trigger = Context.find_trigger(expression, current_scope, triggers) # verbose("trigger", trigger) # 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: verbose(ID, "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) verbose(ID, "changed invalid needle to {0}".format(expression["needle"])) else: verbose(ID, "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 verbose(ID, "abort valid query: auto trigger disabled") return False verbose(ID, ".───────────────────────────────────────────────────────────────") verbose(ID, "| scope settings: {0}".format(trigger)) verbose(ID, "| search needle: '{0}'".format(Query.needle)) verbose(ID, "| in base path: '{0}'".format(Query.base_path)) FuzzyFilePath.start_expression = expression completions = ProjectManager.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 on_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): verbose(ID, "abort query, no valid scope-regex for current context") return False # parse current context, may contain 'is_valid: False' expression = Context.get_context(view) if expression["error"] and not Query.by_command(): verbose(ID, "abort not a valid context") return False # check if there is a trigger for the current expression trigger = Context.find_trigger(expression, current_scope, triggers) # verbose("trigger", trigger) # 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: verbose(ID, "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) verbose( ID, "changed invalid needle to {0}".format(expression["needle"])) else: verbose(ID, "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 verbose(ID, "abort valid query: auto trigger disabled") return False verbose( ID, ".───────────────────────────────────────────────────────────────") verbose(ID, "| scope settings: {0}".format(trigger)) verbose(ID, "| search needle: '{0}'".format(Query.needle)) verbose(ID, "| in base path: '{0}'".format(Query.base_path)) FuzzyFilePath.start_expression = expression completions = ProjectManager.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