From ee547125d8d2cd375340e0e7612dbf1d1a2fa954 Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Mon, 24 Jul 2000 23:45:57 +0000 Subject: [PATCH] (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. --- src/editfns.c | 197 ++++++++++++++++++++++++++++++-------------------- 1 file 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) /* Symbol for the text property used to mark fields. */ Lisp_Object Qfield; +/* A special value for Qfield properties. */ +Lisp_Object Qboundary; + /* Find the field surrounding POS in *BEG and *END. If POS is nil, the value of point is used instead. If MERGE_AT_BOUNDARY is nonzero, then if POS is at the very first - position of a field, then the beginning of the previous field - is returned instead of the beginning of POS's field (since the end of - a field is actually also the beginning of the next input - field, this behavior is sometimes useful). + position of a field, then the beginning of the previous field is + returned instead of the beginning of POS's field (since the end of a + field is actually also the beginning of the next input field, this + behavior is sometimes useful). Additionally in the MERGE_AT_BOUNDARY + true case, if two fields are separated by a field with the special + value `boundary', and POS lies within it, then the two separated + fields are considered to be adjacent, and POS between them, when + finding the beginning and ending of the "merged" field. Either BEG or END may be 0, in which case the corresponding value is not stored. */ @@ -355,84 +362,107 @@ find_field (pos, merge_at_boundary, beg, end) Lisp_Object merge_at_boundary; int *beg, *end; { + /* Fields right before and after the point. */ + Lisp_Object before_field, after_field; /* 1 if POS counts as the start of a field. */ int at_field_start = 0; /* 1 if POS counts as the end of a field. */ int at_field_end = 0; - + if (NILP (pos)) XSETFASTINT (pos, PT); else CHECK_NUMBER_COERCE_MARKER (pos, 0); - if (NILP (merge_at_boundary) && XFASTINT (pos) > BEGV) - /* See if we need to handle the case where POS is at beginning of a - field, which can also be interpreted as the end of the previous - field. We decide which one by seeing which field the `field' - property sticks to. The case where if MERGE_AT_BOUNDARY is - non-nil (see function comment) is actually the more natural one; - then we avoid treating the beginning of a field specially. */ - { - /* First see if POS is actually *at* a boundary. */ - Lisp_Object after_field, before_field; - - after_field = Fget_char_property (pos, Qfield, Qnil); - before_field = Fget_char_property (make_number (XINT (pos) - 1), - Qfield, Qnil); - - if (! EQ (after_field, before_field)) - /* We are at a boundary, see which direction is inclusive. */ + after_field = + Fget_char_property (pos, Qfield, Qnil); + before_field = + (XFASTINT (pos) > BEGV + ? Fget_char_property (make_number (XINT (pos) - 1), Qfield, Qnil) + : Qnil); + + /* See if we need to handle the case where MERGE_AT_BOUNDARY is nil + and POS is at beginning of a field, which can also be interpreted + as the end of the previous field. Note that the case where if + MERGE_AT_BOUNDARY is non-nil (see function comment) is actually the + more natural one; then we avoid treating the beginning of a field + specially. */ + if (NILP (merge_at_boundary) && !EQ (after_field, before_field)) + /* We are at a boundary, see which direction is inclusive. We + decide by seeing which field the `field' property sticks to. */ + { + int stickiness = char_property_stickiness (Qfield, pos); + + if (stickiness > 0) + at_field_start = 1; + else if (stickiness < 0) + at_field_end = 1; + else + /* STICKINESS == 0 means that any inserted text will get a + `field' char-property of nil, so check to see if that + matches either of the adjacent characters (this being a + kind of "stickiness by default"). */ { - int stickiness = char_property_stickiness (Qfield, pos); - - if (stickiness > 0) - at_field_start = 1; - else if (stickiness < 0) - at_field_end = 1; - else - /* STICKINESS == 0 means that any inserted text will get a - `field' char-property of nil, so check to see if that - matches either of the adjacent characters (this being a - kind of "stickiness by default"). */ - { - if (NILP (before_field)) - at_field_end = 1; /* Sticks to the left. */ - else if (NILP (after_field)) - at_field_start = 1; /* Sticks to the right. */ - } + if (NILP (before_field)) + at_field_end = 1; /* Sticks to the left. */ + else if (NILP (after_field)) + at_field_start = 1; /* Sticks to the right. */ } } + /* Note about special `boundary' fields: + + Consider the case where the point (`.') is between the fields `x' and `y': + + xxxx.yyyy + + In this situation, if merge_at_boundary is true, we consider the + `x' and `y' fields as forming one big merged field, and so the end + of the field is the end of `y'. + + However, if `x' and `y' are separated by a special `boundary' field + (a field with a `field' char-property of 'boundary), then we ignore + this special field when merging adjacent fields. Here's the same + situation, but with a `boundary' field between the `x' and `y' fields: + + xxx.BBBByyyy + + Here, if point is at the end of `x', the beginning of `y', or + anywhere in-between (within the `boundary' field), we merge all + three fields and consider the beginning as being the beginning of + the `x' field, and the end as being the end of the `y' field. */ + if (beg) - { - if (at_field_start) - /* POS is at the edge of a field, and we should consider it as - the beginning of the following field. */ - *beg = XFASTINT (pos); - else - /* Find the previous field boundary. */ - { - Lisp_Object prev; - prev = - Fprevious_single_char_property_change (pos, Qfield, Qnil, Qnil); - *beg = NILP (prev) ? BEGV : XFASTINT (prev); - } - } + if (at_field_start) + /* POS is at the edge of a field, and we should consider it as + the beginning of the following field. */ + *beg = XFASTINT (pos); + else + /* Find the previous field boundary. */ + { + if (!NILP (merge_at_boundary) && before_field == Qboundary) + /* Skip a `boundary' field. */ + pos = Fprevious_single_char_property_change (pos, Qfield, Qnil,Qnil); + + pos = Fprevious_single_char_property_change (pos, Qfield, Qnil, Qnil); + *beg = NILP (pos) ? BEGV : XFASTINT (pos); + } if (end) - { - if (at_field_end) - /* POS is at the edge of a field, and we should consider it as - the end of the previous field. */ - *end = XFASTINT (pos); - else - /* Find the next field boundary. */ - { - Lisp_Object next; - next = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil); - *end = NILP (next) ? ZV : XFASTINT (next); - } - } + if (at_field_end) + /* POS is at the edge of a field, and we should consider it as + the end of the previous field. */ + *end = XFASTINT (pos); + else + /* Find the next field boundary. */ + { + if (!NILP (merge_at_boundary) && after_field == Qboundary) + /* Skip a `boundary' field. */ + pos = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil); + + pos = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil); + *end = NILP (pos) ? ZV : XFASTINT (pos); + } } DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0, @@ -501,8 +531,9 @@ then the end of the *following* field is returned.") return make_number (end); } -DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 4, 0, +DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 5, 0, "Return the position closest to NEW-POS that is in the same field as OLD-POS.\n\ +\n\ A field is a region of text with the same `field' property.\n\ If NEW-POS is nil, then the current point is used instead, and set to the\n\ 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\ constrained to the field that has the same `field' char-property\n\ as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE\n\ is non-nil, NEW-POS is constrained to the union of the two adjacent\n\ -fields.\n\ +fields. Additionally, if two fields are separated by another field with\n\ +the special value `boundary', then any point within this special field is\n\ +also considered to be `on the boundary'.\n\ \n\ If the optional argument ONLY-IN-LINE is non-nil and constraining\n\ 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\ \\[next-line] or \\[beginning-of-line], which should generally respect field boundaries\n\ only in the case where they can still move to the right line.\n\ \n\ +If the optional argument INHIBIT-CAPTURE-PROPERTY is non-nil, and OLD-POS has\n\ +a non-nil property of that name, then any field boundaries are ignored.\n\ +\n\ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.") - (new_pos, old_pos, escape_from_edge, only_in_line) - Lisp_Object new_pos, old_pos, escape_from_edge, only_in_line; + (new_pos, old_pos, escape_from_edge, only_in_line, inhibit_capture_property) + Lisp_Object new_pos, old_pos; + Lisp_Object escape_from_edge, only_in_line, inhibit_capture_property; { /* If non-zero, then the original point, before re-positioning. */ int orig_point = 0; @@ -537,11 +574,13 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.") if (NILP (Vinhibit_field_text_motion) && !EQ (new_pos, old_pos) - && !char_property_eq (Qfield, new_pos, old_pos)) + && !char_property_eq (Qfield, new_pos, old_pos) + && (NILP (inhibit_capture_property) + || NILP (Fget_char_property(old_pos, inhibit_capture_property, Qnil)))) /* NEW_POS is not within the same field as OLD_POS; try to move NEW_POS so that it is. */ { - int fwd; + int fwd, shortage; Lisp_Object field_bound; CHECK_NUMBER_COERCE_MARKER (new_pos, 0); @@ -564,10 +603,10 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.") || ((XFASTINT (field_bound) < XFASTINT (new_pos)) ? !fwd : fwd) /* If not, see if there's no newline intervening between NEW_POS and FIELD_BOUND. */ - || (find_before_next_newline (XFASTINT (new_pos), - XFASTINT (field_bound), - fwd ? -1 : 1) - == XFASTINT (field_bound))) + || (scan_buffer ('\n', + XFASTINT (new_pos), XFASTINT (field_bound), + fwd ? -1 : 1, &shortage, 1), + shortage != 0)) /* Constrain NEW_POS to FIELD_BOUND. */ new_pos = field_bound; @@ -610,7 +649,7 @@ This function does not move point.") /* Return END constrained to the current input field. */ return Fconstrain_to_field (make_number (end), make_number (orig), XINT (n) != 1 ? Qt : Qnil, - Qt); + Qt, Qnil); } DEFUN ("line-end-position", Fline_end_position, Sline_end_position, @@ -634,7 +673,7 @@ This function does not move point.") /* Return END_POS constrained to the current input field. */ return Fconstrain_to_field (make_number (end_pos), make_number (orig), - Qnil, Qt); + Qnil, Qt, Qnil); } Lisp_Object @@ -3710,6 +3749,8 @@ functions if all the text being accessed has this property."); staticpro (&Qfield); Qfield = intern ("field"); + staticpro (&Qboundary); + Qboundary = intern ("boundary"); defsubr (&Sfield_beginning); defsubr (&Sfield_end); defsubr (&Sfield_string); -- 2.39.2