aboutsummaryrefslogtreecommitdiffstats
path: root/src/editfns.c
diff options
context:
space:
mode:
authorMiles Bader2000-07-24 23:45:57 +0000
committerMiles Bader2000-07-24 23:45:57 +0000
commitee547125d8d2cd375340e0e7612dbf1d1a2fa954 (patch)
tree66db73d3bbd1867e0815360a64c2f829ca07c26d /src/editfns.c
parentc28da48936fda305fba7085c30f043612f48f2f5 (diff)
downloademacs-ee547125d8d2cd375340e0e7612dbf1d1a2fa954.tar.gz
emacs-ee547125d8d2cd375340e0e7612dbf1d1a2fa954.zip
(find_field): Honor special `boundary' fields.
(Fconstrain_to_field): Add the INHIBIT-CAPTURE-PROPERTY argument. Use scan_buffer instead of find_before_next_newline, because it allows us to detect the boundary case where there's a newline at the search limit. (Qboundary): New variables. (syms_of_editfns): Initialize Qboundary.
Diffstat (limited to 'src/editfns.c')
-rw-r--r--src/editfns.c197
1 files changed, 119 insertions, 78 deletions
diff --git a/src/editfns.c b/src/editfns.c
index 2e5cc4a9463..218c5f0ef94 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -337,14 +337,21 @@ char_property_stickiness (prop, pos)
337/* Symbol for the text property used to mark fields. */ 337/* Symbol for the text property used to mark fields. */
338Lisp_Object Qfield; 338Lisp_Object Qfield;
339 339
340/* A special value for Qfield properties. */
341Lisp_Object Qboundary;
342
340/* Find the field surrounding POS in *BEG and *END. If POS is nil, 343/* Find the field surrounding POS in *BEG and *END. If POS is nil,
341 the value of point is used instead. 344 the value of point is used instead.
342 345
343 If MERGE_AT_BOUNDARY is nonzero, then if POS is at the very first 346 If MERGE_AT_BOUNDARY is nonzero, then if POS is at the very first
344 position of a field, then the beginning of the previous field 347 position of a field, then the beginning of the previous field is
345 is returned instead of the beginning of POS's field (since the end of 348 returned instead of the beginning of POS's field (since the end of a
346 a field is actually also the beginning of the next input 349 field is actually also the beginning of the next input field, this
347 field, this behavior is sometimes useful). 350 behavior is sometimes useful). Additionally in the MERGE_AT_BOUNDARY
351 true case, if two fields are separated by a field with the special
352 value `boundary', and POS lies within it, then the two separated
353 fields are considered to be adjacent, and POS between them, when
354 finding the beginning and ending of the "merged" field.
348 355
349 Either BEG or END may be 0, in which case the corresponding value 356 Either BEG or END may be 0, in which case the corresponding value
350 is not stored. */ 357 is not stored. */
@@ -355,84 +362,107 @@ find_field (pos, merge_at_boundary, beg, end)
355 Lisp_Object merge_at_boundary; 362 Lisp_Object merge_at_boundary;
356 int *beg, *end; 363 int *beg, *end;
357{ 364{
365 /* Fields right before and after the point. */
366 Lisp_Object before_field, after_field;
358 /* 1 if POS counts as the start of a field. */ 367 /* 1 if POS counts as the start of a field. */
359 int at_field_start = 0; 368 int at_field_start = 0;
360 /* 1 if POS counts as the end of a field. */ 369 /* 1 if POS counts as the end of a field. */
361 int at_field_end = 0; 370 int at_field_end = 0;
362 371
363 if (NILP (pos)) 372 if (NILP (pos))
364 XSETFASTINT (pos, PT); 373 XSETFASTINT (pos, PT);
365 else 374 else
366 CHECK_NUMBER_COERCE_MARKER (pos, 0); 375 CHECK_NUMBER_COERCE_MARKER (pos, 0);
367 376
368 if (NILP (merge_at_boundary) && XFASTINT (pos) > BEGV) 377 after_field =
369 /* See if we need to handle the case where POS is at beginning of a 378 Fget_char_property (pos, Qfield, Qnil);
370 field, which can also be interpreted as the end of the previous 379 before_field =
371 field. We decide which one by seeing which field the `field' 380 (XFASTINT (pos) > BEGV
372 property sticks to. The case where if MERGE_AT_BOUNDARY is 381 ? Fget_char_property (make_number (XINT (pos) - 1), Qfield, Qnil)
373 non-nil (see function comment) is actually the more natural one; 382 : Qnil);
374 then we avoid treating the beginning of a field specially. */ 383
375 { 384 /* See if we need to handle the case where MERGE_AT_BOUNDARY is nil
376 /* First see if POS is actually *at* a boundary. */ 385 and POS is at beginning of a field, which can also be interpreted
377 Lisp_Object after_field, before_field; 386 as the end of the previous field. Note that the case where if
378 387 MERGE_AT_BOUNDARY is non-nil (see function comment) is actually the
379 after_field = Fget_char_property (pos, Qfield, Qnil); 388 more natural one; then we avoid treating the beginning of a field
380 before_field = Fget_char_property (make_number (XINT (pos) - 1), 389 specially. */
381 Qfield, Qnil); 390 if (NILP (merge_at_boundary) && !EQ (after_field, before_field))
382 391 /* We are at a boundary, see which direction is inclusive. We
383 if (! EQ (after_field, before_field)) 392 decide by seeing which field the `field' property sticks to. */
384 /* We are at a boundary, see which direction is inclusive. */ 393 {
394 int stickiness = char_property_stickiness (Qfield, pos);
395
396 if (stickiness > 0)
397 at_field_start = 1;
398 else if (stickiness < 0)
399 at_field_end = 1;
400 else
401 /* STICKINESS == 0 means that any inserted text will get a
402 `field' char-property of nil, so check to see if that
403 matches either of the adjacent characters (this being a
404 kind of "stickiness by default"). */
385 { 405 {
386 int stickiness = char_property_stickiness (Qfield, pos); 406 if (NILP (before_field))
387 407 at_field_end = 1; /* Sticks to the left. */
388 if (stickiness > 0) 408 else if (NILP (after_field))
389 at_field_start = 1; 409 at_field_start = 1; /* Sticks to the right. */
390 else if (stickiness < 0)
391 at_field_end = 1;
392 else
393 /* STICKINESS == 0 means that any inserted text will get a
394 `field' char-property of nil, so check to see if that
395 matches either of the adjacent characters (this being a
396 kind of "stickiness by default"). */
397 {
398 if (NILP (before_field))
399 at_field_end = 1; /* Sticks to the left. */
400 else if (NILP (after_field))
401 at_field_start = 1; /* Sticks to the right. */
402 }
403 } 410 }
404 } 411 }
405 412
413 /* Note about special `boundary' fields:
414
415 Consider the case where the point (`.') is between the fields `x' and `y':
416
417 xxxx.yyyy
418
419 In this situation, if merge_at_boundary is true, we consider the
420 `x' and `y' fields as forming one big merged field, and so the end
421 of the field is the end of `y'.
422
423 However, if `x' and `y' are separated by a special `boundary' field
424 (a field with a `field' char-property of 'boundary), then we ignore
425 this special field when merging adjacent fields. Here's the same
426 situation, but with a `boundary' field between the `x' and `y' fields:
427
428 xxx.BBBByyyy
429
430 Here, if point is at the end of `x', the beginning of `y', or
431 anywhere in-between (within the `boundary' field), we merge all
432 three fields and consider the beginning as being the beginning of
433 the `x' field, and the end as being the end of the `y' field. */
434
406 if (beg) 435 if (beg)
407 { 436 if (at_field_start)
408 if (at_field_start) 437 /* POS is at the edge of a field, and we should consider it as
409 /* POS is at the edge of a field, and we should consider it as 438 the beginning of the following field. */
410 the beginning of the following field. */ 439 *beg = XFASTINT (pos);
411 *beg = XFASTINT (pos); 440 else
412 else 441 /* Find the previous field boundary. */
413 /* Find the previous field boundary. */ 442 {
414 { 443 if (!NILP (merge_at_boundary) && before_field == Qboundary)
415 Lisp_Object prev; 444 /* Skip a `boundary' field. */
416 prev = 445 pos = Fprevious_single_char_property_change (pos, Qfield, Qnil,Qnil);
417 Fprevious_single_char_property_change (pos, Qfield, Qnil, Qnil); 446
418 *beg = NILP (prev) ? BEGV : XFASTINT (prev); 447 pos = Fprevious_single_char_property_change (pos, Qfield, Qnil, Qnil);
419 } 448 *beg = NILP (pos) ? BEGV : XFASTINT (pos);
420 } 449 }
421 450
422 if (end) 451 if (end)
423 { 452 if (at_field_end)
424 if (at_field_end) 453 /* POS is at the edge of a field, and we should consider it as
425 /* POS is at the edge of a field, and we should consider it as 454 the end of the previous field. */
426 the end of the previous field. */ 455 *end = XFASTINT (pos);
427 *end = XFASTINT (pos); 456 else
428 else 457 /* Find the next field boundary. */
429 /* Find the next field boundary. */ 458 {
430 { 459 if (!NILP (merge_at_boundary) && after_field == Qboundary)
431 Lisp_Object next; 460 /* Skip a `boundary' field. */
432 next = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil); 461 pos = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil);
433 *end = NILP (next) ? ZV : XFASTINT (next); 462
434 } 463 pos = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil);
435 } 464 *end = NILP (pos) ? ZV : XFASTINT (pos);
465 }
436} 466}
437 467
438DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0, 468DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0,
@@ -501,8 +531,9 @@ then the end of the *following* field is returned.")
501 return make_number (end); 531 return make_number (end);
502} 532}
503 533
504DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 4, 0, 534DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 5, 0,
505 "Return the position closest to NEW-POS that is in the same field as OLD-POS.\n\ 535 "Return the position closest to NEW-POS that is in the same field as OLD-POS.\n\
536\n\
506A field is a region of text with the same `field' property.\n\ 537A field is a region of text with the same `field' property.\n\
507If NEW-POS is nil, then the current point is used instead, and set to the\n\ 538If NEW-POS is nil, then the current point is used instead, and set to the\n\
508constrained position if that is is different.\n\ 539constrained position if that is is different.\n\
@@ -513,7 +544,9 @@ ESCAPE-FROM-EDGE: If ESCAPE-FROM-EDGE is nil, then NEW-POS is\n\
513constrained to the field that has the same `field' char-property\n\ 544constrained to the field that has the same `field' char-property\n\
514as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE\n\ 545as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE\n\
515is non-nil, NEW-POS is constrained to the union of the two adjacent\n\ 546is non-nil, NEW-POS is constrained to the union of the two adjacent\n\
516fields.\n\ 547fields. Additionally, if two fields are separated by another field with\n\
548the special value `boundary', then any point within this special field is\n\
549also considered to be `on the boundary'.\n\
517\n\ 550\n\
518If the optional argument ONLY-IN-LINE is non-nil and constraining\n\ 551If the optional argument ONLY-IN-LINE is non-nil and constraining\n\
519NEW-POS would move it to a different line, NEW-POS is returned\n\ 552NEW-POS would move it to a different line, NEW-POS is returned\n\
@@ -521,9 +554,13 @@ unconstrained. This useful for commands that move by line, like\n\
521\\[next-line] or \\[beginning-of-line], which should generally respect field boundaries\n\ 554\\[next-line] or \\[beginning-of-line], which should generally respect field boundaries\n\
522only in the case where they can still move to the right line.\n\ 555only in the case where they can still move to the right line.\n\
523\n\ 556\n\
557If the optional argument INHIBIT-CAPTURE-PROPERTY is non-nil, and OLD-POS has\n\
558a non-nil property of that name, then any field boundaries are ignored.\n\
559\n\
524Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.") 560Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.")
525 (new_pos, old_pos, escape_from_edge, only_in_line) 561 (new_pos, old_pos, escape_from_edge, only_in_line, inhibit_capture_property)
526 Lisp_Object new_pos, old_pos, escape_from_edge, only_in_line; 562 Lisp_Object new_pos, old_pos;
563 Lisp_Object escape_from_edge, only_in_line, inhibit_capture_property;
527{ 564{
528 /* If non-zero, then the original point, before re-positioning. */ 565 /* If non-zero, then the original point, before re-positioning. */
529 int orig_point = 0; 566 int orig_point = 0;
@@ -537,11 +574,13 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.")
537 574
538 if (NILP (Vinhibit_field_text_motion) 575 if (NILP (Vinhibit_field_text_motion)
539 && !EQ (new_pos, old_pos) 576 && !EQ (new_pos, old_pos)
540 && !char_property_eq (Qfield, new_pos, old_pos)) 577 && !char_property_eq (Qfield, new_pos, old_pos)
578 && (NILP (inhibit_capture_property)
579 || NILP (Fget_char_property(old_pos, inhibit_capture_property, Qnil))))
541 /* NEW_POS is not within the same field as OLD_POS; try to 580 /* NEW_POS is not within the same field as OLD_POS; try to
542 move NEW_POS so that it is. */ 581 move NEW_POS so that it is. */
543 { 582 {
544 int fwd; 583 int fwd, shortage;
545 Lisp_Object field_bound; 584 Lisp_Object field_bound;
546 585
547 CHECK_NUMBER_COERCE_MARKER (new_pos, 0); 586 CHECK_NUMBER_COERCE_MARKER (new_pos, 0);
@@ -564,10 +603,10 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.")
564 || ((XFASTINT (field_bound) < XFASTINT (new_pos)) ? !fwd : fwd) 603 || ((XFASTINT (field_bound) < XFASTINT (new_pos)) ? !fwd : fwd)
565 /* If not, see if there's no newline intervening between 604 /* If not, see if there's no newline intervening between
566 NEW_POS and FIELD_BOUND. */ 605 NEW_POS and FIELD_BOUND. */
567 || (find_before_next_newline (XFASTINT (new_pos), 606 || (scan_buffer ('\n',
568 XFASTINT (field_bound), 607 XFASTINT (new_pos), XFASTINT (field_bound),
569 fwd ? -1 : 1) 608 fwd ? -1 : 1, &shortage, 1),
570 == XFASTINT (field_bound))) 609 shortage != 0))
571 /* Constrain NEW_POS to FIELD_BOUND. */ 610 /* Constrain NEW_POS to FIELD_BOUND. */
572 new_pos = field_bound; 611 new_pos = field_bound;
573 612
@@ -610,7 +649,7 @@ This function does not move point.")
610 /* Return END constrained to the current input field. */ 649 /* Return END constrained to the current input field. */
611 return Fconstrain_to_field (make_number (end), make_number (orig), 650 return Fconstrain_to_field (make_number (end), make_number (orig),
612 XINT (n) != 1 ? Qt : Qnil, 651 XINT (n) != 1 ? Qt : Qnil,
613 Qt); 652 Qt, Qnil);
614} 653}
615 654
616DEFUN ("line-end-position", Fline_end_position, Sline_end_position, 655DEFUN ("line-end-position", Fline_end_position, Sline_end_position,
@@ -634,7 +673,7 @@ This function does not move point.")
634 673
635 /* Return END_POS constrained to the current input field. */ 674 /* Return END_POS constrained to the current input field. */
636 return Fconstrain_to_field (make_number (end_pos), make_number (orig), 675 return Fconstrain_to_field (make_number (end_pos), make_number (orig),
637 Qnil, Qt); 676 Qnil, Qt, Qnil);
638} 677}
639 678
640Lisp_Object 679Lisp_Object
@@ -3710,6 +3749,8 @@ functions if all the text being accessed has this property.");
3710 3749
3711 staticpro (&Qfield); 3750 staticpro (&Qfield);
3712 Qfield = intern ("field"); 3751 Qfield = intern ("field");
3752 staticpro (&Qboundary);
3753 Qboundary = intern ("boundary");
3713 defsubr (&Sfield_beginning); 3754 defsubr (&Sfield_beginning);
3714 defsubr (&Sfield_end); 3755 defsubr (&Sfield_end);
3715 defsubr (&Sfield_string); 3756 defsubr (&Sfield_string);