72 lines
2.8 KiB
EmacsLisp
72 lines
2.8 KiB
EmacsLisp
;;; +lisp.el --- extra lisp functionality -*- lexical-binding: t -*-
|
|
|
|
;;; Code:
|
|
|
|
;;; Sort sexps in a region.
|
|
;; https://github.com/alphapapa/unpackaged.el
|
|
|
|
(defun +lisp-skip-whitespace ()
|
|
(while (looking-at (rx (1+ (or space "\n"))))
|
|
(goto-char (match-end 0))))
|
|
|
|
(defun +lisp-skip-both ()
|
|
(while (cond ((or (nth 4 (syntax-ppss))
|
|
(ignore-errors
|
|
(save-excursion
|
|
(forward-char 1)
|
|
(nth 4 (syntax-ppss)))))
|
|
(forward-line 1))
|
|
((looking-at (rx (1+ (or space "\n"))))
|
|
(goto-char (match-end 0))))))
|
|
|
|
(defun +lisp-sort-sexps (beg end &optional key-fn sort-fn)
|
|
"Sort sexps between BEG and END.
|
|
Comments stay with the code below.
|
|
|
|
Optional argument KEY-FN will determine where in each sexp to
|
|
start sorting. e.g. (lambda (sexp) (symbol-name (car sexp)))
|
|
|
|
Optional argument SORT-FN will determine how to sort two sexps'
|
|
strings. It's passed to `sort'. By default, it sorts the sexps
|
|
with `string<' starting with the key determined by KEY-FN."
|
|
(interactive "r")
|
|
(save-excursion
|
|
(save-restriction
|
|
(narrow-to-region beg end)
|
|
(goto-char beg)
|
|
(+lisp-skip-both)
|
|
(cl-destructuring-bind (sexps markers)
|
|
(cl-loop do (+lisp-skip-whitespace)
|
|
for start = (point-marker)
|
|
for sexp = (ignore-errors
|
|
(read (current-buffer)))
|
|
for end = (point-marker)
|
|
while sexp
|
|
;; Collect the real string, then one used for sorting.
|
|
collect (cons (buffer-substring (marker-position start)
|
|
(marker-position end))
|
|
(save-excursion
|
|
(goto-char (marker-position start))
|
|
(+lisp-skip-both)
|
|
(if key-fn
|
|
(funcall key-fn sexp)
|
|
(buffer-substring
|
|
(point)
|
|
(marker-position end)))))
|
|
into sexps
|
|
collect (cons start end)
|
|
into markers
|
|
finally return (list sexps markers))
|
|
(setq sexps (sort sexps (if sort-fn sort-fn
|
|
(lambda (a b)
|
|
(string< (cdr a) (cdr b))))))
|
|
(cl-loop for (real . sort) in sexps
|
|
for (start . end) in markers
|
|
do (progn
|
|
(goto-char (marker-position start))
|
|
(insert-before-markers real)
|
|
(delete-region (point) (marker-position end))))))))
|
|
|
|
(provide '+lisp)
|
|
;;; +lisp.el ends here
|