Diff của hai bộ đệm mà không tạo tập tin tạm thời


9

Tôi cần sự khác biệt của hai bộ đệm. Một cách sẽ là tạo các tệp tạm thời chứa nội dung của các bộ đệm này và sử dụng diffchức năng. Tuy nhiên, bộ đệm chứa thông tin nhạy cảm và tôi không muốn có thông tin đó trong văn bản rõ ràng trên đĩa.

Tôi đã nghĩ về việc sử dụng ediff có thể so sánh trực tiếp bộ đệm nhưng ediff bắt đầu một phiên tương tác và tôi muốn sử dụng điều này trong một kịch bản.


Chỉ cần làm rõ, bạn muốn một chức năng cung cấp khác biệt của hai bộ đệm mà không có bất kỳ tương tác người dùng?
dùng2699

@ user2699, chính xác. Bối cảnh: emacs.stackexchange.com/questions/27349/ từ
tmalsburg

Có thể sử dụng ống được đặt tên cho điều này?
tmalsburg

1
Tôi không quen thuộc với các đường ống được đặt tên, nhưng có vẻ như giải pháp tốt nhất sẽ là một cái gì đó vượt ra ngoài emacs. Nhìn qua mã nguồn ediff-buffersrất ngắn gọn, có vẻ như lưu bộ đệm vào các tệp tạm thời trên đĩa, sau đó gọi tiện ích diff của hệ thống trên các tệp đó, do đó sẽ không có bất kỳ sự khác biệt thực tế nào khi difftự gọi .
dùng2699

2
Theo hệ điều hành nào? Hàm diff sử dụng một chương trình bên ngoài và giao tiếp với một chương trình bên ngoài phụ thuộc vào hệ điều hành. Giải pháp đơn giản sẽ là lưu trữ các tệp trong hệ thống tệp trong bộ nhớ; những tiêu chuẩn trên Linux hiện nay nhưng có thể không tồn tại trên các nền tảng khác.
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


3

@tmalsburg, Lệnh sau gọi diff trên 2 bộ đệm mà không tạo tệp tạm thời. Nó sử dụng các đường ống được đặt tên như bạn đề xuất ở trên:

(require 'diff)
(defun diff-buffers-without-temp-files (buffer1 buffer2 &optional switches)
  "Run diff program on BUFFER1 and BUFFER2.
Make the comparison without the creation of temporary files.

When called interactively with a prefix argument, prompt
interactively for diff switches.  Otherwise, the switches
specified in the variable `diff-switches' are passed to the diff command."
  (interactive
   (list (read-buffer "buffer1: " (current-buffer))
         (read-buffer "buffer2: " (current-buffer))
         (diff-switches)))
  (or switches (setq switches diff-switches))
  (unless (listp switches) (setq switches (list switches)))
  (let ((buffers (list buffer1 buffer2))
        (buf (get-buffer-create "*diff-buffers*"))
        fifos res)
    (dotimes (_ 2) (push (make-temp-name "/tmp/pipe") fifos))
    (setq fifos (nreverse fifos))
    (with-current-buffer buf (erase-buffer))
    (unwind-protect
        (progn
          (dotimes (i 2)
            (let ((cmd (format "cat > %s << EOF\n%s\nEOF"
                               (nth i fifos)
                               (with-current-buffer (nth i buffers)
                                 (buffer-string)))))
              (call-process "mkfifo" nil nil nil (nth i fifos))
              (start-process-shell-command (format "p%d" i) nil cmd)))
          (setq res (apply #'call-process diff-command nil buf nil (car fifos) (cadr fifos) switches))
          (if (zerop res)
              (message "Buffers have same content")
            (display-buffer buf)
            (with-current-buffer buf (diff-mode))
            (message "Buffer contents are different"))
          res)
      ;; Clean up.
      (dolist (x fifos)
        (and (file-exists-p x) (delete-file x))))))
  1. Khi được gọi tương tác, nó hiển thị khác biệt khi bộ đệm có nội dung khác nhau.
  2. Khi được gọi từ Lisp, nó trả về mã thoát của chương trình diff; nghĩa là 0 nếu bộ đệm có cùng nội dung, 1 nếu không.

    (diff-buffers-without-temp-files (get-buffer "*scratch*") (get-buffer "*scratch*"))
    => 0
    
    
    (diff-buffers-without-temp-files (get-buffer "*scratch*") (get-buffer "*Messages*"))
    => 1
    

Đã thử nghiệm phiên bản Emacs 24.3 trong một máy chạy Debian GNU / Linux 9.0 (kéo dài).

  • Các mã ở trên dường như làm việc được gọi là từ Lisp. Thật không may, hầu hết thời gian cho thấy một sự khác biệt cắt ngắn trong các cuộc gọi tương tác.

  • Phiên bản sau sử dụng thư viện async của bên thứ 3 ; nó không cắt bớt các khác biệt.

(require 'diff)
(require 'async)
(defun diff-buffers-without-temp-files (buffer1 buffer2 &optional switches)
  "Run diff program on BUFFER1 and BUFFER2.
Make the comparison without the creation of temporary files.

When called interactively with a prefix argument, prompt
interactively for diff switches.  Otherwise, the switches
specified in the variable `diff-switches' are passed to the diff command."
  (interactive
   (list (read-buffer "buffer1: " (current-buffer))
         (read-buffer "buffer2: " (current-buffer))
         (diff-switches)))
  (or switches (setq switches diff-switches))
  (unless (listp switches) (setq switches (list switches)))
  (let ((buffers (list buffer1 buffer2))
        (buf (get-buffer-create "*diff-buffers*"))
        fifos res)
    (dotimes (_ 2) (push (make-temp-name "/tmp/pipe") fifos))
    (setq fifos (nreverse fifos))
    (with-current-buffer buf (erase-buffer))
    (unwind-protect
        (progn
          (dotimes (i 2)
            (let ((cmd (format "cat > %s" (nth i fifos))))
              (call-process "mkfifo" nil nil nil (nth i fifos))
              (async-start
               `(lambda ()
                  (with-temp-buffer
                    (insert ,(with-current-buffer (nth i buffers) (buffer-string)))
                    (call-process-region
                     1 (point-max) shell-file-name nil nil nil
                     shell-command-switch ,cmd))))))
          (setq res (apply #'call-process diff-command nil buf nil (car fifos) (cadr fifos) switches))
          (if (zerop res)
              (message "Buffers have same content")
            (display-buffer buf)
            (with-current-buffer buf (diff-mode))
            (message "Buffer contents are different"))
          res)
      ;; Clean up.
      (dolist (x fifos)
        (and (file-exists-p x) (delete-file x))))))

Cảm ơn bạn, @tino, đây chính xác là những gì tôi đang tìm kiếm!
tmalsburg

0

AFAIU Emacs lấy các chương trình bên ngoài để làm khác. Ví dụ ediff-make-diff2-buffer, sẽ so sánh hai bộ đệm, gọi nội bộ

  (ediff-exec-process ediff-diff-program
                 diff-buffer
                 'synchronize
                 ediff-actual-diff-options file1 file2)

Trường hợp ediff-diff-programcó thể đại diện cho GNU / Linux diff. Với FFI mới, hệ thống diffcó thể truy cập được. Ngoài ra một triển khai khác biệt Emacs Lisp có thể thực hiện công việc.


0

Làm thế nào về bạn sử dụng lệnh shell để gọi diff, truyền cho nó một bộ đệm đầu ra? Hoặc, shell-lệnh-to-string để lấy diff trong chuỗi


Tôi không chắc tôi hiểu ý của bạn bằng cách chuyển nó vào bộ đệm đầu ra. Bạn có thể vui lòng giải thích điều này một chút? Cảm ơn.
tmalsburg

Cú pháp của shell-lệnh là (lệnh shell-lệnh & OUTPUT-BUFFER ERROR-BUFFER tùy chọn). Đối số thứ hai tùy chọn là: "" "Đối số thứ hai tùy chọn OUTPUT-BUFFER, nếu không phải là số không, nói sẽ đặt đầu ra vào một số bộ đệm khác. Nếu OUTPUT-BUFFER là tên bộ đệm hoặc tên bộ đệm, hãy đặt đầu ra ở đó. Nếu OUTPUT -BUFFER không phải là bộ đệm và không phải là con số không, hãy chèn đầu ra vào bộ đệm hiện tại. (Điều này không thể được thực hiện không đồng bộ.) "
russell

0

Nếu bạn ổn với Ediff, điều này sẽ làm:

(defun my/diff-buffers (buffer-A buffer-B)
  "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B."
  (ediff-buffers-internal buffer-A buffer-B nil nil 'ediff-buffers))

và gọi nó như thế này:

(my/diff-buffers "*temp*" "*temp*<2>")

Cảm ơn vì sự trả lời. Có hai vấn đề với giải pháp này. 1. Theo hiểu biết của tôi, ediff sử dụng diff và do đó cần các tập tin tạm thời. 2. Giải pháp của bạn bắt đầu một phiên tương tác nhưng tôi chỉ muốn khác biệt trong bộ đệm hoặc chuỗi.
tmalsburg

1
Ah, tôi đọc sai câu hỏi của bạn. Tôi nghĩ bạn không muốn tự tạo các tệp tạm thời. emacs.stackexchange.com/questions/19812 đang yêu cầu phiên bản elisp của diff. Không có đề cập về các tập tin tạm thời, mặc dù. Đọc câu hỏi của bạn một lần nữa, bạn phải có đầu ra khác? hoặc bạn muốn chỉ so sánh chuỗi của bạn và biết khác biệt? Một ví dụ người gọi có thể giúp đỡ.
Yasushi Shoji

(defun my/diff-buffers (buffer-A buffer-B) "Run Ediff on a pair of buffers, BUFFER-A and BUFFER-B." (interactive (list (read-buffer "buffer1: " (current-buffer)) (read-buffer "buffer2: " (current-buffer)))) (ediff-buffers-internal buffer-A buffer-B nil nil 'ediff-buffers))
HappyFace
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.