When working with LaTeX, it is recommended to start each sentence on a new line. The reasons can be found in Axel Brandenburg’s computing tips and this stack overflow page so I won’t repeat them here. However, as an emacs user, I always want emacs do the formatting for me.

The existing solutions are summarized here. The  most promising Emacs Lisp macro is provided by Chris Conway, which was cribbed from Luca de Alfaro. Their method does the job well. However, suppose I have a paragraph like the following (which is taken from this paper)

Once we obtain \citeauthor{Grad1949}'s coefficients, we can use them
to compute the flux terms.  \citeauthor{Grad1949}'s moment method is
linear in the fiducial frame.  The linearity naturally form a class of
closure schemes.  Since we fix the weight $w(\xi)$, the only freedoms
in the closures are the energy scale $\theta$ and the fiducial
reference frame corresponds to $U^\alpha$.

their fill-sentence macro has no effect because no line-break is placed between sentences.

So this morning I finally sat down and worked on the problem. I first needed to understand out how the standard fill-paragraph macro works:

$ gunzip -c /opt/local/share/emacs/23.3/lisp/textmodes/fill.el.gz | less

Note that my GNU Emacs 23.3 was installed by MacPorts, your path may be different. Scanning through the codes, I realized that all those fill-paragraph and fill-region macros go back to fill-region-as-paragraph (line 608 in the source). Hacking this function/macro may provide a good solution.

I copied the whole fill-region-as-paragraph function into my ~/.emacs and started playing around it. The final product is now on my git repository. I highlight the most important changes here

	...

	;; FROM, and point, are now before the text to fill,
	;; but after any fill prefix on the first line.
	(fill-delete-newlines from to justify nosqueeze squeeze-after)

	(if (not newline-after-sentence)
	    (fill-one-line from to justify) ;; original innner loop

	  ;; Insert a line break after each sentence
	  (goto-char from)
	  (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 innner loop
	      (forward-line)))))

	...

From line 152 to 154, the macros inserts line-breaks after sentences. The loop from line 158 to 163 then fills sentence line-by-line. You can also look at the diff for more details.

Well, I should warn you that this is my first experience on Emacs Lisp. The macros seem to run correctly on GNU Emacs 23.3.1 but they surely contain bugs. Use and test them at your own risk, but please feel free to leave comment or bug report. I really hope this will become something useful for everybody. If you are ready to take the risk, you can append this hack to your ~/.emacs and override the original fill-region-as-paragraph macro:

$ curl http://fermi.mycloudnas.com/cgit.cgi/fill/plain/hack.el >> ~/.emacs

Now, apply fill-paragraph (or simply M-q) in emacs results

Once we obtain \citeauthor{Grad1949}'s coefficients, we can use them
to compute the flux terms.
\citeauthor{Grad1949}'s moment method is linear in the fiducial frame.
The linearity naturally form a class of closure schemes.
Since we fix the weight $w(\xi)$, the only freedoms in the closures
are the energy scale $\theta$ and the fiducial reference frame
corresponds to $U^\alpha$.

which is exactly what I want.

 

5 Responses to Smart Sentence Filling in Emacs

  1. KnowsEmacs says:

    Hello,
    thanks for your article. But why?

    gunzip -c /opt/local/share/emacs/23.3/lisp/textmodes/fill.el.gz | less

    Open the file! Emacs knows about gunzip. You can even hit: C-h f fill-paragraph and select the link to the file and you get immediately to the definition of the macro. No need to use less.

    (And even less knows how to gunzip a file if you have lesspipes activated)

    Regards

    • CK says:

      Thanks for point out the “C-h f fill-paragraph” method! I feel bad not knowing this after using emacs for almost 8 years. For using less directly on gzipped files, it seems that I have to run zless instead of less.

      Cheers!

  2. [...] Smart Sentence Filling in Emacs | Chi-kwan Chan’s Website at NorditaMay 23, 2011 … their fill-sentence macro has no effect because no line-break is placed … I first needed to understand out how the standard fill-paragraph … [...]

  3. [...] Here is a solution that takes care of this by patching/overriding the fill-region-as-paragraph function of text modes. This is not very elegant, but the defadvice mechanism does not work in this case. My main quibble, however, is that this no longer works nicely if you use the most capable LaTeX-editing mode AUCTeX: In its file latex.el, the code of the several filling functions is a quite convoluted (for my capabilities and taste) extension of the original TeX mode functions. So you get two different implementations of related functionality, and you lose some LaTeX-awareness of the filling functions. [...]

  4. Ingo says:

    Hi, I liked your article.

    One thing that bothered me was that it is a reimplementation, and that it is not integrated with the TeX-specific filling functions. Your post motivated me to finally tackle the problem myself (had it on my mind for quite some time).

    Here is an alternative solution that builds on top of the LaTeX functionality in AUCTeX:

    Emacs sentence-fills paragraphs for version control

    It is an ongoing work to integrate it more smoothly, but should be fully functional as it is.

    Regards.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Set your Twitter account name in your settings to use the TwitterBar Section.