1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
# localization: tier1
function funced --description 'Edit function definition'
set -l options h/help 'e/editor=' i/interactive s/save
argparse -n funced --max-args=1 $options -- $argv
or return
if set -q _flag_help
__fish_print_help funced
return 0
end
if not set -q argv[1]
printf (_ "%s: Expected at least %d args, got only %d\n") funced 1 0
return 1
end
set -l funcname $argv[1]
# Check VISUAL first since theoretically EDITOR could be ed.
set -l editor
if set -q _flag_interactive
set editor fish
else if set -q _flag_editor
echo $_flag_editor | read -at editor
else if set -q VISUAL
echo $VISUAL | read -at editor
else if set -q EDITOR
echo $EDITOR | read -at editor
else
set editor fish
end
set -l init
switch $funcname
case '-*'
set init function -- $funcname\n\nend
case '*'
set init function $funcname\n\nend
end
if not type -q -f "$editor[1]"
echo (_ "funced: The value for \$EDITOR '$editor' could not be used because the command '$editor[1]' could not be found") >&2
set editor fish
end
if test "$editor" = fish
if functions -q -- $funcname
functions --no-details -- $funcname | fish_indent --only-unindent | fish_indent --no-indent | read -z init
end
set -l prompt 'printf "%s%s%s> " (set_color green) $funcname (set_color normal)'
if read -p $prompt -c "$init" --shell cmd
echo -n $cmd | fish_indent --only-unindent | read -lz cmd
eval "$cmd"
end
if set -q _flag_save
funcsave $funcname
end
return 0
end
# Create a directory so we can use a ".fish" suffix for the file -
# makes editors pick up that it's a fish file.
set -l tmpdir (__fish_mktemp_relative -d fish-funced)
or return 1
set -l tmpname $tmpdir/$funcname.fish
set -l writepath
if not functions -q -- $funcname
echo $init >$tmpname
else if not string match --quiet --regex '^(?:n/a|not-autoloaded|autoloaded)$' -- (functions --details --verbose -- $funcname)[2]
# Pretend this copied function does not have a definition file. Editing the file which
# originally defined it would not update this copy, and the file which copied it
# would not have a function body to edit. (issue #11614)
functions -- $funcname >$tmpname
else if functions --details -- $funcname | string match --invert --quiet --regex '^(?:-|stdin|embedded:.*)$'
set writepath (functions --details -- $funcname)
# Use cat here rather than cp to avoid copying permissions
cat "$writepath" >$tmpname
else if set -l path (functions --details -- $funcname | string match -rg '^embedded:(.*)$')
status get-file $path >$tmpname
else
functions -- $funcname >$tmpname
end
# Repeatedly edit until it either parses successfully, or the user cancels
# If the editor command itself fails, we assume the user cancelled or the file
# could not be edited, and we do not try again
while true
set -l checksum (__fish_md5 "$tmpname")
if not $editor $tmpname
echo (_ "Editing failed or was cancelled")
else
# Verify the checksum (if present) to detect potential problems
# with the editor command
if set -q checksum[1]
set -l new_checksum (__fish_md5 "$tmpname")
if test "$new_checksum" = "$checksum"
echo (_ "Editor exited but the function was not modified")
echo (_ "If the editor is still running, check if it waits for completion, maybe a '--wait' option?")
# Source but don't save an unmodified file.
# (Source in case the file changed externally since we first loaded it.)
if set -q writepath[1]
source "$writepath"
end
break
end
end
if not source <$tmpname
# Failed to source the function file. Prompt to try again.
echo # add a line between the parse error and the prompt
set -l repeat
set -l prompt (_ 'Edit the file again? [Y/n]')
read -P "$prompt " response
if test -z "$response"
or contains $response {Y,y}{E,e,}{S,s,}
continue
else if not contains $response {N,n}{O,o,}
echo "I don't understand '$response', assuming 'Yes'"
sleep 2
continue
end
echo (_ "Cancelled function editing")
else if test -n "$writepath"
if not set -q _flag_save
echo (_ "Warning: the file containing this function has not been saved. Changes may be lost when fish is closed.")
set -l prompt (printf (_ 'Save function to %s? [Y/n]') "$writepath")
read --prompt-str "$prompt " response
if test -z "$response"
or contains $response {Y,y}{E,e,}{S,s,}
set _flag_save 1
else if not contains $response {N,n}{O,o,}
echo "I don't understand '$response', assuming 'Yes'"
set _flag_save 1
end
end
if set -q _flag_save
# try to write the file back
# cp preserves existing permissions, though it might overwrite the owner
if cp $tmpname "$writepath" 2>&1
printf (_ "Function saved to %s") "$writepath"
echo
# read it back again - this ensures that the output of `functions --details` is correct
source "$writepath"
else
echo (_ "Saving to original location failed; saving to user configuration instead.")
set writepath $__fish_config_dir/functions/(path basename "$writepath")
if cp $tmpname "$writepath"
printf (_ "Function saved to %s") "$writepath"
echo
# read it back again - this ensures that the output of `functions --details` is correct
source "$writepath"
else
echo (_ "Saving to user configuration failed. Changes may be lost when fish is closed.")
end
end
end
else if set -q _flag_save
funcsave $funcname
else
printf (_ "Run funcsave %s to save this function to the configuration directory.") $funcname
echo
end
end
break
end
set -l stat $status
command rm $tmpname >/dev/null
and rmdir $tmpdir >/dev/null
return $stat
end
|