6

I'm looking for a way to determine the filetype of a file in vim and set the syntax highlighting based on the filetype. The only catch is I cannot use the file extension for determining the filetype.

This is my scenario: I use vimdiff or gvimdiff as my P4DIFF tool, which shows the changes between the files in my local copy and the ones from the perforce server. Perforce seems to bring in the files from the perforce server into the /tmp directory and uses the PID to name the file, for example:

/tmp/tmp.24673.23

This was for a C++ source file.

The most frequent filetypes I encounter in the perforce repository are C/C++ sources and header files, Makefiles, python scripts, perl scripts, ruby scripts, and tcl scripts.

  • I've looked into using modeline, but most of the sources in our tree do not have this information embedded in the file.

  • This post mentions about a possible approach to search and identify a magic pattern. I could not find any consistent magic pattern that I could get a high success rate with.

  • Tried using the file binary on my linux box to see what results I get. It seems to identify C/C++ sources well, but fails for Makefiles and even python scripts (which don't have the hashbang)

One good thing is that, among the 2 files that are compared, the file on the right is from my local copy and hence has the correct file name with extension, thereby syntax highlighting is enabled correctly for the file on the right.

Is there a way I could leverage this to set the same syntax highlighting for the file displayed on the left ?

Any alternate solutions to this problem are also welcome.

Community
  • 1
  • 1
Tuxdude
  • 47,485
  • 15
  • 109
  • 110

2 Answers2

6

This was an interesting puzzle. :)

aug SmartDiffType
  au!
  au VimEnter * :if &diff && len(&ft) | call setwinvar(2/winnr(),'&ft',&ft) | elseif &diff | let &ft=getwinvar(2/winnr(),'&ft') | endif
aug END

Notes:

  • Of the 4 lines above, you only need the au VimEnter line, but it is generally a good practice to put autocommands in some autocommand group with a reset (au!) at the top.
  • Autocommand on VimEnter because otherwise diff or the windows are not properly intialized yet
  • vimdiff might have been triggered with the old file on the right or the left of the split, so we consider both cases.
  • The 2/winnr() is a math trick to flip between 1 and 2 (2/2 = 1, 2/1=2)
Daan Bakker
  • 6,122
  • 3
  • 24
  • 23
  • Cool! This works out really nice... Just moved the if-endif into a function and replaced the command with a call to the function. :) – Tuxdude Mar 12 '13 at 23:31
3

Assuming that you have open only the 2 splits and the split on the left is your local file you can do the following

:windo let &ft = getwinvar(1, '&ft')

This will set the filetype to the value of the top left most window for all windows.

For more help see:

:h :windo
:h 'ft'
:h getwinvar(
Peter Rincker
  • 43,539
  • 9
  • 74
  • 101
  • Thanks, it works. I had to use `windo let &ft = getwinvar(2, '&ft')` since the right window had the correct file type. Is there a way to add it to `.vimrc` so that for every vimdiff, it does this automatically ? Merely adding the `windo` command to .vimrc did not do the trick. I'm guessing it gets overriden later may be. – Tuxdude Mar 12 '13 at 21:39
  • Although I am sure such an `autocmd` could be created, I feel like the simplest solution would be to create a custom command: `command! -bar -nargs=0 SameFiletype exe 'windo set ft='.&ft` Add this to your `~/.vimrc` file. Next time the situation arises move to the buffer with the correct filetype and execute `:SameFiletype` – Peter Rincker Mar 12 '13 at 22:02
  • Thanks, that sounds like a reasonable approach :) – Tuxdude Mar 12 '13 at 22:04