From 4569e97200a6a2c21eeb0b108f75051a5ece3fae Mon Sep 17 00:00:00 2001 From: Eric Torres Date: Tue, 12 Feb 2019 12:24:10 -0800 Subject: [PATCH] Reimplement fedit script in Python --- fedit.py | 106 ++++++++++++++++++++++++++++++++++++++++++++ fedit.sh | 132 ------------------------------------------------------- 2 files changed, 106 insertions(+), 132 deletions(-) create mode 100644 fedit.py delete mode 100644 fedit.sh diff --git a/fedit.py b/fedit.py new file mode 100644 index 0000000..5bad880 --- /dev/null +++ b/fedit.py @@ -0,0 +1,106 @@ +#!/usr/bin/python3 +""" +Fuzzy-find a file and edit it. + +Dependencies +============ +* fd +* fzf +""" + +import argparse +import os +import shutil +import subprocess + +# ========== Constants ========== +# Paths +BOOT_DIR = '/boot' +ETC_DIR = '/etc' + +# Exit Codes +E_NOEDITORFOUND = 2 +E_NOFILESELECTED = 3 + +# Commands +FIND_CMD = shutil.which('fd') +FIND_OPTS = ['--hidden', '--print0', '--type', 'f', '--no-ignore-vcs'] +FZF_CMD = shutil.which('fzf') +FZF_OPTS = ['--read0', '--select-1', '--exit-0'] + + +# ========== Functions ========== +def select_editor(editor_override=None): + """Return a possible canonical path to an editor. + Select an editor from one of: + * -e, --editor + * $EDITOR + * Default of vim + + In this order + + If an editor cannot be resolved, then an Error is raised instead. + + :param editor_override: argument to override an editor + :returns: path to one of these editors + :rtype: str + :raises: FileNotFoundError if an editor could not be resolved + """ + if editor_override is not None: + return shutil.which(editor_override) + elif 'EDITOR' in os.environ: + return shutil.which(os.environ.get('EDITOR')) + elif shutil.which('vim') is not None: + return shutil.which('vim') + else: + raise FileNotFoundError('An editor could not be resolved') + + +# ========== Main Script ========== +parser = argparse.ArgumentParser() +parser.add_argument('-b', '--boot', + action='store_const', + const=BOOT_DIR, + dest='dir', + help='edit a file in /boot') +parser.add_argument('-d', '--dir', + dest='dir', + type=str, + help='edit a file in a given directory') +parser.add_argument('-E', '--etc', + action='store_const', + const=ETC_DIR, + dest='dir', + help='edit a file in /etc') +parser.add_argument('-e', '--editor', + help='use a given editor') + +args = parser.parse_args() + +final_find_cmd = [FIND_CMD] + FIND_OPTS +extra_opts = [] +editor = '' + +try: + editor = select_editor(args.editor) +except FileNotFoundError as e: + print(e) + exit(E_NOEDITORFOUND) + +if args.dir is not None: + extra_opts.extend(['.', '--', args.dir]) + +final_find_cmd.extend(extra_opts) + +files = subprocess.run(final_find_cmd, + text=True, + capture_output=True) +filename = subprocess.run([FZF_CMD] + FZF_OPTS, + input=files.stdout, + text=True, + stdout=subprocess.PIPE).stdout + +if filename is not None: + subprocess.run([editor, filename.strip('\n')]) +else: + exit(E_NOFILESELECTED) diff --git a/fedit.sh b/fedit.sh deleted file mode 100644 index fb0bc03..0000000 --- a/fedit.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/bash -# fedit - fuzzy find a file and edit it -# Dependencies -# - fd -# - fzf - -help() { -cat << EOF -Usage: fedit [-h|--help] [-b|--boot] [-d|--dir directory] [-e|--etc] [-E|--editor editor] -Options: - -b, --boot edit a file in /boot/loader - -d, --dir edit a file in a given directory - -e, --etc edit a file in /etc - -E, --editor use a given editor (default: ${EDITOR:-none}) - -h, --help print this help page -EOF -} - -[[ ! -f /usr/bin/fzf ]] && exit 1 - -# Error messages -readonly directory_error="Error, enter a directory" -readonly noeditor_error="Error, no editor entered" - -# Pre-run correctness checks -unset find_opts -file= -dir= -editor= - -while true; do - case "${1}" in - '-b'|'--boot') - dir="/boot/loader" - shift - continue - ;; - '-d'|'--dir') - case "${2}" in - "") - printf '%s\n' "${directory_error}" >&2 - exit 1 - ;; - *) - dir="${2}" - [[ ! -d "${dir}" ]] && printf '%s\n' "Not a directory: ${dir}" >&2 && exit 1 - ;; - esac - shift 2 - continue - ;; - --dir=*) - dir="${1#*=}" - [[ -z "${dir}" ]] && printf '%s\n' "${directory_error}" >&2 && exit 1 - [[ ! -d "${dir}" ]] && printf '%s\n' "Not a directory: ${dir}" >&2 && exit 1 - shift - continue - ;; - '-e'|'--etc') - dir='/etc' - shift - continue - ;; - '-E'|'--editor') - editor="${2}" - case "${2}" in - "") - printf '%s\n' "${noeditor_error}" >&2 - exit 1 - ;; - -*) - printf '%s\n' "Not an editor: ${editor}" >&2 - exit 1 - ;; - esac - shift 2 - continue - ;; - --editor=*) - editor="${1#*=}" - [[ -z "${editor}" ]] && printf '%s\n' "${noeditor_error}" >&2 && exit 1 - shift - continue - ;; - '-h'|'--help') - help - exit - ;; - --) - shift - break - ;; - -*) - printf '%s\n' "Unknown option: ${1}" - exit 1 - ;; - *) - break - ;; - esac -done - -declare -a find_opts -if [[ -x '/usr/bin/fd' ]]; then - find_bin='/usr/bin/fd' - find_opts+=('--hidden') - find_opts+=('--print0') - find_opts+=('--type' 'f') - find_opts+=('--no-ignore-vcs') - [[ -n "${dir}" ]] && find_opts+=('.' -- "${dir}") -else - find_bin='/usr/bin/find' - [[ -n "${dir}" ]] && find_opts+=("${dir}") || find_opts+=('.') - find_opts+=('-mindepth' '0') - find_opts+=('-type' 'f') - find_opts+=('-print0') -fi - -if [[ -z "${editor:-${EDITOR}}" ]]; then - printf '%s\n' "No editor found" >&2 - exit 1 -fi - -file="$("${find_bin}" "${find_opts[@]}" 2> /dev/null | fzf --read0 --select-1 --exit-0)" - -[[ ! "${file}" ]] && exit 1 - -if [[ -w "${file}" ]]; then - "${editor:-${EDITOR}}" -- "${file}" -else - sudo --edit -- "${file}" -fi