eintr: fwd-para while

 
 The forward motion ‘while’ loop
 -------------------------------
 
 The second part of the body of the ‘let*’ deals with forward motion.  It
 is a ‘while’ loop that repeats itself so long as the value of ‘arg’ is
 greater than zero.  In the most common use of the function, the value of
 the argument is 1, so the body of the ‘while’ loop is evaluated exactly
 once, and the cursor moves forward one paragraph.
 
    This part handles three situations: when point is between paragraphs,
 when there is a fill prefix and when there is no fill prefix.
 
    The ‘while’ loop looks like this:
 
      ;; going forwards and not at the end of the buffer
      (while (and (> arg 0) (not (eobp)))
 
        ;; between paragraphs
        ;; Move forward over separator lines...
        (while (and (not (eobp))
                    (progn (move-to-left-margin) (not (eobp)))
                    (looking-at parsep))
          (forward-line 1))
        ;;  This decrements the loop
        (unless (eobp) (setq arg (1- arg)))
        ;; ... and one more line.
        (forward-line 1)
 
        (if fill-prefix-regexp
            ;; There is a fill prefix; it overrides parstart;
            ;; we go forward line by line
            (while (and (not (eobp))
                        (progn (move-to-left-margin) (not (eobp)))
                        (not (looking-at parsep))
                        (looking-at fill-prefix-regexp))
              (forward-line 1))
 
          ;; There is no fill prefix;
          ;; we go forward character by character
          (while (and (re-search-forward sp-parstart nil 1)
                      (progn (setq start (match-beginning 0))
                             (goto-char start)
                             (not (eobp)))
                      (progn (move-to-left-margin)
                             (not (looking-at parsep)))
                      (or (not (looking-at parstart))
                          (and use-hard-newlines
                               (not (get-text-property (1- start) 'hard)))))
            (forward-char 1))
 
          ;; and if there is no fill prefix and if we are not at the end,
          ;;     go to whatever was found in the regular expression search
          ;;     for sp-parstart
          (if (< (point) (point-max))
              (goto-char start))))
 
    We can see that this is a decrementing counter ‘while’ loop, using
 the expression ‘(setq arg (1- arg))’ as the decrementer.  That
 expression is not far from the ‘while’, but is hidden in another Lisp
 macro, an ‘unless’ macro.  Unless we are at the end of the buffer—that
 is what the ‘eobp’ function determines; it is an abbreviation of ‘End Of
 Buffer P’—we decrease the value of ‘arg’ by one.
 
    (If we are at the end of the buffer, we cannot go forward any more
 and the next loop of the ‘while’ expression will test false since the
 test is an ‘and’ with ‘(not (eobp))’.  The ‘not’ function means exactly
 as you expect; it is another name for ‘null’, a function that returns
 true when its argument is false.)
 
    Interestingly, the loop count is not decremented until we leave the
 space between paragraphs, unless we come to the end of buffer or stop
 seeing the local value of the paragraph separator.
 
    That second ‘while’ also has a ‘(move-to-left-margin)’ expression.
 The function is self-explanatory.  It is inside a ‘progn’ expression and
 not the last element of its body, so it is only invoked for its side
 effect, which is to move point to the left margin of the current line.
 
    The ‘looking-at’ function is also self-explanatory; it returns true
 if the text after point matches the regular expression given as its
 argument.
 
    The rest of the body of the loop looks difficult at first, but makes
 sense as you come to understand it.
 
    First consider what happens if there is a fill prefix:
 
        (if fill-prefix-regexp
            ;; There is a fill prefix; it overrides parstart;
            ;; we go forward line by line
            (while (and (not (eobp))
                        (progn (move-to-left-margin) (not (eobp)))
                        (not (looking-at parsep))
                        (looking-at fill-prefix-regexp))
              (forward-line 1))
 
 This expression moves point forward line by line so long as four
 conditions are true:
 
   1. Point is not at the end of the buffer.
 
   2. We can move to the left margin of the text and are not at the end
      of the buffer.
 
   3. The text following point does not separate paragraphs.
 
   4. The pattern following point is the fill prefix regular expression.
 
    The last condition may be puzzling, until you remember that point was
 moved to the beginning of the line early in the ‘forward-paragraph’
 function.  This means that if the text has a fill prefix, the
 ‘looking-at’ function will see it.
 
    Consider what happens when there is no fill prefix.
 
          (while (and (re-search-forward sp-parstart nil 1)
                      (progn (setq start (match-beginning 0))
                             (goto-char start)
                             (not (eobp)))
                      (progn (move-to-left-margin)
                             (not (looking-at parsep)))
                      (or (not (looking-at parstart))
                          (and use-hard-newlines
                               (not (get-text-property (1- start) 'hard)))))
            (forward-char 1))
 
 This ‘while’ loop has us searching forward for ‘sp-parstart’, which is
 the combination of possible whitespace with the local value of the start
 of a paragraph or of a paragraph separator.  (The latter two are within
 an expression starting ‘\(?:’ so that they are not referenced by the
 ‘match-beginning’ function.)
 
    The two expressions,
 
      (setq start (match-beginning 0))
      (goto-char start)
 
 mean go to the start of the text matched by the regular expression
 search.
 
    The ‘(match-beginning 0)’ expression is new.  It returns a number
 specifying the location of the start of the text that was matched by the
 last search.
 
    The ‘match-beginning’ function is used here because of a
 characteristic of a forward search: a successful forward search,
 regardless of whether it is a plain search or a regular expression
 search, moves point to the end of the text that is found.  In this case,
 a successful search moves point to the end of the pattern for
 ‘sp-parstart’.
 
    However, we want to put point at the end of the current paragraph,
 not somewhere else.  Indeed, since the search possibly includes the
 paragraph separator, point may end up at the beginning of the next one
 unless we use an expression that includes ‘match-beginning’.
 
    When given an argument of 0, ‘match-beginning’ returns the position
 that is the start of the text matched by the most recent search.  In
 this case, the most recent search looks for ‘sp-parstart’.  The
 ‘(match-beginning 0)’ expression returns the beginning position of that
 pattern, rather than the end position of that pattern.
 
    (Incidentally, when passed a positive number as an argument, the
 ‘match-beginning’ function returns the location of point at that
 parenthesized expression in the last search unless that parenthesized
 expression begins with ‘\(?:’.  I don’t know why ‘\(?:’ appears here
 since the argument is 0.)
 
    The last expression when there is no fill prefix is
 
      (if (< (point) (point-max))
          (goto-char start))))
 
 This says that if there is no fill prefix and if we are not at the end,
 point should move to the beginning of whatever was found by the regular
 expression search for ‘sp-parstart’.
 
    The full definition for the ‘forward-paragraph’ function not only
 includes code for going forwards, but also code for going backwards.
 
    If you are reading this inside of GNU Emacs and you want to see the
 whole function, you can type ‘C-h f’ (‘describe-function’) and the name
 of the function.  This gives you the function documentation and the name
 of the library containing the function’s source.  Place point over the
 name of the library and press the RET key; you will be taken directly to
 the source.  (Be sure to install your sources!  Without them, you are
 like a person who tries to drive a car with his eyes shut!)