Verschieben Sie ausgewählte Zeilen nach oben und unten


7

Ich benutze Eclipse jetzt schon eine Weile und fand einige Verknüpfungen sehr nützlich, insbesondere die Möglichkeit, eine rechteckige Auswahl von Linien mit Alt + Auf / Ab nach oben und unten zu verschieben. Ich habe mich in Emacs nach dieser Funktionalität umgesehen. Bisher habe ich folgendes Skript gefunden:

(defun move-text-internal (arg)
   (cond
    ((and mark-active transient-mark-mode)
     (if (> (point) (mark))
            (exchange-point-and-mark))
     (let ((column (current-column))
              (text (delete-and-extract-region (point) (mark))))
       (forward-line arg)
       (move-to-column column t)
       (set-mark (point))
       (insert text)
       (exchange-point-and-mark)
       (setq deactivate-mark nil)))
    (t
     (beginning-of-line)
     (when (or (> arg 0) (not (bobp)))
       (forward-line)
       (when (or (< arg 0) (not (eobp)))
            (transpose-lines arg))
       (forward-line -1)))))

(defun move-text-down (arg)
   "Move region (transient-mark-mode active) or current line
  arg lines down."
   (interactive "*p")
   (move-text-internal arg))

(defun move-text-up (arg)
   "Move region (transient-mark-mode active) or current line
  arg lines up."
   (interactive "*p")
   (move-text-internal (- arg)))

(global-set-key [\M-up] 'move-text-up)
(global-set-key [\M-down] 'move-text-down)

Dies funktioniert mit Ausnahme der Tatsache, dass dadurch die Auswahl verschoben wird . Ich würde stattdessen lieber alle Zeilen (einschließlich nachfolgender Zeilenumbrüche) verschieben, die in der Auswahl enthalten sind. Gibt es eine Möglichkeit, dies auch zu realisieren?


Eine verwandte Frage zu stackoverflow: stackoverflow.com/q/2423834 .
Name

Von dort habe ich den Code bekommen. Ich fragte noch einmal, weil diese Lösung nicht zu meiner Zufriedenheit war.
hfhc2

Antworten:


14

drag-stuff

Schauen Sie sich das drag-stuffPaket an (auch bei Melpa erhältlich).

Sie können dann eine Region auswählen und diese Region mit drag-stuff-up/ drag-stuff-downnach oben / unten verschieben.


Alternatives Verhalten beim Ziehen von Linien

Standardmäßig ziehen die drag-stuffBefehle auch die Linie, auf der sie sich pointbefinden (auch wenn sich der Punkt in der ersten Spalte befindet). Wenn Sie auswählen möchten, sagen wir 2 ganze Zeilen C-a C-SPC C-n C-n, sieht die Auswahl ungefähr so ​​aus

 line 1
▯line 2
 line 3
▮line 4 
 line 5

Beachten Sie, dass ich hier nur die Zeilen 2 und 3 verschieben möchte, nicht die Zeile 4 . Aber drag-stuffwird diese dritte Zeile bewegen als auch standardmäßig.

Das war mein Liebling (und trifft wahrscheinlich auf niemanden zu) und so bat ich den Paketentwickler um eine Lösung . Hier ist ein Hack, den Sie nach Bedarf in Ihre Emacs-Konfiguration einfügen können, drag-stuffwenn Sie dieses Standardverhalten nicht möchten. Der Hack verschiebt die aktuelle Linie nicht, wenn sich der Punkt in Spalte 0 (erste Spalte) befindet.

;; https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-drag-stuff.el
;; https://github.com/rejeep/drag-stuff.el/issues/4
(defvar modi/drag-stuff--point-adjusted nil)
(defvar modi/drag-stuff--point-mark-exchanged nil)

(defun modi/drag-stuff--adj-pt-pre-drag ()
  "If a region is selected AND the `point' is in the first column, move
back the point by one char so that it ends up on the previous line. If the
point is above the mark, exchange the point and mark temporarily."
  (when (region-active-p)
    (when (< (point) (mark)) ; selection is done starting from bottom to up
      (exchange-point-and-mark)
      (setq modi/drag-stuff--point-mark-exchanged t))
    (if (zerop (current-column))
        (progn
          (backward-char 1)
          (setq modi/drag-stuff--point-adjusted t))
      ;; If point did not end up being on the first column after the
      ;; point/mark exchange, revert that exchange.
      (when modi/drag-stuff--point-mark-exchanged
        (exchange-point-and-mark) ; restore the original point and mark loc
        (setq modi/drag-stuff--point-mark-exchanged nil)))))

(defun modi/drag-stuff--rst-pt-post-drag ()
  "Restore the `point' to where it was by forwarding it by one char after
the vertical drag is done."
  (when modi/drag-stuff--point-adjusted
    (forward-char 1)
    (setq modi/drag-stuff--point-adjusted nil))
  (when modi/drag-stuff--point-mark-exchanged
    (exchange-point-and-mark) ; restore the original point and mark loc
    (setq modi/drag-stuff--point-mark-exchanged nil)))

(add-hook 'drag-stuff-before-drag-hook #'modi/drag-stuff--adj-pt-pre-drag)
(add-hook 'drag-stuff-after-drag-hook  #'modi/drag-stuff--rst-pt-post-drag)

Demonstration, wie das Ziehen von Linien vor und nach dem obigen Hack funktioniert

Vor dem Hack

 line 1                                      line 1
▯line 2                                      line 5
 line 3    --(M-x drag-stuff-down)-->       ▯line 2   MOVED LINE
▮line 4                                      line 3   MOVED LINE
 line 5                                     ▮line 4   MOVED LINE

Nach dem Hack

 line 1                                      line 1
▯line 2                                      line 4
 line 3    --(M-x drag-stuff-down)-->       ▯line 2   MOVED LINE
▮line 4                                      line 3   MOVED LINE
 line 5                                     ▮line 5

Tastenbelegungen

Um das Eclipse-ähnliche Verhalten zu erreichen, fügen Sie einfach die entsprechenden Tastenkombinationen hinzu:

(global-set-key (kbd "M-<up>")   #'drag-stuff-up)
(global-set-key (kbd "M-<down>") #'drag-stuff-down)

Hm ... so nervig es ist, Linie 4 zu bewegen, es ist definitiv konsistenter. Wenn Sie beispielsweise Linien verschieben würden, aber Ihr Punkt bei EOL war, würde das neue "gehackte" Verhalten in der Tat sehr seltsam erscheinen.
PythonNut

@PythonNut Ja, wenn der Punkt nicht auf Spalte 0 wäre, würde diese ganze Linie verschoben. Aber deshalb ist das ein Hack; es passt zu meinem Workflow. Ich glaube an 99% meiner Regionsauswahl beim Verschieben von Linien. Mein Punkt liegt in Spalte 0, da ich dazu neige, ganze Linien ( Beispiel C-a C-SPC C-4 C-n ) oder ganze Absätze ( Beispiel C-a C-SPC M-} ) auszuwählen . Ich weiß, dass ich M-hmich noch nicht daran gewöhnt habe. Stellen Sie sich vor, wie nervig es werden könnte, wenn ich jedes Mal meinen ausgewählten Absatz plus die nächste Zeile ziehe! :)
Kaushal Modi

Wird Ihr Hack nicht das Falsche tun, wenn der Punkt am Anfang der Region statt am Ende liegt?
Harald Hanche-Olsen

@ HaraldHanche-Olsen Richtig. Überraschenderweise habe ich die Auswahl nie so getroffen (von unten nach oben) und deshalb habe ich dieses Problem nie bemerkt :). Es ist jetzt behoben (wie ich anhand einer schnellen Überprüfung erkennen konnte). Lassen Sie mich wissen, ob dies für Sie funktioniert. Danke, dass du das bemerkt hast.
Kaushal Modi

2

Ich habe das vor langer Zeit codiert und benutze es jeden Tag .

(defun move-line-up ()
  "Move up the current line."
  (interactive)
  (transpose-lines 1)
  (forward-line -2)
  (indent-according-to-mode))

(defun move-line-down ()
  "Move down the current line."
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1)
  (indent-according-to-mode))

(global-set-key [(meta shift up)]  'move-line-up)
(global-set-key [(meta shift down)]  'move-line-down)

1
Das ist fantastisch. Danke, dass du das gepostet hast. Ich habe keine Ahnung, warum du keine weiteren Upvotes hast.
iFunction

1

Hier ist eine Möglichkeit, dies mithilfe von Tastaturmakros zu tun:

  • C-x ( Starten Sie die Aufnahme des Makros.
  • C-aSPCC-pSPCC-wC-pC-y Schneiden Sie eine Zeile aus und fügen Sie sie eine Zeile früher in den Puffer ein.
  • C-x ) Beenden Sie die Aufnahme des Makros.
  • C-x e Verschiebt die Linie so oft nach oben, wie Sie sie drücken.

Nun, es gibt eine Funktion, transpose-linesdie auf diese Weise funktioniert , aber dies funktioniert nur für einzelne Zeilen, ebenso wie Ihr Vorschlag ...
hfhc2

@ hfhc2 das Tastaturmakro ist sowieso eine Ad-hoc-Lösung. Mit der gleichen Geschwindigkeit können Sie mehr als eine Zeile verschieben (fügen Sie einfach ein numerisches Argument hinzu C-p).
wvxvw
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.