blob: 214cf6e3ec47e97a015badb7d65a20243732b57b [file] [log] [blame]
Bram Moolenaara2baa732022-02-04 16:09:54 +00001vim9script
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01002
Bram Moolenaara2baa732022-02-04 16:09:54 +00003# Vim functions for file type detection
4#
Doug Kearns68a89472024-01-05 17:59:04 +01005# Maintainer: The Vim Project <https://github.com/vim/vim>
Amelia Clarke35dfe582024-05-24 08:05:00 +02006# Last Change: 2024 May 23
Christian Brabandte978b452023-08-13 10:33:05 +02007# Former Maintainer: Bram Moolenaar <Bram@vim.org>
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01008
Bram Moolenaara2baa732022-02-04 16:09:54 +00009# These functions are moved here from runtime/filetype.vim to make startup
10# faster.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010011
igna_martinoli37853b72024-07-18 21:34:36 +020012var prolog_pattern = '^\s*\(:-\|%\+\(\s\|$\)\|\/\*\)\|\.\s*$'
13
Bram Moolenaara2baa732022-02-04 16:09:54 +000014export def Check_inp()
Wu, Zhenyu61ee8332024-04-09 22:09:30 +020015 if getline(1) =~ '%%'
16 setf tex
17 elseif getline(1) =~ '^\*'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010018 setf abaqus
19 else
Bram Moolenaara2baa732022-02-04 16:09:54 +000020 var n = 1
21 var nmax = line("$") > 500 ? 500 : line("$")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010022 while n <= nmax
23 if getline(n) =~? "^header surface data"
24 setf trasys
25 break
26 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +000027 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010028 endwhile
29 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +000030enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010031
Bram Moolenaara2baa732022-02-04 16:09:54 +000032# This function checks for the kind of assembly that is wanted by the user, or
33# can be detected from the first five lines of the file.
34export def FTasm()
35 # make sure b:asmsyntax exists
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010036 if !exists("b:asmsyntax")
Bram Moolenaara2baa732022-02-04 16:09:54 +000037 b:asmsyntax = ""
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010038 endif
39
40 if b:asmsyntax == ""
Bram Moolenaara2baa732022-02-04 16:09:54 +000041 FTasmsyntax()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010042 endif
43
Bram Moolenaara2baa732022-02-04 16:09:54 +000044 # if b:asmsyntax still isn't set, default to asmsyntax or GNU
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010045 if b:asmsyntax == ""
46 if exists("g:asmsyntax")
Bram Moolenaara2baa732022-02-04 16:09:54 +000047 b:asmsyntax = g:asmsyntax
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010048 else
Bram Moolenaara2baa732022-02-04 16:09:54 +000049 b:asmsyntax = "asm"
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010050 endif
51 endif
52
Bram Moolenaara2baa732022-02-04 16:09:54 +000053 exe "setf " .. fnameescape(b:asmsyntax)
54enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010055
Bram Moolenaara2baa732022-02-04 16:09:54 +000056export def FTasmsyntax()
57 # see if the file contains any asmsyntax=foo overrides. If so, change
58 # b:asmsyntax appropriately
59 var head = " " .. getline(1) .. " " .. getline(2) .. " "
60 .. getline(3) .. " " .. getline(4) .. " " .. getline(5) .. " "
61 var match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010062 if match != ''
Bram Moolenaara2baa732022-02-04 16:09:54 +000063 b:asmsyntax = match
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010064 elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
Bram Moolenaara2baa732022-02-04 16:09:54 +000065 b:asmsyntax = "vmasm"
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010066 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +000067enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +010068
Doug Kearnsf97f6bb2023-08-27 18:44:09 +020069var ft_visual_basic_content = '\c^\s*\%(Attribute\s\+VB_Name\|Begin\s\+\%(VB\.\|{\%(\x\+-\)\+\x\+}\)\)'
Doug Kearnsc570e9c2022-01-31 17:09:14 +000070
Bram Moolenaara2baa732022-02-04 16:09:54 +000071# See FTfrm() for Visual Basic form file detection
72export def FTbas()
Bram Moolenaar6517f142022-01-21 14:55:13 +000073 if exists("g:filetype_bas")
Bram Moolenaara2baa732022-02-04 16:09:54 +000074 exe "setf " .. g:filetype_bas
Bram Moolenaar6517f142022-01-21 14:55:13 +000075 return
76 endif
77
Bram Moolenaara2baa732022-02-04 16:09:54 +000078 # most frequent FreeBASIC-specific keywords in distro files
79 var fb_keywords = '\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!'
Bram Moolenaar8b5901e2022-06-29 14:39:12 +010080 var fb_preproc = '\c^\s*\%(' ..
81 # preprocessor
82 '#\s*\a\+\|' ..
83 # compiler option
84 'option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\|' ..
85 # metacommand
86 '\%(''\|rem\)\s*\$lang\>\|' ..
87 # default datatype
88 'def\%(byte\|longint\|short\|ubyte\|uint\|ulongint\|ushort\)\>' ..
89 '\)'
Bram Moolenaara2baa732022-02-04 16:09:54 +000090 var fb_comment = "^\\s*/'"
Bram Moolenaar8b5901e2022-06-29 14:39:12 +010091
Bram Moolenaara2baa732022-02-04 16:09:54 +000092 # OPTION EXPLICIT, without the leading underscore, is common to many dialects
93 var qb64_preproc = '\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)'
Bram Moolenaar6517f142022-01-21 14:55:13 +000094
Bram Moolenaar8b5901e2022-06-29 14:39:12 +010095 for lnum in range(1, min([line("$"), 100]))
96 var line = getline(lnum)
97 if line =~ ft_visual_basic_content
98 setf vb
99 return
100 elseif line =~ fb_preproc || line =~ fb_comment || line =~ fb_keywords
101 setf freebasic
102 return
103 elseif line =~ qb64_preproc
104 setf qb64
105 return
106 endif
107 endfor
108 setf basic
Bram Moolenaara2baa732022-02-04 16:09:54 +0000109enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100110
Bram Moolenaara2baa732022-02-04 16:09:54 +0000111export def FTbtm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100112 if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
113 setf dosbatch
114 else
115 setf btm
116 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000117enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100118
Bram Moolenaara2baa732022-02-04 16:09:54 +0000119export def BindzoneCheck(default = '')
120 if getline(1) .. getline(2) .. getline(3) .. getline(4)
121 =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100122 setf bindzone
Bram Moolenaara2baa732022-02-04 16:09:54 +0000123 elseif default != ''
124 exe 'setf ' .. default
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100125 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000126enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100127
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100128# Returns true if file content looks like RAPID
129def IsRapid(sChkExt: string = ""): bool
130 if sChkExt == "cfg"
131 return getline(1) =~? '\v^%(EIO|MMC|MOC|PROC|SIO|SYS):CFG'
132 endif
133 # called from FTmod, FTprg or FTsys
134 return getline(nextnonblank(1)) =~? '\v^\s*%(\%{3}|module\s+\k+\s*%(\(|$))'
135enddef
136
137export def FTcfg()
138 if exists("g:filetype_cfg")
139 exe "setf " .. g:filetype_cfg
140 elseif IsRapid("cfg")
141 setf rapid
142 else
143 setf cfg
144 endif
145enddef
146
Bram Moolenaar8b5901e2022-06-29 14:39:12 +0100147export def FTcls()
148 if exists("g:filetype_cls")
149 exe "setf " .. g:filetype_cls
150 return
151 endif
152
Doug Kearnsf97f6bb2023-08-27 18:44:09 +0200153 var line1 = getline(1)
Doug Kearnse06afb72023-08-29 22:21:35 +0200154 if line1 =~ '^#!.*\<\%(rexx\|regina\)\>'
Bram Moolenaar8b5901e2022-06-29 14:39:12 +0100155 setf rexx
Doug Kearnse06afb72023-08-29 22:21:35 +0200156 return
Doug Kearnsf97f6bb2023-08-27 18:44:09 +0200157 elseif line1 == 'VERSION 1.0 CLASS'
Bram Moolenaar8b5901e2022-06-29 14:39:12 +0100158 setf vb
Doug Kearnse06afb72023-08-29 22:21:35 +0200159 return
160 endif
161
162 var nonblank1 = getline(nextnonblank(1))
163 if nonblank1 =~ '^\v%(\%|\\)'
164 setf tex
165 elseif nonblank1 =~ '^\s*\%(/\*\|::\w\)'
166 setf rexx
Bram Moolenaar8b5901e2022-06-29 14:39:12 +0100167 else
168 setf st
169 endif
170enddef
171
Wu, Zhenyubc32bbd2024-11-14 22:55:36 +0100172export def FTll()
173 if getline(1) =~ ';\|\<source_filename\>\|\<target\>'
174 setf llvm
175 else
176 setf lifelines
177 endif
178enddef
179
Bram Moolenaara2baa732022-02-04 16:09:54 +0000180export def FTlpc()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100181 if exists("g:lpc_syntax_for_c")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000182 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100183 while lnum <= 12
184 if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
185 setf lpc
186 return
187 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000188 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100189 endwhile
190 endif
191 setf c
Bram Moolenaara2baa732022-02-04 16:09:54 +0000192enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100193
Bram Moolenaara2baa732022-02-04 16:09:54 +0000194export def FTheader()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100195 if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
196 if exists("g:c_syntax_for_h")
197 setf objc
198 else
199 setf objcpp
200 endif
201 elseif exists("g:c_syntax_for_h")
202 setf c
203 elseif exists("g:ch_syntax_for_h")
204 setf ch
205 else
206 setf cpp
207 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000208enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100209
Bram Moolenaara2baa732022-02-04 16:09:54 +0000210# This function checks if one of the first ten lines start with a '@'. In
211# that case it is probably a change file.
212# If the first line starts with # or ! it's probably a ch file.
213# If a line has "main", "include", "//" or "/*" it's probably ch.
214# Otherwise CHILL is assumed.
215export def FTchange()
216 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100217 while lnum <= 10
218 if getline(lnum)[0] == '@'
219 setf change
220 return
221 endif
222 if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
223 setf ch
224 return
225 endif
226 if getline(lnum) =~ "MODULE"
227 setf chill
228 return
229 endif
230 if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
231 setf ch
232 return
233 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000234 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100235 endwhile
236 setf chill
Bram Moolenaara2baa732022-02-04 16:09:54 +0000237enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100238
Bram Moolenaara2baa732022-02-04 16:09:54 +0000239export def FTent()
240 # This function checks for valid cl syntax in the first five lines.
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100241 # Look for either an opening comment, '#', or a block start, '{'.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000242 # If not found, assume SGML.
243 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100244 while lnum < 6
Bram Moolenaara2baa732022-02-04 16:09:54 +0000245 var line = getline(lnum)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100246 if line =~ '^\s*[#{]'
247 setf cl
248 return
249 elseif line !~ '^\s*$'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000250 # Not a blank line, not a comment, and not a block start,
251 # so doesn't look like valid cl code.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100252 break
253 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000254 lnum += 1
Bram Moolenaarc12dc472022-03-05 13:45:56 +0000255 endwhile
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100256 setf dtd
Bram Moolenaara2baa732022-02-04 16:09:54 +0000257enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100258
Bram Moolenaara2baa732022-02-04 16:09:54 +0000259export def ExCheck()
260 var lines = getline(1, min([line("$"), 100]))
Austin Gatlinf3caeb62021-06-26 12:02:55 +0200261 if exists('g:filetype_euphoria')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000262 exe 'setf ' .. g:filetype_euphoria
Austin Gatlinf3caeb62021-06-26 12:02:55 +0200263 elseif match(lines, '^--\|^ifdef\>\|^include\>') > -1
264 setf euphoria3
265 else
266 setf elixir
267 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000268enddef
Austin Gatlinf3caeb62021-06-26 12:02:55 +0200269
Bram Moolenaara2baa732022-02-04 16:09:54 +0000270export def EuphoriaCheck()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100271 if exists('g:filetype_euphoria')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000272 exe 'setf ' .. g:filetype_euphoria
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100273 else
274 setf euphoria3
275 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000276enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100277
Bram Moolenaara2baa732022-02-04 16:09:54 +0000278export def DtraceCheck()
=?UTF-8?q?Teubel=20Gy=C3=B6rgy?=4d56b972022-02-24 17:59:09 +0000279 if did_filetype()
280 # Filetype was already detected
281 return
282 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000283 var lines = getline(1, min([line("$"), 100]))
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100284 if match(lines, '^module\>\|^import\>') > -1
Bram Moolenaara2baa732022-02-04 16:09:54 +0000285 # D files often start with a module and/or import statement.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100286 setf d
287 elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
288 setf dtrace
289 else
290 setf d
291 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000292enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100293
Doug Kearns68a89472024-01-05 17:59:04 +0100294export def FTdef()
Wu, Zhenyu61ee8332024-04-09 22:09:30 +0200295 # LaTeX def files are usually generated by docstrip, which will output '%%' in first line
296 if getline(1) =~ '%%'
297 setf tex
298 endif
Doug Kearns68a89472024-01-05 17:59:04 +0100299 if get(g:, "filetype_def", "") == "modula2" || IsModula2()
300 SetFiletypeModula2()
301 return
302 endif
303
304 if exists("g:filetype_def")
305 exe "setf " .. g:filetype_def
306 else
307 setf def
308 endif
309enddef
310
Bram Moolenaara2baa732022-02-04 16:09:54 +0000311export def FTe()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100312 if exists('g:filetype_euphoria')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000313 exe 'setf ' .. g:filetype_euphoria
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100314 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000315 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +0100316 while n < 100 && n <= line("$")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100317 if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
318 setf specman
319 return
320 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000321 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100322 endwhile
323 setf eiffel
324 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000325enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100326
Doug Kearns19a3bc32023-08-20 20:51:12 +0200327def IsForth(): bool
328 var first_line = nextnonblank(1)
329
330 # SwiftForth block comment (line is usually filled with '-' or '=') or
331 # OPTIONAL (sometimes precedes the header comment)
332 if getline(first_line) =~? '^\%({\%(\s\|$\)\|OPTIONAL\s\)'
333 return true
334 endif
335
336 var n = first_line
337 while n < 100 && n <= line("$")
338 # Forth comments and colon definitions
339 if getline(n) =~ '^[:(\\] '
340 return true
341 endif
342 n += 1
343 endwhile
344 return false
345enddef
346
347# Distinguish between Forth and Fortran
348export def FTf()
349 if exists("g:filetype_f")
350 exe "setf " .. g:filetype_f
351 elseif IsForth()
352 setf forth
353 else
354 setf fortran
355 endif
356enddef
357
Bram Moolenaara2baa732022-02-04 16:09:54 +0000358export def FTfrm()
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000359 if exists("g:filetype_frm")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000360 exe "setf " .. g:filetype_frm
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000361 return
362 endif
363
Doug Kearnsf97f6bb2023-08-27 18:44:09 +0200364 if getline(1) == "VERSION 5.00"
365 setf vb
366 return
367 endif
368
Bram Moolenaara2baa732022-02-04 16:09:54 +0000369 var lines = getline(1, min([line("$"), 5]))
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000370
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000371 if match(lines, ft_visual_basic_content) > -1
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000372 setf vb
373 else
374 setf form
375 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000376enddef
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000377
Doug Kearns19a3bc32023-08-20 20:51:12 +0200378# Distinguish between Forth and F#
Bram Moolenaara2baa732022-02-04 16:09:54 +0000379export def FTfs()
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000380 if exists("g:filetype_fs")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000381 exe "setf " .. g:filetype_fs
Doug Kearns19a3bc32023-08-20 20:51:12 +0200382 elseif IsForth()
383 setf forth
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000384 else
Johan Kotlinski065088d2023-04-02 20:29:38 +0100385 setf fsharp
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000386 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000387enddef
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000388
Amelia Clarke35dfe582024-05-24 08:05:00 +0200389# Recursively search for Hare source files in a directory and any
390# subdirectories, up to a given depth.
391def IsHareModule(dir: string, depth: number): bool
392 if depth <= 0
393 return !empty(glob(dir .. '/*.ha'))
394 endif
395
396 return reduce(sort(glob(dir .. '/*', true, true),
397 (a, b) => isdirectory(a) - isdirectory(b)),
398 (acc, n) => acc
399 || n =~ '\.ha$'
400 || isdirectory(n)
401 && IsHareModule(n, depth - 1),
402 false)
403enddef
404
405# Determine if a README file exists within a Hare module and should be given the
406# Haredoc filetype.
407export def FTharedoc()
408 if exists('g:filetype_haredoc')
409 if IsHareModule('<afile>:h', get(g:, 'haredoc_search_depth', 1))
410 setf haredoc
411 endif
412 endif
413enddef
414
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200415# Distinguish between HTML, XHTML, Django and Angular
Bram Moolenaara2baa732022-02-04 16:09:54 +0000416export def FThtml()
417 var n = 1
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200418
419 # Test if the filename follows the Angular component template convention
Christian Brabandtc03f6312024-07-10 19:23:39 +0200420 # Disabled for the reasons mentioned here: #13594
421 # if expand('%:t') =~ '^.*\.component\.html$'
422 # setf htmlangular
423 # return
424 # endif
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200425
Afiq Nazrie9718ed72024-06-18 19:59:53 +0200426 while n < 40 && n <= line("$")
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200427 # Check for Angular
428 if getline(n) =~ '@\(if\|for\|defer\|switch\)\|\*\(ngIf\|ngFor\|ngSwitch\|ngTemplateOutlet\)\|ng-template\|ng-content\|{{.*}}'
429 setf htmlangular
430 return
431 endif
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200432 # Check for XHTML
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100433 if getline(n) =~ '\<DTD\s\+XHTML\s'
434 setf xhtml
435 return
436 endif
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200437 # Check for Django
Afiq Nazrie9718ed72024-06-18 19:59:53 +0200438 if getline(n) =~ '{%\s*\(autoescape\|block\|comment\|csrf_token\|cycle\|debug\|extends\|filter\|firstof\|for\|if\|ifchanged\|include\|load\|lorem\|now\|query_string\|regroup\|resetcycle\|spaceless\|templatetag\|url\|verbatim\|widthratio\|with\)\>\|{#\s\+'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100439 setf htmldjango
440 return
441 endif
EliSaudere57c9a12024-07-28 21:28:11 +0200442 # Check for SuperHTML
443 if getline(n) =~ '<extend\|<super>'
444 setf superhtml
445 return
446 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000447 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100448 endwhile
Bram Moolenaar493fbe42019-03-17 17:16:12 +0100449 setf FALLBACK html
Bram Moolenaara2baa732022-02-04 16:09:54 +0000450enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100451
Bram Moolenaara2baa732022-02-04 16:09:54 +0000452# Distinguish between standard IDL and MS-IDL
453export def FTidl()
454 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +0100455 while n < 50 && n <= line("$")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100456 if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
457 setf msidl
458 return
459 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000460 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100461 endwhile
462 setf idl
Bram Moolenaara2baa732022-02-04 16:09:54 +0000463enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100464
Wu, Zhenyu887a38c2024-05-09 20:35:13 +0200465# Distinguish between "default", Prolog, zsh module's C and Cproto prototype file.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000466export def ProtoCheck(default: string)
Wu, Zhenyu887a38c2024-05-09 20:35:13 +0200467 # zsh modules use '#include "*.pro"'
468 # https://github.com/zsh-users/zsh/blob/63f086d167960a27ecdbcb762179e2c2bf8a29f5/Src/Modules/example.c#L31
469 if getline(1) =~ '/* Generated automatically */'
470 setf c
Bram Moolenaara2baa732022-02-04 16:09:54 +0000471 # Cproto files have a comment in the first line and a function prototype in
472 # the second line, it always ends in ";". Indent files may also have
473 # comments, thus we can't match comments to see the difference.
474 # IDL files can have a single ';' in the second line, require at least one
475 # chacter before the ';'.
Wu, Zhenyu887a38c2024-05-09 20:35:13 +0200476 elseif getline(2) =~ '.;$'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100477 setf cpp
478 else
Bram Moolenaar48c3f4e2022-08-08 15:42:38 +0100479 # recognize Prolog by specific text in the first non-empty line
480 # require a blank after the '%' because Perl uses "%list" and "%translate"
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100481 var lnum = getline(nextnonblank(1))
igna_martinoli37853b72024-07-18 21:34:36 +0200482 if lnum =~ '\<prolog\>' || lnum =~ prolog_pattern
Bram Moolenaar48c3f4e2022-08-08 15:42:38 +0100483 setf prolog
484 else
485 exe 'setf ' .. default
486 endif
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100487 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000488enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100489
Bram Moolenaara2baa732022-02-04 16:09:54 +0000490export def FTm()
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200491 if exists("g:filetype_m")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000492 exe "setf " .. g:filetype_m
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200493 return
494 endif
495
Bram Moolenaara2baa732022-02-04 16:09:54 +0000496 # excluding end(for|function|if|switch|while) common to Murphi
497 var octave_block_terminators = '\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>'
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200498
Bram Moolenaara2baa732022-02-04 16:09:54 +0000499 var objc_preprocessor = '^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>'
Doug Kearns7329cfa2021-11-26 13:01:41 +0000500
Bram Moolenaara2baa732022-02-04 16:09:54 +0000501 var n = 1
502 var saw_comment = 0 # Whether we've seen a multiline comment leader.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100503 while n < 100
Bram Moolenaara2baa732022-02-04 16:09:54 +0000504 var line = getline(n)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100505 if line =~ '^\s*/\*'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000506 # /* ... */ is a comment in Objective C and Murphi, so we can't conclude
507 # it's either of them yet, but track this as a hint in case we don't see
508 # anything more definitive.
509 saw_comment = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100510 endif
Doug Kearns7329cfa2021-11-26 13:01:41 +0000511 if line =~ '^\s*//' || line =~ '^\s*@import\>' || line =~ objc_preprocessor
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100512 setf objc
513 return
514 endif
Bram Moolenaarca0627d2021-09-12 17:03:08 +0200515 if line =~ '^\s*\%(#\|%!\)' || line =~ '^\s*unwind_protect\>' ||
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200516 \ line =~ '\%(^\|;\)\s*' .. octave_block_terminators
517 setf octave
518 return
519 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000520 # TODO: could be Matlab or Octave
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100521 if line =~ '^\s*%'
522 setf matlab
523 return
524 endif
525 if line =~ '^\s*(\*'
526 setf mma
527 return
528 endif
529 if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
530 setf murphi
531 return
532 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000533 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100534 endwhile
535
536 if saw_comment
Bram Moolenaara2baa732022-02-04 16:09:54 +0000537 # We didn't see anything definitive, but this looks like either Objective C
538 # or Murphi based on the comment leader. Assume the former as it is more
539 # common.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100540 setf objc
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100541 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000542 # Default is Matlab
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100543 setf matlab
544 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000545enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100546
Ken Takataeb4b9032024-07-25 21:07:13 +0200547export def FTmake()
548 # Check if it is a Microsoft Makefile
549 unlet! b:make_microsoft
550 var n = 1
551 while n < 1000 && n <= line('$')
552 var line = getline(n)
553 if line =~? '^\s*!\s*\(ifn\=\(def\)\=\|include\|message\|error\)\>'
554 b:make_microsoft = 1
555 break
556 elseif line =~ '^ *ifn\=\(eq\|def\)\>' || line =~ '^ *[-s]\=include\s'
557 break
558 elseif line =~ '^ *\w\+\s*[!?:+]='
559 break
560 endif
561 n += 1
562 endwhile
563 setf make
564enddef
565
Bram Moolenaara2baa732022-02-04 16:09:54 +0000566export def FTmms()
567 var n = 1
Bram Moolenaard7df2792020-01-02 21:34:42 +0100568 while n < 20
Bram Moolenaara2baa732022-02-04 16:09:54 +0000569 var line = getline(n)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100570 if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
571 setf mmix
572 return
573 endif
574 if line =~ '^\s*#'
575 setf make
576 return
577 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000578 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100579 endwhile
580 setf mmix
Bram Moolenaara2baa732022-02-04 16:09:54 +0000581enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100582
Bram Moolenaara2baa732022-02-04 16:09:54 +0000583# This function checks if one of the first five lines start with a dot. In
584# that case it is probably an nroff file: 'filetype' is set and 1 is returned.
585export def FTnroff(): number
586 if getline(1)[0] .. getline(2)[0] .. getline(3)[0]
587 .. getline(4)[0] .. getline(5)[0] =~ '\.'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100588 setf nroff
589 return 1
590 endif
591 return 0
Bram Moolenaara2baa732022-02-04 16:09:54 +0000592enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100593
Bram Moolenaara2baa732022-02-04 16:09:54 +0000594export def FTmm()
595 var n = 1
Bram Moolenaard1caa942020-04-10 22:10:56 +0200596 while n < 20
Bram Moolenaara2baa732022-02-04 16:09:54 +0000597 if getline(n) =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100598 setf objcpp
599 return
600 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000601 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100602 endwhile
603 setf nroff
Bram Moolenaara2baa732022-02-04 16:09:54 +0000604enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100605
Bram Moolenaarcdbfc6d2022-06-30 16:25:21 +0100606# Returns true if file content looks like LambdaProlog module
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100607def IsLProlog(): bool
Gaetan Lepage4ce1bda2023-05-10 22:01:55 +0100608 # skip apparent comments and blank lines, what looks like
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100609 # LambdaProlog comment may be RAPID header
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100610 var lnum: number = nextnonblank(1)
611 while lnum > 0 && lnum < line('$') && getline(lnum) =~ '^\s*%' # LambdaProlog comment
612 lnum = nextnonblank(lnum + 1)
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100613 endwhile
614 # this pattern must not catch a go.mod file
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100615 return getline(lnum) =~ '\<module\s\+\w\+\s*\.\s*\(%\|$\)'
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100616enddef
617
Doug Kearns68a89472024-01-05 17:59:04 +0100618def IsModula2(): bool
dkearnsef387c02024-02-20 06:58:30 +1100619 return getline(nextnonblank(1)) =~ '\<MODULE\s\+\w\+\s*\%(\[.*]\s*\)\=;\|^\s*(\*'
Doug Kearns68a89472024-01-05 17:59:04 +0100620enddef
621
622def SetFiletypeModula2()
623 const KNOWN_DIALECTS = ["iso", "pim", "r10"]
624 const KNOWN_EXTENSIONS = ["gm2"]
625 const LINE_COUNT = 200
626 const TAG = '(\*!m2\(\w\+\)\%(+\(\w\+\)\)\=\*)'
627
628 var dialect = get(g:, "modula2_default_dialect", "pim")
629 var extension = get(g:, "modula2_default_extension", "")
630
631 var matches = []
632
633 # ignore unknown dialects or badly formatted tags
634 for lnum in range(1, min([line("$"), LINE_COUNT]))
635 matches = matchlist(getline(lnum), TAG)
636 if !empty(matches)
637 if index(KNOWN_DIALECTS, matches[1]) >= 0
638 dialect = matches[1]
639 endif
640 if index(KNOWN_EXTENSIONS, matches[2]) >= 0
641 extension = matches[2]
642 endif
643 break
644 endif
645 endfor
646
647 modula2#SetDialect(dialect, extension)
648
649 setf modula2
650enddef
651
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100652# Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
653export def FTmod()
Doug Kearns68a89472024-01-05 17:59:04 +0100654 if get(g:, "filetype_mod", "") == "modula2" || IsModula2()
655 SetFiletypeModula2()
656 return
657 endif
658
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100659 if exists("g:filetype_mod")
660 exe "setf " .. g:filetype_mod
Omar El Halabic9fbd252023-05-29 19:59:45 +0100661 elseif expand("<afile>") =~ '\<go.mod$'
662 setf gomod
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100663 elseif IsLProlog()
664 setf lprolog
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100665 elseif IsRapid()
666 setf rapid
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100667 else
668 # Nothing recognized, assume modsim3
669 setf modsim3
670 endif
671enddef
672
Bram Moolenaara2baa732022-02-04 16:09:54 +0000673export def FTpl()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100674 if exists("g:filetype_pl")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000675 exe "setf " .. g:filetype_pl
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100676 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000677 # recognize Prolog by specific text in the first non-empty line
678 # require a blank after the '%' because Perl uses "%list" and "%translate"
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100679 var line = getline(nextnonblank(1))
igna_martinoli37853b72024-07-18 21:34:36 +0200680 if line =~ '\<prolog\>' || line =~ prolog_pattern
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100681 setf prolog
682 else
683 setf perl
684 endif
685 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000686enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100687
Bram Moolenaara2baa732022-02-04 16:09:54 +0000688export def FTinc()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100689 if exists("g:filetype_inc")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000690 exe "setf " .. g:filetype_inc
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100691 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000692 var lines = getline(1) .. getline(2) .. getline(3)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100693 if lines =~? "perlscript"
694 setf aspperl
695 elseif lines =~ "<%"
696 setf aspvbs
697 elseif lines =~ "<?"
698 setf php
Bram Moolenaara2baa732022-02-04 16:09:54 +0000699 # Pascal supports // comments but they're vary rarely used for file
700 # headers so assume POV-Ray
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000701 elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? ft_pascal_keywords
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100702 setf pascal
Gregory Anders30e212d2022-07-26 21:42:03 +0100703 elseif lines =~# '\<\%(require\|inherit\)\>' || lines =~# '[A-Z][A-Za-z0-9_:${}]*\s\+\%(??\|[?:+]\)\?= '
Gregory Andersfa49eb42022-07-16 17:46:47 +0100704 setf bitbake
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100705 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000706 FTasmsyntax()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100707 if exists("b:asmsyntax")
Gregory Andersfa49eb42022-07-16 17:46:47 +0100708 exe "setf " .. fnameescape(b:asmsyntax)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100709 else
Gregory Andersfa49eb42022-07-16 17:46:47 +0100710 setf pov
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100711 endif
712 endif
713 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000714enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100715
Bram Moolenaara2baa732022-02-04 16:09:54 +0000716export def FTprogress_cweb()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100717 if exists("g:filetype_w")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000718 exe "setf " .. g:filetype_w
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100719 return
720 endif
721 if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
722 setf progress
723 else
724 setf cweb
725 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000726enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100727
Julien Marrec2e310652023-11-25 15:30:46 +0100728# These include the leading '%' sign
729var ft_swig_keywords = '^\s*%\%(addmethods\|apply\|beginfile\|clear\|constant\|define\|echo\|enddef\|endoffile\|extend\|feature\|fragment\|ignore\|import\|importfile\|include\|includefile\|inline\|insert\|keyword\|module\|name\|namewarn\|native\|newobject\|parms\|pragma\|rename\|template\|typedef\|typemap\|types\|varargs\|warn\)'
730# This is the start/end of a block that is copied literally to the processor file (C/C++)
731var ft_swig_verbatim_block_start = '^\s*%{'
732
733export def FTi()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100734 if exists("g:filetype_i")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000735 exe "setf " .. g:filetype_i
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100736 return
737 endif
Julien Marrec2e310652023-11-25 15:30:46 +0100738 # This function checks for an assembly comment or a SWIG keyword or verbatim block in the first 50 lines.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000739 # If not found, assume Progress.
740 var lnum = 1
Julien Marrec2e310652023-11-25 15:30:46 +0100741 while lnum <= 50 && lnum < line('$')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000742 var line = getline(lnum)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100743 if line =~ '^\s*;' || line =~ '^\*'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000744 FTasm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100745 return
Julien Marrec2e310652023-11-25 15:30:46 +0100746 elseif line =~ ft_swig_keywords || line =~ ft_swig_verbatim_block_start
747 setf swig
748 return
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100749 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000750 lnum += 1
Bram Moolenaarc12dc472022-03-05 13:45:56 +0000751 endwhile
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100752 setf progress
Bram Moolenaara2baa732022-02-04 16:09:54 +0000753enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100754
Bram Moolenaara2baa732022-02-04 16:09:54 +0000755var ft_pascal_comments = '^\s*\%({\|(\*\|//\)'
756var ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>'
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100757
Bram Moolenaara2baa732022-02-04 16:09:54 +0000758export def FTprogress_pascal()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100759 if exists("g:filetype_p")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000760 exe "setf " .. g:filetype_p
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100761 return
762 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000763 # This function checks for valid Pascal syntax in the first ten lines.
764 # Look for either an opening comment or a program start.
765 # If not found, assume Progress.
766 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100767 while lnum <= 10 && lnum < line('$')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000768 var line = getline(lnum)
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000769 if line =~ ft_pascal_comments || line =~? ft_pascal_keywords
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100770 setf pascal
771 return
772 elseif line !~ '^\s*$' || line =~ '^/\*'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000773 # Not an empty line: Doesn't look like valid Pascal code.
774 # Or it looks like a Progress /* comment
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100775 break
776 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000777 lnum += 1
Bram Moolenaarc12dc472022-03-05 13:45:56 +0000778 endwhile
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100779 setf progress
Bram Moolenaara2baa732022-02-04 16:09:54 +0000780enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100781
Bram Moolenaara2baa732022-02-04 16:09:54 +0000782export def FTpp()
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100783 if exists("g:filetype_pp")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000784 exe "setf " .. g:filetype_pp
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100785 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000786 var line = getline(nextnonblank(1))
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000787 if line =~ ft_pascal_comments || line =~? ft_pascal_keywords
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100788 setf pascal
789 else
790 setf puppet
791 endif
792 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000793enddef
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100794
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100795# Determine if *.prg is ABB RAPID. Can also be Clipper, FoxPro or eviews
796export def FTprg()
797 if exists("g:filetype_prg")
798 exe "setf " .. g:filetype_prg
799 elseif IsRapid()
800 setf rapid
801 else
802 # Nothing recognized, assume Clipper
803 setf clipper
804 endif
805enddef
806
Bram Moolenaara2baa732022-02-04 16:09:54 +0000807export def FTr()
808 var max = line("$") > 50 ? 50 : line("$")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100809
810 for n in range(1, max)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000811 # Rebol is easy to recognize, check for that first
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100812 if getline(n) =~? '\<REBOL\>'
813 setf rebol
814 return
815 endif
816 endfor
817
818 for n in range(1, max)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000819 # R has # comments
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100820 if getline(n) =~ '^\s*#'
821 setf r
822 return
823 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000824 # Rexx has /* comments */
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100825 if getline(n) =~ '^\s*/\*'
826 setf rexx
827 return
828 endif
829 endfor
830
Bram Moolenaara2baa732022-02-04 16:09:54 +0000831 # Nothing recognized, use user default or assume Rexx
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100832 if exists("g:filetype_r")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000833 exe "setf " .. g:filetype_r
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100834 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000835 # Rexx used to be the default, but R appears to be much more popular.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100836 setf r
837 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000838enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100839
Bram Moolenaara2baa732022-02-04 16:09:54 +0000840export def McSetf()
841 # Rely on the file to start with a comment.
842 # MS message text files use ';', Sendmail files use '#' or 'dnl'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100843 for lnum in range(1, min([line("$"), 20]))
Bram Moolenaara2baa732022-02-04 16:09:54 +0000844 var line = getline(lnum)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100845 if line =~ '^\s*\(#\|dnl\)'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000846 setf m4 # Sendmail .mc file
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100847 return
848 elseif line =~ '^\s*;'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000849 setf msmessages # MS Message text file
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100850 return
851 endif
852 endfor
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100853 setf m4 # Default: Sendmail .mc file
Bram Moolenaara2baa732022-02-04 16:09:54 +0000854enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100855
Bram Moolenaara2baa732022-02-04 16:09:54 +0000856# Called from filetype.vim and scripts.vim.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100857# When "setft" is passed and false then the 'filetype' option is not set.
858export def SetFileTypeSH(name: string, setft = true): string
859 if setft && did_filetype()
Bram Moolenaara2baa732022-02-04 16:09:54 +0000860 # Filetype was already detected
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100861 return ''
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100862 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100863 if setft && expand("<amatch>") =~ g:ft_ignore_pat
864 return ''
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100865 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000866 if name =~ '\<csh\>'
867 # Some .sh scripts contain #!/bin/csh.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100868 return SetFileTypeShell("csh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000869 elseif name =~ '\<tcsh\>'
870 # Some .sh scripts contain #!/bin/tcsh.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100871 return SetFileTypeShell("tcsh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000872 elseif name =~ '\<zsh\>'
873 # Some .sh scripts contain #!/bin/zsh.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100874 return SetFileTypeShell("zsh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000875 elseif name =~ '\<ksh\>'
876 b:is_kornshell = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100877 if exists("b:is_bash")
878 unlet b:is_bash
879 endif
880 if exists("b:is_sh")
881 unlet b:is_sh
882 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000883 elseif exists("g:bash_is_sh") || name =~ '\<bash\>' || name =~ '\<bash2\>'
884 b:is_bash = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100885 if exists("b:is_kornshell")
886 unlet b:is_kornshell
887 endif
888 if exists("b:is_sh")
889 unlet b:is_sh
890 endif
Eisuke Kawashima24482fb2022-11-24 10:58:10 +0000891 elseif name =~ '\<sh\>' || name =~ '\<dash\>'
892 # Ubuntu links "sh" to "dash", thus it is expected to work the same way
Bram Moolenaara2baa732022-02-04 16:09:54 +0000893 b:is_sh = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100894 if exists("b:is_kornshell")
895 unlet b:is_kornshell
896 endif
897 if exists("b:is_bash")
898 unlet b:is_bash
899 endif
900 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100901
902 return SetFileTypeShell("sh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000903enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100904
Bram Moolenaara2baa732022-02-04 16:09:54 +0000905# For shell-like file types, check for an "exec" command hidden in a comment,
906# as used for Tcl.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100907# When "setft" is passed and false then the 'filetype' option is not set.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000908# Also called from scripts.vim, thus can't be local to this script.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100909export def SetFileTypeShell(name: string, setft = true): string
910 if setft && did_filetype()
Bram Moolenaara2baa732022-02-04 16:09:54 +0000911 # Filetype was already detected
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100912 return ''
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100913 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100914 if setft && expand("<amatch>") =~ g:ft_ignore_pat
915 return ''
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100916 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100917
918 var lnum = 2
919 while lnum < 20 && lnum < line("$") && getline(lnum) =~ '^\s*\(#\|$\)'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000920 # Skip empty and comment lines.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100921 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100922 endwhile
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100923 if lnum < line("$") && getline(lnum) =~ '\s*exec\s' && getline(lnum - 1) =~ '^\s*#.*\\$'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000924 # Found an "exec" line after a comment with continuation
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100925 var n = substitute(getline(lnum), '\s*exec\s\+\([^ ]*/\)\=', '', '')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100926 if n =~ '\<tclsh\|\<wish'
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100927 if setft
928 setf tcl
929 endif
930 return 'tcl'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100931 endif
932 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100933
934 if setft
935 exe "setf " .. name
936 endif
937 return name
Bram Moolenaara2baa732022-02-04 16:09:54 +0000938enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100939
Bram Moolenaara2baa732022-02-04 16:09:54 +0000940export def CSH()
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100941 if did_filetype()
Bram Moolenaara2baa732022-02-04 16:09:54 +0000942 # Filetype was already detected
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100943 return
944 endif
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100945 if exists("g:filetype_csh")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000946 SetFileTypeShell(g:filetype_csh)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100947 elseif &shell =~ "tcsh"
Bram Moolenaara2baa732022-02-04 16:09:54 +0000948 SetFileTypeShell("tcsh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100949 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000950 SetFileTypeShell("csh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100951 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000952enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100953
Bram Moolenaara2baa732022-02-04 16:09:54 +0000954var ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
955export def FTRules()
956 var path = expand('<amatch>:p')
Bram Moolenaaraa9675a2020-08-17 21:57:09 +0200957 if path =~ '/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|\%(usr/\)\=lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100958 setf udevrules
959 return
960 endif
961 if path =~ '^/etc/ufw/'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000962 setf conf # Better than hog
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100963 return
964 endif
965 if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
966 setf javascript
967 return
968 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000969 var config_lines: list<string>
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100970 try
Bram Moolenaara2baa732022-02-04 16:09:54 +0000971 config_lines = readfile('/etc/udev/udev.conf')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100972 catch /^Vim\%((\a\+)\)\=:E484/
973 setf hog
974 return
975 endtry
Bram Moolenaara2baa732022-02-04 16:09:54 +0000976 var dir = expand('<amatch>:p:h')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100977 for line in config_lines
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000978 if line =~ ft_rules_udev_rules_pattern
979 var udev_rules = substitute(line, ft_rules_udev_rules_pattern, '\1', "")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100980 if dir == udev_rules
981 setf udevrules
982 endif
983 break
984 endif
985 endfor
986 setf hog
Bram Moolenaara2baa732022-02-04 16:09:54 +0000987enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100988
Bram Moolenaara2baa732022-02-04 16:09:54 +0000989export def SQL()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100990 if exists("g:filetype_sql")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000991 exe "setf " .. g:filetype_sql
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100992 else
993 setf sql
994 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000995enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100996
ranjithshegde8cac20e2022-04-13 15:29:21 +0100997# This function checks the first 25 lines of file extension "sc" to resolve
Chris Kipp70ef3f52022-12-14 16:42:15 +0000998# detection between scala and SuperCollider.
999# NOTE: We don't check for 'Class : Method', as this can easily be confused
1000# with valid Scala like `val x : Int = 3`. So we instead only rely on
1001# checks that can't be confused.
ranjithshegde8cac20e2022-04-13 15:29:21 +01001002export def FTsc()
1003 for lnum in range(1, min([line("$"), 25]))
Chris Kipp70ef3f52022-12-14 16:42:15 +00001004 if getline(lnum) =~# 'var\s<\|classvar\s<\|\^this.*\||\w\+|\|+\s\w*\s{\|\*ar\s'
ranjithshegde8cac20e2022-04-13 15:29:21 +01001005 setf supercollider
1006 return
1007 endif
1008 endfor
1009 setf scala
1010enddef
1011
1012# This function checks the first line of file extension "scd" to resolve
1013# detection between scdoc and SuperCollider
1014export def FTscd()
1015 if getline(1) =~# '\%^\S\+(\d[0-9A-Za-z]*)\%(\s\+\"[^"]*\"\%(\s\+\"[^"]*\"\)\=\)\=$'
1016 setf scdoc
1017 else
1018 setf supercollider
1019 endif
1020enddef
1021
Bram Moolenaara2baa732022-02-04 16:09:54 +00001022# If the file has an extension of 't' and is in a directory 't' or 'xt' then
1023# it is almost certainly a Perl test file.
1024# If the first line starts with '#' and contains 'perl' it's probably a Perl
1025# file.
1026# (Slow test) If a file contains a 'use' statement then it is almost certainly
1027# a Perl file.
1028export def FTperl(): number
1029 var dirname = expand("%:p:h:t")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001030 if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
1031 setf perl
1032 return 1
1033 endif
1034 if getline(1)[0] == '#' && getline(1) =~ 'perl'
1035 setf perl
1036 return 1
1037 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001038 var save_cursor = getpos('.')
1039 call cursor(1, 1)
Bram Moolenaare5b78972022-02-05 19:50:34 +00001040 var has_use = search('^use\s\s*\k', 'c', 30) > 0
Bram Moolenaarf0b03c42017-12-17 17:17:07 +01001041 call setpos('.', save_cursor)
1042 if has_use
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001043 setf perl
1044 return 1
1045 endif
1046 return 0
Bram Moolenaara2baa732022-02-04 16:09:54 +00001047enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001048
Bram Moolenaarcdbfc6d2022-06-30 16:25:21 +01001049# LambdaProlog and Standard ML signature files
1050export def FTsig()
1051 if exists("g:filetype_sig")
1052 exe "setf " .. g:filetype_sig
1053 return
1054 endif
1055
1056 var lprolog_comment = '^\s*\%(/\*\|%\)'
1057 var lprolog_keyword = '^\s*sig\s\+\a'
1058 var sml_comment = '^\s*(\*'
1059 var sml_keyword = '^\s*\%(signature\|structure\)\s\+\a'
1060
1061 var line = getline(nextnonblank(1))
1062
1063 if line =~ lprolog_comment || line =~# lprolog_keyword
1064 setf lprolog
1065 elseif line =~ sml_comment || line =~# sml_keyword
1066 setf sml
1067 endif
1068enddef
1069
Bram Moolenaarbe807d52022-09-01 15:01:25 +01001070# This function checks the first 100 lines of files matching "*.sil" to
1071# resolve detection between Swift Intermediate Language and SILE.
1072export def FTsil()
1073 for lnum in range(1, [line('$'), 100]->min())
1074 var line: string = getline(lnum)
1075 if line =~ '^\s*[\\%]'
1076 setf sile
1077 return
1078 elseif line =~ '^\s*\S'
1079 setf sil
1080 return
1081 endif
1082 endfor
1083 # no clue, default to "sil"
1084 setf sil
1085enddef
1086
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +01001087export def FTsys()
KnoP-01f420ff22022-04-13 20:46:21 +01001088 if exists("g:filetype_sys")
1089 exe "setf " .. g:filetype_sys
1090 elseif IsRapid()
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +01001091 setf rapid
1092 else
1093 setf bat
1094 endif
1095enddef
1096
Bram Moolenaara2baa732022-02-04 16:09:54 +00001097# Choose context, plaintex, or tex (LaTeX) based on these rules:
1098# 1. Check the first line of the file for "%&<format>".
1099# 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
1100# 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
1101export def FTtex()
1102 var firstline = getline(1)
1103 var format: string
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001104 if firstline =~ '^%&\s*\a\+'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001105 format = tolower(matchstr(firstline, '\a\+'))
1106 format = substitute(format, 'pdf', '', '')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001107 if format == 'tex'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001108 format = 'latex'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001109 elseif format == 'plaintex'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001110 format = 'plain'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001111 endif
1112 elseif expand('%') =~ 'tex/context/.*/.*.tex'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001113 format = 'context'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001114 else
Bram Moolenaara2baa732022-02-04 16:09:54 +00001115 # Default value, may be changed later:
1116 format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
1117 # Save position, go to the top of the file, find first non-comment line.
1118 var save_cursor = getpos('.')
1119 call cursor(1, 1)
1120 var firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
Bram Moolenaare5b78972022-02-05 19:50:34 +00001121 if firstNC > 0
1122 # Check the next thousand lines for a LaTeX or ConTeXt keyword.
Bram Moolenaara2baa732022-02-04 16:09:54 +00001123 var lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
1124 var 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\>'
1125 var kwline = search('^\s*\\\%(' .. lpat .. '\)\|^\s*\\\(' .. cpat .. '\)',
1126 'cnp', firstNC + 1000)
1127 if kwline == 1 # lpat matched
1128 format = 'latex'
1129 elseif kwline == 2 # cpat matched
1130 format = 'context'
1131 endif # If neither matched, keep default set above.
1132 # let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
1133 # let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
1134 # if cline > 0
1135 # let format = 'context'
1136 # endif
1137 # if lline > 0 && (cline == 0 || cline > lline)
1138 # let format = 'tex'
1139 # endif
1140 endif # firstNC
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001141 call setpos('.', save_cursor)
Bram Moolenaara2baa732022-02-04 16:09:54 +00001142 endif # firstline =~ '^%&\s*\a\+'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001143
Bram Moolenaara2baa732022-02-04 16:09:54 +00001144 # Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001145 if format == 'plain'
1146 setf plaintex
1147 elseif format == 'context'
1148 setf context
Bram Moolenaara2baa732022-02-04 16:09:54 +00001149 else # probably LaTeX
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001150 setf tex
1151 endif
1152 return
Bram Moolenaara2baa732022-02-04 16:09:54 +00001153enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001154
Bram Moolenaara2baa732022-02-04 16:09:54 +00001155export def FTxml()
1156 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +01001157 while n < 100 && n <= line("$")
Bram Moolenaara2baa732022-02-04 16:09:54 +00001158 var line = getline(n)
1159 # DocBook 4 or DocBook 5.
1160 var is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
1161 var is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001162 if is_docbook4 || is_docbook5
Bram Moolenaara2baa732022-02-04 16:09:54 +00001163 b:docbk_type = "xml"
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001164 if is_docbook5
Bram Moolenaara2baa732022-02-04 16:09:54 +00001165 b:docbk_ver = 5
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001166 else
Bram Moolenaara2baa732022-02-04 16:09:54 +00001167 b:docbk_ver = 4
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001168 endif
1169 setf docbk
1170 return
1171 endif
1172 if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
1173 setf xbl
1174 return
1175 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001176 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001177 endwhile
1178 setf xml
Bram Moolenaara2baa732022-02-04 16:09:54 +00001179enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001180
Bram Moolenaara2baa732022-02-04 16:09:54 +00001181export def FTy()
1182 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +01001183 while n < 100 && n <= line("$")
Bram Moolenaara2baa732022-02-04 16:09:54 +00001184 var line = getline(n)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001185 if line =~ '^\s*%'
1186 setf yacc
1187 return
1188 endif
1189 if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
1190 setf racc
1191 return
1192 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001193 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001194 endwhile
1195 setf yacc
Bram Moolenaara2baa732022-02-04 16:09:54 +00001196enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001197
Bram Moolenaara2baa732022-02-04 16:09:54 +00001198export def Redif()
1199 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001200 while lnum <= 5 && lnum < line('$')
1201 if getline(lnum) =~ "^\ctemplate-type:"
1202 setf redif
1203 return
1204 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001205 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001206 endwhile
Bram Moolenaara2baa732022-02-04 16:09:54 +00001207enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001208
Bram Moolenaara2baa732022-02-04 16:09:54 +00001209# This function is called for all files under */debian/patches/*, make sure not
1210# to non-dep3patch files, such as README and other text files.
1211export def Dep3patch()
James McCoy647ab4c2021-12-17 20:52:57 +00001212 if expand('%:t') ==# 'series'
1213 return
1214 endif
1215
1216 for ln in getline(1, 100)
1217 if ln =~# '^\%(Description\|Subject\|Origin\|Bug\|Forwarded\|Author\|From\|Reviewed-by\|Acked-by\|Last-Updated\|Applied-Upstream\):'
1218 setf dep3patch
1219 return
1220 elseif ln =~# '^---'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001221 # end of headers found. stop processing
James McCoy647ab4c2021-12-17 20:52:57 +00001222 return
1223 endif
1224 endfor
Bram Moolenaara2baa732022-02-04 16:09:54 +00001225enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001226
Bram Moolenaara2baa732022-02-04 16:09:54 +00001227# This function checks the first 15 lines for appearance of 'FoamFile'
1228# and then 'object' in a following line.
1229# In that case, it's probably an OpenFOAM file
1230export def FTfoam()
1231 var ffile = 0
1232 var lnum = 1
Elwardi2284f6c2022-01-11 18:14:23 +00001233 while lnum <= 15
1234 if getline(lnum) =~# '^FoamFile'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001235 ffile = 1
Elwardi2284f6c2022-01-11 18:14:23 +00001236 elseif ffile == 1 && getline(lnum) =~# '^\s*object'
1237 setf foam
1238 return
1239 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001240 lnum += 1
Elwardi2284f6c2022-01-11 18:14:23 +00001241 endwhile
Bram Moolenaara2baa732022-02-04 16:09:54 +00001242enddef
Elwardi2284f6c2022-01-11 18:14:23 +00001243
Bram Moolenaara2baa732022-02-04 16:09:54 +00001244# Determine if a *.tf file is TF mud client or terraform
1245export def FTtf()
1246 var numberOfLines = line('$')
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001247 for i in range(1, numberOfLines)
Bram Moolenaara2baa732022-02-04 16:09:54 +00001248 var currentLine = trim(getline(i))
1249 var firstCharacter = currentLine[0]
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001250 if firstCharacter !=? ";" && firstCharacter !=? "/" && firstCharacter !=? ""
1251 setf terraform
1252 return
1253 endif
1254 endfor
1255 setf tf
Bram Moolenaara2baa732022-02-04 16:09:54 +00001256enddef
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001257
KnoP-0193c7a452022-04-16 21:14:04 +01001258var ft_krl_header = '\&\w+'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001259# Determine if a *.src file is Kuka Robot Language
1260export def FTsrc()
KnoP-0193c7a452022-04-16 21:14:04 +01001261 var ft_krl_def_or_deffct = '%(global\s+)?def%(fct)?>'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001262 if exists("g:filetype_src")
1263 exe "setf " .. g:filetype_src
KnoP-0193c7a452022-04-16 21:14:04 +01001264 elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. ft_krl_header .. '|' .. ft_krl_def_or_deffct .. ')'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001265 setf krl
1266 endif
1267enddef
1268
1269# Determine if a *.dat file is Kuka Robot Language
1270export def FTdat()
KnoP-0193c7a452022-04-16 21:14:04 +01001271 var ft_krl_defdat = 'defdat>'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001272 if exists("g:filetype_dat")
1273 exe "setf " .. g:filetype_dat
KnoP-0193c7a452022-04-16 21:14:04 +01001274 elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. ft_krl_header .. '|' .. ft_krl_defdat .. ')'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001275 setf krl
1276 endif
1277enddef
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001278
Doug Kearns4ac8e792022-10-17 13:32:17 +01001279export def FTlsl()
1280 if exists("g:filetype_lsl")
1281 exe "setf " .. g:filetype_lsl
1282 endif
1283
1284 var line = getline(nextnonblank(1))
1285 if line =~ '^\s*%' || line =~# ':\s*trait\s*$'
1286 setf larch
1287 else
1288 setf lsl
1289 endif
1290enddef
1291
Gaetan Lepage4ce1bda2023-05-10 22:01:55 +01001292export def FTtyp()
1293 if exists("g:filetype_typ")
1294 exe "setf " .. g:filetype_typ
1295 return
1296 endif
1297
1298 # Look for SQL type definition syntax
1299 for line in getline(1, 200)
1300 # SQL type files may define the casing
1301 if line =~ '^CASE\s\==\s\=\(SAME\|LOWER\|UPPER\|OPPOSITE\)$'
1302 setf sql
1303 return
1304 endif
1305
1306 # SQL type files may define some types as follows
1307 if line =~ '^TYPE\s.*$'
1308 setf sql
1309 return
1310 endif
1311 endfor
1312
1313 # Otherwise, affect the typst filetype
1314 setf typst
1315enddef
1316
PowerUser64aa61b8a2024-06-19 20:32:11 +02001317# Detect Microsoft Developer Studio Project files (Makefile) or Faust DSP
1318# files.
1319export def FTdsp()
1320 if exists("g:filetype_dsp")
1321 exe "setf " .. g:filetype_dsp
1322 return
1323 endif
1324
1325 # Test the filename
1326 if expand('%:t') =~ '^[mM]akefile.*$'
1327 setf make
1328 return
1329 endif
1330
1331 # Test the file contents
1332 for line in getline(1, 200)
1333 # Chech for comment style
1334 if line =~ '^#.*'
1335 setf make
1336 return
1337 endif
1338
1339 # Check for common lines
1340 if line =~ '^.*Microsoft Developer Studio Project File.*$'
1341 setf make
1342 return
1343 endif
1344
1345 if line =~ '^!MESSAGE This is not a valid makefile\..+$'
1346 setf make
1347 return
1348 endif
1349
1350 # Check for keywords
1351 if line =~ '^!(IF,ELSEIF,ENDIF).*$'
1352 setf make
1353 return
1354 endif
1355
1356 # Check for common assignments
1357 if line =~ '^SOURCE=.*$'
1358 setf make
1359 return
1360 endif
1361 endfor
1362
1363 # Otherwise, assume we have a Faust file
1364 setf faust
1365enddef
1366
Turiiya80406c22023-04-22 21:38:47 +01001367# Set the filetype of a *.v file to Verilog, V or Cog based on the first 200
1368# lines.
1369export def FTv()
1370 if did_filetype()
1371 # ":setf" will do nothing, bail out early
1372 return
1373 endif
Christian Brabandt10b4f752024-01-01 19:19:20 +01001374 if exists("g:filetype_v")
1375 exe "setf " .. g:filetype_v
1376 return
1377 endif
Turiiya80406c22023-04-22 21:38:47 +01001378
Christian Brabandt10b4f752024-01-01 19:19:20 +01001379 var in_comment = 0
1380 for lnum in range(1, min([line("$"), 200]))
1381 var line = getline(lnum)
1382 # Skip Verilog and V comments (lines and blocks).
1383 if line =~ '^\s*/\*'
1384 # start comment block
1385 in_comment = 1
1386 endif
1387 if in_comment == 1
1388 if line =~ '\*/'
1389 # end comment block
1390 in_comment = 0
1391 endif
1392 # skip comment-block line
1393 continue
1394 endif
1395 if line =~ '^\s*//'
Turiiya80406c22023-04-22 21:38:47 +01001396 # skip comment line
1397 continue
1398 endif
1399
Christian Brabandt10b4f752024-01-01 19:19:20 +01001400 # Coq: line ends with a '.' followed by an optional variable number of
1401 # spaces or contains the start of a comment, but not inside a Verilog or V
1402 # comment.
1403 # Example: "Definition x := 10. (*".
1404 if (line =~ '\.\s*$' && line !~ '/[/*]') || (line =~ '(\*' && line !~ '/[/*].*(\*')
1405 setf coq
1406 return
1407 endif
1408
Turiiya80406c22023-04-22 21:38:47 +01001409 # Verilog: line ends with ';' followed by an optional variable number of
1410 # spaces and an optional start of a comment.
1411 # Example: " b <= a + 1; // Add 1".
Christian Brabandt10b4f752024-01-01 19:19:20 +01001412 if line =~ ';\s*\(/[/*].*\)\?$'
Turiiya80406c22023-04-22 21:38:47 +01001413 setf verilog
1414 return
1415 endif
Turiiya80406c22023-04-22 21:38:47 +01001416 endfor
1417
1418 # No line matched, fall back to "v".
1419 setf v
1420enddef
1421
Doug Kearnsf97f6bb2023-08-27 18:44:09 +02001422export def FTvba()
1423 if getline(1) =~ '^["#] Vimball Archiver'
1424 setf vim
1425 else
1426 setf vb
1427 endif
1428enddef
1429
Colin Caine4b3fab12024-04-18 23:53:02 +02001430export def Detect_UCI_statements(): bool
1431 # Match a config or package statement at the start of the line.
1432 const config_or_package_statement = '^\s*\(\(c\|config\)\|\(p\|package\)\)\s\+\S'
1433 # Match a line that is either all blank or blank followed by a comment
1434 const comment_or_blank = '^\s*\(#.*\)\?$'
1435
1436 # Return true iff the file has a config or package statement near the
1437 # top of the file and all preceding lines were comments or blank.
1438 return getline(1) =~# config_or_package_statement
1439 \ || getline(1) =~# comment_or_blank
1440 \ && ( getline(2) =~# config_or_package_statement
1441 \ || getline(2) =~# comment_or_blank
1442 \ && getline(3) =~# config_or_package_statement
1443 \ )
1444enddef
1445
Bram Moolenaara2baa732022-02-04 16:09:54 +00001446# Uncomment this line to check for compilation errors early
dkearnsef387c02024-02-20 06:58:30 +11001447# defcompile