'Semantic' movement across a line - emacs

Consider the following line of Lisp code:
(some-function 7 8 | 9) ;; some comment. note the extra indentation
The point is placed between '8' and '9'. If I perform (move-beginning-of-line), the point will be placed at the absolute beginning of the line, rather than at '('.
Same for move-end-of-line: I'd find it more desirable for it to place the point at ')' if I perform it once, and at the absolute end of the line if I perform it a second time. Some IDEs behave like that.
I tried to implement this but got stuck, my solution behaves particularly bad near the end of a buffer, and on the minibuffer as well. Is there a library that provides this functionality?

I don't know of any library, but it can be done in a few lines of Elisp.
For the beginning of line part, the bundled functions beginning-of-line-text and back-to-indentation (M-m) move to the beginning of the “interesting” part of the line. back-to-indentation ignores only whitespace whereas beginning-of-line-text skips over the fill prefix (in a programming language, this is typically the comment marker, if in a comment). See Smart home in Emacs for how to flip between the beginning of the actual and logical line.
For the end of line part, the following function implements what you're describing. The function end-of-line-code moves to the end of the line, except for trailing whitespace and an optional trailing comment. The function end-of-line-or-code does this, except that if the point was already at the target position, or if the line only contains whitespace and a comment, the point moves to the end of the actual line.
(defun end-of-line-code ()
(interactive "^")
(save-match-data
(let* ((bolpos (progn (beginning-of-line) (point)))
(eolpos (progn (end-of-line) (point))))
(if (comment-search-backward bolpos t)
(search-backward-regexp comment-start-skip bolpos 'noerror))
(skip-syntax-backward " " bolpos))))
(defun end-of-line-or-code ()
(interactive "^")
(let ((here (point)))
(end-of-line-code)
(if (or (= here (point))
(bolp))
(end-of-line))))

Some suggestions that almost do what you ask:
In lisp code, you can sort-of do what you want, with the sexp movement commands. To get to the beginning of the expression from somewhere in the middle, use backward-up-list, which is bound to M-C-u. In your example, that would bring you to the open parenthesis. To move backwards over individual elements in the list, use backward-sexp, bound to M-C-b; forward-sexp moves the other way, and is bound to M-C-f. From the beginning of an sexp, you can skip to the next with M-C-n; reverse with M-C-p.
None of these commands are actually looking at the physical line you are on, so they'll go back or forward over multiple lines.
Other options include Ace Jump mode, which is a very slick way to quickly navigate to the beginning of any word visible on the screen. That might eliminate your need to use line-specific commands. For quick movement within a line, I usually use M-f and M-b to jump over words. Holding the M key down while tapping on b or f is quick enough that I end up using that by default most of the time.
Edit:
Forgot one other nice command - back-to-indentation, bound to M-m. This will back you up to the first non-whitespace character in a line. You could advice this to behave normally on the first call, and then to back up to the beginning of the line on the second call:
(defadvice back-to-indentation (around back-to-back)
(if (eq last-command this-command)
(beginning-of-line)
ad-do-it))
(ad-activate 'back-to-indentation)

I just wrote these two functions that have the behavior you are looking for.
(defun move-beginning-indent ()
(interactive)
(if (eq last-command this-command)
(beginning-of-line)
(back-to-indentation))
)
(defun move-end-indent ()
(interactive)
(if (eq last-command this-command)
(end-of-line)
(end-of-line)
(search-backward-regexp "\\s)" nil t) ; searches backwards for a
(forward-char 1)) ; closed delimiter such as ) or ]
)
(global-set-key [f7] 'move-beginning-indent)
(global-set-key [f8] 'move-end-indent)
Just try them out, they should behave exactly the way you'd want them to.

I use this:
(defun beginning-of-line-or-text (arg)
"Move to BOL, or if already there, to the first non-whitespace character."
(interactive "p")
(if (bolp)
(beginning-of-line-text arg)
(move-beginning-of-line arg)))
(put 'beginning-of-line-or-text 'CUA 'move)
;; <home> is still bound to move-beginning-of-line
(global-set-key (kbd "C-a") 'beginning-of-line-or-text)
(defun end-of-code-or-line ()
"Move to EOL. If already there, to EOL sans comments.
That is, the end of the code, ignoring any trailing comment
or whitespace. Note this does not handle 2 character
comment starters like // or /*. Such will not be skipped."
(interactive)
(if (not (eolp))
(end-of-line)
(skip-chars-backward " \t")
(let ((pt (point))
(lbp (line-beginning-position))
(comment-start-re (concat (if comment-start
(regexp-quote
(replace-regexp-in-string
"[[:space:]]*" "" comment-start))
"[^[:space:]][[:space:]]*$")
"\\|\\s<"))
(comment-stop-re "\\s>")
(lim))
(when (re-search-backward comment-start-re lbp t)
(setq lim (point))
(if (re-search-forward comment-stop-re (1- pt) t)
(goto-char pt)
(goto-char lim) ; test here ->
(while (looking-back comment-start-re (1- (point)))
(backward-char))
(skip-chars-backward " \t"))))))
(put 'end-of-code-or-line 'CUA 'move)
;; <end> is still bound to end-of-visual-line
(global-set-key (kbd "C-e") 'end-of-code-or-line)

Related

Change mark-paragraph behaviour

How to change default emacs mark-paragraph function behaviour to not select first empty line?
my emacs http://dl.dropbox.com/u/1019877/e2.PNG
I've made Bohzidars upgraded version and it works for first line too.
(global-set-key (kbd "M-h") (lambda ()
(interactive)
(mark-paragraph)
(if (> (line-number-at-pos) 1)
(next-line))
(beginning-of-line)))
thanks guys for the tips.
The currently accepted answer has two disadvantages: 1) doesn't accept arguments and 2) doesn't allow to mark more paragraphs by repeated calls (especially this is very useful). Here is my solution - it is the original mark-paragraph with a next-line command at the end. The condition assures it works also on the first of the file.
Possibly a more economic solution is to use advices, but I don't know how to use them yet :).
(defun rs-mark-paragraph (&optional arg allow-extend)
"The original default mark-paragraph, but doesn't mark the first
empty line. Put point at beginning of this paragraph, mark at
end. The paragraph marked is the one that contains point or
follows point.
With argument ARG, puts mark at end of a following paragraph, so that
the number of paragraphs marked equals ARG.
If ARG is negative, point is put at end of this paragraph, mark is put
at beginning of this or a previous paragraph.
Interactively, if this command is repeated
or (in Transient Mark mode) if the mark is active,
it marks the next ARG paragraphs after the ones already marked."
(interactive "p\np")
(unless arg (setq arg 1))
(when (zerop arg)
(error "Cannot mark zero paragraphs"))
(cond ((and allow-extend
(or (and (eq last-command this-command) (mark t))
(and transient-mark-mode mark-active)))
(set-mark
(save-excursion
(goto-char (mark))
(forward-paragraph arg)
(point))))
(t
(forward-paragraph arg)
(push-mark nil t t)
(backward-paragraph arg)
(if (/= (line-number-at-pos) 1)
(next-line)))))
You cannot change the behaviour of mark-paragraph, but you can easily bind another command to the C-M-h keystroke (to resemble the original M-h):
(global-set-key (kbd "C-M-h") (lambda ()
(interactive)
(mark-paragraph)
(next-line)
(beginning-of-line)))
Something like this should do the trick.
I'm not sure I see a convenient way to do this. mark-paragraph calls forward-paragraph and backward-paragraph to do the bulk of the work, and in the documentation for backward-paragraph, we have "if the first real line of a paragraph is preceded by a blank line, the paragraph starts at that blank line."
The most relevant variables to look at appear to be paragraph-start and paragraph-separate, two regular expressions used inside paragraphs.el to figure out this sort of thing. I'd be leary of changing them though, as they are going to have quite a lot of other effects.
Another option is to write your own function that does something like the following:
(defun dg-mark-paragraph ()
(interactive)
(mark-paragraph)
(goto-char (region-beginning))
(when (= (string-match paragraph-separate (thing-at-point 'line)) 0)
(forward-line)))

emacs 23.2.1: character-by-character copying from the previous line seems broken

After upgrading to emacs 23.2.1 with Fedora 15 one of my emacs functions is broken and I just can't seem to find the problem. Something has to have changed, but I sure can't find it in the elisp documentation.
I'd really appreciate any suggestions!
What it should do: Pressing Ctl-hyphen should copy the character above the cursor and move the point ahead by 1.
What it does: Keeps copying the character above without advancing the point. HOWEVER, calling it with "M-x insert-char-from-previous-line" or pressing RightArrow between Ctl-hypens works as it should. Adding (forward-char 1) to the end of the script doesn't help.
(defun insert-char-from-previous-line ()
"Copy previous line character by character"
(interactive)
(previous-line 1)
(let ((char-above (following-char) ))
(next-line 1)
(if (not (char-equal char-above ?\n ))
(insert char-above))))
(global-set-key [?\C--] 'insert-char-from-previous-line) ;copy char above
I think your getting caught in a goal column issue. You probably should not use next-line/previous-line for this, rather try this:
(defun insert-char-from-previous-line ()
"Copy previous line character by character"
(interactive)
(let ((curpoint (point))
(curcolumn (current-column)))
(forward-line -1)
(forward-char curcolumn)
(let ((char-above (following-char) ))
(goto-char curpoint)
(if (not (char-equal char-above ?\n ))
(insert char-above)))))
From the docs on pervious-line:
If you are thinking of using this in a Lisp program, consider using
`forward-line' with a negative argument instead. It is usually easier
to use and more reliable (no dependence on goal column, etc.).
(describe-function 'previous-line)
don't move the point for something like this:
(defun i-char (arg)
(interactive "*p")
(let ((start (+ (point-at-bol 0)
(current-column)))))
(insert (buffer-substring-no-properties start (+ start arg))))

Disable auto-fill-mode locally (or un fill-paragraph) with emacs

I use M-q for fill-paragraph, can I do the un-fill-paragraph in auto-fill-mode?
With org mode, I sometimes enter [[Very long HTML][Name with spaces]], and for the 'Name with spaces' the auto-fill mode break the whole line based on the inserted space, which makes it very ugly.
Is there a command something like un-fill-paragraph? Or, is there a way disable auto-fill-mode temporarily/locally?
Emacs does not record what was your line before calling fill-paragraph. So the only thing you can do is C-_ which runs the command undo. It can undo your fill-paragraph command but only if it is the preceding command call.
If you want to put a multi-line paragraph on one line you could do like this :
Select the region
C-M-% C-q C-j RET SPACE RET !
Xah Lee has updated his code since monotux's answer, and I refactored it somewhat for readability:
(defun my-toggle-fill-paragraph ()
;; Based on http://xahlee.org/emacs/modernization_fill-paragraph.html
"Fill or unfill the current paragraph, depending upon the current line length.
When there is a text selection, act on the region.
See `fill-paragraph' and `fill-region'."
(interactive)
;; We set a property 'currently-filled-p on this command's symbol
;; (i.e. on 'my-toggle-fill-paragraph), thus avoiding the need to
;; create a variable for remembering the current fill state.
(save-excursion
(let* ((deactivate-mark nil)
(line-length (- (line-end-position) (line-beginning-position)))
(currently-filled (if (eq last-command this-command)
(get this-command 'currently-filled-p)
(< line-length fill-column)))
(fill-column (if currently-filled
most-positive-fixnum
fill-column)))
(if (region-active-p)
(fill-region (region-beginning) (region-end))
(fill-paragraph))
(put this-command 'currently-filled-p (not currently-filled)))))
To remake a long line out of a paragraph in Org mode, I gave myself a new command. Here is the associated Emacs Lisp code:
(defun fp-unfill-paragraph (&optional justify region)
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
(interactive)
(let ((fill-column 100000))
(fill-paragraph justify region)))
(global-set-key "\C-ceu" 'fp-unfill-paragraph)
Of course, you adjust the command keybinding as you see fit!
I use the following snippet to fill and un-fill paragraphs (using only M-q), it is really, really handy. I borrowed it from Xah Lee, but removed some comments and whitespace in order to make it fit in here. The link in the first comment goes to his original code.
;; http://xahlee.org/emacs/modernization_fill-paragraph.html
(defun compact-uncompact-block ()
"Remove or add line endings on the current block of text.
This is similar to a toggle for fill-paragraph and unfill-paragraph
When there is a text selection, act on the region.
When in text mode, a paragraph is considered a block. When in programing
language mode, the block defined by between empty lines.
Todo: The programing language behavior is currently not done.
Right now, the code uses fill* functions, so does not work or work well
in programing lang modes. A proper implementation to compact is replacing
newline chars by space when the newline char is not inside string.
"
(interactive)
(let (bds currentLineCharCount currentStateIsCompact
(bigFillColumnVal 4333999) (deactivate-mark nil))
(save-excursion
(setq currentLineCharCount
(progn
(setq bds (bounds-of-thing-at-point 'line))
(length (buffer-substring-no-properties (car bds) (cdr bds)))))
(setq currentStateIsCompact
(if (eq last-command this-command)
(get this-command 'stateIsCompact-p)
(if (> currentLineCharCount fill-column) t nil)))
(if (and transient-mark-mode mark-active)
(if currentStateIsCompact
(fill-region (region-beginning) (region-end))
(let ((fill-column bigFillColumnVal))
(fill-region (region-beginning) (region-end)))
)
(if currentStateIsCompact
(fill-paragraph nil)
(let ((fill-column bigFillColumnVal))
(fill-paragraph nil))))
(put this-command 'stateIsCompact-p
(if currentStateIsCompact
nil t)))))
(global-set-key (kbd "M-q") 'compact-uncompact-block)

Shift a region or line in emacs

I'm looking for a way in emacs to shift text to the right or to the left by n spaces. A similar functionality that it in vim << or >>. It should work on a region or if no region is selected on a current line and not move the cursor from its current location.
The solution from EmacsWiki does not work very well as the M-x indent-rigidly since it somewhat remembers the last region used and shifts that one instead. The closest seems to be the one here but I did not managed to make it work. I'm not a lisp developer so it's difficult to modify the code. I will appreciate any help.
Thanks!
You could select the region then C-u C-x <tab> will shift 4 spaces. You can type a number after C-u to change 4 to anything else.
Maybe this works the way you want.
(defun shift-text (distance)
(if (use-region-p)
(let ((mark (mark)))
(save-excursion
(indent-rigidly (region-beginning)
(region-end)
distance)
(push-mark mark t t)
(setq deactivate-mark nil)))
(indent-rigidly (line-beginning-position)
(line-end-position)
distance)))
(defun shift-right (count)
(interactive "p")
(shift-text count))
(defun shift-left (count)
(interactive "p")
(shift-text (- count)))
To achieve this I usually do a trick:
activate CUA mode
go to the beginning of line
C-RET, now if you move the cursor you should see a rectangular red region
Move the cursor down the lines and type space until you've obtained the correct shifting.
This can be done also programmatically in some way (in the same way).
EDIT:
I've just read the article in emacs wiki, it's the same solution except for the CUA mode that is infinitely more powerful than the "common" rectanguar selection (since it's visual).
As I use Evil (with Spacemacs), the Vim-like region shifting is already implemented in visual mode with S-v and </> properly.
I'm mostly using hybrid-mode though, and when it's active I also want to be able to shift the region, preferrably by the current language's shift-width.
To achieve this, here's an implementation that re-uses evil's shifting, but does it "properly" in hybrid-mode.
(defun jj/shift-text (beg end shift-block-fun shift-line-fun)
"shift text in region or line using evil like S-v with < and > do in Vim.
It takes special care of preserving or even extending the region to the moved text lines."
(if (use-region-p)
(progn
(let ((point-at-end (< (mark) (point))))
;; fix up current region end to grab the whole line
(if point-at-end
(end-of-line)
(beginning-of-line))
;; then fix up the other region end
(exchange-point-and-mark)
(if point-at-end
(beginning-of-line)
(end-of-line))
;; restore mark-point order
(exchange-point-and-mark)
(let ((linebeg (if point-at-end (mark) (point)))
(lineend (if point-at-end (point) (mark))))
;; shift the text
(save-mark-and-excursion
(funcall shift-block-fun linebeg lineend)
;; "In Transient Mark mode, every buffer-modifying primitive sets deactivate-mark"
;; but we wanna keep it active :)
(setq deactivate-mark nil)))))
(funcall shift-line-fun 1)))
(defun jj/shift-left (beg end)
(interactive "r")
(jj/shift-text beg end #'evil-shift-left #'evil-shift-left-line))
(defun jj/shift-right (beg end)
(interactive "r")
(jj/shift-text beg end #'evil-shift-right #'evil-shift-right-line))
and where your keybindings are defined:
;; text shifting. evil-normal-state-map has these anyway.
(define-key evil-hybrid-state-map (kbd "M-<") #'jj/shift-left)
(define-key evil-hybrid-state-map (kbd "M->") #'jj/shift-right)

How do I get Emacs to fill sentences, but not paragraphs?

I've seen at least two recommendations on StackOverflow to insert newlines between sentences when editing LaTeX documents. The reason being that the practice facilitates source control, diffing, and collaborative editing.
I'm basically convinced, but I'm lazy, and I don't want to have to think about it.
So I'm searching for some emacs incantation to handle it for me. Could be a minor mode, could be a set of variables that need to be set.
I think what I don't want is
Soft wrapping of text (say using the longlines and (set long-lines-auto-wrap 't)). This is because I don't want to impose requirements on my collaborators' editors, and I sometimes use other unix tools to examine these files.
I think what I do want is
For fill-paragraph to fill between newlines that look like they mark the end of a sentence.
A solution that works with auto-fill-mode would be a bonus.
That is:
chat chat chat.
A new sentence
with goofed up wrapping that needs to be fixed.
Mumble mumble
Transformed to:
chat chat chat.
A new sentence with goofed up wrapping that needs to be fixed.
Mumble mumble
Your comments and suggestions are appreciated.
Edit: The suggestion by Jouni K. Seppänen pointed me at LaTeX-fill-break-at-separators, which suggests that emacs almost knows how to do this already. Anyway, I'm off to read some code, and will report back. Thanks again.
More general version of the same question: Editor showdown: Maintain newlines at the ends of sentences. Thanks, dreeves.
Here's what I use, which was mostly cribbed from Luca de Alfaro:
(defun fill-sentence ()
(interactive)
(save-excursion
(or (eq (point) (point-max)) (forward-char))
(forward-sentence -1)
(indent-relative t)
(let ((beg (point))
(ix (string-match "LaTeX" mode-name)))
(forward-sentence)
(if (and ix (equal "LaTeX" (substring mode-name ix)))
(LaTeX-fill-region-as-paragraph beg (point))
(fill-region-as-paragraph beg (point))))))
I bind this to M-j with
(global-set-key (kbd "M-j") 'fill-sentence)
The references to "LaTeX" are for AUCTeX support. If you don't use AUCTeX, the let can be simplified to
(let (beg (point))
(forward-sentence)
(fill-region-as-paragraph beg (point)))
I have been meaning to do this forever and I recently found this blog post which worked fairly well for me. So here is (a slightly modified version of) what I have been using for a few days.
(defun auto-fill-by-sentences ()
(if (looking-back (sentence-end))
;; Break at a sentence
(progn
(LaTeX-newline)
t)
;; Fall back to the default
(do-auto-fill)))
(add-hook 'LaTeX-mode-hook (lambda () (setq auto-fill-function 'auto-fill-by-sentences)))
;; Modified from http://pleasefindattached.blogspot.com/2011/12/emacsauctex-sentence-fill-greatly.html
(defadvice LaTeX-fill-region-as-paragraph (around LaTeX-sentence-filling)
"Start each sentence on a new line."
(let ((from (ad-get-arg 0))
(to-marker (set-marker (make-marker) (ad-get-arg 1)))
tmp-end)
(while (< from (marker-position to-marker))
(forward-sentence)
;; might have gone beyond to-marker---use whichever is smaller:
(ad-set-arg 1 (setq tmp-end (min (point) (marker-position to-marker))))
ad-do-it
(ad-set-arg 0 (setq from (point)))
(unless (or (looking-back "^\\s *")
(looking-at "\\s *$"))
(LaTeX-newline)))
(set-marker to-marker nil)))
(ad-activate 'LaTeX-fill-region-as-paragraph)
If you put a comment marker at the end of each sentence, Emacs knows not to move the next line inside the comment:
chat chat chat.%
A new sentence
with goofed up wrapping that needs to be fixed.%
Mumble mumble%
Then M-q fills each sentence separately, at least in AUCTeX 11.85. (If you test this in Emacs, there seems to be a bug where if this is the first paragraph in the buffer and you type M-q, you get an error message. Just put a newline before the text to work around it.)
If you don't want to type the comment characters, you could take LaTeX-fill-paragraph and modify it so that sentence-ending punctuation at end of line works similarly to comments.
(defun wrap-at-sentences ()
"Fills the current paragraph, but starts each sentence on a new line."
(interactive)
(save-excursion
;; Select the entire paragraph.
(mark-paragraph)
;; Move to the start of the paragraph.
(goto-char (region-beginning))
;; Record the location of the end of the paragraph.
(setq end-of-paragraph (region-end))
;; Wrap lines with 'hard' newlines (i.e., real line breaks).
(let ((use-hard-newlines 't))
;; Loop over each sentence in the paragraph.
(while (< (point) end-of-paragraph)
;; Determine the region spanned by the sentence.
(setq start-of-sentence (point))
(forward-sentence)
;; Wrap the sentence with hard newlines.
(fill-region start-of-sentence (point))
;; Delete the whitespace following the period, if any.
(while (char-equal (char-syntax (preceding-char)) ?\s)
(delete-char -1))
;; Insert a newline before the next sentence.
(insert "\n")))))
(global-set-key (kbd "M-q") 'wrap-at-sentences)
May not work in all circumstances, but:
(defun my-fill-sentence ()
"Fill sentence separated by punctuation or blank lines."
(interactive)
(let (start end)
(save-excursion
(re-search-backward "\\(^\\s-*$\\|[.?!]\\)" nil t)
(skip-syntax-forward "^w")
(setq start (point-at-bol)))
(save-excursion
(re-search-forward "\\(^\\s-*$\\|[.?!]\\)" nil t)
(setq end (point-at-eol)))
(save-restriction
(narrow-to-region start end)
(fill-paragraph nil))))
To make it work with auto-fill-mode, add (setq normal-auto-fill-function 'my-fill-sentence) to your LaTeX mode hook (I think).
I am assuming you know elisp.
There are a few approaches you can take:
Hook into auto-fill-mode. There are a lot of hard-coded
conditionals there, so it might not work for you. You can
potentially play with auto-fill-function and see if you have
the hook you need there.
Make a character (probably .) "electric" so that when you press
it, it inserts itself and then calls a function to determine how
to fill the line you're on.
Set an after-change-hook to call a function that determines how
to fill the sentence. This function will be called after every
change to the buffer, so do it efficiently. (This mechanism is
used by font-lock, so don't worry about it too much. It sounds
slow, but really isn't -- people type slowly.)
Once you have hooked in at the right place, you just have to implement
the filling logic. The source for sentence-at-point (from thingatpt) may be
instructive.
Anyway, I've never heard of anyone doing this... but it is definitely possible. Like most things in Emacs, it's just a Simple Matter Of Programming.
If the other answers are too automatic, here's a semiautomatic approach.
It's basically what you would do repeatedly if you were going to manually reformat, but condensed so you can hit a single key repeatedly instead.
;; - go to the end of the line,
;; - do ^d to suck the previous line onto this one,
;; - make sure there's only one space between the now-concatenated
;; lines, and then
;; - jump to the end and hit space so that (with auto-fill-mode)
;; the line nicely rewraps itself:
;; (turn on auto-fill-mode with M-x auto-fill-mode)
(defalias 'fill-sentence
(read-kbd-macro "C-e C-d SPC M-x just- one- space RET C-e SPC <backspace>"))
(define-key global-map [f4] 'fill-sentence) ; or whatever key you like
I like Chris Conway's macro a lot but it only works after you manually line-break each sentence. I'm a lazy guy so I want emacs to do it for me. This morning I finally sat down and looked into the problem. The solution I have now is to hack the built-in macro fill-region-as-paragraph.
After applying the following hack, a new option newline-after-sentence will be set to true. The standard M-q (fill-paragraph) will automatically fill and create line-breaks between sentences. Note that tests are only done with GNU Emacs 23.3.1 — use it at your own risk.
The full macro is long so I won't post it here. The idea is to add the following loops in fill-region-as-paragraph
...
;; Insert a line break after each sentence
(while (< (point) to)
(forward-sentence)
(if (< (point) to) (fill-newline)))
;; This is the actual filling loop.
(goto-char from)
(let (sentbeg sentend)
(while (< (point) to)
(setq sentbeg (point))
(end-of-line)
(setq sentend (point))
(fill-one-line sentbeg sentend justify) ;; original filling loop
(forward-line)))))
...
You can find the full macro in my git repository. Some details are also written in my blog. In case you don't want to read my poor English, you can simply use
$ curl http://fermi.mycloudnas.com/cgit.cgi/fill/plain/hack.el >> ~/.emacs
to append the hack to your ~/.emacs and give it a try. Comments and bug reports are all welcome.
An alternative approach would be to leave your .tex file as is, and use a tool like latexdiff
(described in this StackExchange post) instead of Unix diff. This produces a .tex file with Word-style track changes marks, and handles whitespace correctly so you don't have to worry about where your sentences end.
I wrote the following which loops over a region and inserts newlines. Instead of using forward-sentence which didn't work for me, I use re-search-forward "[.?!][]\"')}]*\\( \\)", which finds all sentences followed only by two spaces (the regexp is a modified sentence-end). The newline is made using newline-and-indent.
(defun fill-sentences-in-paragraph ()
"Put a newline at the end of each sentence in paragraph."
(interactive)
(save-excursion
(mark-paragraph)
(call-interactively 'fill-sentences-in-region)))
(defun fill-sentences-in-region (start end)
"Put a newline at the end of each sentence in region."
(interactive "*r")
(call-interactively 'unfill-region)
(save-excursion
(goto-char start)
(while (re-search-forward "[.?!][]\"')}]*\\( \\)" end t)
(newline-and-indent))))
To be able to fix improperly formatted text such as the example "chat chat chat...", fill-sentences-in-region first calls unfill-region which gets rid of sentence-breaking whitespace:
(defun unfill-region (beg end)
"Unfill the region, joining text paragraphs into a
single logical line. This is useful, e.g., for use
with 'visual-line-mode'."
(interactive "*r")
(let ((fill-column (point-max)))
(fill-region beg end)))
I use visual-line-mode and replace my default paragraph fill M-q to fill-sentences-in-paragraph with (global-set-key "\M-q" 'fill-sentences-in-paragraph).