処理の完了まで暫く時間を要するかもしれない際には、進行状況についてユーザーに通知するべきです。これによりユーザーが残り時間を予測するとともに、Emacsがhungしているのではなく処理中であることを明確に確認できます。プログレスレポーター(progress reporter: 進行状況リポーター)を使用するのが、これを行う便利な方法です。
以下は何も有用なことを行わない実行可能な例です:
(let ((progress-reporter (make-progress-reporter "Collecting mana for Emacs..." 0 500))) (dotimes (k 500) (sit-for 0.01) (progress-reporter-update progress-reporter k)) (progress-reporter-done progress-reporter))
この関数は以下に挙げる他の関数の引数として使用されることになるプログレスレポーターオブジェクトを作成してリターンする。これはプログレスリポーターを高速にするように、可能なかぎり多くのデータを事前に計算するというアイデアが元となっている。
この後にプログレスレポーターを使用する際には、進行状況のパーセンテージを後に付加してmessageが表示されるだろう。messageは単なる文字列として扱われる。たとえばファイル名に依存させる必要があるなら、この関数の呼び出し前にformat-message
を使えばよい。
引数min-valueとmax-valueは処理の開始と終了を意味する数値であること。たとえばバッファーをスキャンする処理なら、これらをそれぞれpoint-min
とpoint-max
にセットするべきだろう。max-valueはmin-valueより大であること。
かわりにmin-valueとmax-valueをnil
にセットすることができる。この場合にはプログレスレポーターは進行状況のパーセンテージを報告しない。かわりにプログレスリポーターを更新するたびに刻み(notch)を回転する“スピナー(spinner)”を表示する。
min-valueとmax-valueが数値なら、進行状況の初期の数値を与える引数current-valueを与えることができる。省略時のデフォルトはmin-value。
残りの引数はエコーエリアの更新レートを制御する。プログレスレポーターは次のメッセージを表示する前に、その処理が少なくともmin-changeパーセントより多く完了するまで待機する。デフォルトは1パーセント。min-timeは連続するプリントの間に空ける最小時間をミリ秒単位で指定する(いくつかのオペレーティングシステムではプログレスリポーターは秒の小数部をさまざまな精度で処理するかもしれない)。
この関数はprogress-reporter-update
を呼び出すので、最初のメッセージは即座にプリントされる。
この関数は操作の進行状況報告に関する主要な機能を担う。これはreporterのメッセージと、その後にvalueにより決定された進行状況のパーセンテージを表示する。パーセンテージが0、または引数min-changeとmin-timeに比べて十分0に近ければ出力は省略される。
reporterはmake-progress-reporter
呼び出しがリターンした結果でなければならない。valueは処理のカレント状況を指定して、make-progress-reporter
に渡されたmin-valueとmax-valueの間(両端を含む)でなければならない。たとえばバッファーのスキャンにおいては、valueはpoint
び呼び出し結果であるべきだろう。
オプション引数suffixは、reporterのメインメッセージと進行状況テキストの後に表示する文字列。reporterが非数値のレポーターならvalueはnil
、またはsuffixのかわりに使用する文字列であること。
この関数はmake-progress-reporter
に渡されたmin-changeとmin-timeにしたがい、毎回の呼び出しで新たなメッセージを出力しない。したがってこれは非常に高速であり、通常はこれを呼び出す回数を減らすことを試みるべきではない。結果として生じるオーバーヘッドは、あなたの努力をほぼ否定するだろう。
この関数はprogress-reporter-update
と同様だが、これは無条件にメッセージをエコーエリアにプリントする点が異なる。
reporter、value、suffixはprogress-reporter-update
の場合と同じ意味をもつ。オプションのnew-messageでreporterのメッセージを変更できる。この関数は常にエコーエリアを更新するので、そのような変更は即座にユーザーに示されるだろう。
この関数は処理の完了時に呼び出されること。これはエコーエリア内に単語‘done’を付加したreporterのメッセージを表示する。
progress-reporter-update
に‘100%’とプリントさせようとせずに、常にこの関数を呼び出すこと。まずこの関数は決してそれをプリントしないだろうし、これが発生しないために多くの正当な理由がある。次に‘done’はより自明である。
これはdotimes
と同じ方法で機能するが、上述の関数を使用してループ進行状況(loop
progress)の報告も行う便利なマクロである。これによりタイプ量を幾分節約できる。引数reporter-or-messageは文字列、またはプログレスレポーターオブジェクト。
以下の方法でこのマクロを使用することにより、このサブセクションの例を書き換えることができる:
(dotimes-with-progress-reporter (k 500) "Collecting some mana for Emacs..." (sit-for 0.01))
make-progress-reporterのオプション引数を指定したい場合には、reporter-or-message引数としてレポーターオブジェクトを使用するのが便利。たとえば前出の例は以下のように書き換えられる:
(dotimes-with-progress-reporter (k 500) (make-progress-reporter "Collecting some mana for Emacs..." 0 500 0 1 1.5) (sit-for 0.01))
これはdolist
と同じ方法で機能するが、上述の関数を使用してループ進行状況(loop
progress)の報告も行う便利なマクロである。これによりタイプ量を幾分節約できる。dotimes-with-progress-reporter
の場合のように、reporter-or-message
はプログレスレポーターか文字列。このマクロにより、前出の例を以下のように書き換えられる:
(dolist-with-progress-reporter (k (number-sequence 0 500)) "Collecting some mana for Emacs..." (sit-for 0.01))
ある処理にたいして、実行に長時間を要するか否かが不明瞭だったり、処理がプログレスレポーターの実装に向いていない場合があるかもしれない。このマクロはそのような状況下で使用できるだろう。
(with-delayed-message (2 (format "Gathering data for %s" entry)) (setq data (gather-data entry)))
この例では、処理の実行が2秒を超える場合にはメッセージが表示される。2秒以下の場合にはメッセージは表示されない。いずれの場合でもbodyは通常どおり評価される。このマクロのリターン値は、bodyの最後の要素のリターン値。
メッセージわwo表示するか否かに関わらず、要素messageはbodyより前に、常に評価される。