blob: 81fdc9d956640a2a39d87141718587385cb996ca [file] [log] [blame]
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001" Vim functions for file type detection
2"
3" Maintainer: Bram Moolenaar <Bram@vim.org>
Bram Moolenaarf0b03c42017-12-17 17:17:07 +01004" Last Change: 2017 Dec 05
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01005
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
Bram Moolenaard09a2062017-11-11 15:37:45 +010013func dist#ft#Check_inp()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010014 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.
Bram Moolenaard09a2062017-11-11 15:37:45 +010035func dist#ft#FTasm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010036 " make sure b:asmsyntax exists
37 if !exists("b:asmsyntax")
38 let b:asmsyntax = ""
39 endif
40
41 if b:asmsyntax == ""
Bram Moolenaard09a2062017-11-11 15:37:45 +010042 call dist#ft#FTasmsyntax()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010043 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
Bram Moolenaard09a2062017-11-11 15:37:45 +010057func dist#ft#FTasmsyntax()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010058 " 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.
Bram Moolenaard09a2062017-11-11 15:37:45 +010072func dist#ft#FTVB(alt)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010073 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
Bram Moolenaard09a2062017-11-11 15:37:45 +010080func dist#ft#FTbtm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010081 if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
82 setf dosbatch
83 else
84 setf btm
85 endif
86endfunc
87
Bram Moolenaard09a2062017-11-11 15:37:45 +010088func dist#ft#BindzoneCheck(default)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010089 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
Bram Moolenaard09a2062017-11-11 15:37:45 +010096func dist#ft#FTlpc()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010097 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100110func dist#ft#FTheader()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100111 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", "//" ir "/*" it's probably ch.
130" Otherwise CHILL is assumed.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100131func dist#ft#FTchange()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100132 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100155func dist#ft#FTent()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100156 " 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100175func dist#ft#EuphoriaCheck()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100176 if exists('g:filetype_euphoria')
177 exe 'setf ' . g:filetype_euphoria
178 else
179 setf euphoria3
180 endif
181endfunc
182
Bram Moolenaard09a2062017-11-11 15:37:45 +0100183func dist#ft#DtraceCheck()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100184 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100195func dist#ft#FTe()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100196 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100212func dist#ft#FThtml()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100213 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 html
226endfunc
227
228" Distinguish between standard IDL and MS-IDL
Bram Moolenaard09a2062017-11-11 15:37:45 +0100229func dist#ft#FTidl()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100230 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. */
Bram Moolenaard09a2062017-11-11 15:37:45 +0100242func dist#ft#ProtoCheck(default)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100243 " 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100255func dist#ft#FTm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100256 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100299func dist#ft#FTmms()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100300 let n = 1
301 while n < 10
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.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100318func dist#ft#FTnroff()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100319 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100326func dist#ft#FTmm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100327 let n = 1
328 while n < 10
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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100339func dist#ft#FTpl()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100340 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
Bram Moolenaard09a2062017-11-11 15:37:45 +0100354func dist#ft#FTinc()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100355 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 else
Bram Moolenaard09a2062017-11-11 15:37:45 +0100366 call dist#ft#FTasmsyntax()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100367 if exists("b:asmsyntax")
368 exe "setf " . fnameescape(b:asmsyntax)
369 else
370 setf pov
371 endif
372 endif
373 endif
374endfunc
375
Bram Moolenaard09a2062017-11-11 15:37:45 +0100376func dist#ft#FTprogress_cweb()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100377 if exists("g:filetype_w")
378 exe "setf " . g:filetype_w
379 return
380 endif
381 if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
382 setf progress
383 else
384 setf cweb
385 endif
386endfunc
387
Bram Moolenaard09a2062017-11-11 15:37:45 +0100388func dist#ft#FTprogress_asm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100389 if exists("g:filetype_i")
390 exe "setf " . g:filetype_i
391 return
392 endif
393 " This function checks for an assembly comment the first ten lines.
394 " If not found, assume Progress.
395 let lnum = 1
396 while lnum <= 10 && lnum < line('$')
397 let line = getline(lnum)
398 if line =~ '^\s*;' || line =~ '^\*'
Bram Moolenaard09a2062017-11-11 15:37:45 +0100399 call dist#ft#FTasm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100400 return
401 elseif line !~ '^\s*$' || line =~ '^/\*'
402 " Not an empty line: Doesn't look like valid assembly code.
403 " Or it looks like a Progress /* comment
404 break
405 endif
406 let lnum = lnum + 1
407 endw
408 setf progress
409endfunc
410
Bram Moolenaard09a2062017-11-11 15:37:45 +0100411func dist#ft#FTprogress_pascal()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100412 if exists("g:filetype_p")
413 exe "setf " . g:filetype_p
414 return
415 endif
416 " This function checks for valid Pascal syntax in the first ten lines.
417 " Look for either an opening comment or a program start.
418 " If not found, assume Progress.
419 let lnum = 1
420 while lnum <= 10 && lnum < line('$')
421 let line = getline(lnum)
422 if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>'
423 \ || line =~ '^\s*{' || line =~ '^\s*(\*'
424 setf pascal
425 return
426 elseif line !~ '^\s*$' || line =~ '^/\*'
427 " Not an empty line: Doesn't look like valid Pascal code.
428 " Or it looks like a Progress /* comment
429 break
430 endif
431 let lnum = lnum + 1
432 endw
433 setf progress
434endfunc
435
Bram Moolenaard09a2062017-11-11 15:37:45 +0100436func dist#ft#FTr()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100437 let max = line("$") > 50 ? 50 : line("$")
438
439 for n in range(1, max)
440 " Rebol is easy to recognize, check for that first
441 if getline(n) =~? '\<REBOL\>'
442 setf rebol
443 return
444 endif
445 endfor
446
447 for n in range(1, max)
448 " R has # comments
449 if getline(n) =~ '^\s*#'
450 setf r
451 return
452 endif
453 " Rexx has /* comments */
454 if getline(n) =~ '^\s*/\*'
455 setf rexx
456 return
457 endif
458 endfor
459
460 " Nothing recognized, use user default or assume Rexx
461 if exists("g:filetype_r")
462 exe "setf " . g:filetype_r
463 else
464 " Rexx used to be the default, but R appears to be much more popular.
465 setf r
466 endif
467endfunc
468
Bram Moolenaard09a2062017-11-11 15:37:45 +0100469func dist#ft#McSetf()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100470 " Rely on the file to start with a comment.
471 " MS message text files use ';', Sendmail files use '#' or 'dnl'
472 for lnum in range(1, min([line("$"), 20]))
473 let line = getline(lnum)
474 if line =~ '^\s*\(#\|dnl\)'
475 setf m4 " Sendmail .mc file
476 return
477 elseif line =~ '^\s*;'
478 setf msmessages " MS Message text file
479 return
480 endif
481 endfor
482 setf m4 " Default: Sendmail .mc file
483endfunc
484
485" Called from filetype.vim and scripts.vim.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100486func dist#ft#SetFileTypeSH(name)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100487 if expand("<amatch>") =~ g:ft_ignore_pat
488 return
489 endif
490 if a:name =~ '\<csh\>'
491 " Some .sh scripts contain #!/bin/csh.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100492 call dist#ft#SetFileTypeShell("csh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100493 return
494 elseif a:name =~ '\<tcsh\>'
495 " Some .sh scripts contain #!/bin/tcsh.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100496 call dist#ft#SetFileTypeShell("tcsh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100497 return
498 elseif a:name =~ '\<zsh\>'
499 " Some .sh scripts contain #!/bin/zsh.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100500 call dist#ft#SetFileTypeShell("zsh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100501 return
502 elseif a:name =~ '\<ksh\>'
503 let b:is_kornshell = 1
504 if exists("b:is_bash")
505 unlet b:is_bash
506 endif
507 if exists("b:is_sh")
508 unlet b:is_sh
509 endif
510 elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
511 let b:is_bash = 1
512 if exists("b:is_kornshell")
513 unlet b:is_kornshell
514 endif
515 if exists("b:is_sh")
516 unlet b:is_sh
517 endif
518 elseif a:name =~ '\<sh\>'
519 let b:is_sh = 1
520 if exists("b:is_kornshell")
521 unlet b:is_kornshell
522 endif
523 if exists("b:is_bash")
524 unlet b:is_bash
525 endif
526 endif
Bram Moolenaard09a2062017-11-11 15:37:45 +0100527 call dist#ft#SetFileTypeShell("sh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100528endfunc
529
530" For shell-like file types, check for an "exec" command hidden in a comment,
531" as used for Tcl.
532" Also called from scripts.vim, thus can't be local to this script.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100533func dist#ft#SetFileTypeShell(name)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100534 if expand("<amatch>") =~ g:ft_ignore_pat
535 return
536 endif
537 let l = 2
538 while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
539 " Skip empty and comment lines.
540 let l = l + 1
541 endwhile
542 if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
543 " Found an "exec" line after a comment with continuation
544 let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
545 if n =~ '\<tclsh\|\<wish'
546 setf tcl
547 return
548 endif
549 endif
550 exe "setf " . a:name
551endfunc
552
Bram Moolenaard09a2062017-11-11 15:37:45 +0100553func dist#ft#CSH()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100554 if exists("g:filetype_csh")
Bram Moolenaard09a2062017-11-11 15:37:45 +0100555 call dist#ft#SetFileTypeShell(g:filetype_csh)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100556 elseif &shell =~ "tcsh"
Bram Moolenaard09a2062017-11-11 15:37:45 +0100557 call dist#ft#SetFileTypeShell("tcsh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100558 else
Bram Moolenaard09a2062017-11-11 15:37:45 +0100559 call dist#ft#SetFileTypeShell("csh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100560 endif
561endfunc
562
Bram Moolenaarcef73222017-11-09 21:05:31 +0100563let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
Bram Moolenaard09a2062017-11-11 15:37:45 +0100564func dist#ft#FTRules()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100565 let path = expand('<amatch>:p')
566 if path =~ '^/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
567 setf udevrules
568 return
569 endif
570 if path =~ '^/etc/ufw/'
571 setf conf " Better than hog
572 return
573 endif
574 if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
575 setf javascript
576 return
577 endif
578 try
579 let config_lines = readfile('/etc/udev/udev.conf')
580 catch /^Vim\%((\a\+)\)\=:E484/
581 setf hog
582 return
583 endtry
584 let dir = expand('<amatch>:p:h')
585 for line in config_lines
586 if line =~ s:ft_rules_udev_rules_pattern
587 let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
588 if dir == udev_rules
589 setf udevrules
590 endif
591 break
592 endif
593 endfor
594 setf hog
595endfunc
596
Bram Moolenaard09a2062017-11-11 15:37:45 +0100597func dist#ft#SQL()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100598 if exists("g:filetype_sql")
599 exe "setf " . g:filetype_sql
600 else
601 setf sql
602 endif
603endfunc
604
605" If the file has an extension of 't' and is in a directory 't' or 'xt' then
606" it is almost certainly a Perl test file.
607" If the first line starts with '#' and contains 'perl' it's probably a Perl
608" file.
609" (Slow test) If a file contains a 'use' statement then it is almost certainly
610" a Perl file.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100611func dist#ft#FTperl()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100612 let dirname = expand("%:p:h:t")
613 if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
614 setf perl
615 return 1
616 endif
617 if getline(1)[0] == '#' && getline(1) =~ 'perl'
618 setf perl
619 return 1
620 endif
Bram Moolenaarf0b03c42017-12-17 17:17:07 +0100621 let save_cursor = getpos('.')
622 call cursor(1,1)
623 let has_use = search('^use\s\s*\k', 'c', 30)
624 call setpos('.', save_cursor)
625 if has_use
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100626 setf perl
627 return 1
628 endif
629 return 0
630endfunc
631
632" Choose context, plaintex, or tex (LaTeX) based on these rules:
633" 1. Check the first line of the file for "%&<format>".
634" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
635" 3. Default to "latex" or to g:tex_flavor, can be set in user's vimrc.
Bram Moolenaard09a2062017-11-11 15:37:45 +0100636func dist#ft#FTtex()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100637 let firstline = getline(1)
638 if firstline =~ '^%&\s*\a\+'
639 let format = tolower(matchstr(firstline, '\a\+'))
640 let format = substitute(format, 'pdf', '', '')
641 if format == 'tex'
642 let format = 'latex'
643 elseif format == 'plaintex'
644 let format = 'plain'
645 endif
646 elseif expand('%') =~ 'tex/context/.*/.*.tex'
647 let format = 'context'
648 else
649 " Default value, may be changed later:
650 let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
651 " Save position, go to the top of the file, find first non-comment line.
652 let save_cursor = getpos('.')
653 call cursor(1,1)
654 let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
655 if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
656 let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
657 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\>'
658 let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
659 \ 'cnp', firstNC + 1000)
660 if kwline == 1 " lpat matched
661 let format = 'latex'
662 elseif kwline == 2 " cpat matched
663 let format = 'context'
664 endif " If neither matched, keep default set above.
665 " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
666 " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
667 " if cline > 0
668 " let format = 'context'
669 " endif
670 " if lline > 0 && (cline == 0 || cline > lline)
671 " let format = 'tex'
672 " endif
673 endif " firstNC
674 call setpos('.', save_cursor)
675 endif " firstline =~ '^%&\s*\a\+'
676
677 " Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
678 if format == 'plain'
679 setf plaintex
680 elseif format == 'context'
681 setf context
682 else " probably LaTeX
683 setf tex
684 endif
685 return
686endfunc
687
Bram Moolenaard09a2062017-11-11 15:37:45 +0100688func dist#ft#FTxml()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100689 let n = 1
690 while n < 100 && n < line("$")
691 let line = getline(n)
692 " DocBook 4 or DocBook 5.
693 let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
694 let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
695 if is_docbook4 || is_docbook5
696 let b:docbk_type = "xml"
697 if is_docbook5
698 let b:docbk_ver = 5
699 else
700 let b:docbk_ver = 4
701 endif
702 setf docbk
703 return
704 endif
705 if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
706 setf xbl
707 return
708 endif
709 let n += 1
710 endwhile
711 setf xml
712endfunc
713
Bram Moolenaard09a2062017-11-11 15:37:45 +0100714func dist#ft#FTy()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100715 let n = 1
716 while n < 100 && n < line("$")
717 let line = getline(n)
718 if line =~ '^\s*%'
719 setf yacc
720 return
721 endif
722 if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
723 setf racc
724 return
725 endif
726 let n = n + 1
727 endwhile
728 setf yacc
729endfunc
730
Bram Moolenaard09a2062017-11-11 15:37:45 +0100731func dist#ft#Redif()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100732 let lnum = 1
733 while lnum <= 5 && lnum < line('$')
734 if getline(lnum) =~ "^\ctemplate-type:"
735 setf redif
736 return
737 endif
738 let lnum = lnum + 1
739 endwhile
740endfunc
741
742
743" Restore 'cpoptions'
744let &cpo = s:cpo_save
745unlet s:cpo_save