let* 式 ¶forward-paragraph 関数の次の行では let* 式(let* の導入を参照)が始まり、そこで Emacs は opoint、fill-prefix-regexp、parstart、parsep、sp-parstart、start、found-start の計 7 つの変数をバインドします。let* 式の前半部分は以下のようになります:
(let* ((opoint (point))
(fill-prefix-regexp
(and fill-prefix (not (equal fill-prefix ""))
(not paragraph-ignore-fill-prefix)
(regexp-quote fill-prefix)))
;; Remove ^ from paragraph-start and paragraph-sep if they are there.
;; These regexps shouldn't be anchored, because we look for them
;; starting at the left-margin. This allows paragraph commands to
;; work normally with indented text.
;; This hack will not find problem cases like "whatever\\|^something".
(parstart (if (and (not (equal "" paragraph-start))
(equal ?^ (aref paragraph-start 0)))
(substring paragraph-start 1)
paragraph-start))
(parsep (if (and (not (equal "" paragraph-separate))
(equal ?^ (aref paragraph-separate 0)))
(substring paragraph-separate 1)
paragraph-separate))
(parsep
(if fill-prefix-regexp
(concat parsep "\\|"
fill-prefix-regexp "[ \t]*$")
parsep))
;; This is used for searching.
(sp-parstart (concat "^[ \t]*\\(?:" parstart "\\|" parsep "\\)"))
start found-start)
...)
変数 parsep は2回登場し、1回目は ‘^’ の出現箇所を削除するため、2回目はフィルプレフィックスを処理するためです。
変数 opoint は単に point
の値です。ご想像の通り、forward-sentence と同様に constrain-to-field の式でも使用されています。
変数 fill-prefix-regexp には、以下のリストを評価して得られた値が代入されます。
(and fill-prefix
(not (equal fill-prefix ""))
(not paragraph-ignore-fill-prefix)
(regexp-quote fill-prefix))
これは、第1要素がand特殊形式である式です。
先に学んだように(kill-new 関数を参照)、and
特殊形式は、引数のいずれかが nil の値を返すまで各引数を評価し、その場合は and 式が nil を返します。ただし、どの引数も
nil の値を返さない場合は、最後の引数を評価した結果が返されます。(このような値は nil ではないため、Lisp では真とみなされます。)言い換えれば、and 式は、すべての引数が真である場合にのみ真の値を返します。
この場合、変数 fill-prefix-regexp が nil 以外の値に束縛されるのは、以下の4つの式を評価した際に真(すなわち nil 以外)の値が得られた場合に限られ、それ以外の場合は fill-prefix-regexp が nil
に束縛されます。
fill-prefixこの変数が評価されると、フィルプレフィックスが存在する場合はその値が返されます。フィルプレフィックスがない場合は、この変数は nil を返します。
(not (equal fill-prefix "")この式は、既存のフィルプレフィックスが空文字列、すなわち文字を含まない文字列であるかどうかを判定します。空文字列は有用なフィルプレフィックスではありません。
(not paragraph-ignore-fill-prefix)この式は、変数 paragraph-ignore-fill-prefix が t のような真の値に設定されて有効になった場合、nil
を返します。
(regexp-quote fill-prefix)これは and 特殊形式への最後の引数です。and のすべての引数が真である場合、この式を評価して得られた値が and 式によって返され、変数 fill-prefix-regexp に束縛されます。
この and 式の評価が正常に完了した結果、fill-prefix-regexp には regexp-quote 関数によって変更された fill-prefix の値がバインドされます。regexp-quote
は文字列を読み込み、その文字列に完全に一致し、それ以外には一切一致しない正規表現を返します。つまり、fill プレフィックスが存在する場合、fill-prefix-regexp にはその fill
プレフィックスに完全に一致する値が設定されます。そうでない場合、変数には nil が設定されます。
let* 式の続く2つのローカル変数は、段落の開始と段落区切りを示すローカル変数である parstart および parsep
から、‘^’ の出現箇所を除去するように設計されています。次の式では、再び
parsep を設定します。これはフィルプレフィックスを処理するためのものです。
これは、letではなく定義呼び出しlet*を必要とする設定です。ifの真偽判定は、変数fill-prefix-regexpがnilと評価されるか、あるいは別の値と評価されるかによって決まります。
fill-prefix-regexp に値がない場合、Emacs は if 式の else 部分を評価し、parsep
をそのローカル値にバインドします。(parsep は、段落を区切る部分にマッチする正規表現です。)
ただし、fill-prefix-regexp に値がある場合、Emacs は if 式の then 部を評価し、parsep を
fill-prefix-regexp をパターンの一部として含む正規表現にバインドします。
具体的には、parsep には、段落の元の値を区切る正規表現に、fill-prefix-regexp
に続いて行末までの任意の空白文字が続く代替表現を連結したものが設定されます。(この空白文字は "[ \t]*$" で定義されます。)‘\\|’ は、この正規表現の部分を parsep
の代替として定義します。
コード内のコメントによると、次のローカル変数 sp-parstart
が検索に使用され、その後、最後の2つ start と found-start が nil に設定されます。
ここからはlet*の本体に入ります。let*の本体の前半部分では、関数に負の引数が与えられ、その結果逆方向に移動する場合について扱っています。この節は省略します。