Kiểm tra bốn câu trả lời hiện có ( hai trên Super User và hai cho câu hỏi này), tôi thấy các vấn đề sau:
- Những người trên SuperUser của Stefan và Peng Bai (di chuyển từng dòng một, nhìn vào vết lõm hiện tại) không thực hiện giữ lại vị trí cột hiện tại và di chuyển lên tới cha mẹ,
- Câu trả lời của Dan (sử dụng tìm kiếm lại chuyển tiếp để tìm dòng tiếp theo có cùng vết lõm) bỏ qua các dòng có ít vết lõm: không biết khi nào không có anh chị em tiếp theo và do đó có thể chuyển sang thứ không phải là anh chị em nhưng có thể là con của một phụ huynh khác, một người anh em họ tiếp theo có lẽ.
- Câu trả lời của Gilles (sử dụng chế độ phác thảo) không giữ vị trí cột và nó không hoạt động với các dòng có độ thụt bằng 0 (dòng "cấp cao nhất"). Ngoài ra, nhìn vào mã của nó
outline.el
, về cơ bản, nó cũng đi theo từng dòng (sử dụng outline-next-visible-heading
) trong trường hợp của chúng tôi, vì (gần như) tất cả các dòng sẽ khớp với biểu thức chính quy và được coi là "tiêu đề".
Vì vậy, kết hợp một số ý tưởng của từng ý tưởng, tôi có những điều sau đây: di chuyển về phía trước từng dòng, bỏ qua các dòng trống và thụt vào nhiều hơn. Nếu bạn ở vị trí thụt bằng nhau thì đó là anh chị em tiếp theo. Ý tưởng cơ bản trông như thế này:
(defun indentation-get-next-sibling-line ()
"The line number of the next sibling, or nil if there isn't any."
(let ((wanted-indentation (current-indentation)))
(save-excursion
(while (and (zerop (forward-line)) ; forward-line returns 0 on success
(or (eolp) ; Skip past blank lines and more-indented lines
(> (current-indentation) wanted-indentation))))
;; Now we can't go further. Which case is it?
(if (and (not (eobp)) (= (current-indentation) wanted-indentation))
(line-number-at-pos)
nil))))
(defun indentation-forward-to-next-sibling ()
(interactive)
(let ((saved-column (current-column)))
(forward-line (- (indentation-get-next-sibling-line) (line-number-at-pos)))
(move-to-column saved-column)))
Tổng quát phù hợp (tiến / lùi / lên / xuống), những gì tôi đang sử dụng trông giống như sau:
(defun indentation-get-next-good-line (direction skip good)
"Moving in direction `direction', and skipping over blank lines and lines that
satisfy relation `skip' between their indentation and the original indentation,
finds the first line whose indentation satisfies predicate `good'."
(let ((starting-indentation (current-indentation))
(lines-moved direction))
(save-excursion
(while (and (zerop (forward-line direction))
(or (eolp) ; Skip past blank lines and other skip lines
(funcall skip (current-indentation) starting-indentation)))
(setq lines-moved (+ lines-moved direction)))
;; Now we can't go further. Which case is it?
(if (and
(not (eobp))
(not (bobp))
(funcall good (current-indentation) starting-indentation))
lines-moved
nil))))
(defun indentation-get-next-sibling-line ()
"The line number of the next sibling, if any."
(indentation-get-next-good-line 1 '> '=))
(defun indentation-get-previous-sibling-line ()
"The line number of the previous sibling, if any"
(indentation-get-next-good-line -1 '> '=))
(defun indentation-get-parent-line ()
"The line number of the parent, if any."
(indentation-get-next-good-line -1 '>= '<))
(defun indentation-get-child-line ()
"The line number of the first child, if any."
(indentation-get-next-good-line +1 'ignore '>))
(defun indentation-move-to-line (func preserve-column name)
"Move the number of lines given by func. If not possible, use `name' to say so."
(let ((saved-column (current-column))
(lines-to-move-by (funcall func)))
(if lines-to-move-by
(progn
(forward-line lines-to-move-by)
(move-to-column (if preserve-column
saved-column
(current-indentation))))
(message "No %s to move to." name))))
(defun indentation-forward-to-next-sibling ()
"Move to the next sibling if any, retaining column position."
(interactive "@")
(indentation-move-to-line 'indentation-get-next-sibling-line t "next sibling"))
(defun indentation-backward-to-previous-sibling ()
"Move to the previous sibling if any, retaining column position."
(interactive "@")
(indentation-move-to-line 'indentation-get-previous-sibling-line t "previous sibling"))
(defun indentation-up-to-parent ()
"Move to the parent line if any."
(interactive "@")
(indentation-move-to-line 'indentation-get-parent-line nil "parent"))
(defun indentation-down-to-child ()
"Move to the first child line if any."
(interactive "@")
(indentation-move-to-line 'indentation-get-child-line nil "child"))
Vẫn còn một số chức năng mong muốn, và xem xét outline.el
và thực hiện lại một số trong số đó có thể giúp ích, nhưng bây giờ tôi hài lòng với điều này, cho mục đích của tôi.
set-selective-display
giúp bạn gần với những gì bạn cần?