diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | autoload/polyglot/detect.vim | 25 | ||||
-rw-r--r-- | autoload/polyglot/ft.vim | 757 | ||||
-rw-r--r-- | autoload/polyglot/shebang.vim | 406 | ||||
-rw-r--r-- | autoload/polyglot/sleuth.vim | 2 | ||||
-rw-r--r-- | ftdetect/polyglot.vim | 107 | ||||
-rwxr-xr-x | scripts/build | 33 |
7 files changed, 1251 insertions, 81 deletions
@@ -7,4 +7,4 @@ test: @ scripts/test dev: - @ find scripts . -type f -depth 1 | DEV=1 entr bash -c 'make && make test' + @ find scripts autoload/polyglot ftdetect tests . -type f -depth 1 | DEV=1 entr bash -c 'make && make test' diff --git a/autoload/polyglot/detect.vim b/autoload/polyglot/detect.vim index af143865..86783cb3 100644 --- a/autoload/polyglot/detect.vim +++ b/autoload/polyglot/detect.vim @@ -1,3 +1,11 @@ +" Line continuation is used here, remove 'C' from 'cpoptions' +let s:cpo_save = &cpo +set cpo&vim + +func! s:WritePostOnce(fn) + exe 'au! filetypedetect BufWritePost <buffer> ++once ' . a:fn +endfunc + " DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE func! polyglot#detect#Inp() @@ -185,7 +193,8 @@ func! polyglot#detect#Pm() let &ft = g:filetype_pm | return endif if polyglot#shebang#Detect() | return | endif - set ft=perl | au BufWritePost <buffer> ++once call polyglot#detect#Pm() + setf perl + call s:WritePostOnce('call polyglot#detect#Pm()') return endfunc @@ -207,7 +216,8 @@ func! polyglot#detect#Pl() let &ft = g:filetype_pl | return endif if polyglot#shebang#Detect() | return | endif - set ft=perl | au BufWritePost <buffer> ++once call polyglot#detect#Pl() + setf perl + call s:WritePostOnce('call polyglot#detect#Pl()') return endfunc @@ -231,7 +241,8 @@ func! polyglot#detect#T() let &ft = g:filetype_t | return endif if polyglot#shebang#Detect() | return | endif - set ft=perl | au BufWritePost <buffer> ++once call polyglot#detect#T() + setf perl + call s:WritePostOnce('call polyglot#detect#T()') return endfunc @@ -259,6 +270,12 @@ func! polyglot#detect#Html() set ft=xhtml | return endif endfor - set ft=html | au BufWritePost <buffer> ++once call polyglot#detect#Html() + setf html + call s:WritePostOnce('call polyglot#detect#Html()') return endfunc + +" DO NOT EDIT CODE ABOVE, IT IS GENERATED WITH MAKEFILE + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/autoload/polyglot/ft.vim b/autoload/polyglot/ft.vim new file mode 100644 index 00000000..35812c37 --- /dev/null +++ b/autoload/polyglot/ft.vim @@ -0,0 +1,757 @@ +" Vim functions for file type detection +" +" Maintainer: Bram Moolenaar <Bram@vim.org> +" Last Change: 2020 Aug 17 + +" These functions are moved here from runtime/filetype.vim to make startup +" faster. + +" Line continuation is used here, remove 'C' from 'cpoptions' +let s:cpo_save = &cpo +set cpo&vim + +func polyglot#ft#Check_inp() + if getline(1) =~ '^\*' + setf abaqus + else + let n = 1 + if line("$") > 500 + let nmax = 500 + else + let nmax = line("$") + endif + while n <= nmax + if getline(n) =~? "^header surface data" + setf trasys + break + endif + let n = n + 1 + endwhile + endif +endfunc + +" 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. +func polyglot#ft#FTasm() + " make sure b:asmsyntax exists + if !exists("b:asmsyntax") + let b:asmsyntax = "" + endif + + if b:asmsyntax == "" + call polyglot#ft#FTasmsyntax() + endif + + " if b:asmsyntax still isn't set, default to asmsyntax or GNU + if b:asmsyntax == "" + if exists("g:asmsyntax") + let b:asmsyntax = g:asmsyntax + else + let b:asmsyntax = "asm" + endif + endif + + exe "setf " . fnameescape(b:asmsyntax) +endfunc + +func polyglot#ft#FTasmsyntax() + " see if file contains any asmsyntax=foo overrides. If so, change + " b:asmsyntax appropriately + let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4). + \" ".getline(5)." " + let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s') + if match != '' + let b:asmsyntax = match + elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library')) + let b:asmsyntax = "vmasm" + endif +endfunc + +" Check if one of the first five lines contains "VB_Name". In that case it is +" probably a Visual Basic file. Otherwise it's assumed to be "alt" filetype. +func polyglot#ft#FTVB(alt) + if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)' + setf vb + else + exe "setf " . a:alt + endif +endfunc + +func polyglot#ft#FTbtm() + if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm + setf dosbatch + else + setf btm + endif +endfunc + +func polyglot#ft#BindzoneCheck(default) + if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA' + setf bindzone + elseif a:default != '' + exe 'setf ' . a:default + endif +endfunc + +func polyglot#ft#FTlpc() + if exists("g:lpc_syntax_for_c") + let lnum = 1 + while lnum <= 12 + if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)' + setf lpc + return + endif + let lnum = lnum + 1 + endwhile + endif + setf c +endfunc + +func polyglot#ft#FTheader() + if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1 + if exists("g:c_syntax_for_h") + setf objc + else + setf objcpp + endif + elseif exists("g:c_syntax_for_h") + setf c + elseif exists("g:ch_syntax_for_h") + setf ch + else + setf cpp + endif +endfunc + +" 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. +func polyglot#ft#FTchange() + let 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 + let lnum = lnum + 1 + endwhile + setf chill +endfunc + +func polyglot#ft#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. + let lnum = 1 + while lnum < 6 + let 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 + let lnum = lnum + 1 + endw + setf dtd +endfunc + +func polyglot#ft#EuphoriaCheck() + if exists('g:filetype_euphoria') + exe 'setf ' . g:filetype_euphoria + else + setf euphoria3 + endif +endfunc + +func polyglot#ft#DtraceCheck() + let 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 +endfunc + +func polyglot#ft#FTe() + if exists('g:filetype_euphoria') + exe 'setf ' . g:filetype_euphoria + else + let n = 1 + while n < 100 && n <= line("$") + if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$" + setf specman + return + endif + let n = n + 1 + endwhile + setf eiffel + endif +endfunc + +" Distinguish between HTML, XHTML and Django +func polyglot#ft#FThtml() + let n = 1 + while n < 10 && n <= line("$") + if getline(n) =~ '\<DTD\s\+XHTML\s' + setf xhtml + return + endif + if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+' + setf htmldjango + return + endif + let n = n + 1 + endwhile + setf FALLBACK html +endfunc + +" Distinguish between standard IDL and MS-IDL +func polyglot#ft#FTidl() + let n = 1 + while n < 50 && n <= line("$") + if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"' + setf msidl + return + endif + let n = n + 1 + endwhile + setf idl +endfunc + +" Distinguish between "default" and Cproto prototype file. */ +func polyglot#ft#ProtoCheck(default) + " 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 ';'. + if getline(2) =~ '.;$' + setf cpp + else + exe 'setf ' . a:default + endif +endfunc + +func polyglot#ft#FTm() + let n = 1 + let saw_comment = 0 " Whether we've seen a multiline comment leader. + while n < 100 + let 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. + let saw_comment = 1 + endif + if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)' + setf objc + return + endif + if line =~ '^\s*%' + setf matlab + return + endif + if line =~ '^\s*(\*' + setf mma + return + endif + if line =~ '^\c\s*\(\(type\|var\)\>\|--\)' + setf murphi + return + endif + let n = 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 + elseif exists("g:filetype_m") + " Use user specified default filetype for .m + exe "setf " . g:filetype_m + else + " Default is matlab + setf matlab + endif +endfunc + +func polyglot#ft#FTmms() + let n = 1 + while n < 20 + let line = getline(n) + if line =~ '^\s*\(%\|//\)' || line =~ '^\*' + setf mmix + return + endif + if line =~ '^\s*#' + setf make + return + endif + let n = n + 1 + endwhile + setf mmix +endfunc + +" This function checks if one of the first five lines start with a dot. In +" that case it is probably an nroff file: 'filetype' is set and 1 is returned. +func polyglot#ft#FTnroff() + if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.' + setf nroff + return 1 + endif + return 0 +endfunc + +func polyglot#ft#FTmm() + let n = 1 + while n < 20 + let line = getline(n) + if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)' + setf objcpp + return + endif + let n = n + 1 + endwhile + setf nroff +endfunc + +func polyglot#ft#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" + let l = getline(nextnonblank(1)) + if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-' + setf prolog + else + setf perl + endif + endif +endfunc + +func polyglot#ft#FTinc() + if exists("g:filetype_inc") + exe "setf " . g:filetype_inc + else + let lines = getline(1).getline(2).getline(3) + if lines =~? "perlscript" + setf aspperl + elseif lines =~ "<%" + setf aspvbs + elseif lines =~ "<?" + setf php + else + call polyglot#ft#FTasmsyntax() + if exists("b:asmsyntax") + exe "setf " . fnameescape(b:asmsyntax) + else + setf pov + endif + endif + endif +endfunc + +func polyglot#ft#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 +endfunc + +func polyglot#ft#FTprogress_asm() + if exists("g:filetype_i") + exe "setf " . g:filetype_i + return + endif + " This function checks for an assembly comment the first ten lines. + " If not found, assume Progress. + let lnum = 1 + while lnum <= 10 && lnum < line('$') + let line = getline(lnum) + if line =~ '^\s*;' || line =~ '^\*' + call polyglot#ft#FTasm() + return + elseif line !~ '^\s*$' || line =~ '^/\*' + " Not an empty line: Doesn't look like valid assembly code. + " Or it looks like a Progress /* comment + break + endif + let lnum = lnum + 1 + endw + setf progress +endfunc + +func polyglot#ft#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. + let lnum = 1 + while lnum <= 10 && lnum < line('$') + let line = getline(lnum) + if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>' + \ || line =~ '^\s*{' || line =~ '^\s*(\*' + 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 + let lnum = lnum + 1 + endw + setf progress +endfunc + +func polyglot#ft#FTr() + let 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 +endfunc + +func polyglot#ft#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])) + let 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 +endfunc + +" Called from filetype.vim and scripts.vim. +func polyglot#ft#SetFileTypeSH(name) + if did_filetype() + " Filetype was already detected + return + endif + if expand("<amatch>") =~ g:ft_ignore_pat + return + endif + if a:name =~ '\<csh\>' + " Some .sh scripts contain #!/bin/csh. + call polyglot#ft#SetFileTypeShell("csh") + return + elseif a:name =~ '\<tcsh\>' + " Some .sh scripts contain #!/bin/tcsh. + call polyglot#ft#SetFileTypeShell("tcsh") + return + elseif a:name =~ '\<zsh\>' + " Some .sh scripts contain #!/bin/zsh. + call polyglot#ft#SetFileTypeShell("zsh") + return + elseif a:name =~ '\<ksh\>' + let 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") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>' + let 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 a:name =~ '\<sh\>' + let 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 + call polyglot#ft#SetFileTypeShell("sh") +endfunc + +" For shell-like file types, check for an "exec" command hidden in a comment, +" as used for Tcl. +" Also called from scripts.vim, thus can't be local to this script. +func polyglot#ft#SetFileTypeShell(name) + if did_filetype() + " Filetype was already detected + return + endif + if expand("<amatch>") =~ g:ft_ignore_pat + return + endif + let l = 2 + while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)' + " Skip empty and comment lines. + let l = l + 1 + endwhile + if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$' + " Found an "exec" line after a comment with continuation + let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '') + if n =~ '\<tclsh\|\<wish' + setf tcl + return + endif + endif + exe "setf " . a:name +endfunc + +func polyglot#ft#CSH() + if did_filetype() + " Filetype was already detected + return + endif + if exists("g:filetype_csh") + call polyglot#ft#SetFileTypeShell(g:filetype_csh) + elseif &shell =~ "tcsh" + call polyglot#ft#SetFileTypeShell("tcsh") + else + call polyglot#ft#SetFileTypeShell("csh") + endif +endfunc + +let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*' +func polyglot#ft#FTRules() + let 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 + try + let config_lines = readfile('/etc/udev/udev.conf') + catch /^Vim\%((\a\+)\)\=:E484/ + setf hog + return + endtry + let dir = expand('<amatch>:p:h') + for line in config_lines + if line =~ s:ft_rules_udev_rules_pattern + let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "") + if dir == udev_rules + setf udevrules + endif + break + endif + endfor + setf hog +endfunc + +func polyglot#ft#SQL() + if exists("g:filetype_sql") + exe "setf " . g:filetype_sql + else + setf sql + endif +endfunc + +" 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. +func polyglot#ft#FTperl() + let 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 + let save_cursor = getpos('.') + call cursor(1,1) + let has_use = search('^use\s\s*\k', 'c', 30) + call setpos('.', save_cursor) + if has_use + setf perl + return 1 + endif + return 0 +endfunc + +" 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. +func polyglot#ft#FTtex() + let firstline = getline(1) + if firstline =~ '^%&\s*\a\+' + let format = tolower(matchstr(firstline, '\a\+')) + let format = substitute(format, 'pdf', '', '') + if format == 'tex' + let format = 'latex' + elseif format == 'plaintex' + let format = 'plain' + endif + elseif expand('%') =~ 'tex/context/.*/.*.tex' + let format = 'context' + else + " Default value, may be changed later: + let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain' + " Save position, go to the top of the file, find first non-comment line. + let save_cursor = getpos('.') + call cursor(1,1) + let firstNC = search('^\s*[^[:space:]%]', 'c', 1000) + if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword. + let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>' + let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>' + let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)', + \ 'cnp', firstNC + 1000) + if kwline == 1 " lpat matched + let format = 'latex' + elseif kwline == 2 " cpat matched + let 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 +endfunc + +func polyglot#ft#FTxml() + let n = 1 + while n < 100 && n <= line("$") + let line = getline(n) + " DocBook 4 or DocBook 5. + let is_docbook4 = line =~ '<!DOCTYPE.*DocBook' + let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"' + if is_docbook4 || is_docbook5 + let b:docbk_type = "xml" + if is_docbook5 + let b:docbk_ver = 5 + else + let b:docbk_ver = 4 + endif + setf docbk + return + endif + if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"' + setf xbl + return + endif + let n += 1 + endwhile + setf xml +endfunc + +func polyglot#ft#FTy() + let n = 1 + while n < 100 && n <= line("$") + let line = getline(n) + if line =~ '^\s*%' + setf yacc + return + endif + if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include' + setf racc + return + endif + let n = n + 1 + endwhile + setf yacc +endfunc + +func polyglot#ft#Redif() + let lnum = 1 + while lnum <= 5 && lnum < line('$') + if getline(lnum) =~ "^\ctemplate-type:" + setf redif + return + endif + let lnum = lnum + 1 + endwhile +endfunc + + +" Restore 'cpoptions' +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/autoload/polyglot/shebang.vim b/autoload/polyglot/shebang.vim index 66ccacd6..62eb11a2 100644 --- a/autoload/polyglot/shebang.vim +++ b/autoload/polyglot/shebang.vim @@ -1,14 +1,20 @@ +" Line continuation is used here, remove 'C' from 'cpoptions' +let s:cpo_save = &cpo +set cpo&vim + func! polyglot#shebang#Detect() let ft = s:Filetype() if ft != "" let &ft = ft + return 1 endif - if &ft == "" - runtime! scripts.vim + let err = polyglot#shebang#VimDetect() + if err == "" + return 1 endif - return &ft != "" + return 0 endfunc let s:r_hashbang = '^#!\s*\(\S\+\)\s*\(.*\)\s*' @@ -58,6 +64,394 @@ func! s:Filetype() endfor endfunc +func! polyglot#shebang#VimDetect() + let line1 = getline(1) + + if line1 =~# "^#!" + " A script that starts with "#!". + + " Check for a line like "#!/usr/bin/env {options} bash". Turn it into + " "#!/usr/bin/bash" to make matching easier. + " Recognize only a few {options} that are commonly used. + if line1 =~# '^#!\s*\S*\<env\s' + let line1 = substitute(line1, '\S\+=\S\+', '', 'g') + let line1 = substitute(line1, '\(-[iS]\|--ignore-environment\|--split-string\)', '', '') + let line1 = substitute(line1, '\<env\s\+', '', '') + endif + + " Get the program name. + " Only accept spaces in PC style path "#!c:/program files/perl [args]". + " If the word env is used, use the first word after the space: + " "#!/usr/bin/env perl [path/args]" + " If there is no path use the first word: "#!perl [path/args]". + " Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]". + if line1 =~# '^#!\s*\a:[/\\]' + let name = substitute(line1, '^#!.*[/\\]\(\i\+\).*', '\1', '') + elseif line1 =~# '^#!.*\<env\>' + let name = substitute(line1, '^#!.*\<env\>\s\+\(\i\+\).*', '\1', '') + elseif line1 =~# '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)' + let name = substitute(line1, '^#!\s*\([^/\\ ]*\>\).*', '\1', '') + else + let name = substitute(line1, '^#!\s*\S*[/\\]\(\i\+\).*', '\1', '') + endif + + " tcl scripts may have #!/bin/sh in the first line and "exec wish" in the + " third line. Suggested by Steven Atkinson. + if getline(3) =~# '^exec wish' + let name = 'wish' + endif + + " Bourne-like shell script bash bash2 ksh ksh93 sh + if name =~# '^\(bash\d*\|\|ksh\d*\|sh\)\>' + call dist#ft#SetFileTypeSH(line1) " defined in filetype.vim + return + + " csh scripts + elseif name =~# '^csh\>' + if exists("g:filetype_csh") + call dist#ft#SetFileTypeShell(g:filetype_csh) + return + else + call dist#ft#SetFileTypeShell("csh") + return + endif + + " tcsh scripts + elseif name =~# '^tcsh\>' + call dist#ft#SetFileTypeShell("tcsh") + return + + " Z shell scripts + elseif name =~# '^zsh\>' + set ft=zsh | return + + " TCL scripts + elseif name =~# '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>' + set ft=tcl | return + + " Expect scripts + elseif name =~# '^expect\>' + set ft=expect | return + + " Gnuplot scripts + elseif name =~# '^gnuplot\>' + set ft=gnuplot | return + + " Makefiles + elseif name =~# 'make\>' + set ft=make | return + + " Pike + elseif name =~# '^pike\%(\>\|[0-9]\)' + set ft=pike | return + + " Lua + elseif name =~# 'lua' + set ft=lua | return + + " Perl 6 + elseif name =~# 'perl6' + set ft=perl6 | return + + " Perl + elseif name =~# 'perl' + set ft=perl | return + + " PHP + elseif name =~# 'php' + set ft=php | return + + " Python + elseif name =~# 'python' + set ft=python | return + + " Groovy + elseif name =~# '^groovy\>' + set ft=groovy | return + + " Ruby + elseif name =~# 'ruby' + set ft=ruby | return + + " JavaScript + elseif name =~# 'node\(js\)\=\>\|js\>' || name =~# 'rhino\>' + set ft=javascript | return + + " BC calculator + elseif name =~# '^bc\>' + set ft=bc | return + + " sed + elseif name =~# 'sed\>' + set ft=sed | return + + " OCaml-scripts + elseif name =~# 'ocaml' + set ft=ocaml | return + + " Awk scripts; also finds "gawk" + elseif name =~# 'awk\>' + set ft=awk | return + + " Website MetaLanguage + elseif name =~# 'wml' + set ft=wml | return + + " Scheme scripts + elseif name =~# 'scheme' + set ft=scheme | return + + " CFEngine scripts + elseif name =~# 'cfengine' + set ft=cfengine | return + + " Erlang scripts + elseif name =~# 'escript' + set ft=erlang | return + + " Haskell + elseif name =~# 'haskell' + set ft=haskell | return + + " Scala + elseif name =~# 'scala\>' + set ft=scala | return + + " Clojure + elseif name =~# 'clojure' + set ft=clojure | return + + endif + unlet name + + else + " File does not start with "#!". + + let line2 = getline(2) + let line3 = getline(3) + let line4 = getline(4) + let line5 = getline(5) + + " Bourne-like shell script sh ksh bash bash2 + if line1 =~# '^:$' + call dist#ft#SetFileTypeSH(line1) " defined in filetype.vim + return + + " Z shell scripts + elseif line1 =~# '^#compdef\>' || line1 =~# '^#autoload\>' || + \ "\n".line1."\n".line2."\n".line3."\n".line4."\n".line5 =~# '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>' + set ft=zsh | return + + " ELM Mail files + elseif line1 =~# '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$' + set ft=mail | return + + " Mason + elseif line1 =~# '^<[%&].*>' + set ft=mason | return + + " Vim scripts (must have '" vim' as the first line to trigger this) + elseif line1 =~# '^" *[vV]im$' + set ft=vim | return + + " libcxx and libstdc++ standard library headers like "iostream" do not have + " an extension, recognize the Emacs file mode. + elseif line1 =~? '-\*-.*C++.*-\*-' + set ft=cpp | return + + " MOO + elseif line1 =~# '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$' + set ft=moo | return + + " Diff file: + " - "diff" in first line (context diff) + " - "Only in " in first line + " - "--- " in first line and "+++ " in second line (unified diff). + " - "*** " in first line and "--- " in second line (context diff). + " - "# It was generated by makepatch " in the second line (makepatch diff). + " - "Index: <filename>" in the first line (CVS file) + " - "=== ", line of "=", "---", "+++ " (SVK diff) + " - "=== ", "--- ", "+++ " (bzr diff, common case) + " - "=== (removed|added|renamed|modified)" (bzr diff, alternative) + " - "# HG changeset patch" in first line (Mercurial export format) + elseif line1 =~# '^\(diff\>\|Only in \|\d\+\(,\d\+\)\=[cda]\d\+\>\|# It was generated by makepatch \|Index:\s\+\f\+\r\=$\|===== \f\+ \d\+\.\d\+ vs edited\|==== //\f\+#\d\+\|# HG changeset patch\)' + \ || (line1 =~# '^--- ' && line2 =~# '^+++ ') + \ || (line1 =~# '^\* looking for ' && line2 =~# '^\* comparing to ') + \ || (line1 =~# '^\*\*\* ' && line2 =~# '^--- ') + \ || (line1 =~# '^=== ' && ((line2 =~# '^=\{66\}' && line3 =~# '^--- ' && line4 =~# '^+++') || (line2 =~# '^--- ' && line3 =~# '^+++ '))) + \ || (line1 =~# '^=== \(removed\|added\|renamed\|modified\)') + set ft=diff | return + + " PostScript Files (must have %!PS as the first line, like a2ps output) + elseif line1 =~# '^%![ \t]*PS' + set ft=postscr | return + + " M4 script Guess there is a line that starts with "dnl". + elseif line1 =~# '^\s*dnl\>' + \ || line2 =~# '^\s*dnl\>' + \ || line3 =~# '^\s*dnl\>' + \ || line4 =~# '^\s*dnl\>' + \ || line5 =~# '^\s*dnl\>' + set ft=m4 | return + + " AmigaDos scripts + elseif $TERM == "amiga" + \ && (line1 =~# "^;" || line1 =~? '^\.bra') + set ft=amiga | return + + " SiCAD scripts (must have procn or procd as the first line to trigger this) + elseif line1 =~? '^ *proc[nd] *$' + set ft=sicad | return + + " Purify log files start with "**** Purify" + elseif line1 =~# '^\*\*\*\* Purify' + set ft=purifylog | return + + " XML + elseif line1 =~# '<?\s*xml.*?>' + set ft=xml | return + + " XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN") + elseif line1 =~# '\<DTD\s\+XHTML\s' + set ft=xhtml | return + + " HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN") + " Avoid "doctype html", used by slim. + elseif line1 =~? '<!DOCTYPE\s\+html\>' + set ft=html | return + + " PDF + elseif line1 =~# '^%PDF-' + set ft=pdf | return + + " XXD output + elseif line1 =~# '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} ' + set ft=xxd | return + + " RCS/CVS log output + elseif line1 =~# '^RCS file:' || line2 =~# '^RCS file:' + set ft=rcslog | return + + " CVS commit + elseif line2 =~# '^CV' || getline("$") =~# '^CV ' + set ft=cvs | return + + " Prescribe + elseif line1 =~# '^!R!' + set ft=prescribe | return + + " Send-pr + elseif line1 =~# '^SEND-PR:' + set ft=sendpr | return + + " SNNS files + elseif line1 =~# '^SNNS network definition file' + set ft=snnsnet | return + elseif line1 =~# '^SNNS pattern definition file' + set ft=snnspat | return + elseif line1 =~# '^SNNS result file' + set ft=snnsres | return + + " Virata + elseif line1 =~# '^%.\{-}[Vv]irata' + \ || line2 =~# '^%.\{-}[Vv]irata' + \ || line3 =~# '^%.\{-}[Vv]irata' + \ || line4 =~# '^%.\{-}[Vv]irata' + \ || line5 =~# '^%.\{-}[Vv]irata' + set ft=virata | return + + " Strace + elseif line1 =~# '[0-9:.]* *execve(' || line1 =~# '^__libc_start_main' + set ft=strace | return + + " VSE JCL + elseif line1 =~# '^\* $$ JOB\>' || line1 =~# '^// *JOB\>' + set ft=vsejcl | return + + " TAK and SINDA + elseif line4 =~# 'K & K Associates' || line2 =~# 'TAK 2000' + set ft=takout | return + elseif line3 =~# 'S Y S T E M S I M P R O V E D ' + set ft=sindaout | return + elseif getline(6) =~# 'Run Date: ' + set ft=takcmp | return + elseif getline(9) =~# 'Node File 1' + set ft=sindacmp | return + + " DNS zone files + elseif line1.line2.line3.line4 =~# '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA' + set ft=bindzone | return + + " BAAN + elseif line1 =~# '|\*\{1,80}' && line2 =~# 'VRC ' + \ || line2 =~# '|\*\{1,80}' && line3 =~# 'VRC ' + set ft=baan | return + + " Valgrind + elseif line1 =~# '^==\d\+== valgrind' || line3 =~# '^==\d\+== Using valgrind' + set ft=valgrind | return + + " Go docs + elseif line1 =~# '^PACKAGE DOCUMENTATION$' + set ft=godoc | return + + " Renderman Interface Bytestream + elseif line1 =~# '^##RenderMan' + set ft=rib | return + + " Scheme scripts + elseif line1 =~# 'exec\s\+\S*scheme' || line2 =~# 'exec\s\+\S*scheme' + set ft=scheme | return + + " Git output + elseif line1 =~# '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$' + set ft=git | return + + " Gprof (gnu profiler) + elseif line1 == 'Flat profile:' + \ && line2 == '' + \ && line3 =~# '^Each sample counts as .* seconds.$' + set ft=gprof | return + + " Erlang terms + " (See also: http://www.gnu.org/software/emacs/manual/html_node/emacs/Choosing-Modes.html#Choosing-Modes) + elseif line1 =~? '-\*-.*erlang.*-\*-' + set ft=erlang | return + + " YAML + elseif line1 =~# '^%YAML' + set ft=yaml | return + + " CVS diff + else + let lnum = 1 + while getline(lnum) =~# "^? " && lnum < line("$") + let lnum += 1 + endwhile + if getline(lnum) =~# '^Index:\s\+\f\+$' + set ft=diff | return + + " locale input file Formal Definitions of Cultural Conventions + " filename must be like en_US, fr_FR@euro or en_US.UTF-8 + elseif expand("%") =~# '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_' + let lnum = 1 + while lnum < 100 && lnum < line("$") + if getline(lnum) =~# '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$' + setf fdcc | return + break + endif + let lnum += 1 + endwhile + endif + unlet lnum + + endif + + endif + + return 1 +endfunc + " DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE let s:interpreters = { @@ -71,7 +465,9 @@ let s:interpreters = { \ 'fish': 'fish', \ 'gnuplot': 'gnuplot', \ 'groovy': 'groovy', + \ 'runghc': 'haskell', \ 'runhaskell': 'haskell', + \ 'runhugs': 'haskell', \ 'chakra': 'javascript', \ 'd8': 'javascript', \ 'gjs': 'javascript', @@ -131,3 +527,7 @@ let s:interpreters = { \ 'deno': 'typescript', \ 'ts-node': 'typescript', \ } +" DO NOT EDIT CODE ABOVE, IT IS GENERATED WITH MAKEFILE + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/autoload/polyglot/sleuth.vim b/autoload/polyglot/sleuth.vim index 0c3c34e8..d74de687 100644 --- a/autoload/polyglot/sleuth.vim +++ b/autoload/polyglot/sleuth.vim @@ -1,5 +1,3 @@ -" DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE - let s:globs = { \ '8th': '*.8th', \ 'Dockerfile': '*.dockerfile,*.dock,*.Dockerfile,Dockerfile,dockerfile,Dockerfile*', diff --git a/ftdetect/polyglot.vim b/ftdetect/polyglot.vim index 498450d8..b3d04eff 100644 --- a/ftdetect/polyglot.vim +++ b/ftdetect/polyglot.vim @@ -1006,6 +1006,7 @@ if !has_key(s:disabled_packages, '8th') au BufNewFile,BufRead *.8th setf 8th endif + " DO NOT EDIT CODE ABOVE, IT IS GENERATED WITH MAKEFILE au! BufNewFile,BufRead,StdinReadPost * if expand("<afile>:e") == "" | @@ -1245,7 +1246,7 @@ endif au BufNewFile,BufRead $VIMRUNTIME/doc/*.txt setf help " Abaqus or Trasys -au BufNewFile,BufRead *.inp call dist#ft#Check_inp() +au BufNewFile,BufRead *.inp call polyglot#ft#Check_inp() " 8th (Firth-derivative) au BufNewFile,BufRead *.8th setf 8th @@ -1351,7 +1352,7 @@ au BufNewFile,BufRead */boot/grub/menu.lst,*/boot/grub/grub.conf,*/etc/grub.conf " Assembly (all kinds) " *.lst is not pure assembly, it has two extra columns (address, byte codes) -au BufNewFile,BufRead *.asm,*.[sS],*.[aA],*.mac,*.lst call dist#ft#FTasm() +au BufNewFile,BufRead *.asm,*.[sS],*.[aA],*.mac,*.lst call polyglot#ft#FTasm() " Macro (VAX) au BufNewFile,BufRead *.mar setf vmasm @@ -1381,7 +1382,7 @@ au BufNewFile,BufRead *.awk,*.gawk setf awk au BufNewFile,BufRead *.mch,*.ref,*.imp setf b " BASIC or Visual Basic -au BufNewFile,BufRead *.bas call dist#ft#FTVB("basic") +au BufNewFile,BufRead *.bas call polyglot#ft#FTVB("basic") " Visual Basic Script (close to Visual Basic) or Visual Basic .NET au BufNewFile,BufRead *.vb,*.vbs,*.dsm,*.ctl setf vb @@ -1399,7 +1400,7 @@ au BufNewFile,BufRead *.cmd \ if getline(1) =~ '^/\*' | setf rexx | else | setf dosbatch | endif " Batch file for 4DOS -au BufNewFile,BufRead *.btm call dist#ft#FTbtm() +au BufNewFile,BufRead *.btm call polyglot#ft#FTbtm() " BC calculator au BufNewFile,BufRead *.bc setf bc @@ -1419,7 +1420,7 @@ au BufNewFile,BufRead named*.conf,rndc*.conf,rndc*.key setf named " BIND zone au BufNewFile,BufRead named.root setf bindzone -au BufNewFile,BufRead *.db call dist#ft#BindzoneCheck('') +au BufNewFile,BufRead *.db call polyglot#ft#BindzoneCheck('') " Blank au BufNewFile,BufRead *.bl setf blank @@ -1438,7 +1439,7 @@ if has("fname_case") endif " C or lpc -au BufNewFile,BufRead *.c call dist#ft#FTlpc() +au BufNewFile,BufRead *.c call polyglot#ft#FTlpc() au BufNewFile,BufRead *.lpc,*.ulpc setf lpc " Calendar @@ -1493,7 +1494,7 @@ endif " .h files can be C, Ch C++, ObjC or ObjC++. " Set c_syntax_for_h if you want C, ch_syntax_for_h if you want Ch. ObjC is " detected automatically. -au BufNewFile,BufRead *.h call dist#ft#FTheader() +au BufNewFile,BufRead *.h call polyglot#ft#FTheader() " Ch (CHscript) au BufNewFile,BufRead *.chf setf ch @@ -1527,7 +1528,7 @@ au BufNewFile,BufRead NEWS au BufNewFile,BufRead *..ch setf chill " Changes for WEB and CWEB or CHILL -au BufNewFile,BufRead *.ch call dist#ft#FTchange() +au BufNewFile,BufRead *.ch call polyglot#ft#FTchange() " ChordPro au BufNewFile,BufRead *.chopro,*.crd,*.cho,*.crdpro,*.chordpro setf chordpro @@ -1539,7 +1540,7 @@ au BufNewFile,BufRead *.dcl,*.icl setf clean au BufNewFile,BufRead *.eni setf cl " Clever or dtd -au BufNewFile,BufRead *.ent call dist#ft#FTent() +au BufNewFile,BufRead *.ent call polyglot#ft#FTent() " Clipper (or FoxPro; could also be eviews) au BufNewFile,BufRead *.prg @@ -1594,9 +1595,9 @@ au BufNewFile,BufRead *enlightenment/*.cfg setf c au BufNewFile,BufRead *Eterm/*.cfg setf eterm " Euphoria 3 or 4 -au BufNewFile,BufRead *.eu,*.ew,*.ex,*.exu,*.exw call dist#ft#EuphoriaCheck() +au BufNewFile,BufRead *.eu,*.ew,*.ex,*.exu,*.exw call polyglot#ft#EuphoriaCheck() if has("fname_case") - au BufNewFile,BufRead *.EU,*.EW,*.EX,*.EXU,*.EXW call dist#ft#EuphoriaCheck() + au BufNewFile,BufRead *.EU,*.EW,*.EX,*.EXU,*.EXW call polyglot#ft#EuphoriaCheck() endif " Lynx config files @@ -1653,7 +1654,7 @@ au BufNewFile,BufRead */etc/dnsmasq.conf setf dnsmasq au BufNewFile,BufRead *.desc setf desc " the D language or dtrace -au BufNewFile,BufRead *.d call dist#ft#DtraceCheck() +au BufNewFile,BufRead *.d call polyglot#ft#DtraceCheck() " Desktop files au BufNewFile,BufRead *.desktop,*.directory setf desktop @@ -1685,7 +1686,7 @@ au BufNewFile,BufRead *.rul \ endif " DCL (Digital Command Language - vms) or DNS zone file -au BufNewFile,BufRead *.com call dist#ft#BindzoneCheck('dcl') +au BufNewFile,BufRead *.com call polyglot#ft#BindzoneCheck('dcl') " DOT au BufNewFile,BufRead *.dot,*.gv setf dot @@ -1733,7 +1734,7 @@ au BufNewFile,BufRead .editorconfig setf dosini au BufNewFile,BufRead *.ecd setf ecd " Eiffel or Specman or Euphoria -au BufNewFile,BufRead *.e,*.E call dist#ft#FTe() +au BufNewFile,BufRead *.e,*.E call polyglot#ft#FTe() " Elinks configuration au BufNewFile,BufRead elinks.conf setf elinks @@ -1911,7 +1912,7 @@ au BufRead,BufNewFile *.hws setf hollywood au BufNewFile,BufRead *.t.html setf tilde " HTML (.shtml and .stm for server side) -au BufNewFile,BufRead *.html,*.htm,*.shtml,*.stm call dist#ft#FThtml() +au BufNewFile,BufRead *.html,*.htm,*.shtml,*.stm call polyglot#ft#FThtml() " HTML with Ruby - eRuby au BufNewFile,BufRead *.erb,*.rhtml setf eruby @@ -1938,7 +1939,7 @@ au BufNewFile,BufRead *.htt,*.htb setf httest au BufNewFile,BufRead *.icn setf icon " IDL (Interface Description Language) -au BufNewFile,BufRead *.idl call dist#ft#FTidl() +au BufNewFile,BufRead *.idl call polyglot#ft#FTidl() " Microsoft IDL (Interface Description Language) Also *.idl " MOF = WMI (Windows Management Instrumentation) Managed Object Format @@ -1949,10 +1950,10 @@ au BufNewFile,BufRead */.icewm/menu setf icemenu " Indent profile (must come before IDL *.pro!) au BufNewFile,BufRead .indent.pro setf indent -au BufNewFile,BufRead indent.pro call dist#ft#ProtoCheck('indent') +au BufNewFile,BufRead indent.pro call polyglot#ft#ProtoCheck('indent') " IDL (Interactive Data Language) -au BufNewFile,BufRead *.pro call dist#ft#ProtoCheck('idlang') +au BufNewFile,BufRead *.pro call polyglot#ft#ProtoCheck('idlang') " Indent RC au BufNewFile,BufRead indentrc setf indent @@ -2172,7 +2173,7 @@ au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown au BufNewFile,BufRead *.mason,*.mhtml,*.comp setf mason " Mathematica, Matlab, Murphi or Objective C -au BufNewFile,BufRead *.m call dist#ft#FTm() +au BufNewFile,BufRead *.m call polyglot#ft#FTm() " Mathematica notebook au BufNewFile,BufRead *.nb setf mma @@ -2205,7 +2206,7 @@ au BufNewFile,BufRead *.mgl setf mgl au BufNewFile,BufRead *.mix,*.mixal setf mix " MMIX or VMS makefile -au BufNewFile,BufRead *.mms call dist#ft#FTmms() +au BufNewFile,BufRead *.mms call polyglot#ft#FTmms() " Symbian meta-makefile definition (MMP) au BufNewFile,BufRead *.mmp setf mmp @@ -2296,10 +2297,10 @@ au BufNewFile,BufRead *.me \ setf nroff | \ endif au BufNewFile,BufRead *.tr,*.nr,*.roff,*.tmac,*.mom setf nroff -au BufNewFile,BufRead *.[1-9] call dist#ft#FTnroff() +au BufNewFile,BufRead *.[1-9] call polyglot#ft#FTnroff() " Nroff or Objective C++ -au BufNewFile,BufRead *.mm call dist#ft#FTmm() +au BufNewFile,BufRead *.mm call polyglot#ft#FTmm() " Not Quite C au BufNewFile,BufRead *.nqc setf nqc @@ -2366,9 +2367,9 @@ au BufNewFile,BufRead *.pcmk setf pcmk " Perl if has("fname_case") - au BufNewFile,BufRead *.pl,*.PL call dist#ft#FTpl() + au BufNewFile,BufRead *.pl,*.PL call polyglot#ft#FTpl() else - au BufNewFile,BufRead *.pl call dist#ft#FTpl() + au BufNewFile,BufRead *.pl call polyglot#ft#FTpl() endif au BufNewFile,BufRead *.plx,*.al,*.psgi setf perl au BufNewFile,BufRead *.p6,*.pm6,*.pl6 setf perl6 @@ -2444,7 +2445,7 @@ au BufNewFile,BufRead *.pov setf pov au BufNewFile,BufRead .povrayrc setf povini " Povray, PHP or assembly -au BufNewFile,BufRead *.inc call dist#ft#FTinc() +au BufNewFile,BufRead *.inc call polyglot#ft#FTinc() " Printcap and Termcap au BufNewFile,BufRead *printcap @@ -2473,13 +2474,13 @@ au BufNewFile,BufRead *.action setf privoxy au BufNewFile,BufRead .procmail,.procmailrc setf procmail " Progress or CWEB -au BufNewFile,BufRead *.w call dist#ft#FTprogress_cweb() +au BufNewFile,BufRead *.w call polyglot#ft#FTprogress_cweb() " Progress or assembly -au BufNewFile,BufRead *.i call dist#ft#FTprogress_asm() +au BufNewFile,BufRead *.i call polyglot#ft#FTprogress_asm() " Progress or Pascal -au BufNewFile,BufRead *.p call dist#ft#FTprogress_pascal() +au BufNewFile,BufRead *.p call polyglot#ft#FTprogress_pascal() " Software Distributor Product Specification File (POSIX 1387.2-1995) au BufNewFile,BufRead *.psf setf psf @@ -2569,7 +2570,7 @@ else endif " Rexx, Rebol or R -au BufNewFile,BufRead *.r,*.R call dist#ft#FTr() +au BufNewFile,BufRead *.r,*.R call polyglot#ft#FTr() " Remind au BufNewFile,BufRead .reminders,*.remind,*.rem setf remind @@ -2665,7 +2666,7 @@ au BufNewFile,BufRead *.siv,*.sieve setf sieve au BufNewFile,BufRead sendmail.cf setf sm " Sendmail .mc files are actually m4. Could also be MS Message text file. -au BufNewFile,BufRead *.mc call dist#ft#McSetf() +au BufNewFile,BufRead *.mc call polyglot#ft#McSetf() " Services au BufNewFile,BufRead */etc/services setf services @@ -2706,9 +2707,9 @@ au BufNewFile,BufRead catalog setf catalog " Shell scripts (sh, ksh, bash, bash2, csh); Allow .profile_foo etc. " Gentoo ebuilds and Arch Linux PKGBUILDs are actually bash scripts " NOTE: Patterns ending in a star are further down, these have lower priority. -au BufNewFile,BufRead .bashrc,bashrc,bash.bashrc,.bash[_-]profile,.bash[_-]logout,.bash[_-]aliases,bash-fc[-.],*.bash,*/{,.}bash[_-]completion{,.d,.sh}{,/*},*.ebuild,*.eclass,PKGBUILD call dist#ft#SetFileTypeSH("bash") -au BufNewFile,BufRead .kshrc,*.ksh call dist#ft#SetFileTypeSH("ksh") -au BufNewFile,BufRead */etc/profile,.profile,*.sh,*.env call dist#ft#SetFileTypeSH(getline(1)) +au BufNewFile,BufRead .bashrc,bashrc,bash.bashrc,.bash[_-]profile,.bash[_-]logout,.bash[_-]aliases,bash-fc[-.],*.bash,*/{,.}bash[_-]completion{,.d,.sh}{,/*},*.ebuild,*.eclass,PKGBUILD call polyglot#ft#SetFileTypeSH("bash") +au BufNewFile,BufRead .kshrc,*.ksh call polyglot#ft#SetFileTypeSH("ksh") +au BufNewFile,BufRead */etc/profile,.profile,*.sh,*.env call polyglot#ft#SetFileTypeSH(getline(1)) " Shell script (Arch Linux) or PHP file (Drupal) @@ -2716,15 +2717,15 @@ au BufNewFile,BufRead *.install \ if getline(1) =~ '<?php' | \ setf php | \ else | - \ call dist#ft#SetFileTypeSH("bash") | + \ call polyglot#ft#SetFileTypeSH("bash") | \ endif " tcsh scripts (patterns ending in a star further below) -au BufNewFile,BufRead .tcshrc,*.tcsh,tcsh.tcshrc,tcsh.login call dist#ft#SetFileTypeShell("tcsh") +au BufNewFile,BufRead .tcshrc,*.tcsh,tcsh.tcshrc,tcsh.login call polyglot#ft#SetFileTypeShell("tcsh") " csh scripts, but might also be tcsh scripts (on some systems csh is tcsh) " (patterns ending in a start further below) -au BufNewFile,BufRead .login,.cshrc,csh.cshrc,csh.login,csh.logout,*.csh,.alias call dist#ft#CSH() +au BufNewFile,BufRead .login,.cshrc,csh.cshrc,csh.login,csh.logout,*.csh,.alias call polyglot#ft#CSH() " Z-Shell script (patterns ending in a star further below) au BufNewFile,BufRead .zprofile,*/etc/zprofile,.zfbfmarks setf zsh @@ -2795,7 +2796,7 @@ au BufNewFile,BufRead *.mib,*.my setf mib " Snort Configuration au BufNewFile,BufRead *.hog,snort.conf,vision.conf setf hog -au BufNewFile,BufRead *.rules call dist#ft#FTRules() +au BufNewFile,BufRead *.rules call polyglot#ft#FTRules() " Spec (Linux RPM) au BufNewFile,BufRead *.spec setf spec @@ -2819,7 +2820,7 @@ au BufNewFile,BufRead squid.conf setf squid au BufNewFile,BufRead *.tyb,*.typ,*.tyc,*.pkb,*.pks setf sql " SQL -au BufNewFile,BufRead *.sql call dist#ft#SQL() +au BufNewFile,BufRead *.sql call polyglot#ft#SQL() " SQLJ au BufNewFile,BufRead *.sqlj setf sqlj @@ -2885,8 +2886,8 @@ au BufNewFile,BufRead */etc/sudoers,sudoers.tmp setf sudoers au BufNewFile,BufRead *.svg setf svg " Tads (or Nroff or Perl test file) -au BufNewFile,BufRead *.t - \ if !dist#ft#FTnroff() && !dist#ft#FTperl() | setf tads | endif +"au BufNewFile,BufRead *.t +" \ if !polyglot#ft#FTnroff() && !polyglot#ft#FTperl() | setf tads | endif " Tags au BufNewFile,BufRead tags setf tags @@ -2915,7 +2916,7 @@ au BufNewFile,BufRead *.ti setf terminfo " TeX au BufNewFile,BufRead *.latex,*.sty,*.dtx,*.ltx,*.bbl setf tex -au BufNewFile,BufRead *.tex call dist#ft#FTtex() +au BufNewFile,BufRead *.tex call polyglot#ft#FTtex() " ConTeXt au BufNewFile,BufRead *.mkii,*.mkiv,*.mkvi setf context @@ -3018,7 +3019,7 @@ au BufRead,BufNewFile *.hw,*.module,*.pkg \ endif " Visual Basic (also uses *.bas) or FORM -au BufNewFile,BufRead *.frm call dist#ft#FTVB("form") +au BufNewFile,BufRead *.frm call polyglot#ft#FTVB("form") " SaxBasic is close to Visual Basic au BufNewFile,BufRead *.sba setf vb @@ -3114,10 +3115,10 @@ au BufNewFile,BufRead .Xdefaults,.Xpdefaults,.Xresources,xdm-config,*.ad setf xd " Xmath au BufNewFile,BufRead *.msc,*.msf setf xmath au BufNewFile,BufRead *.ms - \ if !dist#ft#FTnroff() | setf xmath | endif + \ if !polyglot#ft#FTnroff() | setf xmath | endif " XML specific variants: docbk and xbl -au BufNewFile,BufRead *.xml call dist#ft#FTxml() +au BufNewFile,BufRead *.xml call polyglot#ft#FTxml() " XMI (holding UML models) is also XML au BufNewFile,BufRead *.xmi setf xml @@ -3164,7 +3165,7 @@ au BufNewFile,BufRead *.xsl,*.xslt setf xslt au BufNewFile,BufRead *.yy,*.yxx,*.y++ setf yacc " Yacc or racc -au BufNewFile,BufRead *.y call dist#ft#FTy() +au BufNewFile,BufRead *.y call polyglot#ft#FTy() " Yaml au BufNewFile,BufRead *.yaml,*.yml setf yaml @@ -3183,9 +3184,9 @@ au BufNewFile,BufRead *.zut setf zimbutempl " Zope " dtml (zope dynamic template markup language), pt (zope page template), " cpt (zope form controller page template) -au BufNewFile,BufRead *.dtml,*.pt,*.cpt call dist#ft#FThtml() +au BufNewFile,BufRead *.dtml,*.pt,*.cpt call polyglot#ft#FThtml() " zsql (zope sql method) -au BufNewFile,BufRead *.zsql call dist#ft#SQL() +au BufNewFile,BufRead *.zsql call polyglot#ft#SQL() " Z80 assembler asz80 au BufNewFile,BufRead *.z8a setf z8a @@ -3352,7 +3353,7 @@ au BufNewFile,BufRead *termcap* " ReDIF " Only used when the .rdf file was not detected to be XML. -au BufRead,BufNewFile *.rdf call dist#ft#Redif() +au BufRead,BufNewFile *.rdf call polyglot#ft#Redif() " Remind au BufNewFile,BufRead .reminders* call s:StarSetf('remind') @@ -3361,15 +3362,15 @@ au BufNewFile,BufRead .reminders* call s:StarSetf('remind') au BufNewFile,BufRead sgml.catalog* call s:StarSetf('catalog') " Shell scripts ending in a star -au BufNewFile,BufRead .bashrc*,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,bash-fc[-.]*,,PKGBUILD* call dist#ft#SetFileTypeSH("bash") -au BufNewFile,BufRead .kshrc* call dist#ft#SetFileTypeSH("ksh") -au BufNewFile,BufRead .profile* call dist#ft#SetFileTypeSH(getline(1)) +au BufNewFile,BufRead .bashrc*,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,bash-fc[-.]*,,PKGBUILD* call polyglot#ft#SetFileTypeSH("bash") +au BufNewFile,BufRead .kshrc* call polyglot#ft#SetFileTypeSH("ksh") +au BufNewFile,BufRead .profile* call polyglot#ft#SetFileTypeSH(getline(1)) " tcsh scripts ending in a star -au BufNewFile,BufRead .tcshrc* call dist#ft#SetFileTypeShell("tcsh") +au BufNewFile,BufRead .tcshrc* call polyglot#ft#SetFileTypeShell("tcsh") " csh scripts ending in a star -au BufNewFile,BufRead .login*,.cshrc* call dist#ft#CSH() +au BufNewFile,BufRead .login*,.cshrc* call polyglot#ft#CSH() " VHDL au BufNewFile,BufRead *.vhdl_[0-9]* call s:StarSetf('vhdl') diff --git a/scripts/build b/scripts/build index 8b40e571..48ed10a1 100755 --- a/scripts/build +++ b/scripts/build @@ -392,7 +392,8 @@ def rule_to_code(rule) if rule.has_key?("filetype") if rule.has_key?("fallback") return <<~EOS - set ft=#{rule["filetype"]} | au BufWritePost <buffer> ++once call polyglot#detect##{camelize(rule["extensions"].first)}() + setf #{rule["filetype"]} + call s:WritePostOnce('call polyglot#detect##{camelize(rule["extensions"].first)}()') return EOS end @@ -496,7 +497,7 @@ end def generate_ftdetect(packages, heuristics) FileUtils.mkdir_p('autoload/polyglot') - output = "\n" + output = "" all_filetypes = packages.flat_map { |f| f["filetypes"] || [] } filetype_names = Set.new(all_filetypes.map { |f| f["name"] }) @@ -581,17 +582,9 @@ def generate_ftdetect(packages, heuristics) show_warnings(all_filetypes, expected_filetypes) - ftdetect = File.read('ftdetect/polyglot.vim') - - starting = '" DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE' - ending = '" DO NOT EDIT CODE ABOVE, IT IS GENERATED WITH MAKEFILE' - - File.write( - 'ftdetect/polyglot.vim', - ftdetect.gsub(/(?<=#{starting}\n)(.*)(?=#{ending})/m) { output } - ) + inject_code('ftdetect/polyglot.vim', output) - output = ["\" DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE\n"] + output = [] for heuristic in heuristics output << <<~EOS @@ -601,7 +594,7 @@ def generate_ftdetect(packages, heuristics) EOS end - File.write('autoload/polyglot/detect.vim', output.join("\n")) + inject_code('autoload/polyglot/detect.vim', output.join("\n")) output = <<~EOS let s:interpreters = { @@ -619,9 +612,15 @@ def generate_ftdetect(packages, heuristics) end def inject_code(path, code) - header = "\" DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE\n" - normal, generated = File.read(path).split(header) - File.write(path, [normal, generated].join(header)) + source = File.read(path) + + starting = '" DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE' + ending = '" DO NOT EDIT CODE ABOVE, IT IS GENERATED WITH MAKEFILE' + + File.write( + path, + source.gsub(/(?<=#{starting}\n)(.*)(?=#{ending})/m) { "\n" + code + "\n" } + ) end def generate_tests(packages) @@ -739,8 +738,6 @@ end def generate_plugins(packages) output = <<~EOS - " DO NOT EDIT CODE BELOW, IT IS GENERATED WITH MAKEFILE - let s:globs = { EOS |