Reimplement fedit script in Python

This commit is contained in:
Eric Torres 2019-02-12 12:24:10 -08:00
parent 8c064a13b2
commit 4569e97200
2 changed files with 106 additions and 132 deletions

106
fedit.py Normal file
View File

@ -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)

132
fedit.sh
View File

@ -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