0

Searching on Google, I found this website: https://www.dcode.fr/differences-2-texts. It allows "visually" comparing two text strings at the character level,

enter image description here

returning a result like this:

enter image description here

My question is: is there any function or package that allows doing the same thing directly in Emacs?

The function should take the two strings as arguments and return the "fontified" comparison string or show the result in a dedicated buffer.

I would need to use the function something like this:

(emacs-text-compare-bla-bla "String1" "String2" 'character-level)

without the need to manually select the strings to compare.

Note. I would really prefer to have a fontified string as output, like in the example, so that I can easily view/insert it without the need for additional buffers. If I were to have the output in a buffer, it should be a single window, not two as in the case of *diff* functions.

I thought that perhaps I could use a function used internally by some tool used for diffing... but since I don't use Emacs for this type of operation, I have no idea where to start.

2 Answers 2

3

Based on the answer above by @db48x, this seems to roughly work:

(defun malb/visual-diff-strings (old-string new-string)
  (let ((old-buffer (get-buffer-create (make-temp-name "old-buffer-")))
        (new-buffer (get-buffer-create (make-temp-name "new-buffer-")))
        (output-buffer (get-buffer-create (make-temp-name "*output-diff*"))))
    (with-current-buffer old-buffer
      (insert old-string))
    (with-current-buffer new-buffer
      (insert new-string))
    (diff-no-select old-buffer new-buffer "-u" t output-buffer)
    (kill-buffer old-buffer)
    (kill-buffer new-buffer)
    (display-buffer-pop-up-frame output-buffer '((pop-up-frame-parameters (width . 80))))))

8
  • Thanks for doing that; I hadn’t yet gotten around to it.
    – db48x
    Commented Feb 28 at 2:14
  • Thank you for the time spent, but this function does not do what I asked for. It does not condense the differences between the two compared strings into a single string. Additionally, on my machine, it opens a new frame instead of a new window.
    – Gabriele
    Commented Feb 28 at 7:32
  • I've realized that this is the best solution I can get. Thank you.
    – Gabriele
    Commented Feb 28 at 14:06
  • I didn't know how to add it as a comment to your answer @db48x, it was too long. Sorry! Commented Feb 28 at 16:42
  • You can change display-buffer-pop-up-frame to just display-buffer. There should be a way to wedge in some word diff, too. Commented Feb 28 at 16:43
1

Yes, just call the function diff.

It only takes buffers though, not strings. You’ll want to turn your strings into temporary buffers first by using with-temp-buffer. (Or, depending on how you are writing your code, you might already have buffers and can just skip the step of turning them into strings.)

Edit:

The difference between strings and buffers is pretty trivial. A buffer is mostly just a string with some ancillary data, such as the cursor location, stored alongside it. If you just want the text that would be displayed in a diff buffer, you can call the function diff-no-select instead. This will create the “Diff” buffer without making it visible, unless you pass in a buffer of your own. Thus, if you want a string, all you have to do is make a temporary buffer, render the diff into it, and then fetch the content of the buffer as a string. Like this:

(with-temp-buffer
  (diff-no-select old-buffer new-buffer nil t (current-buffer))
  (buffer-string))

Of course, that is such a common idiom that there is macro that does exactly that called with-output-to-string:

(with-output-to-string
  (diff-no-select old-buffer new-buffer nil t (current-buffer)))

Another edit:

I must have forgotten to mention this, but the resulting buffer will be in diff-mode, which can do refinement to a character–based diff. If you customize the variable diff-refine, you can turn this on or off.

3
  • diff is an autoloaded interactive Lisp function in ‘diff.el’. (diff OLD NEW &optional SWITCHES NO-ASYNC) Find and display the differences between OLD and NEW files.
    – Gabriele
    Commented Feb 25 at 16:06
  • I updated my question to clarify my purpose.
    – Gabriele
    Commented Feb 25 at 17:41
  • I tried you code but it didn't work. diff-no-select (like diff) does not accept "buffers" as arguments but "files". In you answer you talk about "strings" and "buffers". Also you mention turning strings into buffers using "with-temp-buffer" but it's not clear how to pass this temp buffers to a function as args. Is it possible? It would be useful if you provide a complete working example for 2 strings.
    – Gabriele
    Commented Feb 26 at 6:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.