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.
Drew
  • 75,699
  • 9
  • 109
  • 225
Brian Fitzpatrick
  • 2,265
  • 1
  • 17
  • 40
  • 1
    How about `randomize-region.el`?: https://www.mail-archive.com/gnu-emacs-sources@gnu.org/msg00034.html which is the accepted answer from this related thread: https://stackoverflow.com/questions/6172054/how-can-i-random-sort-lines-in-a-buffer – lawlist Jun 12 '19 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. – Brian Fitzpatrick Jun 12 '19 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"))))))`. – Brian Fitzpatrick Jun 12 '19 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/](https://nadiakvk.org/shuffle-paragraphs/) – Milly Texas spam Jan 08 '23 at 05:03

3 Answers3

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)
siery
  • 241
  • 2
  • 13
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))))
jagrg
  • 3,824
  • 4
  • 19
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))))))
clemera
  • 3,401
  • 13
  • 40