Skip to content

Instantly share code, notes, and snippets.

@xiongtx
Last active May 12, 2025 18:33
Show Gist options
  • Save xiongtx/165ff287f9b44ddefb19ede05d35257f to your computer and use it in GitHub Desktop.
Save xiongtx/165ff287f9b44ddefb19ede05d35257f to your computer and use it in GitHub Desktop.
Sort INI file
(require 'cl-lib)
(require 'subr-x)
(defun *-ini-sort ()
"Sort an INI buffer by sections and properties.
Combines repeated sections. E.g.
[b]
b1=1
b3=3
[b]
b2=2
becomes
[b]
b1=1
b2=2
b3=3
Does NOT keep comments together with first property below them
For more on INI config files, see `conf-windows-mode'."
(interactive)
(goto-char (point-min))
(flush-lines "^\\s-*$" (point-min) (point-max))
(let ((ht (make-hash-table :test #'equal)))
(cl-flet ((find-section () (when (search-forward-regexp "\\[.+?\\]" nil t)
(match-string-no-properties 0))))
(let ((section (find-section)))
(while (not (null section))
(let* ((beg (min (1+ (match-end 0)) (point-max)))
(next-section (find-section))
(end (if next-section (1- (match-beginning 0)) (point-max))))
(sort-lines nil beg end)
(let ((props (buffer-substring-no-properties beg end)))
(when (not (string-empty-p props))
(when-let ((existing-properties (gethash section ht)))
(setq props (with-temp-buffer
(insert existing-properties "\n")
(insert props)
(sort-lines nil (point-min) (point-max))
(buffer-string))))
(puthash section props ht)))
(setq section next-section)))))
(erase-buffer)
(cl-loop for k in (sort (hash-table-keys ht) #'string<)
for v = (gethash k ht)
do (progn
(insert k "\n")
(insert v "\n\n")))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment