Refactoring of code and update of zsh plugin for fedit script
This commit is contained in:
		
							
								
								
									
										75
									
								
								fedit.py
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								fedit.py
									
									
									
									
									
								
							| @@ -14,27 +14,31 @@ import shutil | ||||
| import subprocess | ||||
|  | ||||
| # ========== Constants ========== | ||||
| # Paths | ||||
| # ----- Paths ----- | ||||
| BOOT_DIR = "/boot" | ||||
| ETC_DIR = "/etc" | ||||
|  | ||||
| # Exit Codes | ||||
| # ----- Exit Codes ----- | ||||
| E_NOEDITORFOUND = 2 | ||||
| E_NOFILESELECTED = 3 | ||||
|  | ||||
| # Commands | ||||
| # ----- Commands ----- | ||||
| FIND_CMD = "/usr/bin/fd" | ||||
| FIND_OPTS = ["--hidden", "--print0", "--type", "f", "--no-ignore-vcs"] | ||||
| FZF_CMD = "/usr/bin/fzf" | ||||
| FZF_OPTS = ["--read0", "--select-1", "--exit-0", "--print0"] | ||||
| FIND_OPTS = ["--hidden", "--print0", "--type", "f"] | ||||
| EXTRA_FIND_OPTS = {"no_ignore_vcs": "--no-ignore", "no_ignore": "--no-ignore-vcs"} | ||||
|  | ||||
| LOCATE_CMD = "/usr/bin/locate" | ||||
| LOCATE_OPTS = ["--all", "--ignore-case", "--null"] | ||||
|  | ||||
| FZF_CMD = "/usr/bin/fzf" | ||||
| FZF_OPTS = ["--read0", "--select-1", "--exit-0", "--print0"] | ||||
|  | ||||
| # ----- Misc. ----- | ||||
| LOCALE = "utf-8" | ||||
|  | ||||
|  | ||||
| # ========== Functions ========== | ||||
| def select_editor(editor_override=None): | ||||
| def select_editor(override=None): | ||||
|     """Return a possible canonical path to an editor. | ||||
|     Select an editor from one of: | ||||
|     * -e, --editor | ||||
| @@ -45,15 +49,15 @@ def select_editor(editor_override=None): | ||||
|  | ||||
|     If an editor cannot be resolved, then an Error is raised instead. | ||||
|  | ||||
|     :param editor_override: argument to override an editor | ||||
|     :param override: argument to override an editor | ||||
|     :returns: path to one of these editors | ||||
|     :rtype: str | ||||
|     :raises: FileNotFoundError if an editor could not be resolved | ||||
|     """ | ||||
|     editor = None | ||||
|  | ||||
|     if editor_override is not None: | ||||
|         editor = shutil.which(editor_override) | ||||
|     if override is not None: | ||||
|         editor = shutil.which(override) | ||||
|     elif "EDITOR" in os.environ: | ||||
|         editor = shutil.which(os.environ.get("EDITOR")) | ||||
|     elif shutil.which("vim") is not None: | ||||
| @@ -69,12 +73,16 @@ def gen_editor_cmd(filename): | ||||
|     """Generate a command line to run for editing a file based on | ||||
|     permissions. | ||||
|  | ||||
|     This command does not pass extra options to the editor, hence | ||||
|     there are no arguments to pass for options. | ||||
|  | ||||
|     :param filename: name of file to edit | ||||
|     :type filename: str or path-like object | ||||
|     :returns: command to execute to edit file | ||||
|     :rtype: list | ||||
|     """ | ||||
|     # possible for a race condition to occur here | ||||
|     # Possible for a race condition to occur here | ||||
|     # What happens if the file or its metadata changes? | ||||
|     if os.access(filename, os.W_OK): | ||||
|         return [editor, filename] | ||||
|     else: | ||||
| @@ -90,21 +98,24 @@ def run_fzf(files): | ||||
|     :rtype: str | ||||
|     """ | ||||
|     selected_file = subprocess.run( | ||||
|         [FZF_CMD] + FZF_OPTS, input=files, stdout=subprocess.PIPE | ||||
|         [FZF_CMD, *FZF_OPTS], input=files, stdout=subprocess.PIPE | ||||
|     ).stdout | ||||
|  | ||||
|     return selected_file.decode(LOCALE).strip("\x00") | ||||
|  | ||||
|  | ||||
| def find_files(directory=None): | ||||
| def find_files(opts, directory=None): | ||||
|     """Use a find-based program to locate files, then pass to fzf. | ||||
|  | ||||
|     :param opts: options to pass to the find program | ||||
|     :type opts: list of str | ||||
|     :param directory: directory to search for files | ||||
|     :type directory: str | ||||
|     :returns: path of user-selected file | ||||
|     :rtype: bytes | ||||
|     """ | ||||
|     cmd = [FIND_CMD] + FIND_OPTS | ||||
|     cmd = [FIND_CMD, *opts] | ||||
|  | ||||
|     if directory is not None: | ||||
|         cmd.extend(["--", ".", directory]) | ||||
|  | ||||
| @@ -126,6 +137,7 @@ def locate_files(patterns): | ||||
|  | ||||
|  | ||||
| # ========== Main Script ========== | ||||
| if __name__ == "__main__": | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument( | ||||
|         "-b", | ||||
| @@ -146,12 +158,32 @@ parser.add_argument( | ||||
|         dest="dir", | ||||
|         help="edit a file in /etc", | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         "-I", | ||||
|         "--no-ignore", | ||||
|         action="append_const", | ||||
|         const="--no-ignore", | ||||
|         dest="extra_find_opts", | ||||
|         help="do not respect .(git|fd)ignore files", | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         "-i", | ||||
|         "--no-ignore-vcs", | ||||
|         action="append_const", | ||||
|         const="--no-ignore-vcs", | ||||
|         dest="extra_find_opts", | ||||
|         help="do not respect .gitignore files", | ||||
|     ) | ||||
|     parser.add_argument("-e", "--editor", help="use a given editor") | ||||
| parser.add_argument("patterns", type=str, nargs="*", help="patterns to pass to locate") | ||||
|     parser.add_argument( | ||||
|         "patterns", type=str, nargs="*", help="patterns to pass to locate" | ||||
|     ) | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
| final_find_cmd = [FIND_CMD] + FIND_OPTS | ||||
|     user_opts = [] if args.extra_find_opts is None else args.extra_find_opts | ||||
|     user_opts.extend(FIND_OPTS) | ||||
|  | ||||
|     editor = "" | ||||
|  | ||||
|     try: | ||||
| @@ -162,14 +194,15 @@ except FileNotFoundError as e: | ||||
|  | ||||
|     # If patterns were passed, use locate | ||||
|     # Otherwise check for -d and use fd | ||||
| if not args.patterns == []: | ||||
|     files = locate_files(args.patterns) | ||||
| else: | ||||
|     files = find_files(args.dir) | ||||
|     files = ( | ||||
|         find_files(user_opts, args.dir) | ||||
|         if not args.patterns | ||||
|         else locate_files(args.patterns) | ||||
|     ) | ||||
|  | ||||
|     selected_file = run_fzf(files) | ||||
|  | ||||
| if not selected_file == "": | ||||
|     if selected_file != "": | ||||
|         cmd = gen_editor_cmd(selected_file) | ||||
|         subprocess.run(cmd) | ||||
|     else: | ||||
|   | ||||
| @@ -7,6 +7,8 @@ arguments=( | ||||
|   {-d,--dir}'[edit a file in a given directory]' | ||||
|   {-E,--etc}'[edit a file in /etc]' | ||||
|   {-e,--editor}'[use a given editor]' | ||||
|   {-I,--no-ignore}'[do not respect  .(git|fd)ignore files]' | ||||
|   {-i,--no-ignore-vcs}'[do not respect .gitignore files]' | ||||
|   '*:filename:_files' | ||||
| ) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user