Intelligent paragraph reflowing in vim?

I'm not sure whether this is an appropriate question for tex.SE. If you think questions like this should not be asked here, please voice you concern. If necessary I'll open a question on meta.

For readability I like to keep line lengths in my source files at about 80 characters. Vim has the nice shortcut gqap that reflows the current paragraph to fit within 80 characters without wasting space with lines that are too short. It even keeps indentation. Unfortunately it considers paragraphs to be marked by empty lines and considers everything that is not separated by an empty line to be in the same paragraph. In particular any equations (started with $ or \begin{...}) are always considered to be part of the paragraph and reflowed. Is there any way to have vim handle LaTeX syntax more intelligently in this respect? Are there any other text editors which can to that? (I know that I can highlight only the text and then use gq, but if possible I'd like to have a single command to reflow a paragraph without the need to manually mark what a paragraph is.) • If I understood correctly, does gqq do what you need? (or Vgq). It's line-wise, ie. if you type-in text without manual line-breaks. May 25, 2011 at 3:11 • Emacs does this out-of-the-proverbial-box ;-D (although, no TeX–Emacs experience is complete without AUCTeX.) (Edit: didn't realize how old this post was—must have been bumped by an edit—but Emacs is definitely "another editor".) Aug 14, 2013 at 3:42 • @SeanAllred: Actually the question is so old that I stopped doing the 80 characters/line thing a long time ago (I now find one sentence per line much more useful for editing). Aug 14, 2013 at 15:20 • @Caramidir, I'm curious then how you've got that working in Vim, because I'd like to do the same :) Mar 8, 2018 at 15:30 • @Timtro: Nowadays I do a sentence per line and don't reflow. I find that much easier to handle with version control systems. Mar 13, 2018 at 17:13 7 Answers I have the following function in my VIM/ftplugin/context.vim file to format ConTeXt paragraphs (same as LaTeX: the environments are enclosed in \start... and \stop... instead of \begin{...} and \end{...}. It should be easy to adapt this to LaTeX (In fact, I think that I copied it originally from someone who had written it for LaTeX and adapted it to ConTeXt). " Reformat lines (getting the spacing correct) {{{ fun! TeX_fmt() if (getline(".") != "") let save_cursor = getpos(".") let op_wrapscan = &wrapscan set nowrapscan let par_begin = '^$$%D$$\=\s*$$\|\\start\|\\stop\|\\Start\|\\Stop\|\\\(sub$$*section\>\|\\item\>\|\\NC\>\|\\blank\>\|\\noindent\>\)' let par_end = '^$$%D$$\=\s*$$\|\\start\|\\stop\|\\Start\|\\Stop\|\\place\|\\\(sub$$*section\>\|\\item\>\|\\NC\>\|\\blank\>\)' try exe '?'.par_begin.'?+' catch /E384/ 1 endtry norm V try exe '/'.par_end.'/-' catch /E385/  endtry norm gq let &wrapscan = op_wrapscan call setpos('.', save_cursor) endif endfun nmap Q :call TeX_fmt()<CR>  • Thank you, this works really well. For LaTeX one needs only needs to replace \\start\|\\stop\|\\Start\|\\Stop\| by |\\begin\|\\end\|\\[\|\$\|. (Also the {{{ should be ended by a " }}} after the last line.) Aug 11, 2010 at 17:35
• I'm not having success with the pattern \$ and \$. In my case, Vim seems to simply ignore display math that starts and ends with $ and $. I'm no expert in Vim regular expressions but I found that escaping the square brackets does the trick, i.e., replacing \$ with \\\[ and \$ with \\\]. Jan 2, 2012 at 22:49

I know it's against policy to answer commenting on other answers, but in this case -- given I lack the 50 reputation needed to comment directly on the relevant answer -- I think it's worth it.

The function provided by Aditya functions perfectly for LaTeX, mutatis mutandis, except for one detail: often after beginning an environment, or a section, the very next line will be a \label{}. The original TeX_fmt() function wrongly considers this line to be a part of the paragraph. To fix this, modify the line that sets par_begin, to this:

let par_begin = '^$$%D$$\=\s*$$\|\\label\|\\begin\|\\end\|\$\|\$\|\\\(sub$$*section\>\|\\item\>\|\\NC\>\|\\blank\>\|\\noindent\>\)'


Basically, you add a \label before the \begin.

Profit!!

• This would be too long for a comment as it stands, and extends functionality in some sense. Nice catch!! Aug 14, 2013 at 3:47
• Works great, thanks! Nov 20, 2020 at 15:46

The following solution only applies to paragraph formatting, it will properly work depending on the LaTeX styling settings.

Another possible solution would be to set a hard wrap of 80 characters.

http://vimcasts.org/episodes/hard-wrapping-text/

formatoptions:

t - Auto-wrap text using textwidth

c - Auto-wrap comments using textwidth, inserting the current comment leader automatically.

a - Automatic formatting of paragraphs.

Here are some of the commands to set it up:

:set formatoptions=tc
:set fo+=a
:set textwidth=80


Tip: Use the autocmd or ftplugin folder to setup these settings automatically according to filetype. Run help: ftplugin in vim for more info.

http://vimdoc.sourceforge.net/htmldoc/change.html#fo-table

• With this method, you can't end lines with a comment. Dec 13, 2012 at 16:12

Sorry to barge in, but just don't. I'll give several reasons, each one of them good enough for me on its own.

First, I got into the habit of splitting source lines at punctuation, and otherwise to keep a (vaguely defined) phrase/idea together on a line. I.e., keep the article and the subject together, etc. And cut lines into short(ish) pieces when writing.

• It makes searching for mistakes, like "an wrong article" or repeated repeated words easy
• Most of the time editing gets to be shuffling lines around, erasing/adding lines. This is natural with the editor's commands, whatever it might be.
• Last in my personal history, but overwhelming today: by the second point above, differences from one version to the next will be restricted to only the "real" changes, no "this line and most of the rest of the paragraph got reflowed" noise because a word got added. This makes version control keep smaller differences (nice), but more importantly makes differences understandable.

But that can't be automated in any reasonable way (unless you want to add full text understanding to your editor, and that is definitely emacs' territory, not vi's... ;-)

• I downvoted because of the complete dismissal of OPs approach. This isn't a kind of issue on which the OP is doing something obviously wrong, and so they need to throw away one of the premises altogether. There are a ton of reasons for why one might prefer "fill at X columns". Sure it might look like a complete waste of time to some people — and it probably is to them — but people end up with very idiosyncratic setups. And I mean (as a separate example), people are still arguing about using tabs or not to this day! ¶ But the arguments you give are largely solid, in themselves. Dec 17, 2016 at 20:56
• @Guildenstern: vonbrand's approach is what I am actually doing now (and have been doing for a while -- this question is more than 6 years old...). Dec 19, 2016 at 20:39
• @Caramdir Yes, and I saw that. But SE questions and answers are a common good and not just intended for the benefit of the asker. So I was replying with the other people that were having the same issues as you originally had, in mind (people that come here from Google etc.). Dec 20, 2016 at 12:46

I came into the same problem. Here is solution that worked for me. I've wrote an external script to handle the formatting of latex text (https://github.com/elmanuelito/par-latex). I usually reformat the entire document at once, but it can be done paragraph-wise.

Example of usage in vim:

• Select some text (e.g. Vj or ggVG)
• type ":!par-latex" (vim command-line looks like: '<,'>!par-latex)
• type enter

You can customize the script (it's based on some regexp) and change some parameters at the beginning.

To save you a bit time, this is aditiya's code for LaTeX.

" Reformat lines (getting the spacing correct) {{{
fun! TeX_fmt()
if (getline(".") != "")
let save_cursor = getpos(".")
let op_wrapscan = &wrapscan
set nowrapscan
let par_begin = '^$$%D$$\=\s*$$\|\\begin\|\\end\|\$\|\$\|\\\(sub$$*section\>\|\\item\>\|\\NC\>\|\\blank\>\|\\noindent\>\)'
let par_end   = '^$$%D$$\=\s*$$\|\\begin\|\\end\|\$\|\$\|\\place\|\\\(sub$$*section\>\|\\item\>\|\\NC\>\|\\blank\>\)'
try
exe '?'.par_begin.'?+'
catch /E384/
1
endtry
norm V
try
exe '/'.par_end.'/-'
catch /E385/
\$
endtry
norm gq
let &wrapscan = op_wrapscan
call setpos('.', save_cursor)
endif
endfun

nmap Q :call TeX_fmt()<CR>
" }}}


I wrote a very customizable plugin to do this. It lets you specify in which environments you would like the text to be reflowed, whether you'd like a line ending in \\ to join the line following it, etc.

https://github.com/engeljh/vim-latexfmt