Subject: Re: bug#31240: 26.1; mouse-save-then-kill does not kill rectangles

From: martin rudalics <[email-masked]>
Date: Tue, 09 Oct 2018 09:43:33 +0200

> Martin, I didn't manage to understand the condition you are testing:
 >
 > (and (>= start point-to-paste)
 >       (<= point-to-paste (+ start (car size))))))))

Obviously so.  It should be

(and (<= start point-to-paste)
      (<= point-to-paste (+ start (car size))))))))

I attach a diff of this very chunk against the original trunk version
I have here.  Sorry for my sloppiness.

The idea is to not set drag-but-negligible when point-to-paste is (1)
on the first line of the original region and (2) before its start or
after its end.  To elaborate:

If point-to-paste is on the first line of the original region in
between its start and end, we would try to replace the text by itself
on this and all subsequent lines which is just as silly as replacing a
contiguous region with itself.  So set drag-but-negligible in such a
case.

If point-to-paste is not on the first line of the original region but
the region to insert intersects with the original region, then killing
the original region after inserting the copy might get me some pretty
unintelligible result.  So set drag-but-negligible in that case as
well.

But moving the rectangle strictly to the left or the right on the same
lines it originally occupied seems to work here.  So I would not set
drag-but-negligible in that case.

 > If the first condition is true, the second will also be true (if
 > point-to-paste is smaller than start, point-to-paste will also be
 > smaller than start plus a positive integer).

Indeed.

 >>From what I understand, these two explanations refer to the same
 > thing: it is better to have at all times the dragged region somewhere
 > in the buffer (even when undoing the drag operation). It would be best
 > to keep this behaviour in future versions of
 > mouse-drag-and-drop-region.

This looks like an invariant we could try to preserve.  But I only
tried to guess the rationale of the original design for moving a
contiguous region.

Note that I have never written or used rectangle code.  AFAICT
'insert-rectangle' inserts spaces (via 'move-to-column') when the
target line is too short.  And these insertions can make the result of
a rectangle move look bad when the deletion is done after the copying.
Is that interpretation correct?  Does it always look intelligible when
the deletion is done before the copying?

 > I'll check if I can come up with a better solution that best fits the
 > points that have been discussed above. If I can't, I'll check how
 > complex it would be to implement this special case at the end.

IIUC the code of rect.el nowhere provides an operation that kills a
rectangle and reinserts it in one and the same step not to mention the
possibility that these operations take place in an overlapping area of
one and the same buffer.  So I think that you are in uncharted waters
here and hardly anyone will tell you what to do.

If worse comes to worst, we can always leave your patch as it is now.

martin
@@ -2500,12 +2520,24 @@ mouse-drag-and-drop-region
             ;; text will be inserted to inside of the original
             ;; region.
             (setq drag-but-negligible
-                  (and (eq (overlay-buffer mouse-drag-and-drop-overlay)
+                  (and (eq (overlay-buffer (car mouse-drag-and-drop-overlays))
                            buffer-to-paste)
-                       (<= (overlay-start mouse-drag-and-drop-overlay)
-                          point-to-paste)
-                       (<= point-to-paste
-                          (overlay-end mouse-drag-and-drop-overlay)))))
+                       (if region-noncontiguous
+                           ;; If the region is rectangular, check if the newly inserted
+                           ;; rectangular text would intersect the already selected
+                           ;; region. If it would, then set "drag-but-negligible" to t.
+                           (let ((size (cons region-width region-height)))
+                             (and (rectangle-intersect-p
+                                   (rectangle-position-as-coordinates start) size
+                                   (rectangle-position-as-coordinates point-to-paste) size)
+                                  (or (not (= (line-number-at-pos start)
+                                              (line-number-at-pos point-to-paste)))
+                                      (and (<= start point-to-paste)
+                                           (<= point-to-paste (+ start (car size)))))))
+                         (and (<= (overlay-start (car mouse-drag-and-drop-overlays))
+                                  point-to-paste)
+                              (<= point-to-paste
+                                  (overlay-end (car mouse-drag-and-drop-overlays))))))))
 
           ;; Show a tooltip.
           (if mouse-drag-and-drop-region-show-tooltip