comparison src/indent.c @ 288:e11d67e05968 r21-0b42

Import from CVS: tag r21-0b42
author cvs
date Mon, 13 Aug 2007 10:35:54 +0200
parents 6330739388db
children 70ad99077275
comparison
equal deleted inserted replaced
287:13a0bd77a29d 288:e11d67e05968
647 vmotion (struct window *w, Bufpos orig, int vtarget, int *ret_vpos) 647 vmotion (struct window *w, Bufpos orig, int vtarget, int *ret_vpos)
648 { 648 {
649 return vmotion_1 (w, orig, vtarget, ret_vpos, NULL); 649 return vmotion_1 (w, orig, vtarget, ret_vpos, NULL);
650 } 650 }
651 651
652 /* Helper for Fvertical_motion and Fvertical_motion_pixels. 652 /* Helper for Fvertical_motion.
653 * Share as much code as possible so these stay synched.
654 */ 653 */
655 static 654 static
656 Lisp_Object vertical_motion_1 (Lisp_Object lines, Lisp_Object window, 655 Lisp_Object vertical_motion_1 (Lisp_Object lines, Lisp_Object window,
657 int pixels) 656 int pixels)
658 { 657 {
690 w->buffer); 689 w->buffer);
691 690
692 return make_int (value); 691 return make_int (value);
693 } 692 }
694 693
695 DEFUN ("vertical-motion", Fvertical_motion, 1, 2, 0, /* 694 DEFUN ("vertical-motion", Fvertical_motion, 1, 3, 0, /*
696 Move to start of frame line LINES lines down. 695 Move to start of frame line LINES lines down.
697 If LINES is negative, this is moving up. 696 If LINES is negative, this is moving up.
698 Optional second argument is WINDOW to move in, 697 Optional second argument is WINDOW to move in,
699 the default is the selected window. 698 the default is the selected window.
700 699
701 Sets point to position found; this may be start of line 700 Sets point to position found; this may be start of line
702 or just the start of a continuation line. 701 or just the start of a continuation line.
703 Returns number of lines moved; may be closer to zero than LINES 702 If optional third argument PIXELS is nil, returns number
704 if beginning or end of buffer was reached. 703 of lines moved; may be closer to zero than LINES if beginning
704 or end of buffer was reached. If PIXELS is non-nil, the
705 vertical pixel height of the motion which took place is
706 returned instead of the actual number of lines moved. A
707 motion of zero lines returns the height of the current line.
705 708
706 Note that `vertical-motion' sets WINDOW's buffer's point, not 709 Note that `vertical-motion' sets WINDOW's buffer's point, not
707 WINDOW's point. (This differs from FSF Emacs, which buggily always 710 WINDOW's point. (This differs from FSF Emacs, which buggily always
708 sets current buffer's point, regardless of WINDOW.) 711 sets current buffer's point, regardless of WINDOW.)
709 */ 712 */
710 (lines, window)) 713 (lines, window, pixels))
711 { 714 {
712 return vertical_motion_1 (lines, window, /* pixels = */ 0); 715 return vertical_motion_1 (lines, window, !NILP (pixels));
713 } 716 }
714 717
715 DEFUN ("vertical-motion-pixels", Fvertical_motion_pixels, 1, 2, 0, /* 718 /*
716 Move to start of frame line LINES lines down. 719 * Like vmotion() but requested and returned movement is in pixels.
717 If LINES is negative, this is moving up. 720 * HOW specifies the stopping condition. Positive means move at least
721 * PIXELS. Negative means at most. Zero means as close as possible.
722 */
723 Bufpos
724 vmotion_pixels (Lisp_Object window, Bufpos start, int pixels, int how,
725 int *motion)
726 {
727 struct window *w;
728 Bufpos eobuf, bobuf;
729 int defheight;
730 int needed;
731 int line, next;
732 int remain, abspix, dirn;
733 int elt, nelt;
734 int i;
735 line_start_cache_dynarr *cache;
736 int previous = -1;
737 int lines;
738
739 if (NILP (window))
740 window = Fselected_window (Qnil);
741
742 CHECK_WINDOW (window);
743 w = XWINDOW (window);
744
745 eobuf = BUF_ZV (XBUFFER (w->buffer));
746 bobuf = BUF_BEGV (XBUFFER (w->buffer));
747
748 default_face_height_and_width (window, &defheight, NULL);
749
750 /* guess num lines needed in line start cache + a few extra */
751 abspix = abs (pixels);
752 needed = (abspix + defheight-1)/defheight + 3;
753
754 dirn = (pixels >= 0) ? 1 : -1;
755
756 while (1)
757 {
758 elt = point_in_line_start_cache (w, start, needed);
759 assert (elt >= 0); /* in the cache */
760
761 cache = w->line_start_cache;
762 nelt = Dynarr_length (cache);
763
764 *motion = 0;
765
766 if (pixels == 0)
767 /* No vertical motion requested so we just return the position
768 of the beginning of the current display line. */
769 return Dynarr_atp (cache, elt)->start;
770
771 if ((dirn < 0 && elt == 0 &&
772 Dynarr_atp (cache, elt)->start <= bobuf) ||
773 (dirn > 0 && elt == nelt-1 &&
774 Dynarr_atp (cache, elt)->end >= eobuf))
775 return Dynarr_atp (cache, elt)->start;
776
777 remain = abspix;
778 for (i = elt; (dirn > 0) ? (i < nelt) : (i > 0); i += dirn)
779 {
780 /* cache line we're considering moving over */
781 int ii = (dirn > 0) ? i : i-1;
782
783 if (remain < 0)
784 return Dynarr_atp (cache, i)->start;
785
786 line = Dynarr_atp (cache, ii)->height;
787 next = remain - line;
788
789 /* is stopping condition satisfied? */
790 if ((how > 0 && remain <= 0) || /* at least */
791 (how < 0 && next < 0) || /* at most */
792 (how == 0 && remain <= abs (next))) /* closest */
793 return Dynarr_atp (cache, i)->start;
794
795 /* moving down and nowhere left to go? */
796 if (dirn > 0 && Dynarr_atp (cache, ii)->end >= eobuf)
797 return Dynarr_atp (cache, ii)->start;
798
799 /* take the step */
800 remain = next;
801 *motion += dirn * line;
802
803 /* moving up and nowhere left to go? */
804 if (dirn < 0 && Dynarr_atp (cache, ii)->start <= bobuf)
805 return Dynarr_atp (cache, ii)->start;
806 }
807
808 /* get here => need more cache lines. try again. */
809 assert (abs (*motion) > previous); /* progress? */
810 previous = abs (*motion);
811
812 lines = (pixels < 0) ? elt : (nelt - elt);
813 needed += (remain*lines + abspix-1)/abspix + 3;
814 }
815
816 RETURN_NOT_REACHED(0) /* shut up compiler */
817 }
818
819 DEFUN ("vertical-motion-pixels", Fvertical_motion_pixels, 1, 3, 0, /*
820 Move to start of frame line PIXELS vertical pixels down.
821 If PIXELS is negative, this is moving up.
822 The actual vertical motion in pixels is returned.
823
718 Optional second argument is WINDOW to move in, 824 Optional second argument is WINDOW to move in,
719 the default is the selected window. 825 the default is the selected window.
720 826
721 This function is identical in behavior to `vertical-motion' 827 Optional third argument HOW specifies when to stop. A value
722 except that the vertical pixel height of the motion which 828 less than zero indicates that the motion should be no more
723 took place is returned instead of the actual number of lines 829 than PIXELS. A value greater than zero indicates that the
724 moved. A motion of zero lines returns the height of the 830 motion should be at least PIXELS. Any other value indicates
725 current line. 831 that the motion should be as close as possible to PIXELS.
726 */ 832 */
727 (lines, window)) 833 (pixels, window, how))
728 { 834 {
729 return vertical_motion_1 (lines, window, /* pixels = */ 1); 835 Bufpos bufpos;
836 Bufpos orig;
837 int selected;
838 int motion;
839 int howto;
840 struct window *w;
841
842 if (NILP (window))
843 window = Fselected_window (Qnil);
844
845 CHECK_WINDOW (window);
846 CHECK_INT (pixels);
847
848 selected = (EQ (window, Fselected_window (Qnil)));
849
850 w = XWINDOW (window);
851
852 orig = selected ? BUF_PT (XBUFFER (w->buffer))
853 : marker_position (w->pointm[CURRENT_DISP]);
854
855 howto = INTP (how) ? XINT (how) : 0;
856
857 bufpos = vmotion_pixels (window, orig, XINT (pixels), howto, &motion);
858
859 if (selected)
860 BUF_SET_PT (XBUFFER (w->buffer), bufpos);
861 else
862 set_marker_restricted (w->pointm[CURRENT_DISP],
863 make_int(bufpos),
864 w->buffer);
865
866 return make_int (motion);
730 } 867 }
731 868
732 869
733 void 870 void
734 syms_of_indent (void) 871 syms_of_indent (void)