Allow count-lines to ignore invisible lines

* doc/lispref/positions.texi (Text Lines): Document it (bug#23675).

* lisp/simple.el (count-lines): Add an optional parameter to
ignore invisible lines (bug#23675).
This commit is contained in:
Robert Weiner 2020-08-11 16:52:01 +02:00 committed by Lars Ingebrigtsen
parent 119a9ecfe1
commit 4d4d3e42ca
3 changed files with 44 additions and 18 deletions

View file

@ -411,7 +411,7 @@ function counts that line as one line successfully moved.
In an interactive call, @var{count} is the numeric prefix argument.
@end deffn
@defun count-lines start end
@defun count-lines start end &optional ignore-invisible-lines
@cindex lines in region
@anchor{Definition of count-lines}
This function returns the number of lines between the positions
@ -420,6 +420,9 @@ This function returns the number of lines between the positions
1, even if @var{start} and @var{end} are on the same line. This is
because the text between them, considered in isolation, must contain at
least one line unless it is empty.
If the optional @var{ignore-invisible-lines} is non-@code{nil},
invisible lines will not be included in the count.
@end defun
@deffn Command count-words start end

View file

@ -868,6 +868,10 @@ have now been removed.
* Lisp Changes in Emacs 28.1
+++
** The 'count-lines' function now takes an optional parameter to
ignore invisible lines.
---
** New function 'custom-add-choice'.
This function can be used by modes to add elements to the

View file

@ -1366,28 +1366,47 @@ END, without printing any message."
(message "line %d (narrowed line %d)"
(+ n (line-number-at-pos start) -1) n))))))
(defun count-lines (start end)
(defun count-lines (start end &optional ignore-invisible-lines)
"Return number of lines between START and END.
This is usually the number of newlines between them,
but can be one more if START is not equal to END
and the greater of them is not at the start of a line."
This is usually the number of newlines between them, but can be
one more if START is not equal to END and the greater of them is
not at the start of a line.
When IGNORE-INVISIBLE-LINES is non-nil, invisible lines are not
included in the count."
(save-excursion
(save-restriction
(narrow-to-region start end)
(goto-char (point-min))
(if (eq selective-display t)
(save-match-data
(let ((done 0))
(while (re-search-forward "[\n\C-m]" nil t 40)
(setq done (+ 40 done)))
(while (re-search-forward "[\n\C-m]" nil t 1)
(setq done (+ 1 done)))
(goto-char (point-max))
(if (and (/= start end)
(not (bolp)))
(1+ done)
done)))
(- (buffer-size) (forward-line (buffer-size)))))))
(cond ((and (not ignore-invisible-lines)
(eq selective-display t))
(save-match-data
(let ((done 0))
(while (re-search-forward "\n\\|\r[^\n]" nil t 40)
(setq done (+ 40 done)))
(while (re-search-forward "\n\\|\r[^\n]" nil t 1)
(setq done (+ 1 done)))
(goto-char (point-max))
(if (and (/= start end)
(not (bolp)))
(1+ done)
done))))
(ignore-invisible-lines
(save-match-data
(- (buffer-size)
(forward-line (buffer-size))
(let ((invisible-count 0)
prop)
(goto-char (point-min))
(while (re-search-forward "\n\\|\r[^\n]" nil t)
(setq prop (get-char-property (1- (point)) 'invisible))
(if (if (eq buffer-invisibility-spec t)
prop
(or (memq prop buffer-invisibility-spec)
(assq prop buffer-invisibility-spec)))
(setq invisible-count (1+ invisible-count))))
invisible-count))))
(t (- (buffer-size) (forward-line (buffer-size))))))))
(defun line-number-at-pos (&optional pos absolute)
"Return buffer line number at position POS.