Emacs'de satırı / bölgeyi yukarı ve aşağı taşı


85

Emacs'de seçilen bölgeyi veya çizgiyi (seçim yoksa) yukarı veya aşağı hareket ettirmenin en kolay yolu nedir? Tutulmadakiyle aynı işlevselliği arıyorum (M-yukarı, M-aşağı ile sınırlı).


1
Deyimin sadece taşımak istediğiniz şeyi öldürmek olduğundan eminim, kodun olmasını istediğiniz noktayı taşımak için normal gezinme işlevlerini (isearch vb. Dahil) kullanın ve sonra yank yapın. Bir yığın öldürme var, unutmayın, bu yüzden konumu hemen bulmanız bile gerekmez; daha sonra çekmek için diğer parçaları toplayabilirsiniz. Kişisel olarak, yoğun bir Emacs kullanıcısı olarak, tek bir satırı manuel olarak yukarı veya aşağı hareket ettirmeyi tercih ettiğim herhangi bir durumu hayal edemiyorum. Yararlı olmaz.
jrockway

7
@jrockway: Yorumunuz için teşekkürler. Bence herkesin kendi yöntemi var. Tutulma ile çok çalışıyorum ve çizgileri / bölgeleri hareket ettirmeye çok alışkınım. Emac'lerin çok genişletilebilir olmasının en güzel yanlarından biri, bu işlevselliğin kolayca eklenebilmesidir.
fikovnik

3
kabul. Bunu destekleyen bir editörde olsam da olmasam da, tarif ettiğiniz gibi sık sık satırları yukarı ve aşağı kaydırmak istiyorum. Ya da bu konuda, kod üzerinde çalışıp çalışmadığım. Word bunu (paragraf bazında) Alt + Shift + Yukarı ve Aşağı ile destekliyor ve bunu elimden geldiğince editörlerimde eşleştiriyorum.
harpo

6
@Drew ve Jrockway: Bence daha azına razı olmak pek de zor değil. Hareket ettirmek, onları hareket ettirmek istediğinizde kill / yankk'tan daha hızlıdır. Tabii org-modu da bir nedenden ötürü uyguladı: aslında bir satırı taşımak istediğiniz birçok durum vardır, yanlış yerleştirilmiş bir ifadeyi bir blok kapsamı içine / dışına taşımak birdir, ifade sırasını değiştirir, belge sırasını değiştirir (bkz. modu), .. Tutulma sırasında pek çok insan kullanıyor. Kullanmadığınız şeyleri genellikle kaçırmazsınız, ancak hareket eden çizgilerin faydası birçok programcı için bir gerçektir
Peter

2
Bu, yeniden sıralamak isteyebileceğiniz commit listelerini içeren git-rebase dosyalarını düzenlerken kullanışlıdır.
Ken Williams

Yanıtlar:


47

Bir çizgi, bağlı transpoze hatları kullanılarak taşınabilir C-x C-t. Yine de bölgeler hakkında Dunno.

Bağlamaları değiştirmeniz gerekmesi dışında, istediğiniz şeyi yapan bu elisp parçacığını buldum .

(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-\S-up] 'move-text-up)
(global-set-key [\M-\S-down] 'move-text-down)

Snippet için teşekkürler. Bu tam olarak aradığım şey!
fikovnik

Hem bu çözümde hem de @sanityinc tarafından gönderilen neredeyse aynı çözümde küçük bir sorun var: Bir bölgeyi yukarı ve / veya aşağı taşımak için tanımlanmış kısayolu kullanırsam, hemen geri almak için kısayolu kullanın (varsayılan olarak C-_), bölge kaybolur ve "Bölgede Geri Al!" mesajı görüntülenir. yankı alanında görüntülenir. Başka bir geri alma komutu, "Bölge için başka geri alma bilgisi yok" mesajını verir. Ancak, imleci hareket ettirirsem, ardından geri al komutu verirsem, geri alma işlemi yeniden çalışmaya başlar. Nispeten küçük bir rahatsızlık, ancak diğer tüm Emacs komutları bir numaraya başvurulmadan hemen geri alınabilir.
Teemu Leisti

1
Bunu yapmanın tam olarak doğru yolu bu. Emacs'teki varsayılan transpoze satırı doğru işlevsellik DEĞİLDİR çünkü imleç, transpoze işleminden sonra bir sonraki satıra hareket ederek adım adım tekrar etmeyi zorlaştırır.
mithicalcoder

51

Güncelleme: Aşağıdaki kodu almak için move-textpaketi Marmalade veya MELPA'dan yükleyin .

Hem bölgelerde hem de ayrı hatlarda çalışan kullandığım şey:

(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
    (let ((column (current-column)))
      (beginning-of-line)
      (when (or (> arg 0) (not (bobp)))
        (forward-line)
        (when (or (< arg 0) (not (eobp)))
          (transpose-lines arg)
          (when (and (eval-when-compile
                       '(and (>= emacs-major-version 24)
                             (>= emacs-minor-version 3)))
                     (< arg 0))
            (forward-line -1)))
        (forward-line -1))
      (move-to-column column t)))))

(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-S-up] 'move-text-up)
(global-set-key [M-S-down] 'move-text-down)

1
Bunu sizin için EmacsWiki'ye ekledim, burada: emacswiki.org/emacs/MoveText
ocodo

Teşekkürler! Sanırım kod zaten oradaydı ( emacswiki.org/emacs/basic-edit-toolkit.el ) ama bu yeni sayfa insanların bulması için daha kolay olacak.
sanityinc

Ahh, harika, bunu daha önce görmemiştim, görünüşe göre temel-düzenleme-araç takımı bir temizleme gerektirebilir.
ocodo

1
@mcb Evet, herhangi bir ELPA paketi el-get aracılığıyla kurulabilir. (Bu günlerde el-get yazarının bile package.el'e doğru ilerlediğini unutmayın.) Tam satırları seçmek için, mevcut satırı hızlıca seçen veya mevcut bölgeyi tam satırları içerecek şekilde genişleten ayrı bir işlev yazmanızı öneririm. Sonra bu işlevi hareket metni işlevlerinden önce çağırın.
sanityinc

1
@sanityinc Bunun için teşekkürler. İlk kullandığımda mini bir Emacs 'O' içtim. İyi şeyler!
JS.

31

Denemelisin drag-stuff!

Tam olarak eclipse Alt+ Up/ gibi Downtek hatlar için ve ayrıca seçilen bölge hatları için çalışır!

Buna ek olarak, kelimeleri Alt+ Left/ ile taşımanıza izin verir. Right
Tam olarak aradığınız şey budur! Ve ELPA depolarından bile edinilebilir !

Diğer çözümler benim için hiç işe yaramadı. Bazıları buggydi (sıralarını değiştirirken hatları aktarıyorlar, wtf?) Ve bazıları tam olarak seçilmiş bölgeyi hareket ettiriyor, hatların seçilmemiş kısımlarını konumlarında bırakıyorlardı. Ama drag-stuffaynen tutulmadaki gibi çalışıyor!

Ve daha fazlası! Bir bölge seçmeyi ve Alt+ Left/ kullanmayı deneyebilirsiniz Right! Bu, seçilen bölgeyi bir karakter sola veya sağa transpoze eder. İnanılmaz!

Global olarak etkinleştirmek için şunu çalıştırın:

(drag-stuff-global-mode)

Varsayılan emacs tuş eşlemesini geçersiz kıldığı için gerçekten sol ve sağ hareketin isteğe bağlı olması gerekir.
ocodo

@Slomojo belki! Neden bunu emacswiki'de önermiyorsun? :)
Aleks-Daniel Jakimenko-A.

1
Bunu kullanıyordum, şimdi smart-shift kullanıyorum. Yatay hareket için DWIM olmasını seviyorum.
jpkotta

1
(drag-stuff-define-keys)Anahtar bağlamaları çalışmaya başlamadan önce init dosyasındaki ihtiyaçlar . Bu, bu github'da
agent18

11

Satırları yukarı / aşağı hareket ettirmek için birkaç etkileşimli işlev yazdım:

;; move line up
(defun move-line-up ()
  (interactive)
  (transpose-lines 1)
  (previous-line 2))

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

;; move line down
(defun move-line-down ()
  (interactive)
  (next-line 1)
  (transpose-lines 1)
  (previous-line 1))

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

Tuş atamaları IntelliJ IDEA stilidir, ancak istediğiniz her şeyi kullanabilirsiniz. Muhtemelen bölgelerde de işleyen bazı işlevleri uygulamalıyım.


5

İşte benim pasajım mevcut satırı veya aktif bölge tarafından yayılan çizgileri hareket ettirmek için. İmleç konumuna ve vurgulanan bölgeye saygı duyar. Ve bölge, çizgi sınırlarında başlamadığında / bitmediğinde satırları kırmayacaktır. (Tutulmadan esinlenmiştir; tutulma yolunu 'transpoze çizgilerinden' daha uygun buldum.)

;; move the line(s) spanned by the active region up/down (line transposing)
;; {{{
(defun move-lines (n)
  (let ((beg) (end) (keep))
    (if mark-active 
        (save-excursion
          (setq keep t)
          (setq beg (region-beginning)
                end (region-end))
          (goto-char beg)
          (setq beg (line-beginning-position))
          (goto-char end)
          (setq end (line-beginning-position 2)))
      (setq beg (line-beginning-position)
            end (line-beginning-position 2)))
    (let ((offset (if (and (mark t) 
                           (and (>= (mark t) beg)
                                (< (mark t) end)))
                      (- (point) (mark t))))
          (rewind (- end (point))))
      (goto-char (if (< n 0) beg end))
      (forward-line n)
      (insert (delete-and-extract-region beg end))
      (backward-char rewind)
      (if offset (set-mark (- (point) offset))))
    (if keep
        (setq mark-active t
              deactivate-mark nil))))

(defun move-lines-up (n)
  "move the line(s) spanned by the active region up by N lines."
  (interactive "*p")
  (move-lines (- (or n 1))))

(defun move-lines-down (n)
  "move the line(s) spanned by the active region down by N lines."
  (interactive "*p")
  (move-lines (or n 1)))

1
Benim için hareket-metin paketi bozuldu. Çözümünüz benim sistemimde mükemmel çalışıyor. Bunun için teşekkürler!
Rune Kaagaard


1

Yerleşik yok. Transpoze satırları (Cx Ct) kullanabilirsiniz, ancak tekrar tekrar kullanamazsınız. Http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/ adresindeki işlevlere bakın .

Bunu bölgelere uyarlamak da kolay olmalı.


1
Btw, bağlantılı parçacığı kullanmaya karar verirseniz, let ifadesini (let ((col (current-column)) (line-move-visual nil)) olarak değiştirmek isteyebilirsiniz, aksi takdirde sarılmış satırlarla komik davranışlar elde edersiniz .
Leo Alekseyev

1

transpose-paragraphFonksiyon sana yardım edebilir.

Emacs kılavuzundaki transpoze bölümüne de göz atmak isteyebilirsiniz . Esasen:

C-t
Transpose two characters (transpose-chars).
M-t
Transpose two words (transpose-words).
C-M-t
Transpose two balanced expressions (transpose-sexps).
C-x C-t
Transpose two lines (transpose-lines).

0

Bunun için smart-shift paketini (Melpa'da) kullanıyorum. Varsayılan olarak, C-C <arrow>bir çizgiyi veya bölgeyi hareket ettirmek için yeniden bağlanır . Bir majör moda özgü miktarda yatay olarak hareket eder (örn. C-temel-ofset veya python-indent-offset). Bölgeler üzerinde de çalışır.

;; binds C-C <arrows>
(when (require 'smart-shift nil 'noerror)
  (global-smart-shift-mode 1))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.