1

I see others doing this in there IDEs is there a way to highlight a file or some text in a file and diff it with whats in my clipboard/kill-ring ?

6
  • Not sure what magit has to do with it? The answers in emacs.stackexchange.com/questions/14935/… might be helpful.
    – npostavs
    Commented May 12, 2017 at 15:45
  • Thats close, I the difference is i am in the magit buffer and viewing staged changes so i want to expand the file highlight and compare with whats in my clipboard. diff region is close but does not work that well with the magit buffer from what i can tell.
    – Oly
    Commented May 12, 2017 at 15:58
  • I am not sure what you are trying to do. But maybe it would help to know that you can press RET on a diff (or file name) to visit the respective file? To make it easier to understand what you are after, consider posting examples of the things you want to compare and what you expect the result of that comparison to look like.
    – tarsius
    Commented Jun 1, 2017 at 16:36
  • I did know that, but that does raise the question can i diff he current file or selection with the clipboard easily in which case i could work with that.
    – Oly
    Commented Jun 1, 2017 at 20:03
  • 1
    I think that a feature like this probably makes more sense when not using git/magit, so I think it would be better to implement a new specialized diff-* function instead of a magit-diff-* function. So I am removing the magit flag.
    – tarsius
    Commented Jun 5, 2017 at 17:22

1 Answer 1

2

Step 1: Select text and M-x diff-region-tag-selected-as-a

Step 2, Select or not select text, M-x diff-region-tag-selected-as-b

You need install cli tool diff on windows (its bundled with Cygwin or MSYS2).

To read clipboard, you need install Emacs plugin simpleclip.

Here is the code:

;; {{ diff region SDK
(defun diff-region-exit-from-certain-buffer (buffer-name)
  (bury-buffer buffer-name)
  (winner-undo))

(defmacro diff-region-open-diff-output (content buffer-name)
  `(let ((rlt-buf (get-buffer-create ,buffer-name)))
    (save-current-buffer
      (switch-to-buffer-other-window rlt-buf)
      (set-buffer rlt-buf)
      (erase-buffer)
      (insert ,content)
      (diff-mode)
      (goto-char (point-min))
      ;; Evil keybinding
      (if (fboundp 'evil-local-set-key)
          (evil-local-set-key 'normal "q"
                              (lambda ()
                                (interactive)
                                (diff-region-exit-from-certain-buffer ,buffer-name))))
      ;; Emacs key binding
      (local-set-key (kbd "C-c C-c")
                     (lambda ()
                       (interactive)
                       (diff-region-exit-from-certain-buffer ,buffer-name)))
      )))

;; }}

;; {{ Diff two regions
;; Step 1: Select a region and `M-x diff-region-tag-selected-as-a'
;; Step 2: Select another region and `M-x diff-region-compare-with-b'
;; Press "q" in evil-mode or "C-c C-c" to exit the diff output buffer
(defun diff-region-format-region-boundary (b e)
  "Make sure lines are selected and B is less than E"
  (let (tmp rlt)
    ;; swap b e, make sure b < e
    (when (> b e)
      (setq tmp b)
      (setq b e)
      (set e tmp))

    ;; select lines
    (save-excursion
      ;; Another workaround for evil-visual-line bug:
      ;; In evil-mode, if we use hotkey V or `M-x evil-visual-line` to select line,
      ;; the (line-beginning-position) of the line which is after the last selected
      ;; line is always (region-end)! Don't know why.
      (if (and (> e b)
               (save-excursion (goto-char e) (= e (line-beginning-position)))
               (boundp 'evil-state) (eq evil-state 'visual))
          (setq e (1- e)))
      (goto-char b)
      (setq b (line-beginning-position))
      (goto-char e)
      (setq e (line-end-position)))
    (setq rlt (list b e))
    rlt))

(defun diff-region-tag-selected-as-a ()
  "Select a region to compare."
  (interactive)
  (when (region-active-p)
    (let (tmp buf)
      ;; select lines
      (setq tmp (diff-region-format-region-boundary (region-beginning) (region-end)))
      (setq buf (get-buffer-create "*Diff-regionA*"))
      (save-current-buffer
        (set-buffer buf)
        (erase-buffer))
      (append-to-buffer buf (car tmp) (cadr tmp))))
  (message "Now select other region to compare and run `diff-region-compare-with-b'"))

(defun diff-region-compare-with-b ()
  "Compare current region with region selected by `diff-region-tag-selected-as-a'.
If no region is selected. You will be asked to use `kill-ring' or clipboard instead.
`simpleclip' need be installed to read clipboard."
  (interactive)
  (let* (rlt-buf
         diff-output
         ;; file A
         (fa (make-temp-file (expand-file-name "scor"
                                               (or small-temporary-file-directory
                                                   temporary-file-directory))))
         ;; file B
         (fb (make-temp-file (expand-file-name "scor"
                                               (or small-temporary-file-directory
                                                   temporary-file-directory)))))
    (when (and fa (file-exists-p fa) fb (file-exists-p fb))
      (cond
       ((region-active-p)
        ;; text from selected region
        (setq tmp (diff-region-format-region-boundary (region-beginning) (region-end)))
        (write-region (car tmp) (cadr tmp) fb))
       (t
        ;; text from `kill-ring' or clipboard
        (unless (featurep 'ido) (require 'ido))
        (let* ((choice (ido-completing-read "Since no region selected, compare text in:"
                                            '("kill-ring" "clipboard")))
               (txt (cond
                     ((string= choice "kill-ring")
                      (car kill-ring))
                     ((string= choice "clipboard")
                      (unless (featurep 'simpleclip) (require 'simpleclip))
                      (simpleclip-get-contents)))))
          (with-temp-file fb
            (insert txt)))))
      ;; save region A as file A
      (save-current-buffer
        (set-buffer (get-buffer-create "*Diff-regionA*"))
        (write-region (point-min) (point-max) fa))
      ;; diff NOW!
      ;; show the diff output
      (if (string= (setq diff-output (shell-command-to-string (format "diff -Nabur %s %s" fa fb))) "")
          ;; two regions are same
          (message "Two regions are SAME!")
        ;; show the diff
        (diff-region-open-diff-output diff-output
                                      "*Diff-region-output*"))
      ;; clean the temporary files
      (if (and fa (file-exists-p fa))
          (delete-file fa))
      (if (and fb (file-exists-p fb))
          (delete-file fb)))))
;; }}

The code is a simplified version from what I'm using (https://github.com/redguardtoo/emacs.d/blob/master/lisp/init-misc.el)

1
  • Cheers, I can do what i was aiming to with this and hoping i can adjust slightly to my own needs if i get a chance :)
    – Oly
    Commented Jun 9, 2017 at 9:29

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.