From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.bugs Subject: bug#30393: 24.4; cperl-mode: indentation failure Date: Mon, 5 Mar 2018 08:42:55 +0000 Message-ID: <20180305084255.GA4786@ACM> References: <20180208152552.GL13340@hodi> <20180209175040.63536.qmail@mail.muc.de> <3331f80a-c5aa-5cb9-8088-0a88888bdaca@yandex.ru> <20180210112654.GA4537@ACM> <20180211103610.GA4515@ACM> <20180212183800.GA5601@ACM> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: blaine.gmane.org 1520240348 31576 195.159.176.226 (5 Mar 2018 08:59:08 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 5 Mar 2018 08:59:08 +0000 (UTC) User-Agent: Mutt/1.7.2 (2016-11-26) Cc: 30393@debbugs.gnu.org, Dmitry Gutov , Noam Postavsky To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Mon Mar 05 09:59:03 2018 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eslxT-0007GJ-4b for geb-bug-gnu-emacs@m.gmane.org; Mon, 05 Mar 2018 09:58:59 +0100 Original-Received: from localhost ([::1]:47969 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eslzV-0006nt-Nz for geb-bug-gnu-emacs@m.gmane.org; Mon, 05 Mar 2018 04:01:05 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:40237) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eslxa-0004re-6f for bug-gnu-emacs@gnu.org; Mon, 05 Mar 2018 03:59:09 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eslxW-0002Wq-S4 for bug-gnu-emacs@gnu.org; Mon, 05 Mar 2018 03:59:06 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:37183) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eslxW-0002Vm-K7 for bug-gnu-emacs@gnu.org; Mon, 05 Mar 2018 03:59:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1eslxW-0007Zd-8d for bug-gnu-emacs@gnu.org; Mon, 05 Mar 2018 03:59:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 05 Mar 2018 08:59:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 30393 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 30393-submit@debbugs.gnu.org id=B30393.152024028329041 (code B ref 30393); Mon, 05 Mar 2018 08:59:02 +0000 Original-Received: (at 30393) by debbugs.gnu.org; 5 Mar 2018 08:58:03 +0000 Original-Received: from localhost ([127.0.0.1]:45080 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eslwX-0007Y2-AF for submit@debbugs.gnu.org; Mon, 05 Mar 2018 03:58:02 -0500 Original-Received: from colin.muc.de ([193.149.48.1]:14723 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1eslwT-0007Xr-L4 for 30393@debbugs.gnu.org; Mon, 05 Mar 2018 03:57:58 -0500 Original-Received: (qmail 80724 invoked by uid 3782); 5 Mar 2018 08:57:56 -0000 Original-Received: from acm.muc.de (p548C79D6.dip0.t-ipconnect.de [84.140.121.214]) by colin.muc.de (tmda-ofmipd) with ESMTP; Mon, 05 Mar 2018 09:57:55 +0100 Original-Received: (qmail 5896 invoked by uid 1000); 5 Mar 2018 08:42:55 -0000 Content-Disposition: inline In-Reply-To: X-Delivery-Agent: TMDA/1.1.12 (Macallan) X-Primary-Address: acm@muc.de X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:143921 Archived-At: 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; } +/* 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 . */ #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).