3

I wrote a rather clunky elisp function to sort the SYM VAL args in a setq expression alphabetically by SYM. For example:

(setq c "blah"              (setq a 9
      b '(more stuff)  -->        b '(more stuff)
      a 9)                        c "blah")

After reading about sort-subr, I thought I might be able to build a cleaner implementation. I thought I had it, but something's not right. What am I doing wrong here?

(defun sort-setq ()
  (interactive)
  (save-excursion
    (save-restriction
      (let ((sort-end (progn (end-of-defun)
                             (backward-char)
                             (point-marker)))
            (sort-beg (progn (beginning-of-defun)
                             (re-search-forward "[ \\t]*(" (point-at-eol))
                             (forward-sexp)
                             (re-search-forward "\\<" (point-at-eol))
                             (point-marker))))
        (narrow-to-region (1- sort-beg) (1+ sort-end))
        (sort-subr nil #'sort-setq-next-record #'sort-setq-end-record)))))

(defun sort-setq-next-record ()
  (condition-case nil
      (progn
        (forward-sexp 3)
        (backward-sexp))
    ('scan-error (end-of-buffer))))

(defun sort-setq-end-record ()
  (condition-case nil
      (forward-sexp 2)
    ('scan-error (end-of-buffer))))

It seems to work for the 3-pair example above, but if I start adding more pairs it fails to sort them all.

2
  • 2
    (I wonder why you want to do this.)
    – Drew
    May 25, 2017 at 14:06
  • @Drew It's partly just me messing around and getting familiar with elisp, but also there are some groups of variables in my init file that are "miscellaneous" (I can't find any other way to organize them that makes sense) and it makes it easier to find them visually if I keep them alphabetized.
    – ivan
    May 25, 2017 at 20:40

3 Answers 3

1

If each SYM VAL is one the same line, you can simply use M-x sort-lines. For your example,

(setq c "blah"
      b '(more stuff)
      a 9)

-->

(setq
 c "blah"
 b '(more stuff)
 a 9
 ) 

M-x sort-lines -->

(setq
 a 9
 b '(more stuff)
 c "blah"
 )

-->

(setq a 9
      b '(more stuff)
      c "blah")
0

In sort-setq-next-record you where jumping to far. Instead of using (forward-sexp 3) you should use (forward-sexp 1).

Here is the new function:

(defun sort-setq-next-record ()
    (condition-case nil
            (progn
                (forward-sexp 1)
                (backward-sexp))
        ('scan-error (end-of-buffer))))
0

Here is my attempt

(defun sort-setq (beg end)
  (interactive "*r")
  (save-restriction
    (narrow-to-region beg end)
    (goto-char (point-min))
    (let ((nextrecfun (lambda () (skip-chars-forward " \n")))
          (endrecfun  (lambda () (forward-sexp 2))))
      (sort-subr nil nextrecfun endrecfun))))

Note that you need to select just SYM-VAL pairs to the Region, e.g., to sort (setq b 2 a 1), select b 2 a 1.

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.