unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* delete lines with overlays [workaround to diff mode]
@ 2023-08-29  5:32 Samuel Wales
  2023-08-29 17:19 ` Marcin Borkowski
  2023-08-29 22:03 ` Jens Schmidt via Users list for the GNU Emacs text editor
  0 siblings, 2 replies; 7+ messages in thread
From: Samuel Wales @ 2023-08-29  5:32 UTC (permalink / raw)
  To: help-gnu-emacs

i have been struggling with this and working on this description for
many years.  hoping for a command that can delete all lines starting
with "-" that contain overlays.


rationale:

diff mode does not distinguish DELETED lines in A (i.e. -)
from lines in A that have more text ADDED somewhere in their
B version (i.e. +).

thus, those lines are ambiguous.  they might 1) have been
accidentally deleted, or they might 2) merely be the shorter
version of the line that has text in the other polarity.
the converse is also true if you swap A and B.

the result is that i cannot tell if lines are missing in A
by looking only at the - lines; i have to search through all
of the + lines also, in order to determine whehter, instead,
text was added.

this applies to A lines that have no overlays.  if they have
an overlay for TEXT, then i know that it is not a deleted
line.  also, sometimes a refilled paragraph or so will have
overlays on the - at BOL and presumably are not deleted.


i filed a bug on this, to request e.g. a marker like ^ or
something to show in any diff mode - or + line where text is
exists in the opposite polarity (e.g. + if it is a - line
or - if it is a + line).

  bug#61396: diff mode could distinguish changed from deleted lines

here is an example from that bug report:

[edit: the caret is an indicator here, not part of the
example text.]

===
so basically,

  -this is a line that ^looks deleted, but it is changed
...
  +this is a line that REALLY looks deleted, but it is changed

what is not indicated for the user is at the ^.  i woul dlike it if
diff mode if possible showed that text was deleted there.

this allows you to look at only the - line and know that it is not a
deleted line, possibly even mistakenly, but rather is part of a cange
set, namely it and the + version of hte same line.  this would reduce
user confusion considerably.
===


i do not know if this is fixable in diff mode.  however, i
thought of a so-so but still useful workaround.

the workaround would be to have a command that can delete
lines with overlays in A (i.e. -).  then the REMAINING lines
are the ambiguous lines and can be inspected without
distraction.  they are either deleted or got changed.

the problem is that i don't know how to program such a
command.  i guess it would take a c-u to delete + lines with
overlays instead of - lines with overlays.


(a better solution is as follows, but i assme it is too
difficult.  it sure would be for me.

that is a command that internally removes overlays for
purposes of comparison and searches for "+" lines that are
otherwise equal to the "-" line.  if such a dual line is
found, then deletes those "-" lines.)



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: delete lines with overlays [workaround to diff mode]
  2023-08-29  5:32 delete lines with overlays [workaround to diff mode] Samuel Wales
@ 2023-08-29 17:19 ` Marcin Borkowski
  2023-08-29 22:03 ` Jens Schmidt via Users list for the GNU Emacs text editor
  1 sibling, 0 replies; 7+ messages in thread
From: Marcin Borkowski @ 2023-08-29 17:19 UTC (permalink / raw)
  To: Samuel Wales; +Cc: help-gnu-emacs


On 2023-08-29, at 07:32, Samuel Wales <samologist@gmail.com> wrote:

> the workaround would be to have a command that can delete
> lines with overlays in A (i.e. -).  then the REMAINING lines
> are the ambiguous lines and can be inspected without
> distraction.  they are either deleted or got changed.
>
> the problem is that i don't know how to program such a
> command.  i guess it would take a c-u to delete + lines with
> overlays instead of - lines with overlays.

It will indeed be a bit of work to code this, but not too hard.  I would
start with `(overlays-in (point-min) (point-max))' to get all the
overlays in the buffer, then iterate over that list with `mapc' and at
each overlay check if the current line begins with `-' or `+' and delete
it if so.

If that is too difficult for you, and nobody else steps in, I can help
you with that.  I'm not sure, though, if it will really help you.

What I would probably do instead would be to iterate over, say, all
"deleted" lines, and for every such line try to find an "added" line
which is equal to the "deleted" line plus some string (or strings?)
somewhere.  The latter seems to be a special case of finding a longest
common subsequence (see
https://en.wikipedia.org/wiki/Longest_common_subsequence), though I'm
not good enough in algorithms to know for sure if this is the right
approach.

Hth,

-- 
Marcin Borkowski
http://mbork.pl



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: delete lines with overlays [workaround to diff mode]
  2023-08-29  5:32 delete lines with overlays [workaround to diff mode] Samuel Wales
  2023-08-29 17:19 ` Marcin Borkowski
@ 2023-08-29 22:03 ` Jens Schmidt via Users list for the GNU Emacs text editor
  2023-08-30  5:07   ` Samuel Wales
  1 sibling, 1 reply; 7+ messages in thread
From: Jens Schmidt via Users list for the GNU Emacs text editor @ 2023-08-29 22:03 UTC (permalink / raw)
  To: help-gnu-emacs

On what Emacs version exactly are you?  Probably a minor patch on
function `diff--refine-hunk' could do what you want...





^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: delete lines with overlays [workaround to diff mode]
  2023-08-29 22:03 ` Jens Schmidt via Users list for the GNU Emacs text editor
@ 2023-08-30  5:07   ` Samuel Wales
  2023-08-30 11:21     ` Jens Schmidt via Users list for the GNU Emacs text editor
                       ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Samuel Wales @ 2023-08-30  5:07 UTC (permalink / raw)
  To: Jens Schmidt; +Cc: help-gnu-emacs

currently 27

On 8/29/23, Jens Schmidt <jschmidt4gnu@vodafonemail.de> wrote:
> On what Emacs version exactly are you?  Probably a minor patch on
> function `diff--refine-hunk' could do what you want...
>
>


-- 
The Kafka Pandemic

A blog about science, health, human rights, and misopathy:
https://thekafkapandemic.blogspot.com



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: delete lines with overlays [workaround to diff mode]
  2023-08-30  5:07   ` Samuel Wales
@ 2023-08-30 11:21     ` Jens Schmidt via Users list for the GNU Emacs text editor
  2023-08-30 11:30     ` Jens Schmidt via Users list for the GNU Emacs text editor
  2023-08-30 16:25     ` Jens Schmidt
  2 siblings, 0 replies; 7+ messages in thread
From: Jens Schmidt via Users list for the GNU Emacs text editor @ 2023-08-30 11:21 UTC (permalink / raw)
  To: help-gnu-emacs; +Cc: help-gnu-emacs

On 2023-08-30  07:07, Samuel Wales wrote:

> currently 27

How convenient ... having that around here as well.

As Dmitry has noted in your bug#61396, the diff refinement machinery
probably already has what you are looking for, but without
ready-made switches to turn it on.

You might want to try whether the following modified function
`diff--refine-hunk' does what you need.  Not sure how proficient
you are in Elisp hacking, so I provide full instructions to get
it activated.

1. Start Emacs as "emacs -Q" to get reproducible results.  (This
   is required only for the initial tests.)
2. M-x load-library diff-mode RET to load the original library
3. Paste below function definition into *scratch* and press C-M-x
   with point in or after the definition to evaluate the modified
   function definition.
4. Then check whether the result matches your expectation.

The only lines I modified in the function are these:

-              (smerge-refine-regions beg-del beg-add beg-add end-add
-                                     nil #'diff-refine-preproc props-r props-a)))))

I replaced that by:

+              (smerge-refine-regions beg-del beg-add beg-add end-add
+                                     props-c nil nil nil)))))

Comments:

- `props-c' is responsible for highlighting changes in yellow
  (compared to `props-r' for removals, `props-a' for additions)
- Function `diff-refine-preproc' referenced in the original function
  strips off the leading '-' and '+' chars from the diffs to avoid
  getting them highlighted as refined diffs.
  When replacing the reference to that function by nil, these leading
  chars get processed by the refinement as well and are highlighted as
  changes if needed.  Hopefully, they did at least in the samples I
  checked.

You might also want to try:

+              (smerge-refine-regions beg-del beg-add beg-add end-add
+                                     props-c nil props-r props-a)))))

Anyway, here is the full modified function:

(defun diff--refine-hunk (start end)
  (require 'smerge-mode)
  (goto-char start)
  (let* ((style (diff-hunk-style))      ;Skips the hunk header as well.
         (beg (point))
         (props-c '((diff-mode . fine) (face . diff-refine-changed)))
         (props-r '((diff-mode . fine) (face . diff-refine-removed)))
         (props-a '((diff-mode . fine) (face . diff-refine-added))))

    (remove-overlays beg end 'diff-mode 'fine)

    (goto-char beg)
    (pcase style
      ('unified
       (while (re-search-forward "^-" end t)
         (let ((beg-del (progn (beginning-of-line) (point)))
               beg-add end-add)
           (when (and (diff--forward-while-leading-char ?- end)
                      ;; Allow for "\ No newline at end of file".
                      (progn (diff--forward-while-leading-char ?\\ end)
                             (setq beg-add (point)))
                      (diff--forward-while-leading-char ?+ end)
                      (progn (diff--forward-while-leading-char ?\\ end)
                             (setq end-add (point))))
             (smerge-refine-regions beg-del beg-add beg-add end-add
                                    props-c nil nil nil)))))
      ('context
       (let* ((middle (save-excursion (re-search-forward "^---" end)))
              (other middle))
         (while (re-search-forward "^\\(?:!.*\n\\)+" middle t)
           (smerge-refine-regions (match-beginning 0) (match-end 0)
                                  (save-excursion
                                    (goto-char other)
                                    (re-search-forward "^\\(?:!.*\n\\)+" end)
                                    (setq other (match-end 0))
                                    (match-beginning 0))
                                  other
                                  (if diff-use-changed-face props-c)
                                  #'diff-refine-preproc
                                  (unless diff-use-changed-face props-r)
                                  (unless diff-use-changed-face props-a)))))
      (_ ;; Normal diffs.
       (let ((beg1 (1+ (point))))
         (when (re-search-forward "^---.*\n" end t)
           ;; It's a combined add&remove, so there's something to do.
           (smerge-refine-regions beg1 (match-beginning 0)
                                  (match-end 0) end
                                  nil #'diff-refine-preproc props-r props-a)))))))




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: delete lines with overlays [workaround to diff mode]
  2023-08-30  5:07   ` Samuel Wales
  2023-08-30 11:21     ` Jens Schmidt via Users list for the GNU Emacs text editor
@ 2023-08-30 11:30     ` Jens Schmidt via Users list for the GNU Emacs text editor
  2023-08-30 16:25     ` Jens Schmidt
  2 siblings, 0 replies; 7+ messages in thread
From: Jens Schmidt via Users list for the GNU Emacs text editor @ 2023-08-30 11:30 UTC (permalink / raw)
  To: help-gnu-emacs; +Cc: help-gnu-emacs

On 2023-08-30  07:07, Samuel Wales wrote:

> currently 27

How convenient ... having that around here as well.

As Dmitry has noted in your bug#61396, the diff refinement machinery
probably already has what you are looking for, but without
ready-made switches to turn it on.

You might want to try whether the following modified function
`diff--refine-hunk' does what you need.  Not sure how proficient
you are in Elisp hacking, so I provide full instructions to get
it activated.

1. Start Emacs as "emacs -Q" to get reproducible results.  (This
   is required only for the initial tests.)
2. M-x load-library diff-mode RET to load the original library
3. Paste below function definition into *scratch* and press C-M-x
   with point in or after the definition to evaluate the modified
   function definition.
4. Then check whether the result matches your expectation.

The only lines I modified in the function are these:

-              (smerge-refine-regions beg-del beg-add beg-add end-add
-                                     nil #'diff-refine-preproc props-r props-a)))))

I replaced that by:

+              (smerge-refine-regions beg-del beg-add beg-add end-add
+                                     props-c nil nil nil)))))

Comments:

- `props-c' is responsible for highlighting changes in yellow
  (compared to `props-r' for removals, `props-a' for additions)
- Function `diff-refine-preproc' referenced in the original function
  strips off the leading '-' and '+' chars from the diffs to avoid
  getting them highlighted as refined diffs.
  When replacing the reference to that function by nil, these leading
  chars get processed by the refinement as well and are highlighted as
  changes if needed.  Hopefully, they did at least in the samples I
  checked.

You might also want to try:

+              (smerge-refine-regions beg-del beg-add beg-add end-add
+                                     props-c nil props-r props-a)))))

Anyway, here is the full modified function:

(defun diff--refine-hunk (start end)
  (require 'smerge-mode)
  (goto-char start)
  (let* ((style (diff-hunk-style))      ;Skips the hunk header as well.
         (beg (point))
         (props-c '((diff-mode . fine) (face . diff-refine-changed)))
         (props-r '((diff-mode . fine) (face . diff-refine-removed)))
         (props-a '((diff-mode . fine) (face . diff-refine-added))))

    (remove-overlays beg end 'diff-mode 'fine)

    (goto-char beg)
    (pcase style
      ('unified
       (while (re-search-forward "^-" end t)
         (let ((beg-del (progn (beginning-of-line) (point)))
               beg-add end-add)
           (when (and (diff--forward-while-leading-char ?- end)
                      ;; Allow for "\ No newline at end of file".
                      (progn (diff--forward-while-leading-char ?\\ end)
                             (setq beg-add (point)))
                      (diff--forward-while-leading-char ?+ end)
                      (progn (diff--forward-while-leading-char ?\\ end)
                             (setq end-add (point))))
             (smerge-refine-regions beg-del beg-add beg-add end-add
                                    props-c nil nil nil)))))
      ('context
       (let* ((middle (save-excursion (re-search-forward "^---" end)))
              (other middle))
         (while (re-search-forward "^\\(?:!.*\n\\)+" middle t)
           (smerge-refine-regions (match-beginning 0) (match-end 0)
                                  (save-excursion
                                    (goto-char other)
                                    (re-search-forward "^\\(?:!.*\n\\)+" end)
                                    (setq other (match-end 0))
                                    (match-beginning 0))
                                  other
                                  (if diff-use-changed-face props-c)
                                  #'diff-refine-preproc
                                  (unless diff-use-changed-face props-r)
                                  (unless diff-use-changed-face props-a)))))
      (_ ;; Normal diffs.
       (let ((beg1 (1+ (point))))
         (when (re-search-forward "^---.*\n" end t)
           ;; It's a combined add&remove, so there's something to do.
           (smerge-refine-regions beg1 (match-beginning 0)
                                  (match-end 0) end
                                  nil #'diff-refine-preproc props-r props-a)))))))




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: delete lines with overlays [workaround to diff mode]
  2023-08-30  5:07   ` Samuel Wales
  2023-08-30 11:21     ` Jens Schmidt via Users list for the GNU Emacs text editor
  2023-08-30 11:30     ` Jens Schmidt via Users list for the GNU Emacs text editor
@ 2023-08-30 16:25     ` Jens Schmidt
  2 siblings, 0 replies; 7+ messages in thread
From: Jens Schmidt @ 2023-08-30 16:25 UTC (permalink / raw)
  To: Samuel Wales; +Cc: help-gnu-emacs

[Internet sucks at my current place, sorry for the split
sends/resends.]

On 2023-08-30  07:07, Samuel Wales wrote:

> currently 27

How convenient ... having that around here as well.

As Dmitry has noted in your bug#61396, the diff refinement machinery
probably already has what you are looking for, but without
ready-made switches to turn it on.

You might want to try whether the following modified function
`diff--refine-hunk' does what you need.  Not sure how proficient
you are in Elisp hacking, so I provide full instructions to get
it activated.

1. Start Emacs as "emacs -Q" to get reproducible results.  (This
   is required only for the initial tests.)
2. M-x load-library diff-mode RET to load the original library
3. Paste below function definition into *scratch* and press C-M-x
   with point in or after the definition to evaluate the modified
   function definition.
4. Then check whether the result matches your expectation.

The only lines I modified in the function are these:

-              (smerge-refine-regions beg-del beg-add beg-add end-add
-                                     nil #'diff-refine-preproc props-r props-a)))))

I replaced that by:

+              (smerge-refine-regions beg-del beg-add beg-add end-add
+                                     props-c nil nil nil)))))

Comments:

- `props-c' is responsible for highlighting changes in yellow
  (compared to `props-r' for removals, `props-a' for additions)
- Function `diff-refine-preproc' referenced in the original function
  strips off the leading '-' and '+' chars from the diffs to avoid
  getting them highlighted as refined diffs.
  When replacing the reference to that function by nil, these leading
  chars get processed by the refinement as well and are highlighted as
  changes if needed.  Hopefully, they did at least in the samples I
  checked.

You might also want to try:

+              (smerge-refine-regions beg-del beg-add beg-add end-add
+                                     props-c nil props-r props-a)))))

Anyway, here is the full modified function:

(defun diff--refine-hunk (start end)
  (require 'smerge-mode)
  (goto-char start)
  (let* ((style (diff-hunk-style))      ;Skips the hunk header as well.
         (beg (point))
         (props-c '((diff-mode . fine) (face . diff-refine-changed)))
         (props-r '((diff-mode . fine) (face . diff-refine-removed)))
         (props-a '((diff-mode . fine) (face . diff-refine-added))))

    (remove-overlays beg end 'diff-mode 'fine)

    (goto-char beg)
    (pcase style
      ('unified
       (while (re-search-forward "^-" end t)
         (let ((beg-del (progn (beginning-of-line) (point)))
               beg-add end-add)
           (when (and (diff--forward-while-leading-char ?- end)
                      ;; Allow for "\ No newline at end of file".
                      (progn (diff--forward-while-leading-char ?\\ end)
                             (setq beg-add (point)))
                      (diff--forward-while-leading-char ?+ end)
                      (progn (diff--forward-while-leading-char ?\\ end)
                             (setq end-add (point))))
             (smerge-refine-regions beg-del beg-add beg-add end-add
                                    props-c nil nil nil)))))
      ('context
       (let* ((middle (save-excursion (re-search-forward "^---" end)))
              (other middle))
         (while (re-search-forward "^\\(?:!.*\n\\)+" middle t)
           (smerge-refine-regions (match-beginning 0) (match-end 0)
                                  (save-excursion
                                    (goto-char other)
                                    (re-search-forward "^\\(?:!.*\n\\)+" end)
                                    (setq other (match-end 0))
                                    (match-beginning 0))
                                  other
                                  (if diff-use-changed-face props-c)
                                  #'diff-refine-preproc
                                  (unless diff-use-changed-face props-r)
                                  (unless diff-use-changed-face props-a)))))
      (_ ;; Normal diffs.
       (let ((beg1 (1+ (point))))
         (when (re-search-forward "^---.*\n" end t)
           ;; It's a combined add&remove, so there's something to do.
           (smerge-refine-regions beg1 (match-beginning 0)
                                  (match-end 0) end
                                  nil #'diff-refine-preproc props-r props-a)))))))



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-08-30 16:25 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-29  5:32 delete lines with overlays [workaround to diff mode] Samuel Wales
2023-08-29 17:19 ` Marcin Borkowski
2023-08-29 22:03 ` Jens Schmidt via Users list for the GNU Emacs text editor
2023-08-30  5:07   ` Samuel Wales
2023-08-30 11:21     ` Jens Schmidt via Users list for the GNU Emacs text editor
2023-08-30 11:30     ` Jens Schmidt via Users list for the GNU Emacs text editor
2023-08-30 16:25     ` Jens Schmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).