Tuesday, March 26, 2019

Re: vim-xml-ftplugin vs. formatoptions

On Di, 26 Mär 2019, Rob Foehl wrote:

> I've noticed that formatoptions+=c and a suitable textwidth value has no
> effect with xml/xslt filetypes, and found this in
> $VIMRUNTIME/autoload/xmlformat.vim:
>
> func! xmlformat#Format()
> " only allow reformatting through the gq command
> " (e.g. Vim is in normal mode)
> if mode() != 'n'
> " do not fall back to internal formatting
> return 0
> endif
> [...]
>
> This is as shipped with 8.1.998, although the upstream version appears to be
> identical at the moment. Kind of surprised at that -- is there some
> underlying reason to disable auto formatting for XML filetypes?
>
> Removing that mode() test definitely causes problems, figured I'd ask here
> before digging any further...

Maintainer here: Yes, there were some serious problems with the way
formatexpressions are evaluated, therefore I explicitly disabled it.

This is from a mail to Bram about the topic (sorry for disclosure):

Also, it looks like the doc patch has never been included, so I keep it
here for reference. (CC'ing Bram, who might want to include the doc
patch):

On Sa, 12 Mai 2018, Bram Moolenaar wrote:
> Christian wrote:
> > However when playing around a bit with formatexpession in insert mode, I
> > had all kind of strange effects (non-undoable insertions below the
> > current line, kind of a recursive call of the function, etc) so I would
> > actually go so far to discourage calling the function in insert mode (or
> > at least mention that in insert mode the function should fall back to
> > Vims internal formatter by returning non-zero).
> >
> > And in general it feels too limited to be called in insert mode for each
> > character inserted (since you have to be really careful not to overwrite
> > anything unwanted and it is a bit tricky to simply add a line break)
> >
> > Also I think it is hardly possible to make an educated guess what the
> > user actually wants from the single character to be inserted.
> >
[...]
>
> Oh, I didn't mean to include an example of a function, but just when to
> set 'formatexpr' to an existing function. And where to do that. I
> would assume in most cases it would be done in the ftplugin file:
>
> :set formatexpr=xmlformat#Format()
>
> With an explanation of how Vim finds the file that contains the function
> in the autoload directory.

Okay, how about this then:
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index ab820b066..95479fae8 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1445,7 +1445,52 @@ to the name of an external program for Vim to use for text formatting. The
'textwidth' and other options have no effect on formatting by an external
program.

- *right-justify*
+ *format-formatexpr*
+The 'formatexpr' option can be set to a Vim Script function that performs
+reformatting of the buffer. This should usually happen in a |ftplugin|, since
+formatting is highly dependent on the actually used language. It makes sense
+to use an |autoload| script, so the corresponding script is only loaded when
+actually needed and the script should be called <filetype>format.vim.
+
+For example, the xml filetype plugin distributed with Vim in the $VIMRUNTIME
+directory, sets the 'formatexpr' option to: >
+
+ setlocal formatexpr=xmlformat#Format()
+
+That means, you will find the corresponding script in the directory
+`$VIMRUNTIME/autoload/xmlformat.vim`
+
+Here is an example script that removes trailing whitespace from the selected text: >
+
+ func! format#Format()
+ " only reformat on explicit gq command
+ if mode() != 'n'
+ " fall back to Vims internal reformatting
+ return 1
+ endif
+ let lines = getline(v:lnum, v:lnum + v:count - 1)
+ call map(lines, {key, val -> substitute(val, '\s\+$', '', 'g')})
+ call setline('.', lines)
+
+ " do not run internal formatter!
+ return 0
+ endfunc
+ setl formatexpr=format#Format()
+>
+Note: this function explicitly returns non-zero when called from insert mode
+(which basically means, text is inserted beyond the 'textwidth' limit). This
+causes Vim to fall back to reformat the text by using the internal formatter.
+
+However, if the |gq| command is used to reformat the text, the function
+will receive the selected lines, trim trailing whitespace from those lines and
+put them back in place. If you are going to split single lines into multiple
+lines, be careful not to overwrite anything.
+
+If you want to allow reformatting of text from insert or replace mode, one has
+to be very careful, because the function might be called recursively. For
+debugging it helps to set the 'debug' option.
+
+ *right-justify*
There is no command in Vim to right justify text. You can do it with
an external command, like "par" (e.g.: "!}par" to format until the end of the
paragraph) or set 'formatprg' to "par".


> Fixing the problems in Insert mode is a different issue.

Another inconsistency: The script will be called for every (normal)
typed character that is typed in insert mode (when beyond the textwidth
limit) but not when pressing enter. I am just mentioning it. It seems so
seldomly used, that I think it might be enough to document that there
might still be bugs and discourage using it.

Best,
Christian

--
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments: