+;;; Line breaking and paragraph filling.
+
+(defvar c-auto-fill-prefix t)
+(defvar c-lit-limits nil)
+(defvar c-lit-type nil)
+
+;; The filling code is based on a simple theory; leave the intricacies
+;; of the text handling to the currently active mode for that
+;; (e.g. adaptive-fill-mode or filladapt-mode) and do as little as
+;; possible to make them work correctly wrt the comment and string
+;; separators, one-line paragraphs etc. Unfortunately, when it comes
+;; to it, there's quite a lot of special cases to handle which makes
+;; the code anything but simple. The intention is that it will work
+;; with any well-written text filling package that preserves a fill
+;; prefix.
+;;
+;; We temporarily mask comment starters and enders as necessary for
+;; the filling code to do its job on a seemingly normal text block.
+;; We do _not_ mask the fill prefix, so it's up to the filling code to
+;; preserve it correctly (especially important when filling C++ style
+;; line comments). By default, we set up and use adaptive-fill-mode,
+;; which is standard in all supported Emacs flavors.
+
+(defun c-guess-fill-prefix (lit-limits lit-type)
+ ;; Determine the appropriate comment fill prefix for a block or line
+ ;; comment. Return a cons of the prefix string and the column where
+ ;; it ends. If fill-prefix is set, it'll override. Note that this
+ ;; function also uses the value of point in some heuristics.
+ ;;
+ ;; This function might do hidden buffer changes.
+
+ (let* ((here (point))
+ (prefix-regexp (concat "[ \t]*\\("
+ c-current-comment-prefix
+ "\\)[ \t]*"))
+ (comment-start-regexp (if (eq lit-type 'c++)
+ prefix-regexp
+ comment-start-skip))
+ prefix-line comment-prefix res comment-text-end)
+
+ (cond
+ (fill-prefix
+ (setq res (cons fill-prefix
+ ;; Ugly way of getting the column after the fill
+ ;; prefix; it'd be nice with a current-column
+ ;; that works on strings..
+ (let ((start (point)))
+ (unwind-protect
+ (progn
+ (insert-and-inherit "\n" fill-prefix)
+ (current-column))
+ (delete-region start (point)))))))
+
+ ((eq lit-type 'c++)
+ (save-excursion
+ ;; Set fallback for comment-prefix if none is found.
+ (setq comment-prefix "// "
+ comment-text-end (cdr lit-limits))
+
+ (beginning-of-line)
+ (if (> (point) (car lit-limits))
+ ;; The current line is not the comment starter, so the
+ ;; comment has more than one line, and it can therefore be
+ ;; used to find the comment fill prefix.
+ (setq prefix-line (point))
+
+ (goto-char (car lit-limits))
+ (if (and (= (forward-line 1) 0)
+ (< (point) (cdr lit-limits)))
+ ;; The line after the comment starter is inside the
+ ;; comment, so we can use it.
+ (setq prefix-line (point))
+
+ ;; The comment is only one line. Take the comment prefix
+ ;; from it and keep the indentation.
+ (goto-char (car lit-limits))
+ (if (looking-at prefix-regexp)
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+
+ (let (str col)
+ (if (eq (c-point 'boi) (car lit-limits))
+ ;; There is only whitespace before the comment
+ ;; starter; take the prefix straight from this line.
+ (setq str (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ col (current-column))
+
+ ;; There is code before the comment starter, so we
+ ;; have to temporarily insert and indent a new line to
+ ;; get the right space/tab mix in the indentation.
+ (let ((prefix-len (- (point) (car lit-limits)))
+ tmp)
+ (unwind-protect
+ (progn
+ (goto-char (car lit-limits))
+ (indent-to (prog1 (current-column)
+ (insert ?\n)))
+ (setq tmp (point))
+ (forward-char prefix-len)
+ (setq str (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ col (current-column)))
+ (delete-region (car lit-limits) tmp))))
+
+ (setq res
+ (if (or (string-match "\\s \\'" str) (not (eolp)))
+ (cons str col)
+ ;; The prefix ends the line with no whitespace
+ ;; after it. Default to a single space.
+ (cons (concat str " ") (1+ col))))
+ )))))
+
+ (t
+ (setq comment-text-end
+ (save-excursion
+ (goto-char (- (cdr lit-limits) 2))
+ (if (looking-at "\\*/") (point) (cdr lit-limits))))
+
+ (save-excursion
+ (beginning-of-line)
+ (if (and (> (point) (car lit-limits))
+ (not (and (looking-at "[ \t]*\\*/")
+ (eq (cdr lit-limits) (match-end 0)))))
+ ;; The current line is not the comment starter and
+ ;; contains more than just the ender, so it's good enough
+ ;; to be used for the comment fill prefix.
+ (setq prefix-line (point))
+ (goto-char (car lit-limits))
+
+ (cond ((or (/= (forward-line 1) 0)
+ (>= (point) (cdr lit-limits))
+ (and (looking-at "[ \t]*\\*/")
+ (eq (cdr lit-limits) (match-end 0)))
+ (and (looking-at prefix-regexp)
+ (<= (1- (cdr lit-limits)) (match-end 0))))
+ ;; The comment is either one line or the next line contains
+ ;; just the comment ender. In this case we have no
+ ;; information about a suitable comment prefix, so we resort
+ ;; to c-block-comment-prefix.
+ (setq comment-prefix (or c-block-comment-prefix "")))
+
+ ((< here (point))
+ ;; The point was on the comment opener line, so we might want
+ ;; to treat this as a not yet closed comment.
+
+ (if (and (match-beginning 1)
+ (/= (match-beginning 1) (match-end 1)))
+ ;; Above `prefix-regexp' matched a nonempty prefix on the
+ ;; second line, so let's use it. Normally it should do
+ ;; to set `prefix-line' and let the code below pick up
+ ;; the whole prefix, but if there's no text after the
+ ;; match then it will probably fall back to no prefix at
+ ;; all if the comment isn't closed yet, so in that case
+ ;; it's better to force use of the prefix matched now.
+ (if (= (match-end 0) (c-point 'eol))
+ (setq comment-prefix (match-string 1))
+ (setq prefix-line (point)))
+
+ ;; There's no nonempty prefix on the line after the
+ ;; comment opener. If the line is empty, or if the
+ ;; text on it has less or equal indentation than the
+ ;; comment starter we assume it's an unclosed
+ ;; comment starter, i.e. that
+ ;; `c-block-comment-prefix' should be used.
+ ;; Otherwise we assume it's a closed comment where
+ ;; the prefix really is the empty string.
+ ;; E.g. this is an unclosed comment:
+ ;;
+ ;; /*
+ ;; foo
+ ;;
+ ;; But this is not:
+ ;;
+ ;; /*
+ ;; foo
+ ;; */
+ ;;
+ ;; (Looking for the presence of the comment closer
+ ;; rarely works since it's probably the closer of
+ ;; some comment further down when the comment
+ ;; really is unclosed.)
+ (if (<= (save-excursion (back-to-indentation)
+ (current-column))
+ (save-excursion (goto-char (car lit-limits))
+ (current-column)))
+ (setq comment-prefix (or c-block-comment-prefix ""))
+ (setq prefix-line (point)))))
+
+ (t
+ ;; Otherwise the line after the comment starter is good
+ ;; enough to find the prefix in.
+ (setq prefix-line (point))))
+
+ (when comment-prefix
+ ;; Haven't got the comment prefix on any real line that we
+ ;; can take it from, so we have to temporarily insert
+ ;; `comment-prefix' on a line and indent it to find the
+ ;; correct column and the correct mix of tabs and spaces.
+ (setq res
+ (let (tmp-pre tmp-post)
+ (unwind-protect
+ (progn
+
+ (goto-char (car lit-limits))
+ (if (looking-at comment-start-regexp)
+ (goto-char (min (match-end 0)
+ comment-text-end))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+
+ (when (eq (char-syntax (char-before)) ?\ )
+ ;; If there's ws on the current line, we'll use it
+ ;; instead of what's ending comment-prefix.
+ (setq comment-prefix
+ (concat (substring comment-prefix
+ 0 (string-match
+ "\\s *\\'"
+ comment-prefix))
+ (buffer-substring-no-properties
+ (save-excursion
+ (skip-chars-backward " \t")
+ (point))
+ (point)))))
+
+ (setq tmp-pre (point-marker))
+
+ ;; We insert an extra non-whitespace character
+ ;; before the line break and after comment-prefix in
+ ;; case it's "" or ends with whitespace.
+ (insert-and-inherit "x\n" comment-prefix "x")
+ (setq tmp-post (point-marker))
+
+ (indent-according-to-mode)
+
+ (goto-char (1- tmp-post))
+ (cons (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ (current-column)))
+
+ (when tmp-post
+ (delete-region tmp-pre tmp-post)
+ (set-marker tmp-pre nil)
+ (set-marker tmp-post nil))))))))))
+
+ (or res ; Found a good prefix above.
+
+ (save-excursion
+ ;; prefix-line is the bol of a line on which we should try
+ ;; to find the prefix.
+ (let* (fb-string fb-endpos ; Contains any fallback prefix found.
+ (test-line
+ (lambda ()
+ (when (and (looking-at prefix-regexp)
+ (<= (match-end 0) comment-text-end))
+ (unless (eq (match-end 0) (c-point 'eol))
+ ;; The match is fine if there's text after it.
+ (throw 'found (cons (buffer-substring-no-properties
+ (match-beginning 0) (match-end 0))
+ (progn (goto-char (match-end 0))
+ (current-column)))))
+ (unless fb-string
+ ;; This match is better than nothing, so let's
+ ;; remember it in case nothing better is found
+ ;; on another line.
+ (setq fb-string (buffer-substring-no-properties
+ (match-beginning 0) (match-end 0))
+ fb-endpos (match-end 0)))
+ t))))
+
+ (or (catch 'found
+ ;; Search for a line which has text after the prefix
+ ;; so that we get the proper amount of whitespace
+ ;; after it. We start with the current line, then
+ ;; search backwards, then forwards.
+
+ (goto-char prefix-line)
+ (when (and (funcall test-line)
+ (or (/= (match-end 1) (match-end 0))
+ ;; The whitespace is sucked up by the
+ ;; first [ \t]* glob if the prefix is empty.
+ (and (= (match-beginning 1) (match-end 1))
+ (/= (match-beginning 0) (match-end 0)))))
+ ;; If the current line doesn't have text but do
+ ;; have whitespace after the prefix, we'll use it.
+ (throw 'found (cons fb-string
+ (progn (goto-char fb-endpos)
+ (current-column)))))
+
+ (if (eq lit-type 'c++)
+ ;; For line comments we can search up to and
+ ;; including the first line.
+ (while (and (zerop (forward-line -1))
+ (>= (point) (car lit-limits)))
+ (funcall test-line))
+ ;; For block comments we must stop before the
+ ;; block starter.
+ (while (and (zerop (forward-line -1))
+ (> (point) (car lit-limits)))
+ (funcall test-line)))
+
+ (goto-char prefix-line)
+ (while (and (zerop (forward-line 1))
+ (< (point) (cdr lit-limits)))
+ (funcall test-line))
+
+ (goto-char prefix-line)
+ nil)
+
+ (when fb-string
+ ;; A good line wasn't found, but at least we have a
+ ;; fallback that matches the comment prefix regexp.
+ (cond ((or (string-match "\\s \\'" fb-string)
+ (progn
+ (goto-char fb-endpos)
+ (not (eolp))))
+ ;; There are ws or text after the prefix, so
+ ;; let's use it.
+ (cons fb-string (current-column)))
+
+ ((progn
+ ;; Check if there's any whitespace padding
+ ;; on the comment start line that we can
+ ;; use after the prefix.
+ (goto-char (car lit-limits))
+ (if (looking-at comment-start-regexp)
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+ (or (not (eolp))
+ (eq (char-syntax (char-before)) ?\ )))
+
+ (setq fb-string (buffer-substring-no-properties
+ (save-excursion
+ (skip-chars-backward " \t")
+ (point))
+ (point)))
+ (goto-char fb-endpos)
+ (skip-chars-backward " \t")
+
+ (let ((tmp (point)))
+ ;; Got to mess in the buffer once again to
+ ;; ensure the column gets correct. :P
+ (unwind-protect
+ (progn
+ (insert-and-inherit fb-string)
+ (cons (buffer-substring-no-properties
+ (c-point 'bol)
+ (point))
+ (current-column)))
+ (delete-region tmp (point)))))
+
+ (t
+ ;; Last resort: Just add a single space after
+ ;; the prefix.
+ (cons (concat fb-string " ")
+ (progn (goto-char fb-endpos)
+ (1+ (current-column)))))))
+
+ ;; The line doesn't match the comment prefix regexp.
+ (if comment-prefix
+ ;; We have a fallback for line comments that we must use.
+ (cons (concat (buffer-substring-no-properties
+ prefix-line (c-point 'boi))
+ comment-prefix)
+ (progn (back-to-indentation)
+ (+ (current-column) (length comment-prefix))))
+
+ ;; Assume we are dealing with a "free text" block
+ ;; comment where the lines doesn't have any comment
+ ;; prefix at all and we should just fill it as
+ ;; normal text.
+ '("" . 0))))))
+ ))
+
+(defun c-mask-paragraph (fill-paragraph apply-outside-literal fun &rest args)
+ ;; Calls FUN with ARGS ar arguments while the current paragraph is
+ ;; masked to allow adaptive filling to work correctly. That
+ ;; includes narrowing the buffer and, if point is inside a comment,
+ ;; masking the comment starter and ender appropriately.
+ ;;
+ ;; FILL-PARAGRAPH is non-nil if called for whole paragraph filling.
+ ;; The position of point is then less significant when doing masking
+ ;; and narrowing.
+ ;;
+ ;; If APPLY-OUTSIDE-LITERAL is nil then the function will be called
+ ;; only if the point turns out to be inside a comment or a string.
+ ;;
+ ;; Note that this function does not do any hidden buffer changes.
+
+ (let (fill
+ ;; beg and end limit the region to narrow. end is a marker.
+ beg end
+ ;; tmp-pre and tmp-post mark strings that are temporarily
+ ;; inserted at the start and end of the region. tmp-pre is a
+ ;; cons of the positions of the prepended string. tmp-post is
+ ;; a marker pointing to the single character of the appended
+ ;; string.
+ tmp-pre tmp-post
+ ;; If hang-ender-stuck isn't nil, the comment ender is
+ ;; hanging. In that case it's set to the number of spaces
+ ;; that should be between the text and the ender.
+ hang-ender-stuck
+ ;; auto-fill-spaces is the exact sequence of whitespace between a
+ ;; comment's last word and the comment ender, temporarily replaced
+ ;; with 'x's before calling FUN when FILL-PARAGRAPH is nil.
+ auto-fill-spaces
+ (here (point))
+ (c-lit-limits c-lit-limits)
+ (c-lit-type c-lit-type))
+
+ ;; Restore point on undo. It's necessary since we do a lot of
+ ;; hidden inserts and deletes below that should be as transparent
+ ;; as possible.
+ (if (and buffer-undo-list (not (eq buffer-undo-list t)))
+ (setq buffer-undo-list (cons (point) buffer-undo-list)))
+
+ ;; Determine the limits and type of the containing literal (if any):
+ ;; C-LIT-LIMITS, C-LIT-TYPE; and the limits of the current paragraph:
+ ;; BEG and END.
+ (c-save-buffer-state ()
+ (save-restriction
+ ;; Widen to catch comment limits correctly.
+ (widen)
+ (unless c-lit-limits
+ (setq c-lit-limits (c-literal-limits nil fill-paragraph)))
+ (setq c-lit-limits (c-collect-line-comments c-lit-limits))
+ (unless c-lit-type
+ (setq c-lit-type (c-literal-type c-lit-limits))))
+
+ (save-excursion
+ (unless (c-safe (backward-char)
+ (forward-paragraph)
+ (>= (point) here))
+ (goto-char here)
+ (forward-paragraph))
+ (setq end (point-marker)))
+ (save-excursion
+ (unless (c-safe (forward-char)
+ (backward-paragraph)
+ (<= (point) here))
+ (goto-char here)
+ (backward-paragraph))
+ (setq beg (point))))
+
+ (unwind-protect
+ (progn
+ ;; For each of the possible types of text (string, C comment ...)
+ ;; determine BEG and END, the region we will narrow to. If we're in
+ ;; a literal, constrain BEG and END to the limits of this literal.
+ ;;
+ ;; For some of these text types, particularly a block comment, we
+ ;; may need to massage whitespace near literal delimiters, so that
+ ;; these don't get filled inappropriately.
+ (cond
+
+ ((eq c-lit-type 'c++) ; Line comment.
+ (save-excursion
+ ;; Limit to the comment or paragraph end, whichever
+ ;; comes first.
+ (set-marker end (min end (cdr c-lit-limits)))
+
+ (when (<= beg (car c-lit-limits))
+ ;; The region includes the comment starter, so we must
+ ;; check it.
+ (goto-char (car c-lit-limits))
+ (back-to-indentation)
+ (if (eq (point) (car c-lit-limits))
+ ;; Include the first line in the region.
+ (setq beg (c-point 'bol))
+ ;; The first line contains code before the
+ ;; comment. We must fake a line that doesn't.
+ (setq tmp-pre t))))
+
+ (setq apply-outside-literal t))
+
+ ((eq c-lit-type 'c) ; Block comment.
+ (when
+ (or (> end (cdr c-lit-limits))
+ (and (= end (cdr c-lit-limits))
+ (eq (char-before end) ?/)
+ (eq (char-before (1- end)) ?*)
+ ;; disallow "/*/"
+ (> (- (cdr c-lit-limits) (car c-lit-limits)) 3)))
+ ;; There is a comment ender, and the region includes it. If
+ ;; it's on its own line, it stays on its own line. If it's got
+ ;; company on the line, it keeps (at least one word of) it.
+ ;; "=====*/" counts as a comment ender here, but "===== */"
+ ;; doesn't and "foo*/" doesn't.
+ (unless
+ (save-excursion
+ (goto-char (cdr c-lit-limits))
+ (beginning-of-line)
+ (and (search-forward-regexp
+ (concat "\\=[ \t]*\\(" c-current-comment-prefix "\\)")
+ (- (cdr c-lit-limits) 2) t)
+ (not (search-forward-regexp
+ "\\(\\s \\|\\sw\\)"
+ (- (cdr c-lit-limits) 2) 'limit))
+ ;; The comment ender IS on its own line. Exclude
+ ;; this line from the filling.
+ (set-marker end (c-point 'bol))))
+
+ ;; The comment ender is hanging. Replace all space between it
+ ;; and the last word either by one or two 'x's (when
+ ;; FILL-PARAGRAPH is non-nil), or a row of x's the same width
+ ;; as the whitespace (when auto filling), and include it in
+ ;; the region. We'll change them back to whitespace
+ ;; afterwards. The effect of this is to glue the comment
+ ;; ender to the last word in the comment during filling.
+ (let* ((ender-start (save-excursion
+ (goto-char (cdr c-lit-limits))
+ (skip-syntax-backward "^w ")
+ (point)))
+ (ender-column (save-excursion
+ (goto-char ender-start)
+ (current-column)))
+ (point-rel (- ender-start here))
+ spaces)
+
+ (save-excursion
+ ;; Insert a CR after the "*/", adjust END
+ (goto-char (cdr c-lit-limits))
+ (setq tmp-post (point-marker))
+ (insert ?\n)
+ (set-marker end (point))
+
+ (forward-line -1) ; last line of the comment
+ (if (and (looking-at (concat "[ \t]*\\(\\("
+ c-current-comment-prefix
+ "\\)[ \t]*\\)"))
+ (eq ender-start (match-end 0)))
+ ;; The comment ender is prefixed by nothing but a
+ ;; comment line prefix. IS THIS POSSIBLE? (ACM,
+ ;; 2006/4/28). Remove it along with surrounding ws.
+ (setq spaces (- (match-end 1) (match-end 2)))
+ (goto-char ender-start))
+ (skip-chars-backward " \t\r\n") ; Surely this can be
+ ; " \t"? "*/" is NOT alone on the line (ACM, 2005/8/18)
+
+ ;; What's being tested here? 2006/4/20. FIXME!!!
+ (if (/= (point) ender-start)
+ (progn
+ (if (<= here (point))
+ ;; Don't adjust point below if it's
+ ;; before the string we replace.
+ (setq point-rel -1))
+ ;; Keep one or two spaces between the
+ ;; text and the ender, depending on how
+ ;; many there are now.
+ (unless spaces
+ (setq spaces (- ender-column (current-column))))
+ (setq auto-fill-spaces (c-delete-and-extract-region
+ (point) ender-start))
+ ;; paragraph filling condenses multiple spaces to
+ ;; single or double spaces. auto-fill doesn't.
+ (if fill-paragraph
+ (setq spaces
+ (max
+ (min spaces
+ (if sentence-end-double-space 2 1))
+ 1)))
+ ;; Insert the filler first to keep marks right.
+ (insert-char ?x spaces t)
+ (setq hang-ender-stuck spaces)
+ (setq point-rel
+ (and (>= point-rel 0)
+ (- (point) (min point-rel spaces)))))
+ (setq point-rel nil)))
+
+ (if point-rel
+ ;; Point was in the middle of the string we
+ ;; replaced above, so put it back in the same
+ ;; relative position, counting from the end.
+ (goto-char point-rel)))
+ ))
+
+ (when (<= beg (car c-lit-limits))
+ ;; The region includes the comment starter.
+ (save-excursion
+ (goto-char (car c-lit-limits))
+ (if (looking-at (concat "\\(" comment-start-skip "\\)$"))
+ ;; Begin with the next line.
+ (setq beg (c-point 'bonl))
+ ;; Fake the fill prefix in the first line.
+ (setq tmp-pre t))))
+
+ (setq apply-outside-literal t))
+
+ ((eq c-lit-type 'string) ; String.
+ (save-excursion
+ (when (>= end (cdr c-lit-limits))
+ (goto-char (1- (cdr c-lit-limits)))
+ (setq tmp-post (point-marker))
+ (insert ?\n)
+ (set-marker end (point)))
+ (when (<= beg (car c-lit-limits))
+ (goto-char (1+ (car c-lit-limits)))
+ (setq beg (if (looking-at "\\\\$")
+ ;; Leave the start line if it's
+ ;; nothing but an escaped newline.
+ (1+ (match-end 0))
+ (point)))))
+ (setq apply-outside-literal t))
+
+ ((eq c-lit-type 'pound) ; Macro
+ ;; Narrow to the macro limits if they are nearer than the
+ ;; paragraph limits. Don't know if this is necessary but
+ ;; do it for completeness sake (doing auto filling at all
+ ;; inside macros is bogus to begin with since the line
+ ;; continuation backslashes aren't handled).
+ (save-excursion
+ (c-save-buffer-state ()
+ (c-beginning-of-macro)
+ (beginning-of-line)
+ (if (> (point) beg)
+ (setq beg (point)))
+ (c-end-of-macro)
+ (forward-line)
+ (if (< (point) end)
+ (set-marker end (point))))))
+
+ (t ; Other code.
+ ;; Try to avoid comments and macros in the paragraph to
+ ;; avoid that the adaptive fill mode gets the prefix from
+ ;; them.
+ (c-save-buffer-state nil
+ (save-excursion
+ (goto-char beg)
+ (c-forward-syntactic-ws end)
+ (beginning-of-line)
+ (setq beg (point))
+ (goto-char end)
+ (c-backward-syntactic-ws beg)
+ (forward-line)
+ (set-marker end (point))))))
+
+ (when tmp-pre
+ ;; Temporarily insert the fill prefix after the comment
+ ;; starter so that the first line looks like any other
+ ;; comment line in the narrowed region.
+ (setq fill (c-save-buffer-state nil
+ (c-guess-fill-prefix c-lit-limits c-lit-type)))
+ (unless (string-match (concat "\\`[ \t]*\\("
+ c-current-comment-prefix
+ "\\)[ \t]*\\'")
+ (car fill))
+ ;; Oops, the prefix doesn't match the comment prefix
+ ;; regexp. This could produce very confusing
+ ;; results with adaptive fill packages together with
+ ;; the insert prefix magic below, since the prefix
+ ;; often doesn't appear at all. So let's warn about
+ ;; it.
+ (message "\
+Warning: Regexp from `c-comment-prefix-regexp' doesn't match the comment prefix %S"
+ (car fill)))
+ ;; Find the right spot on the line, break it, insert
+ ;; the fill prefix and make sure we're back in the
+ ;; same column by temporarily prefixing the first word
+ ;; with a number of 'x'.
+ (save-excursion
+ (goto-char (car c-lit-limits))
+ (if (looking-at (if (eq c-lit-type 'c++)
+ c-current-comment-prefix
+ comment-start-skip))
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+ (while (and (< (current-column) (cdr fill))
+ (not (eolp)))
+ (forward-char 1))
+ (let ((col (current-column)))
+ (setq beg (1+ (point))
+ tmp-pre (list (point)))
+ (unwind-protect
+ (progn
+ (insert-and-inherit "\n" (car fill))
+ (insert-char ?x (- col (current-column)) t))
+ (setcdr tmp-pre (point))))))
+
+ (when apply-outside-literal
+ ;; `apply-outside-literal' is always set to t here if
+ ;; we're inside a literal.
+
+ (let ((fill-prefix
+ (or fill-prefix
+ ;; Kludge: If the function that adapts the fill prefix
+ ;; doesn't produce the required comment starter for
+ ;; line comments, then force it by setting fill-prefix.
+ (when (and (eq c-lit-type 'c++)
+ ;; Kludge the kludge: filladapt-mode doesn't
+ ;; have this problem, but it currently
+ ;; doesn't override fill-context-prefix
+ ;; (version 2.12).
+ (not (and (boundp 'filladapt-mode)
+ filladapt-mode))
+ (not (string-match
+ "\\`[ \t]*//"
+ (or (fill-context-prefix beg end)
+ ""))))
+ (c-save-buffer-state nil
+ (car (or fill (c-guess-fill-prefix
+ c-lit-limits c-lit-type)))))))
+
+ ;; Save the relative position of point if it's outside the
+ ;; region we're going to narrow. Want to restore it in that
+ ;; case, but otherwise it should be moved according to the
+ ;; called function.
+ (point-rel (cond ((< (point) beg) (- (point) beg))
+ ((> (point) end) (- (point) end)))))
+
+ ;; Preparations finally done! Now we can call the
+ ;; actual function.
+ (prog1
+ (save-restriction
+ (narrow-to-region beg end)
+ (apply fun args))
+ (if point-rel
+ ;; Restore point if it was outside the region.
+ (if (< point-rel 0)
+ (goto-char (+ beg point-rel))
+ (goto-char (+ end point-rel))))))))
+
+ (when (consp tmp-pre)
+ (delete-region (car tmp-pre) (cdr tmp-pre)))
+
+ (when tmp-post
+ (save-excursion
+ (goto-char tmp-post)
+ (delete-char 1))
+ (when hang-ender-stuck
+ ;; Preserve point even if it's in the middle of the string
+ ;; we replace; save-excursion doesn't work in that case.
+ (setq here (point))
+ (goto-char tmp-post)
+ (skip-syntax-backward "^w ")
+ (forward-char (- hang-ender-stuck))
+ (if (or fill-paragraph (not auto-fill-spaces))
+ (insert-char ?\ hang-ender-stuck t)
+ (insert auto-fill-spaces)
+ (setq here (- here (- hang-ender-stuck (length auto-fill-spaces)))))
+ (delete-char hang-ender-stuck)
+ (goto-char here))
+ (set-marker tmp-post nil))
+
+ (set-marker end nil))))
+