zshの既存の機能のオーバーライドと再利用

zshの既存の機能のオーバーライドと再利用

zshコンプリート機能を少し拡張したいです。

関数全体の本文を私のホームディレクトリに入れることを避け、1行だけ変更したいと思います。代わりに、呼び出しを傍受して元の関数を直接呼び出したいと思います。ベアコードから:

<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

だから私の2つの質問は

  1. $fpathファイルから関数をロードする方法
  2. 一度関数をロードします。これをスクリプトにコピーしたり、新しい関数名を割り当てるにはどうすればよいですか?

答え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
    

関連情報