Function: buffer-line-statistics

buffer-line-statistics is a function defined in fns.c.

Signature

(buffer-line-statistics &optional BUFFER-OR-NAME)

Documentation

Return data about lines in BUFFER.

The data is returned as a list, and the first element is the number of lines in the buffer, the second is the length of the longest line, and the third is the mean line length. The lengths returned are in bytes, not characters.

Probably introduced at or before Emacs version 28.1.

Source Code

// Defined in /usr/src/emacs/src/fns.c
{
  Lisp_Object buffer;
  ptrdiff_t lines = 0, longest = 0;
  double mean = 0;
  struct buffer *b;

  if (NILP (buffer_or_name))
    buffer = Fcurrent_buffer ();
  else
    buffer = Fget_buffer (buffer_or_name);
  if (NILP (buffer))
    nsberror (buffer_or_name);

  b = XBUFFER (buffer);

  unsigned char *start = BUF_BEG_ADDR (b);
  ptrdiff_t area = BUF_GPT_BYTE (b) - BUF_BEG_BYTE (b), pre_gap = 0;

  /* Process the first part of the buffer. */
  while (area > 0)
    {
      unsigned char *n = memchr (start, '\n', area);

      if (n)
	{
	  ptrdiff_t this_line = n - start;
	  if (this_line > longest)
	    longest = this_line;
	  lines++;
	  /* Blame Knuth. */
	  mean = mean + (this_line - mean) / lines;
	  area = area - this_line - 1;
	  start += this_line + 1;
	}
      else
	{
	  /* Didn't have a newline here, so save the rest for the
	     post-gap calculation. */
	  pre_gap = area;
	  area = 0;
	}
    }

  /* If the gap is before the end of the buffer, process the last half
     of the buffer. */
  if (BUF_GPT_BYTE (b) < BUF_Z_BYTE (b))
    {
      start = BUF_GAP_END_ADDR (b);
      area = BUF_Z_ADDR (b) - BUF_GAP_END_ADDR (b);

      while (area > 0)
	{
	  unsigned char *n = memchr (start, '\n', area);
	  ptrdiff_t this_line = n? n - start + pre_gap: area + pre_gap;

	  if (this_line > longest)
	    longest = this_line;
	  lines++;
	  /* Blame Knuth again. */
	  mean = mean + (this_line - mean) / lines;
	  area = area - this_line - 1;
	  start += this_line + 1;
	  pre_gap = 0;
	}
    }
  else if (pre_gap > 0)
    {
      if (pre_gap > longest)
	longest = pre_gap;
      lines++;
      mean = mean + (pre_gap - mean) / lines;
    }

  return list3 (make_int (lines), make_int (longest), make_float (mean));
}