scripts.vim 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. " Vim support file to detect file types in scripts
  2. "
  3. " Maintainer: Bram Moolenaar <Bram@vim.org>
  4. " Last change: 2021 Jan 22
  5. " This file is called by an autocommand for every file that has just been
  6. " loaded into a buffer. It checks if the type of file can be recognized by
  7. " the file contents. The autocommand is in $VIMRUNTIME/filetype.vim.
  8. "
  9. " Note that the pattern matches are done with =~# to avoid the value of the
  10. " 'ignorecase' option making a difference. Where case is to be ignored use
  11. " =~? instead. Do not use =~ anywhere.
  12. " Only run when using legacy filetype
  13. if !exists('g:do_legacy_filetype')
  14. finish
  15. endif
  16. " Only do the rest when the FileType autocommand has not been triggered yet.
  17. if did_filetype()
  18. finish
  19. endif
  20. " Load the user defined scripts file first
  21. " Only do this when the FileType autocommand has not been triggered yet
  22. if exists("myscriptsfile") && filereadable(expand(myscriptsfile))
  23. execute "source " . myscriptsfile
  24. if did_filetype()
  25. finish
  26. endif
  27. endif
  28. " Line continuation is used here, remove 'C' from 'cpoptions'
  29. let s:cpo_save = &cpo
  30. set cpo&vim
  31. let s:line1 = getline(1)
  32. if s:line1 =~# "^#!"
  33. " A script that starts with "#!".
  34. " Check for a line like "#!/usr/bin/env {options} bash". Turn it into
  35. " "#!/usr/bin/bash" to make matching easier.
  36. " Recognize only a few {options} that are commonly used.
  37. if s:line1 =~# '^#!\s*\S*\<env\s'
  38. let s:line1 = substitute(s:line1, '\S\+=\S\+', '', 'g')
  39. let s:line1 = substitute(s:line1, '\(-[iS]\|--ignore-environment\|--split-string\)', '', '')
  40. let s:line1 = substitute(s:line1, '\<env\s\+', '', '')
  41. endif
  42. " Get the program name.
  43. " Only accept spaces in PC style paths: "#!c:/program files/perl [args]".
  44. " If the word env is used, use the first word after the space:
  45. " "#!/usr/bin/env perl [path/args]"
  46. " If there is no path use the first word: "#!perl [path/args]".
  47. " Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]".
  48. if s:line1 =~# '^#!\s*\a:[/\\]'
  49. let s:name = substitute(s:line1, '^#!.*[/\\]\(\i\+\).*', '\1', '')
  50. elseif s:line1 =~# '^#!.*\<env\>'
  51. let s:name = substitute(s:line1, '^#!.*\<env\>\s\+\(\i\+\).*', '\1', '')
  52. elseif s:line1 =~# '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)'
  53. let s:name = substitute(s:line1, '^#!\s*\([^/\\ ]*\>\).*', '\1', '')
  54. else
  55. let s:name = substitute(s:line1, '^#!\s*\S*[/\\]\(\i\+\).*', '\1', '')
  56. endif
  57. " tcl scripts may have #!/bin/sh in the first line and "exec wish" in the
  58. " third line. Suggested by Steven Atkinson.
  59. if getline(3) =~# '^exec wish'
  60. let s:name = 'wish'
  61. endif
  62. " Bourne-like shell scripts: bash bash2 ksh ksh93 sh
  63. if s:name =~# '^\(bash\d*\|\|ksh\d*\|sh\)\>'
  64. call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
  65. " csh scripts
  66. elseif s:name =~# '^csh\>'
  67. if exists("g:filetype_csh")
  68. call dist#ft#SetFileTypeShell(g:filetype_csh)
  69. else
  70. call dist#ft#SetFileTypeShell("csh")
  71. endif
  72. " tcsh scripts
  73. elseif s:name =~# '^tcsh\>'
  74. call dist#ft#SetFileTypeShell("tcsh")
  75. " Z shell scripts
  76. elseif s:name =~# '^zsh\>'
  77. set ft=zsh
  78. " TCL scripts
  79. elseif s:name =~# '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>'
  80. set ft=tcl
  81. " Expect scripts
  82. elseif s:name =~# '^expect\>'
  83. set ft=expect
  84. " Gnuplot scripts
  85. elseif s:name =~# '^gnuplot\>'
  86. set ft=gnuplot
  87. " Makefiles
  88. elseif s:name =~# 'make\>'
  89. set ft=make
  90. " Pike
  91. elseif s:name =~# '^pike\%(\>\|[0-9]\)'
  92. set ft=pike
  93. " Lua
  94. elseif s:name =~# 'lua'
  95. set ft=lua
  96. " Perl
  97. elseif s:name =~# 'perl'
  98. set ft=perl
  99. " PHP
  100. elseif s:name =~# 'php'
  101. set ft=php
  102. " Python
  103. elseif s:name =~# 'python'
  104. set ft=python
  105. " Groovy
  106. elseif s:name =~# '^groovy\>'
  107. set ft=groovy
  108. " Raku
  109. elseif s:name =~# 'raku'
  110. set ft=raku
  111. " Ruby
  112. elseif s:name =~# 'ruby'
  113. set ft=ruby
  114. " JavaScript
  115. elseif s:name =~# 'node\(js\)\=\>\|js\>' || s:name =~# 'rhino\>'
  116. set ft=javascript
  117. " BC calculator
  118. elseif s:name =~# '^bc\>'
  119. set ft=bc
  120. " sed
  121. elseif s:name =~# 'sed\>'
  122. set ft=sed
  123. " OCaml-scripts
  124. elseif s:name =~# 'ocaml'
  125. set ft=ocaml
  126. " Awk scripts; also finds "gawk"
  127. elseif s:name =~# 'awk\>'
  128. set ft=awk
  129. " Website MetaLanguage
  130. elseif s:name =~# 'wml'
  131. set ft=wml
  132. " Scheme scripts
  133. elseif s:name =~# 'scheme'
  134. set ft=scheme
  135. " CFEngine scripts
  136. elseif s:name =~# 'cfengine'
  137. set ft=cfengine
  138. " Erlang scripts
  139. elseif s:name =~# 'escript'
  140. set ft=erlang
  141. " Haskell
  142. elseif s:name =~# 'haskell'
  143. set ft=haskell
  144. " Scala
  145. elseif s:name =~# 'scala\>'
  146. set ft=scala
  147. " Clojure
  148. elseif s:name =~# 'clojure'
  149. set ft=clojure
  150. " Free Pascal
  151. elseif s:name =~# 'instantfpc\>'
  152. set ft=pascal
  153. " Fennel
  154. elseif s:name =~# 'fennel\>'
  155. set ft=fennel
  156. " MikroTik RouterOS script
  157. elseif s:name =~# 'rsc\>'
  158. set ft=routeros
  159. " Fish shell
  160. elseif s:name =~# 'fish\>'
  161. set ft=fish
  162. " Gforth
  163. elseif s:name =~# 'gforth\>'
  164. set ft=forth
  165. " Icon
  166. elseif s:name =~# 'icon\>'
  167. set ft=icon
  168. " Guile
  169. elseif s:name =~# 'guile'
  170. set ft=scheme
  171. endif
  172. unlet s:name
  173. else
  174. " File does not start with "#!".
  175. let s:line2 = getline(2)
  176. let s:line3 = getline(3)
  177. let s:line4 = getline(4)
  178. let s:line5 = getline(5)
  179. " Bourne-like shell scripts: sh ksh bash bash2
  180. if s:line1 =~# '^:$'
  181. call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
  182. " Z shell scripts
  183. elseif s:line1 =~# '^#compdef\>' || s:line1 =~# '^#autoload\>' ||
  184. \ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~# '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>'
  185. set ft=zsh
  186. " ELM Mail files
  187. elseif s:line1 =~# '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
  188. set ft=mail
  189. " Mason
  190. elseif s:line1 =~# '^<[%&].*>'
  191. set ft=mason
  192. " Vim scripts (must have '" vim' as the first line to trigger this)
  193. elseif s:line1 =~# '^" *[vV]im$'
  194. set ft=vim
  195. " libcxx and libstdc++ standard library headers like "iostream" do not have
  196. " an extension, recognize the Emacs file mode.
  197. elseif s:line1 =~? '-\*-.*C++.*-\*-'
  198. set ft=cpp
  199. " MOO
  200. elseif s:line1 =~# '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
  201. set ft=moo
  202. " Diff file:
  203. " - "diff" in first line (context diff)
  204. " - "Only in " in first line
  205. " - "--- " in first line and "+++ " in second line (unified diff).
  206. " - "*** " in first line and "--- " in second line (context diff).
  207. " - "# It was generated by makepatch " in the second line (makepatch diff).
  208. " - "Index: <filename>" in the first line (CVS file)
  209. " - "=== ", line of "=", "---", "+++ " (SVK diff)
  210. " - "=== ", "--- ", "+++ " (bzr diff, common case)
  211. " - "=== (removed|added|renamed|modified)" (bzr diff, alternative)
  212. " - "# HG changeset patch" in first line (Mercurial export format)
  213. elseif s: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\)'
  214. \ || (s:line1 =~# '^--- ' && s:line2 =~# '^+++ ')
  215. \ || (s:line1 =~# '^\* looking for ' && s:line2 =~# '^\* comparing to ')
  216. \ || (s:line1 =~# '^\*\*\* ' && s:line2 =~# '^--- ')
  217. \ || (s:line1 =~# '^=== ' && ((s:line2 =~# '^=\{66\}' && s:line3 =~# '^--- ' && s:line4 =~# '^+++') || (s:line2 =~# '^--- ' && s:line3 =~# '^+++ ')))
  218. \ || (s:line1 =~# '^=== \(removed\|added\|renamed\|modified\)')
  219. set ft=diff
  220. " PostScript Files (must have %!PS as the first line, like a2ps output)
  221. elseif s:line1 =~# '^%![ \t]*PS'
  222. set ft=postscr
  223. " M4 scripts: Guess there is a line that starts with "dnl".
  224. elseif s:line1 =~# '^\s*dnl\>'
  225. \ || s:line2 =~# '^\s*dnl\>'
  226. \ || s:line3 =~# '^\s*dnl\>'
  227. \ || s:line4 =~# '^\s*dnl\>'
  228. \ || s:line5 =~# '^\s*dnl\>'
  229. set ft=m4
  230. " AmigaDos scripts
  231. elseif $TERM == "amiga"
  232. \ && (s:line1 =~# "^;" || s:line1 =~? '^\.bra')
  233. set ft=amiga
  234. " SiCAD scripts (must have procn or procd as the first line to trigger this)
  235. elseif s:line1 =~? '^ *proc[nd] *$'
  236. set ft=sicad
  237. " Purify log files start with "**** Purify"
  238. elseif s:line1 =~# '^\*\*\*\* Purify'
  239. set ft=purifylog
  240. " XML
  241. elseif s:line1 =~# '<?\s*xml.*?>'
  242. set ft=xml
  243. " XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN")
  244. elseif s:line1 =~# '\<DTD\s\+XHTML\s'
  245. set ft=xhtml
  246. " HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN")
  247. " Avoid "doctype html", used by slim.
  248. elseif s:line1 =~? '<!DOCTYPE\s\+html\>'
  249. set ft=html
  250. " PDF
  251. elseif s:line1 =~# '^%PDF-'
  252. set ft=pdf
  253. " XXD output
  254. elseif s:line1 =~# '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} '
  255. set ft=xxd
  256. " RCS/CVS log output
  257. elseif s:line1 =~# '^RCS file:' || s:line2 =~# '^RCS file:'
  258. set ft=rcslog
  259. " CVS commit
  260. elseif s:line2 =~# '^CVS:' || getline("$") =~# '^CVS: '
  261. set ft=cvs
  262. " Prescribe
  263. elseif s:line1 =~# '^!R!'
  264. set ft=prescribe
  265. " Send-pr
  266. elseif s:line1 =~# '^SEND-PR:'
  267. set ft=sendpr
  268. " SNNS files
  269. elseif s:line1 =~# '^SNNS network definition file'
  270. set ft=snnsnet
  271. elseif s:line1 =~# '^SNNS pattern definition file'
  272. set ft=snnspat
  273. elseif s:line1 =~# '^SNNS result file'
  274. set ft=snnsres
  275. " Virata
  276. elseif s:line1 =~# '^%.\{-}[Vv]irata'
  277. \ || s:line2 =~# '^%.\{-}[Vv]irata'
  278. \ || s:line3 =~# '^%.\{-}[Vv]irata'
  279. \ || s:line4 =~# '^%.\{-}[Vv]irata'
  280. \ || s:line5 =~# '^%.\{-}[Vv]irata'
  281. set ft=virata
  282. " Strace
  283. elseif s:line1 =~# '[0-9:.]* *execve(' || s:line1 =~# '^__libc_start_main'
  284. set ft=strace
  285. " VSE JCL
  286. elseif s:line1 =~# '^\* $$ JOB\>' || s:line1 =~# '^// *JOB\>'
  287. set ft=vsejcl
  288. " TAK and SINDA
  289. elseif s:line4 =~# 'K & K Associates' || s:line2 =~# 'TAK 2000'
  290. set ft=takout
  291. elseif s:line3 =~# 'S Y S T E M S I M P R O V E D '
  292. set ft=sindaout
  293. elseif getline(6) =~# 'Run Date: '
  294. set ft=takcmp
  295. elseif getline(9) =~# 'Node File 1'
  296. set ft=sindacmp
  297. " DNS zone files
  298. elseif s:line1.s:line2.s:line3.s:line4 =~# '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
  299. set ft=bindzone
  300. " BAAN
  301. elseif s:line1 =~# '|\*\{1,80}' && s:line2 =~# 'VRC '
  302. \ || s:line2 =~# '|\*\{1,80}' && s:line3 =~# 'VRC '
  303. set ft=baan
  304. " Valgrind
  305. elseif s:line1 =~# '^==\d\+== valgrind' || s:line3 =~# '^==\d\+== Using valgrind'
  306. set ft=valgrind
  307. " Go docs
  308. elseif s:line1 =~# '^PACKAGE DOCUMENTATION$'
  309. set ft=godoc
  310. " Renderman Interface Bytestream
  311. elseif s:line1 =~# '^##RenderMan'
  312. set ft=rib
  313. " Scheme scripts
  314. elseif s:line1 =~# 'exec\s\+\S*scheme' || s:line2 =~# 'exec\s\+\S*scheme'
  315. set ft=scheme
  316. " Git output
  317. elseif s:line1 =~# '^\(commit\|tree\|object\) \x\{40,\}\>\|^tag \S\+$'
  318. set ft=git
  319. " Gprof (gnu profiler)
  320. elseif s:line1 == 'Flat profile:'
  321. \ && s:line2 == ''
  322. \ && s:line3 =~# '^Each sample counts as .* seconds.$'
  323. set ft=gprof
  324. " Erlang terms
  325. " (See also: http://www.gnu.org/software/emacs/manual/html_node/emacs/Choosing-Modes.html#Choosing-Modes)
  326. elseif s:line1 =~? '-\*-.*erlang.*-\*-'
  327. set ft=erlang
  328. " YAML
  329. elseif s:line1 =~# '^%YAML'
  330. set ft=yaml
  331. " MikroTik RouterOS script
  332. elseif s:line1 =~# '^#.*by RouterOS.*$'
  333. set ft=routeros
  334. " Sed scripts
  335. " #ncomment is allowed but most likely a false positive so require a space
  336. " before any trailing comment text
  337. elseif s:line1 =~# '^#n\%($\|\s\)'
  338. set ft=sed
  339. " CVS diff
  340. else
  341. let s:lnum = 1
  342. while getline(s:lnum) =~# "^? " && s:lnum < line("$")
  343. let s:lnum += 1
  344. endwhile
  345. if getline(s:lnum) =~# '^Index:\s\+\f\+$'
  346. set ft=diff
  347. " locale input files: Formal Definitions of Cultural Conventions
  348. " filename must be like en_US, fr_FR@euro or en_US.UTF-8
  349. elseif expand("%") =~# '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_'
  350. let s:lnum = 1
  351. while s:lnum < 100 && s:lnum < line("$")
  352. if getline(s:lnum) =~# '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$'
  353. setf fdcc
  354. break
  355. endif
  356. let s:lnum += 1
  357. endwhile
  358. endif
  359. unlet s:lnum
  360. endif
  361. unlet s:line2 s:line3 s:line4 s:line5
  362. endif
  363. " Restore 'cpoptions'
  364. let &cpo = s:cpo_save
  365. unlet s:cpo_save s:line1