Mercurial > emacs
comparison src/editfns.c @ 26058:c11f0832a7c5
(Fconstrain_to_field): Make sure we don't violate the
argument preconditions of find_before_next_newline in the case
where both ONLY_IN_LINE and ESCAPE_FROM_EDGE are set and OLD_POS
was indeed at the edge.
(text_property_eq, text_property_stickiness): Don't
use initializers for auto variables of type Lisp_Object.
(find_field): Likewise. Use braces around nested ifs.
(Fline_end_position): Store the raw eol in a variable, so that the
final expression doesn't look so ugly.
(Fconstrain_to_field): Doc fix.
(preceding_pos): Renamed from `preceeding_pos'.
(text_property_stickiness, find_field): Call preceding_pos,
not preceeding_pos.
(Ffield_string_no_properties): New function.
(text_property_stickiness, preceeding_pos): New functions.
(Ffield_string): Remove PROPS parameter.
(find_field): Add MERGE_AT_BOUNDARY parameter.
Rewrite to use stickiness of `field' property to resolve
ambiguous cases.
(Ffield_beginning, Ffield_end): Add ESCAPE_FROM_EDGE parameter.
(Fconstrain_to_field): Likewise.
(syms_of_editfns): Init Sfield_string_no_properties.
(Ffield_string, Ferase_field, Ffield_end):
Supply new MERGE_AT_BOUNDARY argument to find_field.
(Fline_beginning_position, Fline_end_position): Supply new
ESCAPE_FROM_EDGE parameter to Fconstrain_to_field.
Pass a value of Qt for the ONLY_IN_LINE argument to
Fconstrain_to_field (only matters if N != 1).
(Fconstrain_to_field): Add get/set-current-point
behavior when NEW_POS is nil.
(find_field): Use XSETFASTINT instead of make_number.
(Qfield): New variable.
(find_field, Ferase_field, Ffield_string,
Ffield_beginning, Ffield_end, Fconstrain_to_field): New functions.
(Fline_beginning_position, Fline_end_position): Constrain to any field.
(make_buffer_string_both): Remove minibuffer-prompt hack.
(syms_of_editfns): Initialize Qfield, and subr entries for
field functions above.
author | Gerd Moellmann <gerd@gnu.org> |
---|---|
date | Sun, 17 Oct 1999 12:55:00 +0000 |
parents | 65cab65c4a28 |
children | b7aa6ac26872 |
comparison
equal
deleted
inserted
replaced
26057:0816bcaebc8c | 26058:c11f0832a7c5 |
---|---|
1 /* Lisp functions pertaining to editing. | 1 /* Lisp functions pertaining to editing. |
2 Copyright (C) 1985,86,87,89,93,94,95,96,97,98 Free Software Foundation, Inc. | 2 Copyright (C) 1985,86,87,89,93,94,95,96,97,98, 1999 Free Software Foundation, Inc. |
3 | 3 |
4 This file is part of GNU Emacs. | 4 This file is part of GNU Emacs. |
5 | 5 |
6 GNU Emacs is free software; you can redistribute it and/or modify | 6 GNU Emacs is free software; you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
274 () | 274 () |
275 { | 275 { |
276 return current_buffer->mark; | 276 return current_buffer->mark; |
277 } | 277 } |
278 | 278 |
279 /* Returns the position before POS in the current buffer. POS must not | |
280 be at the beginning of the buffer. */ | |
281 static Lisp_Object | |
282 preceding_pos (int pos) | |
283 { | |
284 int pos_byte = CHAR_TO_BYTE (pos); | |
285 | |
286 /* Decrement POS_BYTE (is all this cruft really necessary?). */ | |
287 if (NILP (current_buffer->enable_multibyte_characters)) | |
288 pos_byte--; | |
289 else | |
290 DEC_POS (pos_byte); | |
291 | |
292 return make_number (BYTE_TO_CHAR (pos_byte)); | |
293 } | |
294 | |
295 /* Returns true if POS1 and POS2 have the same value for text property PROP. */ | |
296 static int | |
297 text_property_eq (prop, pos1, pos2) | |
298 Lisp_Object prop; | |
299 Lisp_Object pos1, pos2; | |
300 { | |
301 Lisp_Object pval1, pval2; | |
302 | |
303 pval1 = Fget_text_property (pos1, prop, Qnil); | |
304 pval2 = Fget_text_property (pos2, prop, Qnil); | |
305 | |
306 return EQ (pval1, pval2); | |
307 } | |
308 | |
309 /* Returns the direction that the text-property PROP would be inherited | |
310 by any new text inserted at POS: 1 if it would be inherited from POS, | |
311 -1 if it would be inherited from POS-1, and 0 if from neither. */ | |
312 static int | |
313 text_property_stickiness (prop, pos) | |
314 Lisp_Object prop; | |
315 Lisp_Object pos; | |
316 { | |
317 Lisp_Object front_sticky; | |
318 | |
319 if (PT > BEGV) | |
320 /* Consider previous position. */ | |
321 { | |
322 Lisp_Object prev_pos, rear_non_sticky; | |
323 | |
324 prev_pos = preceding_pos (pos); | |
325 rear_non_sticky = Fget_text_property (prev_pos, Qrear_nonsticky, Qnil); | |
326 | |
327 if (EQ (rear_non_sticky, Qnil) | |
328 || (CONSP (rear_non_sticky) | |
329 && !Fmemq (prop, rear_non_sticky))) | |
330 /* PROP is not rear-non-sticky, and since this takes precedence over | |
331 any front-stickiness, that must be the answer. */ | |
332 return -1; | |
333 } | |
334 | |
335 /* Consider current position. */ | |
336 front_sticky = Fget_text_property (pos, Qfront_sticky, Qnil); | |
337 | |
338 if (EQ (front_sticky, Qt) | |
339 || (CONSP (front_sticky) | |
340 && Fmemq (prop, front_sticky))) | |
341 /* PROP is front-sticky. */ | |
342 return 1; | |
343 | |
344 /* PROP is not sticky at all. */ | |
345 return 0; | |
346 } | |
347 | |
348 /* Name for the text property we use to distinguish fields. */ | |
349 Lisp_Object Qfield; | |
350 | |
351 /* Returns the field surrounding POS in *BEG and *END; an | |
352 `field' is a region of text with the same `field' property. | |
353 If POS is nil, the position of the current buffer's point is used. | |
354 If MERGE_AT_BOUNDARY is true, then if POS is at the very first | |
355 position of a field, then the beginning of the previous field | |
356 is returned instead of the beginning of POS's field (since the end of | |
357 a field is actually also the beginning of the next input | |
358 field, this behavior is sometimes useful). BEG or END may be 0, in | |
359 which case the corresponding value is not returned. */ | |
360 void | |
361 find_field (pos, merge_at_boundary, beg, end) | |
362 Lisp_Object pos; | |
363 Lisp_Object merge_at_boundary; | |
364 int *beg, *end; | |
365 { | |
366 /* If POS is at the edge of a field, then -1 or 1 depending on | |
367 whether it should be considered as the beginning of the following | |
368 field, or the end of the previous field, respectively. If POS is | |
369 not at a field-boundary, then STICKINESS is 0. */ | |
370 int stickiness = 0; | |
371 | |
372 if (NILP (pos)) | |
373 XSETFASTINT (pos, PT); | |
374 else | |
375 CHECK_NUMBER_COERCE_MARKER (pos, 0); | |
376 | |
377 if (NILP (merge_at_boundary) && XFASTINT (pos) > BEGV) | |
378 /* See if we need to handle the case where POS is at beginning of a | |
379 field, which can also be interpreted as the end of the previous | |
380 field. We decide which one by seeing which field the `field' | |
381 property sticks to. The case where if MERGE_AT_BOUNDARY is | |
382 non-nil (see function comment) is actually the more natural one; | |
383 then we avoid treating the beginning of a field specially. */ | |
384 { | |
385 /* First see if POS is actually *at* a boundary. */ | |
386 Lisp_Object after_field, before_field; | |
387 | |
388 after_field = Fget_text_property (pos, Qfield, Qnil); | |
389 before_field = Fget_text_property (preceding_pos (pos), Qfield, Qnil); | |
390 | |
391 if (! EQ (after_field, before_field)) | |
392 /* We are at a boundary, see which direction is inclusive. */ | |
393 { | |
394 stickiness = text_property_stickiness (Qfield, pos); | |
395 | |
396 if (stickiness == 0) | |
397 /* STICKINESS == 0 means that any inserted text will get a | |
398 `field' text-property of nil, so check to see if that | |
399 matches either of the adjacent characters (this being a | |
400 kind of `stickiness by default'). */ | |
401 { | |
402 if (NILP (before_field)) | |
403 stickiness = -1; /* Sticks to the left. */ | |
404 else if (NILP (after_field)) | |
405 stickiness = 1; /* Sticks to the right. */ | |
406 } | |
407 } | |
408 } | |
409 | |
410 if (beg) | |
411 { | |
412 if (stickiness > 0) | |
413 /* POS is at the edge of a field, and we should consider it as | |
414 the beginning of the following field. */ | |
415 *beg = XFASTINT (pos); | |
416 else | |
417 /* Find the previous field boundary. */ | |
418 { | |
419 Lisp_Object prev; | |
420 prev = Fprevious_single_property_change (pos, Qfield, Qnil, Qnil); | |
421 *beg = NILP(prev) ? BEGV : XFASTINT (prev); | |
422 } | |
423 } | |
424 | |
425 if (end) | |
426 { | |
427 if (stickiness < 0) | |
428 /* POS is at the edge of a field, and we should consider it as | |
429 the end of the previous field. */ | |
430 *end = XFASTINT (pos); | |
431 else | |
432 /* Find the next field boundary. */ | |
433 { | |
434 Lisp_Object next; | |
435 next = Fnext_single_property_change (pos, Qfield, Qnil, Qnil); | |
436 *end = NILP(next) ? ZV : XFASTINT (next); | |
437 } | |
438 } | |
439 } | |
440 | |
441 DEFUN ("erase-field", Ferase_field, Serase_field, 0, 1, "d", | |
442 "Erases the field surrounding POS.\n\ | |
443 A field is a region of text with the same `field' property.\n\ | |
444 If POS is nil, the position of the current buffer's point is used.") | |
445 (pos) | |
446 Lisp_Object pos; | |
447 { | |
448 int beg, end; | |
449 find_field (pos, Qnil, &beg, &end); | |
450 if (beg != end) | |
451 del_range (beg, end); | |
452 } | |
453 | |
454 DEFUN ("field-string", Ffield_string, Sfield_string, 0, 1, 0, | |
455 "Return the contents of the field surrounding POS as a string.\n\ | |
456 A field is a region of text with the same `field' property.\n\ | |
457 If POS is nil, the position of the current buffer's point is used.") | |
458 (pos) | |
459 Lisp_Object pos; | |
460 { | |
461 int beg, end; | |
462 find_field (pos, Qnil, &beg, &end); | |
463 return make_buffer_string (beg, end, 1); | |
464 } | |
465 | |
466 DEFUN ("field-string-no-properties", Ffield_string_no_properties, Sfield_string_no_properties, 0, 1, 0, | |
467 "Return the contents of the field around POS, without text-properties.\n\ | |
468 A field is a region of text with the same `field' property.\n\ | |
469 If POS is nil, the position of the current buffer's point is used.") | |
470 (pos) | |
471 Lisp_Object pos; | |
472 { | |
473 int beg, end; | |
474 find_field (pos, Qnil, &beg, &end); | |
475 return make_buffer_string (beg, end, 0); | |
476 } | |
477 | |
478 DEFUN ("field-beginning", Ffield_beginning, Sfield_beginning, 0, 2, 0, | |
479 "Return the beginning of the field surrounding POS.\n\ | |
480 A field is a region of text with the same `field' property.\n\ | |
481 If POS is nil, the position of the current buffer's point is used.\n\ | |
482 If ESCAPE-FROM-EDGE is non-nil and POS is already at beginning of an\n\ | |
483 field, then the beginning of the *previous* field is returned.") | |
484 (pos, escape_from_edge) | |
485 Lisp_Object pos, escape_from_edge; | |
486 { | |
487 int beg; | |
488 find_field (pos, escape_from_edge, &beg, 0); | |
489 return make_number (beg); | |
490 } | |
491 | |
492 DEFUN ("field-end", Ffield_end, Sfield_end, 0, 2, 0, | |
493 "Return the end of the field surrounding POS.\n\ | |
494 A field is a region of text with the same `field' property.\n\ | |
495 If POS is nil, the position of the current buffer's point is used.\n\ | |
496 If ESCAPE-FROM-EDGE is non-nil and POS is already at end of a field,\n\ | |
497 then the end of the *following* field is returned.") | |
498 (pos, escape_from_edge) | |
499 Lisp_Object pos, escape_from_edge; | |
500 { | |
501 int end; | |
502 find_field (pos, escape_from_edge, 0, &end); | |
503 return make_number (end); | |
504 } | |
505 | |
506 DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 4, 0, | |
507 "Return the position closest to NEW-POS that is in the same field as OLD-POS.\n\ | |
508 A field is a region of text with the same `field' property.\n\ | |
509 If NEW-POS is nil, then the current point is used instead, and set to the\n\ | |
510 constrained position if that is is different.\n\ | |
511 \n\ | |
512 If OLD-POS is at the boundary of two fields, then the allowable\n\ | |
513 positions for NEW-POS depends on the value of the optional argument\n\ | |
514 ESCAPE-FROM-EDGE: If ESCAPE-FROM-EDGE is nil, then NEW-POS is\n\ | |
515 constrained to the field that has the same `field' text-property\n\ | |
516 as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE\n\ | |
517 is non-nil, NEW-POS is constrained to the union of the two adjacent\n\ | |
518 fields.\n\ | |
519 \n\ | |
520 If the optional argument ONLY-IN-LINE is non-nil and constraining\n\ | |
521 NEW-POS would move it to a different line, NEW-POS is returned\n\ | |
522 unconstrained. This useful for commands that move by line, like\n\ | |
523 \\[next-line] or \\[beginning-of-line], which should generally respect field boundaries\n\ | |
524 only in the case where they can still move to the right line.") | |
525 (new_pos, old_pos, escape_from_edge, only_in_line) | |
526 Lisp_Object new_pos, old_pos, escape_from_edge, only_in_line; | |
527 { | |
528 /* If non-zero, then the original point, before re-positioning. */ | |
529 int orig_point = 0; | |
530 | |
531 if (NILP (new_pos)) | |
532 /* Use the current point, and afterwards, set it. */ | |
533 { | |
534 orig_point = PT; | |
535 XSETFASTINT (new_pos, PT); | |
536 } | |
537 | |
538 if (!EQ (new_pos, old_pos) && !text_property_eq (Qfield, new_pos, old_pos)) | |
539 /* NEW_POS is not within the same field as OLD_POS; try to | |
540 move NEW_POS so that it is. */ | |
541 { | |
542 int fwd; | |
543 Lisp_Object field_bound; | |
544 | |
545 CHECK_NUMBER_COERCE_MARKER (new_pos, 0); | |
546 CHECK_NUMBER_COERCE_MARKER (old_pos, 0); | |
547 | |
548 fwd = (XFASTINT (new_pos) > XFASTINT (old_pos)); | |
549 | |
550 if (fwd) | |
551 field_bound = Ffield_end (old_pos, escape_from_edge); | |
552 else | |
553 field_bound = Ffield_beginning (old_pos, escape_from_edge); | |
554 | |
555 if (/* If ONLY_IN_LINE is non-nil, we only constrain NEW_POS if doing | |
556 so would remain within the same line. */ | |
557 NILP (only_in_line) | |
558 /* In that case, see if ESCAPE_FROM_EDGE caused FIELD_BOUND | |
559 to jump to the other side of NEW_POS, which would mean | |
560 that NEW_POS is already acceptable, and that we don't | |
561 have to do the line-check. */ | |
562 || ((XFASTINT (field_bound) < XFASTINT (new_pos)) ? !fwd : fwd) | |
563 /* If not, see if there's no newline intervening between | |
564 NEW_POS and FIELD_BOUND. */ | |
565 || (find_before_next_newline (XFASTINT (new_pos), | |
566 XFASTINT (field_bound), | |
567 fwd ? -1 : 1) | |
568 == XFASTINT (field_bound))) | |
569 /* Constrain NEW_POS to FIELD_BOUND. */ | |
570 new_pos = field_bound; | |
571 | |
572 if (orig_point && XFASTINT (new_pos) != orig_point) | |
573 /* The NEW_POS argument was originally nil, so automatically set PT. */ | |
574 SET_PT (XFASTINT (new_pos)); | |
575 } | |
576 | |
577 return new_pos; | |
578 } | |
579 | |
279 DEFUN ("line-beginning-position", Fline_beginning_position, Sline_beginning_position, | 580 DEFUN ("line-beginning-position", Fline_beginning_position, Sline_beginning_position, |
280 0, 1, 0, | 581 0, 1, 0, |
281 "Return the character position of the first character on the current line.\n\ | 582 "Return the character position of the first character on the current line.\n\ |
282 With argument N not nil or 1, move forward N - 1 lines first.\n\ | 583 With argument N not nil or 1, move forward N - 1 lines first.\n\ |
283 If scan reaches end of buffer, return that position.\n\ | 584 If scan reaches end of buffer, return that position.\n\ |
298 orig = PT; | 599 orig = PT; |
299 orig_byte = PT_BYTE; | 600 orig_byte = PT_BYTE; |
300 Fforward_line (make_number (XINT (n) - 1)); | 601 Fforward_line (make_number (XINT (n) - 1)); |
301 end = PT; | 602 end = PT; |
302 | 603 |
303 if (INTEGERP (current_buffer->prompt_end_charpos) | |
304 && orig >= XFASTINT (current_buffer->prompt_end_charpos) | |
305 && end < XFASTINT (current_buffer->prompt_end_charpos)) | |
306 end = XFASTINT (current_buffer->prompt_end_charpos); | |
307 | |
308 SET_PT_BOTH (orig, orig_byte); | 604 SET_PT_BOTH (orig, orig_byte); |
309 | 605 |
310 return make_number (end); | 606 /* Return END constrained to the current input field. */ |
607 return Fconstrain_to_field (make_number (end), make_number (orig), Qnil, Qt); | |
311 } | 608 } |
312 | 609 |
313 DEFUN ("line-end-position", Fline_end_position, Sline_end_position, | 610 DEFUN ("line-end-position", Fline_end_position, Sline_end_position, |
314 0, 1, 0, | 611 0, 1, 0, |
315 "Return the character position of the last character on the current line.\n\ | 612 "Return the character position of the last character on the current line.\n\ |
317 If scan reaches end of buffer, return that position.\n\ | 614 If scan reaches end of buffer, return that position.\n\ |
318 This function does not move point.") | 615 This function does not move point.") |
319 (n) | 616 (n) |
320 Lisp_Object n; | 617 Lisp_Object n; |
321 { | 618 { |
619 int end_pos; | |
620 register int orig = PT; | |
621 | |
322 if (NILP (n)) | 622 if (NILP (n)) |
323 XSETFASTINT (n, 1); | 623 XSETFASTINT (n, 1); |
324 else | 624 else |
325 CHECK_NUMBER (n, 0); | 625 CHECK_NUMBER (n, 0); |
326 | 626 |
327 return make_number (find_before_next_newline | 627 end_pos = find_before_next_newline (orig, 0, XINT (n) - (XINT (n) <= 0)); |
328 (PT, 0, XINT (n) - (XINT (n) <= 0))); | 628 |
629 /* Return END_POS constrained to the current input field. */ | |
630 return | |
631 Fconstrain_to_field (make_number (end_pos), make_number (orig), Qnil, Qt); | |
329 } | 632 } |
330 | 633 |
331 Lisp_Object | 634 Lisp_Object |
332 save_excursion_save () | 635 save_excursion_save () |
333 { | 636 { |
1722 If narrowing is in effect, this function returns only the visible part\n\ | 2025 If narrowing is in effect, this function returns only the visible part\n\ |
1723 of the buffer. If in a mini-buffer, don't include the prompt in the\n\ | 2026 of the buffer. If in a mini-buffer, don't include the prompt in the\n\ |
1724 string returned.") | 2027 string returned.") |
1725 () | 2028 () |
1726 { | 2029 { |
1727 int start = BEGV; | 2030 return make_buffer_string (BEGV, ZV, 1); |
1728 | |
1729 if (INTEGERP (current_buffer->prompt_end_charpos)) | |
1730 { | |
1731 int len = XFASTINT (current_buffer->prompt_end_charpos); | |
1732 start = min (ZV, max (len, start)); | |
1733 } | |
1734 | |
1735 return make_buffer_string (start, ZV, 1); | |
1736 } | 2031 } |
1737 | 2032 |
1738 DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring, | 2033 DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring, |
1739 1, 3, 0, | 2034 1, 3, 0, |
1740 "Insert before point a substring of the contents of buffer BUFFER.\n\ | 2035 "Insert before point a substring of the contents of buffer BUFFER.\n\ |
3417 defsubr (&Smark_marker); | 3712 defsubr (&Smark_marker); |
3418 defsubr (&Spoint); | 3713 defsubr (&Spoint); |
3419 defsubr (&Sregion_beginning); | 3714 defsubr (&Sregion_beginning); |
3420 defsubr (&Sregion_end); | 3715 defsubr (&Sregion_end); |
3421 | 3716 |
3717 staticpro (&Qfield); | |
3718 Qfield = intern ("field"); | |
3719 defsubr (&Sfield_beginning); | |
3720 defsubr (&Sfield_end); | |
3721 defsubr (&Sfield_string); | |
3722 defsubr (&Sfield_string_no_properties); | |
3723 defsubr (&Serase_field); | |
3724 defsubr (&Sconstrain_to_field); | |
3725 | |
3422 defsubr (&Sline_beginning_position); | 3726 defsubr (&Sline_beginning_position); |
3423 defsubr (&Sline_end_position); | 3727 defsubr (&Sline_end_position); |
3424 | 3728 |
3425 /* defsubr (&Smark); */ | 3729 /* defsubr (&Smark); */ |
3426 /* defsubr (&Sset_mark); */ | 3730 /* defsubr (&Sset_mark); */ |