/* 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. */
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);
+ }
}
\f
DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0,
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\
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\
\\[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;
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);
|| ((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;
/* 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,
/* 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);
}
\f
Lisp_Object
staticpro (&Qfield);
Qfield = intern ("field");
+ staticpro (&Qboundary);
+ Qboundary = intern ("boundary");
defsubr (&Sfield_beginning);
defsubr (&Sfield_end);
defsubr (&Sfield_string);