3

I'd like to be able to quickly "shuffle" the order in which all paragraphs in a region occur. Can this be easily accomplished in emacs?

For example, consider the following region.

Hello world.

This is the original second paragraph
and it contains two lines.

This is the original third paragraph and
it contains three
lines

Paragraph number four.

Running my desired command would result in a random reordering of these four paragraphs. The output might be something like

This is the original third paragraph and
it contains three
lines

Hello world.

Paragraph number four.

This is the original second paragraph
and it contains two lines.
4
  • 1
    How about randomize-region.el?: mail-archive.com/[email protected]/msg00034.html which is the accepted answer from this related thread: stackoverflow.com/questions/6172054/…
    – lawlist
    Commented Jun 12, 2019 at 18:41
  • @lawlist randomize-region.el is related, but doesn't solve the problem. randomize-region permutes all of the lines and doesn't respect paragraphs. I'm sure the code can be altered, but I'm not savvy enough to see how. Commented Jun 12, 2019 at 20:17
  • @lawlist Actually... maybe I am savvy enough. I think all I need is to change (insert (concat str "\n")))))) to (insert (concat str "\n\n")))))). Commented Jun 12, 2019 at 20:21
  • Yes, its true we can shuffle paragraphs by using this tool they provide reverse line shuffle, Sort Line Alphabetically, shuffle paragraphs that tool address is: https://nadiakvk.org/shuffle-paragraphs/ Commented Jan 8, 2023 at 5:03

3 Answers 3

1

Adapted from sort-paragraphs:

(defun sort-paragraphs-randomly (beg end)
  (interactive (if (use-region-p)
                   (list (region-beginning) (region-end))
                 (list (point-min) (point-max))))
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (goto-char (point-min))
      (sort-subr nil
                 (lambda ()
                   (while (and (not (eobp)) (looking-at paragraph-separate))
                     (forward-line 1)))
      'forward-paragraph
      nil nil 
      (lambda (_ _)
        (= (random 2) 0))))))
1

Edt. For short answer, look at @lawlist answer.

For explicit one, kinda. you may repeat the following sequence

(mark-paragraph)
(kill-region)
(backward-paragraph) || (forward-paragraph)
(yank)

while if in the leaf or root paragraph and there is no newline at the beginning and end do

(backward-paragraph) || (forward-paragraph)     ;; Respectively (leaf || root)
(newline)

Ow.. and if this happened to be the leaf then also do

(previous-line)
1

First create a list of paragraphs in the region. Then 1. shuffle the list, 2. delete the region, and 3. insert the shuffled list. The function below is a modified version of the shuffle-list function found here (thanks to lawlist for the link). Also, to get the correct spacing between paragraphs, you have to start with the cursor on the line above the first paragraph and end on the line below the last paragraph.

(defun shuffle (list)
  (let ((i (1- (length list))))
    (while (>= i 0)
      (let ((rand (random (1+ i)))
            (orig (nth i list)))
        (setcar (nthcdr i list) (nth rand list))
        (setcar (nthcdr rand list) orig)
        (setq i (1- i)))))
  list)

(defun shuffle-paragraphs (beg end)
  (interactive "r")
  (let* ((region (buffer-substring beg end))
         (list (split-string region org-element-paragraph-separate t))
         (shuffle (shuffle list)))
    (delete-region beg end)
    (cl-loop for par in shuffle
             do (insert par))))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.