Fix sorting in ls-lisp.el under -v

* lisp/ls-lisp.el (ls-lisp-version-lessp): Handle correctly the
case where strings begin with numerical parts.  More faithful
implementation of the 'strverscmp' spec for fractional parts.
(Bug#55787)

* test/lisp/ls-lisp-tests.el (ls-lisp-test-bug55787): New test.
This commit is contained in:
Eli Zaretskii 2022-06-05 09:52:09 +03:00
parent e4725ab688
commit 993853531a
2 changed files with 52 additions and 5 deletions

View file

@ -621,14 +621,22 @@ in some standard C libraries does."
(sub2 (substring s2 ni2 e2))
;; "Fraction" is a numerical sequence with leading zeros.
(fr1 (string-match "\\`0+" sub1))
(fr2 (string-match "\\`0+" sub2)))
(efr1 (match-end 0))
(fr2 (string-match "\\`0+" sub2))
(efr2 (match-end 0)))
(cond
((and fr1 fr2) ; two fractions, the shortest wins
(setq val (- val (- (length sub1) (length sub2)))))
;; Two fractions: the longer one is less than the other,
;; but only if the "common prefix" is all-zeroes,
;; otherwise fall back on numerical comparison.
((and fr1 fr2)
(if (or (and (< efr1 (- e1 ni1)) (< efr2 (- e2 ni2))
(not (eq (aref sub1 efr1) (aref sub2 efr2))))
(= efr1 (- e1 ni1)) (= efr2 (- e2 ni2)))
(setq val (- val (- (length sub1) (length sub2))))))
(fr1 ; a fraction is always less than an integral
(setq val (- ni1)))
(setq val (- 0 ni1 1))) ; make sure val is non-zero
(fr2
(setq val ni2)))
(setq val (1+ ni2)))) ; make sure val is non-zero
(if (zerop val) ; fall back on numerical comparison
(setq val (- (string-to-number sub1)
(string-to-number sub2))))

View file

@ -93,5 +93,44 @@
(should (looking-back "[[:space:]]" (1- (point)))))
(when (buffer-live-p buf) (kill-buffer buf)))))
(ert-deftest ls-lisp-test-bug55787 ()
"Test proper sorting by version."
(let ((files1 (vector "34 klmn-300dpi.jpg"
"34 klmn-300dpi.png"
"054_xyz.jpg"
"054_xyz.png"
"91 opqrs.jpg"
"91 opqrs.png"
"0717-abcd.jpg"
"0717-abcd.png"
"1935 uv.jpg"
"1935 uv.png"
"FFFF_fghk.jpg"
"FFFF_fghk.png"
"hhhh.jpg"
"hhhh.png"))
(files2 (vector "01.0" "10" "010" "01.2")))
(should (equal (sort files1
(lambda (x y)
(ls-lisp-version-lessp x y)))
'["0717-abcd.jpg"
"0717-abcd.png"
"054_xyz.jpg"
"054_xyz.png"
"34 klmn-300dpi.jpg"
"34 klmn-300dpi.png"
"91 opqrs.jpg"
"91 opqrs.png"
"1935 uv.jpg"
"1935 uv.png"
"FFFF_fghk.jpg"
"FFFF_fghk.png"
"hhhh.jpg"
"hhhh.png"]))
(should (equal (sort files2
(lambda (x y)
(ls-lisp-version-lessp x y)))
'["01.0" "01.2" "010" "10"]))))
(provide 'ls-lisp-tests)
;;; ls-lisp-tests.el ends here