|
| 1 | +-- Ported from scripts.vim |
| 2 | + |
| 3 | +localgetlines=vim.filetype.getlines |
| 4 | +localfindany=vim.filetype.findany |
| 5 | +localmatchregex=vim.filetype.matchregex |
| 6 | +localdid_filetype=vim.filetype.did_filetype |
| 7 | + |
| 8 | +localM= {} |
| 9 | + |
| 10 | +---@private |
| 11 | +-- TODO: name |
| 12 | +localfunctionscripts_shebang(path,bufnr) |
| 13 | +localfirst_line=getlines(bufnr,1) |
| 14 | +-- Check for a line like "#!/usr/bin/env {options} bash". Turn it into |
| 15 | +-- "#!/usr/bin/bash" to make matching easier. |
| 16 | +-- Recognize only a few {options} that are commonly used. |
| 17 | +ifmatchregex(first_line,[[^#!\s*\S*\<env\s]])then |
| 18 | +first_line=first_line:gsub('%S+=%S+','') |
| 19 | +first_line=first_line |
| 20 | + :gsub('%-[iS]','',1) |
| 21 | + :gsub('%-%-ignore%-environment','',1) |
| 22 | + :gsub('%-%-split%-string','',1) |
| 23 | +first_line=vim.fn.substitute(first_line,[[\<env\s\+]],'','') |
| 24 | +end |
| 25 | + |
| 26 | +-- Get the program name. |
| 27 | +-- Only accept spaces in PC style paths: "#!c:/program files/perl [args]". |
| 28 | +-- If the word env is used, use the first word after the space: |
| 29 | +-- "#!/usr/bin/env perl [path/args]" |
| 30 | +-- If there is no path use the first word: "#!perl [path/args]". |
| 31 | +-- Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]". |
| 32 | +localname |
| 33 | +iffirst_line:find('^#!%s*%a:[/\\]')then |
| 34 | +name=vim.fn.substitute(first_line,[[^#!.*[/\\]\(\i\+\).*]],'\\1','') |
| 35 | +elseifmatchregex(first_line,[[^#!.*\<env\>]])then |
| 36 | +name=vim.fn.substitute(first_line,[[^#!.*\<env\>\s\+\(\i\+\).*]],'\\1','') |
| 37 | +elseifmatchregex(first_line,[[^#!\s*[^/\\ ]*\>\([^/\\]\|$\)]])then |
| 38 | +name=vim.fn.substitute(first_line,[[^#!\s*\([^/\\ ]*\>\).*]],'\\1','') |
| 39 | +else |
| 40 | +name=vim.fn.substitute(first_line,[[^#!\s*\S*[/\\]\(\i\+\).*]],'\\1','') |
| 41 | +end |
| 42 | + |
| 43 | +-- tcl scripts may have #!/bin/sh in the first line and "exec wish" in the |
| 44 | +-- third line. Suggested by Steven Atkinson. |
| 45 | +ifgetlines(bufnr,3):find('^exec wish')then |
| 46 | +name='wish' |
| 47 | +end |
| 48 | + |
| 49 | +ifmatchregex(name,[[^\(bash\d*\|\|ksh\d*\|sh\)\>]])then |
| 50 | +-- Bourne-like shell scripts: bash bash2 ksh ksh93 sh |
| 51 | +returnM.sh(path,bufnr,first_line) |
| 52 | +elseifmatchregex(name,[[^csh\>]])then |
| 53 | +returnM.shell(path,bufnr,vim.g.filetype_cshor'csh') |
| 54 | +elseifmatchregex(name,[[^tcsh\>]])then |
| 55 | +returnM.shell(path,bufnr,'tcsh') |
| 56 | +end |
| 57 | + |
| 58 | +localpatterns= { |
| 59 | + ['^zsh\\>']= {'zsh', {vim_regex=true } }, |
| 60 | + ['^\\(tclsh\\|wish\\|expectk\\|itclsh\\|itkwish\\)\\>']= {'tcl', {vim_regex=true } }, |
| 61 | + ['^expect\\>']= {'expect', {vim_regex=true } }, |
| 62 | + ['^gnuplot\\>']= {'gnuplot', {vim_regex=true } }, |
| 63 | + ['make\\>']= {'make', {vim_regex=true } }, |
| 64 | + ['^pike\\%(\\>\\|[0-9]\\)']= {'pike', {vim_regex=true } }, |
| 65 | +lua='lua', |
| 66 | +perl='lua', |
| 67 | +php='php', |
| 68 | +python='python', |
| 69 | + ['^groovy\\>']= {'groovy', {vim_regex=true } }, |
| 70 | +raku='raku', |
| 71 | +ruby='ruby', |
| 72 | + ['node\\(js\\)\\=\\>\\|js\\>']= {'javascript', {vim_regex=true } }, |
| 73 | + ['rhino\\>']= {'javascript', {vim_regex=true } }, |
| 74 | +-- BC calculator |
| 75 | + ['^bc\\>']= {'bc', {vim_regex=true } }, |
| 76 | + ['sed\\>']= {'sed', {vim_regex=true } }, |
| 77 | +ocaml='ocaml', |
| 78 | +-- Awk scripts; also finds "gawk" |
| 79 | + ['awk\\>']= {'awk', {vim_regex=true } }, |
| 80 | +wml='wml', |
| 81 | +scheme='scheme', |
| 82 | +cfengine='cfengine', |
| 83 | +escript='erlang', |
| 84 | +haskell='haskell', |
| 85 | +clojure='clojure', |
| 86 | + ['scala\\>']= {'scala', {vim_regex=true } }, |
| 87 | +-- Free Pascal |
| 88 | + ['instantfpc\\>']= {'pascal', {vim_regex=true } }, |
| 89 | + ['fennel\\>']= {'fennel', {vim_regex=true } }, |
| 90 | +-- MikroTik RouterOS script |
| 91 | + ['rsc\\>']= {'routeros', {vim_regex=true } }, |
| 92 | +-- Fish shell |
| 93 | + ['fish\\>']= {'fish', {vim_regex=true } }, |
| 94 | + ['gforth\\>']= {'forth', {vim_regex=true } }, |
| 95 | + } |
| 96 | + |
| 97 | +fork,vinpairs(patterns)do |
| 98 | +localft=type(v)=='table'andv[1]orv |
| 99 | +localopts=type(v)=='table'andv[2]or {} |
| 100 | +ifopts.vim_regexandmatchregex(name,k)orname:find(k)then |
| 101 | +returnft |
| 102 | +end |
| 103 | +end |
| 104 | +end |
| 105 | + |
| 106 | +localfunctionscripts_no_shebang(path,bufnr) |
| 107 | +locallines=getlines(bufnr,1,5) |
| 108 | + |
| 109 | +iflines[1]:find('^:$')then |
| 110 | +-- Bourne-like shell scripts: sh ksh bash bash2 |
| 111 | +returnM.sh(path,bufnr,lines[1]) |
| 112 | +elseifmatchregex('\n'..table.concat(lines,'\n'),[[\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>]])then |
| 113 | +-- Z shell scripts |
| 114 | +return'zsh' |
| 115 | +end |
| 116 | + |
| 117 | +localpatterns= { |
| 118 | + ['^#compdef\\>']= {'zsh', {vim_regex=true } }, |
| 119 | + ['^#autoload\\>']= {'zsh', {vim_regex=true } }, |
| 120 | +-- ELM Mail files |
| 121 | + ['^From [a-zA-Z][a-zA-Z_0-9%.=%-]*(@[^ ]*)? .* 19%d%d$']='mail', |
| 122 | + ['^From [a-zA-Z][a-zA-Z_0-9%.=%-]*(@[^ ]*)? .* 20%d%d$']='mail', |
| 123 | + ['^From %- .* 19%d%d$']='mail', |
| 124 | + ['^From %- .* 20%d%d$']='mail', |
| 125 | +-- Mason |
| 126 | + ['^<[%%&].*>']='mason', |
| 127 | +-- Vim scripts (must have '" vim' as the first line to trigger this) |
| 128 | + ['^" *[vV]im$[']='vim', |
| 129 | +-- libcxx and libstdc++ standard library headers like ["iostream["] do not have |
| 130 | +-- an extension, recognize the Emacs file mode. |
| 131 | + ['%-%*%-.*[cC]%+%+.*%-%*%-']='cpp', |
| 132 | + ['^\\*\\* LambdaMOO Database, Format Version\\%([1-3]\\>\\)\\@!\\d\\+\\*\\*$']= { |
| 133 | +'moo', |
| 134 | + {vim_regex=true }, |
| 135 | + }, |
| 136 | +-- Diff file: |
| 137 | +-- - "diff" in first line (context diff) |
| 138 | +-- - "Only in " in first line |
| 139 | +-- - "--- " in first line and "+++ " in second line (unified diff). |
| 140 | +-- - "*** " in first line and "--- " in second line (context diff). |
| 141 | +-- - "# It was generated by makepatch " in the second line (makepatch diff). |
| 142 | +-- - "Index: <filename>" in the first line (CVS file) |
| 143 | +-- - "=== ", line of "=", "---", "+++ " (SVK diff) |
| 144 | +-- - "=== ", "--- ", "+++ " (bzr diff, common case) |
| 145 | +-- - "=== (removed|added|renamed|modified)" (bzr diff, alternative) |
| 146 | +-- - "# HG changeset patch" in first line (Mercurial export format) |
| 147 | + ['^\\(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\\)']= { |
| 148 | +'diff', |
| 149 | + {vim_regex=true }, |
| 150 | + }, |
| 151 | +function() |
| 152 | +if |
| 153 | +lines[1]:find('^%-%-%-')andlines[2]:find('^%+%+%+') |
| 154 | +orlines[1]:find('^%* looking for')andlines[2]:find('^%* comparing to') |
| 155 | +orlines[1]:find('^%*%*%*')andlines[2]:find('^%-%-%-') |
| 156 | +orlines[1]:find('^===')and ((lines[2]:find('^'..string.rep('=',66))andlines[3]:find('^%-%-%')andlines[4]:find( |
| 157 | +'^%+%+%+' |
| 158 | + ))or (lines[2]:find('^%-%-%-')andlines[3]:find('^%+%+%+'))) |
| 159 | +orfindany(lines[1], {'^=== removed','^=== added','^=== renamed','^=== modified'}) |
| 160 | +then |
| 161 | +return'diff' |
| 162 | +end |
| 163 | +end, |
| 164 | +-- PostScript Files (must have %!PS as the first line, like a2ps output) |
| 165 | + ['^%%![\t]*PS']='postscr', |
| 166 | +function() |
| 167 | +-- M4 scripts: Guess there is a line that starts with "dnl". |
| 168 | +for_,lineinipairs(lines)do |
| 169 | +ifmatchregex(line,'^\\%sdnl\\>')then |
| 170 | +return'm4' |
| 171 | +end |
| 172 | +end |
| 173 | +ifvim.env.TERM=='amiga'andfindany(lines[1]:lower(), {'^;','^%.bra'})then |
| 174 | +-- AmigaDos scripts |
| 175 | +return'amiga' |
| 176 | +end |
| 177 | +end, |
| 178 | +-- SiCAD scripts (must have procn or procd as the first line to trigger this) |
| 179 | + ['^ *proc[nd] *$']= {'sicad', {ignorecase=true } }, |
| 180 | +-- Purify log files start with "**** Purify" |
| 181 | + ['^%*%*%*%* Purify']='purifylog', |
| 182 | +-- XML |
| 183 | + ['<%?%s*xml.*%?>']='xml', |
| 184 | +-- XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN") |
| 185 | + ['\\<DTD\\s\\+XHTML\\s']='xhtml', |
| 186 | +-- HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN") |
| 187 | +-- Avoid "doctype html", used by slim. |
| 188 | + ['\\c<!DOCTYPE\\s\\+html\\>']= {'html', {vim_regex=true } }, |
| 189 | +-- PDF |
| 190 | + ['^%%PDF%-']='pdf', |
| 191 | +-- XXD output |
| 192 | + ['^%x%x%x%x%x%x%x: %x%x ?%x%x ?%x%x ?%x%x']='xxd', |
| 193 | +-- RCS/CVS log output |
| 194 | + ['^RCS file:']= {'rcslog', {start_lnum=1,end_lnum=2 } }, |
| 195 | +-- CVS commit |
| 196 | + ['^CVS:']= {'cvs', {start_lnum=2 } }, |
| 197 | + ['^CVS:']= {'cvs', {start_lnum=-1 } }, |
| 198 | +-- Prescribe |
| 199 | + ['^!R!']='prescribe', |
| 200 | +-- Send-pr |
| 201 | + ['^SEND%-PR:']='sendpr', |
| 202 | +-- SNNS files |
| 203 | + ['^SNNS network definition file']='snnsnet', |
| 204 | + ['^SNNS pattern definition file']='snnspat', |
| 205 | + ['^SNNS result file']='snnsres', |
| 206 | + ['&%%.-[Vv]irata']= {'virata', {start_lnum=1,end_lnum=5 } }, |
| 207 | + ['[0-9:.]* *execve%(']='strace', |
| 208 | + ['^__libc_start_main']='strace', |
| 209 | +-- VSE JCL |
| 210 | + ['^\\* $$ JOB\\>']= {'vsejcl', {vim_regex=true } }, |
| 211 | + ['^// *JOB\\>']= {'vsejcl', {vim_regex=true } }, |
| 212 | +-- TAK and SINDA |
| 213 | + ['K & K Associates']= {'takout', {start_lnum=4 } }, |
| 214 | + ['TAK 2000']= {'takout', {start_lnum=2 } }, |
| 215 | + ['S Y S T E M S I M P R O V E D']= {'syndaout', {start_lnum=3 } }, |
| 216 | + ['Run Date:']= {'takcmp', {start_lnum=6 } }, |
| 217 | + ['Node File 1']= {'sindacmp', {start_lnum=9 } }, |
| 218 | +function() |
| 219 | +-- DNS zone files |
| 220 | +if |
| 221 | +findany( |
| 222 | +lines[1]..lines[2]..lines[3]..lines[4], |
| 223 | + {'^; <<>> DiG [0-9%.]+.* <<>>','%$ORIGIN','%$TTL','IN%s+SOA'} |
| 224 | + ) |
| 225 | +then |
| 226 | +return'bindzone' |
| 227 | +end |
| 228 | +-- BAAN |
| 229 | +if-- 1 to 80 '*' characters |
| 230 | +lines[1]:find('|%*'..string.rep('%*?',79))andlines[2]:find('VRC') |
| 231 | +orlines[2]:find('|%*'..string.rep('%*?',79))andlines[3]:find('VRC') |
| 232 | +then |
| 233 | +return'baan' |
| 234 | +end |
| 235 | +end, |
| 236 | +-- Valgrind |
| 237 | + ['^==%d+== valgrind']='valgrind', |
| 238 | + ['^==%d+== Using valgrind']= {'valgrind', {start_lnum=3 } }, |
| 239 | +-- Go docs |
| 240 | + ['PACKAGE DOCUMENTATION$']='godoc', |
| 241 | +-- Renderman Interface Bytestream |
| 242 | + ['^##RenderMan']='rib', |
| 243 | +-- Scheme scripts |
| 244 | + ['exec%s%+%S*scheme']= {'scheme', {start_lnum=1,end_lnum=2 } }, |
| 245 | +-- Git output |
| 246 | + ['^\\(commit\\|tree\\|object\\)\\x\\{40,\\}\\>\\|^tag\\S\\+$']= {'git', {vim_regex=true } }, |
| 247 | +function() |
| 248 | +-- Gprof (gnu profiler) |
| 249 | +iflines[1]=='Flat profile:'andlines[2]==''andlines[3]:find('^Each sample counts as .* seconds%.$')then |
| 250 | +return'gprof' |
| 251 | +end |
| 252 | +end, |
| 253 | +-- Erlang terms |
| 254 | +-- (See also: http://www.gnu.org/software/emacs/manual/html_node/emacs/Choosing-Modes.html#Choosing-Modes) |
| 255 | + ['%-%*%-.*erlang.*%-%*%-']= {'erlang', {ignorecase=true } }, |
| 256 | +-- YAML |
| 257 | + ['^&YAML']='yaml', |
| 258 | +-- MikroTik RouterOS script |
| 259 | + ['^#.*by RouterOS']='routeros', |
| 260 | +-- Sed scripts |
| 261 | +-- #ncomment is allowed but most likely a false positive so reuire a space |
| 262 | +-- before any trailing comment text |
| 263 | + ['^#n%s']='sed', |
| 264 | + ['^#n$']='sed', |
| 265 | + } |
| 266 | + |
| 267 | +fork,vinpairs(patterns)do |
| 268 | +iftype(v)=='string'then |
| 269 | +-- Check the first line only |
| 270 | +iflines[1]:find(k)then |
| 271 | +returnv |
| 272 | +end |
| 273 | +elseiftype(v)=='function'then |
| 274 | +localft=v() |
| 275 | +ifftthen |
| 276 | +returnft |
| 277 | +end |
| 278 | +else |
| 279 | +localopts=type(v)=='table'andv[2]or {} |
| 280 | +ifopts.start_lnumthen |
| 281 | +for_,lineinipairs(getlines(bufnr,opts.start_lnum,opts.end_lnum))do |
| 282 | +ifline:find(k)then |
| 283 | +returnv[1] |
| 284 | +end |
| 285 | +end |
| 286 | +else |
| 287 | +-- Check the first line only |
| 288 | +localline=opts.ignorecaseandlines[1]:lower()orlines[1] |
| 289 | +ifopts.vim_regexandmatchregex(line,k)orline:find(k)then |
| 290 | +returnv[1] |
| 291 | +end |
| 292 | +end |
| 293 | +end |
| 294 | +end |
| 295 | + |
| 296 | +-- CVS diff |
| 297 | +for_,lineinipairs(getlines(bufnr,1,-1))do |
| 298 | +ifnotline:find('^%?')then |
| 299 | +ifmatchregex(line,[[^Index:\s\+\f\+$]])then |
| 300 | +return'diff' |
| 301 | +elseif |
| 302 | +-- Locale input files: Formal Definitions of Cultural Conventions |
| 303 | +-- Filename must be like en_US, fr_FR@euro or en_US.UTF-8 |
| 304 | +findany(path, {'%a%a_%a%a$','%a%a_%a%a[%.@]','%a%a_%a%ai18n$','%a%a_%a%aPOSIX$','%a%a_%a%atranslit_'}) |
| 305 | +then |
| 306 | +for_,line_inipairs(getlines(bufnr,1,100))do |
| 307 | +if |
| 308 | +findany(line_, { |
| 309 | +'^LC_IDENTIFICATION$', |
| 310 | +'^LC_CTYPE$', |
| 311 | +'^LC_COLLATE$', |
| 312 | +'^LC_MONETARY$', |
| 313 | +'^LC_NUMERIC$', |
| 314 | +'^LC_TIME$', |
| 315 | +'^LC_MESSAGES$', |
| 316 | +'^LC_PAPER$', |
| 317 | +'^LC_TELEPHONE$', |
| 318 | +'^LC_MEASUREMENT$', |
| 319 | +'^LC_NAME$', |
| 320 | +'^LC_ADDRESS$', |
| 321 | + }) |
| 322 | +then |
| 323 | +return'fdcc' |
| 324 | +end |
| 325 | +end |
| 326 | +end |
| 327 | +end |
| 328 | +end |
| 329 | +end |
| 330 | + |
| 331 | +-- Only do the rest when the FileType autocommand has not been triggered yet. |
| 332 | +ifdid_filetype()then |
| 333 | +returnM |
| 334 | +end |
| 335 | + |
| 336 | +-- Load the user defined scripts file first |
| 337 | +-- Only do this when the FileType autocommand has not been triggered yet |
| 338 | +ifvim.fn.exists('myscriptsfile')~=0andvim.fn.filereadable(vim.fn.expand('myscriptsfile'))~=0then |
| 339 | +vim.cmd('execute source myscriptsfile') |
| 340 | +ifdid_filetype()then |
| 341 | +returnM |
| 342 | +end |
| 343 | +end |
| 344 | + |
| 345 | +localcpo_save=vim.o.cpoptions |
| 346 | +vim.cmd('set cpo&vim') |
| 347 | + |
| 348 | +localpath=vim.fn.expand('<afile>') |
| 349 | +localbufnr=vim.api.nvim_get_current_buf() |
| 350 | + |
| 351 | +localfirst_line=getlines(bufnr,1) |
| 352 | +localft=first_line:find('^#!')andscripts_shebang(path,bufnr)orscripts_no_shebang(path,bufnr) |
| 353 | + |
| 354 | +-- luacheck: push ignore 122 |
| 355 | + |
| 356 | +vim.bo[bufnr].filetype=ft |
| 357 | +-- Restore 'cpopoptions' |
| 358 | +vim.o.cpoptions=cpo_save |
| 359 | + |
| 360 | +-- luacheck: pop |
| 361 | + |
| 362 | +returnM |