mirror of
https://github.com/vim/vim
synced 2025-05-02 14:27:44 +02:00
Problem: filetype: nroff detection can be improved Solution: improve nroff detection (Eisuke Kawashima) - explicitly check roff comments and macros typically found in manpages - do not try to detect alphabetically-sectioned files, except for n, as nroff - l: > 'l' happens to be a section for historical reasons <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=391977> - n: e.g. /usr/share/man/mann/Tcl.n.gz - o: unsure (perhaps fedora-specific) - p: unsure (perhaps fedora-specific) closes: #17160 Signed-off-by: Eisuke Kawashima <e-kwsm@users.noreply.github.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1521 lines
39 KiB
VimL
1521 lines
39 KiB
VimL
vim9script
|
|
|
|
# Vim functions for file type detection
|
|
#
|
|
# Maintainer: The Vim Project <https://github.com/vim/vim>
|
|
# Last Change: 2025 Apr 21
|
|
# Former Maintainer: Bram Moolenaar <Bram@vim.org>
|
|
|
|
# These functions are moved here from runtime/filetype.vim to make startup
|
|
# faster.
|
|
|
|
var prolog_pattern = '^\s*\(:-\|%\+\(\s\|$\)\|\/\*\)\|\.\s*$'
|
|
|
|
export def Check_inp()
|
|
if getline(1) =~ '%%'
|
|
setf tex
|
|
elseif getline(1) =~ '^\*'
|
|
setf abaqus
|
|
else
|
|
var n = 1
|
|
var nmax = line("$") > 500 ? 500 : line("$")
|
|
while n <= nmax
|
|
if getline(n) =~? "^header surface data"
|
|
setf trasys
|
|
break
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
endif
|
|
enddef
|
|
|
|
# This function checks for the kind of assembly that is wanted by the user, or
|
|
# can be detected from the first five lines of the file.
|
|
export def FTasm()
|
|
# tiasm uses `* commment`
|
|
if join(getline(1, 10), "\n") =~ '\%(\%(^\|\n\)\*\|Texas Instruments Incorporated\)'
|
|
setf tiasm
|
|
endif
|
|
# make sure b:asmsyntax exists
|
|
if !exists("b:asmsyntax")
|
|
b:asmsyntax = ""
|
|
endif
|
|
|
|
if b:asmsyntax == ""
|
|
FTasmsyntax()
|
|
endif
|
|
|
|
# if b:asmsyntax still isn't set, default to asmsyntax or GNU
|
|
if b:asmsyntax == ""
|
|
if exists("g:asmsyntax")
|
|
b:asmsyntax = g:asmsyntax
|
|
else
|
|
b:asmsyntax = "asm"
|
|
endif
|
|
endif
|
|
|
|
exe "setf " .. fnameescape(b:asmsyntax)
|
|
enddef
|
|
|
|
export def FTasmsyntax()
|
|
# see if the file contains any asmsyntax=foo overrides. If so, change
|
|
# b:asmsyntax appropriately
|
|
var head = " " .. getline(1) .. " " .. getline(2) .. " "
|
|
.. getline(3) .. " " .. getline(4) .. " " .. getline(5) .. " "
|
|
var match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
|
|
if match != ''
|
|
b:asmsyntax = match
|
|
elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
|
|
b:asmsyntax = "vmasm"
|
|
endif
|
|
enddef
|
|
|
|
var ft_visual_basic_content = '\c^\s*\%(Attribute\s\+VB_Name\|Begin\s\+\%(VB\.\|{\%(\x\+-\)\+\x\+}\)\)'
|
|
|
|
# See FTfrm() for Visual Basic form file detection
|
|
export def FTbas()
|
|
if exists("g:filetype_bas")
|
|
exe "setf " .. g:filetype_bas
|
|
return
|
|
endif
|
|
|
|
# most frequent FreeBASIC-specific keywords in distro files
|
|
var fb_keywords = '\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!'
|
|
var fb_preproc = '\c^\s*\%(' ..
|
|
# preprocessor
|
|
'#\s*\a\+\|' ..
|
|
# compiler option
|
|
'option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\|' ..
|
|
# metacommand
|
|
'\%(''\|rem\)\s*\$lang\>\|' ..
|
|
# default datatype
|
|
'def\%(byte\|longint\|short\|ubyte\|uint\|ulongint\|ushort\)\>' ..
|
|
'\)'
|
|
var fb_comment = "^\\s*/'"
|
|
|
|
# OPTION EXPLICIT, without the leading underscore, is common to many dialects
|
|
var qb64_preproc = '\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)'
|
|
|
|
for lnum in range(1, min([line("$"), 100]))
|
|
var line = getline(lnum)
|
|
if line =~ ft_visual_basic_content
|
|
setf vb
|
|
return
|
|
elseif line =~ fb_preproc || line =~ fb_comment || line =~ fb_keywords
|
|
setf freebasic
|
|
return
|
|
elseif line =~ qb64_preproc
|
|
setf qb64
|
|
return
|
|
endif
|
|
endfor
|
|
setf basic
|
|
enddef
|
|
|
|
export def FTbtm()
|
|
if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
|
|
setf dosbatch
|
|
else
|
|
setf btm
|
|
endif
|
|
enddef
|
|
|
|
export def BindzoneCheck(default = '')
|
|
if getline(1) .. getline(2) .. getline(3) .. getline(4)
|
|
=~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
|
|
setf bindzone
|
|
elseif default != ''
|
|
exe 'setf ' .. default
|
|
endif
|
|
enddef
|
|
|
|
# Returns true if file content looks like RAPID
|
|
def IsRapid(sChkExt: string = ""): bool
|
|
if sChkExt == "cfg"
|
|
return getline(1) =~? '\v^%(EIO|MMC|MOC|PROC|SIO|SYS):CFG'
|
|
endif
|
|
# called from FTmod, FTprg or FTsys
|
|
return getline(nextnonblank(1)) =~? '\v^\s*%(\%{3}|module\s+\k+\s*%(\(|$))'
|
|
enddef
|
|
|
|
export def FTcfg()
|
|
if exists("g:filetype_cfg")
|
|
exe "setf " .. g:filetype_cfg
|
|
elseif IsRapid("cfg")
|
|
setf rapid
|
|
else
|
|
setf cfg
|
|
endif
|
|
enddef
|
|
|
|
export def FTcl()
|
|
if join(getline(1, 4), '') =~ '/\*'
|
|
setf opencl
|
|
else
|
|
setf lisp
|
|
endif
|
|
enddef
|
|
|
|
export def FTcls()
|
|
if exists("g:filetype_cls")
|
|
exe "setf " .. g:filetype_cls
|
|
return
|
|
endif
|
|
|
|
var line1 = getline(1)
|
|
if line1 =~ '^#!.*\<\%(rexx\|regina\)\>'
|
|
setf rexx
|
|
return
|
|
elseif line1 == 'VERSION 1.0 CLASS'
|
|
setf vb
|
|
return
|
|
endif
|
|
|
|
var nonblank1 = getline(nextnonblank(1))
|
|
if nonblank1 =~ '^\v%(\%|\\)'
|
|
setf tex
|
|
elseif nonblank1 =~ '^\s*\%(/\*\|::\w\)'
|
|
setf rexx
|
|
else
|
|
setf st
|
|
endif
|
|
enddef
|
|
|
|
export def FTll()
|
|
if getline(1) =~ ';\|\<source_filename\>\|\<target\>'
|
|
setf llvm
|
|
else
|
|
setf lifelines
|
|
endif
|
|
enddef
|
|
|
|
export def FTlpc()
|
|
if exists("g:lpc_syntax_for_c")
|
|
var lnum = 1
|
|
while lnum <= 12
|
|
if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
|
|
setf lpc
|
|
return
|
|
endif
|
|
lnum += 1
|
|
endwhile
|
|
endif
|
|
setf c
|
|
enddef
|
|
|
|
# Searches within the first `maxlines` lines of the file for distinctive
|
|
# Objective-C or C++ syntax and returns the appropriate filetype. Returns a
|
|
# null_string if the search was inconclusive.
|
|
def CheckObjCOrCpp(maxlines = 100): string
|
|
var n = 1
|
|
while n < maxlines && n <= line('$')
|
|
const line = getline(n)
|
|
if line =~ '\v^\s*\@%(class|interface|end)>'
|
|
return 'objcpp'
|
|
elseif line =~ '\v^\s*%(class|namespace|template|using)>'
|
|
return 'cpp'
|
|
endif
|
|
++n
|
|
endwhile
|
|
return null_string
|
|
enddef
|
|
|
|
# Determines whether a *.h file is C, C++, Ch, or Objective-C/Objective-C++.
|
|
export def FTheader()
|
|
if exists('g:filetype_h')
|
|
execute $'setf {g:filetype_h}'
|
|
elseif exists('g:c_syntax_for_h')
|
|
setf c
|
|
elseif exists('g:ch_syntax_for_h')
|
|
setf ch
|
|
else
|
|
# Search the first 100 lines of the file for distinctive Objective-C or C++
|
|
# syntax and set the filetype accordingly. Otherwise, use C as the default
|
|
# filetype.
|
|
execute $'setf {CheckObjCOrCpp() ?? 'c'}'
|
|
endif
|
|
enddef
|
|
|
|
# This function checks if one of the first ten lines start with a '@'. In
|
|
# that case it is probably a change file.
|
|
# If the first line starts with # or ! it's probably a ch file.
|
|
# If a line has "main", "include", "//" or "/*" it's probably ch.
|
|
# Otherwise CHILL is assumed.
|
|
export def FTchange()
|
|
var lnum = 1
|
|
while lnum <= 10
|
|
if getline(lnum)[0] == '@'
|
|
setf change
|
|
return
|
|
endif
|
|
if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
|
|
setf ch
|
|
return
|
|
endif
|
|
if getline(lnum) =~ "MODULE"
|
|
setf chill
|
|
return
|
|
endif
|
|
if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
|
|
setf ch
|
|
return
|
|
endif
|
|
lnum += 1
|
|
endwhile
|
|
setf chill
|
|
enddef
|
|
|
|
export def FTent()
|
|
# This function checks for valid cl syntax in the first five lines.
|
|
# Look for either an opening comment, '#', or a block start, '{'.
|
|
# If not found, assume SGML.
|
|
var lnum = 1
|
|
while lnum < 6
|
|
var line = getline(lnum)
|
|
if line =~ '^\s*[#{]'
|
|
setf cl
|
|
return
|
|
elseif line !~ '^\s*$'
|
|
# Not a blank line, not a comment, and not a block start,
|
|
# so doesn't look like valid cl code.
|
|
break
|
|
endif
|
|
lnum += 1
|
|
endwhile
|
|
setf dtd
|
|
enddef
|
|
|
|
export def ExCheck()
|
|
var lines = getline(1, min([line("$"), 100]))
|
|
if exists('g:filetype_euphoria')
|
|
exe 'setf ' .. g:filetype_euphoria
|
|
elseif match(lines, '^--\|^ifdef\>\|^include\>') > -1
|
|
setf euphoria3
|
|
else
|
|
setf elixir
|
|
endif
|
|
enddef
|
|
|
|
export def EuphoriaCheck()
|
|
if exists('g:filetype_euphoria')
|
|
exe 'setf ' .. g:filetype_euphoria
|
|
else
|
|
setf euphoria3
|
|
endif
|
|
enddef
|
|
|
|
export def DtraceCheck()
|
|
if did_filetype()
|
|
# Filetype was already detected
|
|
return
|
|
endif
|
|
var lines = getline(1, min([line("$"), 100]))
|
|
if match(lines, '^module\>\|^import\>') > -1
|
|
# D files often start with a module and/or import statement.
|
|
setf d
|
|
elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
|
|
setf dtrace
|
|
else
|
|
setf d
|
|
endif
|
|
enddef
|
|
|
|
export def FTdef()
|
|
# LaTeX def files are usually generated by docstrip, which will output '%%' in first line
|
|
if getline(1) =~ '%%'
|
|
setf tex
|
|
endif
|
|
if get(g:, "filetype_def", "") == "modula2" || IsModula2()
|
|
SetFiletypeModula2()
|
|
return
|
|
endif
|
|
|
|
if exists("g:filetype_def")
|
|
exe "setf " .. g:filetype_def
|
|
else
|
|
setf def
|
|
endif
|
|
enddef
|
|
|
|
export def FTe()
|
|
if exists('g:filetype_euphoria')
|
|
exe 'setf ' .. g:filetype_euphoria
|
|
else
|
|
var n = 1
|
|
while n < 100 && n <= line("$")
|
|
if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
|
|
setf specman
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf eiffel
|
|
endif
|
|
enddef
|
|
|
|
def IsForth(): bool
|
|
var first_line = nextnonblank(1)
|
|
|
|
# SwiftForth block comment (line is usually filled with '-' or '=') or
|
|
# OPTIONAL (sometimes precedes the header comment)
|
|
if getline(first_line) =~? '^\%({\%(\s\|$\)\|OPTIONAL\s\)'
|
|
return true
|
|
endif
|
|
|
|
var n = first_line
|
|
while n < 100 && n <= line("$")
|
|
# Forth comments and colon definitions
|
|
if getline(n) =~ '^[:(\\] '
|
|
return true
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
return false
|
|
enddef
|
|
|
|
# Distinguish between Forth and Fortran
|
|
export def FTf()
|
|
if exists("g:filetype_f")
|
|
exe "setf " .. g:filetype_f
|
|
elseif IsForth()
|
|
setf forth
|
|
else
|
|
setf fortran
|
|
endif
|
|
enddef
|
|
|
|
export def FTfrm()
|
|
if exists("g:filetype_frm")
|
|
exe "setf " .. g:filetype_frm
|
|
return
|
|
endif
|
|
|
|
if getline(1) == "VERSION 5.00"
|
|
setf vb
|
|
return
|
|
endif
|
|
|
|
var lines = getline(1, min([line("$"), 5]))
|
|
|
|
if match(lines, ft_visual_basic_content) > -1
|
|
setf vb
|
|
else
|
|
setf form
|
|
endif
|
|
enddef
|
|
|
|
# Distinguish between Forth and F#
|
|
export def FTfs()
|
|
if exists("g:filetype_fs")
|
|
exe "setf " .. g:filetype_fs
|
|
elseif IsForth()
|
|
setf forth
|
|
else
|
|
setf fsharp
|
|
endif
|
|
enddef
|
|
|
|
# Recursively search for Hare source files in a directory and any
|
|
# subdirectories, up to a given depth.
|
|
def IsHareModule(dir: string, depth: number): bool
|
|
if depth <= 0
|
|
return !empty(glob(dir .. '/*.ha'))
|
|
endif
|
|
|
|
return reduce(sort(glob(dir .. '/*', true, true),
|
|
(a, b) => isdirectory(a) - isdirectory(b)),
|
|
(acc, n) => acc
|
|
|| n =~ '\.ha$'
|
|
|| isdirectory(n)
|
|
&& IsHareModule(n, depth - 1),
|
|
false)
|
|
enddef
|
|
|
|
# Determine if a README file exists within a Hare module and should be given the
|
|
# Haredoc filetype.
|
|
export def FTharedoc()
|
|
if exists('g:filetype_haredoc')
|
|
if IsHareModule('<afile>:h', get(g:, 'haredoc_search_depth', 1))
|
|
setf haredoc
|
|
endif
|
|
endif
|
|
enddef
|
|
|
|
# Distinguish between HTML, XHTML, Django and Angular
|
|
export def FThtml()
|
|
var n = 1
|
|
|
|
# Test if the filename follows the Angular component template convention
|
|
# Disabled for the reasons mentioned here: #13594
|
|
# if expand('%:t') =~ '^.*\.component\.html$'
|
|
# setf htmlangular
|
|
# return
|
|
# endif
|
|
|
|
while n < 40 && n <= line("$")
|
|
# Check for Angular
|
|
if getline(n) =~ '@\(if\|for\|defer\|switch\)\|\*\(ngIf\|ngFor\|ngSwitch\|ngTemplateOutlet\)\|ng-template\|ng-content'
|
|
setf htmlangular
|
|
return
|
|
endif
|
|
# Check for XHTML
|
|
if getline(n) =~ '\<DTD\s\+XHTML\s'
|
|
setf xhtml
|
|
return
|
|
endif
|
|
# Check for Django
|
|
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\+'
|
|
setf htmldjango
|
|
return
|
|
endif
|
|
# Check for SuperHTML
|
|
if getline(n) =~ '<extend\|<super>'
|
|
setf superhtml
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf FALLBACK html
|
|
enddef
|
|
|
|
# Distinguish between standard IDL and MS-IDL
|
|
export def FTidl()
|
|
var n = 1
|
|
while n < 50 && n <= line("$")
|
|
if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
|
|
setf msidl
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf idl
|
|
enddef
|
|
|
|
# Distinguish between "default", Prolog, zsh module's C and Cproto prototype file.
|
|
export def ProtoCheck(default: string)
|
|
# zsh modules use '#include "*.pro"'
|
|
# https://github.com/zsh-users/zsh/blob/63f086d167960a27ecdbcb762179e2c2bf8a29f5/Src/Modules/example.c#L31
|
|
if getline(1) =~ '/* Generated automatically */'
|
|
setf c
|
|
# Cproto files have a comment in the first line and a function prototype in
|
|
# the second line, it always ends in ";". Indent files may also have
|
|
# comments, thus we can't match comments to see the difference.
|
|
# IDL files can have a single ';' in the second line, require at least one
|
|
# chacter before the ';'.
|
|
elseif getline(2) =~ '.;$'
|
|
setf cpp
|
|
else
|
|
# recognize Prolog by specific text in the first non-empty line
|
|
# require a blank after the '%' because Perl uses "%list" and "%translate"
|
|
var lnum = getline(nextnonblank(1))
|
|
if lnum =~ '\<prolog\>' || lnum =~ prolog_pattern
|
|
setf prolog
|
|
else
|
|
exe 'setf ' .. default
|
|
endif
|
|
endif
|
|
enddef
|
|
|
|
export def FTm()
|
|
if exists("g:filetype_m")
|
|
exe "setf " .. g:filetype_m
|
|
return
|
|
endif
|
|
|
|
# excluding end(for|function|if|switch|while) common to Murphi
|
|
var octave_block_terminators = '\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>'
|
|
|
|
var objc_preprocessor = '^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>'
|
|
|
|
var n = 1
|
|
var saw_comment = 0 # Whether we've seen a multiline comment leader.
|
|
while n < 100
|
|
var line = getline(n)
|
|
if line =~ '^\s*/\*'
|
|
# /* ... */ is a comment in Objective C and Murphi, so we can't conclude
|
|
# it's either of them yet, but track this as a hint in case we don't see
|
|
# anything more definitive.
|
|
saw_comment = 1
|
|
endif
|
|
if line =~ '^\s*//' || line =~ '^\s*@import\>' || line =~ objc_preprocessor
|
|
setf objc
|
|
return
|
|
endif
|
|
if line =~ '^\s*\%(#\|%!\)' || line =~ '^\s*unwind_protect\>' ||
|
|
\ line =~ '\%(^\|;\)\s*' .. octave_block_terminators
|
|
setf octave
|
|
return
|
|
endif
|
|
# TODO: could be Matlab or Octave
|
|
if line =~ '^\s*%'
|
|
setf matlab
|
|
return
|
|
endif
|
|
if line =~ '^\s*(\*'
|
|
setf mma
|
|
return
|
|
endif
|
|
if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
|
|
setf murphi
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
|
|
if saw_comment
|
|
# We didn't see anything definitive, but this looks like either Objective C
|
|
# or Murphi based on the comment leader. Assume the former as it is more
|
|
# common.
|
|
setf objc
|
|
else
|
|
# Default is Matlab
|
|
setf matlab
|
|
endif
|
|
enddef
|
|
|
|
export def FTmake()
|
|
# Check if it is a BSD, GNU, or Microsoft Makefile
|
|
unlet! b:make_flavor
|
|
|
|
# 1. filename
|
|
if expand('%:t') == 'BSDmakefile'
|
|
b:make_flavor = 'bsd'
|
|
setf make
|
|
return
|
|
elseif expand('%:t') == 'GNUmakefile'
|
|
b:make_flavor = 'gnu'
|
|
setf make
|
|
return
|
|
endif
|
|
|
|
# 2. user's setting
|
|
if exists('g:make_flavor')
|
|
b:make_flavor = g:make_flavor
|
|
setf make
|
|
return
|
|
elseif get(g:, 'make_microsoft')
|
|
echom "make_microsoft is deprecated; try g:make_flavor = 'microsoft' instead"
|
|
b:make_flavor = 'microsoft'
|
|
setf make
|
|
return
|
|
endif
|
|
|
|
# 3. try to detect a flavor from file content
|
|
var n = 1
|
|
while n < 1000 && n <= line('$')
|
|
var line = getline(n)
|
|
if line =~? '^\s*!\s*\(ifn\=\(def\)\=\|include\|message\|error\)\>'
|
|
b:make_flavor = 'microsoft'
|
|
break
|
|
elseif line =~ '^\.\%(export\|error\|for\|if\%(n\=\%(def\|make\)\)\=\|info\|warning\)\>'
|
|
b:make_flavor = 'bsd'
|
|
break
|
|
elseif line =~ '^ *\%(ifn\=\%(eq\|def\)\|define\|override\)\>'
|
|
b:make_flavor = 'gnu'
|
|
break
|
|
elseif line =~ '\$[({][a-z-]\+\s\+\S\+' # a function call, e.g. $(shell pwd)
|
|
b:make_flavor = 'gnu'
|
|
break
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf make
|
|
enddef
|
|
|
|
export def FTmms()
|
|
var n = 1
|
|
while n < 20
|
|
var line = getline(n)
|
|
if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
|
|
setf mmix
|
|
return
|
|
endif
|
|
if line =~ '^\s*#'
|
|
setf make
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf mmix
|
|
enddef
|
|
|
|
# This function checks if one of the first five lines start with a typical
|
|
# nroff pattern in man files. In that case it is probably an nroff file:
|
|
# 'filetype' is set and 1 is returned.
|
|
export def FTnroff(): number
|
|
var n = 1
|
|
while n <= 5
|
|
var line = getline(n)
|
|
if line =~ '^\%([.'']\s*\%(TH\|D[dt]\|S[Hh]\|d[es]1\?\|so\)\s\+\S\|[.'']\s*ig\>\|\%([.'']\s*\)\?\\"\)'
|
|
setf nroff
|
|
return 1
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
return 0
|
|
enddef
|
|
|
|
export def FTmm()
|
|
var n = 1
|
|
while n < 20
|
|
if getline(n) =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
|
|
setf objcpp
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf nroff
|
|
enddef
|
|
|
|
# Returns true if file content looks like LambdaProlog module
|
|
def IsLProlog(): bool
|
|
# skip apparent comments and blank lines, what looks like
|
|
# LambdaProlog comment may be RAPID header
|
|
var lnum: number = nextnonblank(1)
|
|
while lnum > 0 && lnum < line('$') && getline(lnum) =~ '^\s*%' # LambdaProlog comment
|
|
lnum = nextnonblank(lnum + 1)
|
|
endwhile
|
|
# this pattern must not catch a go.mod file
|
|
return getline(lnum) =~ '\<module\s\+\w\+\s*\.\s*\(%\|$\)'
|
|
enddef
|
|
|
|
def IsModula2(): bool
|
|
return getline(nextnonblank(1)) =~ '\<MODULE\s\+\w\+\s*\%(\[.*]\s*\)\=;\|^\s*(\*'
|
|
enddef
|
|
|
|
def SetFiletypeModula2()
|
|
const KNOWN_DIALECTS = ["iso", "pim", "r10"]
|
|
const KNOWN_EXTENSIONS = ["gm2"]
|
|
const LINE_COUNT = 200
|
|
const TAG = '(\*!m2\(\w\+\)\%(+\(\w\+\)\)\=\*)'
|
|
|
|
var dialect = get(g:, "modula2_default_dialect", "pim")
|
|
var extension = get(g:, "modula2_default_extension", "")
|
|
|
|
var matches = []
|
|
|
|
# ignore unknown dialects or badly formatted tags
|
|
for lnum in range(1, min([line("$"), LINE_COUNT]))
|
|
matches = matchlist(getline(lnum), TAG)
|
|
if !empty(matches)
|
|
if index(KNOWN_DIALECTS, matches[1]) >= 0
|
|
dialect = matches[1]
|
|
endif
|
|
if index(KNOWN_EXTENSIONS, matches[2]) >= 0
|
|
extension = matches[2]
|
|
endif
|
|
break
|
|
endif
|
|
endfor
|
|
|
|
modula2#SetDialect(dialect, extension)
|
|
|
|
setf modula2
|
|
enddef
|
|
|
|
# Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
|
|
export def FTmod()
|
|
if get(g:, "filetype_mod", "") == "modula2" || IsModula2()
|
|
SetFiletypeModula2()
|
|
return
|
|
endif
|
|
|
|
if exists("g:filetype_mod")
|
|
exe "setf " .. g:filetype_mod
|
|
elseif expand("<afile>") =~ '\<go.mod$'
|
|
setf gomod
|
|
elseif IsLProlog()
|
|
setf lprolog
|
|
elseif IsRapid()
|
|
setf rapid
|
|
else
|
|
# Nothing recognized, assume modsim3
|
|
setf modsim3
|
|
endif
|
|
enddef
|
|
|
|
export def FTpl()
|
|
if exists("g:filetype_pl")
|
|
exe "setf " .. g:filetype_pl
|
|
else
|
|
# recognize Prolog by specific text in the first non-empty line
|
|
# require a blank after the '%' because Perl uses "%list" and "%translate"
|
|
var line = getline(nextnonblank(1))
|
|
if line =~ '\<prolog\>' || line =~ prolog_pattern
|
|
setf prolog
|
|
else
|
|
setf perl
|
|
endif
|
|
endif
|
|
enddef
|
|
|
|
export def FTinc()
|
|
if exists("g:filetype_inc")
|
|
exe "setf " .. g:filetype_inc
|
|
else
|
|
var lines = getline(1) .. getline(2) .. getline(3)
|
|
if lines =~? "perlscript"
|
|
setf aspperl
|
|
elseif lines =~ "<%"
|
|
setf aspvbs
|
|
elseif lines =~ "<?"
|
|
setf php
|
|
# Pascal supports // comments but they're vary rarely used for file
|
|
# headers so assume POV-Ray
|
|
elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? ft_pascal_keywords
|
|
setf pascal
|
|
elseif lines =~# '\<\%(require\|inherit\)\>' || lines =~# '[A-Z][A-Za-z0-9_:${}]*\s\+\%(??\|[?:+]\)\?= '
|
|
setf bitbake
|
|
else
|
|
FTasmsyntax()
|
|
if exists("b:asmsyntax")
|
|
exe "setf " .. fnameescape(b:asmsyntax)
|
|
else
|
|
setf pov
|
|
endif
|
|
endif
|
|
endif
|
|
enddef
|
|
|
|
export def FTprogress_cweb()
|
|
if exists("g:filetype_w")
|
|
exe "setf " .. g:filetype_w
|
|
return
|
|
endif
|
|
if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
|
|
setf progress
|
|
else
|
|
setf cweb
|
|
endif
|
|
enddef
|
|
|
|
# These include the leading '%' sign
|
|
var 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\)'
|
|
# This is the start/end of a block that is copied literally to the processor file (C/C++)
|
|
var ft_swig_verbatim_block_start = '^\s*%{'
|
|
|
|
export def FTi()
|
|
if exists("g:filetype_i")
|
|
exe "setf " .. g:filetype_i
|
|
return
|
|
endif
|
|
# This function checks for an assembly comment or a SWIG keyword or verbatim block in the first 50 lines.
|
|
# If not found, assume Progress.
|
|
var lnum = 1
|
|
while lnum <= 50 && lnum < line('$')
|
|
var line = getline(lnum)
|
|
if line =~ '^\s*;' || line =~ '^\*'
|
|
FTasm()
|
|
return
|
|
elseif line =~ ft_swig_keywords || line =~ ft_swig_verbatim_block_start
|
|
setf swig
|
|
return
|
|
endif
|
|
lnum += 1
|
|
endwhile
|
|
setf progress
|
|
enddef
|
|
|
|
var ft_pascal_comments = '^\s*\%({\|(\*\|//\)'
|
|
var ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>'
|
|
|
|
export def FTprogress_pascal()
|
|
if exists("g:filetype_p")
|
|
exe "setf " .. g:filetype_p
|
|
return
|
|
endif
|
|
# This function checks for valid Pascal syntax in the first ten lines.
|
|
# Look for either an opening comment or a program start.
|
|
# If not found, assume Progress.
|
|
var lnum = 1
|
|
while lnum <= 10 && lnum < line('$')
|
|
var line = getline(lnum)
|
|
if line =~ ft_pascal_comments || line =~? ft_pascal_keywords
|
|
setf pascal
|
|
return
|
|
elseif line !~ '^\s*$' || line =~ '^/\*'
|
|
# Not an empty line: Doesn't look like valid Pascal code.
|
|
# Or it looks like a Progress /* comment
|
|
break
|
|
endif
|
|
lnum += 1
|
|
endwhile
|
|
setf progress
|
|
enddef
|
|
|
|
export def FTpp()
|
|
if exists("g:filetype_pp")
|
|
exe "setf " .. g:filetype_pp
|
|
else
|
|
var line = getline(nextnonblank(1))
|
|
if line =~ ft_pascal_comments || line =~? ft_pascal_keywords
|
|
setf pascal
|
|
else
|
|
setf puppet
|
|
endif
|
|
endif
|
|
enddef
|
|
|
|
# Determine if *.prg is ABB RAPID. Can also be Clipper, FoxPro or eviews
|
|
export def FTprg()
|
|
if exists("g:filetype_prg")
|
|
exe "setf " .. g:filetype_prg
|
|
elseif IsRapid()
|
|
setf rapid
|
|
else
|
|
# Nothing recognized, assume Clipper
|
|
setf clipper
|
|
endif
|
|
enddef
|
|
|
|
export def FTr()
|
|
var max = line("$") > 50 ? 50 : line("$")
|
|
|
|
for n in range(1, max)
|
|
# Rebol is easy to recognize, check for that first
|
|
if getline(n) =~? '\<REBOL\>'
|
|
setf rebol
|
|
return
|
|
endif
|
|
endfor
|
|
|
|
for n in range(1, max)
|
|
# R has # comments
|
|
if getline(n) =~ '^\s*#'
|
|
setf r
|
|
return
|
|
endif
|
|
# Rexx has /* comments */
|
|
if getline(n) =~ '^\s*/\*'
|
|
setf rexx
|
|
return
|
|
endif
|
|
endfor
|
|
|
|
# Nothing recognized, use user default or assume Rexx
|
|
if exists("g:filetype_r")
|
|
exe "setf " .. g:filetype_r
|
|
else
|
|
# Rexx used to be the default, but R appears to be much more popular.
|
|
setf r
|
|
endif
|
|
enddef
|
|
|
|
export def McSetf()
|
|
# Rely on the file to start with a comment.
|
|
# MS message text files use ';', Sendmail files use '#' or 'dnl'
|
|
for lnum in range(1, min([line("$"), 20]))
|
|
var line = getline(lnum)
|
|
if line =~ '^\s*\(#\|dnl\)'
|
|
setf m4 # Sendmail .mc file
|
|
return
|
|
elseif line =~ '^\s*;'
|
|
setf msmessages # MS Message text file
|
|
return
|
|
endif
|
|
endfor
|
|
setf m4 # Default: Sendmail .mc file
|
|
enddef
|
|
|
|
# Called from filetype.vim and scripts.vim.
|
|
# When "setft" is passed and false then the 'filetype' option is not set.
|
|
export def SetFileTypeSH(name: string, setft = true): string
|
|
if setft && did_filetype()
|
|
# Filetype was already detected
|
|
return ''
|
|
endif
|
|
if setft && expand("<amatch>") =~ g:ft_ignore_pat
|
|
return ''
|
|
endif
|
|
if name =~ '^csh$' || name =~ '^#!.\{-2,}\<csh\>'
|
|
# Some .sh scripts contain #!/bin/csh.
|
|
return SetFileTypeShell("csh", setft)
|
|
elseif name =~ '^tcsh$' || name =~ '^#!.\{-2,}\<tcsh\>'
|
|
# Some .sh scripts contain #!/bin/tcsh.
|
|
return SetFileTypeShell("tcsh", setft)
|
|
elseif name =~ '^zsh$' || name =~ '^#!.\{-2,}\<zsh\>'
|
|
# Some .sh scripts contain #!/bin/zsh.
|
|
return SetFileTypeShell("zsh", setft)
|
|
elseif name =~ '^ksh$' || name =~ '^#!.\{-2,}\<ksh\>'
|
|
b:is_kornshell = 1
|
|
if exists("b:is_bash")
|
|
unlet b:is_bash
|
|
endif
|
|
if exists("b:is_sh")
|
|
unlet b:is_sh
|
|
endif
|
|
elseif exists("g:bash_is_sh") || name =~ '^bash2\=$' ||
|
|
\ name =~ '^#!.\{-2,}\<bash2\=\>'
|
|
b:is_bash = 1
|
|
if exists("b:is_kornshell")
|
|
unlet b:is_kornshell
|
|
endif
|
|
if exists("b:is_sh")
|
|
unlet b:is_sh
|
|
endif
|
|
elseif name =~ '^\%(da\)\=sh$' || name =~ '^#!.\{-2,}\<\%(da\)\=sh\>'
|
|
# Ubuntu links "sh" to "dash", thus it is expected to work the same way
|
|
b:is_sh = 1
|
|
if exists("b:is_kornshell")
|
|
unlet b:is_kornshell
|
|
endif
|
|
if exists("b:is_bash")
|
|
unlet b:is_bash
|
|
endif
|
|
endif
|
|
|
|
return SetFileTypeShell("sh", setft)
|
|
enddef
|
|
|
|
# For shell-like file types, check for an "exec" command hidden in a comment,
|
|
# as used for Tcl.
|
|
# When "setft" is passed and false then the 'filetype' option is not set.
|
|
# Also called from scripts.vim, thus can't be local to this script.
|
|
export def SetFileTypeShell(name: string, setft = true): string
|
|
if setft && did_filetype()
|
|
# Filetype was already detected
|
|
return ''
|
|
endif
|
|
if setft && expand("<amatch>") =~ g:ft_ignore_pat
|
|
return ''
|
|
endif
|
|
|
|
var lnum = 2
|
|
while lnum < 20 && lnum < line("$") && getline(lnum) =~ '^\s*\(#\|$\)'
|
|
# Skip empty and comment lines.
|
|
lnum += 1
|
|
endwhile
|
|
if lnum < line("$") && getline(lnum) =~ '\s*exec\s' && getline(lnum - 1) =~ '^\s*#.*\\$'
|
|
# Found an "exec" line after a comment with continuation
|
|
var n = substitute(getline(lnum), '\s*exec\s\+\([^ ]*/\)\=', '', '')
|
|
if n =~ '\<tclsh\|\<wish'
|
|
if setft
|
|
setf tcl
|
|
endif
|
|
return 'tcl'
|
|
endif
|
|
endif
|
|
|
|
if setft
|
|
exe "setf " .. name
|
|
endif
|
|
return name
|
|
enddef
|
|
|
|
export def CSH()
|
|
if did_filetype()
|
|
# Filetype was already detected
|
|
return
|
|
endif
|
|
if exists("g:filetype_csh")
|
|
SetFileTypeShell(g:filetype_csh)
|
|
elseif &shell =~ "tcsh"
|
|
SetFileTypeShell("tcsh")
|
|
else
|
|
SetFileTypeShell("csh")
|
|
endif
|
|
enddef
|
|
|
|
var ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
|
|
export def FTRules()
|
|
var path = expand('<amatch>:p')
|
|
if path =~ '/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|\%(usr/\)\=lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
|
|
setf udevrules
|
|
return
|
|
endif
|
|
if path =~ '^/etc/ufw/'
|
|
setf conf # Better than hog
|
|
return
|
|
endif
|
|
if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
|
|
setf javascript
|
|
return
|
|
endif
|
|
var config_lines: list<string>
|
|
try
|
|
config_lines = readfile('/etc/udev/udev.conf')
|
|
catch /^Vim\%((\a\+)\)\=:E484/
|
|
setf hog
|
|
return
|
|
endtry
|
|
var dir = expand('<amatch>:p:h')
|
|
for line in config_lines
|
|
if line =~ ft_rules_udev_rules_pattern
|
|
var udev_rules = substitute(line, ft_rules_udev_rules_pattern, '\1', "")
|
|
if dir == udev_rules
|
|
setf udevrules
|
|
endif
|
|
break
|
|
endif
|
|
endfor
|
|
setf hog
|
|
enddef
|
|
|
|
export def SQL()
|
|
if exists("g:filetype_sql")
|
|
exe "setf " .. g:filetype_sql
|
|
else
|
|
setf sql
|
|
endif
|
|
enddef
|
|
|
|
export def FTsa()
|
|
if join(getline(1, 4), "\n") =~# '\%(^\|\n\);'
|
|
setf tiasm
|
|
return
|
|
endif
|
|
setf sather
|
|
enddef
|
|
|
|
# This function checks the first 25 lines of file extension "sc" to resolve
|
|
# detection between scala and SuperCollider.
|
|
# NOTE: We don't check for 'Class : Method', as this can easily be confused
|
|
# with valid Scala like `val x : Int = 3`. So we instead only rely on
|
|
# checks that can't be confused.
|
|
export def FTsc()
|
|
for lnum in range(1, min([line("$"), 25]))
|
|
if getline(lnum) =~# 'var\s<\|classvar\s<\|\^this.*\||\w\+|\|+\s\w*\s{\|\*ar\s'
|
|
setf supercollider
|
|
return
|
|
endif
|
|
endfor
|
|
setf scala
|
|
enddef
|
|
|
|
# This function checks the first line of file extension "scd" to resolve
|
|
# detection between scdoc and SuperCollider
|
|
export def FTscd()
|
|
if getline(1) =~# '\%^\S\+(\d[0-9A-Za-z]*)\%(\s\+\"[^"]*\"\%(\s\+\"[^"]*\"\)\=\)\=$'
|
|
setf scdoc
|
|
else
|
|
setf supercollider
|
|
endif
|
|
enddef
|
|
|
|
# If the file has an extension of 't' and is in a directory 't' or 'xt' then
|
|
# it is almost certainly a Perl test file.
|
|
# If the first line starts with '#' and contains 'perl' it's probably a Perl
|
|
# file.
|
|
# (Slow test) If a file contains a 'use' statement then it is almost certainly
|
|
# a Perl file.
|
|
export def FTperl(): number
|
|
var dirname = expand("%:p:h:t")
|
|
if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
|
|
setf perl
|
|
return 1
|
|
endif
|
|
if getline(1)[0] == '#' && getline(1) =~ 'perl'
|
|
setf perl
|
|
return 1
|
|
endif
|
|
var save_cursor = getpos('.')
|
|
call cursor(1, 1)
|
|
var has_use = search('^use\s\s*\k', 'c', 30) > 0
|
|
call setpos('.', save_cursor)
|
|
if has_use
|
|
setf perl
|
|
return 1
|
|
endif
|
|
return 0
|
|
enddef
|
|
|
|
# LambdaProlog and Standard ML signature files
|
|
export def FTsig()
|
|
if exists("g:filetype_sig")
|
|
exe "setf " .. g:filetype_sig
|
|
return
|
|
endif
|
|
|
|
var lprolog_comment = '^\s*\%(/\*\|%\)'
|
|
var lprolog_keyword = '^\s*sig\s\+\a'
|
|
var sml_comment = '^\s*(\*'
|
|
var sml_keyword = '^\s*\%(signature\|structure\)\s\+\a'
|
|
|
|
var line = getline(nextnonblank(1))
|
|
|
|
if line =~ lprolog_comment || line =~# lprolog_keyword
|
|
setf lprolog
|
|
elseif line =~ sml_comment || line =~# sml_keyword
|
|
setf sml
|
|
endif
|
|
enddef
|
|
|
|
# This function checks the first 100 lines of files matching "*.sil" to
|
|
# resolve detection between Swift Intermediate Language and SILE.
|
|
export def FTsil()
|
|
for lnum in range(1, [line('$'), 100]->min())
|
|
var line: string = getline(lnum)
|
|
if line =~ '^\s*[\\%]'
|
|
setf sile
|
|
return
|
|
elseif line =~ '^\s*\S'
|
|
setf sil
|
|
return
|
|
endif
|
|
endfor
|
|
# no clue, default to "sil"
|
|
setf sil
|
|
enddef
|
|
|
|
export def FTsys()
|
|
if exists("g:filetype_sys")
|
|
exe "setf " .. g:filetype_sys
|
|
elseif IsRapid()
|
|
setf rapid
|
|
else
|
|
setf bat
|
|
endif
|
|
enddef
|
|
|
|
# Choose context, plaintex, or tex (LaTeX) based on these rules:
|
|
# 1. Check the first line of the file for "%&<format>".
|
|
# 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
|
|
# 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
|
|
export def FTtex()
|
|
var firstline = getline(1)
|
|
var format: string
|
|
if firstline =~ '^%&\s*\a\+'
|
|
format = tolower(matchstr(firstline, '\a\+'))
|
|
format = substitute(format, 'pdf', '', '')
|
|
if format == 'tex'
|
|
format = 'latex'
|
|
elseif format == 'plaintex'
|
|
format = 'plain'
|
|
endif
|
|
elseif expand('%') =~ 'tex/context/.*/.*.tex'
|
|
format = 'context'
|
|
else
|
|
# Default value, may be changed later:
|
|
format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
|
|
# Save position, go to the top of the file, find first non-comment line.
|
|
var save_cursor = getpos('.')
|
|
call cursor(1, 1)
|
|
var firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
|
|
if firstNC > 0
|
|
# Check the next thousand lines for a LaTeX or ConTeXt keyword.
|
|
var lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
|
|
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\>'
|
|
var kwline = search('^\s*\\\%(' .. lpat .. '\)\|^\s*\\\(' .. cpat .. '\)',
|
|
'cnp', firstNC + 1000)
|
|
if kwline == 1 # lpat matched
|
|
format = 'latex'
|
|
elseif kwline == 2 # cpat matched
|
|
format = 'context'
|
|
endif # If neither matched, keep default set above.
|
|
# let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
|
|
# let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
|
|
# if cline > 0
|
|
# let format = 'context'
|
|
# endif
|
|
# if lline > 0 && (cline == 0 || cline > lline)
|
|
# let format = 'tex'
|
|
# endif
|
|
endif # firstNC
|
|
call setpos('.', save_cursor)
|
|
endif # firstline =~ '^%&\s*\a\+'
|
|
|
|
# Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
|
|
if format == 'plain'
|
|
setf plaintex
|
|
elseif format == 'context'
|
|
setf context
|
|
else # probably LaTeX
|
|
setf tex
|
|
endif
|
|
return
|
|
enddef
|
|
|
|
export def FTxml()
|
|
var n = 1
|
|
while n < 100 && n <= line("$")
|
|
var line = getline(n)
|
|
# DocBook 4 or DocBook 5.
|
|
var is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
|
|
var is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
|
|
if is_docbook4 || is_docbook5
|
|
b:docbk_type = "xml"
|
|
if is_docbook5
|
|
b:docbk_ver = 5
|
|
else
|
|
b:docbk_ver = 4
|
|
endif
|
|
setf docbk
|
|
return
|
|
endif
|
|
if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
|
|
setf xbl
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf xml
|
|
enddef
|
|
|
|
export def FTy()
|
|
var n = 1
|
|
while n < 100 && n <= line("$")
|
|
var line = getline(n)
|
|
if line =~ '^\s*%'
|
|
setf yacc
|
|
return
|
|
endif
|
|
if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
|
|
setf racc
|
|
return
|
|
endif
|
|
n += 1
|
|
endwhile
|
|
setf yacc
|
|
enddef
|
|
|
|
export def Redif()
|
|
var lnum = 1
|
|
while lnum <= 5 && lnum < line('$')
|
|
if getline(lnum) =~ "^\ctemplate-type:"
|
|
setf redif
|
|
return
|
|
endif
|
|
lnum += 1
|
|
endwhile
|
|
enddef
|
|
|
|
# This function is called for all files under */debian/patches/*, make sure not
|
|
# to non-dep3patch files, such as README and other text files.
|
|
export def Dep3patch()
|
|
if expand('%:t') ==# 'series'
|
|
return
|
|
endif
|
|
|
|
for ln in getline(1, 100)
|
|
if ln =~# '^\%(Description\|Subject\|Origin\|Bug\|Forwarded\|Author\|From\|Reviewed-by\|Acked-by\|Last-Updated\|Applied-Upstream\):'
|
|
setf dep3patch
|
|
return
|
|
elseif ln =~# '^---'
|
|
# end of headers found. stop processing
|
|
return
|
|
endif
|
|
endfor
|
|
enddef
|
|
|
|
# This function checks the first 15 lines for appearance of 'FoamFile'
|
|
# and then 'object' in a following line.
|
|
# In that case, it's probably an OpenFOAM file
|
|
export def FTfoam()
|
|
var ffile = 0
|
|
var lnum = 1
|
|
while lnum <= 15
|
|
if getline(lnum) =~# '^FoamFile'
|
|
ffile = 1
|
|
elseif ffile == 1 && getline(lnum) =~# '^\s*object'
|
|
setf foam
|
|
return
|
|
endif
|
|
lnum += 1
|
|
endwhile
|
|
enddef
|
|
|
|
# Determine if a *.tf file is TF mud client or terraform
|
|
export def FTtf()
|
|
var numberOfLines = line('$')
|
|
for i in range(1, numberOfLines)
|
|
var currentLine = trim(getline(i))
|
|
var firstCharacter = currentLine[0]
|
|
if firstCharacter !=? ";" && firstCharacter !=? "/" && firstCharacter !=? ""
|
|
setf terraform
|
|
return
|
|
endif
|
|
endfor
|
|
setf tf
|
|
enddef
|
|
|
|
var ft_krl_header = '\&\w+'
|
|
# Determine if a *.src file is Kuka Robot Language
|
|
export def FTsrc()
|
|
var ft_krl_def_or_deffct = '%(global\s+)?def%(fct)?>'
|
|
if exists("g:filetype_src")
|
|
exe "setf " .. g:filetype_src
|
|
elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. ft_krl_header .. '|' .. ft_krl_def_or_deffct .. ')'
|
|
setf krl
|
|
endif
|
|
enddef
|
|
|
|
# Determine if a *.dat file is Kuka Robot Language
|
|
export def FTdat()
|
|
var ft_krl_defdat = 'defdat>'
|
|
if exists("g:filetype_dat")
|
|
exe "setf " .. g:filetype_dat
|
|
elseif getline(nextnonblank(1)) =~? '\v^\s*%(' .. ft_krl_header .. '|' .. ft_krl_defdat .. ')'
|
|
setf krl
|
|
endif
|
|
enddef
|
|
|
|
export def FTlsl()
|
|
if exists("g:filetype_lsl")
|
|
exe "setf " .. g:filetype_lsl
|
|
endif
|
|
|
|
var line = getline(nextnonblank(1))
|
|
if line =~ '^\s*%' || line =~# ':\s*trait\s*$'
|
|
setf larch
|
|
else
|
|
setf lsl
|
|
endif
|
|
enddef
|
|
|
|
export def FTtyp()
|
|
if exists("g:filetype_typ")
|
|
exe "setf " .. g:filetype_typ
|
|
return
|
|
endif
|
|
|
|
# Look for SQL type definition syntax
|
|
for line in getline(1, 200)
|
|
# SQL type files may define the casing
|
|
if line =~ '^CASE\s\==\s\=\(SAME\|LOWER\|UPPER\|OPPOSITE\)$'
|
|
setf sql
|
|
return
|
|
endif
|
|
|
|
# SQL type files may define some types as follows
|
|
if line =~ '^TYPE\s.*$'
|
|
setf sql
|
|
return
|
|
endif
|
|
endfor
|
|
|
|
# Otherwise, affect the typst filetype
|
|
setf typst
|
|
enddef
|
|
|
|
# Detect Microsoft Developer Studio Project files (Makefile) or Faust DSP
|
|
# files.
|
|
export def FTdsp()
|
|
if exists("g:filetype_dsp")
|
|
exe "setf " .. g:filetype_dsp
|
|
return
|
|
endif
|
|
|
|
# Test the filename
|
|
if expand('%:t') =~ '^[mM]akefile.*$'
|
|
setf make
|
|
return
|
|
endif
|
|
|
|
# Test the file contents
|
|
for line in getline(1, 200)
|
|
# Chech for comment style
|
|
if line =~ '^#.*'
|
|
setf make
|
|
return
|
|
endif
|
|
|
|
# Check for common lines
|
|
if line =~ '^.*Microsoft Developer Studio Project File.*$'
|
|
setf make
|
|
return
|
|
endif
|
|
|
|
if line =~ '^!MESSAGE This is not a valid makefile\..+$'
|
|
setf make
|
|
return
|
|
endif
|
|
|
|
# Check for keywords
|
|
if line =~ '^!(IF,ELSEIF,ENDIF).*$'
|
|
setf make
|
|
return
|
|
endif
|
|
|
|
# Check for common assignments
|
|
if line =~ '^SOURCE=.*$'
|
|
setf make
|
|
return
|
|
endif
|
|
endfor
|
|
|
|
# Otherwise, assume we have a Faust file
|
|
setf faust
|
|
enddef
|
|
|
|
# Set the filetype of a *.v file to Verilog, V or Cog based on the first 500
|
|
# lines.
|
|
export def FTv()
|
|
if did_filetype()
|
|
# ":setf" will do nothing, bail out early
|
|
return
|
|
endif
|
|
if exists("g:filetype_v")
|
|
exe "setf " .. g:filetype_v
|
|
return
|
|
endif
|
|
|
|
var in_comment = 0
|
|
for lnum in range(1, min([line("$"), 500]))
|
|
var line = getline(lnum)
|
|
# Skip Verilog and V comments (lines and blocks).
|
|
if line =~ '^\s*/\*'
|
|
# start comment block
|
|
in_comment = 1
|
|
endif
|
|
if in_comment == 1
|
|
if line =~ '\*/'
|
|
# end comment block
|
|
in_comment = 0
|
|
endif
|
|
# skip comment-block line
|
|
continue
|
|
endif
|
|
if line =~ '^\s*//'
|
|
# skip comment line
|
|
continue
|
|
endif
|
|
|
|
# Coq: line ends with a '.' followed by an optional variable number of
|
|
# spaces or contains the start of a comment, but not inside a Verilog or V
|
|
# comment.
|
|
# Example: "Definition x := 10. (*".
|
|
if (line =~ '\.\s*$' && line !~ '/[/*]') || (line =~ '(\*' && line !~ '/[/*].*(\*')
|
|
setf coq
|
|
return
|
|
endif
|
|
|
|
# Verilog: line ends with ';' followed by an optional variable number of
|
|
# spaces and an optional start of a comment.
|
|
# Example: " b <= a + 1; // Add 1".
|
|
# Alternatively: a module is defined: " module MyModule ( input )"
|
|
if line =~ ';\s*\(/[/*].*\)\?$' || line =~ '\C^\s*module\s\+\w\+\s*('
|
|
setf verilog
|
|
return
|
|
endif
|
|
endfor
|
|
|
|
# No line matched, fall back to "v".
|
|
setf v
|
|
enddef
|
|
|
|
export def FTvba()
|
|
if getline(1) =~ '^["#] Vimball Archiver'
|
|
setf vim
|
|
else
|
|
setf vb
|
|
endif
|
|
enddef
|
|
|
|
export def Detect_UCI_statements(): bool
|
|
# Match a config or package statement at the start of the line.
|
|
const config_or_package_statement = '^\s*\(\(c\|config\)\|\(p\|package\)\)\s\+\S'
|
|
# Match a line that is either all blank or blank followed by a comment
|
|
const comment_or_blank = '^\s*\(#.*\)\?$'
|
|
|
|
# Return true iff the file has a config or package statement near the
|
|
# top of the file and all preceding lines were comments or blank.
|
|
return getline(1) =~# config_or_package_statement
|
|
\ || getline(1) =~# comment_or_blank
|
|
\ && ( getline(2) =~# config_or_package_statement
|
|
\ || getline(2) =~# comment_or_blank
|
|
\ && getline(3) =~# config_or_package_statement
|
|
\ )
|
|
enddef
|
|
|
|
# Uncomment this line to check for compilation errors early
|
|
# defcompile
|