4

今月は、Emacs Lisp と格闘して、自分のニーズにより適した自動インデントを取得しようとしました。ほとんどのインデント コードがいかに低レベルであるかは驚くべきことです。次のような非常に少数の抽象化を見てきました

  • 文字列またはコメントにない正規表現の最初のインスタンスを検索します

理解しやすく、変更しやすいインデント コードを作成するのに役立つ有用な抽象化が他にもたくさんあると思います。(私が引用した抽象化でさえ、「関数がnilを返すか、ポイントが文字列またはコメントに含まれなくなるまで、この関数をこれらの引数に繰り返し適用する」ように改善できます。)

私はemacsで作業していますが、どこからでも良いアイデアを取り入れるので、この質問にもvimでタグを付けました。

クリーンでよく設計されたモジュール式のカスタム インデント関数をプログラムしたい場合、どの抽象化を使用しますか? (また、適切な抽象化を使用していると思われるコードや、適切に設計されていると思われるコードへのポインターも参照していただければ幸いです。)

4

3 に答える 3

4

より高いレベルのものを探しているように聞こえますが、macs 23 にはSMIEが付属しており、これは一般的にこれを解決しようとしています。ただし、これはメジャー モードの開発者向けであり、既存のインデント動作を変更するためのものではありません。

編集:主要な抽象化は次のように見えます

  • ダーティ トリック レクサーによって補完された、かなり弱い演算子優先パーサー

  • 各トークンは「仮想インデント」の概念を取得し、行を開始すると表示されます

  • 各トークンには、囲んでいる構文構造の開始点である「親」があります。

エントリーのコストはかなり高いようで、ソフトウェアには次の免責事項が付随しています。

実際には、[the] デフォルトのインデント スタイルはおそらく十分ではありません。多くの異なるケースでそれを微調整したいと思うでしょう。

(編集終了)


あなたが言うこと:

文字列またはコメントにない正規表現の最初のインスタンスを検索します

syntax-ppssとを呼び出すことで簡単に実行できre-search-backwardます。

于 2012-07-07T12:19:11.197 に答える
2

プログラムでバッファをナビゲートするための、言語にとらわれない優れた抽象化は、sexp と構文テーブルです。モードの構文テーブルが適切に構築されている場合は、 と を使用して移動できforward-sexpますscan-sexps。これらがうまくいかない場合にのみ正規表現を使用し、最終的に持っている場合はそれらによって提供された値を使用することをお勧めします(その引数re-search-forwardを参照してください)。BOUND

またsyntax-ppss、コメントまたは文字列リテラル内にあるかどうかを簡単に識別したり、文字エスケープの状況に対処したりするために使用します。Emacs Lisp info ノードの構文表を参照してください。

(syntax-ppss)確かに、すべてがリストであり、「深さは何レベルですか?」などの質問を簡単に行うことができるため、sexp はおそらく Lisp のインデントにうまく機能し(point)ます。Ruby のようなブロック区切り文字を使用するbeginend、クレイジーな正規表現の領域に入ります。

したがって(syntax-ppss)、他の言語でのような良さを得るには、そのためだけにパーサーを作成する必要があります。たとえばruby-mode、パーサーを実装し、nxml-modeこれの信じられないほどの例を見てください。

with-syntax-tableまた、バッファを一時的に別の視点から見ることができるため、多くのことができることに注意してください。インデントではありませんが、http://github.com/joaotavora/autopairのこの例を検討してください。これにより、一部の括弧タイプを無視できます

(defvar autopair-empty-syntax-table
  (let ((empty (make-syntax-table)))
    (dotimes (char 256)
      (let ((syntax-entry (aref empty char)))
        (when (and (consp syntax-entry)
                   (or (eq (car (string-to-syntax "("))
                           (car syntax-entry))
                       (eq (car (string-to-syntax ")"))
                           (car syntax-entry))))
          (modify-syntax-entry char "w" empty))))
    empty)
  "A syntax table no \"(\" or \")\" syntaxes")
 
(defun autopair-just-for-delim-syntax-table (delim)
  "A syntax table that has \"parenthesis\" syntax just for DELIM."
  (let* ((syntax-entry (aref (syntax-table) delim))
         (other-syntax-entry (and syntax-entry
                                  (cdr syntax-entry)
                                  (aref (syntax-table) (cdr syntax-entry)))))
    (when (consp other-syntax-entry)
      (let ((retval (make-syntax-table autopair-empty-syntax-table)))
        (aset retval delim syntax-entry)
        (aset retval (cdr syntax-entry) other-syntax-entry)
        retval))))

[]さて、混合された,()と状況のバッファーでは、後者が のみをカウントする場所でor{}を要求するのはまったく異なります。どの言語をインデントしようとしているかはわかりませんが、これは、たとえば C ブロックをインデントするための適切な作業を行うのに役立ちます。(syntax-ppss)(with-syntax-table (autopair-just-for-delim-syntax-table ?{ ) (syntax-ppss)){}

于 2012-07-08T15:14:56.483 に答える
1

私が知っているいくつかの便利な組み込みプリミティブ:

  • インデント行
  • 現在のインデント

私の知る限り、emacs の一部ではない便利なプリミティブ:

  • 前の非空白行に移動
  • line-matches-p (正規表現)
  • inside-p (開始文字列 終了文字列)

このリストを自由に完成させてください。emacs のインデントに関するリソースはあまり見つかりません。

于 2012-07-07T20:48:50.190 に答える