xref: /vim-8.2.3635/runtime/autoload/dist/ft.vim (revision ca0627df)
1" Vim functions for file type detection
2"
3" Maintainer:	Bram Moolenaar <[email protected]>
4" Last Change:	2020 Aug 17
5
6" These functions are moved here from runtime/filetype.vim to make startup
7" faster.
8
9" Line continuation is used here, remove 'C' from 'cpoptions'
10let s:cpo_save = &cpo
11set cpo&vim
12
13func dist#ft#Check_inp()
14  if getline(1) =~ '^\*'
15    setf abaqus
16  else
17    let n = 1
18    if line("$") > 500
19      let nmax = 500
20    else
21      let nmax = line("$")
22    endif
23    while n <= nmax
24      if getline(n) =~? "^header surface data"
25	setf trasys
26	break
27      endif
28      let n = n + 1
29    endwhile
30  endif
31endfunc
32
33" This function checks for the kind of assembly that is wanted by the user, or
34" can be detected from the first five lines of the file.
35func dist#ft#FTasm()
36  " make sure b:asmsyntax exists
37  if !exists("b:asmsyntax")
38    let b:asmsyntax = ""
39  endif
40
41  if b:asmsyntax == ""
42    call dist#ft#FTasmsyntax()
43  endif
44
45  " if b:asmsyntax still isn't set, default to asmsyntax or GNU
46  if b:asmsyntax == ""
47    if exists("g:asmsyntax")
48      let b:asmsyntax = g:asmsyntax
49    else
50      let b:asmsyntax = "asm"
51    endif
52  endif
53
54  exe "setf " . fnameescape(b:asmsyntax)
55endfunc
56
57func dist#ft#FTasmsyntax()
58  " see if file contains any asmsyntax=foo overrides. If so, change
59  " b:asmsyntax appropriately
60  let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
61	\" ".getline(5)." "
62  let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
63  if match != ''
64    let b:asmsyntax = match
65  elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
66    let b:asmsyntax = "vmasm"
67  endif
68endfunc
69
70" Check if one of the first five lines contains "VB_Name".  In that case it is
71" probably a Visual Basic file.  Otherwise it's assumed to be "alt" filetype.
72func dist#ft#FTVB(alt)
73  if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)'
74    setf vb
75  else
76    exe "setf " . a:alt
77  endif
78endfunc
79
80func dist#ft#FTbtm()
81  if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
82    setf dosbatch
83  else
84    setf btm
85  endif
86endfunc
87
88func dist#ft#BindzoneCheck(default)
89  if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
90    setf bindzone
91  elseif a:default != ''
92    exe 'setf ' . a:default
93  endif
94endfunc
95
96func dist#ft#FTlpc()
97  if exists("g:lpc_syntax_for_c")
98    let lnum = 1
99    while lnum <= 12
100      if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
101	setf lpc
102	return
103      endif
104      let lnum = lnum + 1
105    endwhile
106  endif
107  setf c
108endfunc
109
110func dist#ft#FTheader()
111  if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
112    if exists("g:c_syntax_for_h")
113      setf objc
114    else
115      setf objcpp
116    endif
117  elseif exists("g:c_syntax_for_h")
118    setf c
119  elseif exists("g:ch_syntax_for_h")
120    setf ch
121  else
122    setf cpp
123  endif
124endfunc
125
126" This function checks if one of the first ten lines start with a '@'.  In
127" that case it is probably a change file.
128" If the first line starts with # or ! it's probably a ch file.
129" If a line has "main", "include", "//" or "/*" it's probably ch.
130" Otherwise CHILL is assumed.
131func dist#ft#FTchange()
132  let lnum = 1
133  while lnum <= 10
134    if getline(lnum)[0] == '@'
135      setf change
136      return
137    endif
138    if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
139      setf ch
140      return
141    endif
142    if getline(lnum) =~ "MODULE"
143      setf chill
144      return
145    endif
146    if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
147      setf ch
148      return
149    endif
150    let lnum = lnum + 1
151  endwhile
152  setf chill
153endfunc
154
155func dist#ft#FTent()
156  " This function checks for valid cl syntax in the first five lines.
157  " Look for either an opening comment, '#', or a block start, '{".
158  " If not found, assume SGML.
159  let lnum = 1
160  while lnum < 6
161    let line = getline(lnum)
162    if line =~ '^\s*[#{]'
163      setf cl
164      return
165    elseif line !~ '^\s*$'
166      " Not a blank line, not a comment, and not a block start,
167      " so doesn't look like valid cl code.
168      break
169    endif
170    let lnum = lnum + 1
171  endw
172  setf dtd
173endfunc
174
175func dist#ft#ExCheck()
176  let lines = getline(1, min([line("$"), 100]))
177  if exists('g:filetype_euphoria')
178    exe 'setf ' . g:filetype_euphoria
179  elseif match(lines, '^--\|^ifdef\>\|^include\>') > -1
180    setf euphoria3
181  else
182    setf elixir
183  endif
184endfunc
185
186func dist#ft#EuphoriaCheck()
187  if exists('g:filetype_euphoria')
188    exe 'setf ' . g:filetype_euphoria
189  else
190    setf euphoria3
191  endif
192endfunc
193
194func dist#ft#DtraceCheck()
195  let lines = getline(1, min([line("$"), 100]))
196  if match(lines, '^module\>\|^import\>') > -1
197    " D files often start with a module and/or import statement.
198    setf d
199  elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
200    setf dtrace
201  else
202    setf d
203  endif
204endfunc
205
206func dist#ft#FTe()
207  if exists('g:filetype_euphoria')
208    exe 'setf ' . g:filetype_euphoria
209  else
210    let n = 1
211    while n < 100 && n <= line("$")
212      if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
213	setf specman
214	return
215      endif
216      let n = n + 1
217    endwhile
218    setf eiffel
219  endif
220endfunc
221
222" Distinguish between HTML, XHTML and Django
223func dist#ft#FThtml()
224  let n = 1
225  while n < 10 && n <= line("$")
226    if getline(n) =~ '\<DTD\s\+XHTML\s'
227      setf xhtml
228      return
229    endif
230    if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
231      setf htmldjango
232      return
233    endif
234    let n = n + 1
235  endwhile
236  setf FALLBACK html
237endfunc
238
239" Distinguish between standard IDL and MS-IDL
240func dist#ft#FTidl()
241  let n = 1
242  while n < 50 && n <= line("$")
243    if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
244      setf msidl
245      return
246    endif
247    let n = n + 1
248  endwhile
249  setf idl
250endfunc
251
252" Distinguish between "default" and Cproto prototype file. */
253func dist#ft#ProtoCheck(default)
254  " Cproto files have a comment in the first line and a function prototype in
255  " the second line, it always ends in ";".  Indent files may also have
256  " comments, thus we can't match comments to see the difference.
257  " IDL files can have a single ';' in the second line, require at least one
258  " chacter before the ';'.
259  if getline(2) =~ '.;$'
260    setf cpp
261  else
262    exe 'setf ' . a:default
263  endif
264endfunc
265
266func dist#ft#FTm()
267  if exists("g:filetype_m")
268    exe "setf " . g:filetype_m
269    return
270  endif
271
272  " excluding end(for|function|if|switch|while) common to Murphi
273  let octave_block_terminators = '\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>'
274
275  let n = 1
276  let saw_comment = 0 " Whether we've seen a multiline comment leader.
277  while n < 100
278    let line = getline(n)
279    if line =~ '^\s*/\*'
280      " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
281      " it's either of them yet, but track this as a hint in case we don't see
282      " anything more definitive.
283      let saw_comment = 1
284    endif
285    if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
286      setf objc
287      return
288    endif
289    if line =~ '^\s*\%(#\|%!\)' || line =~ '^\s*unwind_protect\>' ||
290	  \ line =~ '\%(^\|;\)\s*' .. octave_block_terminators
291      setf octave
292      return
293    endif
294    " TODO: could be Matlab or Octave
295    if line =~ '^\s*%'
296      setf matlab
297      return
298    endif
299    if line =~ '^\s*(\*'
300      setf mma
301      return
302    endif
303    if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
304      setf murphi
305      return
306    endif
307    let n = n + 1
308  endwhile
309
310  if saw_comment
311    " We didn't see anything definitive, but this looks like either Objective C
312    " or Murphi based on the comment leader. Assume the former as it is more
313    " common.
314    setf objc
315  else
316    " Default is Matlab
317    setf matlab
318  endif
319endfunc
320
321func dist#ft#FTmms()
322  let n = 1
323  while n < 20
324    let line = getline(n)
325    if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
326      setf mmix
327      return
328    endif
329    if line =~ '^\s*#'
330      setf make
331      return
332    endif
333    let n = n + 1
334  endwhile
335  setf mmix
336endfunc
337
338" This function checks if one of the first five lines start with a dot.  In
339" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
340func dist#ft#FTnroff()
341  if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
342    setf nroff
343    return 1
344  endif
345  return 0
346endfunc
347
348func dist#ft#FTmm()
349  let n = 1
350  while n < 20
351    let line = getline(n)
352    if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
353      setf objcpp
354      return
355    endif
356    let n = n + 1
357  endwhile
358  setf nroff
359endfunc
360
361func dist#ft#FTpl()
362  if exists("g:filetype_pl")
363    exe "setf " . g:filetype_pl
364  else
365    " recognize Prolog by specific text in the first non-empty line
366    " require a blank after the '%' because Perl uses "%list" and "%translate"
367    let l = getline(nextnonblank(1))
368    if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
369      setf prolog
370    else
371      setf perl
372    endif
373  endif
374endfunc
375
376func dist#ft#FTinc()
377  if exists("g:filetype_inc")
378    exe "setf " . g:filetype_inc
379  else
380    let lines = getline(1).getline(2).getline(3)
381    if lines =~? "perlscript"
382      setf aspperl
383    elseif lines =~ "<%"
384      setf aspvbs
385    elseif lines =~ "<?"
386      setf php
387    " Pascal supports // comments but they're vary rarely used for file
388    " headers so assume POV-Ray
389    elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? s:ft_pascal_keywords
390      setf pascal
391    else
392      call dist#ft#FTasmsyntax()
393      if exists("b:asmsyntax")
394	exe "setf " . fnameescape(b:asmsyntax)
395      else
396	setf pov
397      endif
398    endif
399  endif
400endfunc
401
402func dist#ft#FTprogress_cweb()
403  if exists("g:filetype_w")
404    exe "setf " . g:filetype_w
405    return
406  endif
407  if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
408    setf progress
409  else
410    setf cweb
411  endif
412endfunc
413
414func dist#ft#FTprogress_asm()
415  if exists("g:filetype_i")
416    exe "setf " . g:filetype_i
417    return
418  endif
419  " This function checks for an assembly comment the first ten lines.
420  " If not found, assume Progress.
421  let lnum = 1
422  while lnum <= 10 && lnum < line('$')
423    let line = getline(lnum)
424    if line =~ '^\s*;' || line =~ '^\*'
425      call dist#ft#FTasm()
426      return
427    elseif line !~ '^\s*$' || line =~ '^/\*'
428      " Not an empty line: Doesn't look like valid assembly code.
429      " Or it looks like a Progress /* comment
430      break
431    endif
432    let lnum = lnum + 1
433  endw
434  setf progress
435endfunc
436
437let s:ft_pascal_comments = '^\s*\%({\|(\*\|//\)'
438let s:ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>'
439
440func dist#ft#FTprogress_pascal()
441  if exists("g:filetype_p")
442    exe "setf " . g:filetype_p
443    return
444  endif
445  " This function checks for valid Pascal syntax in the first ten lines.
446  " Look for either an opening comment or a program start.
447  " If not found, assume Progress.
448  let lnum = 1
449  while lnum <= 10 && lnum < line('$')
450    let line = getline(lnum)
451    if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
452      setf pascal
453      return
454    elseif line !~ '^\s*$' || line =~ '^/\*'
455      " Not an empty line: Doesn't look like valid Pascal code.
456      " Or it looks like a Progress /* comment
457      break
458    endif
459    let lnum = lnum + 1
460  endw
461  setf progress
462endfunc
463
464func dist#ft#FTpp()
465  if exists("g:filetype_pp")
466    exe "setf " . g:filetype_pp
467  else
468    let line = getline(nextnonblank(1))
469    if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
470      setf pascal
471    else
472      setf puppet
473    endif
474  endif
475endfunc
476
477func dist#ft#FTr()
478  let max = line("$") > 50 ? 50 : line("$")
479
480  for n in range(1, max)
481    " Rebol is easy to recognize, check for that first
482    if getline(n) =~? '\<REBOL\>'
483      setf rebol
484      return
485    endif
486  endfor
487
488  for n in range(1, max)
489    " R has # comments
490    if getline(n) =~ '^\s*#'
491      setf r
492      return
493    endif
494    " Rexx has /* comments */
495    if getline(n) =~ '^\s*/\*'
496      setf rexx
497      return
498    endif
499  endfor
500
501  " Nothing recognized, use user default or assume Rexx
502  if exists("g:filetype_r")
503    exe "setf " . g:filetype_r
504  else
505    " Rexx used to be the default, but R appears to be much more popular.
506    setf r
507  endif
508endfunc
509
510func dist#ft#McSetf()
511  " Rely on the file to start with a comment.
512  " MS message text files use ';', Sendmail files use '#' or 'dnl'
513  for lnum in range(1, min([line("$"), 20]))
514    let line = getline(lnum)
515    if line =~ '^\s*\(#\|dnl\)'
516      setf m4  " Sendmail .mc file
517      return
518    elseif line =~ '^\s*;'
519      setf msmessages  " MS Message text file
520      return
521    endif
522  endfor
523  setf m4  " Default: Sendmail .mc file
524endfunc
525
526" Called from filetype.vim and scripts.vim.
527func dist#ft#SetFileTypeSH(name)
528  if did_filetype()
529    " Filetype was already detected
530    return
531  endif
532  if expand("<amatch>") =~ g:ft_ignore_pat
533    return
534  endif
535  if a:name =~ '\<csh\>'
536    " Some .sh scripts contain #!/bin/csh.
537    call dist#ft#SetFileTypeShell("csh")
538    return
539  elseif a:name =~ '\<tcsh\>'
540    " Some .sh scripts contain #!/bin/tcsh.
541    call dist#ft#SetFileTypeShell("tcsh")
542    return
543  elseif a:name =~ '\<zsh\>'
544    " Some .sh scripts contain #!/bin/zsh.
545    call dist#ft#SetFileTypeShell("zsh")
546    return
547  elseif a:name =~ '\<ksh\>'
548    let b:is_kornshell = 1
549    if exists("b:is_bash")
550      unlet b:is_bash
551    endif
552    if exists("b:is_sh")
553      unlet b:is_sh
554    endif
555  elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
556    let b:is_bash = 1
557    if exists("b:is_kornshell")
558      unlet b:is_kornshell
559    endif
560    if exists("b:is_sh")
561      unlet b:is_sh
562    endif
563  elseif a:name =~ '\<sh\>'
564    let b:is_sh = 1
565    if exists("b:is_kornshell")
566      unlet b:is_kornshell
567    endif
568    if exists("b:is_bash")
569      unlet b:is_bash
570    endif
571  endif
572  call dist#ft#SetFileTypeShell("sh")
573endfunc
574
575" For shell-like file types, check for an "exec" command hidden in a comment,
576" as used for Tcl.
577" Also called from scripts.vim, thus can't be local to this script.
578func dist#ft#SetFileTypeShell(name)
579  if did_filetype()
580    " Filetype was already detected
581    return
582  endif
583  if expand("<amatch>") =~ g:ft_ignore_pat
584    return
585  endif
586  let l = 2
587  while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
588    " Skip empty and comment lines.
589    let l = l + 1
590  endwhile
591  if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
592    " Found an "exec" line after a comment with continuation
593    let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
594    if n =~ '\<tclsh\|\<wish'
595      setf tcl
596      return
597    endif
598  endif
599  exe "setf " . a:name
600endfunc
601
602func dist#ft#CSH()
603  if did_filetype()
604    " Filetype was already detected
605    return
606  endif
607  if exists("g:filetype_csh")
608    call dist#ft#SetFileTypeShell(g:filetype_csh)
609  elseif &shell =~ "tcsh"
610    call dist#ft#SetFileTypeShell("tcsh")
611  else
612    call dist#ft#SetFileTypeShell("csh")
613  endif
614endfunc
615
616let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
617func dist#ft#FTRules()
618  let path = expand('<amatch>:p')
619  if path =~ '/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|\%(usr/\)\=lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
620    setf udevrules
621    return
622  endif
623  if path =~ '^/etc/ufw/'
624    setf conf  " Better than hog
625    return
626  endif
627  if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
628    setf javascript
629    return
630  endif
631  try
632    let config_lines = readfile('/etc/udev/udev.conf')
633  catch /^Vim\%((\a\+)\)\=:E484/
634    setf hog
635    return
636  endtry
637  let dir = expand('<amatch>:p:h')
638  for line in config_lines
639    if line =~ s:ft_rules_udev_rules_pattern
640      let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
641      if dir == udev_rules
642	setf udevrules
643      endif
644      break
645    endif
646  endfor
647  setf hog
648endfunc
649
650func dist#ft#SQL()
651  if exists("g:filetype_sql")
652    exe "setf " . g:filetype_sql
653  else
654    setf sql
655  endif
656endfunc
657
658" If the file has an extension of 't' and is in a directory 't' or 'xt' then
659" it is almost certainly a Perl test file.
660" If the first line starts with '#' and contains 'perl' it's probably a Perl
661" file.
662" (Slow test) If a file contains a 'use' statement then it is almost certainly
663" a Perl file.
664func dist#ft#FTperl()
665  let dirname = expand("%:p:h:t")
666  if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
667    setf perl
668    return 1
669  endif
670  if getline(1)[0] == '#' && getline(1) =~ 'perl'
671    setf perl
672    return 1
673  endif
674  let save_cursor = getpos('.')
675  call cursor(1,1)
676  let has_use = search('^use\s\s*\k', 'c', 30)
677  call setpos('.', save_cursor)
678  if has_use
679    setf perl
680    return 1
681  endif
682  return 0
683endfunc
684
685" Choose context, plaintex, or tex (LaTeX) based on these rules:
686" 1. Check the first line of the file for "%&<format>".
687" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
688" 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
689func dist#ft#FTtex()
690  let firstline = getline(1)
691  if firstline =~ '^%&\s*\a\+'
692    let format = tolower(matchstr(firstline, '\a\+'))
693    let format = substitute(format, 'pdf', '', '')
694    if format == 'tex'
695      let format = 'latex'
696    elseif format == 'plaintex'
697      let format = 'plain'
698    endif
699  elseif expand('%') =~ 'tex/context/.*/.*.tex'
700    let format = 'context'
701  else
702    " Default value, may be changed later:
703    let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
704    " Save position, go to the top of the file, find first non-comment line.
705    let save_cursor = getpos('.')
706    call cursor(1,1)
707    let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
708    if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
709      let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
710      let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
711      let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
712			      \ 'cnp', firstNC + 1000)
713      if kwline == 1	" lpat matched
714	let format = 'latex'
715      elseif kwline == 2	" cpat matched
716	let format = 'context'
717      endif		" If neither matched, keep default set above.
718      " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
719      " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
720      " if cline > 0
721      "   let format = 'context'
722      " endif
723      " if lline > 0 && (cline == 0 || cline > lline)
724      "   let format = 'tex'
725      " endif
726    endif " firstNC
727    call setpos('.', save_cursor)
728  endif " firstline =~ '^%&\s*\a\+'
729
730  " Translation from formats to file types.  TODO:  add AMSTeX, RevTex, others?
731  if format == 'plain'
732    setf plaintex
733  elseif format == 'context'
734    setf context
735  else " probably LaTeX
736    setf tex
737  endif
738  return
739endfunc
740
741func dist#ft#FTxml()
742  let n = 1
743  while n < 100 && n <= line("$")
744    let line = getline(n)
745    " DocBook 4 or DocBook 5.
746    let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
747    let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
748    if is_docbook4 || is_docbook5
749      let b:docbk_type = "xml"
750      if is_docbook5
751	let b:docbk_ver = 5
752      else
753	let b:docbk_ver = 4
754      endif
755      setf docbk
756      return
757    endif
758    if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
759      setf xbl
760      return
761    endif
762    let n += 1
763  endwhile
764  setf xml
765endfunc
766
767func dist#ft#FTy()
768  let n = 1
769  while n < 100 && n <= line("$")
770    let line = getline(n)
771    if line =~ '^\s*%'
772      setf yacc
773      return
774    endif
775    if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
776      setf racc
777      return
778    endif
779    let n = n + 1
780  endwhile
781  setf yacc
782endfunc
783
784func dist#ft#Redif()
785  let lnum = 1
786  while lnum <= 5 && lnum < line('$')
787    if getline(lnum) =~ "^\ctemplate-type:"
788      setf redif
789      return
790    endif
791    let lnum = lnum + 1
792  endwhile
793endfunc
794
795
796" Restore 'cpoptions'
797let &cpo = s:cpo_save
798unlet s:cpo_save
799