Subject: Re: bug#4816: change of coding system without inquiry

From: Norbert Eisinger <[email-masked]>
Date: Sat, 31 Oct 2009 17:32:56 +0100

Stefan Monnier wrote:
>
> I think you're right that we should at
> least do a y-or-n-p prompt when changing the buffer-file-coding-system,
> unless the change is to a "superset coding system" (like from us-ascii
> to latin-1).

I understand the tightrope walk. When you ask users about technical stuff,
they feel bothered if it does not make any difference to them. When you
don't ask them, they feel patronized if it does make a difference.

The superset strategy is probably a reasonable compromise. I believe
that something like the following might still go wrong, but this
is a construed example and I did not test it:

File announcement.tex contains
   \include{config.tex}
   ... \LECTURER ...
   % only ASCII characters in this file

Latin-1 encoded file config.tex contains
   \usepackage[latin1]{inputenc}
   \newcommand{\LECTURER}{François}

Later someone edits announcement.tex, adds the letter ç to it and saves it,
thus changing the coding system from ascii to the superset utf-8. After that
the two occurrences of ç are differently encoded.

But, again, this is an unusual case. In normal cases we should be OK with
the superset strategy.

> There is currently no direct way to ask Emacs to prompt when changing
> the coding system

Setting select-safe-coding-system-accept-default-p to
(function (lambda (coding-system) nil))
would not have this effect in the case we are discussing, would it?

> Can you try the patch below to see if it gives you the behavior you want?

I could not apply the patch, but I am at the limit of my knowledge.
Should I have gunzipped the file first?
Below is a description of what I did.

Best regards,
Norbert

============================================================================
Local timezone: +0100

Emacs version:
GNU Emacs 22.2.1 (i486-pc-linux-gnu, X toolkit, Xaw3d scroll bars) of 2008-09-05 on vernadsky, modified by Ubuntu

$ locate mule-cmds
/usr/share/emacs/22.2/lisp/international/mule-cmds.el.gz
/usr/share/emacs/22.2/lisp/international/mule-cmds.elc
/usr/share/xemacs-21.4.21/lisp/mule/mule-cmds.elc

$ ls -l /usr/share/emacs/22.2/lisp/international/mule-cmds.*
-rw-r--r-- 1 root root  79042 2008-09-05 23:28 mule-cmds.elc
-rw-r--r-- 1 root root  30300 2008-01-10 13:15 mule-cmds.el.gz

$ cd /usr/share/emacs/22.2/lisp/international

$ /usr/bin/emacs -Q &
  copy&paste the patch into buffer *scratch*
  menu Tools -> Apply Patch -> To a File
  select buffer *scratch* and file mule-cmds.el

,----[ *scratch* ]
|
| === modified file 'lisp/international/mule-cmds.el'
| --- lisp/international/mule-cmds.el	2009-10-24 18:33:25 +0000
| +++ lisp/international/mule-cmds.el	2009-10-30 15:01:02 +0000
| @@ -979,6 +979,17 @@
|  	(if safe
|  	    (setq coding-system (car safe))))
|
| +      (unless (or (local-variable-p 'buffer-file-coding-system)
| +                  (eq coding-system buffer-file-coding-system)
| +                  ;; We'd rather only bother the user if the coding-system
| +                  ;; change would cause the file's content to change, so we'd
| +                  ;; want to check whether the new coding-system is a superset
| +                  ;; of the previous one.
| +                  (memq buffer-file-coding-system '(nil undecided us-ascii))
| +                  (y-or-n-p (format "Change encoding from %s to %s? "
| +                                    buffer-file-coding-system coding-system)))
| +        (setq coding-system nil))
| +
|        ;; If all the defaults failed, ask a user.
|        (when (not coding-system)
|  	(setq coding-system (select-safe-coding-system-interactively
| @@ -1024,6 +1035,7 @@
|  %s specified by file contents.  Really save (else edit coding cookies \
|  and try again)? " coding-system auto-cs))
|  	      (error "Save aborted"))))
| +
|        (when (and tick (/= tick (buffer-chars-modified-tick)))
|  	(error "Cancelled because the buffer was modified"))
|        coding-system)))
|
`----

,----[ *Messages* ]
| ("/usr/bin/emacs" "-Q")
| For information about GNU Emacs and the GNU system, type C-h C-a.
| Mark set
| Loading ediff...done
| Is the patch already in a buffer? (y or n)
| Making completion list...
| Loading help-mode...done
| Applying patch ... done
| ediff-patch-file-internal: Patch appears to have failed
`----

,----[ *ediff-message* ]
| Patch program has failed due to a bad patch file,
| it couldn't apply all hunks, OR
| it couldn't create the backup for the file being patched.
|
| The former could be caused by a corrupt patch file or because the "patch"
| program doesn't understand the format of the patch file in use.
|
| The second problem might be due to an incompatibility among these settings:
|     ediff-patch-program    = "patch"             ediff-patch-options    = "-f"
|     ediff-backup-extension = ".orig"             ediff-backup-specs     = "-z.orig -b"
|
| See Ediff on-line manual for more details on these variables.
| In particular, check the documentation for `ediff-backup-specs'.
|
| In any of the above cases, Ediff doesn't compare files automatically.
| However, if the patch was applied partially and the backup file was created,
| you can still examine the changes via M-x ediff-files
`----

,----[ mule-cmds.el.rej ]
| ***************
| *** 979,984 ****
|   	(if safe
|   	    (setq coding-system (car safe))))
|
|         ;; If all the defaults failed, ask a user.
|         (when (not coding-system)
|   	(setq coding-system (select-safe-coding-system-interactively
| --- 979,995 ----
|   	(if safe
|   	    (setq coding-system (car safe))))
|
| +       (unless (or (local-variable-p 'buffer-file-coding-system)
| +                   (eq coding-system buffer-file-coding-system)
| +                   ;; We'd rather only bother the user if the coding-system
| +                   ;; change would cause the file's content to change, so we'd
| +                   ;; want to check whether the new coding-system is a superset
| +                   ;; of the previous one.
| +                   (memq buffer-file-coding-system '(nil undecided us-ascii))
| +                   (y-or-n-p (format "Change encoding from %s to %s? "
| +                                     buffer-file-coding-system coding-system)))
| +         (setq coding-system nil))
| +
|         ;; If all the defaults failed, ask a user.
|         (when (not coding-system)
|   	(setq coding-system (select-safe-coding-system-interactively
| ***************
| *** 1024,1029 ****
|   %s specified by file contents.  Really save (else edit coding cookies \
|   and try again)? " coding-system auto-cs))
|   	      (error "Save aborted"))))
|         (when (and tick (/= tick (buffer-chars-modified-tick)))
|   	(error "Cancelled because the buffer was modified"))
|         coding-system)))
| --- 1035,1041 ----
|   %s specified by file contents.  Really save (else edit coding cookies \
|   and try again)? " coding-system auto-cs))
|   	      (error "Save aborted"))))
| +
|         (when (and tick (/= tick (buffer-chars-modified-tick)))
|   	(error "Cancelled because the buffer was modified"))
|         coding-system)))
|
`----

$ ls -l mule-cmds*
-rw-r--r-- 1 root root 30300 2009-10-31 15:26 mule-cmds.el
-rw-r--r-- 1 root root 79042 2008-09-05 23:28 mule-cmds.elc
-rw-r--r-- 1 root root 30300 2008-01-10 13:15 mule-cmds.el.orig
-rw-r--r-- 1 root root  1797 2009-10-31 15:26 mule-cmds.el.rej

$ diff mule-cmds.el.orig mule-cmds.el
$ ### files do not differ

$ ### lines 978 to 990 of a gunzipped safety copy made before
$ ### line number 986 seems to be the line numbered 979 in the patch
$ head -n 990 /tmp/mule-cmds-safety-copy.el | tail -n -13
        ;; Classify the defaults into safe, rejected, and unsafe.
        (dolist (elt default-coding-system)
          (if (memq (cdr elt) codings)
              (if (and (functionp accept-default-p)
                       (not (funcall accept-default-p (cdr elt))))
                  (push (car elt) rejected)
                (push (car elt) safe))
            (push (car elt) unsafe)))
        (if safe
            (setq coding-system (car safe))))

      ;; If all the defaults failed, ask a user.
      (when (not coding-system)