aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJim Blandy1994-10-08 22:14:04 +0000
committerJim Blandy1994-10-08 22:14:04 +0000
commit0aa01123caabb74724a77580e388586808a77767 (patch)
tree024b25b896014def6696d6ce283ce60772a61571 /src
parentef5623efbd9b2579aaef52f18d307281dd6d0a0a (diff)
downloademacs-0aa01123caabb74724a77580e388586808a77767.tar.gz
emacs-0aa01123caabb74724a77580e388586808a77767.zip
* indent.c: #include "region-cache.h".
(character_width, disptab_matches_widthtab, recompute_width_table, width_run_cache_on_off): New functions. (compute_motion): Call width_run_cache_on_off. If this buffer's width run cache is enabled, consult it to see if we need to traverse a region character-by-character; store information in the cache after doing so. Call find_before_next_newline instead of writing out an equivalent loop explicitly, to take advantage of the newline cache. Doc fixes.
Diffstat (limited to 'src')
-rw-r--r--src/indent.c385
1 files changed, 308 insertions, 77 deletions
diff --git a/src/indent.c b/src/indent.c
index 4dacd1eddff..5e369e8d976 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -28,6 +28,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
28#include "termopts.h" 28#include "termopts.h"
29#include "disptab.h" 29#include "disptab.h"
30#include "intervals.h" 30#include "intervals.h"
31#include "region-cache.h"
31 32
32/* Indentation can insert tabs if this is non-zero; 33/* Indentation can insert tabs if this is non-zero;
33 otherwise always uses spaces */ 34 otherwise always uses spaces */
@@ -64,6 +65,112 @@ buffer_display_table ()
64 return 0; 65 return 0;
65} 66}
66 67
68/* Width run cache considerations. */
69
70/* Return the width of character C under display table DP. */
71static int
72character_width (c, dp)
73 int c;
74 struct Lisp_Vector *dp;
75{
76 Lisp_Object elt;
77
78 /* These width computations were determined by examining the cases
79 in display_text_line. */
80
81 /* Some characters are never handled by the display table. */
82 if (c == '\n' || c == '\t' || c == '\015')
83 return 0;
84
85 /* Everything else might be handled by the display table, if it's
86 present and the element is right. */
87 else if (dp && (elt = DISP_CHAR_VECTOR (dp, c),
88 VECTORP (elt)))
89 return XVECTOR (elt)->size;
90
91 /* In the absence of display table perversities, printing characters
92 have width 1. */
93 else if (c >= 040 && c < 0177)
94 return 1;
95
96 /* Everybody else (control characters, metacharacters) has other
97 widths. We could return their actual widths here, but they
98 depend on things like ctl_arrow and crud like that, and they're
99 not very common at all. So we'll just claim we don't know their
100 widths. */
101 else
102 return 0;
103}
104
105/* Return true iff the display table DISPTAB specifies the same widths
106 for characters as WIDTHTAB. We use this to decide when to
107 invalidate the buffer's width_run_cache. */
108int
109disptab_matches_widthtab (disptab, widthtab)
110 struct Lisp_Vector *disptab;
111 struct Lisp_Vector *widthtab;
112{
113 int i;
114
115 if (widthtab->size != 256)
116 abort ();
117
118 for (i = 0; i < 256; i++)
119 if (character_width (i, disptab)
120 != XFASTINT (widthtab->contents[i]))
121 return 0;
122
123 return 1;
124}
125
126/* Recompute BUF's width table, using the display table DISPTAB. */
127void
128recompute_width_table (buf, disptab)
129 struct buffer *buf;
130 struct Lisp_Vector *disptab;
131{
132 int i;
133 struct Lisp_Vector *widthtab
134 = (VECTORP (buf->width_table)
135 ? XVECTOR (buf->width_table)
136 : XVECTOR (Fmake_vector (make_number (256), make_number (0))));
137
138 if (widthtab->size != 256)
139 abort ();
140
141 for (i = 0; i < 256; i++)
142 widthtab->contents[i] = character_width (i, disptab);
143}
144
145/* Allocate or free the width run cache, as requested by the current
146 state of current_buffer's cache_long_line_scans variable. */
147static void
148width_run_cache_on_off ()
149{
150 if (NILP (current_buffer->cache_long_line_scans))
151 {
152 /* It should be off. */
153 if (current_buffer->width_run_cache)
154 {
155 free_region_cache (current_buffer->width_run_cache);
156 current_buffer->width_run_cache = 0;
157 current_buffer->width_table = Qnil;
158 }
159 }
160 else
161 {
162 /* It should be on. */
163 if (current_buffer->width_run_cache == 0)
164 {
165 current_buffer->width_run_cache = new_region_cache ();
166 current_buffer->width_table = Fmake_vector (make_number (256),
167 make_number (0));
168 recompute_width_table (current_buffer, buffer_display_table ());
169 }
170 }
171}
172
173
67DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0, 174DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
68 "Return the horizontal position of point. Beginning of line is column 0.\n\ 175 "Return the horizontal position of point. Beginning of line is column 0.\n\
69This is calculated by adding together the widths of all the displayed\n\ 176This is calculated by adding together the widths of all the displayed\n\
@@ -173,7 +280,6 @@ current_column ()
173 return col; 280 return col;
174} 281}
175 282
176
177DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ", 283DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
178 "Indent from point with tabs and spaces until COLUMN is reached.\n\ 284 "Indent from point with tabs and spaces until COLUMN is reached.\n\
179Optional second argument MIN says always do at least MIN spaces\n\ 285Optional second argument MIN says always do at least MIN spaces\n\
@@ -221,6 +327,7 @@ even if that goes past COLUMN; by default, MIN is zero.")
221 XSETINT (col, mincol); 327 XSETINT (col, mincol);
222 return col; 328 return col;
223} 329}
330
224 331
225DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation, 332DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
226 0, 0, 0, 333 0, 0, 0,
@@ -282,6 +389,7 @@ indented_beyond_p (pos, column)
282 pos = find_next_newline_no_quit (pos - 1, -1); 389 pos = find_next_newline_no_quit (pos - 1, -1);
283 return (position_indentation (pos) >= column); 390 return (position_indentation (pos) >= column);
284} 391}
392
285 393
286DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0, 394DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
287 "Move point to column COLUMN in the current line.\n\ 395 "Move point to column COLUMN in the current line.\n\
@@ -379,13 +487,18 @@ and if COLUMN is in the middle of a tab character, change it to spaces.")
379 XSETFASTINT (val, col); 487 XSETFASTINT (val, col);
380 return val; 488 return val;
381} 489}
490
382 491
492/* compute_motion: compute buffer posn given screen posn and vice versa */
493
383struct position val_compute_motion; 494struct position val_compute_motion;
384 495
385/* Scan the current buffer forward from offset FROM, pretending that 496/* Scan the current buffer forward from offset FROM, pretending that
386 this is at line FROMVPOS, column FROMHPOS, until reaching buffer 497 this is at line FROMVPOS, column FROMHPOS, until reaching buffer
387 offset TO or line TOVPOS, column TOHPOS (whichever comes first), 498 offset TO or line TOVPOS, column TOHPOS (whichever comes first),
388 and return the ending buffer position and screen location. 499 and return the ending buffer position and screen location. If we
500 can't hit the requested column exactly (because of a tab or other
501 multi-column character), overshoot.
389 502
390 WIDTH is the number of columns available to display text; 503 WIDTH is the number of columns available to display text;
391 compute_motion uses this to handle continuation lines and such. 504 compute_motion uses this to handle continuation lines and such.
@@ -397,8 +510,14 @@ struct position val_compute_motion;
397 510
398 compute_motion returns a pointer to a struct position. The bufpos 511 compute_motion returns a pointer to a struct position. The bufpos
399 member gives the buffer position at the end of the scan, and hpos 512 member gives the buffer position at the end of the scan, and hpos
400 and vpos give its cartesian location. I'm not clear on what the 513 and vpos give its cartesian location. prevhpos is the column at
401 other members are. 514 which the character before bufpos started, and contin is non-zero
515 if we reached the current line by continuing the previous.
516
517 Note that FROMHPOS and TOHPOS should be expressed in real screen
518 columns, taking HSCROLL and the truncation glyph at the left margin
519 into account. That is, beginning-of-line moves you to the hpos
520 -HSCROLL + (HSCROLL > 0).
402 521
403 Note that FROMHPOS and TOHPOS should be expressed in real screen 522 Note that FROMHPOS and TOHPOS should be expressed in real screen
404 columns, taking HSCROLL and the truncation glyph at the left margin 523 columns, taking HSCROLL and the truncation glyph at the left margin
@@ -452,7 +571,7 @@ compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, ta
452 = (INTEGERP (current_buffer->selective_display) 571 = (INTEGERP (current_buffer->selective_display)
453 ? XINT (current_buffer->selective_display) 572 ? XINT (current_buffer->selective_display)
454 : !NILP (current_buffer->selective_display) ? -1 : 0); 573 : !NILP (current_buffer->selective_display) ? -1 : 0);
455 int prev_vpos, prev_hpos = 0; 574 int prev_vpos = vpos, prev_hpos = 0;
456 int selective_rlen 575 int selective_rlen
457 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp)) 576 = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
458 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0); 577 ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
@@ -462,8 +581,30 @@ compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, ta
462 Lisp_Object prop, position; 581 Lisp_Object prop, position;
463#endif 582#endif
464 583
584 /* For computing runs of characters with similar widths.
585 Invariant: width_run_width is zero, or all the characters
586 from width_run_start to width_run_end have a fixed width of
587 width_run_width. */
588 int width_run_start = from;
589 int width_run_end = from;
590 int width_run_width = 0;
591 Lisp_Object *width_table;
592
593 /* The next buffer pos where we should consult the width run cache. */
594 int next_width_run = from;
595
596 width_run_cache_on_off ();
597 if (dp == buffer_display_table ())
598 width_table = (VECTORP (current_buffer->width_table)
599 ? XVECTOR (current_buffer->width_table)->contents
600 : 0);
601 else
602 /* If the window has its own display table, we can't use the width
603 run cache, because that's based on the buffer's display table. */
604 width_table = 0;
605
465 if (tab_width <= 0 || tab_width > 1000) tab_width = 8; 606 if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
466 for (pos = from; pos < to; pos++) 607 for (pos = from; pos < to; )
467 { 608 {
468 /* Stop if past the target screen position. */ 609 /* Stop if past the target screen position. */
469 if (vpos > tovpos 610 if (vpos > tovpos
@@ -504,74 +645,158 @@ compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, ta
504 if (pos >= to) 645 if (pos >= to)
505 break; 646 break;
506#endif 647#endif
507 c = FETCH_CHAR (pos); 648
508 if (c >= 040 && c < 0177 649 /* Consult the width run cache to see if we can avoid inspecting
509 && (dp == 0 || !VECTORP (DISP_CHAR_VECTOR (dp, c)))) 650 the text character-by-character. */
510 hpos++; 651 if (current_buffer->width_run_cache && pos >= next_width_run)
511 else if (c == '\t') 652 {
512 { 653 int run_end;
513 hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0) 654 int common_width
514 /* Add tab_width here to make sure positive. 655 = region_cache_forward (current_buffer,
515 hpos can be negative after continuation 656 current_buffer->width_run_cache,
516 but can't be less than -tab_width. */ 657 pos, &run_end);
517 + tab_width) 658
518 % tab_width); 659 /* A width of zero means the character's width varies (like
519 } 660 a tab), is meaningless (like a newline), or we just don't
520 else if (c == '\n') 661 want to skip over it for some other reason. */
521 { 662 if (common_width != 0)
522 if (selective > 0 && indented_beyond_p (pos + 1, selective)) 663 {
523 { 664 int run_end_hpos;
524 /* Skip any number of invisible lines all at once */ 665
525 do 666 /* Don't go past the final buffer posn the user
526 { 667 requested. */
527 while (++pos < to && FETCH_CHAR (pos) != '\n'); 668 if (run_end > to)
528 } 669 run_end = to;
529 while (pos < to && indented_beyond_p (pos + 1, selective)); 670
530 pos--; /* Reread the newline on the next pass. */ 671 run_end_hpos = hpos + (run_end - pos) * common_width;
531 /* Allow for the " ..." that is displayed for them. */ 672
532 if (selective_rlen) 673 /* Don't go past the final horizontal position the user
533 { 674 requested. */
534 hpos += selective_rlen; 675 if (vpos == tovpos && run_end_hpos > tohpos)
535 if (hpos >= width) 676 {
536 hpos = width; 677 run_end = pos + (tohpos - hpos) / common_width;
537 } 678 run_end_hpos = hpos + (run_end - pos) * common_width;
538 /* We have skipped the invis text, but not the newline after. */ 679 }
539 } 680
540 else 681 /* Don't go past the margin. */
541 { 682 if (run_end_hpos >= width)
542 /* A visible line. */ 683 {
543 vpos++; 684 run_end = pos + (width - hpos) / common_width;
544 hpos = 0; 685 run_end_hpos = hpos + (run_end - pos) * common_width;
545 hpos -= hscroll; 686 }
546 if (hscroll > 0) hpos++; /* Truncation glyph on column 0 */ 687
547 tab_offset = 0; 688 hpos = run_end_hpos;
548 } 689 if (run_end > pos)
549 } 690 prev_hpos = hpos - common_width;
550 else if (c == CR && selective < 0) 691 pos = run_end;
551 { 692 }
552 /* In selective display mode, 693
553 everything from a ^M to the end of the line is invisible */ 694 next_width_run = run_end + 1;
554 while (pos < to && FETCH_CHAR (pos) != '\n') pos++; 695 }
555 /* Stop *before* the real newline. */ 696
556 pos--; 697 /* We have to scan the text character-by-character. */
557 /* Allow for the " ..." that is displayed for them. */
558 if (selective_rlen)
559 {
560 hpos += selective_rlen;
561 if (hpos >= width)
562 hpos = width;
563 }
564 }
565 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
566 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
567 else 698 else
568 hpos += (ctl_arrow && c < 0200) ? 2 : 4; 699 {
700 c = FETCH_CHAR (pos);
701 pos++;
702
703 /* Perhaps add some info to the width_run_cache. */
704 if (current_buffer->width_run_cache)
705 {
706 /* Is this character part of the current run? If so, extend
707 the run. */
708 if (pos - 1 == width_run_end
709 && width_table[c] == width_run_width)
710 width_run_end = pos;
711
712 /* The previous run is over, since this is a character at a
713 different position, or a different width. */
714 else
715 {
716 /* Have we accumulated a run to put in the cache?
717 (Currently, we only cache runs of width == 1. */
718 if (width_run_start < width_run_end
719 && width_run_width == 1)
720 know_region_cache (current_buffer,
721 current_buffer->width_run_cache,
722 width_run_start, width_run_end);
723
724 /* Start recording a new width run. */
725 width_run_width = width_table[c];
726 width_run_start = pos - 1;
727 width_run_end = pos;
728 }
729 }
730
731 if (c >= 040 && c < 0177
732 && (dp == 0 || ! VECTORP (DISP_CHAR_VECTOR (dp, c))))
733 hpos++;
734 else if (c == '\t')
735 {
736 hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0)
737 /* Add tab_width here to make sure
738 positive. hpos can be negative
739 after continuation but can't be
740 less than -tab_width. */
741 + tab_width)
742 % tab_width);
743 }
744 else if (c == '\n')
745 {
746 if (selective > 0 && indented_beyond_p (pos, selective))
747 {
748 /* Skip any number of invisible lines all at once */
749 do
750 pos = find_before_next_newline (pos, to, 1);
751 while (pos < to
752 && indented_beyond_p (pos, selective));
753 /* Allow for the " ..." that is displayed for them. */
754 if (selective_rlen)
755 {
756 hpos += selective_rlen;
757 if (hpos >= width)
758 hpos = width;
759 }
760 /* We have skipped the invis text, but not the
761 newline after. */
762 }
763 else
764 {
765 /* A visible line. */
766 vpos++;
767 hpos = 0;
768 hpos -= hscroll;
769 /* Count the truncation glyph on column 0 */
770 if (hscroll > 0)
771 hpos++;
772 tab_offset = 0;
773 }
774 }
775 else if (c == CR && selective < 0)
776 {
777 /* In selective display mode,
778 everything from a ^M to the end of the line is invisible.
779 Stop *before* the real newline. */
780 pos = find_before_next_newline (pos, to, 1);
781 /* Allow for the " ..." that is displayed for them. */
782 if (selective_rlen)
783 {
784 hpos += selective_rlen;
785 if (hpos >= width)
786 hpos = width;
787 }
788 }
789 else if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
790 hpos += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
791 else
792 hpos += (ctl_arrow && c < 0200) ? 2 : 4;
793 }
569 794
570 /* Handle right margin. */ 795 /* Handle right margin. */
571 if (hpos >= width 796 if (hpos >= width
572 && (hpos > width 797 && (hpos > width
573 || (pos < ZV - 1 798 || (pos < ZV
574 && FETCH_CHAR (pos + 1) != '\n'))) 799 && FETCH_CHAR (pos) != '\n')))
575 { 800 {
576 if (vpos > tovpos 801 if (vpos > tovpos
577 || (vpos == tovpos && hpos >= tohpos)) 802 || (vpos == tovpos && hpos >= tohpos))
@@ -582,8 +807,7 @@ compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, ta
582 || !NILP (current_buffer->truncate_lines)) 807 || !NILP (current_buffer->truncate_lines))
583 { 808 {
584 /* Truncating: skip to newline. */ 809 /* Truncating: skip to newline. */
585 while (pos < to && FETCH_CHAR (pos) != '\n') pos++; 810 pos = find_before_next_newline (pos, to, 1);
586 pos--;
587 hpos = width; 811 hpos = width;
588 } 812 }
589 else 813 else
@@ -597,6 +821,13 @@ compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, ta
597 } 821 }
598 } 822 }
599 823
824 /* Remember any final width run in the cache. */
825 if (current_buffer->width_run_cache
826 && width_run_width == 1
827 && width_run_start < width_run_end)
828 know_region_cache (current_buffer, current_buffer->width_run_cache,
829 width_run_start, width_run_end);
830
600 val_compute_motion.bufpos = pos; 831 val_compute_motion.bufpos = pos;
601 val_compute_motion.hpos = hpos; 832 val_compute_motion.hpos = hpos;
602 val_compute_motion.vpos = vpos; 833 val_compute_motion.vpos = vpos;
@@ -710,8 +941,8 @@ DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
710 941
711} 942}
712 943
713/* Return the column of position POS in window W's buffer, 944/* Return the column of position POS in window W's buffer.
714 rounded down to a multiple of the internal width of W. 945 The result is rounded down to a multiple of the internal width of W.
715 This is the amount of indentation of position POS 946 This is the amount of indentation of position POS
716 that is not visible in its horizontal position in the window. */ 947 that is not visible in its horizontal position in the window. */
717 948
@@ -732,10 +963,8 @@ pos_tab_offset (w, pos)
732 return col - (col % width); 963 return col - (col % width);
733} 964}
734 965
735/* start_hpos is the hpos of the first character of the buffer: 966
736 zero except for the minibuffer window, 967/* Fvertical_motion and vmotion */
737 where it is the width of the prompt. */
738
739struct position val_vmotion; 968struct position val_vmotion;
740 969
741struct position * 970struct position *
@@ -884,6 +1113,8 @@ if beginning or end of buffer was reached.")
884 return make_number (pos.vpos); 1113 return make_number (pos.vpos);
885} 1114}
886 1115
1116/* file's initialization. */
1117
887syms_of_indent () 1118syms_of_indent ()
888{ 1119{
889 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode, 1120 DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,