From 993853531aebb303870d6ff1ba7db2007d464b63 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 5 Jun 2022 09:52:09 +0300 Subject: [PATCH] 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. --- lisp/ls-lisp.el | 18 +++++++++++++----- test/lisp/ls-lisp-tests.el | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/lisp/ls-lisp.el b/lisp/ls-lisp.el index 33dd98ef8d2..6d1f449568a 100644 --- a/lisp/ls-lisp.el +++ b/lisp/ls-lisp.el @@ -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)))) diff --git a/test/lisp/ls-lisp-tests.el b/test/lisp/ls-lisp-tests.el index 3e23fc74540..39843defc2e 100644 --- a/test/lisp/ls-lisp-tests.el +++ b/test/lisp/ls-lisp-tests.el @@ -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 -- 2.39.2