blob: c8942eb3d114a589cfb8815d366b3b529c8c8e38 [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
Bram Moolenaara2baa732022-02-04 16:09:54 +0000172export def FTlpc()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100173 if exists("g:lpc_syntax_for_c")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000174 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100175 while lnum <= 12
176 if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
177 setf lpc
178 return
179 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000180 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100181 endwhile
182 endif
183 setf c
Bram Moolenaara2baa732022-02-04 16:09:54 +0000184enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100185
Bram Moolenaara2baa732022-02-04 16:09:54 +0000186export def FTheader()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100187 if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
188 if exists("g:c_syntax_for_h")
189 setf objc
190 else
191 setf objcpp
192 endif
193 elseif exists("g:c_syntax_for_h")
194 setf c
195 elseif exists("g:ch_syntax_for_h")
196 setf ch
197 else
198 setf cpp
199 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000200enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100201
Bram Moolenaara2baa732022-02-04 16:09:54 +0000202# This function checks if one of the first ten lines start with a '@'. In
203# that case it is probably a change file.
204# If the first line starts with # or ! it's probably a ch file.
205# If a line has "main", "include", "//" or "/*" it's probably ch.
206# Otherwise CHILL is assumed.
207export def FTchange()
208 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100209 while lnum <= 10
210 if getline(lnum)[0] == '@'
211 setf change
212 return
213 endif
214 if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
215 setf ch
216 return
217 endif
218 if getline(lnum) =~ "MODULE"
219 setf chill
220 return
221 endif
222 if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
223 setf ch
224 return
225 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000226 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100227 endwhile
228 setf chill
Bram Moolenaara2baa732022-02-04 16:09:54 +0000229enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100230
Bram Moolenaara2baa732022-02-04 16:09:54 +0000231export def FTent()
232 # This function checks for valid cl syntax in the first five lines.
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100233 # Look for either an opening comment, '#', or a block start, '{'.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000234 # If not found, assume SGML.
235 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100236 while lnum < 6
Bram Moolenaara2baa732022-02-04 16:09:54 +0000237 var line = getline(lnum)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100238 if line =~ '^\s*[#{]'
239 setf cl
240 return
241 elseif line !~ '^\s*$'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000242 # Not a blank line, not a comment, and not a block start,
243 # so doesn't look like valid cl code.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100244 break
245 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000246 lnum += 1
Bram Moolenaarc12dc472022-03-05 13:45:56 +0000247 endwhile
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100248 setf dtd
Bram Moolenaara2baa732022-02-04 16:09:54 +0000249enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100250
Bram Moolenaara2baa732022-02-04 16:09:54 +0000251export def ExCheck()
252 var lines = getline(1, min([line("$"), 100]))
Austin Gatlinf3caeb62021-06-26 12:02:55 +0200253 if exists('g:filetype_euphoria')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000254 exe 'setf ' .. g:filetype_euphoria
Austin Gatlinf3caeb62021-06-26 12:02:55 +0200255 elseif match(lines, '^--\|^ifdef\>\|^include\>') > -1
256 setf euphoria3
257 else
258 setf elixir
259 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000260enddef
Austin Gatlinf3caeb62021-06-26 12:02:55 +0200261
Bram Moolenaara2baa732022-02-04 16:09:54 +0000262export def EuphoriaCheck()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100263 if exists('g:filetype_euphoria')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000264 exe 'setf ' .. g:filetype_euphoria
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100265 else
266 setf euphoria3
267 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000268enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100269
Bram Moolenaara2baa732022-02-04 16:09:54 +0000270export def DtraceCheck()
=?UTF-8?q?Teubel=20Gy=C3=B6rgy?=4d56b972022-02-24 17:59:09 +0000271 if did_filetype()
272 # Filetype was already detected
273 return
274 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000275 var lines = getline(1, min([line("$"), 100]))
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100276 if match(lines, '^module\>\|^import\>') > -1
Bram Moolenaara2baa732022-02-04 16:09:54 +0000277 # D files often start with a module and/or import statement.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100278 setf d
279 elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
280 setf dtrace
281 else
282 setf d
283 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000284enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100285
Doug Kearns68a89472024-01-05 17:59:04 +0100286export def FTdef()
Wu, Zhenyu61ee8332024-04-09 22:09:30 +0200287 # LaTeX def files are usually generated by docstrip, which will output '%%' in first line
288 if getline(1) =~ '%%'
289 setf tex
290 endif
Doug Kearns68a89472024-01-05 17:59:04 +0100291 if get(g:, "filetype_def", "") == "modula2" || IsModula2()
292 SetFiletypeModula2()
293 return
294 endif
295
296 if exists("g:filetype_def")
297 exe "setf " .. g:filetype_def
298 else
299 setf def
300 endif
301enddef
302
Bram Moolenaara2baa732022-02-04 16:09:54 +0000303export def FTe()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100304 if exists('g:filetype_euphoria')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000305 exe 'setf ' .. g:filetype_euphoria
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100306 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000307 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +0100308 while n < 100 && n <= line("$")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100309 if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
310 setf specman
311 return
312 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000313 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100314 endwhile
315 setf eiffel
316 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000317enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100318
Doug Kearns19a3bc32023-08-20 20:51:12 +0200319def IsForth(): bool
320 var first_line = nextnonblank(1)
321
322 # SwiftForth block comment (line is usually filled with '-' or '=') or
323 # OPTIONAL (sometimes precedes the header comment)
324 if getline(first_line) =~? '^\%({\%(\s\|$\)\|OPTIONAL\s\)'
325 return true
326 endif
327
328 var n = first_line
329 while n < 100 && n <= line("$")
330 # Forth comments and colon definitions
331 if getline(n) =~ '^[:(\\] '
332 return true
333 endif
334 n += 1
335 endwhile
336 return false
337enddef
338
339# Distinguish between Forth and Fortran
340export def FTf()
341 if exists("g:filetype_f")
342 exe "setf " .. g:filetype_f
343 elseif IsForth()
344 setf forth
345 else
346 setf fortran
347 endif
348enddef
349
Bram Moolenaara2baa732022-02-04 16:09:54 +0000350export def FTfrm()
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000351 if exists("g:filetype_frm")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000352 exe "setf " .. g:filetype_frm
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000353 return
354 endif
355
Doug Kearnsf97f6bb2023-08-27 18:44:09 +0200356 if getline(1) == "VERSION 5.00"
357 setf vb
358 return
359 endif
360
Bram Moolenaara2baa732022-02-04 16:09:54 +0000361 var lines = getline(1, min([line("$"), 5]))
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000362
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000363 if match(lines, ft_visual_basic_content) > -1
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000364 setf vb
365 else
366 setf form
367 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000368enddef
Doug Kearnsc570e9c2022-01-31 17:09:14 +0000369
Doug Kearns19a3bc32023-08-20 20:51:12 +0200370# Distinguish between Forth and F#
Bram Moolenaara2baa732022-02-04 16:09:54 +0000371export def FTfs()
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000372 if exists("g:filetype_fs")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000373 exe "setf " .. g:filetype_fs
Doug Kearns19a3bc32023-08-20 20:51:12 +0200374 elseif IsForth()
375 setf forth
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000376 else
Johan Kotlinski065088d2023-04-02 20:29:38 +0100377 setf fsharp
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000378 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000379enddef
Bram Moolenaar3d14c0f2021-11-27 17:22:07 +0000380
Amelia Clarke35dfe582024-05-24 08:05:00 +0200381# Recursively search for Hare source files in a directory and any
382# subdirectories, up to a given depth.
383def IsHareModule(dir: string, depth: number): bool
384 if depth <= 0
385 return !empty(glob(dir .. '/*.ha'))
386 endif
387
388 return reduce(sort(glob(dir .. '/*', true, true),
389 (a, b) => isdirectory(a) - isdirectory(b)),
390 (acc, n) => acc
391 || n =~ '\.ha$'
392 || isdirectory(n)
393 && IsHareModule(n, depth - 1),
394 false)
395enddef
396
397# Determine if a README file exists within a Hare module and should be given the
398# Haredoc filetype.
399export def FTharedoc()
400 if exists('g:filetype_haredoc')
401 if IsHareModule('<afile>:h', get(g:, 'haredoc_search_depth', 1))
402 setf haredoc
403 endif
404 endif
405enddef
406
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200407# Distinguish between HTML, XHTML, Django and Angular
Bram Moolenaara2baa732022-02-04 16:09:54 +0000408export def FThtml()
409 var n = 1
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200410
411 # Test if the filename follows the Angular component template convention
Christian Brabandtc03f6312024-07-10 19:23:39 +0200412 # Disabled for the reasons mentioned here: #13594
413 # if expand('%:t') =~ '^.*\.component\.html$'
414 # setf htmlangular
415 # return
416 # endif
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200417
Afiq Nazrie9718ed72024-06-18 19:59:53 +0200418 while n < 40 && n <= line("$")
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200419 # Check for Angular
420 if getline(n) =~ '@\(if\|for\|defer\|switch\)\|\*\(ngIf\|ngFor\|ngSwitch\|ngTemplateOutlet\)\|ng-template\|ng-content\|{{.*}}'
421 setf htmlangular
422 return
423 endif
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200424 # Check for XHTML
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100425 if getline(n) =~ '\<DTD\s\+XHTML\s'
426 setf xhtml
427 return
428 endif
Dennis van den Berg1ad194c2024-07-09 19:25:33 +0200429 # Check for Django
Afiq Nazrie9718ed72024-06-18 19:59:53 +0200430 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 +0100431 setf htmldjango
432 return
433 endif
EliSaudere57c9a12024-07-28 21:28:11 +0200434 # Check for SuperHTML
435 if getline(n) =~ '<extend\|<super>'
436 setf superhtml
437 return
438 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000439 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100440 endwhile
Bram Moolenaar493fbe42019-03-17 17:16:12 +0100441 setf FALLBACK html
Bram Moolenaara2baa732022-02-04 16:09:54 +0000442enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100443
Bram Moolenaara2baa732022-02-04 16:09:54 +0000444# Distinguish between standard IDL and MS-IDL
445export def FTidl()
446 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +0100447 while n < 50 && n <= line("$")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100448 if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
449 setf msidl
450 return
451 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000452 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100453 endwhile
454 setf idl
Bram Moolenaara2baa732022-02-04 16:09:54 +0000455enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100456
Wu, Zhenyu887a38c2024-05-09 20:35:13 +0200457# Distinguish between "default", Prolog, zsh module's C and Cproto prototype file.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000458export def ProtoCheck(default: string)
Wu, Zhenyu887a38c2024-05-09 20:35:13 +0200459 # zsh modules use '#include "*.pro"'
460 # https://github.com/zsh-users/zsh/blob/63f086d167960a27ecdbcb762179e2c2bf8a29f5/Src/Modules/example.c#L31
461 if getline(1) =~ '/* Generated automatically */'
462 setf c
Bram Moolenaara2baa732022-02-04 16:09:54 +0000463 # Cproto files have a comment in the first line and a function prototype in
464 # the second line, it always ends in ";". Indent files may also have
465 # comments, thus we can't match comments to see the difference.
466 # IDL files can have a single ';' in the second line, require at least one
467 # chacter before the ';'.
Wu, Zhenyu887a38c2024-05-09 20:35:13 +0200468 elseif getline(2) =~ '.;$'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100469 setf cpp
470 else
Bram Moolenaar48c3f4e2022-08-08 15:42:38 +0100471 # recognize Prolog by specific text in the first non-empty line
472 # require a blank after the '%' because Perl uses "%list" and "%translate"
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100473 var lnum = getline(nextnonblank(1))
igna_martinoli37853b72024-07-18 21:34:36 +0200474 if lnum =~ '\<prolog\>' || lnum =~ prolog_pattern
Bram Moolenaar48c3f4e2022-08-08 15:42:38 +0100475 setf prolog
476 else
477 exe 'setf ' .. default
478 endif
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100479 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000480enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100481
Bram Moolenaara2baa732022-02-04 16:09:54 +0000482export def FTm()
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200483 if exists("g:filetype_m")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000484 exe "setf " .. g:filetype_m
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200485 return
486 endif
487
Bram Moolenaara2baa732022-02-04 16:09:54 +0000488 # excluding end(for|function|if|switch|while) common to Murphi
489 var octave_block_terminators = '\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>'
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200490
Bram Moolenaara2baa732022-02-04 16:09:54 +0000491 var objc_preprocessor = '^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>'
Doug Kearns7329cfa2021-11-26 13:01:41 +0000492
Bram Moolenaara2baa732022-02-04 16:09:54 +0000493 var n = 1
494 var saw_comment = 0 # Whether we've seen a multiline comment leader.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100495 while n < 100
Bram Moolenaara2baa732022-02-04 16:09:54 +0000496 var line = getline(n)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100497 if line =~ '^\s*/\*'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000498 # /* ... */ is a comment in Objective C and Murphi, so we can't conclude
499 # it's either of them yet, but track this as a hint in case we don't see
500 # anything more definitive.
501 saw_comment = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100502 endif
Doug Kearns7329cfa2021-11-26 13:01:41 +0000503 if line =~ '^\s*//' || line =~ '^\s*@import\>' || line =~ objc_preprocessor
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100504 setf objc
505 return
506 endif
Bram Moolenaarca0627d2021-09-12 17:03:08 +0200507 if line =~ '^\s*\%(#\|%!\)' || line =~ '^\s*unwind_protect\>' ||
Bram Moolenaardeba5eb2021-09-03 19:21:36 +0200508 \ line =~ '\%(^\|;\)\s*' .. octave_block_terminators
509 setf octave
510 return
511 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000512 # TODO: could be Matlab or Octave
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100513 if line =~ '^\s*%'
514 setf matlab
515 return
516 endif
517 if line =~ '^\s*(\*'
518 setf mma
519 return
520 endif
521 if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
522 setf murphi
523 return
524 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000525 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100526 endwhile
527
528 if saw_comment
Bram Moolenaara2baa732022-02-04 16:09:54 +0000529 # We didn't see anything definitive, but this looks like either Objective C
530 # or Murphi based on the comment leader. Assume the former as it is more
531 # common.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100532 setf objc
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100533 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000534 # Default is Matlab
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100535 setf matlab
536 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000537enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100538
Ken Takataeb4b9032024-07-25 21:07:13 +0200539export def FTmake()
540 # Check if it is a Microsoft Makefile
541 unlet! b:make_microsoft
542 var n = 1
543 while n < 1000 && n <= line('$')
544 var line = getline(n)
545 if line =~? '^\s*!\s*\(ifn\=\(def\)\=\|include\|message\|error\)\>'
546 b:make_microsoft = 1
547 break
548 elseif line =~ '^ *ifn\=\(eq\|def\)\>' || line =~ '^ *[-s]\=include\s'
549 break
550 elseif line =~ '^ *\w\+\s*[!?:+]='
551 break
552 endif
553 n += 1
554 endwhile
555 setf make
556enddef
557
Bram Moolenaara2baa732022-02-04 16:09:54 +0000558export def FTmms()
559 var n = 1
Bram Moolenaard7df2792020-01-02 21:34:42 +0100560 while n < 20
Bram Moolenaara2baa732022-02-04 16:09:54 +0000561 var line = getline(n)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100562 if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
563 setf mmix
564 return
565 endif
566 if line =~ '^\s*#'
567 setf make
568 return
569 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000570 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100571 endwhile
572 setf mmix
Bram Moolenaara2baa732022-02-04 16:09:54 +0000573enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100574
Bram Moolenaara2baa732022-02-04 16:09:54 +0000575# This function checks if one of the first five lines start with a dot. In
576# that case it is probably an nroff file: 'filetype' is set and 1 is returned.
577export def FTnroff(): number
578 if getline(1)[0] .. getline(2)[0] .. getline(3)[0]
579 .. getline(4)[0] .. getline(5)[0] =~ '\.'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100580 setf nroff
581 return 1
582 endif
583 return 0
Bram Moolenaara2baa732022-02-04 16:09:54 +0000584enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100585
Bram Moolenaara2baa732022-02-04 16:09:54 +0000586export def FTmm()
587 var n = 1
Bram Moolenaard1caa942020-04-10 22:10:56 +0200588 while n < 20
Bram Moolenaara2baa732022-02-04 16:09:54 +0000589 if getline(n) =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100590 setf objcpp
591 return
592 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000593 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100594 endwhile
595 setf nroff
Bram Moolenaara2baa732022-02-04 16:09:54 +0000596enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100597
Bram Moolenaarcdbfc6d2022-06-30 16:25:21 +0100598# Returns true if file content looks like LambdaProlog module
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100599def IsLProlog(): bool
Gaetan Lepage4ce1bda2023-05-10 22:01:55 +0100600 # skip apparent comments and blank lines, what looks like
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100601 # LambdaProlog comment may be RAPID header
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100602 var lnum: number = nextnonblank(1)
603 while lnum > 0 && lnum < line('$') && getline(lnum) =~ '^\s*%' # LambdaProlog comment
604 lnum = nextnonblank(lnum + 1)
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100605 endwhile
606 # this pattern must not catch a go.mod file
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100607 return getline(lnum) =~ '\<module\s\+\w\+\s*\.\s*\(%\|$\)'
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100608enddef
609
Doug Kearns68a89472024-01-05 17:59:04 +0100610def IsModula2(): bool
dkearnsef387c02024-02-20 06:58:30 +1100611 return getline(nextnonblank(1)) =~ '\<MODULE\s\+\w\+\s*\%(\[.*]\s*\)\=;\|^\s*(\*'
Doug Kearns68a89472024-01-05 17:59:04 +0100612enddef
613
614def SetFiletypeModula2()
615 const KNOWN_DIALECTS = ["iso", "pim", "r10"]
616 const KNOWN_EXTENSIONS = ["gm2"]
617 const LINE_COUNT = 200
618 const TAG = '(\*!m2\(\w\+\)\%(+\(\w\+\)\)\=\*)'
619
620 var dialect = get(g:, "modula2_default_dialect", "pim")
621 var extension = get(g:, "modula2_default_extension", "")
622
623 var matches = []
624
625 # ignore unknown dialects or badly formatted tags
626 for lnum in range(1, min([line("$"), LINE_COUNT]))
627 matches = matchlist(getline(lnum), TAG)
628 if !empty(matches)
629 if index(KNOWN_DIALECTS, matches[1]) >= 0
630 dialect = matches[1]
631 endif
632 if index(KNOWN_EXTENSIONS, matches[2]) >= 0
633 extension = matches[2]
634 endif
635 break
636 endif
637 endfor
638
639 modula2#SetDialect(dialect, extension)
640
641 setf modula2
642enddef
643
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100644# Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
645export def FTmod()
Doug Kearns68a89472024-01-05 17:59:04 +0100646 if get(g:, "filetype_mod", "") == "modula2" || IsModula2()
647 SetFiletypeModula2()
648 return
649 endif
650
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100651 if exists("g:filetype_mod")
652 exe "setf " .. g:filetype_mod
Omar El Halabic9fbd252023-05-29 19:59:45 +0100653 elseif expand("<afile>") =~ '\<go.mod$'
654 setf gomod
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100655 elseif IsLProlog()
656 setf lprolog
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100657 elseif IsRapid()
658 setf rapid
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100659 else
660 # Nothing recognized, assume modsim3
661 setf modsim3
662 endif
663enddef
664
Bram Moolenaara2baa732022-02-04 16:09:54 +0000665export def FTpl()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100666 if exists("g:filetype_pl")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000667 exe "setf " .. g:filetype_pl
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100668 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000669 # recognize Prolog by specific text in the first non-empty line
670 # require a blank after the '%' because Perl uses "%list" and "%translate"
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100671 var line = getline(nextnonblank(1))
igna_martinoli37853b72024-07-18 21:34:36 +0200672 if line =~ '\<prolog\>' || line =~ prolog_pattern
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100673 setf prolog
674 else
675 setf perl
676 endif
677 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000678enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100679
Bram Moolenaara2baa732022-02-04 16:09:54 +0000680export def FTinc()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100681 if exists("g:filetype_inc")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000682 exe "setf " .. g:filetype_inc
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100683 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000684 var lines = getline(1) .. getline(2) .. getline(3)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100685 if lines =~? "perlscript"
686 setf aspperl
687 elseif lines =~ "<%"
688 setf aspvbs
689 elseif lines =~ "<?"
690 setf php
Bram Moolenaara2baa732022-02-04 16:09:54 +0000691 # Pascal supports // comments but they're vary rarely used for file
692 # headers so assume POV-Ray
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000693 elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? ft_pascal_keywords
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100694 setf pascal
Gregory Anders30e212d2022-07-26 21:42:03 +0100695 elseif lines =~# '\<\%(require\|inherit\)\>' || lines =~# '[A-Z][A-Za-z0-9_:${}]*\s\+\%(??\|[?:+]\)\?= '
Gregory Andersfa49eb42022-07-16 17:46:47 +0100696 setf bitbake
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100697 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000698 FTasmsyntax()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100699 if exists("b:asmsyntax")
Gregory Andersfa49eb42022-07-16 17:46:47 +0100700 exe "setf " .. fnameescape(b:asmsyntax)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100701 else
Gregory Andersfa49eb42022-07-16 17:46:47 +0100702 setf pov
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100703 endif
704 endif
705 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000706enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100707
Bram Moolenaara2baa732022-02-04 16:09:54 +0000708export def FTprogress_cweb()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100709 if exists("g:filetype_w")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000710 exe "setf " .. g:filetype_w
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100711 return
712 endif
713 if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
714 setf progress
715 else
716 setf cweb
717 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000718enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100719
Julien Marrec2e310652023-11-25 15:30:46 +0100720# These include the leading '%' sign
721var 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\)'
722# This is the start/end of a block that is copied literally to the processor file (C/C++)
723var ft_swig_verbatim_block_start = '^\s*%{'
724
725export def FTi()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100726 if exists("g:filetype_i")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000727 exe "setf " .. g:filetype_i
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100728 return
729 endif
Julien Marrec2e310652023-11-25 15:30:46 +0100730 # 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 +0000731 # If not found, assume Progress.
732 var lnum = 1
Julien Marrec2e310652023-11-25 15:30:46 +0100733 while lnum <= 50 && lnum < line('$')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000734 var line = getline(lnum)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100735 if line =~ '^\s*;' || line =~ '^\*'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000736 FTasm()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100737 return
Julien Marrec2e310652023-11-25 15:30:46 +0100738 elseif line =~ ft_swig_keywords || line =~ ft_swig_verbatim_block_start
739 setf swig
740 return
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100741 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000742 lnum += 1
Bram Moolenaarc12dc472022-03-05 13:45:56 +0000743 endwhile
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100744 setf progress
Bram Moolenaara2baa732022-02-04 16:09:54 +0000745enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100746
Bram Moolenaara2baa732022-02-04 16:09:54 +0000747var ft_pascal_comments = '^\s*\%({\|(\*\|//\)'
748var ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>'
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100749
Bram Moolenaara2baa732022-02-04 16:09:54 +0000750export def FTprogress_pascal()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100751 if exists("g:filetype_p")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000752 exe "setf " .. g:filetype_p
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100753 return
754 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000755 # This function checks for valid Pascal syntax in the first ten lines.
756 # Look for either an opening comment or a program start.
757 # If not found, assume Progress.
758 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100759 while lnum <= 10 && lnum < line('$')
Bram Moolenaara2baa732022-02-04 16:09:54 +0000760 var line = getline(lnum)
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000761 if line =~ ft_pascal_comments || line =~? ft_pascal_keywords
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100762 setf pascal
763 return
764 elseif line !~ '^\s*$' || line =~ '^/\*'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000765 # Not an empty line: Doesn't look like valid Pascal code.
766 # Or it looks like a Progress /* comment
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100767 break
768 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000769 lnum += 1
Bram Moolenaarc12dc472022-03-05 13:45:56 +0000770 endwhile
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100771 setf progress
Bram Moolenaara2baa732022-02-04 16:09:54 +0000772enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100773
Bram Moolenaara2baa732022-02-04 16:09:54 +0000774export def FTpp()
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100775 if exists("g:filetype_pp")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000776 exe "setf " .. g:filetype_pp
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100777 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000778 var line = getline(nextnonblank(1))
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000779 if line =~ ft_pascal_comments || line =~? ft_pascal_keywords
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100780 setf pascal
781 else
782 setf puppet
783 endif
784 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000785enddef
Bram Moolenaara0122dc2021-01-12 17:42:24 +0100786
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100787# Determine if *.prg is ABB RAPID. Can also be Clipper, FoxPro or eviews
788export def FTprg()
789 if exists("g:filetype_prg")
790 exe "setf " .. g:filetype_prg
791 elseif IsRapid()
792 setf rapid
793 else
794 # Nothing recognized, assume Clipper
795 setf clipper
796 endif
797enddef
798
Bram Moolenaara2baa732022-02-04 16:09:54 +0000799export def FTr()
800 var max = line("$") > 50 ? 50 : line("$")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100801
802 for n in range(1, max)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000803 # Rebol is easy to recognize, check for that first
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100804 if getline(n) =~? '\<REBOL\>'
805 setf rebol
806 return
807 endif
808 endfor
809
810 for n in range(1, max)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000811 # R has # comments
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100812 if getline(n) =~ '^\s*#'
813 setf r
814 return
815 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000816 # Rexx has /* comments */
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100817 if getline(n) =~ '^\s*/\*'
818 setf rexx
819 return
820 endif
821 endfor
822
Bram Moolenaara2baa732022-02-04 16:09:54 +0000823 # Nothing recognized, use user default or assume Rexx
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100824 if exists("g:filetype_r")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000825 exe "setf " .. g:filetype_r
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100826 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000827 # Rexx used to be the default, but R appears to be much more popular.
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100828 setf r
829 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000830enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100831
Bram Moolenaara2baa732022-02-04 16:09:54 +0000832export def McSetf()
833 # Rely on the file to start with a comment.
834 # MS message text files use ';', Sendmail files use '#' or 'dnl'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100835 for lnum in range(1, min([line("$"), 20]))
Bram Moolenaara2baa732022-02-04 16:09:54 +0000836 var line = getline(lnum)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100837 if line =~ '^\s*\(#\|dnl\)'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000838 setf m4 # Sendmail .mc file
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100839 return
840 elseif line =~ '^\s*;'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000841 setf msmessages # MS Message text file
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100842 return
843 endif
844 endfor
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +0100845 setf m4 # Default: Sendmail .mc file
Bram Moolenaara2baa732022-02-04 16:09:54 +0000846enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100847
Bram Moolenaara2baa732022-02-04 16:09:54 +0000848# Called from filetype.vim and scripts.vim.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100849# When "setft" is passed and false then the 'filetype' option is not set.
850export def SetFileTypeSH(name: string, setft = true): string
851 if setft && did_filetype()
Bram Moolenaara2baa732022-02-04 16:09:54 +0000852 # Filetype was already detected
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100853 return ''
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100854 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100855 if setft && expand("<amatch>") =~ g:ft_ignore_pat
856 return ''
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100857 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000858 if name =~ '\<csh\>'
859 # Some .sh scripts contain #!/bin/csh.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100860 return SetFileTypeShell("csh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000861 elseif name =~ '\<tcsh\>'
862 # Some .sh scripts contain #!/bin/tcsh.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100863 return SetFileTypeShell("tcsh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000864 elseif name =~ '\<zsh\>'
865 # Some .sh scripts contain #!/bin/zsh.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100866 return SetFileTypeShell("zsh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000867 elseif name =~ '\<ksh\>'
868 b:is_kornshell = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100869 if exists("b:is_bash")
870 unlet b:is_bash
871 endif
872 if exists("b:is_sh")
873 unlet b:is_sh
874 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000875 elseif exists("g:bash_is_sh") || name =~ '\<bash\>' || name =~ '\<bash2\>'
876 b:is_bash = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100877 if exists("b:is_kornshell")
878 unlet b:is_kornshell
879 endif
880 if exists("b:is_sh")
881 unlet b:is_sh
882 endif
Eisuke Kawashima24482fb2022-11-24 10:58:10 +0000883 elseif name =~ '\<sh\>' || name =~ '\<dash\>'
884 # Ubuntu links "sh" to "dash", thus it is expected to work the same way
Bram Moolenaara2baa732022-02-04 16:09:54 +0000885 b:is_sh = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100886 if exists("b:is_kornshell")
887 unlet b:is_kornshell
888 endif
889 if exists("b:is_bash")
890 unlet b:is_bash
891 endif
892 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100893
894 return SetFileTypeShell("sh", setft)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000895enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100896
Bram Moolenaara2baa732022-02-04 16:09:54 +0000897# For shell-like file types, check for an "exec" command hidden in a comment,
898# as used for Tcl.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100899# When "setft" is passed and false then the 'filetype' option is not set.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000900# Also called from scripts.vim, thus can't be local to this script.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100901export def SetFileTypeShell(name: string, setft = true): string
902 if setft && did_filetype()
Bram Moolenaara2baa732022-02-04 16:09:54 +0000903 # Filetype was already detected
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100904 return ''
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100905 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100906 if setft && expand("<amatch>") =~ g:ft_ignore_pat
907 return ''
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100908 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100909
910 var lnum = 2
911 while lnum < 20 && lnum < line("$") && getline(lnum) =~ '^\s*\(#\|$\)'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000912 # Skip empty and comment lines.
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100913 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100914 endwhile
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100915 if lnum < line("$") && getline(lnum) =~ '\s*exec\s' && getline(lnum - 1) =~ '^\s*#.*\\$'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000916 # Found an "exec" line after a comment with continuation
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100917 var n = substitute(getline(lnum), '\s*exec\s\+\([^ ]*/\)\=', '', '')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100918 if n =~ '\<tclsh\|\<wish'
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100919 if setft
920 setf tcl
921 endif
922 return 'tcl'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100923 endif
924 endif
Bram Moolenaarf07d1a72023-06-09 21:01:47 +0100925
926 if setft
927 exe "setf " .. name
928 endif
929 return name
Bram Moolenaara2baa732022-02-04 16:09:54 +0000930enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100931
Bram Moolenaara2baa732022-02-04 16:09:54 +0000932export def CSH()
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100933 if did_filetype()
Bram Moolenaara2baa732022-02-04 16:09:54 +0000934 # Filetype was already detected
Bram Moolenaar147e7d02019-01-18 21:46:47 +0100935 return
936 endif
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100937 if exists("g:filetype_csh")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000938 SetFileTypeShell(g:filetype_csh)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100939 elseif &shell =~ "tcsh"
Bram Moolenaara2baa732022-02-04 16:09:54 +0000940 SetFileTypeShell("tcsh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100941 else
Bram Moolenaara2baa732022-02-04 16:09:54 +0000942 SetFileTypeShell("csh")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100943 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000944enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100945
Bram Moolenaara2baa732022-02-04 16:09:54 +0000946var ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
947export def FTRules()
948 var path = expand('<amatch>:p')
Bram Moolenaaraa9675a2020-08-17 21:57:09 +0200949 if path =~ '/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|\%(usr/\)\=lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100950 setf udevrules
951 return
952 endif
953 if path =~ '^/etc/ufw/'
Bram Moolenaara2baa732022-02-04 16:09:54 +0000954 setf conf # Better than hog
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100955 return
956 endif
957 if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
958 setf javascript
959 return
960 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000961 var config_lines: list<string>
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100962 try
Bram Moolenaara2baa732022-02-04 16:09:54 +0000963 config_lines = readfile('/etc/udev/udev.conf')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100964 catch /^Vim\%((\a\+)\)\=:E484/
965 setf hog
966 return
967 endtry
Bram Moolenaara2baa732022-02-04 16:09:54 +0000968 var dir = expand('<amatch>:p:h')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100969 for line in config_lines
Bram Moolenaarb2c72352022-02-22 21:17:40 +0000970 if line =~ ft_rules_udev_rules_pattern
971 var udev_rules = substitute(line, ft_rules_udev_rules_pattern, '\1', "")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100972 if dir == udev_rules
973 setf udevrules
974 endif
975 break
976 endif
977 endfor
978 setf hog
Bram Moolenaara2baa732022-02-04 16:09:54 +0000979enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100980
Bram Moolenaara2baa732022-02-04 16:09:54 +0000981export def SQL()
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100982 if exists("g:filetype_sql")
Bram Moolenaara2baa732022-02-04 16:09:54 +0000983 exe "setf " .. g:filetype_sql
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100984 else
985 setf sql
986 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +0000987enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +0100988
ranjithshegde8cac20e2022-04-13 15:29:21 +0100989# This function checks the first 25 lines of file extension "sc" to resolve
Chris Kipp70ef3f52022-12-14 16:42:15 +0000990# detection between scala and SuperCollider.
991# NOTE: We don't check for 'Class : Method', as this can easily be confused
992# with valid Scala like `val x : Int = 3`. So we instead only rely on
993# checks that can't be confused.
ranjithshegde8cac20e2022-04-13 15:29:21 +0100994export def FTsc()
995 for lnum in range(1, min([line("$"), 25]))
Chris Kipp70ef3f52022-12-14 16:42:15 +0000996 if getline(lnum) =~# 'var\s<\|classvar\s<\|\^this.*\||\w\+|\|+\s\w*\s{\|\*ar\s'
ranjithshegde8cac20e2022-04-13 15:29:21 +0100997 setf supercollider
998 return
999 endif
1000 endfor
1001 setf scala
1002enddef
1003
1004# This function checks the first line of file extension "scd" to resolve
1005# detection between scdoc and SuperCollider
1006export def FTscd()
1007 if getline(1) =~# '\%^\S\+(\d[0-9A-Za-z]*)\%(\s\+\"[^"]*\"\%(\s\+\"[^"]*\"\)\=\)\=$'
1008 setf scdoc
1009 else
1010 setf supercollider
1011 endif
1012enddef
1013
Bram Moolenaara2baa732022-02-04 16:09:54 +00001014# If the file has an extension of 't' and is in a directory 't' or 'xt' then
1015# it is almost certainly a Perl test file.
1016# If the first line starts with '#' and contains 'perl' it's probably a Perl
1017# file.
1018# (Slow test) If a file contains a 'use' statement then it is almost certainly
1019# a Perl file.
1020export def FTperl(): number
1021 var dirname = expand("%:p:h:t")
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001022 if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
1023 setf perl
1024 return 1
1025 endif
1026 if getline(1)[0] == '#' && getline(1) =~ 'perl'
1027 setf perl
1028 return 1
1029 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001030 var save_cursor = getpos('.')
1031 call cursor(1, 1)
Bram Moolenaare5b78972022-02-05 19:50:34 +00001032 var has_use = search('^use\s\s*\k', 'c', 30) > 0
Bram Moolenaarf0b03c42017-12-17 17:17:07 +01001033 call setpos('.', save_cursor)
1034 if has_use
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001035 setf perl
1036 return 1
1037 endif
1038 return 0
Bram Moolenaara2baa732022-02-04 16:09:54 +00001039enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001040
Bram Moolenaarcdbfc6d2022-06-30 16:25:21 +01001041# LambdaProlog and Standard ML signature files
1042export def FTsig()
1043 if exists("g:filetype_sig")
1044 exe "setf " .. g:filetype_sig
1045 return
1046 endif
1047
1048 var lprolog_comment = '^\s*\%(/\*\|%\)'
1049 var lprolog_keyword = '^\s*sig\s\+\a'
1050 var sml_comment = '^\s*(\*'
1051 var sml_keyword = '^\s*\%(signature\|structure\)\s\+\a'
1052
1053 var line = getline(nextnonblank(1))
1054
1055 if line =~ lprolog_comment || line =~# lprolog_keyword
1056 setf lprolog
1057 elseif line =~ sml_comment || line =~# sml_keyword
1058 setf sml
1059 endif
1060enddef
1061
Bram Moolenaarbe807d52022-09-01 15:01:25 +01001062# This function checks the first 100 lines of files matching "*.sil" to
1063# resolve detection between Swift Intermediate Language and SILE.
1064export def FTsil()
1065 for lnum in range(1, [line('$'), 100]->min())
1066 var line: string = getline(lnum)
1067 if line =~ '^\s*[\\%]'
1068 setf sile
1069 return
1070 elseif line =~ '^\s*\S'
1071 setf sil
1072 return
1073 endif
1074 endfor
1075 # no clue, default to "sil"
1076 setf sil
1077enddef
1078
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +01001079export def FTsys()
KnoP-01f420ff22022-04-13 20:46:21 +01001080 if exists("g:filetype_sys")
1081 exe "setf " .. g:filetype_sys
1082 elseif IsRapid()
Bram Moolenaar0bbf09c2022-04-09 15:16:53 +01001083 setf rapid
1084 else
1085 setf bat
1086 endif
1087enddef
1088
Bram Moolenaara2baa732022-02-04 16:09:54 +00001089# Choose context, plaintex, or tex (LaTeX) based on these rules:
1090# 1. Check the first line of the file for "%&<format>".
1091# 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
1092# 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
1093export def FTtex()
1094 var firstline = getline(1)
1095 var format: string
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001096 if firstline =~ '^%&\s*\a\+'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001097 format = tolower(matchstr(firstline, '\a\+'))
1098 format = substitute(format, 'pdf', '', '')
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001099 if format == 'tex'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001100 format = 'latex'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001101 elseif format == 'plaintex'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001102 format = 'plain'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001103 endif
1104 elseif expand('%') =~ 'tex/context/.*/.*.tex'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001105 format = 'context'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001106 else
Bram Moolenaara2baa732022-02-04 16:09:54 +00001107 # Default value, may be changed later:
1108 format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
1109 # Save position, go to the top of the file, find first non-comment line.
1110 var save_cursor = getpos('.')
1111 call cursor(1, 1)
1112 var firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
Bram Moolenaare5b78972022-02-05 19:50:34 +00001113 if firstNC > 0
1114 # Check the next thousand lines for a LaTeX or ConTeXt keyword.
Bram Moolenaara2baa732022-02-04 16:09:54 +00001115 var lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
1116 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\>'
1117 var kwline = search('^\s*\\\%(' .. lpat .. '\)\|^\s*\\\(' .. cpat .. '\)',
1118 'cnp', firstNC + 1000)
1119 if kwline == 1 # lpat matched
1120 format = 'latex'
1121 elseif kwline == 2 # cpat matched
1122 format = 'context'
1123 endif # If neither matched, keep default set above.
1124 # let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
1125 # let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
1126 # if cline > 0
1127 # let format = 'context'
1128 # endif
1129 # if lline > 0 && (cline == 0 || cline > lline)
1130 # let format = 'tex'
1131 # endif
1132 endif # firstNC
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001133 call setpos('.', save_cursor)
Bram Moolenaara2baa732022-02-04 16:09:54 +00001134 endif # firstline =~ '^%&\s*\a\+'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001135
Bram Moolenaara2baa732022-02-04 16:09:54 +00001136 # Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001137 if format == 'plain'
1138 setf plaintex
1139 elseif format == 'context'
1140 setf context
Bram Moolenaara2baa732022-02-04 16:09:54 +00001141 else # probably LaTeX
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001142 setf tex
1143 endif
1144 return
Bram Moolenaara2baa732022-02-04 16:09:54 +00001145enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001146
Bram Moolenaara2baa732022-02-04 16:09:54 +00001147export def FTxml()
1148 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +01001149 while n < 100 && n <= line("$")
Bram Moolenaara2baa732022-02-04 16:09:54 +00001150 var line = getline(n)
1151 # DocBook 4 or DocBook 5.
1152 var is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
1153 var is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001154 if is_docbook4 || is_docbook5
Bram Moolenaara2baa732022-02-04 16:09:54 +00001155 b:docbk_type = "xml"
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001156 if is_docbook5
Bram Moolenaara2baa732022-02-04 16:09:54 +00001157 b:docbk_ver = 5
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001158 else
Bram Moolenaara2baa732022-02-04 16:09:54 +00001159 b:docbk_ver = 4
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001160 endif
1161 setf docbk
1162 return
1163 endif
1164 if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
1165 setf xbl
1166 return
1167 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001168 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001169 endwhile
1170 setf xml
Bram Moolenaara2baa732022-02-04 16:09:54 +00001171enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001172
Bram Moolenaara2baa732022-02-04 16:09:54 +00001173export def FTy()
1174 var n = 1
Bram Moolenaar493fbe42019-03-17 17:16:12 +01001175 while n < 100 && n <= line("$")
Bram Moolenaara2baa732022-02-04 16:09:54 +00001176 var line = getline(n)
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001177 if line =~ '^\s*%'
1178 setf yacc
1179 return
1180 endif
1181 if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
1182 setf racc
1183 return
1184 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001185 n += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001186 endwhile
1187 setf yacc
Bram Moolenaara2baa732022-02-04 16:09:54 +00001188enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001189
Bram Moolenaara2baa732022-02-04 16:09:54 +00001190export def Redif()
1191 var lnum = 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001192 while lnum <= 5 && lnum < line('$')
1193 if getline(lnum) =~ "^\ctemplate-type:"
1194 setf redif
1195 return
1196 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001197 lnum += 1
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001198 endwhile
Bram Moolenaara2baa732022-02-04 16:09:54 +00001199enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001200
Bram Moolenaara2baa732022-02-04 16:09:54 +00001201# This function is called for all files under */debian/patches/*, make sure not
1202# to non-dep3patch files, such as README and other text files.
1203export def Dep3patch()
James McCoy647ab4c2021-12-17 20:52:57 +00001204 if expand('%:t') ==# 'series'
1205 return
1206 endif
1207
1208 for ln in getline(1, 100)
1209 if ln =~# '^\%(Description\|Subject\|Origin\|Bug\|Forwarded\|Author\|From\|Reviewed-by\|Acked-by\|Last-Updated\|Applied-Upstream\):'
1210 setf dep3patch
1211 return
1212 elseif ln =~# '^---'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001213 # end of headers found. stop processing
James McCoy647ab4c2021-12-17 20:52:57 +00001214 return
1215 endif
1216 endfor
Bram Moolenaara2baa732022-02-04 16:09:54 +00001217enddef
Bram Moolenaar851ee6c2017-11-09 20:46:17 +01001218
Bram Moolenaara2baa732022-02-04 16:09:54 +00001219# This function checks the first 15 lines for appearance of 'FoamFile'
1220# and then 'object' in a following line.
1221# In that case, it's probably an OpenFOAM file
1222export def FTfoam()
1223 var ffile = 0
1224 var lnum = 1
Elwardi2284f6c2022-01-11 18:14:23 +00001225 while lnum <= 15
1226 if getline(lnum) =~# '^FoamFile'
Bram Moolenaara2baa732022-02-04 16:09:54 +00001227 ffile = 1
Elwardi2284f6c2022-01-11 18:14:23 +00001228 elseif ffile == 1 && getline(lnum) =~# '^\s*object'
1229 setf foam
1230 return
1231 endif
Bram Moolenaara2baa732022-02-04 16:09:54 +00001232 lnum += 1
Elwardi2284f6c2022-01-11 18:14:23 +00001233 endwhile
Bram Moolenaara2baa732022-02-04 16:09:54 +00001234enddef
Elwardi2284f6c2022-01-11 18:14:23 +00001235
Bram Moolenaara2baa732022-02-04 16:09:54 +00001236# Determine if a *.tf file is TF mud client or terraform
1237export def FTtf()
1238 var numberOfLines = line('$')
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001239 for i in range(1, numberOfLines)
Bram Moolenaara2baa732022-02-04 16:09:54 +00001240 var currentLine = trim(getline(i))
1241 var firstCharacter = currentLine[0]
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001242 if firstCharacter !=? ";" && firstCharacter !=? "/" && firstCharacter !=? ""
1243 setf terraform
1244 return
1245 endif
1246 endfor
1247 setf tf
Bram Moolenaara2baa732022-02-04 16:09:54 +00001248enddef
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001249
KnoP-0193c7a452022-04-16 21:14:04 +01001250var ft_krl_header = '\&\w+'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001251# Determine if a *.src file is Kuka Robot Language
1252export def FTsrc()
KnoP-0193c7a452022-04-16 21:14:04 +01001253 var ft_krl_def_or_deffct = '%(global\s+)?def%(fct)?>'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001254 if exists("g:filetype_src")
1255 exe "setf " .. g:filetype_src
KnoP-0193c7a452022-04-16 21:14:04 +01001256 elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. ft_krl_header .. '|' .. ft_krl_def_or_deffct .. ')'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001257 setf krl
1258 endif
1259enddef
1260
1261# Determine if a *.dat file is Kuka Robot Language
1262export def FTdat()
KnoP-0193c7a452022-04-16 21:14:04 +01001263 var ft_krl_defdat = 'defdat>'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001264 if exists("g:filetype_dat")
1265 exe "setf " .. g:filetype_dat
KnoP-0193c7a452022-04-16 21:14:04 +01001266 elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. ft_krl_header .. '|' .. ft_krl_defdat .. ')'
Bram Moolenaar3ad20902022-04-06 18:57:39 +01001267 setf krl
1268 endif
1269enddef
=?UTF-8?q?Dundar=20G=C3=B6c?=bd8168c2022-01-28 14:15:09 +00001270
Doug Kearns4ac8e792022-10-17 13:32:17 +01001271export def FTlsl()
1272 if exists("g:filetype_lsl")
1273 exe "setf " .. g:filetype_lsl
1274 endif
1275
1276 var line = getline(nextnonblank(1))
1277 if line =~ '^\s*%' || line =~# ':\s*trait\s*$'
1278 setf larch
1279 else
1280 setf lsl
1281 endif
1282enddef
1283
Gaetan Lepage4ce1bda2023-05-10 22:01:55 +01001284export def FTtyp()
1285 if exists("g:filetype_typ")
1286 exe "setf " .. g:filetype_typ
1287 return
1288 endif
1289
1290 # Look for SQL type definition syntax
1291 for line in getline(1, 200)
1292 # SQL type files may define the casing
1293 if line =~ '^CASE\s\==\s\=\(SAME\|LOWER\|UPPER\|OPPOSITE\)$'
1294 setf sql
1295 return
1296 endif
1297
1298 # SQL type files may define some types as follows
1299 if line =~ '^TYPE\s.*$'
1300 setf sql
1301 return
1302 endif
1303 endfor
1304
1305 # Otherwise, affect the typst filetype
1306 setf typst
1307enddef
1308
PowerUser64aa61b8a2024-06-19 20:32:11 +02001309# Detect Microsoft Developer Studio Project files (Makefile) or Faust DSP
1310# files.
1311export def FTdsp()
1312 if exists("g:filetype_dsp")
1313 exe "setf " .. g:filetype_dsp
1314 return
1315 endif
1316
1317 # Test the filename
1318 if expand('%:t') =~ '^[mM]akefile.*$'
1319 setf make
1320 return
1321 endif
1322
1323 # Test the file contents
1324 for line in getline(1, 200)
1325 # Chech for comment style
1326 if line =~ '^#.*'
1327 setf make
1328 return
1329 endif
1330
1331 # Check for common lines
1332 if line =~ '^.*Microsoft Developer Studio Project File.*$'
1333 setf make
1334 return
1335 endif
1336
1337 if line =~ '^!MESSAGE This is not a valid makefile\..+$'
1338 setf make
1339 return
1340 endif
1341
1342 # Check for keywords
1343 if line =~ '^!(IF,ELSEIF,ENDIF).*$'
1344 setf make
1345 return
1346 endif
1347
1348 # Check for common assignments
1349 if line =~ '^SOURCE=.*$'
1350 setf make
1351 return
1352 endif
1353 endfor
1354
1355 # Otherwise, assume we have a Faust file
1356 setf faust
1357enddef
1358
Turiiya80406c22023-04-22 21:38:47 +01001359# Set the filetype of a *.v file to Verilog, V or Cog based on the first 200
1360# lines.
1361export def FTv()
1362 if did_filetype()
1363 # ":setf" will do nothing, bail out early
1364 return
1365 endif
Christian Brabandt10b4f752024-01-01 19:19:20 +01001366 if exists("g:filetype_v")
1367 exe "setf " .. g:filetype_v
1368 return
1369 endif
Turiiya80406c22023-04-22 21:38:47 +01001370
Christian Brabandt10b4f752024-01-01 19:19:20 +01001371 var in_comment = 0
1372 for lnum in range(1, min([line("$"), 200]))
1373 var line = getline(lnum)
1374 # Skip Verilog and V comments (lines and blocks).
1375 if line =~ '^\s*/\*'
1376 # start comment block
1377 in_comment = 1
1378 endif
1379 if in_comment == 1
1380 if line =~ '\*/'
1381 # end comment block
1382 in_comment = 0
1383 endif
1384 # skip comment-block line
1385 continue
1386 endif
1387 if line =~ '^\s*//'
Turiiya80406c22023-04-22 21:38:47 +01001388 # skip comment line
1389 continue
1390 endif
1391
Christian Brabandt10b4f752024-01-01 19:19:20 +01001392 # Coq: line ends with a '.' followed by an optional variable number of
1393 # spaces or contains the start of a comment, but not inside a Verilog or V
1394 # comment.
1395 # Example: "Definition x := 10. (*".
1396 if (line =~ '\.\s*$' && line !~ '/[/*]') || (line =~ '(\*' && line !~ '/[/*].*(\*')
1397 setf coq
1398 return
1399 endif
1400
Turiiya80406c22023-04-22 21:38:47 +01001401 # Verilog: line ends with ';' followed by an optional variable number of
1402 # spaces and an optional start of a comment.
1403 # Example: " b <= a + 1; // Add 1".
Christian Brabandt10b4f752024-01-01 19:19:20 +01001404 if line =~ ';\s*\(/[/*].*\)\?$'
Turiiya80406c22023-04-22 21:38:47 +01001405 setf verilog
1406 return
1407 endif
Turiiya80406c22023-04-22 21:38:47 +01001408 endfor
1409
1410 # No line matched, fall back to "v".
1411 setf v
1412enddef
1413
Doug Kearnsf97f6bb2023-08-27 18:44:09 +02001414export def FTvba()
1415 if getline(1) =~ '^["#] Vimball Archiver'
1416 setf vim
1417 else
1418 setf vb
1419 endif
1420enddef
1421
Colin Caine4b3fab12024-04-18 23:53:02 +02001422export def Detect_UCI_statements(): bool
1423 # Match a config or package statement at the start of the line.
1424 const config_or_package_statement = '^\s*\(\(c\|config\)\|\(p\|package\)\)\s\+\S'
1425 # Match a line that is either all blank or blank followed by a comment
1426 const comment_or_blank = '^\s*\(#.*\)\?$'
1427
1428 # Return true iff the file has a config or package statement near the
1429 # top of the file and all preceding lines were comments or blank.
1430 return getline(1) =~# config_or_package_statement
1431 \ || getline(1) =~# comment_or_blank
1432 \ && ( getline(2) =~# config_or_package_statement
1433 \ || getline(2) =~# comment_or_blank
1434 \ && getline(3) =~# config_or_package_statement
1435 \ )
1436enddef
1437
Bram Moolenaara2baa732022-02-04 16:09:54 +00001438# Uncomment this line to check for compilation errors early
dkearnsef387c02024-02-20 06:58:30 +11001439# defcompile