Subject: Re: bug#27391: 25.2.50; utf-8 coding cookie is not applied on some specific markdown file

From: Philipp Stephani <[email-masked]>
Date: Fri, 16 Jun 2017 21:52:24 +0000

Philipp Stephani <[email-masked]> schrieb am Fr., 16. Juni 2017 um
23:39 Uhr:

> Philipp Stephani <[email-masked]> schrieb am Fr., 16. Juni 2017 um
> 23:34 Uhr:
>
>> Vincent Belaïche <[email-masked]> schrieb am Fr., 16. Juni
>> 2017 um 23:28 Uhr:
>>
>>>
>>>
>>> Le 16/06/2017 à 21:37, Vincent Belaïche a écrit :
>>> >
>>> >
>>> > Le 16/06/2017 à 21:15, Vincent Belaïche a écrit :
>>> >>
>>>
>>> [...]
>>>
>>> >>
>>> >>
>>> > After some more investigation, I think that the bug is in function
>>> > insert-file-contents of fileio.c which is the one that decide and sets
>>> > the coding system well before the other local variables are looked
>>> into.
>>>
>>> After some more investigation, in the end the find-auto-coding of
>>> mule.el is what is called to detect the coding. This function calls some
>>> re-coding regexp.
>>>
>>> Here is a test function defining the same regexp.
>>>
>>>
>>> (defun doit ()
>>>   (interactive)
>>>   (let* ((prefix (regexp-quote "[comment]: # ("))
>>>          (suffix (regexp-quote ")"))
>>>          (re-coding
>>>           (concat
>>>            "[\r\n]" prefix
>>>            ;; N.B. without the \n below, the regexp can
>>>            ;; eat newlines.
>>>            "[ \t]*coding[ \t]*:[ \t]*\\([^ \t\r\n]+\\)[ \t]*"
>>>            suffix "[\r\n]")))
>>>     (message (if (looking-at re-coding) "ok" "nak"))))
>>>
>>> I tried it with point at end of line
>>>
>>> [comment]: # ( Local Variables: )
>>>
>>> and it answered "ok". Now I defined this with re-search-forward instead
>>> of looking-at:
>>>
>>> (defun doit ()
>>>   (interactive)
>>>   (let* ((prefix (regexp-quote "[comment]: # ("))
>>>          (suffix (regexp-quote ")"))
>>>          (re-coding
>>>           (concat
>>>            "[\r\n]" prefix
>>>            ;; N.B. without the \n below, the regexp can
>>>            ;; eat newlines.
>>>            "[ \t]*coding[ \t]*:[ \t]*\\([^ \t\r\n]+\\)[ \t]*"
>>>            suffix "[\r\n]")))
>>>     (message (if (re-search-forward re-coding nil t) "ok" "nak"))))
>>>
>>> I placed the point before the coding: line, and I also got answer "ok"
>>>
>>> So I don't think that the regexp as such is to blame. Something else
>>> seems to happen. It is too late now, I need to go to bed...
>>>
>>>   Vincent.
>>>
>>>
>> I think it's actually the regexp that searches for "Local Variables". The
>> following minimal example fails for me:
>>
>> (with-temp-buffer
>>   (insert "
>>
>> [comment]: # ( Local Variables: )
>> [comment]: # ( coding: utf-8 )
>> [comment]: # ( End: )
>>
>> ")
>> (goto-char (point-min))
>> (re-search-forward
>>  "[\r\n]\\([^[\r\n]*\\)[ \t]*Local Variables:[ \t]*\\([^\r\n]*\\)[\r\n]"))
>>
>>
> Does anybody know why the second character range says [^[\r\n] instead of
>  [^\r\n]? This seems to explicitly exclude a leading [.
>

If this is a typo, then here's a patch.
From 2f8bbf7e729ea09addf0d066861a3b38c312141d Mon Sep 17 00:00:00 2001
From: Philipp Stephani <[email-masked]>
Date: Fri, 16 Jun 2017 23:49:09 +0200
Subject: [PATCH] Allow local variables section to begin with a square bracket

Fixes Bug#27391.

* lisp/international/mule.el (find-auto-coding): Fix regular
expression for "Local Variables" section.

* test/lisp/international/mule-tests.el (find-auto-coding--bug27391):
Add unit test.
---
 lisp/international/mule.el            |  2 +-
 test/lisp/international/mule-tests.el | 39 +++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 test/lisp/international/mule-tests.el

diff --git a/lisp/international/mule.el b/lisp/international/mule.el
index fa3ad80e2f..6cfb7e6d45 100644
--- a/lisp/international/mule.el
+++ b/lisp/international/mule.el
@@ -1970,7 +1970,7 @@ find-auto-coding
 	  (goto-char tail-start)
 	  (re-search-forward "[\r\n]\^L" tail-end t)
 	  (if (re-search-forward
-	       "[\r\n]\\([^[\r\n]*\\)[ \t]*Local Variables:[ \t]*\\([^\r\n]*\\)[\r\n]"
+	       "[\r\n]\\([^\r\n]*\\)[ \t]*Local Variables:[ \t]*\\([^\r\n]*\\)[\r\n]"
 	       tail-end t)
 	      ;; The prefix is what comes before "local variables:" in its
 	      ;; line.  The suffix is what comes after "local variables:"
diff --git a/test/lisp/international/mule-tests.el b/test/lisp/international/mule-tests.el
new file mode 100644
index 0000000000..084f609c45
--- /dev/null
+++ b/test/lisp/international/mule-tests.el
@@ -0,0 +1,39 @@
+;;; mule-tests.el --- unit tests for mule.el         -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2017 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Unit tests for lisp/international/mule.el.
+
+;;; Code:
+
+(ert-deftest find-auto-coding--bug27391 ()
+  "Check that Bug#27391 is fixed."
+  (with-temp-buffer
+    (insert "\n[comment]: # ( Local Variables: )\n"
+            "[comment]: # ( coding: utf-8	)\n"
+            "[comment]: # ( End:		)n")
+    (goto-char (point-min))
+    (should (equal (let ((auto-coding-alist ())
+                         (auto-coding-regexp-alist ())
+                         (auto-coding-functions ()))
+                     (find-auto-coding "" (buffer-size)))
+                   '(utf-8 . :coding)))))
+
+;;; mule-tests.el ends here
-- 
2.13.1