
(defun d-dired-updown--unmark-all ()
  (save-excursion
    (goto-char (point-min))
    (dired-unmark 1)))

(defun d-dired-updown--mark-all ()
  (save-excursion
    (goto-char (point-min))
    (dired-mark 1)))

(defun d-dired-updown--mark-files (list)
  (let ((ptr list)
        (m   nil))
    (while ptr
      (setq m (concat "^" (regexp-quote (car ptr)) "$"))
      ;;(message "marking %s" m)
      (dired-mark-files-regexp m)
      (setq ptr (cdr ptr)))))

(defun d-dired-down ()
  (interactive)
  (assert (not (string-match (regexp-quote "\\(") d-dired-updown--pre-regexp)))
  (assert (not (string-match (regexp-quote "\\(") d-dired-updown--post-regexp)))
  (let* ((list    (sort (dired-get-marked-files) 'string<))
         (ptr     list)
         (newlist nil))
    (while ptr
      (let ((filename (car ptr)))
        (when (string-match (concat d-dired-updown--pre-regexp "\\([0-9][0-9]\\)") filename)
          (let ((pre    (substring filename 0 (match-beginning 1)))
                (number (read (substring filename (match-beginning 1) (match-end 1))))
                (post   (substring filename (match-end 1)))
                (newname nil))
            (assert (>= number 1))
            (decf number)
            (setq number (format "%02d" number))
            (setq newname (concat pre number post))
            (assert (not (file-exists-p newname)))
            (rename-file filename newname)
            (setq newlist (cons (file-name-nondirectory newname) newlist))
            ;;(d-beeps "oldname=%s, newname=%s" filename newname)
            )))
      (setq ptr (cdr ptr)))
    ;;(debug)
    (d-dired-updown--unmark-all)
    (revert-buffer)
    (d-dired-updown--mark-files newlist)))

(defun d-dired-up ()
  (interactive)
  (assert (not (string-match (regexp-quote "\\(") d-dired-updown--pre-regexp)))
  (assert (not (string-match (regexp-quote "\\(") d-dired-updown--post-regexp)))
  (let* ((list    (nreverse (sort (dired-get-marked-files) 'string<)))
         (ptr     list)
         (newlist nil))
    (while ptr
      (let ((filename (car ptr)))
        (when (string-match (concat d-dired-updown--pre-regexp "\\([0-9][0-9]\\)") filename)
          (let ((pre    (substring filename 0 (match-beginning 1)))
                (number (read (substring filename (match-beginning 1) (match-end 1))))
                (post   (substring filename (match-end 1)))
                (newname nil))
            (assert (<= number 99))
            (incf number)
            (setq number (format "%02d" number))
            (setq newname (concat pre number post))
            (assert (not (file-exists-p newname)))
            (rename-file filename newname)
            (setq newlist (cons (file-name-nondirectory newname) newlist))
            ;;(d-beeps "oldname=%s, newname=%s" filename newname)
            )))
      (setq ptr (cdr ptr)))
    (d-dired-updown--unmark-all)
    (revert-buffer)
    (d-dired-updown--mark-files newlist)))

;;;
;;; NOTE: d-dired-updown--pre-regexp could be /
;;;

(progn
  (setq d-dired-updown--pre-regexp  (regexp-quote "Track"))
  (setq d-dired-updown--post-regexp "\\.flac$")
  )

(provide 'd-dired-updown)

