Wenn ich die vier derzeit verfügbaren Antworten ( zwei für Superuser und zwei für diese Frage) betrachte, sehe ich die folgenden Probleme:
- Bei denen in SuperUser von Stefan und Peng Bai (zeilenweise verschieben, aktuelle Einrückung anzeigen ) wird die aktuelle Spaltenposition nicht beibehalten und zum übergeordneten Element verschoben.
- Die Antwort von Dan (mit erneuter Suche nach vorne, um die nächste Zeile mit demselben Einzug zu finden) überspringt Zeilen mit weniger Einzug: Er weiß nicht, wann es kein nächstes Geschwister gibt, und kann daher zu etwas wechseln, das kein Geschwister ist aber ein Kind eines anderen Elternteils ... vielleicht ein nächster "Cousin".
- Die Antwort von Gilles (im Umriss-Modus) behält die Spaltenposition nicht bei und funktioniert nicht mit Zeilen ohne Einrückung (Zeilen der obersten Ebene). Wenn man sich den Code darin ansieht
outline.el
, geht es outline-next-visible-heading
in unserem Fall ohnehin auch grundsätzlich zeilenweise (mit ), da (fast) alle Zeilen dem regulären Ausdruck der Gliederung entsprechen und als "Überschrift" zählen würden.
Wenn ich also einige Ideen für jede zusammenstelle, habe ich Folgendes: Gehen Sie Zeile für Zeile vor, und überspringen Sie leere und stärker eingerückte Zeilen. Wenn Sie die gleiche Einrückung haben, ist es das nächste Geschwister. Die Grundidee sieht so aus:
(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)))
Entsprechend verallgemeinert (vorwärts / rückwärts / aufwärts / abwärts) sieht das, was ich verwende, derzeit folgendermaßen aus:
(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"))
Es ist noch etwas mehr Funktionalität wünschenswert, und outline.el
es kann hilfreich sein, einige davon zu betrachten und neu zu implementieren, aber ich bin für meine Zwecke im Moment damit zufrieden.
set-selective-display
erhalten Sie in der Nähe zu dem, was Sie brauchen?