summaryrefslogtreecommitdiffstats
path: root/autoload/polyglot/shebang.vim
diff options
context:
space:
mode:
authorAdam Stankiewicz <sheerun@sher.pl>2020-10-02 03:42:03 +0200
committerAdam Stankiewicz <sheerun@sher.pl>2020-10-02 03:42:03 +0200
commit94ec9c38e744241e48fb8d75ae6e8811bc73fc59 (patch)
tree03940b00ce5d9a494253af5d2976d095a11a5d2f /autoload/polyglot/shebang.vim
parentbff55a54fa8a70e664ebe8a614681dd0d92d66b6 (diff)
downloadvim-polyglot-94ec9c38e744241e48fb8d75ae6e8811bc73fc59.tar.gz
vim-polyglot-94ec9c38e744241e48fb8d75ae6e8811bc73fc59.zip
Do not use ++once to support older vims, fixes #7056
Diffstat (limited to 'autoload/polyglot/shebang.vim')
-rw-r--r--autoload/polyglot/shebang.vim406
1 files changed, 403 insertions, 3 deletions
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