2

I am trying to create a lazy sequence of the lines in the current buffer using the stream.el library. These two recursive functions both read the lines of the current buffer from point to the end of the buffer. The first function collects the lines in a list, the second creates a "lazy list", which means the buffer lines aren't read until they are needed.

(defun lines-to-list ()
  (unless (eobp)
    (cons (prog1
            (thing-at-point 'line t)
            (next-line))
          (lines-to-list))))

(defun lines-as-stream ()
  (unless (eobp)
    (stream-cons (prog1
                   (thing-at-point 'line t)
                   (next-line))
                 (lines-as-stream))))

My problem is that the lines-as-stream function never includes the last line of the buffer. I have the following test lines in the current buffer:

1
2
3
4
5

with point on 1 and a newline after 5. When I run lines-to-list, I get a nice list with five elements: ("1", "2", "3", "4", "5") (the strings also include newlines, but I have omitted them for readability). However, when I evaluate (seq-length (lines-as-stream)) in the minibuffer, I get the value 4. I have also tried (seq-into (lines-as-stream) 'list), which I expected to return the same list as before, but I only getting ("1", "2", "3", "4") (newlines omitted again). Curiously, in both cases the cursor ends up on the empty line after the 5, which would indicate that both functions have processed all the lines.

What am I missing? Why is the stream version not returning the last line when evaluated?

Drew
  • 75,699
  • 9
  • 109
  • 225

1 Answers1

1

The stream library requires you to return (stream-empty) instead of nil when reaching the end of the buffer. The following function returns the empty stream when point is at the end of the buffer.

(defun lines-as-stream ()
  (if (eobp)
      (stream-empty)
    (stream-cons (prog1
                   (thing-at-point 'line t)
                   (forward-line 1))
                 (lines-as-stream))))

Some people might find this to be a more elegant solution:

(defun lines-as-stream ()
  (if (eobp)
      (stream-empty)
    (stream-cons (thing-at-point 'line t) (progn
                                            (forward-line 1)
                                            (lines-as-stream)))))