开发者

Using Vim, isn't there a more efficient way to format LaTeX paragraphs according to this best practice?

The best practice mentioned in the title is the one suggested by Uri:

When writing paragraphs, start each sentence at the beginning of a line, and if it spills over, each subsequent line is tabbed.

I use gVim with Vim-LaTeX, which comes with an indent/tex.vim file, to edit LaTeX files. The way I currently implement the practice mentioned above is as follows:

  1. I :set textwidth=79 to automatically break lines before they become too long.
  2. I manually hit Enter after I finish inserting each sentence.
  3. If I'm done with revising and editing a sentence, I manually shift any spillovers using >>, prefixing it with a count if necessary.

Occasionally, that last step will make one or more spillovers go over the maximum line width. In this case, I

  1. gqq the faulty line.
  2. J my way through to the end of the sentence.
  3. repeat steps 1 and 2 as n开发者_高级运维ecessary.

As you can imagine, this can become tedious. Isn't there a more efficient way to achieve the same result? Ultimately, I want to be able to write the sentences without worrying about their format, and then use gqap, or gqip, to automatically produce the result that I currently produce manually.

To do that, I suspect that I will need to write a formatexpr of my own, but I'm not sure how to proceed. I have found a number of plugins, Latex Text Formatter and Text (Especially LaTeX) Formatter, and a tip, but none of them seem to suit my needs, and I'm not sure how to modify them to do so.


I may well be oversimplifying the problem, but does this mapping do what you want?

nnoremap \z (j>>gq)

So pressing \z in normal mode will do the following: From the cursor position, jump to the start of the sentence. Then go to the next line and indent it. Then reformat from this line to the end of the sentence. Reformatting sentence-wise is the way to go, rather than reformatting each line individually, as your method seems to do.

Of course you can use an insert-mode mapping if you prefer, or even try redefining the behaviour of the Enter key to do this automatically (although I don't know if this will have unintended consequences...).


One way to do this is not by actually breaking the lines in the file but instead doing the following:

set wrap linebreak
let &showbreak='===>  '

The wrap option makes long lines wrap instead of extending off the screen and linebreak makes the line breaks happen only at characters specified in the breakat option.

You can set showbreak to anything that is pleasing to your eye. My favorite when I'm using vim where unicode characters work right is:

let &showbreak="\u21aa "

This puts a ↪ symbol at the beginning of each wrapped line.

I also like to turn on line numbers (set number) to give another indicator of what the actual lines in the file are.

To make navigating the file easier you might want to use

noremap j gj
noremap k gk
noremap gj j
noremap gk k

This makes k and j move up and down by displayed lines not file lines. To affect the cursor keys as well replace k with <Up> and j with <Down>.


One option that takes different tack than tabbing subsequent lines would be to set the w flag in formatoptions. When you do that it changes the way Vim identifies new paragraphs, and lines ending in a space are understood to continue on a new line as part of same paragraph. See :h fo-table.

If you set the w flag and enter your text so that continued sentence lines are the only ones ending in a space (and abandon completely practice of entering tabs at beginning of any text lines) then I think you should be able to use gqap to format text paragraphs as you want. To get visual cues to logical structure you can then set listchars to display the eol (i.e., <cr>) character and set different highlightings for <space><cr> and for <non-space><cr> so that sentence/paragraph ends are easily spotted.

Another benefit of this method is that you can just type your text naturally and let line breaks be entered automatically by textwidth setting. (Just make sure that LaTeX formatting lines don't break automatically in textwidth area; you want them to have non-space char as last char in line.)


That tip also caught my eye. Here's how I solved the problem (a diff of the changed lines in tex.vim):

*** tex.vim.old 2011-08-16 08:26:56.845046457 +0200
--- tex.vim 2011-08-16 08:59:14.736306930 +0200
***************
*** 90,95 ****
--- 90,96 ----
    " LH modification : \begin does not always start a line
    if line =~ '\\begin{\(.*\)}'  && line !~ 'verbatim'
          \ && line !~ 'document'
+       \ || line =~ '^\s*[A-Z].*[a-zA-Z0-9,]\s*$\C'

      let ind = ind + &sw

***************
*** 105,110 ****
--- 106,112 ----
    " Subtract a 'shiftwidth' when an environment ends
    if cline =~ '^\s*\\end' && cline !~ 'verbatim'
          \&& cline !~ 'document'
+       \|| line =~ '\.\s*$'

      if g:tex_indent_items == 1
        " Remove another sw for item-environments

Basically it indents new lines when the previous line starts with a capital letter and ends with a letter, digit, or comma, and "unindents" new lines with the previous line ends with a period.

There is definitely room for improvement (better criteria) but for me it works all right so far.


I find the suggestion from @kev (and the people commented) at this post to be the most satisfying.

There, it is explained that by setting

:set fo+=n

followed by either

:let &flp='^\s*\\(item\|end\|begin)*\s*'

or

:let &l:flp='^\s*\\\(item\|end\|begin\)\s*'

lets you type gggqG to reformat the entire file.


I use the vim-textobj-usr plugin to define a "LaTeXPar" text-object. Then I can use gwal to format.

There is already a vim-textobj-latex plugin, but the biggest text-object it defines is "environment". This is not what I (and OP) want.

A "LaTeXPar" is delimited by

  • an empty line
  • a line begin with \[, \], \begin, \end, }
  • a line end with {

this is adapted to my writing habit: I always have an empty line after \section, always use \[ \] on a single line, and so on. You can easily write one for yourself.

Here is the relative part in my ~/.vim/ftplugin/tex.vim.

call textobj#user#plugin('latexpar', {
            \   'par': {
            \     'select-a-function': 'LaTeXPar',
            \     'select-a': 'al',
            \   },
            \ })

function! LaTeXPar()
    let pattern='\v^$|^\s*(\\\[|\\\]|\\begin|\\end|\})|\{$'
    if search(pattern,"bW")
        normal! j
    else
        normal! gg
    endif
    let head_pos = getpos('.')
    if search(pattern,"W")
        normal! k
    else
        normal! G
    endif
    let tail_pos = getpos('.')
    " echo head_pos[2]
    " echo tail_pos[2]
    return ["V", head_pos, tail_pos]
endfunction
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜