comparison src/editfns.c @ 48094:2a8ba962e34d

(overlays_around, get_pos_property): New funs. (find_field): Use them. Also be careful not to modify POS before its last use. (Fmessage): Don't Fformat if there's nothing to format.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Wed, 30 Oct 2002 23:11:26 +0000
parents 7ac7ca5ac550
children 7103ad01172d
comparison
equal deleted inserted replaced
48093:b7cdece1cebf 48094:2a8ba962e34d
326 { 326 {
327 return current_buffer->mark; 327 return current_buffer->mark;
328 } 328 }
329 329
330 330
331 /* Find all the overlays in the current buffer that touch position POS.
332 Return the number found, and store them in a vector in VEC
333 of length LEN. */
334
335 static int
336 overlays_around (pos, vec, len)
337 int pos;
338 Lisp_Object *vec;
339 int len;
340 {
341 Lisp_Object tail, overlay, start, end;
342 int startpos, endpos;
343 int idx = 0;
344
345 for (tail = current_buffer->overlays_before;
346 GC_CONSP (tail);
347 tail = XCDR (tail))
348 {
349 overlay = XCAR (tail);
350
351 end = OVERLAY_END (overlay);
352 endpos = OVERLAY_POSITION (end);
353 if (endpos < pos)
354 break;
355 start = OVERLAY_START (overlay);
356 startpos = OVERLAY_POSITION (start);
357 if (startpos <= pos)
358 {
359 if (idx < len)
360 vec[idx] = overlay;
361 /* Keep counting overlays even if we can't return them all. */
362 idx++;
363 }
364 }
365
366 for (tail = current_buffer->overlays_after;
367 GC_CONSP (tail);
368 tail = XCDR (tail))
369 {
370 overlay = XCAR (tail);
371
372 start = OVERLAY_START (overlay);
373 startpos = OVERLAY_POSITION (start);
374 if (pos < startpos)
375 break;
376 end = OVERLAY_END (overlay);
377 endpos = OVERLAY_POSITION (end);
378 if (pos <= endpos)
379 {
380 if (idx < len)
381 vec[idx] = overlay;
382 idx++;
383 }
384 }
385
386 return idx;
387 }
388
389 /* Return the value of property PROP, in OBJECT at POSITION.
390 It's the value of PROP that a char inserted at POSITION would get.
391 OBJECT is optional and defaults to the current buffer.
392 If OBJECT is a buffer, then overlay properties are considered as well as
393 text properties.
394 If OBJECT is a window, then that window's buffer is used, but
395 window-specific overlays are considered only if they are associated
396 with OBJECT. */
397 static Lisp_Object
398 get_pos_property (position, prop, object)
399 Lisp_Object position, object;
400 register Lisp_Object prop;
401 {
402 struct window *w = 0;
403
404 CHECK_NUMBER_COERCE_MARKER (position);
405
406 if (NILP (object))
407 XSETBUFFER (object, current_buffer);
408
409 if (WINDOWP (object))
410 {
411 w = XWINDOW (object);
412 object = w->buffer;
413 }
414 if (BUFFERP (object))
415 {
416 int posn = XINT (position);
417 int noverlays;
418 Lisp_Object *overlay_vec, tem;
419 struct buffer *obuf = current_buffer;
420
421 set_buffer_temp (XBUFFER (object));
422
423 /* First try with room for 40 overlays. */
424 noverlays = 40;
425 overlay_vec = (Lisp_Object *) alloca (noverlays * sizeof (Lisp_Object));
426 noverlays = overlays_around (posn, overlay_vec, noverlays);
427
428 /* If there are more than 40,
429 make enough space for all, and try again. */
430 if (noverlays > 40)
431 {
432 overlay_vec = (Lisp_Object *) alloca (noverlays * sizeof (Lisp_Object));
433 noverlays = overlays_around (posn, overlay_vec, noverlays);
434 }
435 noverlays = sort_overlays (overlay_vec, noverlays, NULL);
436
437 set_buffer_temp (obuf);
438
439 /* Now check the overlays in order of decreasing priority. */
440 while (--noverlays >= 0)
441 {
442 Lisp_Object ol = overlay_vec[noverlays];
443 tem = Foverlay_get (ol, prop);
444 if (!NILP (tem))
445 {
446 /* Check the overlay is indeed active at point. */
447 Lisp_Object start = OVERLAY_START (ol), finish = OVERLAY_END (ol);
448 if ((OVERLAY_POSITION (start) == posn
449 && XMARKER (start)->insertion_type == 1)
450 || (OVERLAY_POSITION (finish) == posn
451 && XMARKER (finish)->insertion_type == 0))
452 ; /* The overlay will not cover a char inserted at point. */
453 else
454 {
455 return tem;
456 }
457 }
458 }
459
460 }
461
462 { /* Now check the text-properties. */
463 int stickiness = text_property_stickiness (Qfield, position);
464 if (stickiness > 0)
465 return Fget_text_property (position, Qfield, Qnil);
466 else if (stickiness < 0 && XINT (position) > BEGV)
467 return Fget_text_property (make_number (XINT (position) - 1),
468 Qfield, Qnil);
469 else
470 return Qnil;
471 }
472 }
473
331 /* Find the field surrounding POS in *BEG and *END. If POS is nil, 474 /* Find the field surrounding POS in *BEG and *END. If POS is nil,
332 the value of point is used instead. If BEG or END null, 475 the value of point is used instead. If BEG or END null,
333 means don't store the beginning or end of the field. 476 means don't store the beginning or end of the field.
334 477
335 BEG_LIMIT and END_LIMIT serve to limit the ranged of the returned 478 BEG_LIMIT and END_LIMIT serve to limit the ranged of the returned
355 Lisp_Object beg_limit, end_limit; 498 Lisp_Object beg_limit, end_limit;
356 int *beg, *end; 499 int *beg, *end;
357 { 500 {
358 /* Fields right before and after the point. */ 501 /* Fields right before and after the point. */
359 Lisp_Object before_field, after_field; 502 Lisp_Object before_field, after_field;
360 /* If the fields came from overlays, the associated overlays.
361 Qnil means they came from text-properties. */
362 Lisp_Object before_overlay = Qnil, after_overlay = Qnil;
363 /* 1 if POS counts as the start of a field. */ 503 /* 1 if POS counts as the start of a field. */
364 int at_field_start = 0; 504 int at_field_start = 0;
365 /* 1 if POS counts as the end of a field. */ 505 /* 1 if POS counts as the end of a field. */
366 int at_field_end = 0; 506 int at_field_end = 0;
367 507
369 XSETFASTINT (pos, PT); 509 XSETFASTINT (pos, PT);
370 else 510 else
371 CHECK_NUMBER_COERCE_MARKER (pos); 511 CHECK_NUMBER_COERCE_MARKER (pos);
372 512
373 after_field 513 after_field
374 = get_char_property_and_overlay (pos, Qfield, Qnil, &after_overlay); 514 = get_char_property_and_overlay (pos, Qfield, Qnil, NULL);
375 before_field 515 before_field
376 = (XFASTINT (pos) > BEGV 516 = (XFASTINT (pos) > BEGV
377 ? get_char_property_and_overlay (make_number (XINT (pos) - 1), 517 ? get_char_property_and_overlay (make_number (XINT (pos) - 1),
378 Qfield, Qnil, 518 Qfield, Qnil, NULL)
379 &before_overlay)
380 : Qnil); 519 : Qnil);
381 520
382 /* See if we need to handle the case where MERGE_AT_BOUNDARY is nil 521 /* See if we need to handle the case where MERGE_AT_BOUNDARY is nil
383 and POS is at beginning of a field, which can also be interpreted 522 and POS is at beginning of a field, which can also be interpreted
384 as the end of the previous field. Note that the case where if 523 as the end of the previous field. Note that the case where if
385 MERGE_AT_BOUNDARY is non-nil (see function comment) is actually the 524 MERGE_AT_BOUNDARY is non-nil (see function comment) is actually the
386 more natural one; then we avoid treating the beginning of a field 525 more natural one; then we avoid treating the beginning of a field
387 specially. */ 526 specially. */
388 if (NILP (merge_at_boundary) && !EQ (after_field, before_field)) 527 if (NILP (merge_at_boundary))
389 /* We are at a boundary, see which direction is inclusive. We 528 {
390 decide by seeing which field the `field' property sticks to. */ 529 Lisp_Object field = get_pos_property (pos, Qfield, Qnil);
391 { 530 if (!EQ (field, after_field))
392 /* -1 means insertions go into before_field, 1 means they go 531 at_field_end = 1;
393 into after_field, 0 means neither. */ 532 if (!EQ (field, before_field))
394 int stickiness;
395 /* Whether the before/after_field come from overlays. */
396 int bop = !NILP (before_overlay);
397 int aop = !NILP (after_overlay);
398
399 if (bop && XMARKER (OVERLAY_END (before_overlay))->insertion_type == 1)
400 /* before_field is from an overlay, which expands upon
401 end-insertions. Note that it's possible for after_overlay to
402 also eat insertions here, but then they will overlap, and
403 there's not much we can do. */
404 stickiness = -1;
405 else if (aop
406 && XMARKER (OVERLAY_START (after_overlay))->insertion_type == 0)
407 /* after_field is from an overlay, which expand to contain
408 start-insertions. */
409 stickiness = 1;
410 else if (bop && aop)
411 /* Both fields come from overlays, but neither will contain any
412 insertion here. */
413 stickiness = 0;
414 else if (bop)
415 /* before_field is an overlay that won't eat any insertion, but
416 after_field is from a text-property. Assume that the
417 text-property continues underneath the overlay, and so will
418 be inherited by any insertion, regardless of any stickiness
419 settings. */
420 stickiness = 1;
421 else if (aop)
422 /* Similarly, when after_field is the overlay. */
423 stickiness = -1;
424 else
425 /* Both fields come from text-properties. Look for explicit
426 stickiness properties. */
427 stickiness = text_property_stickiness (Qfield, pos);
428
429 if (stickiness > 0)
430 at_field_start = 1; 533 at_field_start = 1;
431 else if (stickiness < 0)
432 at_field_end = 1;
433 else
434 /* STICKINESS == 0 means that any inserted text will get a
435 `field' char-property of nil, so check to see if that
436 matches either of the adjacent characters (this being a
437 kind of "stickiness by default"). */
438 {
439 if (NILP (before_field))
440 at_field_end = 1; /* Sticks to the left. */
441 else if (NILP (after_field))
442 at_field_start = 1; /* Sticks to the right. */
443 }
444 } 534 }
445 535
446 /* Note about special `boundary' fields: 536 /* Note about special `boundary' fields:
447 537
448 Consider the case where the point (`.') is between the fields `x' and `y': 538 Consider the case where the point (`.') is between the fields `x' and `y':
472 the beginning of the following field. */ 562 the beginning of the following field. */
473 *beg = XFASTINT (pos); 563 *beg = XFASTINT (pos);
474 else 564 else
475 /* Find the previous field boundary. */ 565 /* Find the previous field boundary. */
476 { 566 {
567 Lisp_Object p = pos;
477 if (!NILP (merge_at_boundary) && EQ (before_field, Qboundary)) 568 if (!NILP (merge_at_boundary) && EQ (before_field, Qboundary))
478 /* Skip a `boundary' field. */ 569 /* Skip a `boundary' field. */
479 pos = Fprevious_single_char_property_change (pos, Qfield, Qnil, 570 p = Fprevious_single_char_property_change (p, Qfield, Qnil,
480 beg_limit);
481
482 pos = Fprevious_single_char_property_change (pos, Qfield, Qnil,
483 beg_limit); 571 beg_limit);
484 *beg = NILP (pos) ? BEGV : XFASTINT (pos); 572
573 p = Fprevious_single_char_property_change (p, Qfield, Qnil,
574 beg_limit);
575 *beg = NILP (p) ? BEGV : XFASTINT (p);
485 } 576 }
486 } 577 }
487 578
488 if (end) 579 if (end)
489 { 580 {
2928 return Qnil; 3019 return Qnil;
2929 } 3020 }
2930 else 3021 else
2931 { 3022 {
2932 register Lisp_Object val; 3023 register Lisp_Object val;
2933 val = Fformat (nargs, args); 3024 val = nargs < 2 && STRINGP (args[0]) ? args[0] : Fformat (nargs, args);
2934 message3 (val, SBYTES (val), STRING_MULTIBYTE (val)); 3025 message3 (val, SBYTES (val), STRING_MULTIBYTE (val));
2935 return val; 3026 return val;
2936 } 3027 }
2937 } 3028 }
2938 3029