0

I don't want VIM to automatically wrap text, so setting textwidth is not a solution to this problem.

This comment gives a useful outline, but I'm not really sure how to go about doing this. My first naive, sanity-check attempt is:

function FormatExpr()
    normal gw
endfunction
set formatexpr=FormatExpr()

... Which I would expect to just invoke gw on a paragraph I select, but the text is left totally unchanged. In fact, it doesn't seem like any alterations I make to formatexpr have any affect on gq. :help formatexpr says:

Expression which is evaluated to format a range of lines for the |gq| operator or automatic formatting (see 'formatoptions'). When this option is empty 'formatprg' is used.

But doesn't give me an idea of what that expression is supposed to be. I've also tried, for example %s/foo/bar/g, to see if gq will replace all instances of "foo" with "bar", but that didn't work either.

Ideally, I would like something like this to work:

function FormatExpr()
    let stored_textwidth = textwidth
    set textwidth = 100
    normal gq
    set textwidth = stored_textwidth
endfunction

I suspect this is a trivial problem—but I'm pretty ignorant regarding things like formatexpr.

2 Answers 2

0

I suggest manipulating formatoptions and also use textwidth, like

:set fo-=t
:set tw=100

In this way, you wont get an automatic line break in insert mode even if you've typed a line longer than 100 chars. But manually wrapping lines via gq still works.

See :help fo-table. You may also use the l option for formatoptions, or naively :set fo=.

0

:help 'formatexpr' doesn't stop at:

Expression which is evaluated to format a range of lines for the |gq| operator or automatic formatting (see 'formatoptions'). When this option is empty 'formatprg' is used.

If you read it entirely, the key takeaways are:

  • that v:lnum is the line where the area to format starts,
  • that v:count is the number of lines to be formatted,
  • that you must return 0 to prevent Vim from using its internal mechanism.

With that information, we can start experimenting:

function! FormatExpr()
    execute v:lnum .. ',+' .. (v:count - 1) .. 'left'
    return 0
endfunction

where we build a range for :help :left out of v:lnum and v:count. Supposing the area we want to format starts at line 4 and spans 10 lines, we should get the following:

:4,+9left

We must subtract 1 to v:count because it represents the total number of lines to be formatted, while we are interested in how many lines we must cover in addition to the first line.

This works as intended so let's go ahead with the function as you envisioned it:

function! FormatExpr()
    let stored_textwidth = &l:textwidth
    let &l:textwidth = 100
    execute v:lnum .. ',+' .. (v:count - 1) .. 'normal gw'
    let &l:textwidth = stored_textwidth
    return 0
endfunction

which does… nothing.

The problem with this approach is that gw and gq are operators, that do nothing on their own. Since :normal gw does nothing, we would either need to:

  • make a visual selection first, and then do gw,
  • or do gw<motion>.

We will go with the latter because it seems simpler:

function! FormatExpr()
    let stored_textwidth = &l:textwidth
    let &l:textwidth = 100
    execute 'normal ' .. v:lnum .. 'Ggw' .. (v:count - 1) .. 'j'
    let &l:textwidth = stored_textwidth
    return 0
endfunction

where we build a proper Ex command from the variables exposed by Vim. Supposing the same area as above, we should get the following:

:normal 4Ggw9j
  • 4G moves the cursor to line 4,
  • gw9j does gw on the current line and the 9 lines below.

Your Answer

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

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