# HG changeset patch # User Richard M. Stallman # Date 732755058 0 # Node ID 00e3cc81c1befbbea431f6f80856f47d73dfffb4 # Parent 560f7fcb759c74875f07b91627637a3e77ba87b6 (decode_mode_spec): Handle `%l'. (display_count_lines): New function. (redisplay_window): Update base_line_number and base_line_pos fields. Always update mode line if it's an integer. diff -r 560f7fcb759c -r 00e3cc81c1be src/xdisp.c --- a/src/xdisp.c Sun Mar 21 22:58:10 1993 +0000 +++ b/src/xdisp.c Sun Mar 21 23:04:18 1993 +0000 @@ -129,6 +129,7 @@ static char *decode_mode_spec (); static int display_string (); static void display_menu_bar (); +static int display_count_lines (); /* Prompt to display in front of the minibuffer contents */ char *minibuf_prompt; @@ -168,6 +169,12 @@ since last redisplay that finished */ int windows_or_buffers_changed; +/* Nonzero after display_mode_line if %l was used + and it displayed a line number. */ +int line_number_displayed; + +/* Maximum buffer size for which to display line numbers. */ +int line_number_display_limit; /* Specify m, a string, as a message in the minibuf. If m is 0, clear out any existing message, and let the minibuffer text show through. */ @@ -819,9 +826,11 @@ startp = marker_position (w->start); /* Handle case where place to start displaying has been specified, - unless the specified location is outside the visible range. */ + unless the specified location is outside the accessible range. */ if (!NILP (w->force_start)) { + /* Forget any recorded base line for line number display. */ + w->base_line_number = Qnil; w->update_mode_line = Qt; w->force_start = Qnil; XFASTINT (w->last_modified) = 0; @@ -928,7 +937,12 @@ /* If point has not moved off frame, accept the results */ try_window (window, startp); if (cursor_vpos >= 0) - goto done; + { + if (!just_this_one || clip_changed || beg_unchanged < startp) + /* Forget any recorded base line for line number display. */ + w->base_line_number = Qnil; + goto done; + } else cancel_my_columns (w); } @@ -955,7 +969,12 @@ { try_window (window, pos.bufpos); if (cursor_vpos >= 0) - goto done; + { + if (!just_this_one || clip_changed || beg_unchanged < startp) + /* Forget any recorded base line for line number display. */ + w->base_line_number = Qnil; + goto done; + } else cancel_my_columns (w); } @@ -965,6 +984,9 @@ /* Finally, just choose place to start which centers point */ recenter: + /* Forget any previously recorded base line for line number display. */ + w->base_line_number = Qnil; + pos = *vmotion (point, - height / 2, width, hscroll, window); try_window (window, pos.bufpos); @@ -973,12 +995,19 @@ (startp == BEGV || FETCH_CHAR (startp - 1) == '\n') ? Qt : Qnil; done: - /* If window not full width, must redo its mode line - if the window to its side is being redone */ if ((!NILP (w->update_mode_line) - || (!just_this_one && width < FRAME_WIDTH (f) - 1)) + /* If window not full width, must redo its mode line + if the window to its side is being redone */ + || (!just_this_one && width < FRAME_WIDTH (f) - 1) + || INTEGERP (w->base_line_pos)) && height != XFASTINT (w->height)) display_mode_line (w); + if (! line_number_displayed + && ! BUFFERP (w->base_line_pos)) + { + w->base_line_pos = Qnil; + w->base_line_number = Qnil; + } /* When we reach a frame's selected window, redo the frame's menu bar. */ if (!NILP (w->update_mode_line) @@ -1889,6 +1918,8 @@ register int right = XFASTINT (w->width) + left; register FRAME_PTR f = XFRAME (WINDOW_FRAME (w)); + line_number_displayed = 0; + get_display_line (f, vpos, left); display_mode_element (w, vpos, left, 0, right, right, current_buffer->mode_line_format); @@ -2181,6 +2212,93 @@ #endif break; + case 'l': + { + int startpos = marker_position (w->start); + int line, linepos, topline; + int nlines, junk; + Lisp_Object tem; + int height = XFASTINT (w->height); + + /* If we decided that this buffer isn't suitable for line numbers, + don't forget that too fast. */ + if (EQ (w->base_line_pos, w->buffer)) + return "??"; + + /* If the buffer is very big, don't waste time. */ + if (ZV - BEGV > line_number_display_limit) + { + w->base_line_pos = Qnil; + w->base_line_number = Qnil; + return "??"; + } + + if (!NILP (w->base_line_number) + && !NILP (w->base_line_pos) + && XFASTINT (w->base_line_pos) <= marker_position (w->start)) + { + line = XFASTINT (w->base_line_number); + linepos = XFASTINT (w->base_line_pos); + } + else + { + line = 1; + linepos = BEGV; + } + + /* Count lines from base line to window start position. */ + nlines = display_count_lines (linepos, startpos, startpos, &junk); + + topline = nlines + line; + + /* Determine a new base line, if the old one is too close + or too far away, or if we did not have one. + "Too close" means it's plausible a scroll-down would + go back past it. */ + if (startpos == BEGV) + { + XFASTINT (w->base_line_number) = topline; + XFASTINT (w->base_line_pos) = BEGV; + } + else if (nlines < height + 25 || nlines > height * 3 + 50 + || linepos == BEGV) + { + int limit = BEGV; + int position; + int distance = (height * 2 + 30) * 200; + + if (startpos - distance > limit) + limit = startpos - distance; + + nlines = display_count_lines (startpos, limit, + -(height * 2 + 30), + &position); + /* If we couldn't find the lines we wanted within + 200 chars per line, + give up on line numbers for this window. */ + if (position == startpos - distance) + { + w->base_line_pos = w->buffer; + w->base_line_number = Qnil; + return "??"; + } + + XFASTINT (w->base_line_number) = topline - nlines; + XFASTINT (w->base_line_pos) = position; + } + + /* Now count lines from the start pos to point. */ + nlines = display_count_lines (startpos, PT, PT, &junk); + + /* Record that we did display the line number. */ + line_number_displayed = 1; + + /* Make the string to show. */ + sprintf (decode_mode_spec_buf, "%d", topline + nlines); + return decode_mode_spec_buf; + } + break; + case 'm': obj = current_buffer->mode_name; break; @@ -2284,6 +2402,37 @@ else return ""; } + +/* Count up to N lines starting from FROM. + But don't go beyond LIMIT. + Return the number of lines thus found (always positive). + Store the position after what was found into *POS_PTR. */ + +static int +display_count_lines (from, limit, n, pos_ptr) + int from, limit, n; + int *pos_ptr; +{ + int oldbegv = BEGV; + int oldzv = ZV; + int shortage = 0; + + if (limit < from) + BEGV = limit; + else + ZV = limit; + + *pos_ptr = scan_buffer ('\n', from, n, &shortage); + + ZV = oldzv; + BEGV = oldbegv; + + if (n < 0) + /* When scanning backwards, scan_buffer stops *after* the last newline + it finds, but does count it. Compensate for that. */ + return - n - shortage - (*pos_ptr != limit); + return n - shortage; +} /* Display STRING on one line of window W, starting at HPOS. Display at position VPOS. Caller should have done get_display_line. @@ -2462,6 +2611,10 @@ DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video, "*Non-nil means use inverse video for the mode line."); mode_line_inverse_video = 1; + + DEFVAR_INT ("line-number-display-limit", &line_number_display_limit, + "*Maximum buffer size for which line number should be displayed."); + line_number_display_limit = 1000000; } /* initialize the window system */