Trong khi đó tôi đã viết một mã để thực hiện hack mà @glucas đã đề cập. Nó có lẽ chỉ phù hợp với mục đích sắp xếp các tiêu đề trong C, nhưng tôi hy vọng ai đó thấy nó hữu ích.
(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)))))))))
Chức năng swap-<-and-quote-includes
biến đổi mỗi văn bản như <foo>
đến "foo"
, và mỗi "foo"
để <foo>
trong phạm vi được cầu xin , cuối .
Và đây là mã để tìm và sắp xếp các tiêu đề:
(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))
)))
Hàm c-sort-includes
tìm kiếm đoạn đầu tiên của «#include» s và sắp xếp nó. Tôi đã thêm nó vào before-save-hook
với một mã để chỉ chạy nó cho chế độ C và C ++. Nhược điểm đã biết: α) chỉ đoạn đầu tiên có bao gồm sẽ được sắp xếp. Đó là bởi vì tìm kiếm cho đến cuối tập tin có thể tốn kém - ví dụ như trong công việc của tôi, gần đây tôi đã tìm thấy một .c
tập tin với - bạn có thể tưởng tượng được không?! - 00016000 dòng! Giải pháp chính xác sẽ là một chế độ nhỏ, theo dõi các khối tiêu đề trong tệp nằm ở đâu. ) Trong các Emac cũ hơn, từ năm 2015, chức năng có thể bị treo - đó là một lỗi mà sau đó đã được sửa.
sort-subr
trực tiếp. Hoặc .. là một hack, bạn có thể khuyênsort-lines
rằng trước khi sắp xếp bạn trao đổi"
và<
ký tự và sau khi sắp xếp bạn trao đổi chúng trở lại. :-)