[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13. カスタマイズ定義の書き方

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Customization"
"elisp/カスタマイズ定義の書き方"へのコメント(無し)

本章では、カスタマイズのためのユーザーオプションの宣言方法、 および、それらを分類するカスタマイズグループの宣言方法を説明します。 フェイスの定義(see 節 38.10.2 フェイスを定義する)に加えて、 カスタマイズの両方の種類を含めて、 カスタマイズ項目(customization item)という用語を使います。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.1 すべての種類の項目に共通のキーワード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Common%20Keywords"
"elisp/すべての種類の項目に共通のキーワード"へのコメント(無し)

(変数やグループ、フェイスの)すべての種類のカスタマイズ宣言では、 さまざまな情報を指定するためのキーワード引数を受け付けます。 本節では、全種類に適用できるキーワードを説明します。

:tagを除くこれらのキーワードすべては、各項目で複数回使えます。 キーワードのそれぞれの使用には、独立の効果があります。 キーワード:tagは例外です。 任意の項目には名前を1つしか表示できないからです。

:tag name
カスタマイズメニューやカスタマイズバッファ内で 項目に付けるラベルとして、項目の名前のかわりに文字列nameを使う。

:group group
このカスタマイズ項目をグループgroupに入れる。 defgroupの中で:groupを使うと、 新たなグループをgroupの下位グループにする。

このキーワードを複数回使うと、 1つの項目を複数のグループに入れることができる。 それらのグループのどれを表示しても、この項目が表示される。 これを多用しすぎないように注意すること!

:link link-data
この項目に対する説明文字列のうしろに外部リンクを含める。 これは、他の説明文字列を参照するアクティブフィールドを含む文である。

link-dataとして使えるものは3種類ある。

(custom-manual info-node)
infoのノードへリンクする。 info-nodeは、"(emacs)Top"のようなノード名を指定する文字列。 リンクは、カスタマイズバッファでは`[manual]'のように表示される。

(info-link info-node)
custom-manualと同様であるが、 カスタマイズバッファに現れるリンクはinfoのノード名になる。

(url-link url)
webページへリンクする。 urlは、URLを指定する文字列。 カスタマイズバッファに現れるリンクはurlになる。

link-dataの先頭要素のうしろに:tag nameを使うことで、 カスタマイズバッファに使うテキストを指定できる。 たとえば、(info-link :tag "foo" "(emacs)Top")とすると、 バッファでは`foo'と表示されるEmacsマニュアルへのリンクを作れる。

1つの項目に複数個の外部リンクがあってもよいが、 ほとんどの項目には外部リンクはない。

:load file
このカスタマイズ項目を表示するまえにファイルfile(文字列)をロードする。 ファイルをすでにロードしていない場合に限り、 load-libraryでロードする。

:require feature
カスタマイズ機能を用いて保存するこの項目に対する値をインストールするときに 必要となる機能feature(シンボル)を指定する。 requireを呼び出す。

:requireを使うもっとも一般的な理由は、 変数がマイナモードなどの機能をオンにするとき、 そのモードを実装するコードをロードしてないと、 変数にはなんの効果もないからである。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.2 カスタマイズグループを定義する

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Group%20Definitions"
"elisp/カスタマイズグループを定義する"へのコメント(無し)

Emacs Lispの各パッケージには、 そのパッケージのすべてのオプション、フェイス、他のグループを含んだ 1つの主要なカスタマイズグループがあるべきです。 パッケージに少数のオプションやフェイスしかなければ、 それらを1つのグループにまとめます。 12個を超えるオプションやフェイスがある場合には、 それらを下位グループに構造化して、 下位グループすべてをパッケージの主カスタマイズグループに入れておきます。 パッケージの主グループに下位グループとともにいくつかのオプションやフェイスを 入れておくのもよいでしょう。

パッケージの主グループや単一のグループは、 標準カスタマイズグループの1つかそれ以上のメンバであるべきです。 (それらの完全な一覧を表示するにはM-x customizeを使う。) それらの中から1個か数個を選び(多すぎないこと)、 キーワード:groupを使って、それぞれに読者のグループを追加します。

新たなカスタマイズグループは、defgroupで宣言します。

Macro: defgroup group members doc [keyword value]...
membersを含むカスタマイズグループとしてgroupを宣言する。 シンボルgroupをクォートしないこと。 引数docは、グループの説明文字列を指定する。

引数membersは、グループのメンバとなる カスタマイズ項目の初期集合を指定するリストである。 しかし、ほとんどの場合、membersnilであり、 それらのメンバを定義するときに、キーワード:groupを使って、 グループのメンバであることを指定する。

membersでグループのメンバを指定する場合には、 各要素は(name widget)という形式であること。 ここで、nameはシンボル、 widgetはそのシンボルを編集するためのウィジェット型である。 有用なウィジェットは、変数に対してはcustom-variable、 フェイスに対してはcustom-face、 グループに対してはcustom-groupである。

共通のキーワード(see 節 13.1 すべての種類の項目に共通のキーワード)に加えて、 defgroupではつぎのキーワードも使える。

:prefix prefix
グループ内の項目の名前がprefixで始まるときには、 その項目に対するタグを(デフォルトでは)prefixを省略して作る。

1つのグループにprefixがいくつあってもよい。

接頭辞を取りさる機能は、現在、オフにしてあります。 つまり、:prefixは、現在、なんの効果もありません。 このようにしたのは、指定した接頭辞を取りさると、 オプション名がしばしば混乱するからです。 さまざまなグループのdefgroup定義を書く人は、 論理的と考えられるとき、つまり、ライブラリに共通の接頭辞があるときには キーワード:prefixを追加するので、このようになるのです。

:prefixを使ってよい結果を得るには、 グループ内の特定の項目とそれらの名前と説明文字列に関して、 特定の接頭辞を取りさった場合の効果を調べる必要があります。 その結果、テキストがわかり難ければ、 その場面では、:prefixを使うべきではないのでしょう。

カスタマイズグループすべてを調べ直して、 わかり難くなる結果をもたらす:prefix指定を削除し、 この機能をオンにすることは、誰かが頑張れば、可能です。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.3 カスタマイズ変数を定義する

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Variable%20Definitions"
"elisp/カスタマイズ変数を定義する"へのコメント(無し)

defcustomを使って、ユーザーが編集可能な変数を宣言します。

Macro: defcustom option default doc [keyword value]...
カスタマイズ可能なユーザーオプション変数としてoptionを宣言する。 optionをクォートしないこと。 引数docは変数の説明文字列を指定する。

optionが空であると、defcustomdefaultで初期化する。 defaultは値を計算する式であること。 これは複数回評価される可能性があるので、書き方には注意すること。

defcustomでは、つぎの追加キーワードも使えます。

:type type
このオプションのデータ型としてtypeを使う。 これは、正しい値とその表示方法を指定する。 詳しくは、see 節 13.4 カスタマイズ型

:options list
このオプションに使える合理的な値のリストとしてlistを指定する。

これは、現時点では、型がhookのときだけ意味を持つ。 その場合、listの要素は、フックの値の要素として使える関数であること。 ユーザーはこれらの関数以外も使えるが、便利な選択肢として提示する。

:version version
このオプションは、変数を最初に導入したり、デフォルト値を変更したりした Emacsの版versionを指定する。 値versionは、文字列であること。 たとえば、つぎのとおり。

 
(defcustom foo-max 34
  "*Maximum number of foo's allowed."
  :type 'integer
  :group 'foo
  :version "20.3")

:set setfunction
このオプションの値を変更する方法としてsetfunctionを指定する。 関数setfunctionは、2つの引数、つまり、シンボルと新しい値を取り、 このオプションの値を(Lisp変数としてオプションを設定するだけでなく) 適切に更新するために必要なことを行うこと。 setfunctionのデフォルトはset-default

:get getfunction
このオプションの値を取り出す方法としてgetfunctionを指定する。 関数getfunctionは、1つの引数、つまり、シンボルを取り、 そのシンボル(のLisp値とは必ずしも限らない)の『現在値』を返すこと。 デフォルトはdefault-value

:initialize function
functionは、defcustomを評価したときに変数の初期化に使う関数。 この関数は、2つの引数、つまり、シンボルと値を取ること。 このように使うことを意図した定義済みの関数がいくつかある。

custom-initialize-set
変数の:set関数を使って変数を初期化するが、 変数の値が空でないときには再初期化しない。 これは:initializeのデフォルト。

custom-initialize-default
custom-initialize-setに似ているが、 変数の:set関数のかわりに関数set-defaultを使って変数を設定する。 変数の:set関数がマイナモードをオン/オフする場合には、 普通はこれを選ぶ。 これを選ぶと、変数を定義してもマイナモード関数を呼び出さないが、 変数をカスタマイズするとマイナモード関数を呼び出す。

custom-initialize-reset
変数を初期化するにはつねに:set関数を使う。 変数の値が空でない場合には、(:getで得られる)現在値で :set関数を呼び出して、変数をリセットする。

custom-initialize-changed
変数がすでに設定されていたりカスタマイズしてあるときに、 変数を初期化するために:set関数を使う。 さもなければ、set-defaultを使う。

:requireオプションは、 特定の機能をオンにするようなオプションには便利です。 パッケージがオプション変数の値を検査するように書かれていたとしても、 パッケージをロードするようにする必要があります。 これを:requireで行えるのです。 See 節 13.1 すべての種類の項目に共通のキーワード。 ライブラリ`paren.el'からとった例をつぎに示します。

 
(defcustom show-paren-mode nil
  "Toggle Show Paren mode...."
  :set (lambda (symbol value)
         (show-paren-mode (or value 0)))
  :initialize 'custom-initialize-default
  :type 'boolean
  :group 'paren-showing
  :require 'paren)

内部的には、defcustomは、 デフォルト値を与える式は属性standard-valueを使って記録し、 ユーザーがカスタマイズバッファで保存した値は 属性saved-valueを使って記録しています。 属性saved-valueは実際にはリストであり、 そのCARが値に評価される式です。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.4 カスタマイズ型

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Customization%20Types"
"elisp/カスタマイズ型"へのコメント(無し)

defcustomでユーザーオプションを定義するときには、 そのカスタマイズ型(customization type)を定義する必要があります。 これはLispオブジェクトであり、 (1)どのような値が正しいものであり、 (2)編集用にカスタマイズバッファに表示する方法、 を示します。

カスタマイズ型は、defcustom内の:typeキーワードで指定します。 :typeの引数は評価されます。 実行時に型が変わるものはほとんど使い途がないので、 普通、クォートした型を指定します。 たとえば、つぎのとおりです。

 
(defcustom diff-command "diff"
  "*The command to use to run diff."
  :type '(string)
  :group 'diff)

一般に、カスタマイズ型はリストであり、 その先頭要素はシンボルで、次節以降で定義するカスタマイズ型名の1つです。 このシンボルのあとには、シンボルに依存した数個の引数が続きます。 型シンボルとその引数のあいだには、 キーワード・値の対を書くこともできます (see 節 13.4.4 型キーワード)。

型シンボルには、引数を取らないものもあります。 これらを単純型(simple types)と呼びます。 単純型では、キーワード・値の対を指定しなければ、 型シンボルを囲む括弧を省略できます。 たとえば、カスタマイズ型としてのstringは、 (string)と等価です。

13.4.1 単純型   
13.4.2 複合型   
13.4.3 リストに繋ぎ合わせる   
13.4.4 型キーワード   



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.4.1 単純型

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Simple%20Types"
"elisp/単純型"へのコメント(無し)

本節では、すべての単純型を説明します。

sexp
値は、表示したり読み取れるならば、任意のLispオブジェクトでよい。 使用する型をより限定する手間を省きたければ、 任意のオプションに対するデフォルトとして、 sexpを使うことができる。

integer
値は整数である必要があり、カスタマイズバッファではテキストで表示する。

number
値は数である必要があり、カスタマイズバッファではテキストで表示する。

string
値は文字列である必要があり、 カスタマイズバッファでは、その内容だけを表示し、 文字`"'で区切ったり、`\'でクォートしない。

regexp
stringと同様であるが、 文字列は正規表現である必要がある。

character
値は文字コードである必要がある。 文字コードは実際には整数であるが、 この型では、数として表示するのではなく、 文字としてバッファに挿入してその値を表示する。

file
値はファイル名である必要があり、M-TABで補完できる。

(file :must-match t)
値は既存のファイル名である必要があり、M-TABで補完できる。

directory
値はディレクトリ名である必要があり、M-TABで補完できる。

hook
値は関数のリスト(あるいは、単一の関数。ただし、この使い方は廃れている) である必要がある。 このカスタマイズ型は、フック変数に使用する。 フックに使う推奨される関数のリストを指定するために、 フック変数のdefcustom:optionsキーワードを使用できる。 see 節 13.3 カスタマイズ変数を定義する

symbol
値はシンボルである必要がある。 カスタマイズバッファでは、シンボルの名前を表示する。

function
値はラムダ式か関数名である必要がある。 関数名の場合、M-TABで補完できる。

variable
値は変数名である必要があり、M-TABで補完できる。

face
値はフェイス名を表すシンボルである必要があり、M-TABで補完できる。

boolean
値は真理値、つまり、niltである必要がある。 choiceconstを同時に使うと(次節参照)、 値はniltである必要があることを指定し、 さらに、どちらの値がどの選択肢に合うかを記述するテキストを 指定できることに注意。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.4.2 複合型

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Composite%20Types"
"elisp/複合型"へのコメント(無し)

単純型が適切でない場合には、 他の型から新たな型を作り上げる複合型を使えます。 これには、いくつかの方法があります。

(restricted-sexp :match-alternatives criteria)
値は、criteriaの1つを満たす任意のLispオブジェクトでよい。 criteriaはリストであり、その各要素は以下の1つであること。

たとえば、

 
(restricted-sexp :match-alternatives
                 (integerp 't 'nil))

は、整数、tnilが正しい値である。

カスタマイズバッファでは、すべての正しい値はその入力構文で表示し、 ユーザーはそれらをテキストとして編集する。

(cons car-type cdr-type)
値はコンスセルである必要があり、 そのCARはcar-typeに合い、かつ、 そのCDRはcdr-typeに合う必要がある。 たとえば、(cons string symbol)は、 ("foo" . foo)などの値に一致するカスタマイズ型である。

カスタマイズバッファでは、 CARとCDRは、 それらに指定した型に応じて別々に表示され、個別に編集できる。

(list element-types...)
値はelement-typesに指定したとおりの個数のリストである必要があり、 各要素はelement-typeに合うこと。

たとえば、(list integer string function)は、 3要素のリストを意味し、 第1要素は整数、第2要素は文字列、第3要素は関数であることを指定する。

カスタマイズバッファでは、 各要素は、それらに指定した型に応じて別々に表示され、個別に編集できる。

(vector element-types...)
listと同様だが、値はリストではなくベクトルである必要がある。 その要素はlistの場合と同じ。

(choice alternative-types...)
値は、alternative-typesの少なくとも1つに合う必要がある。 たとえば、(choice integer string)は、整数か文字列を許す。

カスタマイズバッファでは、ユーザーはメニューを使って選択肢を選び、 その選択肢において普通の方法で値を編集する。

通常、このメニューの選択肢名は、選択肢から自動的に決定されるが、 選択肢に:tagキーワードを含めることで、 メニューに異なる名前を指定できる。 たとえば、整数が空白の個数を表し、文字列がそのまま使うテキストを表す場合には、 つぎのようにカスタマイズ型を書く。

 
(choice (integer :tag "Number of spaces")
        (string :tag "Literal text"))

そうすると、メニューには、 `Number of spaces'と`Literal Text'が表示される。

const以外のnilが正当な値ではない選択肢では、 そのような選択肢には:valueキーワードを使って 正当なデフォルト値を指定すること。 See 節 13.4.4 型キーワード

(const value)
値はvalueであること。 それ以外は許さない。

constの主な用途はchoiceの内側である。 たとえば、(choice integer (const nil))は、整数かnilを許す。

choiceの内側では、constにしばしば:tagを使う。 たとえば、

 
(choice (const :tag "Yes" t)
        (const :tag "No" nil)
        (const :tag "Ask" foo))

は、tは『yes』(はい)、nilは『no』(いいえ)、 fooは『ask』(問い合わせる)を意味する変数を記述する。

(other value)
この選択肢は任意のLisp値に一致するが、 ユーザーがこの選択肢を選ぶと、値valueを選ぶことになる。

otherは、主に、choiceの最後の要素として使うことである。 たとえば、

 
(choice (const :tag "Yes" t)
        (const :tag "No" nil)
        (other :tag "Ask" foo))

は、tは『yes』(はい)、nilは『no』(いいえ)、 それ以外は『ask』(問い合わせる)を意味することを示す。 ユーザーが選択肢のメニューから`Ask'を選ぶと、値fooを指定する。 しかし、(tでもnilでもfooでもない)それ以外の値は、 fooと同様に`Ask'と表示される。

(function-item function)
constと同様だが、関数であるような値に使う。 これは、関数名に加えて説明文字列を表示する。 説明文字列は、:docに指定したものか、 functionそのものの説明文字列である。

(variable-item variable)
constと同様だが、変数名であるような値に使う。 これは、変数名に加えて説明文字列を表示する。 説明文字列は、:docに指定したものか、 variableそのものの説明文字列である。

(set elements...)
値はリストである必要があり、 その各要素はelementsに指定したものの1つである必要がある。 これは、カスタマイズバッファにはチェックリストとして表示される。

(repeat element-type)
値はリストである必要があり、 その各要素はelement-typeに指定した型に合う必要がある。 これは、カスタマイズバッファには、 要素を追加したり削除したりする`[INS]'や`[DEL]'ボタンを伴って、 要素のリストとして表示される。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.4.3 リストに繋ぎ合わせる

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Splicing%20into%20Lists"
"elisp/リストに繋ぎ合わせる"へのコメント(無し)

:inline機能により、可変個数の要素をリストやベクトルの 途中に繋ぎ合わせることができます。 listvectorの要素型に現れる set型、choice型、repeat型の中に使います。

通常、listvectorのおのおのの要素型は、 リストやベクトルのたった1つの要素を記述します。 したがって、要素型がrepeatであると、 1要素として表示される長さを指定しないリストを指定します。

しかし、要素型に:inlineを使うと、 これに一致する値は、:inlineを含むシーケンスに直接に併合されます。 たとえば、3要素のリストに一致すると、 それがシーケンス全体の3つの要素になります。 これはバッククォート構文の`,@'の使い方に似ています。

たとえば、先頭要素がtであり、 残りがfoobarの0個以上の繰り返しであるリストを指定するには、 つぎのカスタマイズ型を使います。

 
(list (const t) (set :inline t foo bar))

これは、(t)(t foo)(t bar)(t foo bar)などの 値に一致します。

要素型がchoiceであるときには、 choiceそのものには:inlineを使いませんが、 choiceの選択肢(のどれか)に:inlineを使います。 たとえば、ファイル名で始まりシンボルtか2つの文字列が続くような リストに一致するようにするには、 つぎのカスタマイズ型を使います。

 
(list file
      (choice (const t)
              (list :inline t string string)))

ユーザーが最初の選択肢を選ぶと、全体としてのリストは2要素になり、 第2要素はtです。 ユーザーが2番目の選択肢を選ぶと、 全体としてのリストは3要素になり、 第2要素と第3要素は文字列である必要があります。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

13.4.4 型キーワード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Type%20Keywords"
"elisp/型キーワード"へのコメント(無し)

型名のシンボルのあとに、カスタマイズ型内にキーワード・引数の対を指定できます。 使えるキーワードとその意味を以下に示します。

:value default
choiceの内側の選択肢として現れる型に使う。 これは、カスタマイズバッファのメニューでユーザーがこの選択肢を選ぶと、 使用するデフォルト値をまず指定する。

もちろん、オプションの実際の値がこの選択肢に合えば、 defaultではなく実際の値が表示される。

選択肢の値としてnilが不正であるときには、 :valueで正当なデフォルトを指定することが本質的である。

:format format-string
この文字列は、型に対応する値を表現するためにバッファに挿入される。 format-stringには、以下に示す`%'を使える。

`%[button%]'
ボタンとして印を付けたテキストbuttonを表示する。 :action属性は、ユーザーがボタンを起動したらなにを行うかを指定する。 その値は2つの引数、つまり、ボタンが現れるウィジェットとイベント を取る関数であること。

異なるアクションを有する異なるボタンを指定する方法はない。

`%{sample%}'
:sample-faceで指定した特別なフェイスでsampleを表示する。

`%v'
項目の値で置き換える。 値の表示方法は項目の種類と、 (変数の)カスタマイズ型に依存する。

`%d'
項目の説明文字列で置き換える。

`%h'
`%d'と同様だが、説明文字列が1行を超えるときには、 説明文字列全体を表示するか先頭行だけを表示するかを 制御するアクティブフィールドを追加する。

`%t'
タグで置き換える。 タグは:tagキーワードで指定する。

`%%'
`%'をそのまま表示する。

:action action
ユーザーがボタンをクリックしたらactionを行う。

:button-face face
`%[...%]'で表示するボタンテキストに フェイスface(フェイス名かフェイス名のリスト)を使う。

:button-prefix prefix
:button-suffix suffix
これらは、以下のようにボタンの前後に表示するテキストを指定する。

nil
テキストを挿入しない。

文字列
文字列をそのまま挿入する。

シンボル
シンボルの値を使う。

:tag tag
この型に対応する値(やその一部)に対するタグとして tag(文字列)を使う

:doc doc
この型に対応する値(やその一部)に対する説明文字列として docを使う。 これが動作するためには、 :formatの値を指定し、かつ、 その値の中で`%d'や`%h'を使う必要がある。

型に対して説明文字列を指定するのは、 :choiceの選択肢や他の複合型の一部の意味について より多くの情報をユーザーに与えるためである。

:help-echo motion-doc
widget-forwardwidget-backwardでこの項目に移動すると、 エコー領域に文字列motion-docを表示する。

:match function
値がこの型に一致することを調べる方法を指定する。 対応する値functionは、2つの引数、つまり、 ウィジェットと値を取る関数であること。 受理できる値の場合にはnil以外を返すこと。


[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端] [?]