xref: /vim-8.2.3635/runtime/autoload/dist/ft.vim (revision 4c295027)
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#EuphoriaCheck()
176  if exists('g:filetype_euphoria')
177    exe 'setf ' . g:filetype_euphoria
178  else
179    setf euphoria3
180  endif
181endfunc
182
183func dist#ft#DtraceCheck()
184  let lines = getline(1, min([line("$"), 100]))
185  if match(lines, '^module\>\|^import\>') > -1
186    " D files often start with a module and/or import statement.
187    setf d
188  elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
189    setf dtrace
190  else
191    setf d
192  endif
193endfunc
194
195func dist#ft#FTe()
196  if exists('g:filetype_euphoria')
197    exe 'setf ' . g:filetype_euphoria
198  else
199    let n = 1
200    while n < 100 && n <= line("$")
201      if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
202	setf specman
203	return
204      endif
205      let n = n + 1
206    endwhile
207    setf eiffel
208  endif
209endfunc
210
211" Distinguish between HTML, XHTML and Django
212func dist#ft#FThtml()
213  let n = 1
214  while n < 10 && n <= line("$")
215    if getline(n) =~ '\<DTD\s\+XHTML\s'
216      setf xhtml
217      return
218    endif
219    if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
220      setf htmldjango
221      return
222    endif
223    let n = n + 1
224  endwhile
225  setf FALLBACK html
226endfunc
227
228" Distinguish between standard IDL and MS-IDL
229func dist#ft#FTidl()
230  let n = 1
231  while n < 50 && n <= line("$")
232    if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
233      setf msidl
234      return
235    endif
236    let n = n + 1
237  endwhile
238  setf idl
239endfunc
240
241" Distinguish between "default" and Cproto prototype file. */
242func dist#ft#ProtoCheck(default)
243  " Cproto files have a comment in the first line and a function prototype in
244  " the second line, it always ends in ";".  Indent files may also have
245  " comments, thus we can't match comments to see the difference.
246  " IDL files can have a single ';' in the second line, require at least one
247  " chacter before the ';'.
248  if getline(2) =~ '.;$'
249    setf cpp
250  else
251    exe 'setf ' . a:default
252  endif
253endfunc
254
255func dist#ft#FTm()
256  let n = 1
257  let saw_comment = 0 " Whether we've seen a multiline comment leader.
258  while n < 100
259    let line = getline(n)
260    if line =~ '^\s*/\*'
261      " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
262      " it's either of them yet, but track this as a hint in case we don't see
263      " anything more definitive.
264      let saw_comment = 1
265    endif
266    if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
267      setf objc
268      return
269    endif
270    if line =~ '^\s*%'
271      setf matlab
272      return
273    endif
274    if line =~ '^\s*(\*'
275      setf mma
276      return
277    endif
278    if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
279      setf murphi
280      return
281    endif
282    let n = n + 1
283  endwhile
284
285  if saw_comment
286    " We didn't see anything definitive, but this looks like either Objective C
287    " or Murphi based on the comment leader. Assume the former as it is more
288    " common.
289    setf objc
290  elseif exists("g:filetype_m")
291    " Use user specified default filetype for .m
292    exe "setf " . g:filetype_m
293  else
294    " Default is matlab
295    setf matlab
296  endif
297endfunc
298
299func dist#ft#FTmms()
300  let n = 1
301  while n < 20
302    let line = getline(n)
303    if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
304      setf mmix
305      return
306    endif
307    if line =~ '^\s*#'
308      setf make
309      return
310    endif
311    let n = n + 1
312  endwhile
313  setf mmix
314endfunc
315
316" This function checks if one of the first five lines start with a dot.  In
317" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
318func dist#ft#FTnroff()
319  if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
320    setf nroff
321    return 1
322  endif
323  return 0
324endfunc
325
326func dist#ft#FTmm()
327  let n = 1
328  while n < 20
329    let line = getline(n)
330    if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
331      setf objcpp
332      return
333    endif
334    let n = n + 1
335  endwhile
336  setf nroff
337endfunc
338
339func dist#ft#FTpl()
340  if exists("g:filetype_pl")
341    exe "setf " . g:filetype_pl
342  else
343    " recognize Prolog by specific text in the first non-empty line
344    " require a blank after the '%' because Perl uses "%list" and "%translate"
345    let l = getline(nextnonblank(1))
346    if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
347      setf prolog
348    else
349      setf perl
350    endif
351  endif
352endfunc
353
354func dist#ft#FTinc()
355  if exists("g:filetype_inc")
356    exe "setf " . g:filetype_inc
357  else
358    let lines = getline(1).getline(2).getline(3)
359    if lines =~? "perlscript"
360      setf aspperl
361    elseif lines =~ "<%"
362      setf aspvbs
363    elseif lines =~ "<?"
364      setf php
365    " Pascal supports // comments but they're vary rarely used for file
366    " headers so assume POV-Ray
367    elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? s:ft_pascal_keywords
368      setf pascal
369    else
370      call dist#ft#FTasmsyntax()
371      if exists("b:asmsyntax")
372	exe "setf " . fnameescape(b:asmsyntax)
373      else
374	setf pov
375      endif
376    endif
377  endif
378endfunc
379
380func dist#ft#FTprogress_cweb()
381  if exists("g:filetype_w")
382    exe "setf " . g:filetype_w
383    return
384  endif
385  if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
386    setf progress
387  else
388    setf cweb
389  endif
390endfunc
391
392func dist#ft#FTprogress_asm()
393  if exists("g:filetype_i")
394    exe "setf " . g:filetype_i
395    return
396  endif
397  " This function checks for an assembly comment the first ten lines.
398  " If not found, assume Progress.
399  let lnum = 1
400  while lnum <= 10 && lnum < line('$')
401    let line = getline(lnum)
402    if line =~ '^\s*;' || line =~ '^\*'
403      call dist#ft#FTasm()
404      return
405    elseif line !~ '^\s*$' || line =~ '^/\*'
406      " Not an empty line: Doesn't look like valid assembly code.
407      " Or it looks like a Progress /* comment
408      break
409    endif
410    let lnum = lnum + 1
411  endw
412  setf progress
413endfunc
414
415let s:ft_pascal_comments = '^\s*\%({\|(\*\|//\)'
416let s:ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>'
417
418func dist#ft#FTprogress_pascal()
419  if exists("g:filetype_p")
420    exe "setf " . g:filetype_p
421    return
422  endif
423  " This function checks for valid Pascal syntax in the first ten lines.
424  " Look for either an opening comment or a program start.
425  " If not found, assume Progress.
426  let lnum = 1
427  while lnum <= 10 && lnum < line('$')
428    let line = getline(lnum)
429    if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
430      setf pascal
431      return
432    elseif line !~ '^\s*$' || line =~ '^/\*'
433      " Not an empty line: Doesn't look like valid Pascal code.
434      " Or it looks like a Progress /* comment
435      break
436    endif
437    let lnum = lnum + 1
438  endw
439  setf progress
440endfunc
441
442func dist#ft#FTpp()
443  if exists("g:filetype_pp")
444    exe "setf " . g:filetype_pp
445  else
446    let line = getline(nextnonblank(1))
447    if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
448      setf pascal
449    else
450      setf puppet
451    endif
452  endif
453endfunc
454
455func dist#ft#FTr()
456  let max = line("$") > 50 ? 50 : line("$")
457
458  for n in range(1, max)
459    " Rebol is easy to recognize, check for that first
460    if getline(n) =~? '\<REBOL\>'
461      setf rebol
462      return
463    endif
464  endfor
465
466  for n in range(1, max)
467    " R has # comments
468    if getline(n) =~ '^\s*#'
469      setf r
470      return
471    endif
472    " Rexx has /* comments */
473    if getline(n) =~ '^\s*/\*'
474      setf rexx
475      return
476    endif
477  endfor
478
479  " Nothing recognized, use user default or assume Rexx
480  if exists("g:filetype_r")
481    exe "setf " . g:filetype_r
482  else
483    " Rexx used to be the default, but R appears to be much more popular.
484    setf r
485  endif
486endfunc
487
488func dist#ft#McSetf()
489  " Rely on the file to start with a comment.
490  " MS message text files use ';', Sendmail files use '#' or 'dnl'
491  for lnum in range(1, min([line("$"), 20]))
492    let line = getline(lnum)
493    if line =~ '^\s*\(#\|dnl\)'
494      setf m4  " Sendmail .mc file
495      return
496    elseif line =~ '^\s*;'
497      setf msmessages  " MS Message text file
498      return
499    endif
500  endfor
501  setf m4  " Default: Sendmail .mc file
502endfunc
503
504" Called from filetype.vim and scripts.vim.
505func dist#ft#SetFileTypeSH(name)
506  if did_filetype()
507    " Filetype was already detected
508    return
509  endif
510  if expand("<amatch>") =~ g:ft_ignore_pat
511    return
512  endif
513  if a:name =~ '\<csh\>'
514    " Some .sh scripts contain #!/bin/csh.
515    call dist#ft#SetFileTypeShell("csh")
516    return
517  elseif a:name =~ '\<tcsh\>'
518    " Some .sh scripts contain #!/bin/tcsh.
519    call dist#ft#SetFileTypeShell("tcsh")
520    return
521  elseif a:name =~ '\<zsh\>'
522    " Some .sh scripts contain #!/bin/zsh.
523    call dist#ft#SetFileTypeShell("zsh")
524    return
525  elseif a:name =~ '\<ksh\>'
526    let b:is_kornshell = 1
527    if exists("b:is_bash")
528      unlet b:is_bash
529    endif
530    if exists("b:is_sh")
531      unlet b:is_sh
532    endif
533  elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
534    let b:is_bash = 1
535    if exists("b:is_kornshell")
536      unlet b:is_kornshell
537    endif
538    if exists("b:is_sh")
539      unlet b:is_sh
540    endif
541  elseif a:name =~ '\<sh\>'
542    let b:is_sh = 1
543    if exists("b:is_kornshell")
544      unlet b:is_kornshell
545    endif
546    if exists("b:is_bash")
547      unlet b:is_bash
548    endif
549  endif
550  call dist#ft#SetFileTypeShell("sh")
551endfunc
552
553" For shell-like file types, check for an "exec" command hidden in a comment,
554" as used for Tcl.
555" Also called from scripts.vim, thus can't be local to this script.
556func dist#ft#SetFileTypeShell(name)
557  if did_filetype()
558    " Filetype was already detected
559    return
560  endif
561  if expand("<amatch>") =~ g:ft_ignore_pat
562    return
563  endif
564  let l = 2
565  while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
566    " Skip empty and comment lines.
567    let l = l + 1
568  endwhile
569  if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
570    " Found an "exec" line after a comment with continuation
571    let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
572    if n =~ '\<tclsh\|\<wish'
573      setf tcl
574      return
575    endif
576  endif
577  exe "setf " . a:name
578endfunc
579
580func dist#ft#CSH()
581  if did_filetype()
582    " Filetype was already detected
583    return
584  endif
585  if exists("g:filetype_csh")
586    call dist#ft#SetFileTypeShell(g:filetype_csh)
587  elseif &shell =~ "tcsh"
588    call dist#ft#SetFileTypeShell("tcsh")
589  else
590    call dist#ft#SetFileTypeShell("csh")
591  endif
592endfunc
593
594let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
595func dist#ft#FTRules()
596  let path = expand('<amatch>:p')
597  if path =~ '/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|\%(usr/\)\=lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
598    setf udevrules
599    return
600  endif
601  if path =~ '^/etc/ufw/'
602    setf conf  " Better than hog
603    return
604  endif
605  if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
606    setf javascript
607    return
608  endif
609  try
610    let config_lines = readfile('/etc/udev/udev.conf')
611  catch /^Vim\%((\a\+)\)\=:E484/
612    setf hog
613    return
614  endtry
615  let dir = expand('<amatch>:p:h')
616  for line in config_lines
617    if line =~ s:ft_rules_udev_rules_pattern
618      let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
619      if dir == udev_rules
620	setf udevrules
621      endif
622      break
623    endif
624  endfor
625  setf hog
626endfunc
627
628func dist#ft#SQL()
629  if exists("g:filetype_sql")
630    exe "setf " . g:filetype_sql
631  else
632    setf sql
633  endif
634endfunc
635
636" If the file has an extension of 't' and is in a directory 't' or 'xt' then
637" it is almost certainly a Perl test file.
638" If the first line starts with '#' and contains 'perl' it's probably a Perl
639" file.
640" (Slow test) If a file contains a 'use' statement then it is almost certainly
641" a Perl file.
642func dist#ft#FTperl()
643  let dirname = expand("%:p:h:t")
644  if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
645    setf perl
646    return 1
647  endif
648  if getline(1)[0] == '#' && getline(1) =~ 'perl'
649    setf perl
650    return 1
651  endif
652  let save_cursor = getpos('.')
653  call cursor(1,1)
654  let has_use = search('^use\s\s*\k', 'c', 30)
655  call setpos('.', save_cursor)
656  if has_use
657    setf perl
658    return 1
659  endif
660  return 0
661endfunc
662
663" Choose context, plaintex, or tex (LaTeX) based on these rules:
664" 1. Check the first line of the file for "%&<format>".
665" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
666" 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
667func dist#ft#FTtex()
668  let firstline = getline(1)
669  if firstline =~ '^%&\s*\a\+'
670    let format = tolower(matchstr(firstline, '\a\+'))
671    let format = substitute(format, 'pdf', '', '')
672    if format == 'tex'
673      let format = 'latex'
674    elseif format == 'plaintex'
675      let format = 'plain'
676    endif
677  elseif expand('%') =~ 'tex/context/.*/.*.tex'
678    let format = 'context'
679  else
680    " Default value, may be changed later:
681    let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
682    " Save position, go to the top of the file, find first non-comment line.
683    let save_cursor = getpos('.')
684    call cursor(1,1)
685    let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
686    if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
687      let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
688      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\>'
689      let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
690			      \ 'cnp', firstNC + 1000)
691      if kwline == 1	" lpat matched
692	let format = 'latex'
693      elseif kwline == 2	" cpat matched
694	let format = 'context'
695      endif		" If neither matched, keep default set above.
696      " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
697      " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
698      " if cline > 0
699      "   let format = 'context'
700      " endif
701      " if lline > 0 && (cline == 0 || cline > lline)
702      "   let format = 'tex'
703      " endif
704    endif " firstNC
705    call setpos('.', save_cursor)
706  endif " firstline =~ '^%&\s*\a\+'
707
708  " Translation from formats to file types.  TODO:  add AMSTeX, RevTex, others?
709  if format == 'plain'
710    setf plaintex
711  elseif format == 'context'
712    setf context
713  else " probably LaTeX
714    setf tex
715  endif
716  return
717endfunc
718
719func dist#ft#FTxml()
720  let n = 1
721  while n < 100 && n <= line("$")
722    let line = getline(n)
723    " DocBook 4 or DocBook 5.
724    let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
725    let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
726    if is_docbook4 || is_docbook5
727      let b:docbk_type = "xml"
728      if is_docbook5
729	let b:docbk_ver = 5
730      else
731	let b:docbk_ver = 4
732      endif
733      setf docbk
734      return
735    endif
736    if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
737      setf xbl
738      return
739    endif
740    let n += 1
741  endwhile
742  setf xml
743endfunc
744
745func dist#ft#FTy()
746  let n = 1
747  while n < 100 && n <= line("$")
748    let line = getline(n)
749    if line =~ '^\s*%'
750      setf yacc
751      return
752    endif
753    if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
754      setf racc
755      return
756    endif
757    let n = n + 1
758  endwhile
759  setf yacc
760endfunc
761
762func dist#ft#Redif()
763  let lnum = 1
764  while lnum <= 5 && lnum < line('$')
765    if getline(lnum) =~ "^\ctemplate-type:"
766      setf redif
767      return
768    endif
769    let lnum = lnum + 1
770  endwhile
771endfunc
772
773
774" Restore 'cpoptions'
775let &cpo = s:cpo_save
776unlet s:cpo_save
777