diff --git a/CHANGES.md b/CHANGES.md index d9aecab2..a20b4790 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,6 +21,8 @@ Previously, `markdown-header-delimiter-face` was used. - Markdown Mode is now distributed under the GNU GPL version 3 or later. + - Rename `markdown-fill-forward-paragraph-function` to + `markdown-fill-forward-paragraph`. * New features: @@ -118,6 +120,8 @@ - Reuse existing windows, when possible, rather than splitting again in preferred direction. ([GH-129][]) - Update known languages in `markdown-gfm-recognized-languages`. + - Filling with `fill-region` now leaves code blocks unmodified. + ([GH-192][]) * Bug fixes: @@ -135,6 +139,7 @@ [gh-176]: https://github.com/jrblevin/markdown-mode/issues/176 [gh-185]: https://github.com/jrblevin/markdown-mode/issues/185 [gh-191]: https://github.com/jrblevin/markdown-mode/issues/191 + [gh-192]: https://github.com/jrblevin/markdown-mode/issues/192 [gh-197]: https://github.com/jrblevin/markdown-mode/issues/197 # Markdown Mode 2.2 diff --git a/markdown-mode.el b/markdown-mode.el index 9680ddd6..04f21203 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -7709,24 +7709,39 @@ handles filling itself, it always returns t so that (fill-paragraph justify)) t) -(defun markdown-fill-forward-paragraph-function (&optional arg) +(make-obsolete 'markdown-fill-forward-paragraph-function + 'markdown-fill-forward-paragraph "v2.3") + +(defun markdown-fill-forward-paragraph (&optional arg) "Function used by `fill-paragraph' to move over ARG paragraphs. This is a `fill-forward-paragraph-function' for `markdown-mode'. It is called with a single argument specifying the number of paragraphs to move. Just like `forward-paragraph', it should return the number of paragraphs left to move." - (let* ((arg (or arg 1)) - (paragraphs-remaining (forward-paragraph arg)) - (start (point))) - (when (< arg 0) + (or arg (setq arg 1)) + (if (> arg 0) + ;; With positive ARG, move across ARG non-code-block paragraphs, + ;; one at a time. When passing a code block, don't decrement ARG. + (while (and (not (eobp)) + (> arg 0) + (= (forward-paragraph 1) 0) + (or (markdown-code-block-at-pos (point-at-bol 0)) + (setq arg (1- arg))))) + ;; Move backward by one paragraph with negative ARG (always -1). + (let ((start (point))) + (setq arg (forward-paragraph arg)) (while (and (not (eobp)) (progn (move-to-left-margin) (not (eobp))) (looking-at-p paragraph-separate)) (forward-line 1)) - (if (looking-at markdown-regex-list) - (forward-char (length (match-string 0))) - (goto-char start))) - paragraphs-remaining)) + (cond + ;; Move point past whitespace following list marker. + ((looking-at markdown-regex-list) + (goto-char (match-end 0))) + ;; Return point if the paragraph passed was a code block. + ((markdown-code-block-at-pos (point-at-bol 2)) + (goto-char start))))) + arg) ;;; Extension Framework ======================================================= @@ -8210,7 +8225,7 @@ position." (set (make-local-variable 'adaptive-fill-function) 'markdown-adaptive-fill-function) (set (make-local-variable 'fill-forward-paragraph-function) - 'markdown-fill-forward-paragraph-function) + #'markdown-fill-forward-paragraph) ;; Outline mode (make-local-variable 'outline-regexp) (setq outline-regexp markdown-regex-header) diff --git a/tests/markdown-test.el b/tests/markdown-test.el index 35855d8f..b96bdd93 100644 --- a/tests/markdown-test.el +++ b/tests/markdown-test.el @@ -4346,6 +4346,60 @@ this is not header line (fill-paragraph) (should (string-equal (buffer-string) text)))))) +(ert-deftest test-markdown-filling/fill-region-skip-code-blocks () + "Test `fill-region' on code blocks." + (let ((text "testing\n\n```\nhello\nworld\n```\n\n123")) + (markdown-test-string text + ;; Fill entire buffer; buffer should not change. + (fill-region (point-min) (point-max)) + (should (string-equal (buffer-string) text))))) + +(ert-deftest test-markdown-filling/fill-region-skip-code-blocks-2 () + "Test `fill-region' on a buffer with a code block with long paragraphs." + (markdown-test-string "long unwrapped paragraph 1 + +``` +code +block + +foo +bar +``` + +long unwrapped paragraph 2" + ;; Test markdown-fill-forward-paragraph movement. + (should (= (markdown-fill-forward-paragraph 1) 0)) + (should (= (point) 28)) ;; Point just after par. 1. + (should (= (markdown-fill-forward-paragraph 1) 0)) + (should (= (point) 84)) ;; Point at end of par. 2. + ;; Test filling the entire buffer with `fill-region'. + (let ((fill-column 12)) + (fill-region (point-min) (point-max)) + (should (string-equal (buffer-string) + "long +unwrapped +paragraph 1 + +``` +code +block + +foo +bar +``` + +long +unwrapped +paragraph 2"))))) + +(ert-deftest test-markdown-filling/fill-region-skip-code-blocks-3 () + "Test `fill-region' on a lone code block with no surrounding text." + (let ((text "```\ncode\nblock\n```\n")) + (markdown-test-string text + ;; Fill entire buffer; buffer should not change. + (fill-region (point-min) (point-max)) + (should (string-equal (buffer-string) text))))) + (ert-deftest test-markdown-filling/long-paragraph-with-link () "Test `fill-paragraph' on a long paragraph with a long link." (markdown-test-string