Search code examples
emacsorg-modeparagraphs

Emacs - switch paragraphs with each other


I'm looking for a solution which is already possible in Org-mode with headlines, example:

* HL1
* HL2 {press: Meta+arrowup}

=>

* HL2
* HL1

(1) I want to switch paragraphs like that. The idea is basically that I move the point somewhere {example: here []} in the middle of a paragraph, press {key+arrowdown} and the paragraph will be switched with the next one beneath.

(2) This would make it easier to restructure text while editing papers.

=> Paragraph (2) should be in front of paragraph (1) now. I am not sure if this is a trivial problem. It would be more suitable if it's not just a function like:

  • Mark paragraph P1
  • Copy
  • move point beneath P2
  • paste P1

A real switching of P1 and P2 wouldn't mess up spacings around the paragraphs.

Thanks,

Edit: Solution found:

1.easy:

(global-set-key (kbd "M-ü") 'transpose-paragraphs) ;; forward
(global-set-key (kbd "C-M-ü")
                (lambda () (interactive) (transpose-paragraphs -1)
      (backward-paragraph)
    )) ;; backwards

2.elaborated (found in ergoemacs-functions.el - currently only org-mode):

(defmacro ergoemacs-define-org-meta (direction &optional disable)
  "Defines org-mode meta-direction keys.
DIRECTION defines the `org-mode' and `ergoemacs-mode' direction.
DISABLE defines if the option should be disabled by default."
  `(progn
     (defcustom ,(intern (format "ergoemacs-use-ergoemacs-meta%s" direction)) ,(not disable)
       ,(format "Use ergoemacs-mode defined <M-%s>." direction)
       :type 'boolean
       :group 'ergoemacs-mode)
     (defun ,(intern (format "ergoemacs-org-meta%s" direction))  ()
       ,(format "Run `org-meta%s' in the proper context.
When `ergoemacs-use-ergoemacs-meta%s' is non-nil use what ergoemacs-mode defines for <M-%s>.
ARG is the prefix argument for either command." direction direction direction)
       (interactive)
       (cond
        ((or
          (not ,(intern (format "ergoemacs-use-ergoemacs-meta%s" direction)))
          (org-at-heading-p)
          (org-at-item-p)
          (org-at-table-p)
          (and (org-region-active-p)
               (save-excursion
                 (goto-char (region-beginning))
                 (org-at-item-p)))
          (org-with-limited-levels
           (or (org-at-heading-p)
               (and (org-region-active-p)
                    (save-excursion
                      (goto-char (region-beginning))
                      (org-at-heading-p))))))
         ;; (setq prefix-arg current-prefix-arg)
         ;; Send prefix to next function
         (call-interactively ',(intern (format "org-meta%s" direction))))
        (t
         ;; (setq prefix-arg current-prefix-arg)
         ;; Send prefix to next function
         (ergoemacs-lookup-key-and-run ,(format "<M-%s>" direction)))))))
(ergoemacs-define-org-meta "left")
(ergoemacs-define-org-meta "right")
(ergoemacs-define-org-meta "up" t)
(ergoemacs-define-org-meta "down" t)

please confirm working!


Solution

  • transpose-paragraphs

    transpose-paragraphs sounds like the function you want. It's interactive, so you can invoke it with M-x. If you find you need it a lot, consider binding it to a key (perhaps M-T?).

    Edit (summary of discussion following)

    User lpoik found that, on his/her system, transpose-paragraphs with a argument of -1 was not leaving point in the correct position (between the two paragraphs) for a subsequent repeat of the operation to move the paragraph up one more. The workaround arrived at is to move point using backward-paragraph afterwards:

    (defun my-transpose-paragraphs-backward ()
      (interactive "*")
      (transpose-paragraphs -1)
      (backward-paragraph))
    (global-set-key (kbd "C-M-ü") 'my-transpose-paragraphs-backward)
    

    I don't know whether this also works if you make my-transpose-paragraphs-backward accept a numeric argument:

    (defun my-transpose-paragraphs-backward (arg)
      (interactive "*p")
      (transpose-paragraphs (- arg))
      (backward-paragraph))