diff options
| author | Miles Bader | 2000-07-24 23:45:57 +0000 |
|---|---|---|
| committer | Miles Bader | 2000-07-24 23:45:57 +0000 |
| commit | ee547125d8d2cd375340e0e7612dbf1d1a2fa954 (patch) | |
| tree | 66db73d3bbd1867e0815360a64c2f829ca07c26d /src/editfns.c | |
| parent | c28da48936fda305fba7085c30f043612f48f2f5 (diff) | |
| download | emacs-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.c | 197 |
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. */ |
| 338 | Lisp_Object Qfield; | 338 | Lisp_Object Qfield; |
| 339 | 339 | ||
| 340 | /* A special value for Qfield properties. */ | ||
| 341 | Lisp_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 | ||
| 438 | DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0, | 468 | DEFUN ("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 | ||
| 504 | DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 4, 0, | 534 | DEFUN ("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\ | ||
| 506 | A field is a region of text with the same `field' property.\n\ | 537 | A field is a region of text with the same `field' property.\n\ |
| 507 | If NEW-POS is nil, then the current point is used instead, and set to the\n\ | 538 | If NEW-POS is nil, then the current point is used instead, and set to the\n\ |
| 508 | constrained position if that is is different.\n\ | 539 | constrained 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\ | |||
| 513 | constrained to the field that has the same `field' char-property\n\ | 544 | constrained to the field that has the same `field' char-property\n\ |
| 514 | as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE\n\ | 545 | as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE\n\ |
| 515 | is non-nil, NEW-POS is constrained to the union of the two adjacent\n\ | 546 | is non-nil, NEW-POS is constrained to the union of the two adjacent\n\ |
| 516 | fields.\n\ | 547 | fields. Additionally, if two fields are separated by another field with\n\ |
| 548 | the special value `boundary', then any point within this special field is\n\ | ||
| 549 | also considered to be `on the boundary'.\n\ | ||
| 517 | \n\ | 550 | \n\ |
| 518 | If the optional argument ONLY-IN-LINE is non-nil and constraining\n\ | 551 | If the optional argument ONLY-IN-LINE is non-nil and constraining\n\ |
| 519 | NEW-POS would move it to a different line, NEW-POS is returned\n\ | 552 | NEW-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\ |
| 522 | only in the case where they can still move to the right line.\n\ | 555 | only in the case where they can still move to the right line.\n\ |
| 523 | \n\ | 556 | \n\ |
| 557 | If the optional argument INHIBIT-CAPTURE-PROPERTY is non-nil, and OLD-POS has\n\ | ||
| 558 | a non-nil property of that name, then any field boundaries are ignored.\n\ | ||
| 559 | \n\ | ||
| 524 | Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.") | 560 | Field 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 | ||
| 616 | DEFUN ("line-end-position", Fline_end_position, Sline_end_position, | 655 | DEFUN ("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 | ||
| 640 | Lisp_Object | 679 | Lisp_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); |