To: vim_dev@googlegroups.com Subject: Patch 8.2.4305 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4305 Problem: Tex filetype detection fails. Solution: Check value to be positive. (closes #9704) Files: runtime/autoload/dist/ft.vim, src/testdir/test_filetype.vim *** ../vim-8.2.4304/runtime/autoload/dist/ft.vim 2022-01-31 17:08:05.653352132 +0000 --- runtime/autoload/dist/ft.vim 2022-02-05 19:41:36.660295409 +0000 *************** *** 1,89 **** ! " Vim functions for file type detection ! " ! " Maintainer: Bram Moolenaar ! " Last Change: 2019 Mar 08 ! ! " 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 dist#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 dist#ft#FTasm() ! " make sure b:asmsyntax exists if !exists("b:asmsyntax") ! let b:asmsyntax = "" endif if b:asmsyntax == "" ! call dist#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 dist#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 ! let s:ft_visual_basic_content = '\cVB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)' ! " See FTfrm() for Visual Basic form file detection ! func dist#ft#FTbas() if exists("g:filetype_bas") ! exe "setf " . g:filetype_bas return endif ! " most frequent FreeBASIC-specific keywords in distro files ! let fb_keywords = '\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!' ! let fb_preproc = '\c^\s*\%(#\a\+\|option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\)' ! let fb_comment = "^\\s*/'" ! " OPTION EXPLICIT, without the leading underscore, is common to many dialects ! let qb64_preproc = '\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)' ! let lines = getline(1, min([line("$"), 100])) if match(lines, fb_preproc) > -1 || match(lines, fb_comment) > -1 || match(lines, fb_keywords) > -1 setf freebasic --- 1,83 ---- ! vim9script ! # Vim functions for file type detection ! # ! # Maintainer: Bram Moolenaar ! # Last Change: 2022 Feb 05 ! ! # These functions are moved here from runtime/filetype.vim to make startup ! # faster. ! ! export def Check_inp() if 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() ! # 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 = '\cVB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)' ! # 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*\%(#\a\+\|option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\)' ! 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\)\>\)' ! var lines = getline(1, min([line("$"), 100])) if match(lines, fb_preproc) > -1 || match(lines, fb_comment) > -1 || match(lines, fb_keywords) > -1 setf freebasic *************** *** 94,132 **** else setf basic endif ! endfunc ! func dist#ft#FTbtm() if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm setf dosbatch else setf btm endif ! endfunc ! func dist#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 dist#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 dist#ft#FTheader() if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1 if exists("g:c_syntax_for_h") setf objc --- 88,127 ---- else setf basic endif ! 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 ! 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 ! export def FTheader() if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1 if exists("g:c_syntax_for_h") setf objc *************** *** 140,154 **** 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 dist#ft#FTchange() ! let lnum = 1 while lnum <= 10 if getline(lnum)[0] == '@' setf change --- 135,149 ---- else setf cpp 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 *************** *** 166,266 **** setf ch return endif ! let lnum = lnum + 1 endwhile setf chill ! endfunc ! func dist#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 dist#ft#ExCheck() ! let 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 ! endfunc ! func dist#ft#EuphoriaCheck() if exists('g:filetype_euphoria') ! exe 'setf ' . g:filetype_euphoria else setf euphoria3 endif ! endfunc ! func dist#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 dist#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 ! func dist#ft#FTfrm() if exists("g:filetype_frm") ! exe "setf " . g:filetype_frm return endif ! let lines = getline(1, min([line("$"), 5])) if match(lines, s:ft_visual_basic_content) > -1 setf vb else setf form endif ! endfunc ! " Distinguish between Forth and F#. ! " Provided by Doug Kearns. ! func dist#ft#FTfs() if exists("g:filetype_fs") ! exe "setf " . g:filetype_fs else ! let line = getline(nextnonblank(1)) ! " comments and colon definitions if line =~ '^\s*\.\=( ' || line =~ '^\s*\\G\= ' || line =~ '^\\$' \ || line =~ '^\s*: \S' setf forth --- 161,261 ---- 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 endw 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() ! 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 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 ! export def FTfrm() if exists("g:filetype_frm") ! exe "setf " .. g:filetype_frm return endif ! var lines = getline(1, min([line("$"), 5])) if match(lines, s:ft_visual_basic_content) > -1 setf vb else setf form endif ! enddef ! # Distinguish between Forth and F#. ! # Provided by Doug Kearns. ! export def FTfs() if exists("g:filetype_fs") ! exe "setf " .. g:filetype_fs else ! var line = getline(nextnonblank(1)) ! # comments and colon definitions if line =~ '^\s*\.\=( ' || line =~ '^\s*\\G\= ' || line =~ '^\\$' \ || line =~ '^\s*: \S' setf forth *************** *** 268,278 **** setf fsharp endif endif ! endfunc ! " Distinguish between HTML, XHTML and Django ! func dist#ft#FThtml() ! let n = 1 while n < 10 && n <= line("$") if getline(n) =~ '\' || line =~ objc_preprocessor setf objc --- 277,334 ---- setf htmldjango 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" and Cproto prototype file. */ ! export def ProtoCheck(default: string) ! # 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 ' .. default 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 = '\' ! 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 *************** *** 344,350 **** setf octave return endif ! " TODO: could be Matlab or Octave if line =~ '^\s*%' setf matlab return --- 339,345 ---- setf octave return endif ! # TODO: could be Matlab or Octave if line =~ '^\s*%' setf matlab return *************** *** 357,380 **** 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 else ! " Default is Matlab setf matlab endif ! endfunc ! func dist#ft#FTmms() ! let n = 1 while n < 20 ! let line = getline(n) if line =~ '^\s*\(%\|//\)' || line =~ '^\*' setf mmix return --- 352,375 ---- 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 FTmms() ! var n = 1 while n < 20 ! var line = getline(n) if line =~ '^\s*\(%\|//\)' || line =~ '^\*' setf mmix return *************** *** 383,460 **** 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 dist#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 dist#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 dist#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 =~ '\' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-' setf prolog else setf perl endif endif ! endfunc ! func dist#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 =~ "\|@import\>\|/\*\)' setf objcpp return endif ! n += 1 endwhile setf nroff ! 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 l = getline(nextnonblank(1)) if l =~ '\' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-' 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 =~ "' ! func dist#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:ft_pascal_comments || line =~? s: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 ! let lnum = lnum + 1 endw setf progress ! endfunc ! func dist#ft#FTpp() if exists("g:filetype_pp") ! exe "setf " . g:filetype_pp else ! let line = getline(nextnonblank(1)) if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords setf pascal else setf puppet endif endif ! endfunc ! func dist#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) =~? '\' setf rebol return --- 457,532 ---- else setf cweb endif ! enddef ! export def 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. ! var lnum = 1 while lnum <= 10 && lnum < line('$') ! var line = getline(lnum) if line =~ '^\s*;' || line =~ '^\*' ! 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 ! lnum += 1 endw 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 =~ s:ft_pascal_comments || line =~? s: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 endw setf progress ! enddef ! export def FTpp() if exists("g:filetype_pp") ! exe "setf " .. g:filetype_pp else ! var line = getline(nextnonblank(1)) if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords setf pascal else setf puppet endif 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) =~? '\' setf rebol return *************** *** 539,620 **** 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 dist#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 dist#ft#SetFileTypeSH(name) if did_filetype() ! " Filetype was already detected return endif if expand("") =~ g:ft_ignore_pat return endif ! if a:name =~ '\' ! " Some .sh scripts contain #!/bin/csh. ! call dist#ft#SetFileTypeShell("csh") ! return ! elseif a:name =~ '\' ! " Some .sh scripts contain #!/bin/tcsh. ! call dist#ft#SetFileTypeShell("tcsh") ! return ! elseif a:name =~ '\' ! " Some .sh scripts contain #!/bin/zsh. ! call dist#ft#SetFileTypeShell("zsh") return ! elseif a:name =~ '\' ! 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 =~ '\' || a:name =~ '\' ! 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 =~ '\' ! let b:is_sh = 1 if exists("b:is_kornshell") unlet b:is_kornshell endif --- 534,615 ---- 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. ! export def SetFileTypeSH(name: string) if did_filetype() ! # Filetype was already detected return endif if expand("") =~ g:ft_ignore_pat return endif ! if name =~ '\' ! # Some .sh scripts contain #!/bin/csh. ! SetFileTypeShell("csh") ! return ! elseif name =~ '\' ! # Some .sh scripts contain #!/bin/tcsh. ! SetFileTypeShell("tcsh") ! return ! elseif name =~ '\' ! # Some .sh scripts contain #!/bin/zsh. ! SetFileTypeShell("zsh") return ! elseif name =~ '\' ! 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 =~ '\' || name =~ '\' ! 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 =~ '\' ! b:is_sh = 1 if exists("b:is_kornshell") unlet b:is_kornshell endif *************** *** 622,696 **** unlet b:is_bash endif endif ! call dist#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 dist#ft#SetFileTypeShell(name) if did_filetype() ! " Filetype was already detected return endif if expand("") =~ 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 =~ '\: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(':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 --- 617,692 ---- unlet b:is_bash endif endif ! SetFileTypeShell("sh") ! enddef ! # 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. ! export def SetFileTypeShell(name: string) if did_filetype() ! # Filetype was already detected return endif if expand("") =~ g:ft_ignore_pat return endif ! var l = 2 while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)' ! # Skip empty and comment lines. ! l += 1 endwhile if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$' ! # Found an "exec" line after a comment with continuation ! var n = substitute(getline(l), '\s*exec\s\+\([^ ]*/\)\=', '', '') if n =~ '\: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 try ! config_lines = readfile('/etc/udev/udev.conf') catch /^Vim\%((\a\+)\)\=:E484/ setf hog return endtry ! var dir = expand(':p:h') for line in config_lines if line =~ s:ft_rules_udev_rules_pattern ! var udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "") if dir == udev_rules setf udevrules endif *************** *** 698,721 **** endif endfor setf hog ! endfunc ! func dist#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 dist#ft#FTperl() ! let dirname = expand("%:p:h:t") if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt') setf perl return 1 --- 694,717 ---- endif endfor setf hog ! enddef ! export def SQL() if exists("g:filetype_sql") ! exe "setf " .. g:filetype_sql else setf sql 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 *************** *** 724,809 **** 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 "%&". ! " 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 dist#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 dist#ft#FTxml() ! let n = 1 while n < 100 && n <= line("$") ! let line = getline(n) ! " DocBook 4 or DocBook 5. ! let is_docbook4 = line =~ ' 0 call setpos('.', save_cursor) if has_use setf perl return 1 endif return 0 ! enddef ! # Choose context, plaintex, or tex (LaTeX) based on these rules: ! # 1. Check the first line of the file for "%&". ! # 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 =~ '