Whenever I call
fill-paragraph, the buffer is always marked as modified, even if the command had no effect (i.e. if the paragraph was already filled). It also creates an empty undoable action (easily detected with
undo-tree-mode). Other commands which have the potential to make changes, such as the indentation commands, don't mark the buffer as modified or create an undoable action if nothing was changed. Is there any way to make
fill-paragraph mark the buffer modified and create an undoable action only if it actually changed something?
Whenever I call
Note that this is fixed for newer Emacsen (v.26 upwards).
The problem is that
fill-paragraph (or rather,
fill-region-as-paragraph) will remove and re-insert newlines while it breaks down your paragraph. It won't modify the buffer if there is only one line. The no-op in the undo list you witness is just
fill-paragraph removing and re-inserting newlines.
It is non-trivial to avoid this. The following is a pretty bad hack, and highly inefficient for large buffers, but maybe it works for you. The command mimics
M-q) with the identical behavior, except it stores the contents of the buffer before calling it, and afterwards, if the contents stayed the same, it will restore the modification state and undo list from before the change. To do this, it needs a copy (two, actually) of the buffer contents, so really, this is quite inefficient. :-)
(defun my/fill-paragraph (&optional justify region) (interactive (progn (barf-if-buffer-read-only) (list (if current-prefix-arg 'full) t))) (let ((old-text (buffer-string)) (old-modified (buffer-modified-p)) (old-undo-list buffer-undo-list)) (fill-paragraph justify region) (when (equal old-text (buffer-string)) (setq buffer-undo-list old-undo-list) (set-buffer-modified-p old-modified))))
You can bind that to
Late answer, but here's a simple version that doesn't modify the buffer if the text doesn't change.
(defun my-fill-paragraph (&optional justify region) "Fill paragraph, but don't modify the buffer if filling doesn't change the text. See `fill-paragraph' for details." (interactive (progn (barf-if-buffer-read-only) (list (if current-prefix-arg 'full) t))) (if (buffer-modified-p) ;; if modified: use standard fill-paragraph (fill-paragraph justify region) ;; if unmodified: get a candidate filled version (save-excursion (let* ((col fill-column) (beg (progn (forward-paragraph -1) (skip-syntax-forward " >") (point))) (end (progn (forward-paragraph 1) (skip-syntax-backward " >") (point))) (old (buffer-substring-no-properties beg end)) (new (with-temp-buffer (setq fill-column col) (insert old) (fill-paragraph justify region) (buffer-string)))) ;; don't modify unless the old and new versions differ (unless (string-equal old new) (delete-region beg end) (insert new))))))
It adapts some of the ideas in @JorgenSchäfer's answer, but works only with the current paragraph, and only in a simple, whitespace-separated way (see comments on @JorgenSchäfer's answer about complications under the hood).
This is about the only use case that's relevant for my own purposes (ie, interactive use with "normal" prose, no active region), so I'm posting it in case anyone wants to use it or improve it for more complicated use cases.