2022-02-13 20:32:02 +00:00
vim9script
# Vim function for detecting a filetype from the file contents .
# Invoked from "scripts.vim" in 'runtimepath'
#
2023-08-13 10:33:05 +02:00
# Maintainer : The Vim Project < https :// github .com /vim/ vim >
# Last Change : 2023 Aug 10
# Former Maintainer : Bram Moolenaar < Bram @vim .org >
2022-02-13 20:32:02 +00:00
export def DetectFiletype ( )
var line1 = getline ( 1 )
if line1 [0 ] = = '#' && line1 [1 ] = = '!'
# File that starts with "#!" .
DetectFromHashBang ( line1 )
else
# File does not start with "#!" .
DetectFromText ( line1 )
endif
enddef
# Called for a script that has "#!" in the first line .
def DetectFromHashBang ( firstline : string )
var line1 = firstline
# 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'
line1 = substitute ( line1 , '\S\+=\S\+' , '' , 'g' )
line1 = substitute ( line1 , '\(-[iS]\|--ignore-environment\|--split-string\)' , '' , '' )
line1 = substitute ( line1 , '\<env\s\+' , '' , '' )
endif
# Get the program name .
# Only accept spaces in PC style paths : "#!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]" .
var name : string
if line1 = ~ '^#!\s*\a:[/\\]'
name = substitute ( line1 , '^#!.*[/\\]\(\i\+\).*' , '\1' , '' )
elseif line1 = ~ '^#!.*\<env\>'
name = substitute ( line1 , '^#!.*\<env\>\s\+\(\i\+\).*' , '\1' , '' )
elseif line1 = ~ '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)'
name = substitute ( line1 , '^#!\s*\([^/\\ ]*\>\).*' , '\1' , '' )
else
2023-06-08 21:27:13 +01:00
name = substitute ( line1 , '^#!\s*\S*[/\\]\(\f\+\).*' , '\1' , '' )
2022-02-13 20:32:02 +00:00
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'
name = 'wish'
endif
2023-06-09 21:01:47 +01:00
var ft = Exe2filetype ( name , line1 )
if ft ! = ''
exe 'setl ft=' .. ft
endif
enddef
# Returns the filetype name associated with program "name" .
# "line1" is the #! line at the top of the file . Use the same as "name" if
# not available .
# Returns an empty string when not recognized .
export def Exe2filetype ( name : string , line1 : string ) : string
2022-11-24 10:58:10 +00:00
# Bourne - like shell scripts : bash bash2 dash ksh ksh93 sh
if name = ~ '^\(bash\d*\|dash\|ksh\d*\|sh\)\>'
2023-06-09 21:01:47 +01:00
return dist #ft #SetFileTypeSH ( line1 , false )
2022-02-13 20:32:02 +00:00
# csh scripts
elseif name = ~ '^csh\>'
2023-06-09 21:01:47 +01:00
return dist #ft #SetFileTypeShell ( exists ( "g:filetype_csh" ) ? g :filetype_csh : 'csh' , false )
2022-02-13 20:32:02 +00:00
# tcsh scripts
elseif name = ~ '^tcsh\>'
2023-06-09 21:01:47 +01:00
return dist #ft #SetFileTypeShell ( "tcsh" , false )
2022-02-13 20:32:02 +00:00
# Z shell scripts
elseif name = ~ '^zsh\>'
2023-06-09 21:01:47 +01:00
return 'zsh'
2022-02-13 20:32:02 +00:00
# TCL scripts
elseif name = ~ '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>'
2023-06-09 21:01:47 +01:00
return 'tcl'
2022-02-13 20:32:02 +00:00
# Expect scripts
elseif name = ~ '^expect\>'
2023-06-09 21:01:47 +01:00
return 'expect'
2022-02-13 20:32:02 +00:00
# Gnuplot scripts
elseif name = ~ '^gnuplot\>'
2023-06-09 21:01:47 +01:00
return 'gnuplot'
2022-02-13 20:32:02 +00:00
# Makefiles
elseif name = ~ 'make\>'
2023-06-09 21:01:47 +01:00
return 'make'
2022-02-13 20:32:02 +00:00
# Pike
elseif name = ~ '^pike\%(\>\|[0-9]\)'
2023-06-09 21:01:47 +01:00
return 'pike'
2022-02-13 20:32:02 +00:00
# Lua
elseif name = ~ 'lua'
2023-06-09 21:01:47 +01:00
return 'lua'
2022-02-13 20:32:02 +00:00
# Perl
elseif name = ~ 'perl'
2023-06-09 21:01:47 +01:00
return 'perl'
2022-02-13 20:32:02 +00:00
# PHP
elseif name = ~ 'php'
2023-06-09 21:01:47 +01:00
return 'php'
2022-02-13 20:32:02 +00:00
# Python
elseif name = ~ 'python'
2023-06-09 21:01:47 +01:00
return 'python'
2022-02-13 20:32:02 +00:00
# Groovy
elseif name = ~ '^groovy\>'
2023-06-09 21:01:47 +01:00
return 'groovy'
2022-02-13 20:32:02 +00:00
# Raku
elseif name = ~ 'raku'
2023-06-09 21:01:47 +01:00
return 'raku'
2022-02-13 20:32:02 +00:00
# Ruby
elseif name = ~ 'ruby'
2023-06-09 21:01:47 +01:00
return 'ruby'
2022-02-13 20:32:02 +00:00
# JavaScript
elseif name = ~ 'node\(js\)\=\>\|js\>' | | name = ~ 'rhino\>'
2023-06-09 21:01:47 +01:00
return 'javascript'
2022-02-13 20:32:02 +00:00
# BC calculator
elseif name = ~ '^bc\>'
2023-06-09 21:01:47 +01:00
return 'bc'
2022-02-13 20:32:02 +00:00
# sed
elseif name = ~ 'sed\>'
2023-06-09 21:01:47 +01:00
return 'sed'
2022-02-13 20:32:02 +00:00
# OCaml - scripts
elseif name = ~ 'ocaml'
2023-06-09 21:01:47 +01:00
return 'ocaml'
2022-02-13 20:32:02 +00:00
# Awk scripts ; also finds "gawk"
elseif name = ~ 'awk\>'
2023-06-09 21:01:47 +01:00
return 'awk'
2022-02-13 20:32:02 +00:00
# Website MetaLanguage
elseif name = ~ 'wml'
2023-06-09 21:01:47 +01:00
return 'wml'
2022-02-13 20:32:02 +00:00
# Scheme scripts
elseif name = ~ 'scheme'
2023-06-09 21:01:47 +01:00
return 'scheme'
2022-02-13 20:32:02 +00:00
# CFEngine scripts
elseif name = ~ 'cfengine'
2023-06-09 21:01:47 +01:00
return 'cfengine'
2022-02-13 20:32:02 +00:00
# Erlang scripts
elseif name = ~ 'escript'
2023-06-09 21:01:47 +01:00
return 'erlang'
2022-02-13 20:32:02 +00:00
# Haskell
elseif name = ~ 'haskell'
2023-06-09 21:01:47 +01:00
return 'haskell'
2022-02-13 20:32:02 +00:00
# Scala
elseif name = ~ 'scala\>'
2023-06-09 21:01:47 +01:00
return 'scala'
2022-02-13 20:32:02 +00:00
# Clojure
elseif name = ~ 'clojure'
2023-06-09 21:01:47 +01:00
return 'clojure'
2022-02-13 20:32:02 +00:00
# Free Pascal
elseif name = ~ 'instantfpc\>'
2023-06-09 21:01:47 +01:00
return 'pascal'
2022-02-13 20:32:02 +00:00
# Fennel
elseif name = ~ 'fennel\>'
2023-06-09 21:01:47 +01:00
return 'fennel'
2022-02-13 20:32:02 +00:00
# MikroTik RouterOS script
elseif name = ~ 'rsc\>'
2023-06-09 21:01:47 +01:00
return 'routeros'
2022-02-13 20:32:02 +00:00
# Fish shell
elseif name = ~ 'fish\>'
2023-06-09 21:01:47 +01:00
return 'fish'
2022-02-13 20:32:02 +00:00
# Gforth
elseif name = ~ 'gforth\>'
2023-06-09 21:01:47 +01:00
return 'forth'
2022-02-13 20:32:02 +00:00
2022-06-16 13:27:18 +01:00
# Icon
elseif name = ~ 'icon\>'
2023-06-09 21:01:47 +01:00
return 'icon'
2022-06-16 13:27:18 +01:00
2022-07-05 21:56:39 +01:00
# Guile
elseif name = ~ 'guile'
2023-06-09 21:01:47 +01:00
return 'scheme'
2022-07-05 21:56:39 +01:00
2023-06-08 21:27:13 +01:00
# Nix
elseif name = ~ 'nix-shell'
2023-06-09 21:01:47 +01:00
return 'nix'
2023-06-08 21:27:13 +01:00
2023-08-27 19:51:37 +02:00
# Crystal
elseif name = ~ '^crystal\>'
return 'crystal'
2023-08-29 22:21:35 +02:00
# Rexx
elseif name = ~ '^\%(rexx\|regina\)\>'
return 'rexx'
2023-10-23 19:24:05 +02:00
# Janet
elseif name = ~ '^janet\>'
return 'janet'
2023-10-28 21:19:54 +02:00
# Dart
elseif name = ~ '^dart\>'
return 'dart'
2023-12-19 20:44:41 +01:00
# Execline ( s6 )
elseif name = ~ '^execlineb\>'
return 'execline'
2024-06-16 08:32:15 +02:00
# Vim
elseif name = ~ '^vim\>'
return 'vim'
2022-02-13 20:32:02 +00:00
endif
2023-06-09 21:01:47 +01:00
return ''
2022-02-13 20:32:02 +00:00
enddef
# Called for a script that does not have "#!" in the first line .
def DetectFromText ( line1 : string )
var line2 = getline ( 2 )
var line3 = getline ( 3 )
var line4 = getline ( 4 )
var line5 = getline ( 5 )
# Bourne - like shell scripts : sh ksh bash bash2
if line1 = ~ '^:$'
call dist #ft #SetFileTypeSH ( line1 )
# 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\>'
2023-05-06 21:21:52 +01:00
setl ft = zsh
2022-02-13 20:32:02 +00:00
# ELM Mail files
elseif line1 = ~ '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
2023-05-06 21:21:52 +01:00
setl ft = mail
2022-02-13 20:32:02 +00:00
# Mason
elseif line1 = ~ '^<[%&].*>'
2023-05-06 21:21:52 +01:00
setl ft = mason
2022-02-13 20:32:02 +00:00
# Vim scripts ( must have '" vim' as the first line to trigger this )
elseif line1 = ~ '^" *[vV]im$'
2023-05-06 21:21:52 +01:00
setl ft = vim
2022-02-13 20:32:02 +00:00
# libcxx and libstdc + + standard library headers like "iostream" do not have
# an extension , recognize the Emacs file mode .
elseif line1 = ~ ? '-\*-.*C++.*-\*-'
2023-05-06 21:21:52 +01:00
setl ft = cpp
2022-02-13 20:32:02 +00:00
# MOO
elseif line1 = ~ '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
2023-05-06 21:21:52 +01:00
setl ft = moo
2022-02-13 20:32:02 +00:00
# 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\)' )
2023-05-06 21:21:52 +01:00
setl ft = diff
2022-02-13 20:32:02 +00:00
# PostScript Files ( must have %! PS as the first line , like a2ps output )
elseif line1 = ~ '^%![ \t]*PS'
2023-05-06 21:21:52 +01:00
setl ft = postscr
2022-02-13 20:32:02 +00:00
# M4 scripts : 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\>'
2023-05-06 21:21:52 +01:00
setl ft = m4
2022-02-13 20:32:02 +00:00
# AmigaDos scripts
elseif $TERM = = "amiga" && ( line1 = ~ "^;" | | line1 = ~ ? '^\.bra' )
2023-05-06 21:21:52 +01:00
setl ft = amiga
2022-02-13 20:32:02 +00:00
# SiCAD scripts ( must have procn or procd as the first line to trigger this )
elseif line1 = ~ ? '^ *proc[nd] *$'
2023-05-06 21:21:52 +01:00
setl ft = sicad
2022-02-13 20:32:02 +00:00
# Purify log files start with "**** Purify"
elseif line1 = ~ '^\*\*\*\* Purify'
2023-05-06 21:21:52 +01:00
setl ft = purifylog
2022-02-13 20:32:02 +00:00
# XML
elseif line1 = ~ '<?\s*xml.*?>'
2023-05-06 21:21:52 +01:00
setl ft = xml
2022-02-13 20:32:02 +00:00
# XHTML ( e .g .: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" )
elseif line1 = ~ '\<DTD\s\+XHTML\s'
2023-05-06 21:21:52 +01:00
setl ft = xhtml
2022-02-13 20:32:02 +00:00
# HTML ( e .g .: < ! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" )
# Avoid "doctype html" , used by slim .
elseif line1 = ~ ? '<!DOCTYPE\s\+html\>'
2023-05-06 21:21:52 +01:00
setl ft = html
2022-02-13 20:32:02 +00:00
# PDF
elseif line1 = ~ '^%PDF-'
2023-05-06 21:21:52 +01:00
setl ft = pdf
2022-02-13 20:32:02 +00:00
# XXD output
elseif line1 = ~ '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} '
2023-05-06 21:21:52 +01:00
setl ft = xxd
2022-02-13 20:32:02 +00:00
# RCS /CVS log output
elseif line1 = ~ '^RCS file:' | | line2 = ~ '^RCS file:'
2023-05-06 21:21:52 +01:00
setl ft = rcslog
2022-02-13 20:32:02 +00:00
# CVS commit
elseif line2 = ~ '^CVS:' | | getline ( "$" ) = ~ '^CVS: '
2023-05-06 21:21:52 +01:00
setl ft = cvs
2022-02-13 20:32:02 +00:00
# Prescribe
elseif line1 = ~ '^!R!'
2023-05-06 21:21:52 +01:00
setl ft = prescribe
2022-02-13 20:32:02 +00:00
# Send - pr
elseif line1 = ~ '^SEND-PR:'
2023-05-06 21:21:52 +01:00
setl ft = sendpr
2022-02-13 20:32:02 +00:00
# SNNS files
elseif line1 = ~ '^SNNS network definition file'
2023-05-06 21:21:52 +01:00
setl ft = snnsnet
2022-02-13 20:32:02 +00:00
elseif line1 = ~ '^SNNS pattern definition file'
2023-05-06 21:21:52 +01:00
setl ft = snnspat
2022-02-13 20:32:02 +00:00
elseif line1 = ~ '^SNNS result file'
2023-05-06 21:21:52 +01:00
setl ft = snnsres
2022-02-13 20:32:02 +00:00
# Virata
elseif line1 = ~ '^%.\{-}[Vv]irata'
| | line2 = ~ '^%.\{-}[Vv]irata'
| | line3 = ~ '^%.\{-}[Vv]irata'
| | line4 = ~ '^%.\{-}[Vv]irata'
| | line5 = ~ '^%.\{-}[Vv]irata'
2023-05-06 21:21:52 +01:00
setl ft = virata
2022-02-13 20:32:02 +00:00
# Strace
2023-04-17 22:31:38 +01:00
# inaccurate fast match first , then use accurate slow match
2023-11-04 09:39:54 +01:00
elseif ( line1 = ~ 'execve(' && line1 = ~ '^[0-9:. ]*execve(' )
2023-04-17 22:31:38 +01:00
| | line1 = ~ '^__libc_start_main'
2023-05-06 21:21:52 +01:00
setl ft = strace
2022-02-13 20:32:02 +00:00
# VSE JCL
elseif line1 = ~ '^\* $$ JOB\>' | | line1 = ~ '^// *JOB\>'
2023-05-06 21:21:52 +01:00
setl ft = vsejcl
2022-02-13 20:32:02 +00:00
# TAK and SINDA
elseif line4 = ~ 'K & K Associates' | | line2 = ~ 'TAK 2000'
2023-05-06 21:21:52 +01:00
setl ft = takout
2022-02-13 20:32:02 +00:00
elseif line3 = ~ 'S Y S T E M S I M P R O V E D '
2023-05-06 21:21:52 +01:00
setl ft = sindaout
2022-02-13 20:32:02 +00:00
elseif getline ( 6 ) = ~ 'Run Date: '
2023-05-06 21:21:52 +01:00
setl ft = takcmp
2022-02-13 20:32:02 +00:00
elseif getline ( 9 ) = ~ 'Node File 1'
2023-05-06 21:21:52 +01:00
setl ft = sindacmp
2022-02-13 20:32:02 +00:00
# DNS zone files
elseif line1 .. line2 .. line3 .. line4 = ~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
2023-05-06 21:21:52 +01:00
setl ft = bindzone
2022-02-13 20:32:02 +00:00
# BAAN
elseif line1 = ~ '|\*\{1,80}' && line2 = ~ 'VRC '
| | line2 = ~ '|\*\{1,80}' && line3 = ~ 'VRC '
2023-05-06 21:21:52 +01:00
setl ft = baan
2022-02-13 20:32:02 +00:00
# Valgrind
elseif line1 = ~ '^==\d\+== valgrind' | | line3 = ~ '^==\d\+== Using valgrind'
2023-05-06 21:21:52 +01:00
setl ft = valgrind
2022-02-13 20:32:02 +00:00
# Go docs
elseif line1 = ~ '^PACKAGE DOCUMENTATION$'
2023-05-06 21:21:52 +01:00
setl ft = godoc
2022-02-13 20:32:02 +00:00
# Renderman Interface Bytestream
elseif line1 = ~ '^##RenderMan'
2023-05-06 21:21:52 +01:00
setl ft = rib
2022-02-13 20:32:02 +00:00
# Scheme scripts
elseif line1 = ~ 'exec\s\+\S*scheme' | | line2 = ~ 'exec\s\+\S*scheme'
2023-05-06 21:21:52 +01:00
setl ft = scheme
2022-02-13 20:32:02 +00:00
# Git output
elseif line1 = ~ '^\(commit\|tree\|object\) \x\{40,\}\>\|^tag \S\+$'
2023-05-06 21:21:52 +01:00
setl ft = git
2022-02-13 20:32:02 +00:00
# Gprof ( gnu profiler )
elseif line1 = = 'Flat profile:'
&& line2 = = ''
&& line3 = ~ '^Each sample counts as .* seconds.$'
2023-05-06 21:21:52 +01:00
setl ft = gprof
2022-02-13 20:32:02 +00:00
# Erlang terms
# ( See also : http :// www .gnu .org /software/ emacs /manual/ html_node /emacs/ Choosing - Modes .html #Choosing - Modes )
elseif line1 = ~ ? '-\*-.*erlang.*-\*-'
2023-05-06 21:21:52 +01:00
setl ft = erlang
2022-02-13 20:32:02 +00:00
# YAML
elseif line1 = ~ '^%YAML'
2023-05-06 21:21:52 +01:00
setl ft = yaml
2022-02-13 20:32:02 +00:00
# MikroTik RouterOS script
elseif line1 = ~ '^#.*by RouterOS.*$'
2023-05-06 21:21:52 +01:00
setl ft = routeros
2022-02-13 20:32:02 +00:00
# Sed scripts
# #ncomment is allowed but most likely a false positive so require a space
# before any trailing comment text
elseif line1 = ~ '^#n\%($\|\s\)'
2023-05-06 21:21:52 +01:00
setl ft = sed
2022-02-13 20:32:02 +00:00
else
var lnum = 1
while getline ( lnum ) = ~ "^? " && lnum < line ( "$" )
lnum + = 1
endwhile
if getline ( lnum ) = ~ '^Index:\s\+\f\+$'
# CVS diff
2023-05-06 21:21:52 +01:00
setl ft = diff
2022-02-13 20:32:02 +00:00
# locale input files : 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_'
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
break
endif
lnum + = 1
endwhile
endif
endif
enddef