I would like to slightly extend a zsh completion function.
I would like to avoid putting the complete function body into my homedir with only one line changed. Instead I would like to intercept it's call and then call the original function myself. In quasi code:
<make sure _the_original_function is loaded>
_backup_of_original_function=_the_original_function
_the_original_function() {
_arguments "-superduper[that one option I always need]"
_backup_of_originial_function $@
}
In my concrete case, I have an cmake property in practically all my projects such that I would like to modify the cmake completion. Not having that option in the completion would annoy me much more than having it in projects where the option does not belong. So instead of copying _cmake
somewhere I would just redefine _cmake_define_common_property_names()
in my .zshrc
:
_cmake_define_common_property_names() {
local properties; properties=(
'MY_GREAT_OPTION:be awesome'
)
_describe -t 'my-property-names' 'my property name' properties $@
**call original _cmake_define_common_property_names here
}
So what's missing is loading _cmake_define_common_property_names
and assigning a new function name to it.
From here I tried
autoload -Uz +X _cmake_define_common_property_names
but this fails (the function is not defined within its own file, but rather in _cmake
.
NB: I don't assign a new function name to avoid having to modify the place from where the function gets called in its original version.
What works partially is autoload -Uz +X _cmake
BUT this only ensures that _cmake
is loaded (which I verify by calling functions _cmake
). It does not load the helper function _cmake_define_common_property_names
.
So my two questions are
- how do I load a function from within an
$fpath
file - Once I have a function loaded. How do I copy it in a script / Assign a new function name?
Best Answer
How to patch a function
The code of a function is stored in the associative array
functions
. That's the source code with normalized whitespace and no comments (zsh has done lexical analysis and pretty-prints the tokens). You can change the code of a function by modifying the entry of thefunctions
array. For example, to add extra code at the beginning:You can also use the
functions
array to copy a function to another name. This is the easiest way to wrap around an existing function.Loading all the functions
The only sure-fire way to load all the functions from a file made for autoload is to execute the function, if you can arrange to execute it with no side effects. For a completion function, just run the function with errors redirected to the bit bucket. It'll do nothing but complain that it isn't being executed in a completion context.
The reason
autoload -Uz +X _cmake
doesn't work is that the definitions of the auxiliary functions are in the_cmake
function itself.If you really don't want to execute the toplevel function, you have several choices:
_cmake_define_common_property_names
inside the definition of_cmake
._cmake_define_common_property_names
from the definition of_cmake
and use that to define_cmake_define_common_property_names_orig
or_cmake_define_common_property_names
.Patch the definition of
_cmake
to remove the parts other than the function definitions, then execute it. It isn't really workable with_cmake
, but some other completion functions are better structured. For example_cvs
consists purely of conditional function definitions (e.g.(( $+functions[_cvs_command] )) || _cvs_command () { … }
), a definition of the titular function, and a call of the titular function as the very last thing, thus you can define all the function but not execute anything by removing the last line.