Reset did_filetype() manually?

28 views
Skip to first unread message

ben.k...@gmail.com

unread,
Jun 30, 2021, 5:33:00 PM6/30/21
to vim_dev
TL;DR, I need to reset did_filetype() in the middle of filetype-detection autocommands. I have a hack that works, but is inefficient (`new | bdelete`). Is there another way?

---

I am in a unique situation, trying to develop a plugin for Pollen [1]. It is similar to a pre-processor, so needs to merge the underlying syntax with it's own.

I think the simplest path forward is a "clever" syntax file that augments whatever syntax already exists, using, e.g., `set filetype=markdown.pollen`.

The difficult bit so far is filetype-detection. I'm using a trick [2] to try and get the filetype set. For example, in a directory on the runtimepath I have ftdetect/pollen.vim with (simplified)

```
function! PollenDetectFiletype(filename) abort
  " HACK: new file resets did_filetype()
  " ignore old filetype, probably pascal or some junk
  new | bdelete
  let out_ext = fnamemodify(a:filename, ':r')
  " original filetype detection
  execute 'doautocmd filetypedetect BufRead' fnameescape(out_ext)
  " add pollen at end, taking care to only add it once
  let &l:filetype = substitute(&filetype, '\C\.\<pollen\>', '', 'g') . '.pollen'
endfunction

autocmd BufNewFile,BufRead *.pp call PollenDetectFiletype(expand("<afile>"))
```

When I edit a file `foo.md.pp`, the filetype is `markdown.pollen`. But see the HACK.

Because the `*.pp` extension causes `setf pascal` to run from `$VIMRUNTIME`, the `doautocommand` line (which correctly triggers `setf markdown`, in the example) is effectively neutralized: `did_filetype()` is still TRUE. My HACK exploits the fact that editing a new file resets the counter (`:h did_filetype`), but seems grossly inefficient.

Gary Johnson

unread,
Jun 30, 2021, 8:39:45 PM6/30/21
to vim_dev
On 2021-06-30, ben.k...@gmail.com wrote:
> TL;DR, I need to reset did_filetype() in the middle of filetype-detection
> autocommands. I have a hack that works, but is inefficient (`new | bdelete`).
> Is there another way?

See

:help :setf

and see if the FALLBACK argument does what you want.

For an example of its use, see $VIMRUNTIME/filetype.vim.

HTH,
Gary

ben.k...@gmail.com

unread,
Jul 1, 2021, 9:47:35 AM7/1/21
to vim_dev
> See
>
> :help :setf
>
> and see if the FALLBACK argument does what you want.

Not quite: the original filetype is set using :setf pascal; I'm trying to
override this in the same sequence of commands.

Here is perhaps a clearer picture:

+ vim file.md.pp
|
+++ filetype detection autocommands trigger
  |
  + $VIMRUNTIME *.pp => :setf pascal (did_filetype() now true)
  |
  +++ my plugin *.pp => doautocommand … file.md
    |
    + $VIMRUNTIME *.md => :setf markdown
      but did_filetype() was still true, so this has no effect.

Perhaps I've misunderstood your comment, though. Changing the distribution's setf pascal to setf FALLBACK pascal would work, but that seems like it would require more discussion.

Gary Johnson

unread,
Jul 1, 2021, 11:43:28 AM7/1/21
to vim_dev
On 2021-07-01, ben.k...@gmail.com wrote:
> > See
> >
> > :help :setf
> >
> > and see if the FALLBACK argument does what you want.
>
> Not quite: the original filetype is set using :setf pascal; I'm trying to
> override this in the same sequence of commands.
>
> Here is perhaps a clearer picture:
>
> + vim file.md.pp
> |
> +++ filetype detection autocommands trigger
> |
> + $VIMRUNTIME *.pp => :setf pascal (did_filetype() now true)
> |
> +++ my plugin *.pp => doautocommand … file.md
> |
> + $VIMRUNTIME *.md => :setf markdown
> but did_filetype() was still true, so this has no effect.
>
> Perhaps I've misunderstood your comment, though. Changing the distribution's
> setf pascal to setf FALLBACK pascal would work, but that seems like it would
> require more discussion.

You can override or preempt what the distribution does in
$VIMRUNTIME/filetype.vim by creating your own ~/.vim/filetype.vim
file (or ~/vimfiles/filetype.vim on Windows). That might work
better than trying to reset did_filetype(). You could treat *.md.pp
files specially that way. Or do your own extended handling of *.pp
files.

This is discussed in the help section starting with

:help new-filetype

The answer may be as simple as using ":set ft" instead of ":setf" in
your plugin. You can also do things like put ":runtime
ftplugin/markdown.vim" in your ftplugin to source all the
distribution's ftplugin files for your filetype. See, for example:

$VIMRUNTIME/ftplugin/cpp.vim
$VIMRUNTIME/ftplugin/docbk.vim

I don't have a concrete answer because I don't understand exactly
what you're trying to do. Also, I'm no expert in Vim's handling of
filetypes. Generally I've found that Vim has the hooks to do what
you want, but it may take some study and tinkering and rethinking of
your initial solution to get the results you want.

Regards,
Gary

ben.k...@gmail.com

unread,
Jul 1, 2021, 5:54:26 PM7/1/21
to vim_dev
You can override or preempt what the distribution does in
$VIMRUNTIME/filetype.vim by creating your own ~/.vim/filetype.vim
file (or ~/vimfiles/filetype.vim on Windows).

I know that, but I'm writing a plugin. Something that might live, e.g., in ~/.vim/pack/me/opt/pollen/{ftdetect,ftplugin}/pollen.vim.
 
That might work
better than trying to reset did_filetype(). You could treat *.md.pp
files specially that way. Or do your own extended handling of *.pp
files.

It's got to be all *.pp, esp. those with two extensions. 
 
The answer may be as simple as using ":set ft" instead of ":setf" in
your plugin. You can also do things like put ":runtime
ftplugin/markdown.vim" in your ftplugin to source all the
distribution's ftplugin files for your filetype. See, for example:

$VIMRUNTIME/ftplugin/cpp.vim
$VIMRUNTIME/ftplugin/docbk.vim

This won't work without re-inventing all of vim's filetype detection mechanisms, which is what I want to avoid with the execute 'doautocommand …' line. Why? Because the filetype to use heavily depends on the base filename, sans .pp extension.
 
I don't have a concrete answer because I don't understand exactly
what you're trying to do. Also, I'm no expert in Vim's handling of
filetypes. Generally I've found that Vim has the hooks to do what
you want, but it may take some study and tinkering and rethinking of
your initial solution to get the results you want.

My current "hack" works—I just hoped there was a better way. I haven't even noticed any screen issues, since I don't think anything is drawn until after the whole sequence completes. I do wonder if this could disturb window sizing though. 
Reply all
Reply to author
Forward
0 new messages