Subject: 25.1.50; dired-mark: Not remark a marked file

From: Tino Calancha <[email-masked]>
Date: Thu, 3 Mar 2016 19:09:39 +0900 (JST)

* lisp/dired.el (dired-mark-files-in-region,dired-mark):
A marked file can be remarked just:
1) To mark for deletion.
2) To unmark it, that is, the mark changes to `?\\s'.
3) If its marked for deletion, a different mark can be assigned.

The purpose of this changes is to prevent changing accidentally
the mark of a file. Current code allow to change marks on files very
easily.

Marking many files using several markers may need some time, with
some regexp gimnastics. Its a pity if someone accidentaly change
one of the marks. For instance, using `dired-mark-files-in-region',
the last/first file in the region could be included unintentionally
changing the mark of one file.

I'm not sure if allow 1) or to ban it.
I'm not sure if someone find this thread useful either :-)

In GNU Emacs 25.1.50.1 (x86_64-pc-linux-gnu, GTK+ Version 2.24.29)
  of 2016-03-03 built on calancha-pc
Repository revision: 887f6126c5ce9084f93083765ac026ca6b28175c

diff --git a/lisp/dired.el b/lisp/dired.el
index 6c7445c..057e533 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -3215,20 +3215,29 @@ dired-file-marker
 	       (following-char))))))
 
 (defun dired-mark-files-in-region (start end)
+  "Mark all files inside the region in the Dired buffer.
+The mark MARK of a file already marked only changes if:
+1) MARK equals to `dired-del-marker'.
+2) `dired-marked-char' equals to `?\\s' or `dired-del-marker'."
+
   (let ((inhibit-read-only t))
     (if (> start end)
-	(error "start > end"))
-    (goto-char start)			; assumed at beginning of line
+    (error "start > end"))
+    (goto-char start)           ; assumed at beginning of line
     (while (< (point) end)
       ;; Skip subdir line and following garbage like the `total' line:
       (while (and (< (point) end) (dired-between-files))
-	(forward-line 1))
-      (if (and (not (looking-at-p dired-re-dot))
-	       (dired-get-filename nil t))
-	  (progn
-	    (delete-char 1)
-	    (insert dired-marker-char)))
-      (forward-line 1))))
+    (forward-line 1))
+      (when (and (not (looking-at-p dired-re-dot))
+                 (or (looking-at-p "^ ")
+                     (looking-at-p (concat "^" (regexp-quote (char-to-string dired-del-marker))))
+                     (eq dired-marker-char ?\s)
+                     (eq dired-marker-char dired-del-marker))
+                 (dired-get-filename nil t))
+        (delete-char 1)
+        (insert dired-marker-char))
+      (forward-line 1))
+    (deactivate-mark 'force)))
 
 (defun dired-mark (arg &optional interactive)
   "Mark the file at point in the Dired buffer.
@@ -3237,6 +3246,10 @@ dired-mark
 
 If on a subdir headerline, mark all its files except `.' and `..'.
 
+The mark MARK of a file already marked only changes if:
+1) MARK equals to `dired-del-marker'.
+2) `dired-marked-char' equals to `?\\s' or `dired-del-marker'.
+
 Use \\[dired-unmark-all-files] to remove all marks
 and \\[dired-unmark] on a subdir to remove the marks in
 this subdir."
@@ -3246,10 +3259,10 @@ dired-mark
    ((and interactive (use-region-p))
     (save-excursion
       (let ((beg (region-beginning))
-	    (end (region-end)))
-	(dired-mark-files-in-region
-	 (progn (goto-char beg) (line-beginning-position))
-	 (progn (goto-char end) (line-beginning-position))))))
+        (end (region-end)))
+    (dired-mark-files-in-region
+     (progn (goto-char beg) (line-beginning-position))
+     (progn (goto-char end) (line-beginning-position))))))
    ;; Mark subdir files from the subdir headerline.
    ((dired-get-subdir)
     (save-excursion (dired-mark-subdir-files)))
@@ -3258,7 +3271,11 @@ dired-mark
     (let ((inhibit-read-only t))
       (dired-repeat-over-lines
        (prefix-numeric-value arg)
-       (function (lambda () (delete-char 1) (insert dired-marker-char))))))))
+       (function (lambda () (when (or (looking-at-p "^ ")
+                                      (looking-at-p (concat "^" (regexp-quote (char-to-string dired-del-marker))))
+                                      (eq dired-marker-char ?\s)
+                                      (eq dired-marker-char dired-del-marker))
+                              (delete-char 1) (insert dired-marker-char)))))))))
 
 (defun dired-unmark (arg &optional interactive)
   "Unmark the file at point in the Dired buffer.