For programming languages, an important feature of a major mode is to
provide automatic indentation. There are two parts: one is to decide what
is the right indentation of a line, and the other is to decide when to
reindent a line. By default, Emacs reindents a line whenever you type a
character in electric-indent-chars, which by
default only includes Newline. Major modes can add chars to electric-indent-chars according to the syntax of the
language.
適切なインデントをどう決定するかは、Emacsではindent-line-functionによって制御されています(メジャーモードによるインデント制御を参照)。一部のモードでは、通常、インデントが重要な意味を持つため複数のインデントが有効でありながらそれぞれ異なる意味を持ち、適切なインデントを確実に特定することができません。そのような場合、ユーザーの意図に反して行が絶えず再インデントされないよう、モード側でelectric-indent-inhibitを設定する必要があります。
優れたインデント関数を書くのは難しく、大部分において今なお一種の「黒魔術」のようなものです。多くのメジャーモードの開発者は、まず単純なケースで動作するシンプルなインデント関数――例えば、直前のテキスト行のインデントと比較するようなもの――を書くことから始めます。真の意味で行ベースではないほとんどのプログラミング言語において、こうした手法は拡張性に著しく欠ける傾向があります。より多様な状況に対応できるよう関数を改良しようとすると、次第に困難さが増し、結果として、誰も手をつけようとしない、巨大で複雑かつ保守不可能なインデント関数が出来上がってしまうのです。
優れたインデント機能には、通常、言語の構文に従ってテキストを実際にパースする必要があります。幸いなことに、コンパイラほど詳細にパースする必要はありませんが、その一方で、インデントコードに組み込まれたパーサーは、構文的に不正なコードに対してもある程度寛容である必要があります。
保守性の高いインデント関数は、通常、2つのカテゴリーに分類される。ある安全な起点から目的の位置まで順方向にパースする方法か、あるいは目的の位置から逆方向にパースする方法である。この2つのうち、どちらかが明確に他方より優れているというわけではない。プログラミング言語は順方向のパースを前提に設計されているため、逆方向のパースは順方向よりも困難なことが多い。しかし、インデントに関しては、安全な起点を推測する必要がないという利点があり、一般的に、行のインデントを決定するために解析されるテキスト量が最小限で済むという特性を持つ。そのため、インデントは、それより前の無関係なコード部分にある構文エラーの影響を受けにくくなる傾向がある。一方、順方向のパースは通常より容易であり、一度のパースで領域全体を効率的に再インデントできるという利点がある。
インデント機能を一から自作するよりも、既存の機能を再利用したり、汎用的なインデントエンジンを利用したりする方が望ましい場合が多いです。残念ながら、そうしたエンジンはごくわずかしかありません。CCモードのインデントコード(C、C++、Java、Awk、およびその他のいくつかのモードで使用される)は、長年にわたってより汎用的なものへと改良されてきたため、使用している言語がこれらの言語のいずれかに多少似ているようであれば、そのエンジンを試してみるとよいでしょう。もう一つはSMIEで、Lispのセクスプの考え方を取り入れ、それを非Lisp言語向けに適応させたものです。さらに別の方法としては、例えばtree-sitterライブラリのような本格的なパーサーを利用するという手もあります。