2

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
    (I wonder why you want to do this.) – Drew May 25 '17 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 '17 at 20:40
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, privacy policy and cookie policy

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