unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Alan Mackenzie <acm@muc.de>
To: Stefan Monnier <monnier@IRO.UMontreal.CA>
Cc: 30393@debbugs.gnu.org, Dmitry Gutov <dgutov@yandex.ru>,
	Noam Postavsky <npostavs@users.sourceforge.net>
Subject: bug#30393: 24.4; cperl-mode: indentation failure
Date: Mon, 5 Mar 2018 08:42:55 +0000	[thread overview]
Message-ID: <20180305084255.GA4786@ACM> (raw)
In-Reply-To: <jwvsha6c4z1.fsf-monnier+emacsbugs@gnu.org>

Hello, Stefan.

Sorry this has taken so long.  I've been preoccupied with things outside
of Emacs.

On Mon, Feb 12, 2018 at 15:45:40 -0500, Stefan Monnier wrote:
> > It has occurred to me over the last day or two that I have already
> > solved these problems (basically, with your first approach, hooking into
> > set-syntax-table and friends) in the comment-cache branch, and that the
> > approach taken could be used more or less unchanged in the current
> > master.

> If you can reuse existing code, even better.

The following patch ensures that (almost) any time the syntax table or a
syntax-table text property is changed in a way which affects literals,
the function syntax-ppss-flush-cache is called.

The known exceptions to the above are that setting any of the variables
parse-sexp-lookup-properties, syntax-propertize-function,
syntax-propertize-extend-region-functions, multibyte-syntax-as-symbol,
parse-sexp-ignore-comments, comment-end-can-be-escaped after mode
initialisation is not detected.  The major mode code would need to flush
the caches explicitly on such a change.  Also, changing the syntax-table
property of a symbol which is the value of a category text-property is
not detected.

In the following descriptions "literally the same" and "literally
different", when applied to syntax things, are shorthand for "will parse
literals (comments and strings) the same/differently".

Existing C functions have been modified as follows:
  o - signal_after_change.
    * - Regardless of the settings of the change hooks,
      syntax-ppss-flush-cache will be called for an actual textual
      change.
  o - Fset_syntax_table.
    * - If the new table is literally different from the old,
      syntax-ppss-flush-cache will be called with an argument of -1.
  o - Fmodify_syntax_entry.
    * - If the new entry is literally different from the old one,
      syntax-ppss-flush-cache will be called with an argument of -1.
  o - init_syntax_once and syms_of_syntax.
    * - Administrative amendments.
  o - set_properties, add_properties, remove_properties.  If a
    syntax-table property set or removed, whether directly or via a
    category property, potentially alters the parsing of literals,
    syntax-ppss-flush-cache will be called.



diff --git a/src/chartab.c b/src/chartab.c
index 065ae4f9f2..e2b9e682cc 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -314,7 +314,6 @@ sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to,
   return val;
 }
 
-
 /* Return the value for C in char-table TABLE.  Shrink the range *FROM
    and *TO to cover characters (containing C) that have the same value
    as C.  It is not assured that the values of (*FROM - 1) and (*TO +
@@ -386,6 +385,60 @@ char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
   return val;
 }
 
+/* Return the value for C in char-table TABLE.  Shrink the range
+   *FROM and *TO to cover characters (containing C) that have the same
+   value as C.  Should the value for C in TABLE be nil, consult the
+   parent table of TABLE, recursively if necessary.  It is not
+   guaranteed that the values of (*FROM - 1) and (*TO + 1) are
+   different from that of C.  */
+Lisp_Object
+char_table_ref_and_range_with_parents (Lisp_Object table, int c,
+                                       int *from, int *to)
+{
+  Lisp_Object val;
+  Lisp_Object parent, defalt;
+  struct Lisp_Char_Table *tbl;
+
+  if (*to < 0)
+    *to = MAX_CHAR;
+  if (ASCII_CHAR_P (c)
+      && *from <= c
+      && *to >= c)
+    {
+      tbl = XCHAR_TABLE (table);
+      parent = tbl->parent;     /* Added in to try to fix segfault.  2018-02-18. */
+      defalt = tbl->defalt;
+      val = NILP (tbl->ascii)
+        ? defalt /*Qnil*/
+        : sub_char_table_ref_and_range (tbl->ascii, c, from, to, defalt, false);
+      while (NILP (val) && !NILP (parent))
+        {
+          tbl = XCHAR_TABLE (parent);
+          parent = tbl->parent;
+          defalt = tbl->defalt;
+          val = NILP (tbl->ascii)
+            ? defalt /*Qnil*/
+            : sub_char_table_ref_and_range (tbl->ascii, c, from, to, defalt, false);
+        }
+      return val;
+    }
+  else if (!ASCII_CHAR_P (c))
+    {
+      val = char_table_ref_and_range (table, c, from, to);
+      tbl = XCHAR_TABLE (table);
+      while (NILP (val))
+        {
+          parent = tbl->parent;
+          if (NILP (parent))
+            break;
+          val = char_table_ref_and_range (parent, c, from, to);
+          tbl = XCHAR_TABLE (parent);
+        }
+      return val;
+    }
+  else
+    return Qnil;
+}
 
 static void
 sub_char_table_set (Lisp_Object table, int c, Lisp_Object val, bool is_uniprop)
diff --git a/src/insdel.c b/src/insdel.c
index 02e3f41bc9..4016ceb845 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -2170,6 +2170,12 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins)
   ptrdiff_t count = SPECPDL_INDEX ();
   struct rvoe_arg rvoe_arg;
 
+  /* Ensure we invalidate the syntax cache on an actual text change
+     regardless of the settings of inhibit-modification-hooks and
+     after-change-functions. */
+  if ((lenins != lendel)
+      && Ffboundp (Qsyntax_ppss_flush_cache)) /* For bootstrapping. */
+    call1 (Qsyntax_ppss_flush_cache, make_number (charpos));
   if (inhibit_modification_hooks)
     return;
 
diff --git a/src/lisp.h b/src/lisp.h
index a7f0a1d78f..e4f76f4561 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3851,6 +3851,8 @@ extern void r_alloc_inhibit_buffer_relocation (int);
 extern Lisp_Object copy_char_table (Lisp_Object);
 extern Lisp_Object char_table_ref_and_range (Lisp_Object, int,
                                              int *, int *);
+extern Lisp_Object char_table_ref_and_range_with_parents (Lisp_Object, int,
+                                                          int*, int*);
 extern void char_table_set_range (Lisp_Object, int, int, Lisp_Object);
 extern void map_char_table (void (*) (Lisp_Object, Lisp_Object,
                             Lisp_Object),
diff --git a/src/syntax.c b/src/syntax.c
index 52cec23cd7..d81a57cd22 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -178,8 +178,12 @@ static ptrdiff_t find_start_begv;
 static EMACS_INT find_start_modiff;
 
 
+static void check_syntax_table (Lisp_Object);
 static Lisp_Object skip_chars (bool, Lisp_Object, Lisp_Object, bool);
 static Lisp_Object skip_syntaxes (bool, Lisp_Object, Lisp_Object);
+static bool syntax_table_value_range_is_interesting_for_literals (Lisp_Object,
+                                                                  int, int);
+static void break_off_syntax_tables_literal_relations (Lisp_Object);
 static Lisp_Object scan_lists (EMACS_INT, EMACS_INT, EMACS_INT, bool);
 static void scan_sexps_forward (struct lisp_parse_state *,
                                 ptrdiff_t, ptrdiff_t, ptrdiff_t, EMACS_INT,
@@ -687,6 +691,112 @@ prev_char_comend_first (ptrdiff_t pos, ptrdiff_t pos_byte)
   return val;
 }
 
+/* Empty the syntax-ppss cache of every buffer whose syntax table is
+   currently set to TABLE. */
+static void
+empty_syntax_tables_buffers_syntax_caches (Lisp_Object table)
+{
+  Lisp_Object buf, buf_list;
+  struct buffer *current = current_buffer;
+  struct buffer *b;
+
+  buf_list = Fbuffer_list (Qnil);
+  while (!NILP (buf_list))
+    {
+      buf = XCAR (buf_list);
+      b = XBUFFER (buf);
+      if (EQ (BVAR (b, syntax_table), table))
+        {
+          set_buffer_internal_1 (b);
+          call1 (Qsyntax_ppss_flush_cache, make_number (-1));
+        }
+      buf_list = XCDR (buf_list);
+    }
+  set_buffer_internal_1 (current);
+}
+
+#define LITERAL_MASK ((1 << Sstring)            \
+                      | (1 << Sescape)          \
+                      | (1 << Scharquote)       \
+                      | (1 << Scomment)         \
+                      | (1 << Sendcomment)      \
+                      | (1 << Scomment_fence)   \
+                      | (1 << Sstring_fence))
+
+/* The following returns true if ELT (which will be a raw syntax
+   descriptor (see page "Syntax Table Internals" in the Elisp manual)
+   or nil) represents a syntax which is (potentially) relevant to
+   strings or comments.  */
+static bool
+SYNTAB_LITERAL (Lisp_Object elt)
+{
+  int ielt;
+  if (!CONSP (elt))
+    return false;
+  ielt = XINT (XCAR (elt));
+  return (ielt & 0xF0000)       /* a comment flag is set */
+    || ((1 << (ielt & 0xFF)) & LITERAL_MASK); /* One of Sstring, .... */
+}
+
+static
+bool syntax_table_value_is_interesting_for_literals (Lisp_Object val)
+{
+  if (!CONSP (val)
+      || !INTEGERP (XCAR (val)))
+    return false;
+  return SYNTAB_LITERAL (XCAR (val));
+}
+
+/* The text property PROP is having its value VAL at position POS in buffer BUF
+either set or cleared.  If this value is relevant to the syntax of literals,
+reduce the BUF's "syntax cache position" to POS.  */
+void
+check_syntax_cache_for_prop (ptrdiff_t pos, Lisp_Object prop,
+                             Lisp_Object val, Lisp_Object buffer)
+{
+  struct buffer *b;
+  struct buffer *current = current_buffer;
+  Lisp_Object plist;
+
+  if (!BUFFERP (buffer))
+    return;
+  b = XBUFFER (buffer);
+  set_buffer_internal_1 (b);
+  if (pos >= syntax_propertize__done)
+    {
+      set_buffer_internal_1 (current);
+      return;
+    }
+
+  if (EQ (prop, Qcategory)
+      && SYMBOLP (val))
+    {
+      plist = Fsymbol_plist (val);
+      while (CONSP (plist))
+        {
+          prop = XCAR (plist);
+          plist = XCDR (plist);
+          if (!CONSP (plist))
+            {
+              set_buffer_internal_1 (current);
+              return;
+            }
+          val = XCAR (plist);
+          if (EQ (prop, Qsyntax_table))
+            break;
+          plist = XCDR (plist);
+        }
+    }
+  if (EQ (prop, Qsyntax_table)
+      && syntax_table_value_is_interesting_for_literals (val))
+    call1 (Qsyntax_ppss_flush_cache, make_number (pos));
+  set_buffer_internal_1 (current);
+}
+
+/*****************************************************************************
+ *****************************************************************************/
+
+
 /* Check whether charpos FROM is at the end of a comment.
    FROM_BYTE is the bytepos corresponding to FROM.
    Do not move back before STOP.
@@ -989,6 +1099,222 @@ back_comment (ptrdiff_t from, ptrdiff_t from_byte, ptrdiff_t stop,
   return from != comment_end;
 }
 \f
+/* If the two syntax entries OLD_SYN and NEW_SYN would parse strings
+   or comments differently return true, otherwise return nil. */
+static bool
+literally_different (Lisp_Object old_syn, Lisp_Object new_syn)
+{
+  bool old_literality = SYNTAB_LITERAL (old_syn),
+    new_literality = SYNTAB_LITERAL (new_syn);
+  return (old_literality != new_literality)
+    || (old_literality
+        && (!EQ (Fcar (old_syn), Fcar (new_syn))));
+}
+
+/* If there is a character position in the range [START, END] for
+   whose syntaxes in syntax tables OLD and NEW strings or comments
+   might be parsed differently, return the lowest character for which
+   this holds.  Otherwise, return -1.  */
+static int
+syntax_table_ranges_differ_literally_p (Lisp_Object old, Lisp_Object new,
+                                              int start, int end)
+{
+  int old_from, new_from, old_to, new_to;
+  Lisp_Object old_syn = Qnil, new_syn = Qnil; /* Initialise to avoid compiler warnings. */
+
+  new_from = old_from = start;
+  new_to = old_to = -1;
+
+  while ((old_from < end) && (new_from < end))
+    {
+      if (old_from == new_from)
+        {
+          old_syn = char_table_ref_and_range_with_parents (old, old_from,
+                                                           &old_from, &old_to);
+          new_syn = char_table_ref_and_range_with_parents (new, new_from,
+                                                           &new_from, &new_to);
+          if (literally_different (old_syn, new_syn))
+            return old_from;
+          old_from = old_to + 1;
+          new_from = new_to + 1;
+          old_to = -1;
+          new_to = -1;
+        }
+      else if (old_from < new_from)
+        {
+          old_syn = char_table_ref_and_range_with_parents (old, old_from,
+                                                           &old_from, &old_to);
+          if (literally_different (old_syn, new_syn))
+            return old_from;
+          old_from = old_to + 1;
+          old_to = -1;
+        }
+      else
+        {
+          new_syn = char_table_ref_and_range_with_parents (new, new_from,
+                                                           &new_from, &new_to);
+          if (literally_different (old_syn, new_syn))
+            return new_from;
+          new_from = new_to + 1;
+          new_to = -1;
+        }
+    }
+  return -1;
+}
+
+DEFUN ("least-literal-difference-between-syntax-tables",
+       Fleast_literal_difference_between_syntax_tables,
+       Sleast_literal_difference_between_syntax_tables,
+       2, 2, 0,
+       doc: /* Lowest char whose different syntaxes in OLD and NEW parse literals differently.
+               OLD and NEW are syntax tables.  */)
+       (Lisp_Object old, Lisp_Object new)
+{
+  int c;
+
+  check_syntax_table (old);
+  check_syntax_table (new);
+  c = syntax_table_ranges_differ_literally_p (old, new, 0, MAX_CHAR + 1);
+  if (c >= 0)
+    return make_number (c);
+  return Qnil;
+}
+
+/* The next two variables are alists, the key being a syntax table,
+   and the value being a non-empty list of syntax_tables.  When a
+   syntax table B is known to parse strings and comments the same as
+   syntax table A, it will be a member of the value whose key is A in
+   `literally_the_same_sts' (and vice versa).  Similarly, when two
+   syntax tables are known to parse strings and comments differently,
+   there will be entries in `literally_different_sts'. */
+static Lisp_Object literally_the_same_sts, literally_different_sts;
+
+DEFUN ("syntax-tables-literally-different-p",
+       Fsyntax_tables_literally_different_p,
+       Ssyntax_tables_literally_different_p,
+       2, 2, 0,
+       doc: /* Will syntax tables OLD and NEW parse literals differently?
+Return t when OLD and NEW might parse comments and strings differently,
+otherwise nil.  (Use `least-literal-difference-between-syntax-tables'
+to locate a character position where the tables differ.)  */)
+     (Lisp_Object old, Lisp_Object new)
+{
+  Lisp_Object elt;
+
+  check_syntax_table (old);
+  check_syntax_table (new);
+  /* Check to see if there is a cached relationship between the tables. */
+  if (!NILP (Fmemq (new, /*XCHAR_TABLE (old)->extras[0])*/
+                    Fassq (old, literally_the_same_sts))))
+    return Qnil;
+  if (!NILP (Fmemq (new, /*XCHAR_TABLE (old)->extras[1])*/
+                    Fassq (old, literally_different_sts))))
+    return Qt;
+  /* The two tables have no known relationship, so we'll have
+     laboriously to compare them. */
+  if (syntax_table_ranges_differ_literally_p (old, new, 0, MAX_CHAR + 1) >= 0)
+    {
+      /* Mark the "literally different" relationship between the OLD and
+         NEW syntax tables. */
+      elt = Fassq (new, literally_different_sts);
+      if (NILP (elt))
+        literally_different_sts = Fcons (Fcons (new, Fcons (old, Qnil)),
+                                         literally_different_sts);
+      else
+        Fsetcdr (elt, Fcons (old, XCDR (elt)));
+      elt = Fassq (old, literally_different_sts);
+      if (NILP (elt))
+        literally_different_sts = Fcons (Fcons (old, Fcons (new, Qnil)),
+                                         literally_different_sts);
+      else
+        Fsetcdr (elt, Fcons (new, XCDR (elt)));
+      return Qt;
+    }
+  else
+    {
+      /* Mark the "not literally different" relationship between the OLD
+         and NEW syntax tables. */
+      elt = Fassq (new, literally_the_same_sts);
+      if (NILP (elt))
+        literally_the_same_sts = Fcons (Fcons (new, Fcons (old, Qnil)),
+                                        literally_the_same_sts);
+      else
+        Fsetcdr (elt, Fcons (old, XCDR (elt)));
+      elt = Fassq (old, literally_the_same_sts);
+      if (NILP (elt))
+        literally_the_same_sts = Fcons (Fcons (old, Fcons (new, Qnil)),
+                                        literally_the_same_sts);
+      else
+        Fsetcdr (elt, Fcons (new, XCDR (elt)));
+      return Qnil;
+    }
+}
+
+/* If any character in the range [START, END) has an entry in syntax
+   table TABLE which is relevant to literal parsing, return true,
+   else return false. */
+static bool
+syntax_table_value_range_is_interesting_for_literals (Lisp_Object table,
+                                                      int start, int end)
+{
+  int from, to;
+  Lisp_Object syn;
+
+  from = start;
+  to = end;
+  while (from < to)
+    {
+      syn = char_table_ref_and_range_with_parents (table, from, &from, &to);
+      if (SYNTAB_LITERAL (syn))
+        return true;
+      from = to + 1;
+      to = end;
+    }
+  return false;
+}
+
+static void
+break_off_syntax_tables_literal_relations (Lisp_Object table)
+{
+  Lisp_Object remotes_elt;
+  Lisp_Object remotes, keep_remotes;
+  Lisp_Object rem, elt;
+
+  remotes_elt = Fassq (table, literally_the_same_sts);
+  remotes = Fcdr (remotes_elt);
+  keep_remotes = remotes;
+  while (!NILP (remotes))
+    {
+      rem = Fcar (remotes);
+      elt = Fassq (rem, literally_the_same_sts);
+      Fsetcdr (elt, Fdelq (table, Fcdr (elt)));
+      if (NILP (Fcdr (elt)))
+        literally_the_same_sts = Fdelq (elt, literally_the_same_sts);
+      remotes = Fcdr (remotes);
+    }
+  if (!NILP (keep_remotes))
+    literally_the_same_sts = Fdelq (remotes_elt, literally_the_same_sts);
+
+  remotes_elt = Fassq (table, literally_different_sts);
+  remotes = Fcdr (remotes_elt);
+  keep_remotes = remotes;
+  while (!NILP (remotes))
+    {
+      rem = Fcar (remotes);
+      elt = Fassq (rem, literally_different_sts);
+      Fsetcdr (elt, Fdelq (table, Fcdr (elt)));
+      if (NILP (Fcdr (elt)))
+        literally_different_sts = Fdelq (elt, literally_different_sts);
+      remotes = Fcdr (remotes);
+    }
+  if (!NILP (keep_remotes))
+    literally_different_sts = Fdelq (remotes_elt, literally_different_sts);
+}
+
+
+/*****************************************************************************
+ ****************************************************************************/
+
 DEFUN ("syntax-table-p", Fsyntax_table_p, Ssyntax_table_p, 1, 1, 0,
        doc: /* Return t if OBJECT is a syntax table.
 Currently, any char-table counts as a syntax table.  */)
@@ -1057,6 +1383,14 @@ One argument, a syntax table.  */)
 {
   int idx;
   check_syntax_table (table);
+  /* Optimise away the case when we're not changing the table. */
+  if (EQ (BVAR (current_buffer, syntax_table), table))
+    return table;
+  if (!NILP (Fsyntax_table_p (BVAR (current_buffer, syntax_table)))
+      && !NILP (Fsyntax_tables_literally_different_p
+                (BVAR (current_buffer, syntax_table), table))
+      && Ffboundp (Qsyntax_ppss_flush_cache)) /* for bootstrapping. */
+    call1 (Qsyntax_ppss_flush_cache, make_number (-1));
   bset_syntax_table (current_buffer, table);
   /* Indicate that this buffer now has a specified syntax table.  */
   idx = PER_BUFFER_VAR_IDX (syntax_table);
@@ -1274,6 +1608,16 @@ usage: (modify-syntax-entry CHAR NEWENTRY &optional SYNTAX-TABLE)  */)
     check_syntax_table (syntax_table);
 
   newentry = Fstring_to_syntax (newentry);
+  if (SYNTAB_LITERAL (newentry)
+      || (CONSP (c)
+          ? syntax_table_value_range_is_interesting_for_literals
+          (syntax_table, XINT (XCAR(c)), XINT (XCDR (c)))
+          : (SYNTAB_LITERAL (Faref (syntax_table, c)))))
+    {
+      empty_syntax_tables_buffers_syntax_caches (syntax_table);
+      break_off_syntax_tables_literal_relations (syntax_table);
+    }
+
   if (CONSP (c))
     SET_RAW_SYNTAX_ENTRY_RANGE (syntax_table, c, newentry);
   else
@@ -3637,6 +3981,10 @@ init_syntax_once (void)
   /* This has to be done here, before we call Fmake_char_table.  */
   DEFSYM (Qsyntax_table, "syntax-table");
 
+  /* We do not yet have any knowledge of how syntax tables parse literals. */
+  literally_the_same_sts = Qnil;
+  literally_different_sts = Qnil;
+
   /* Create objects which can be shared among syntax tables.  */
   Vsyntax_code_object = make_uninit_vector (Smax);
   for (i = 0; i < Smax; i++)
@@ -3728,6 +4076,9 @@ syms_of_syntax (void)
   staticpro (&gl_state.current_syntax_table);
   staticpro (&gl_state.old_prop);
 
+  staticpro (&literally_the_same_sts);
+  staticpro (&literally_different_sts);
+
   /* Defined in regex.c.  */
   staticpro (&re_match_object);
 
@@ -3752,6 +4103,8 @@ See the info node `(elisp)Syntax Properties' for a description of the
   DEFSYM (Qinternal__syntax_propertize, "internal--syntax-propertize");
   Fmake_variable_buffer_local (intern ("syntax-propertize--done"));
 
+  DEFSYM (Qsyntax_ppss_flush_cache, "syntax-ppss-flush-cache");
+
   words_include_escapes = 0;
   DEFVAR_BOOL ("words-include-escapes", words_include_escapes,
 	       doc: /* Non-nil means `forward-word', etc., should treat escape chars part of words.  */);
@@ -3790,6 +4143,8 @@ In both cases, LIMIT bounds the search. */);
   DEFSYM (Qcomment_end_can_be_escaped, "comment-end-can-be-escaped");
   Fmake_variable_buffer_local (Qcomment_end_can_be_escaped);
 
+  defsubr (&Sleast_literal_difference_between_syntax_tables);
+  defsubr (&Ssyntax_tables_literally_different_p);
   defsubr (&Ssyntax_table_p);
   defsubr (&Ssyntax_table);
   defsubr (&Sstandard_syntax_table);
diff --git a/src/syntax.h b/src/syntax.h
index 2171cbbba4..1771ae4728 100644
--- a/src/syntax.h
+++ b/src/syntax.h
@@ -28,6 +28,10 @@ INLINE_HEADER_BEGIN
 
 extern void update_syntax_table (ptrdiff_t, EMACS_INT, bool, Lisp_Object);
 extern void update_syntax_table_forward (ptrdiff_t, bool, Lisp_Object);
+extern void check_syntax_cache_for_prop (ptrdiff_t, Lisp_Object,
+                                         Lisp_Object, Lisp_Object);
+
+
 
 /* The standard syntax table is stored where it will automatically
    be used in all new buffers.  */
diff --git a/src/textprop.c b/src/textprop.c
index 984f2e6640..cd56d8b12c 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -21,6 +21,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "intervals.h"
+#include "syntax.h"
 #include "buffer.h"
 #include "window.h"
 
@@ -340,6 +341,12 @@ set_properties (Lisp_Object properties, INTERVAL interval, Lisp_Object object)
 	    record_property_change (interval->position, LENGTH (interval),
 				    XCAR (sym), XCAR (value),
 				    object);
+            check_syntax_cache_for_prop
+              (interval->position, XCAR (sym), XCAR (value), object);
+            if (!EQ (property_value (properties, XCAR (sym)), Qunbound))
+              check_syntax_cache_for_prop
+                (interval->position, XCAR (sym),
+                 property_value (properties, XCAR (sym)), object);
 	  }
 
       /* For each new property that has no value at all in the old plist,
@@ -352,6 +359,8 @@ set_properties (Lisp_Object properties, INTERVAL interval, Lisp_Object object)
 	    record_property_change (interval->position, LENGTH (interval),
 				    XCAR (sym), Qnil,
 				    object);
+            check_syntax_cache_for_prop
+                (interval->position, XCAR (sym), XCAR (value), object);
 	  }
     }
 
@@ -406,6 +415,10 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
 	      {
 		record_property_change (i->position, LENGTH (i),
 					sym1, Fcar (this_cdr), object);
+                check_syntax_cache_for_prop
+                    (i->position, sym1, Fcar (this_cdr), object);
+                check_syntax_cache_for_prop
+                    (i->position, sym1, val1, object);
 	      }
 
 	    /* I's property has a different value -- change it */
@@ -442,6 +455,8 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
 	    {
 	      record_property_change (i->position, LENGTH (i),
 				      sym1, Qnil, object);
+              check_syntax_cache_for_prop
+                (i->position, sym1, val1, object);
 	    }
 	  set_interval_plist (i, Fcons (sym1, Fcons (val1, i->plist)));
 	  changed = true;
@@ -475,11 +490,14 @@ remove_properties (Lisp_Object plist, Lisp_Object list, INTERVAL i, Lisp_Object
       /* First, remove the symbol if it's at the head of the list */
       while (CONSP (current_plist) && EQ (sym, XCAR (current_plist)))
 	{
-	  if (BUFFERP (object))
-	    record_property_change (i->position, LENGTH (i),
-				    sym, XCAR (XCDR (current_plist)),
-				    object);
-
+          if (BUFFERP (object))
+            {
+              record_property_change (i->position, LENGTH (i),
+                                      sym, XCAR (XCDR (current_plist)),
+                                      object);
+              check_syntax_cache_for_prop
+                (i->position, sym, XCAR (XCDR (current_plist)), object);
+            }
 	  current_plist = XCDR (XCDR (current_plist));
 	  changed = true;
 	}
@@ -492,8 +510,12 @@ remove_properties (Lisp_Object plist, Lisp_Object list, INTERVAL i, Lisp_Object
 	  if (CONSP (this) && EQ (sym, XCAR (this)))
 	    {
 	      if (BUFFERP (object))
-		record_property_change (i->position, LENGTH (i),
-					sym, XCAR (XCDR (this)), object);
+                {
+                  record_property_change (i->position, LENGTH (i),
+                                          sym, XCAR (XCDR (this)), object);
+                  check_syntax_cache_for_prop
+                    (i->position, sym, XCAR (XCDR (this)), object);
+                }
 
 	      Fsetcdr (XCDR (tail2), XCDR (XCDR (this)));
 	      changed = true;


>         Stefan

-- 
Alan Mackenzie (Nuremberg, Germany).





  reply	other threads:[~2018-03-05  8:42 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-08 15:25 bug#30393: 24.4; cperl-mode: indentation failure paulusm
2018-02-09  1:44 ` Noam Postavsky
     [not found] ` <mailman.8766.1518140709.27995.bug-gnu-emacs@gnu.org>
2018-02-09 17:50   ` Alan Mackenzie
2018-02-10  3:55     ` Noam Postavsky
2018-02-10  8:53     ` Dmitry Gutov
2018-02-10 11:26       ` Alan Mackenzie
2018-02-10 12:08         ` Eli Zaretskii
2018-02-11 12:49           ` Alan Mackenzie
2018-02-11 16:16             ` Eli Zaretskii
2018-02-14 21:00               ` Alan Mackenzie
2018-02-15 17:39                 ` Eli Zaretskii
2018-02-16 11:52                 ` Dmitry Gutov
2018-02-16 17:43                   ` Alan Mackenzie
2018-02-17  2:16                     ` Dmitry Gutov
2018-02-17 10:54                       ` Alan Mackenzie
2018-02-10 14:58         ` Stefan Monnier
2018-02-11 10:36           ` Alan Mackenzie
2018-02-11 22:53             ` Stefan Monnier
2018-02-12 18:38               ` Alan Mackenzie
2018-02-12 20:45                 ` Stefan Monnier
2018-03-05  8:42                   ` Alan Mackenzie [this message]
2018-03-05 16:14                     ` Eli Zaretskii
2018-03-06 18:09                       ` Alan Mackenzie
2018-04-08 10:52                       ` Alan Mackenzie
2018-04-09 18:41                         ` Eli Zaretskii
2018-04-10 17:31                           ` Alan Mackenzie
2018-04-16 19:21                           ` bug#30393: 24.4; cperl-mode: indentation failure - Documentation enhancements Alan Mackenzie
2018-04-19  7:52                             ` Eli Zaretskii
2020-08-22 16:07                               ` Lars Ingebrigtsen
2020-11-03 13:45 ` bug#30393: [PATCH] Add a test to verify that the bug is gone (and a fix for Emacs 26) Harald Jörg
2020-11-03 14:29   ` Lars Ingebrigtsen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180305084255.GA4786@ACM \
    --to=acm@muc.de \
    --cc=30393@debbugs.gnu.org \
    --cc=dgutov@yandex.ru \
    --cc=monnier@IRO.UMontreal.CA \
    --cc=npostavs@users.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).