From 9edf08d0e0fc32722d1d217b9a184b8442e04664 Mon Sep 17 00:00:00 2001 From: mosquito-magnet <24659697+mosquito-magnet@users.noreply.github.com> Date: Thu, 2 Dec 2021 23:32:27 +0100 Subject: [PATCH] Support encodings incompatible with emacs default When running git-gutter on files with encodings incompatible with the emacs default encoding (prefer-coding-system), several problems could occur. When reading incompatible file content data from processes the receiving buffers would contain bytes with their (default) encoding. Writing contents from these buffers to file (original/current) would prompt user for proper encoding, if it could not automatically determine a safe one. Original/current temporary files with improper/deviating encoding yield incorrect diff results. On staging, patch files with improper encoding would not apply. Popup hunk buffer could display garbled characters. To fix this, use the current workdir file encoding to set read and write encodings where appropriate. This assumes the unchanged file uses the same encoding, so there are still error situations possible if that encoding is incompatible with the workdir file one. This should be good enough for most situations though. --- git-gutter.el | 75 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/git-gutter.el b/git-gutter.el index 9321f6c..13c6f6f 100644 --- a/git-gutter.el +++ b/git-gutter.el @@ -387,11 +387,12 @@ Argument TEST is the case before BODY execution." "bzr" "diff" "--context=0" args))) (defun git-gutter:start-diff-process1 (file proc-buf) - (cl-case git-gutter:vcs-type - (git (git-gutter:start-git-diff-process file proc-buf)) - (svn (git-gutter:start-svn-diff-process file proc-buf)) - (hg (git-gutter:start-hg-diff-process file proc-buf)) - (bzr (git-gutter:start-bzr-diff-process file proc-buf)))) + (let ((coding-system-for-read buffer-file-coding-system)) + (cl-case git-gutter:vcs-type + (git (git-gutter:start-git-diff-process file proc-buf)) + (svn (git-gutter:start-svn-diff-process file proc-buf)) + (hg (git-gutter:start-hg-diff-process file proc-buf)) + (bzr (git-gutter:start-bzr-diff-process file proc-buf))))) (defun git-gutter:start-diff-process (curfile proc-buf) (let ((file (git-gutter:base-file)) ;; for tramp @@ -833,9 +834,13 @@ Argument TEST is the case before BODY execution." (let ((content (git-gutter-hunk-content diff-info)) (type (git-gutter-hunk-type diff-info)) (header (git-gutter:extract-hunk-header)) - (patch (make-temp-name "git-gutter"))) + (patch (make-temp-name "git-gutter")) + (coding buffer-file-coding-system)) (when header (with-temp-file patch + ;; patch must match target file encoding, but unix eols are mandatory + (setq buffer-file-coding-system + (coding-system-change-eol-conversion coding 'unix)) (insert header) (git-gutter:insert-staging-hunk content type)) (let ((dir-option (git-gutter:apply-directory-option)) @@ -868,16 +873,18 @@ Argument TEST is the case before BODY execution." (push-mark end nil t)))) (defun git-gutter:update-popuped-buffer (diffinfo) - (with-current-buffer (get-buffer-create git-gutter:popup-buffer) - (view-mode -1) - (setq buffer-read-only nil) - (erase-buffer) - (insert (git-gutter-hunk-content diffinfo)) - (insert "\n") - (goto-char (point-min)) - (diff-mode) - (view-mode +1) - (current-buffer))) + (let ((coding buffer-file-coding-system)) + (with-current-buffer (get-buffer-create git-gutter:popup-buffer) + (setq buffer-file-coding-system (coding-system-base coding)) + (view-mode -1) + (setq buffer-read-only nil) + (erase-buffer) + (insert (git-gutter-hunk-content diffinfo)) + (insert "\n") + (goto-char (point-min)) + (diff-mode) + (view-mode +1) + (current-buffer)))) (defun git-gutter:popup-hunk (&optional diffinfo) "Popup current diff hunk." @@ -1043,30 +1050,36 @@ start revision." (setq git-gutter:update-timer nil)) (defsubst git-gutter:write-current-content (tmpfile) - (let ((content (buffer-substring-no-properties (point-min) (point-max)))) + (let ((content (buffer-substring-no-properties (point-min) (point-max))) + (coding buffer-file-coding-system)) (with-temp-file tmpfile + (setq buffer-file-coding-system coding) (insert content)))) (defun git-gutter:original-file-content (file vcs) - (with-temp-buffer - (cl-case vcs - (git - (when (zerop (process-file "git" nil t nil "show" (concat ":" file))) - (buffer-substring-no-properties (point-min) (point-max)))) - ((svn hg bzr) - (let ((command (symbol-name vcs))) - (when (zerop (process-file command nil t nil "cat" file)) - (buffer-substring-no-properties (point-min) (point-max)))))))) + (let ((coding-system-for-read (coding-system-base buffer-file-coding-system))) + (with-temp-buffer + (cl-case vcs + (git + (when (zerop (process-file "git" nil t nil "show" (concat ":" file))) + (buffer-substring-no-properties (point-min) (point-max)))) + ((svn hg bzr) + (let ((command (symbol-name vcs))) + (when (zerop (process-file command nil t nil "cat" file)) + (buffer-substring-no-properties (point-min) (point-max))))))))) (defun git-gutter:write-original-content (tmpfile filename) (git-gutter:awhen (git-gutter:original-file-content filename git-gutter:vcs-type) - (with-temp-file tmpfile - (insert it) - t))) + (let ((coding buffer-file-coding-system)) + (with-temp-file tmpfile + (setq buffer-file-coding-system coding) + (insert it) + t)))) (defsubst git-gutter:start-raw-diff-process (proc-buf original now) - (start-file-process "git-gutter:update-timer" proc-buf - "diff" "-U0" original now)) + (let ((coding-system-for-read buffer-file-coding-system)) + (start-file-process "git-gutter:update-timer" proc-buf + "diff" "-U0" original now))) (defun git-gutter:start-live-update (file original now) (let ((proc-bufname (git-gutter:diff-process-buffer file)))