30

A bit of background.

I’m trying to version-control my latex documents, and the effectiveness of this initiative would be greatly improved if I adopt a one-sentence-per-line approach.

For instance, the following is what my documents will look like.

Some text here.
New stencence on the same paragraph.
Some more text, still on the same paragraph.

This is another paragraph.

My question is simple.
How much of that can I automate/improve with Emacs?

The following two points are what I have in mind.

  1. My sentences are long, so I need to wrap lines without actually filling them. That is, a very long sentence needs to be displayed over several lines on my screen, but it needs to be a single line in the “.tex” file. This would preferably be done in a way that doesn’t wrap equations.

    visual-line-mode wraps at window width, that is too wide. I need something that wraps lines and limits their width to 80 or so characters. Just like fill-paragraph would normally do, but without actually breaking the lines in the file.

  2. I can manually break the line after each sentence, but it would be highly preferable if I could configure fill-paragraph (or maybe even auto-fill-mode) to put one sentence per line as well.
11
  • 1
    What kind of improvement/automation are you after exactly ? Do you want to know how to edit effectively in files like this ?
    – Rangi Lin
    Sep 29, 2014 at 10:16
  • @RangiLin Yes. The first point I mentioned is the most important thing for me. But anything else to make this more effective is welcome.
    – Malabarba
    Sep 29, 2014 at 10:21
  • The description in first point looks like visual-line-mode. But in addition to that line wrapping, you also need to auto insert a newline character after each sentence too, correct? Sep 29, 2014 at 10:23
  • @kaushalmodi Yes, but the newline after each sentence is real, it should be in the file. The problem with visual line mode is that it's just too wide by default. If there's a way to reduce it, it'd be great.
    – Malabarba
    Sep 29, 2014 at 10:26
  • @Malabarba: Do you know why? To me, it's the most useful wrapping mode by far... Sep 30, 2014 at 17:17

5 Answers 5

12

If you just want something like visual-line-mode but configurable, you can try longlines-mode which is what I use for most of my prose. longlines-mode wraps your text similarly to visual-line-mode with the width configured by fill-column.

Here's a screenshot with fill-column set to 70 (the window actually extends even more to the right).

An example of longlines-mode wrapping text.

Configuring fill-paragraph would be neat, but I'm not sure how to do it. Instead, here's a reasonable temporary hack: make your . character electric in TeX mode, inserting a newline. This just involves rebinding it in whatever the appropriate mode hook is:

(defun my-electric-dot ()
  (interactive)
  (insert ".\n"))
(defun my-tex-hook ()
  (local-set-key (kbd ".") 'my-electric-dot))
(add-hook 'TeX-mode-hook 'my-tex-hook)
7
  • 1
    Thanks a lot for pointing out longlines-mode! I managed to get it to not wrap equations and even fix the look of indented lines. Here is the gist gist.github.com/c532f77144ddf86b4ea4.git
    – Malabarba
    Sep 30, 2014 at 10:23
  • @Malabarba: Cool. I'll probably use some of those changes myself! Your link doesn't work properly though; here's a web-friendly version: gist.github.com/Bruce-Connor/c532f77144ddf86b4ea4 Sep 30, 2014 at 10:45
  • Thanks. Also, forgot to mention, that advice uses a function from the latex-extra package.
    – Malabarba
    Sep 30, 2014 at 10:53
  • By the way, it's worth noting that longlines-mode is marked as obsolete in 24.4 (not that it has an equivalent alternative),
    – Malabarba
    Sep 30, 2014 at 13:33
  • 2
    The electric dot isn't going to work well because dots are not just used to end sentences but also for all kinds of other purposes. It would be better to replace a dot followed by two spaces by a dot followed by a newline.
    – tmalsburg
    Jan 7, 2015 at 11:19
14

For (1), I would use an enlarged margin, so that visual-line-mode wraps lines at the desired fill-column. This will affect both text lines and equations, though.

As for (2), one can define a custom filling command to be bound to M-q and correctly fill paragraphs. I haven't yet managed to write a command with the correct behaviour for auto-filling.

Wrapping this all in a minor mode could look like the following. It is not very beautiful code, but should work in most cases. (I have had the unfill-paragraph function in my init.el for quite some time without noticing problems).

(define-minor-mode ospl-mode
  "One Sentence Per Line"
  :init-value nil
  :lighter " ospl"
  :keymap (let ((map (make-sparse-keymap)))
            (define-key map (kbd "M-q") 'ospl/fill-paragraph)
            map)

  (if ospl-mode
      (progn
        (visual-line-mode 1)
        (setq right-margin-width (- (window-body-width) fill-column)))
    (visual-line-mode -1)
    (setq right-margin-width 0))

  ;; Account for new margin width
  (set-window-buffer (selected-window) (current-buffer)))


(defun ospl/unfill-paragraph ()
  "Unfill the paragraph at point.

This repeatedly calls `join-line' until the whole paragraph does
not contain hard line breaks any more."
  (interactive)
  (forward-paragraph 1)
  (forward-paragraph -1)
  (while (looking-at paragraph-start)
    (forward-line 1))
  (let ((beg (point)))
    (forward-paragraph 1)
    (backward-char 1)
    (while (> (point) beg)
      (join-line)
      (beginning-of-line))))


(defun ospl/fill-paragraph ()
  "Fill the current paragraph until there is one sentence per line.

This unfills the paragraph, and places hard line breaks after each sentence."
  (interactive)
  (save-excursion
    (fill-paragraph)         ; takes care of putting 2 spaces if needed
    (ospl/unfill-paragraph)  ; remove hard line breaks

    ;; insert line breaks again
    (let ((end-of-paragraph (make-marker)))
      (save-excursion
        (forward-paragraph)
        (backward-sentence)
        (forward-sentence)
        (set-marker end-of-paragraph (point)))
      (forward-sentence) 
      (while (< (point) end-of-paragraph)
        (just-one-space)
        (delete-backward-char 1)
        (newline)
        (forward-sentence))
      (set-marker end-of-paragraph nil)))) 
9
  • The paragraph filling works great, I wish I could accept two answers. Just replace unfill-paragraph with ospl/unfill-paragraph. The margins also work, but indented text looks bad and they also wrap equations, whereas I managed to hack the longlines method below fix these two problems.
    – Malabarba
    Sep 30, 2014 at 10:15
  • Fixed, thanks. As I said, I've had unfill-paragraph (unprefixed) in my init.el for a long time. I just prefixed it yesterday for consistency and introduced a bug.... Sep 30, 2014 at 11:55
  • Yeah, I figured it was something like that. I also realised we can probably unfill paragraph by just doing something like (let ((fill-column 1000000)) (fill-pragraph)). Haven't tested it yet though.
    – Malabarba
    Sep 30, 2014 at 13:15
  • Yep, such a solution works. I just don't like having magic constants (but my code is not very beautiful either, so one could argue which is better...) Sep 30, 2014 at 15:16
  • 1
    Love this solution. Is there a simple way to avoid breaking commented lines into multiple lines?
    – Ramprasad
    Jul 28, 2015 at 12:38
9

Would your version-control issues be avoided/resolved if you use git diff --color-words or latexdiff? Then you can look at changed words.

1
  • 2
    Coloring words is hepful indeed! But I still need the olps approach to help avoid conflicts when merging other people's contributions and when reverting old commits.
    – Malabarba
    Sep 30, 2014 at 9:16
2

One way of improving this that I have used (at times) for several years is to display sentences with line breaks as flowing after each other by folding the line breaks using the facilities of tex-fold (a part of AUCTeX).

This means that this

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Mauris pellentesque fringilla justo, quis dapibus velit tincidunt quis?
Quisque varius ligula arcu, ut imperdiet risus maximus nec.

is folded to

Lorem ipsum dolor sit amet, consectetur adipiscing elit⁎ Mauris pellentesque fringilla justo, quis dapibus velit tincidunt quis❓  Quisque varius ligula arcu, ut imperdiet risus maximus nec⁎

I've recently put this together as a minor mode in a package. Perhaps someone else will also find this useful: https://github.com/andersjohansson/tex-fold-linebreaks

1

Jan Seeger has made Twauctex. One of the features it provides is

Enable one-sentence-per-line mode.

It says:

Usage

Simply write your latex as you would normally. twauctex will take care of breaking the line whenever you enter a space after a sentence end. If the standard settings do not agree with you, use (customize-group 'twauctex), and you can customize the builtin configuration.

At the time of writing this, the package is not available on MELPA. You need to following installation instructions as provided on the GitHub repo page of Twauctex.

1
  • 1
    Thanks! Great find.
    – ayman
    Jan 10, 2022 at 6:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.