428
+ − 1 /* Routines to compute the current syntactic context, for font-lock mode.
+ − 2 Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+ − 3 Copyright (C) 1995 Sun Microsystems, Inc.
1296
+ − 4 Copyright (C) 2002, 2003 Ben Wing.
428
+ − 5
+ − 6 This file is part of XEmacs.
+ − 7
+ − 8 XEmacs is free software; you can redistribute it and/or modify it
+ − 9 under the terms of the GNU General Public License as published by the
+ − 10 Free Software Foundation; either version 2, or (at your option) any
+ − 11 later version.
+ − 12
+ − 13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ − 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ − 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ − 16 for more details.
+ − 17
+ − 18 You should have received a copy of the GNU General Public License
+ − 19 along with XEmacs; see the file COPYING. If not, write to
+ − 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ − 21 Boston, MA 02111-1307, USA. */
+ − 22
+ − 23 /* Synched up with: Not in FSF. */
+ − 24
+ − 25 /* This code computes the syntactic context of the current point, that is,
+ − 26 whether point is within a comment, a string, what have you. It does
+ − 27 this by picking a point "known" to be outside of any syntactic constructs
+ − 28 and moving forward, examining the syntax of each character.
+ − 29
+ − 30 Two caches are used: one caches the last point computed, and the other
+ − 31 caches the last point at the beginning of a line. This makes there
+ − 32 be little penalty for moving left-to-right on a line a character at a
+ − 33 time; makes starting over on a line be cheap; and makes random-accessing
+ − 34 within a line relatively cheap.
+ − 35
+ − 36 When we move to a different line farther down in the file (but within the
+ − 37 current top-level form) we simply continue computing forward. If we move
+ − 38 backward more than a line, or move beyond the end of the current tlf, or
+ − 39 switch buffers, then we call `beginning-of-defun' and start over from
+ − 40 there.
+ − 41
+ − 42 #### We should really rewrite this to keep extents over the buffer
+ − 43 that hold the current syntactic information. This would be a big win.
+ − 44 This way there would be no guessing or incorrect results.
+ − 45 */
+ − 46
838
+ − 47 #include <config.h>
826
+ − 48
838
+ − 49 #ifdef USE_C_FONT_LOCK
+ − 50
428
+ − 51 #include "lisp.h"
+ − 52
+ − 53 #include "buffer.h"
+ − 54 #include "insdel.h"
+ − 55 #include "syntax.h"
+ − 56
+ − 57 Lisp_Object Qcomment;
+ − 58 Lisp_Object Qblock_comment;
+ − 59 Lisp_Object Qbeginning_of_defun;
+ − 60
+ − 61 enum syntactic_context
+ − 62 {
+ − 63 context_none,
+ − 64 context_string,
+ − 65 context_comment,
460
+ − 66 context_block_comment,
+ − 67 context_generic_comment,
+ − 68 context_generic_string
428
+ − 69 };
+ − 70
+ − 71 enum block_comment_context
+ − 72 {
+ − 73 ccontext_none,
+ − 74 ccontext_start1,
+ − 75 ccontext_start2,
+ − 76 ccontext_end1
+ − 77 };
+ − 78
+ − 79 enum comment_style
+ − 80 {
+ − 81 comment_style_none,
+ − 82 comment_style_a,
+ − 83 comment_style_b
+ − 84 };
+ − 85
+ − 86 struct context_cache
+ − 87 {
665
+ − 88 Charbpos start_point; /* beginning of defun */
+ − 89 Charbpos cur_point; /* cache location */
+ − 90 Charbpos end_point; /* end of defun */
428
+ − 91 struct buffer *buffer; /* does this need to be staticpro'd? */
+ − 92 enum syntactic_context context; /* single-char-syntax state */
+ − 93 enum block_comment_context ccontext; /* block-comment state */
+ − 94 enum comment_style style; /* which comment group */
867
+ − 95 Ichar scontext; /* active string delimiter */
428
+ − 96 int depth; /* depth in parens */
+ − 97 int backslash_p; /* just read a backslash */
+ − 98 int needs_its_head_reexamined; /* we're apparently outside of
+ − 99 a top level form, and far away
+ − 100 from it. This is a bad situation
+ − 101 because it will lead to constant
+ − 102 slowness as we keep going way
+ − 103 back to that form and moving
+ − 104 forward again. In this case,
+ − 105 we try to compute a "pseudo-
+ − 106 top-level-form" where the
+ − 107 depth is 0 and the context
+ − 108 is none at both ends. */
+ − 109 };
+ − 110
+ − 111 /* We have two caches; one for the current point and one for
+ − 112 the beginning of line. We used to rely on the caller to
+ − 113 tell us when to invalidate them, but now we do it ourselves;
+ − 114 it lets us be smarter. */
+ − 115
+ − 116 static struct context_cache context_cache;
+ − 117
+ − 118 static struct context_cache bol_context_cache;
+ − 119
+ − 120 int font_lock_debug;
+ − 121
+ − 122 #define reset_context_cache(cc) memset (cc, 0, sizeof (struct context_cache))
+ − 123
+ − 124 /* This function is called from signal_after_change() to tell us when
+ − 125 textual changes are made so we can flush our caches when necessary.
+ − 126
+ − 127 We make the following somewhat heuristic assumptions:
+ − 128
+ − 129 (remember that current_point is always >= start_point, but may be
+ − 130 less than or greater than end_point (we might not be inside any
+ − 131 top-level form)).
+ − 132
+ − 133 1) Textual changes before the beginning of the current top-level form
+ − 134 don't affect anything; all we need to do is offset the caches
+ − 135 appropriately.
+ − 136 2) Textual changes right at the beginning of the current
+ − 137 top-level form messes things up and requires that we flush
+ − 138 the caches.
+ − 139 3) Textual changes after the beginning of the current top-level form
+ − 140 and before one or both or the caches invalidates the corresponding
+ − 141 cache(s).
+ − 142 4) Textual changes after the caches and before the end of the
+ − 143 current top-level form don't affect anything; all we need to do is
+ − 144 offset the caches appropriately.
+ − 145 5) Textual changes right at the end of the current top-level form
+ − 146 necessitate recomputing that end value.
+ − 147 6) Textual changes after the end of the current top-level form
+ − 148 are ignored. */
+ − 149
+ − 150
+ − 151 void
665
+ − 152 font_lock_maybe_update_syntactic_caches (struct buffer *buf, Charbpos start,
+ − 153 Charbpos orig_end, Charbpos new_end)
428
+ − 154 {
+ − 155 /* Note: either both context_cache and bol_context_cache are valid and
+ − 156 point to the same buffer, or both are invalid. If we have to
+ − 157 invalidate just context_cache, we recopy it from bol_context_cache.
+ − 158 */
+ − 159 if (context_cache.buffer != buf)
+ − 160 /* caches don't apply */
+ − 161 return;
+ − 162 /* NOTE: The order of the if statements below is important. If you
+ − 163 change them around unthinkingly, you will probably break something. */
+ − 164 if (orig_end <= context_cache.start_point - 1)
+ − 165 {
+ − 166 /* case 1: before the beginning of the current top-level form */
+ − 167 Charcount diff = new_end - orig_end;
+ − 168 if (font_lock_debug)
+ − 169 stderr_out ("font-lock; Case 1\n");
+ − 170 context_cache.start_point += diff;
+ − 171 context_cache.cur_point += diff;
+ − 172 context_cache.end_point += diff;
+ − 173 bol_context_cache.start_point += diff;
+ − 174 bol_context_cache.cur_point += diff;
+ − 175 bol_context_cache.end_point += diff;
+ − 176 }
+ − 177 else if (start <= context_cache.start_point)
+ − 178 {
+ − 179 if (font_lock_debug)
+ − 180 stderr_out ("font-lock; Case 2\n");
+ − 181 /* case 2: right at the current top-level form (paren that starts
+ − 182 top level form got deleted or moved away from the newline it
+ − 183 was touching) */
+ − 184 reset_context_cache (&context_cache);
+ − 185 reset_context_cache (&bol_context_cache);
+ − 186 }
+ − 187 /* OK, now we know that the start is after the beginning of the
+ − 188 current top-level form. */
+ − 189 else if (start < bol_context_cache.cur_point)
+ − 190 {
+ − 191 if (font_lock_debug)
+ − 192 stderr_out ("font-lock; Case 3 (1)\n");
+ − 193 /* case 3: after the beginning of the current top-level form
+ − 194 and before both of the caches */
+ − 195 reset_context_cache (&context_cache);
+ − 196 reset_context_cache (&bol_context_cache);
+ − 197 }
+ − 198 else if (start < context_cache.cur_point)
+ − 199 {
+ − 200 if (font_lock_debug)
+ − 201 stderr_out ("font-lock; Case 3 (2)\n");
+ − 202 /* case 3: but only need to invalidate one cache */
+ − 203 context_cache = bol_context_cache;
+ − 204 }
+ − 205 /* OK, now we know that the start is after the caches. */
+ − 206 else if (start >= context_cache.end_point)
+ − 207 {
+ − 208 if (font_lock_debug)
+ − 209 stderr_out ("font-lock; Case 6\n");
+ − 210 /* case 6: after the end of the current top-level form
+ − 211 and after the caches. */
+ − 212 }
+ − 213 else if (orig_end <= context_cache.end_point - 2)
+ − 214 {
+ − 215 /* case 4: after the caches and before the end of the
+ − 216 current top-level form */
+ − 217 Charcount diff = new_end - orig_end;
+ − 218 if (font_lock_debug)
+ − 219 stderr_out ("font-lock; Case 4\n");
+ − 220 context_cache.end_point += diff;
+ − 221 bol_context_cache.end_point += diff;
+ − 222 }
+ − 223 else
+ − 224 {
+ − 225 if (font_lock_debug)
+ − 226 stderr_out ("font-lock; Case 5\n");
+ − 227 /* case 5: right at the end of the current top-level form */
+ − 228 context_cache.end_point = context_cache.start_point - 1;
+ − 229 bol_context_cache.end_point = context_cache.start_point - 1;
+ − 230 }
+ − 231 }
+ − 232
+ − 233 /* This function is called from Fkill_buffer(). */
+ − 234
+ − 235 void
+ − 236 font_lock_buffer_was_killed (struct buffer *buf)
+ − 237 {
+ − 238 if (context_cache.buffer == buf)
+ − 239 {
+ − 240 reset_context_cache (&context_cache);
+ − 241 reset_context_cache (&bol_context_cache);
+ − 242 }
+ − 243 }
+ − 244
665
+ − 245 static Charbpos
+ − 246 beginning_of_defun (struct buffer *buf, Charbpos pt)
428
+ − 247 {
+ − 248 /* This function can GC */
665
+ − 249 Charbpos opt = BUF_PT (buf);
428
+ − 250 if (pt == BUF_BEGV (buf))
+ − 251 return pt;
+ − 252 BUF_SET_PT (buf, pt);
+ − 253 /* There used to be some kludginess to call c++-beginning-of-defun
+ − 254 if we're in C++ mode. There's no point in this any more;
+ − 255 we're using cc-mode. If you really want to get the old c++
+ − 256 mode working, fix it rather than the C code. */
+ − 257 call0_in_buffer (buf, Qbeginning_of_defun);
+ − 258 pt = BUF_PT (buf);
+ − 259 BUF_SET_PT (buf, opt);
+ − 260 return pt;
+ − 261 }
+ − 262
665
+ − 263 static Charbpos
+ − 264 end_of_defun (struct buffer *buf, Charbpos pt)
428
+ − 265 {
+ − 266 Lisp_Object retval = scan_lists (buf, pt, 1, 0, 0, 1);
+ − 267 if (NILP (retval))
+ − 268 return BUF_ZV (buf);
+ − 269 else
+ − 270 return XINT (retval);
+ − 271 }
+ − 272
+ − 273 /* Set up context_cache for attempting to determine the syntactic context
+ − 274 in buffer BUF at point PT. */
+ − 275
+ − 276 static void
665
+ − 277 setup_context_cache (struct buffer *buf, Charbpos pt)
428
+ − 278 {
+ − 279 int recomputed_start_point = 0;
+ − 280 /* This function can GC */
+ − 281 if (context_cache.buffer != buf || pt < context_cache.start_point)
+ − 282 {
+ − 283 start_over:
+ − 284 if (font_lock_debug)
+ − 285 stderr_out ("reset context cache\n");
+ − 286 /* OK, completely invalid. */
+ − 287 reset_context_cache (&context_cache);
+ − 288 reset_context_cache (&bol_context_cache);
+ − 289 }
+ − 290 if (!context_cache.buffer)
+ − 291 {
+ − 292 /* Need to recompute the start point. */
+ − 293 if (font_lock_debug)
+ − 294 stderr_out ("recompute start\n");
+ − 295 context_cache.start_point = beginning_of_defun (buf, pt);
+ − 296 recomputed_start_point = 1;
+ − 297 bol_context_cache.start_point = context_cache.start_point;
+ − 298 bol_context_cache.buffer = context_cache.buffer = buf;
+ − 299 }
+ − 300 if (context_cache.end_point < context_cache.start_point)
+ − 301 {
+ − 302 /* Need to recompute the end point. */
+ − 303 if (font_lock_debug)
+ − 304 stderr_out ("recompute end\n");
+ − 305 context_cache.end_point = end_of_defun (buf, context_cache.start_point);
+ − 306 bol_context_cache.end_point = context_cache.end_point;
+ − 307 }
+ − 308 if (bol_context_cache.cur_point == 0 ||
+ − 309 pt < bol_context_cache.cur_point)
+ − 310 {
+ − 311 if (font_lock_debug)
+ − 312 stderr_out ("reset to start\n");
+ − 313 if (pt > context_cache.end_point
+ − 314 /* 3000 is some arbitrary delta but seems reasonable;
+ − 315 about the size of a reasonable function */
+ − 316 && pt - context_cache.end_point > 3000)
+ − 317 /* If we're far past the end of the top level form,
+ − 318 don't trust it; recompute it. */
+ − 319 {
+ − 320 /* But don't get in an infinite loop doing this.
+ − 321 If we're really far past the end of the top level
+ − 322 form, try to compute a pseudo-top-level form. */
+ − 323 if (recomputed_start_point)
+ − 324 context_cache.needs_its_head_reexamined = 1;
+ − 325 else
+ − 326 /* force recomputation */
+ − 327 goto start_over;
+ − 328 }
+ − 329 /* Go to the nearest end of the top-level form that's before
+ − 330 us. */
+ − 331 if (pt > context_cache.end_point)
+ − 332 pt = context_cache.end_point;
+ − 333 else
+ − 334 pt = context_cache.start_point;
+ − 335 /* Reset current point to start of buffer. */
+ − 336 context_cache.cur_point = pt;
+ − 337 context_cache.context = context_none;
+ − 338 context_cache.ccontext = ccontext_none;
+ − 339 context_cache.style = comment_style_none;
+ − 340 context_cache.scontext = '\000';
+ − 341 context_cache.depth = 0;
460
+ − 342 /* #### shouldn't this be checking the character's syntax instead of
+ − 343 explicitly testing for backslash characters? */
428
+ − 344 context_cache.backslash_p = ((pt > 1) &&
+ − 345 (BUF_FETCH_CHAR (buf, pt - 1) == '\\'));
+ − 346 /* Note that the BOL context cache may not be at the beginning
+ − 347 of the line, but that should be OK, nobody's checking. */
+ − 348 bol_context_cache = context_cache;
+ − 349 return;
+ − 350 }
+ − 351 else if (pt < context_cache.cur_point)
+ − 352 {
+ − 353 if (font_lock_debug)
+ − 354 stderr_out ("reset to bol\n");
+ − 355 /* bol cache is OK but current_cache is not. */
+ − 356 context_cache = bol_context_cache;
+ − 357 return;
+ − 358 }
+ − 359 else if (pt <= context_cache.end_point)
+ − 360 {
+ − 361 if (font_lock_debug)
+ − 362 stderr_out ("everything is OK\n");
+ − 363 /* in same top-level form. */
+ − 364 return;
+ − 365 }
+ − 366 {
+ − 367 /* OK, we're past the end of the top-level form. */
665
+ − 368 Charbpos maxpt = max (context_cache.end_point, context_cache.cur_point);
428
+ − 369 #if 0
+ − 370 int shortage;
+ − 371 #endif
+ − 372
+ − 373 if (font_lock_debug)
+ − 374 stderr_out ("past end\n");
+ − 375 if (pt <= maxpt)
+ − 376 /* OK, fine. */
+ − 377 return;
+ − 378 #if 0
442
+ − 379 /* This appears to cause huge slowdowns in files which have no
+ − 380 top-level forms.
428
+ − 381
+ − 382 In any case, it's not really necessary that we know for
+ − 383 sure the top-level form we're in; if we're in a form
+ − 384 but the form we have recorded is the previous one,
+ − 385 it will be OK. */
+ − 386
+ − 387 scan_buffer (buf, '\n', maxpt, pt, 1, &shortage, 1);
+ − 388 if (!shortage)
+ − 389 /* If there was a newline in the region past the known universe,
+ − 390 we might be inside another top-level form, so start over.
+ − 391 Otherwise, we're outside of any top-level forms and we know
+ − 392 the one directly before us, so it's OK. */
+ − 393 goto start_over;
+ − 394 #endif
+ − 395 }
+ − 396 }
+ − 397
647
+ − 398 /* You'd think it wouldn't be necessary to cast something to the type
+ − 399 it's already defined is, but if you're GCC, you apparently think
+ − 400 differently */
460
+ − 401 #define SYNTAX_START_STYLE(c1, c2) \
647
+ − 402 ((enum comment_style) \
460
+ − 403 (SYNTAX_CODES_MATCH_START_P (c1, c2, SYNTAX_COMMENT_STYLE_A) ? \
428
+ − 404 comment_style_a : \
460
+ − 405 SYNTAX_CODES_MATCH_START_P (c1, c2, SYNTAX_COMMENT_STYLE_B) ? \
428
+ − 406 comment_style_b : \
647
+ − 407 comment_style_none))
428
+ − 408
460
+ − 409 #define SYNTAX_END_STYLE(c1, c2) \
647
+ − 410 ((enum comment_style) \
+ − 411 (SYNTAX_CODES_MATCH_END_P (c1, c2, SYNTAX_COMMENT_STYLE_A) ? \
460
+ − 412 comment_style_a : \
+ − 413 SYNTAX_CODES_MATCH_END_P (c1, c2, SYNTAX_COMMENT_STYLE_B) ? \
+ − 414 comment_style_b : \
647
+ − 415 comment_style_none))
460
+ − 416
+ − 417 #define SINGLE_SYNTAX_STYLE(c) \
647
+ − 418 ((enum comment_style) \
+ − 419 (SYNTAX_CODE_MATCHES_1CHAR_P (c, SYNTAX_COMMENT_STYLE_A) ? \
428
+ − 420 comment_style_a : \
460
+ − 421 SYNTAX_CODE_MATCHES_1CHAR_P (c, SYNTAX_COMMENT_STYLE_B) ? \
428
+ − 422 comment_style_b : \
647
+ − 423 comment_style_none))
428
+ − 424
+ − 425 /* Set up context_cache for position PT in BUF. */
+ − 426
+ − 427 static void
665
+ − 428 find_context (struct buffer *buf, Charbpos pt)
428
+ − 429 {
+ − 430 /* This function can GC */
867
+ − 431 Ichar prev_c, c;
460
+ − 432 int prev_syncode, syncode;
665
+ − 433 Charbpos target = pt;
826
+ − 434 struct syntax_cache *scache;
844
+ − 435 int spec = specpdl_depth ();
+ − 436
+ − 437 /* If we are narrowed, we will get confused. In fact, we are quite often
+ − 438 narrowed when this function is called. */
+ − 439 if (BUF_BEGV (buf) != BUF_BEG (buf) || BUF_ZV (buf) != BUF_Z (buf))
+ − 440 {
+ − 441 record_unwind_protect (save_restriction_restore,
+ − 442 save_restriction_save (buf));
+ − 443 Fwiden (wrap_buffer (buf));
+ − 444 }
826
+ − 445
428
+ − 446 setup_context_cache (buf, pt);
+ − 447 pt = context_cache.cur_point;
+ − 448
842
+ − 449 scache = setup_buffer_syntax_cache (buf, pt > BUF_BEGV (buf) ? pt - 1 : pt,
+ − 450 1);
428
+ − 451 if (pt > BUF_BEGV (buf))
460
+ − 452 {
+ − 453 c = BUF_FETCH_CHAR (buf, pt - 1);
826
+ − 454 syncode = SYNTAX_CODE_FROM_CACHE (scache, c);
460
+ − 455 }
428
+ − 456 else
460
+ − 457 {
+ − 458 c = '\n'; /* to get bol_context_cache at point-min */
+ − 459 syncode = Swhitespace;
+ − 460 }
428
+ − 461
+ − 462 for (; pt < target; pt++, context_cache.cur_point = pt)
+ − 463 {
+ − 464 if (context_cache.needs_its_head_reexamined)
+ − 465 {
+ − 466 if (context_cache.depth == 0
+ − 467 && context_cache.context == context_none)
+ − 468 {
+ − 469 /* We've found an anchor spot.
+ − 470 Try to put the start of defun within 6000 chars of
+ − 471 the target, and the end of defun as close as possible.
+ − 472 6000 is also arbitrary but tries to strike a balance
+ − 473 between two conflicting pulls when dealing with a
+ − 474 file that has lots of stuff sitting outside of a top-
+ − 475 level form:
+ − 476
+ − 477 a) If you move past the start of defun, you will
+ − 478 have to recompute defun, which in this case
+ − 479 means that start of defun goes all the way back
+ − 480 to the beginning of the file; so you want
+ − 481 to set start of defun a ways back from the
+ − 482 current point.
+ − 483 b) If you move a line backwards but within start of
+ − 484 defun, you have to move back to start of defun;
+ − 485 so you don't want start of defun too far from
+ − 486 the current point.
+ − 487 */
+ − 488 if (target - context_cache.start_point > 6000)
+ − 489 context_cache.start_point = pt;
+ − 490 context_cache.end_point = pt;
+ − 491 bol_context_cache = context_cache;
+ − 492 }
+ − 493 }
+ − 494
826
+ − 495 UPDATE_SYNTAX_CACHE_FORWARD (scache, pt);
428
+ − 496 prev_c = c;
460
+ − 497 prev_syncode = syncode;
428
+ − 498 c = BUF_FETCH_CHAR (buf, pt);
826
+ − 499 syncode = SYNTAX_CODE_FROM_CACHE (scache, c);
428
+ − 500
+ − 501 if (prev_c == '\n')
+ − 502 bol_context_cache = context_cache;
+ − 503
+ − 504 if (context_cache.backslash_p)
+ − 505 {
+ − 506 context_cache.backslash_p = 0;
+ − 507 continue;
+ − 508 }
+ − 509
826
+ − 510 switch (SYNTAX_FROM_CODE (syncode))
428
+ − 511 {
+ − 512 case Sescape:
+ − 513 context_cache.backslash_p = 1;
+ − 514 break;
+ − 515
+ − 516 case Sopen:
+ − 517 if (context_cache.context == context_none)
+ − 518 context_cache.depth++;
+ − 519 break;
+ − 520
+ − 521 case Sclose:
+ − 522 if (context_cache.context == context_none)
+ − 523 context_cache.depth--;
+ − 524 break;
+ − 525
+ − 526 case Scomment:
+ − 527 if (context_cache.context == context_none)
+ − 528 {
+ − 529 context_cache.context = context_comment;
+ − 530 context_cache.ccontext = ccontext_none;
460
+ − 531 context_cache.style = SINGLE_SYNTAX_STYLE (syncode);
2500
+ − 532 if (context_cache.style == comment_style_none) ABORT ();
428
+ − 533 }
+ − 534 break;
+ − 535
+ − 536 case Sendcomment:
460
+ − 537 if (context_cache.style != SINGLE_SYNTAX_STYLE (syncode))
428
+ − 538 ;
+ − 539 else if (context_cache.context == context_comment)
+ − 540 {
+ − 541 context_cache.context = context_none;
+ − 542 context_cache.style = comment_style_none;
+ − 543 }
+ − 544 else if (context_cache.context == context_block_comment &&
+ − 545 (context_cache.ccontext == ccontext_start2 ||
+ − 546 context_cache.ccontext == ccontext_end1))
+ − 547 {
+ − 548 context_cache.context = context_none;
+ − 549 context_cache.ccontext = ccontext_none;
+ − 550 context_cache.style = comment_style_none;
+ − 551 }
+ − 552 break;
+ − 553
+ − 554 case Sstring:
+ − 555 {
+ − 556 if (context_cache.context == context_string &&
+ − 557 context_cache.scontext == c)
+ − 558 {
+ − 559 context_cache.context = context_none;
+ − 560 context_cache.scontext = '\000';
+ − 561 }
+ − 562 else if (context_cache.context == context_none)
+ − 563 {
460
+ − 564 Lisp_Object stringtermobj =
1296
+ − 565 syntax_match (scache->syntax_table, c);
867
+ − 566 Ichar stringterm;
428
+ − 567
+ − 568 if (CHARP (stringtermobj))
+ − 569 stringterm = XCHAR (stringtermobj);
+ − 570 else
+ − 571 stringterm = c;
+ − 572 context_cache.context = context_string;
+ − 573 context_cache.scontext = stringterm;
+ − 574 context_cache.ccontext = ccontext_none;
+ − 575 }
+ − 576 break;
+ − 577 }
460
+ − 578
+ − 579 case Scomment_fence:
+ − 580 {
+ − 581 if (context_cache.context == context_generic_comment)
+ − 582 {
+ − 583 context_cache.context = context_none;
+ − 584 }
+ − 585 else if (context_cache.context == context_none)
+ − 586 {
+ − 587 context_cache.context = context_generic_comment;
+ − 588 context_cache.ccontext = ccontext_none;
+ − 589 }
+ − 590 break;
+ − 591 }
+ − 592
+ − 593 case Sstring_fence:
+ − 594 {
+ − 595 if (context_cache.context == context_generic_string)
+ − 596 {
+ − 597 context_cache.context = context_none;
+ − 598 }
+ − 599 else if (context_cache.context == context_none)
+ − 600 {
+ − 601 context_cache.context = context_generic_string;
+ − 602 context_cache.ccontext = ccontext_none;
+ − 603 }
+ − 604 break;
+ − 605 }
+ − 606
428
+ − 607 default:
+ − 608 ;
+ − 609 }
+ − 610
+ − 611 /* That takes care of the characters with manifest syntax.
+ − 612 Now we've got to hack multi-char sequences that start
+ − 613 and end block comments.
+ − 614 */
460
+ − 615 if ((SYNTAX_CODE_COMMENT_BITS (syncode) &
428
+ − 616 SYNTAX_SECOND_CHAR_START) &&
+ − 617 context_cache.context == context_none &&
+ − 618 context_cache.ccontext == ccontext_start1 &&
460
+ − 619 SYNTAX_CODES_START_P (prev_syncode, syncode) /* the two chars match */
428
+ − 620 )
+ − 621 {
+ − 622 context_cache.ccontext = ccontext_start2;
460
+ − 623 context_cache.style = SYNTAX_START_STYLE (prev_syncode, syncode);
2500
+ − 624 if (context_cache.style == comment_style_none) ABORT ();
428
+ − 625 }
460
+ − 626 else if ((SYNTAX_CODE_COMMENT_BITS (syncode) &
428
+ − 627 SYNTAX_FIRST_CHAR_START) &&
+ − 628 context_cache.context == context_none &&
+ − 629 (context_cache.ccontext == ccontext_none ||
+ − 630 context_cache.ccontext == ccontext_start1))
+ − 631 {
+ − 632 context_cache.ccontext = ccontext_start1;
+ − 633 context_cache.style = comment_style_none; /* should be this already*/
+ − 634 }
460
+ − 635 else if ((SYNTAX_CODE_COMMENT_BITS (syncode) &
428
+ − 636 SYNTAX_SECOND_CHAR_END) &&
647
+ − 637 context_cache.context ==
+ − 638 (enum syntactic_context) context_block_comment &&
+ − 639 context_cache.ccontext ==
+ − 640 (enum block_comment_context) ccontext_end1 &&
460
+ − 641 SYNTAX_CODES_END_P (prev_syncode, syncode) &&
428
+ − 642 /* the two chars match */
+ − 643 context_cache.style ==
460
+ − 644 SYNTAX_END_STYLE (prev_syncode, syncode)
428
+ − 645 )
+ − 646 {
+ − 647 context_cache.context = context_none;
+ − 648 context_cache.ccontext = ccontext_none;
+ − 649 context_cache.style = comment_style_none;
+ − 650 }
460
+ − 651 else if ((SYNTAX_CODE_COMMENT_BITS (syncode) &
428
+ − 652 SYNTAX_FIRST_CHAR_END) &&
+ − 653 context_cache.context == context_block_comment &&
460
+ − 654 context_cache.style == SINGLE_SYNTAX_STYLE (syncode) &&
428
+ − 655 (context_cache.ccontext == ccontext_start2 ||
+ − 656 context_cache.ccontext == ccontext_end1))
460
+ − 657 /* #### is it right to check for end1 here??
+ − 658 yes, because this might be a repetition of the first char
+ − 659 of a comment-end sequence. ie, '/xxx foo xxx/' or
+ − 660 '/xxx foo x/', where 'x' = '*' -- mct */
428
+ − 661 {
2500
+ − 662 if (context_cache.style == comment_style_none) ABORT ();
428
+ − 663 context_cache.ccontext = ccontext_end1;
+ − 664 }
+ − 665
+ − 666 else if (context_cache.ccontext == ccontext_start1)
+ − 667 {
2500
+ − 668 if (context_cache.context != context_none) ABORT ();
428
+ − 669 context_cache.ccontext = ccontext_none;
+ − 670 }
+ − 671 else if (context_cache.ccontext == ccontext_end1)
+ − 672 {
2500
+ − 673 if (context_cache.context != context_block_comment) ABORT ();
428
+ − 674 context_cache.context = context_none;
+ − 675 context_cache.ccontext = ccontext_start2;
+ − 676 }
+ − 677
+ − 678 if (context_cache.ccontext == ccontext_start2 &&
+ − 679 context_cache.context == context_none)
+ − 680 {
+ − 681 context_cache.context = context_block_comment;
2500
+ − 682 if (context_cache.style == comment_style_none) ABORT ();
428
+ − 683 }
+ − 684 else if (context_cache.ccontext == ccontext_none &&
+ − 685 context_cache.context == context_block_comment)
+ − 686 {
+ − 687 context_cache.context = context_none;
+ − 688 }
+ − 689 }
+ − 690
+ − 691 context_cache.needs_its_head_reexamined = 0;
844
+ − 692 unbind_to (spec);
428
+ − 693 }
+ − 694
+ − 695 static Lisp_Object
+ − 696 context_to_symbol (enum syntactic_context context)
+ − 697 {
+ − 698 switch (context)
+ − 699 {
460
+ − 700 case context_none: return Qnil;
+ − 701 case context_string: return Qstring;
+ − 702 case context_comment: return Qcomment;
+ − 703 case context_block_comment: return Qblock_comment;
+ − 704 case context_generic_comment: return Qblock_comment;
+ − 705 case context_generic_string: return Qstring;
2500
+ − 706 default: ABORT (); return Qnil; /* suppress compiler warning */
428
+ − 707 }
+ − 708 }
+ − 709
+ − 710 DEFUN ("buffer-syntactic-context", Fbuffer_syntactic_context, 0, 1, 0, /*
+ − 711 Return the syntactic context of BUFFER at point.
+ − 712 If BUFFER is nil or omitted, the current buffer is assumed.
+ − 713 The returned value is one of the following symbols:
+ − 714
+ − 715 nil ; meaning no special interpretation
+ − 716 string ; meaning point is within a string
+ − 717 comment ; meaning point is within a line comment
+ − 718 block-comment ; meaning point is within a block comment
+ − 719
+ − 720 See also the function `buffer-syntactic-context-depth', which returns
+ − 721 the current nesting-depth within all parenthesis-syntax delimiters
+ − 722 and the function `syntactically-sectionize', which will map a function
+ − 723 over each syntactic context in a region.
+ − 724
+ − 725 WARNING: this may alter match-data.
+ − 726 */
+ − 727 (buffer))
+ − 728 {
+ − 729 /* This function can GC */
+ − 730 struct buffer *buf = decode_buffer (buffer, 0);
+ − 731 find_context (buf, BUF_PT (buf));
+ − 732 return context_to_symbol (context_cache.context);
+ − 733 }
+ − 734
+ − 735 DEFUN ("buffer-syntactic-context-depth", Fbuffer_syntactic_context_depth,
+ − 736 0, 1, 0, /*
+ − 737 Return the depth within all parenthesis-syntax delimiters at point.
+ − 738 If BUFFER is nil or omitted, the current buffer is assumed.
+ − 739 WARNING: this may alter match-data.
+ − 740 */
+ − 741 (buffer))
+ − 742 {
+ − 743 /* This function can GC */
+ − 744 struct buffer *buf = decode_buffer (buffer, 0);
+ − 745 find_context (buf, BUF_PT (buf));
+ − 746 return make_int (context_cache.depth);
+ − 747 }
+ − 748
+ − 749
+ − 750 DEFUN ("syntactically-sectionize", Fsyntactically_sectionize, 3, 4, 0, /*
+ − 751 Call FUNCTION for each contiguous syntactic context in the region.
+ − 752 Call the given function with four arguments: the start and end of the
+ − 753 region, a symbol representing the syntactic context, and the current
+ − 754 depth (as returned by the functions `buffer-syntactic-context' and
+ − 755 `buffer-syntactic-context-depth'). When this function is called, the
+ − 756 current buffer will be set to BUFFER.
+ − 757
+ − 758 WARNING: this may alter match-data.
+ − 759 */
+ − 760 (function, start, end, buffer))
+ − 761 {
+ − 762 /* This function can GC */
665
+ − 763 Charbpos s, pt, e;
428
+ − 764 int edepth;
+ − 765 enum syntactic_context this_context;
+ − 766 Lisp_Object extent = Qnil;
+ − 767 struct gcpro gcpro1;
+ − 768 struct buffer *buf = decode_buffer (buffer, 0);
+ − 769
+ − 770 get_buffer_range_char (buf, start, end, &s, &e, 0);
+ − 771
+ − 772 pt = s;
+ − 773 find_context (buf, pt);
+ − 774
+ − 775 GCPRO1 (extent);
+ − 776 while (pt < e)
+ − 777 {
665
+ − 778 Charbpos estart, eend;
428
+ − 779 /* skip over "blank" areas, and bug out at end-of-buffer. */
+ − 780 while (context_cache.context == context_none)
+ − 781 {
+ − 782 pt++;
+ − 783 if (pt >= e) goto DONE_LABEL;
+ − 784 find_context (buf, pt);
+ − 785 }
+ − 786 /* We've found a non-blank area; keep going until we reach its end */
+ − 787 this_context = context_cache.context;
+ − 788 estart = pt;
+ − 789
+ − 790 /* Minor kludge: consider the comment-start character(s) a part of
+ − 791 the comment.
+ − 792 */
+ − 793 if (this_context == context_block_comment &&
+ − 794 context_cache.ccontext == ccontext_start2)
+ − 795 estart -= 2;
460
+ − 796 else if (this_context == context_comment
+ − 797 || this_context == context_generic_comment
+ − 798 )
428
+ − 799 estart -= 1;
+ − 800
+ − 801 edepth = context_cache.depth;
+ − 802 while (context_cache.context == this_context && pt < e)
+ − 803 {
+ − 804 pt++;
+ − 805 find_context (buf, pt);
+ − 806 }
+ − 807
+ − 808 eend = pt;
+ − 809
+ − 810 /* Minor kludge: consider the character which terminated the comment
+ − 811 a part of the comment.
+ − 812 */
+ − 813 if ((this_context == context_block_comment ||
460
+ − 814 this_context == context_comment
+ − 815 || this_context == context_generic_comment
+ − 816 )
428
+ − 817 && pt < e)
+ − 818 eend++;
+ − 819
+ − 820 if (estart == eend)
+ − 821 continue;
+ − 822 /* Make sure not to pass in values that are outside the
+ − 823 actual bounds of this function. */
+ − 824 call4_in_buffer (buf, function, make_int (max (s, estart)),
+ − 825 make_int (eend == e ? e : eend - 1),
+ − 826 context_to_symbol (this_context),
+ − 827 make_int (edepth));
+ − 828 }
+ − 829 DONE_LABEL:
+ − 830 UNGCPRO;
+ − 831 return Qnil;
+ − 832 }
+ − 833
+ − 834 void
+ − 835 syms_of_font_lock (void)
+ − 836 {
563
+ − 837 DEFSYMBOL (Qcomment);
+ − 838 DEFSYMBOL (Qblock_comment);
+ − 839 DEFSYMBOL (Qbeginning_of_defun);
428
+ − 840
+ − 841 DEFSUBR (Fbuffer_syntactic_context);
+ − 842 DEFSUBR (Fbuffer_syntactic_context_depth);
+ − 843 DEFSUBR (Fsyntactically_sectionize);
+ − 844 }
+ − 845
+ − 846 void
+ − 847 reinit_vars_of_font_lock (void)
+ − 848 {
+ − 849 xzero (context_cache);
+ − 850 xzero (bol_context_cache);
+ − 851 }
+ − 852
+ − 853 void
+ − 854 vars_of_font_lock (void)
+ − 855 {
+ − 856 }
838
+ − 857
+ − 858 #endif /* USE_C_FONT_LOCK */