fish への貢献

このドキュメントでは、fish への貢献方法について説明します。

fish は、GPLv2 の条件の下で配布されているフリーでオープンソースのソフトウェアです。

貢献は大歓迎です。また、貢献には多くの方法があります!

Rust で書かれたコアソースの変更、補完スクリプトや関数の強化・追加、ドキュメントの改善や翻訳など、どのような形であれ、このドキュメントでその方法を確認できます。

メーリングリスト

パッチは公開メーリングリスト( mailto:~krobelus/fish-shell@lists.sr.ht )に送信してください。アーカイブは https://lists.sr.ht/~krobelus/fish-shell/ で閲覧可能です。

GitHub

fish は GitHub( https://github.com/fish-shell/fish-shell )で公開されています。

まず、GitHubのアカウントと fish の git クローンが必要です。GitHub でフォークしてから、以下を実行してください。:

git clone https://github.com/<USERNAME>/fish-shell.git

これにより、現在のカレントディレクトリ内の fish-shell ディレクトリに fish リポジトリのコピーが作成されます。

また、ほとんどの変更においてテストを実行する必要があるため、fish をコンパイルするためのセットアップが必要になります。そのためには以下が必要です。

  • Rust - 不明な場合は rustup を試してください

  • CMake

  • PCRE2(ヘッダーとライブラリ) - 任意。見つからない場合はダウンロードされます

  • gettext(msgfmt ツールのみ) - 任意。翻訳サポート用

  • Sphinx - 任意。ドキュメントのビルド用

もちろん、常にすべてが必要なわけではありません。ドキュメントに貢献したいだけであれば Sphinx だけで十分ですし、変更が非常に単純で明白なものであればそのまま送ってもかまいません。状況に応じて判断してください!

変更が完了したら、https://github.com/fish-shell/fish-shell/pulls でプルリクエストを作成してください。

ガイドライン

簡潔に:

  • 必要とするものに対して保守的であること(合意された最小サポートRustバージョンを維持し、新しい依存関係を制限する)

  • 自動化ツールを活用すること(cargo xtask check)

コミット履歴

私たちは、線形で「レシピ形式(recipe-style)」の履歴を採用しています。 すべてのコミットは、私たちのチェックをパスする必要があります。 履歴に「修正用(fixup)」コミットを残すことは望んでいません。 プルリクエスト内のコミットに問題が見つかった場合や、変更を促すフィードバックを受けた場合は、新しい「修正用」コミットを追加するのではなく、コミット履歴を書き換えて該当するコミットを直接修正してください。 プルリクエストの準備が整い次第、現在のmasterブランチの先頭にリベースします。そのため、まだmasterに反映されていないコミット履歴を書き換えることをためらわないでください。 最新のmasterに対してプルリクエストをリベース(マージではなく)することも歓迎します。特にコンフリクトを解消する場合には有効です。

Gitを使用している場合は、作業を容易にするために jj <https://www.jj-vcs.dev/>__ の使用を検討してください。

コミットによって問題を解決する場合は、コミット説明の最後に Fixes #<issue-number> という行を追加してください。

補完スクリプトの貢献

補完スクリプトは fish への最も一般的な貢献であり、非常に歓迎されます。

一般的に、公開されているコマンドに対する適切に記述された補完スクリプトであれば、すべて受け入れます。つまり、非公開のツールや個人的なスクリプトは対象外です。また、その他の理由で拒否する権利を留保します。

fish 本体に貢献する前に、補完対象ツールの作者自身がそのスクリプトをメンテナンスしたいと考えていないか検討してください。多くの場合、作者側で管理する方が合理的です。新しいオプションを追加した際に即座に補完を更新でき、複数のバージョンに対して一つの補完スクリプトを維持する手間も省けるからです。もし作者がメンテナンスの継続を望まない場合は、もちろん fish メンテナに連絡して引き継ぐことができます(PR を作成するのが望ましいです)。これは必須ではありません。作者がメンテナンスを望まない場合や、単に連絡を取りたくない場合は、スクリプトを fish に直接提供していただいて構いません。

補完スクリプトの指針

  1. 依存関係を可能な限り少なくしてください。 grepawk の代わりに string などの fish 組み込みコマンドを使い、jq の代わりに python を使って JSON を読み取るようにしてください(Python は fish ツールの緩やかな依存関係に含まれているためです)。

  2. 一般的な Unix ツールを使用する場合は、POSIX 準拠の呼び出しを行ってください。理想的には GNU/Linux、macOS、BSD 系、およびその他のシステムで動作する必要があります。

  3. オプションや引数の説明は短くまとめてください。説明が短いほど、fish がより多くの列(カラム)を表示できる可能性が高まります。

  4. 関数名は __fish で始める必要があります。また、他で使用されない限り、関数は補完ファイル内に記述してください。

  5. スクリプトに対して fish_indent を実行してください。

  6. fish に導入されたばかりの些細な便利機能は使わないようにしてください。補完スクリプトのバックポート(旧バージョンへの適用)のしやすさを維持するためです。正確性やパフォーマンスに大きな影響がある場合は自由に使っていただいて構いませんが、単なるショートカットであれば控えてください。

補完スクリプトは share/completions/コマンド名.fish に配置してください。複数のコマンドがある場合は、複数のファイルが必要になります。

テストを追加したい場合は、littlecheck テストの追加を検討してください。詳細は後述します。

ドキュメントへの貢献

ドキュメントは doc_src/ に保存されており、ReStructured Text形式で記述され、Sphinxによってビルドされます。 fishに同梱されている組み込みコマンドや各種関数は、 doc_src/cmds/ 内でドキュメント化されています。

ドキュメントのHTML版をローカルでビルドするには、以下を実行してください。:

cargo xtask html-docs

実行すると target/fish-docs/html に出力されます。または、CMakeを使用している場合は以下を実行してください。:

cmake --build build -t sphinx-docs

実行すると build/cargo/fish-docs/html/ に出力されます。また、 sphinx-build を直接実行することも可能で、その場合は出力先ディレクトリを選択できます。:

sphinx-build -j auto -b html doc_src/ /tmp/fish-doc/

実行すると /tmp/fish-doc にHTMLドキュメントが出力されます。

ビルド後、ブラウザでHTMLドキュメントを開き、表示に問題がないか確認してください。

コードスタイル

フォーマットには以下を使用します:

  • Rustには rustfmt

  • fishスクリプトには fish_indent (fishに同梱)

  • Python には ruff format

ファイルを再フォーマットするためのxtaskがあります。

cargo xtask format --all
cargo xtask format somefile.rs some.fish

Ffishスクリプトスタイルガイド

  1. share/functionstests ディレクトリにあるものを含め、すべてのfishスクリプトは fish_indent コマンドを使用してフォーマットする必要があります。

  2. 関数名はすべて小文字とし、単語間はアンダースコアで区切る必要があります。 プライベート関数はアンダースコアで始める必要があります。 その関数がfish固有のものである場合、最初の単語は fish としてください。

  3. グローバル変数名は、ユーザー定義変数との名前の衝突の可能性を最小限に抑えるため、パブリック変数の場合は通常 fish で始め、プライベート変数の場合は _fish で始める必要があります。

エディタの fish スクリプト用設定

Vim を使用している場合: vim-fish をインストールし、~/.vimrc でシンタックスハイライトとファイルタイプ機能が有効になっていることを確認してください。

syntax enable
filetype plugin indent on

次に、 ~/.vim/ftplugin/fish.vim で fish スクリプトをより綺麗に表示するためのオプションを有効にします。

" Set up :make to use fish for syntax checking.
compiler fish

" Set this to have long lines wrap inside comments.
setlocal textwidth=79

" Enable folding of block structures in fish.
setlocal foldmethod=expr

Emacs を使用している場合: fish-mode (MELPA および MELPA Stable からも入手可能)をインストールし、フックまたは use-package の “:init” ブロック経由で (setq-default indent-tabs-mode nil) を設定してください。また、例えば以下のように設定することで fish_indent を実行させることもできます。

(add-hook 'fish-mode-hook (lambda ()
    (add-hook 'before-save-hook 'fish_indent-before-save)))

最小サポート Rust バージョン (MSRV) ポリシー

私たちは、少なくとも Debian Stable で利用可能な rustc のバージョンをサポートします。

テスト

fish のソースコードには、膨大なテストコレクションが含まれています。fish に変更を加える際、これらのテストを実行することは、挙動の一貫性を保ち、デグレード(先祖返り)が発生していないか確認する良い方法です。たとえ自分のマシンでテストを実行しなくても、GitHub Actions を通じて自動的に実行されます。

fish の機能を変更する場合、特にバグを修正する場合は、将来的に同じバグを再発させないために、テストを追加することを強く推奨します。

ユニットテスト(単体テスト)は、Rust ソースファイル内の実装のすぐ隣に、インラインサブモジュール( mod tests {} )として記述されます。

システムテストは tests/ に配置されています。

  • tests/checkslittlecheck によって実行され、非対話的(スクリプト)な挙動をテストします(対話的なシナリオをテストする tests/checks/tmux-* を除きます)。

  • tests/pexpects は、 pexpect を使用して対話的なシナリオをテストします。

迷った場合は、テストの大部分を tests/checks 内の littlecheck テストとして追加してください。littlecheck は修正や実行が最も簡単で、pexpect テストよりも高速で信頼性が高いためです。構文は非常に分かりやすく、fish スクリプトの中に、期待される出力を # CHECK:# CHECKERR: (標準エラー出力用)コメントとして記述するだけです。特定の依存関係が必要な場合は、POSIX sh スクリプト形式で # REQUIRE: ... を使用してください。

pexpect テストは Python で記述されており、ターミナルへの入出力をシミュレートできるため、実際の対話性を必要とするテストに使用されます。何かを修正する必要がある場合に備えて、ランナーは tests/pexpect_helper.py に用意されています。

これらのテストは、環境のセットアップを行う Python スクリプト tests/test_driver.py 経由で実行できます。このスクリプトは一時的な $HOME を作成し、それをカレントディレクトリとして使用するため、テスト内で一時ディレクトリを自作する必要はありません。

テストのために特殊な動作をするコマンドが必要な場合は、 fish_test_helper バイナリ( tests/fish_test_helper.c 内)に追加することを検討してください。

ローカルでのテスト

テストはローカルシステムで実行できます。

cargo build
# Run unit tests
cargo test
# Run system tests
tests/test_driver.py target/debug
# Run a specific system test.
tests/test_driver.py target/debug tests/checks/abbr.fish

ここで、 test_driver.py の第1引数は、 fishfish_indentfish_key_reader が含まれるディレクトリを指します。この例では、ワークスペースのルートで --release なしで cargo build を実行した後のデバッグビルドを想定しています。

すべてのテストとリンターを実行するには、以下を使用します。

cargo xtask check

翻訳への貢献

fish は GNU gettext を使用して、メッセージを英語から他言語へ翻訳しています。 私たちはソースファイルからメッセージを抽出し、実行時にローカライズを行うためのカスタムツールを使用しています。 これは、実行時に gettext ライブラリへの依存関係がないことを意味します。 また、メッセージのコンテキストや複数形などの一部の機能がサポートされていないことも意味します。 さらに、すべてのファイルが UTF-8 でエンコードされていることを想定しています。 実務上、これらは翻訳に貢献する上でそれほど大きな問題にはならないはずです。

翻訳ソースは localization/po ディレクトリに ll_CC.po という名前で保存されています。 ここで ll はターゲット言語の 2 文字(または 3 文字)の ISO 639-1 言語コード(例: ポルトガル語の場合は pt)です。 CC は ISO 3166 の国/地域コード(例: ブラジルの場合は BR)です。 有効な名前の例は pt_BR.po で、これはブラジルポルトガル語であることを示しています。 翻訳を追加する際に操作するのは、これらのファイルになります。

新しい言語の翻訳を追加する

新しい翻訳を作成するには Gettext ツールが必要です。 具体的には、新しい言語の翻訳を作成するために msguniqmsgmerge が必要になります。 新しい翻訳を作成するには、以下を実行してください。:

build_tools/update_translations.fish localization/po/ll_CC.po

これにより、翻訳可能なすべてのメッセージを含む新しい PO ファイルが作成されます。 ファイルが既に存在する場合は、更新されます。

PO ファイルを修正した後、fish を再コンパイルすると、加えた修正が統合されます。 これには msgfmt ユーティリティ(gettext の一部として提供)がインストールされている必要があります。 また、cargo の機能である localize-messages が有効になっていることが重要です(デフォルトで有効になっています)。 以下を使用して明示的に有効にすることもできます。:

cargo build --features=localize-messages

fish が使用する言語を指定するには、環境変数を使用します。例:

LANG=pt_BR.utf8 fish

または、実行中の fish シェル内で以下のように設定します。:

set LANG pt_BR.utf8

言語の選択に関する詳細なオプションについては、対応する gettext のドキュメント を参照してください。 便利な機能として、 LANGUAGE 変数を使用して、翻訳を探す言語の優先順位リストを設定できます。例:

set LANGUAGE pt_BR de_DE

これにより、まずメッセージをポルトガル語に翻訳しようとし、失敗した場合はドイツ語を試し、それも失敗した場合はソースコードで定義されている英語バージョンが表示されます。

既存の翻訳を修正する

すでに対応する po ファイルが存在する言語の翻訳作業を行う場合は、そのファイルを編集するだけで十分です。その他の変更は必要ありません。

fish を再コンパイルすると、翻訳が実際に反映されているのを確認できるはずです。詳細は前のセクションを参照してください。

PO ファイルを編集する

翻訳ファイルを編集するためのツールは、コマンドラインプログラムやグラフィカルユーザーインターフェース(GUI)プログラムを含め、多く存在します。簡単な用途であれば、テキストエディタを使用することもできます。

POファイル(例: localization/po/sv.po)を開くと、以下のような内容が表示されます:

msgid "%s: No suitable job\n"
msgstr ""

ここでの msgid は翻訳対象となる文字列の「名前」であり、通常は翻訳元の英語の文字列です。2行目(msgstr)が翻訳を記入する場所です。

例:

msgid "%s: No suitable job\n"
msgstr "%s: Inget passande jobb\n"

%s%d は、実行時に fish がフォーマットに使用するプレースホルダです。これらを一致させることが重要です。翻訳後の文字列には、同じプレースホルダを同じ順序で含める必要があります。

また、末尾の \n (改行)のようなエスケープ文字も、翻訳が同じ挙動をするように維持する必要があります。

私たちのテストでは msgfmt --check-format /path/to/file を実行しているため、プレースホルダの不一致はそこで検出されます。不一致があると、その文字列が使用される直前に fish が実行時にクラッシュしてしまいます。

既存の翻訳ファイルをむやみに更新しないよう注意してください。 msgid の文字列は手動で更新すべきではなく、必ず適切なスクリプトを実行して更新してください。

ソースファイル内の文字列の変更

ソースファイル内の文字列が変更されると、古い翻訳は機能しなくなります。それらは PO ファイル内に保持されますが、コメントアウト( #~ で始まる行)されます。 ソースファイル内で翻訳可能な文字列を追加、削除、または変更した場合は、 build_tools/update_translations.fish を実行して、すべての翻訳ファイル(localization/po/*.po)にその変更を伝播させてください。 これは、fish のソースファイルや fish スクリプトを修正する開発者にのみ関係する作業です。

翻訳用のコード設定

ユーザーが目にする非デバッグ用メッセージは、すべて翻訳対象としてマークする必要があります。Rust では、 wgettext!wgettext_fmt! マクロを使用する必要があります。

streams.out.append(wgettext_fmt!("%s: There are no jobs\n", argv[0]));

fish スクリプト内のすべてのメッセージは、メッセージ抽出スクリプトがそれらを見つけられるように、シングルクォートまたはダブルクォートで囲む必要があります。 また、それらはコマンド置換を介して翻訳されなければなりません。つまり、以下は 無効 です。

echo (_ hello)
_ "goodbye"

上記は、代わりに次のように記述する必要があります。

echo (_ "hello")
echo (_ "goodbye")

翻訳対象のメッセージを囲むには、シングルクォートまたはダブルクォートのいずれかを使用できます。また、開始括弧の直後や終了括弧の直前に、任意でスペースを含めることもできます。

依存関係の更新

依存関係を更新するには、 build_tools/update-dependencies.sh を実行してください。現在のところ、これには updatecli とその他のいくつかのツールが必要です。

バージョニング

fish のバージョンは、 build_tools/git_version_gen.sh スクリプトによって構成されます。 開発者向けのバージョンは、ブランチ名に git describe --always --dirty の出力を加えたものになります。 通常、バージョンの主要な部分は、最も近い注釈付き(annotated)タグになります。 これは通常、最新のリリース番号(例: 2.6.0)です。