zsh 완성 기능을 약간 확장하고 싶습니다.
전체 함수 본문을 내 홈 디렉터리에 넣는 것을 피하고 한 줄만 변경하고 싶습니다. 대신 호출을 가로채서 원래 함수를 직접 호출하고 싶습니다. 베어 코드에서:
<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 $@
}
제 경우에는 거의 모든 프로젝트에 cmake 속성이 있으므로 cmake 완성을 수정하고 싶습니다. 완료 시 이 옵션이 없으면 옵션이 아닌 프로젝트에 이 옵션이 있는 것보다 더 짜증납니다. 따라서 _cmake
어딘가에 복사하지 않고 _cmake_define_common_property_names()
내 위치에 복사하겠습니다 .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
}
그래서 빠진 것은 _cmake_define_common_property_names
새로운 함수 이름을 로드하고 할당하는 것입니다.
~에서여기나는 노력했다
autoload -Uz +X _cmake_define_common_property_names
그러나 이는 실패합니다(함수는 자체 파일에 정의되어 있지 않지만 _cmake
.
참고: 원래 버전에서 함수가 호출된 위치를 수정할 필요가 없도록 새 함수 이름을 지정하지 않았습니다.
부분적으로는 yes 작동 autoload -Uz +X _cmake
하지만 이는 _cmake
로드된 것만 확인합니다(를 호출하여 확인했습니다 functions _cmake
). 도우미 함수를 로드하지 않습니다 _cmake_define_common_property_names
.
그래서 내 두 가지 질문은
$fpath
파일에서 함수를 로드하는 방법- 일단 함수를 로드합니다. 이것을 스크립트에 복사하거나 새 함수 이름을 할당하려면 어떻게 해야 합니까?
답변1
기능을 패치하는 방법
함수의 코드는 연관 배열에 저장됩니다 functions
. 다음은 정규화된 공백이 있고 주석이 없는 소스 코드입니다(zsh가 어휘 분석을 수행하고 마크업을 보기 좋게 인쇄했습니다). 배열의 항목을 수정하여 함수의 코드를 변경할 수 있습니다 functions
. 예를 들어 시작 부분에 추가 코드를 추가하려면 다음을 수행하세요.
functions[_cmake_define_common_property_names]="
… # your extra code here
$functions[_cmake_define_common_property_names]"
변경하려는 내용이 단순히 원래 코드 앞과 뒤의 코드 실행과 관련된 경우(또는 더 일반적으로는 조건에 넣는 것과 같이) 함수를 새 이름으로 복사하고 해당 새 이름을 호출하도록 함수를 재정의할 수 있습니다. zsh 5.8부터는 다음 명령을 사용하여 쉽게 이 작업을 수행할 수 있습니다.functions -c
.
functions -c _cmake_define_common_property_names _cmake_define_common_property_names_orig
_cmake_define_common_property_names () {
…
_cmake_define_common_property_names_orig "$@"
}
또는 모든 zsh 버전에서 배열을 사용하여 functions
함수를 다른 이름으로 복사할 수도 있습니다.
functions[_cmake_define_common_property_names_orig]=$functions[_cmake_define_common_property_names]
_cmake_define_common_property_names () {
…
_cmake_define_common_property_names_orig "$@"
}
모든 기능 로드
자동 로드 파일에서 모든 기능을 로드하는 신뢰할 수 있는 유일한 방법은 기능을 실행하는 것입니다(부작용 없이 기능을 실행하도록 준비할 수 있는 경우). 완료 함수의 경우 함수를 실행하고 오류를 비트버킷으로 리디렉션하면 됩니다. 완료 컨텍스트에서 실행되지 않는다고 불평하고 아무 작업도 수행하지 않습니다.
_cmake 2>/dev/null
# Now _cmake_xxx is defined
autoload -Uz +X _cmake
작동하지 않는 이유는 도우미 함수가 _cmake
함수 자체에 정의되어 있기 때문입니다.
% echo $functions[_cmake]
builtin autoload -XU
% autoload -Uz +X _cmake
% echo $functions[_cmake]
…
(( $+functions[_cmake_define_property_names] )) || _cmake_define_property_names () {
…
}
…
local cmake_command_actions
cmake_command_actions=('-E[CMake command mode]:*:command')
_cmake_command () {
_arguments -C -s - command "$cmake_command_actions[@]"
}
local cmake_suggest_build
cmake_suggest_build=('--build[build]')
if [ $CURRENT -eq 2 ]
then
_arguments -C -s - help "$cmake_help_actions[@]" - command "$cmake_command_actions[@]" - build_opts "$cmake_build_options[@]" - build_cmds "$cmake_suggest_build[@]" && return 0
elif [[ $words[2] = --help* ]]
then
_cmake_help
elif [[ $words[2] != -E ]]
then
_cmake_on_build
else
_cmake_command
fi
최상위 기능을 실제로 실행하고 싶지 않은 경우 몇 가지 옵션이 있습니다.
_cmake_define_common_property_names
정의 내의 정의를 패치합니다_cmake
._cmake_define_common_property_names
의 정의에서 정의를 추출_cmake
하고 이를 사용하여_cmake_define_common_property_names_orig
또는 을 정의합니다_cmake_define_common_property_names
._cmake
함수 정의 이외의 부분을 제거하려면 정의를 패치한 후 실행합니다. 실제로는 작동하지 않지만_cmake
작업을 더 잘 수행하는 다른 구조가 있습니다. 예를 들어_cvs
순전히 조건부 함수 정의(예:(( $+functions[_cvs_command] )) || _cvs_command () { … }
), 제목 함수 정의, 마지막으로 제목 함수 호출로 구성되므로 모든 함수를 정의할 수 있지만 아무것도 할 수는 없습니다. 마지막 줄을 제거하여.autoload -Uz +X _cvs functions[_cvs]=${functions_cvs%'$\n'*} _cvs # Patch auxiliary functions here