Di chuyển các dòng được chọn lên và xuống


7

Tôi đã sử dụng nhật thực được một thời gian và tôi đã tìm thấy một số phím tắt rất hữu ích, đặc biệt là khả năng di chuyển một lựa chọn hình chữ nhật của các dòng lên và xuống bằng Alt + Lên / Xuống. Tôi đã tìm kiếm chức năng này trong emacs. Cho đến nay tôi đã tìm thấy đoạn script sau:

(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)

Điều này không hoạt động ngoại trừ thực tế là điều này di chuyển lựa chọn . Thay vào đó, tôi muốn di chuyển tất cả các dòng (bao gồm cả dòng mới) trong phần lựa chọn. Có cách nào để nhận ra điều này là tốt?


Một câu hỏi liên quan về stackoverflow: stackoverflow.com/q/2423834 .
Tên

Đó là nơi tôi đã nhận được mã từ. Tôi đã hỏi lại vì giải pháp đó không làm tôi hài lòng.
hfhc2

Câu trả lời:


14

drag-stuff

Kiểm tra drag-stuffgói (cũng có sẵn trên Melpa).

Sau đó, bạn có thể chọn một khu vực và sử dụng drag-stuff-up/ drag-stuff-downđể di chuyển khu vực đó lên / xuống.


Hành vi thay thế khi kéo dòng

Theo mặc định, các drag-stufflệnh cũng sẽ kéo dòng pointđang bật (ngay cả khi điểm nằm trên cột đầu tiên). Nếu bạn muốn chọn, hãy nói toàn bộ 2 dòng bằng cách thực hiện C-a C-SPC C-n C-n, lựa chọn sẽ trông giống như thế này

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

Lưu ý rằng ở đây tôi dự định chỉ di chuyển dòng 2 và 3, không phải dòng 4 . Nhưng drag-stufftheo mặc định sẽ di chuyển dòng thứ 3 đó.

Đó là peeve pet của tôi (và có lẽ không áp dụng cho bất kỳ ai khác) và vì vậy tôi đã yêu cầu nhà phát triển gói giải pháp . Đây là một hack bạn có thể đặt cấu hình emacs của mình sau khi yêu cầu drag-stuffnếu bạn không muốn hành vi mặc định này. Việc hack sẽ không di chuyển dòng hiện tại NẾU điểm nằm trên cột 0 (cột đầu tiên).

;; 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)

Trình diễn cách kéo các dòng hoạt động trước và sau khi hack ở trên

Trước khi 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

Sau khi 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

Tổ hợp phím

Để đạt được hành vi giống như nhật thực, chỉ cần thêm các ràng buộc chính thích hợp:

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

Hừm ... khó chịu như di chuyển dòng 4, nó chắc chắn phù hợp hơn. Ví dụ: nếu bạn định di chuyển các dòng, nhưng quan điểm của bạn là ở EOL, hành vi "bị hack" mới có vẻ rất kỳ lạ.
PythonNut 13/07/2015

@PythonNut Vâng, nếu điểm không nằm trên col 0, toàn bộ dòng đó sẽ được di chuyển. Nhưng đó là lý do tại sao đây là một hack; nó phù hợp với quy trình làm việc của tôi. Tôi tin vào 99% các lựa chọn khu vực của mình khi di chuyển các dòng, điểm của tôi là trên col 0 vì tôi có xu hướng chọn toàn bộ các dòng ( ví dụ C-a C-SPC C-4 C-n ) hoặc toàn bộ đoạn văn ( ví dụ C-a C-SPC M-} ). Tôi biết là có M-h, chỉ là chưa quen với điều đó. Hãy tưởng tượng nó sẽ gây khó chịu như thế nào nếu mỗi lần tôi kết thúc việc kéo đoạn đã chọn của mình cộng với dòng tiếp theo! :)
Kaushal Modi

Liệu hack của bạn có làm sai hay không nếu điểm nằm ở đầu khu vực thay vì ở cuối?
Harald Hanche-Olsen

@ HaraldHanche-Olsen Đúng. Đáng ngạc nhiên là tôi không bao giờ lựa chọn theo cách đó (bắt đầu từ dưới lên và đi lên) và vì vậy tôi không bao giờ bắt gặp vấn đề này :). Bây giờ nó đã được sửa (như tôi có thể nói từ một xác minh nhanh). Hãy cho tôi biết, nếu việc này giúp ích cho bạn. Cảm ơn đã nhận thấy điều này.
Kaushal Modi

2

Tôi đã mã hóa điều này một thời gian trước đây, sử dụng nó mỗi ngày .

(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
Điều này thật tuyệt vời, cảm ơn vì đã đăng bài này, tôi không biết tại sao bạn không có nhiều sự ủng hộ hơn!
iFeft

1

Đây là một cách để làm điều này bằng cách sử dụng macro bàn phím:

  • C-x ( bắt đầu ghi lại macro.
  • C-aSPCC-pSPCC-wC-pC-y cắt một dòng và dán nó một dòng trước đó trong bộ đệm.
  • C-x ) kết thúc ghi vĩ mô.
  • C-x e sẽ di chuyển dòng lên nhiều lần như bạn nhấn nó.

Chà, có một chức năng transpose-lineshoạt động theo cách này, nhưng chức năng này chỉ hoạt động cho các dòng duy nhất như đề xuất của bạn ...
hfhc2

@ hfhc2 macro bàn phím là một giải pháp đặc biệt. Với cùng tốc độ, bạn có thể làm cho nó di chuyển nhiều hơn một dòng (chỉ cần thêm một đối số số vào C-p).
wvxvw
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.