回答:
使用できますsort-regexp-fields
。リージョンをマークして、次の操作を行います。
M-x sort-regexp-fields
RET #include .\(.*\)
RET \1
RET
正規表現のグループは、すべてのものをキャプチャします後#include "
または#include <
ソート代わりに、行全体のそれに。
ちなみに、あなたが見ているソートの理由はASCII "
よりも高いためです<
。
<
、"
シンボル。しかし、私は結論に達しました。このように並べ替えられたヘッダーは少し乱雑に見えます。そのため、文字の順序を変更したいのです。
一方、@ glucasが言及したハックを実装するためのコードを書きました。それはおそらくCでヘッダーをソートする目的にのみ適していますが、誰かがそれを役にたてることを願っています。
(defun replace-char-after (character-number replacement)
"Replaces char in the buffer after the `character-number' with `replacement'"
(save-excursion
(goto-char character-number)
(delete-char 1)
(insert-char replacement)))
(defun replace-delimiters (old-closing-char new-opening-char new-closing-char opening-point end-point)
"Replaces delimiters between `opening-point' and the
`end-point'. Note, that the `opening-point' should point to the
opening symbol, thus the function seeks only the closing"
(block replace-delimiters
(let ((closing-point opening-point))
(setq closing-point (+ 1 opening-point))
(while (< closing-point end-point)
(if (eq (char-after closing-point) ?\n) ;;no closing delimiter
(progn
(print "Err: no closing delimiter")
(return-from replace-delimiters nil))
(when (eq (char-after closing-point) old-closing-char)
(progn
(replace-char-after opening-point new-opening-char);;opening delimiter
(replace-char-after closing-point new-closing-char);;closing delimiter
(return-from replace-delimiters (+ 1 closing-point)))))
(setq closing-point (+ closing-point 1))))))
(defun swap-<-and-quote-includes (beg end)
"Swaps in the text between `beg' and `end' the matching «<» and
«>» character to the \" quote, and vice versa. Mainly used
before sorting to swap the order of these characters, next
after the sort to restore the text."
(block swap-<-and-quote-includes
(let ((curr-point beg))
(while (< curr-point end)
(setq curr-point (+ curr-point 1))
;;first check «"»
(if (eq (char-after curr-point) ?\")
(progn
(setq curr-point (replace-delimiters ?\" ?< ?> curr-point end))
(if (eq curr-point nil)
(return-from swap-<-and-quote-includes t)))
;;else if «<»
(if (eq (char-after curr-point) ?<)
(progn
(setq curr-point (replace-delimiters ?\> ?\" ?\" curr-point end))
(if (eq curr-point nil)
(return-from swap-<-and-quote-includes t)))))))))
この関数は、toのswap-<-and-quote-includes
ようなすべてのテキスト、および指定された範囲beg、end内のすべてのto <foo>
を変換します。"foo"
"foo"
<foo>
そして、これがヘッダーを見つけてソートするためのコードです:
(defun sort-lines-nocase (reverse beg end)
(let ((sort-fold-case t))
(sort-lines reverse beg end)))
(defun c-sort-includes ()
"Sorts #include statements"
(interactive)
(save-excursion
(let (beg end orig-content sorted-content)
(goto-char (point-min))
(while (and (not (looking-at "#include "));;look for includes, if no then
(eq (forward-line 1) 0) ;;go one line down (if not EOF).
))
(setq beg (point))
(while (and (looking-at "#include ")
(eq (forward-line 1) 0)));;to not hang cuz of EOF
(setq end (point))
(setq orig-content (buffer-substring-no-properties beg end))
(setq sorted-content (with-temp-buffer
(insert orig-content)
(swap-<-and-quote-includes (point-min) (point-max)) ;;swap characters < and > in includes
(sort-lines-nocase (point-min) (point-max)) ;;sort
(swap-<-and-quote-includes (point-min) (point-max)) ;;swap the characters back
(buffer-string)))
(when (not (string= orig-content sorted-content))
(kill-region beg end)
(insert sorted-content))
)))
この関数c-sort-includes
は、«#include»の最初の段落を探して並べ替えます。before-save-hook
CおよびC ++モードでのみ実行するコードを追加しました。既知の短所:α)インクルードのある最初の段落のみがソートされます。それは、ファイルの最後までの検索は高額になる可能性があるためです(たとえば、私の仕事では、最近.c
ファイルを見つけたのですが)想像できますか?!—≈16000行!正しい解決策は、ファイル内のヘッダーブロックが存在する場所を追跡するマイナーモードではなく、β)古いEmacsでは、≈2015年以降、機能がハングする可能性がありました-後で修正されたバグです。
sort-subr
直接呼び出す必要がある場合があります。それとも...ハックとして、あなたは助言することができsort-lines
、ソート前に入れ替えるように"
し、<
文字と、その後の並べ替え後にあなたが戻ってそれらを交換します。:-)