26

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.
  • 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 '14 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 '14 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? – Kaushal Modi Sep 29 '14 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 '14 at 10:26
  • @Malabarba: Do you know why? To me, it's the most useful wrapping mode by far... – Tikhon Jelvis Sep 30 '14 at 17:17
11

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)
  • 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 '14 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 – Tikhon Jelvis Sep 30 '14 at 10:45
  • Thanks. Also, forgot to mention, that advice uses a function from the latex-extra package. – Malabarba Sep 30 '14 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 '14 at 13:33
  • 1
    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 '15 at 11:19
13

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)))) 
  • 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 '14 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.... – Francesco Sep 30 '14 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 '14 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...) – Francesco Sep 30 '14 at 15:16
  • 1
    Love this solution. Is there a simple way to avoid breaking commented lines into multiple lines? – Ramprasad Jul 28 '15 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.

  • 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 '14 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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