Improve file detection with signature check capabilities

This allows more complex detection upon regex rules for a certain amount of
lines.
This commit is contained in:
Jöran Karl 2023-05-04 23:48:42 +02:00
parent d8e9d61a95
commit 433879046e
37 changed files with 130 additions and 85 deletions

View File

@ -685,6 +685,16 @@ func (b *Buffer) UpdateRules() {
if ft == "off" { if ft == "off" {
return return
} }
// syntaxFileBuffer is a helper structure
// to store properties of one single syntax file
type syntaxFileBuffer struct {
header *highlight.Header
fileName string
syntaxDef *highlight.Def
}
syntaxFiles := []syntaxFileBuffer{}
syntaxFile := "" syntaxFile := ""
foundDef := false foundDef := false
var header *highlight.Header var header *highlight.Header
@ -707,16 +717,21 @@ func (b *Buffer) UpdateRules() {
continue continue
} }
if ((ft == "unknown" || ft == "") && highlight.MatchFiletype(header.FtDetect, b.Path, b.lines[0].data)) || header.FileType == ft { if ((ft == "unknown" || ft == "") && header.MatchFileName(b.Path)) || header.FileType == ft {
syndef, err := highlight.ParseDef(file, header) syndef, err := highlight.ParseDef(file, header)
if err != nil { if err != nil {
screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error())
continue continue
} }
b.SyntaxDef = syndef
syntaxFile = f.Name()
foundDef = true foundDef = true
break
if header.FileType == ft {
b.SyntaxDef = syndef
syntaxFile = f.Name()
break
} else {
syntaxFiles = append(syntaxFiles, syntaxFileBuffer{header, f.Name(), syndef})
}
} }
} }
@ -735,9 +750,8 @@ func (b *Buffer) UpdateRules() {
} }
if ft == "unknown" || ft == "" { if ft == "unknown" || ft == "" {
if highlight.MatchFiletype(header.FtDetect, b.Path, b.lines[0].data) { if header.MatchFileName(b.Path) {
syntaxFile = f.Name() syntaxFiles = append(syntaxFiles, syntaxFileBuffer{header, f.Name(), nil})
break
} }
} else if header.FileType == ft { } else if header.FileType == ft {
syntaxFile = f.Name() syntaxFile = f.Name()
@ -745,6 +759,32 @@ func (b *Buffer) UpdateRules() {
} }
} }
if syntaxFile == "" {
length := len(syntaxFiles)
if length > 0 {
signatureMatch := false
if length > 1 {
for i := 0; i < length && !signatureMatch; i++ {
if syntaxFiles[i].header.HasFileSignature() {
for j := 0; j < 100 && !signatureMatch; j++ {
if syntaxFiles[i].header.MatchFileSignature(b.lines[j].data) {
syntaxFile = syntaxFiles[i].fileName
b.SyntaxDef = syntaxFiles[i].syntaxDef
header = syntaxFiles[i].header
signatureMatch = true
}
}
}
}
}
if length == 1 || !signatureMatch {
syntaxFile = syntaxFiles[0].fileName
b.SyntaxDef = syntaxFiles[0].syntaxDef
header = syntaxFiles[0].header
}
}
}
if syntaxFile != "" && !foundDef { if syntaxFile != "" && !foundDef {
// we found a syntax file using a syntax header file // we found a syntax file using a syntax header file
for _, f := range config.ListRuntimeFiles(config.RTSyntax) { for _, f := range config.ListRuntimeFiles(config.RTSyntax) {

View File

@ -1,18 +0,0 @@
package highlight
import "regexp"
// MatchFiletype will use the list of syntax definitions provided and the filename and first line of the file
// to determine the filetype of the file
// It will return the corresponding syntax definition for the filetype
func MatchFiletype(ftdetect [2]*regexp.Regexp, filename string, firstLine []byte) bool {
if ftdetect[0] != nil && ftdetect[0].MatchString(filename) {
return true
}
if ftdetect[1] != nil {
return ftdetect[1].Match(firstLine)
}
return false
}

View File

@ -33,27 +33,26 @@ func (g Group) String() string {
// Then it has the rules which define how to highlight the file // Then it has the rules which define how to highlight the file
type Def struct { type Def struct {
*Header *Header
rules *rules rules *rules
} }
type Header struct { type Header struct {
FileType string FileType string
FtDetect [2]*regexp.Regexp FileNameRegex *regexp.Regexp
SignatureRegex *regexp.Regexp
} }
type HeaderYaml struct { type HeaderYaml struct {
FileType string `yaml:"filetype"` FileType string `yaml:"filetype"`
Detect struct { Detect struct {
FNameRgx string `yaml:"filename"` FNameRegexStr string `yaml:"filename"`
HeaderRgx string `yaml:"header"` SignatureRegexStr string `yaml:"signature"`
} `yaml:"detect"` } `yaml:"detect"`
} }
type File struct { type File struct {
FileType string FileType string
yamlSrc map[interface{}]interface{}
yamlSrc map[interface{}]interface{}
} }
// A Pattern is one simple syntax rule // A Pattern is one simple syntax rule
@ -103,14 +102,14 @@ func MakeHeader(data []byte) (*Header, error) {
header := new(Header) header := new(Header)
var err error var err error
header.FileType = string(lines[0]) header.FileType = string(lines[0])
fnameRgx := string(lines[1]) fnameRegexStr := string(lines[1])
headerRgx := string(lines[2]) signatureRegexStr := string(lines[2])
if fnameRgx != "" { if fnameRegexStr != "" {
header.FtDetect[0], err = regexp.Compile(fnameRgx) header.FileNameRegex, err = regexp.Compile(fnameRegexStr)
} }
if err == nil && headerRgx != "" { if err == nil && signatureRegexStr != "" {
header.FtDetect[1], err = regexp.Compile(headerRgx) header.SignatureRegex, err = regexp.Compile(signatureRegexStr)
} }
if err != nil { if err != nil {
@ -132,11 +131,11 @@ func MakeHeaderYaml(data []byte) (*Header, error) {
header := new(Header) header := new(Header)
header.FileType = hdrYaml.FileType header.FileType = hdrYaml.FileType
if hdrYaml.Detect.FNameRgx != "" { if hdrYaml.Detect.FNameRegexStr != "" {
header.FtDetect[0], err = regexp.Compile(hdrYaml.Detect.FNameRgx) header.FileNameRegex, err = regexp.Compile(hdrYaml.Detect.FNameRegexStr)
} }
if err == nil && hdrYaml.Detect.HeaderRgx != "" { if err == nil && hdrYaml.Detect.SignatureRegexStr != "" {
header.FtDetect[1], err = regexp.Compile(hdrYaml.Detect.HeaderRgx) header.SignatureRegex, err = regexp.Compile(hdrYaml.Detect.SignatureRegexStr)
} }
if err != nil { if err != nil {
@ -146,6 +145,29 @@ func MakeHeaderYaml(data []byte) (*Header, error) {
return header, nil return header, nil
} }
// MatchFileName will check the given file name with the stored regex
func (header *Header) MatchFileName(filename string) bool {
if header.FileNameRegex != nil {
return header.FileNameRegex.MatchString(filename)
}
return false
}
// HasFileSignature checks the presence of a stored signature
func (header *Header) HasFileSignature() bool {
return header.SignatureRegex != nil
}
// MatchFileSignature will check the given line with the stored regex
func (header *Header) MatchFileSignature(line []byte) bool {
if header.SignatureRegex != nil {
return header.SignatureRegex.Match(line)
}
return false
}
func ParseFile(input []byte) (f *File, err error) { func ParseFile(input []byte) (f *File, err error) {
// This is just so if we have an error, we can exit cleanly and return the parse error to the user // This is just so if we have an error, we can exit cleanly and return the parse error to the user
defer func() { defer func() {

View File

@ -267,13 +267,13 @@ detect:
``` ```
Micro will match this regex against a given filename to detect the filetype. Micro will match this regex against a given filename to detect the filetype.
You may also provide an optional `header` regex that will check the first line You may also provide an optional `signature` regex that will check a certain
of the file. For example: amount of lines of a file to find specific marks. For example:
``` ```
detect: detect:
filename: "\\.ya?ml$" filename: "\\.ya?ml$"
header: "%YAML" signature: "%YAML"
``` ```
### Syntax rules ### Syntax rules

View File

@ -5,7 +5,7 @@ filetype: powershell
detect: detect:
filename: "\\.ps(1|m1|d1)$" filename: "\\.ps(1|m1|d1)$"
#header: "" #signature: ""
rules: rules:
# - comment.block: # Block Comment # - comment.block: # Block Comment

View File

@ -2,7 +2,7 @@
Here are micro's syntax files. Here are micro's syntax files.
Each yaml file specifies how to detect the filetype based on file extension or headers (first line of the file). Each yaml file specifies how to detect the filetype based on file extension or given signature. The signature can be matched to a maximum of 100 lines (to limit parse times) for a best "guess".
Then there are patterns and regions linked to highlight groups which tell micro how to highlight that filetype. Then there are patterns and regions linked to highlight groups which tell micro how to highlight that filetype.
Making your own syntax files is very simple. I recommend you check the file after you are finished with the Making your own syntax files is very simple. I recommend you check the file after you are finished with the

View File

@ -2,7 +2,7 @@ filetype: awk
detect: detect:
filename: "\\.awk$" filename: "\\.awk$"
header: "^#!.*bin/(env +)?awk( |$)" signature: "^#!.*bin/(env +)?awk( |$)"
rules: rules:
- preproc: "\\$[A-Za-z0-9_!@#$*?\\-]+" - preproc: "\\$[A-Za-z0-9_!@#$*?\\-]+"

View File

@ -2,7 +2,7 @@ filetype: batch
detect: detect:
filename: "(\\.bat$|\\.cmd$)" filename: "(\\.bat$|\\.cmd$)"
# header: "" # signature: ""
rules: rules:
# Numbers # Numbers

View File

@ -2,7 +2,7 @@ filetype: crontab
detect: detect:
filename: "crontab$" filename: "crontab$"
header: "^#.*?/etc/crontab" signature: "^#.*?/etc/crontab"
rules: rules:
# The time and date fields are: # The time and date fields are:

View File

@ -1,7 +1,7 @@
filetype: csharp-script filetype: csharp-script
detect: detect:
filename: "\\.csx$" filename: "\\.csx$"
header: "^#!.*/(env +)?dotnet-script( |$)" signature: "^#!.*/(env +)?dotnet-script( |$)"
rules: rules:
- include: "csharp" - include: "csharp"

View File

@ -2,7 +2,7 @@ filetype: fish
detect: detect:
filename: "\\.fish$" filename: "\\.fish$"
header: "^#!.*/(env +)?fish( |$)" signature: "^#!.*/(env +)?fish( |$)"
rules: rules:
# Numbers # Numbers

View File

@ -5,7 +5,7 @@ filetype: godoc
detect: detect:
filename: "\\.godoc$" filename: "\\.godoc$"
header: package.*import signature: package.*import
rules: rules:
- preproc: "^[^ ].*" - preproc: "^[^ ].*"

View File

@ -2,7 +2,7 @@ filetype: groovy
detect: detect:
filename: "(\\.(groovy|gy|gvy|gsh|gradle)$|^[Jj]enkinsfile$)" filename: "(\\.(groovy|gy|gvy|gsh|gradle)$|^[Jj]enkinsfile$)"
header: "^#!.*/(env +)?groovy *$" signature: "^#!.*/(env +)?groovy *$"
rules: rules:
# And the style guide for constants is CONSTANT_CASE # And the style guide for constants is CONSTANT_CASE

View File

@ -2,7 +2,7 @@ filetype: html4
detect: detect:
filename: "\\.htm[l]?4$" filename: "\\.htm[l]?4$"
header: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN|http://www.w3.org/TR/html4/strict.dtd\">" signature: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN|http://www.w3.org/TR/html4/strict.dtd\">"
rules: rules:
- error: "<[^!].*?>" - error: "<[^!].*?>"

View File

@ -2,7 +2,7 @@ filetype: html5
detect: detect:
filename: "\\.htm[l]?5$" filename: "\\.htm[l]?5$"
header: "<!DOCTYPE html5>" signature: "<!DOCTYPE html5>"
rules: rules:
- error: "<[^!].*?>" - error: "<[^!].*?>"

View File

@ -2,7 +2,7 @@ filetype: javascript
detect: detect:
filename: "(\\.js$|\\.es[5678]?$|\\.mjs$)" filename: "(\\.js$|\\.es[5678]?$|\\.mjs$)"
header: "^#!.*/(env +)?node( |$)" signature: "^#!.*/(env +)?node( |$)"
rules: rules:
- constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b"

View File

@ -2,7 +2,7 @@ filetype: json
detect: detect:
filename: "\\.json$" filename: "\\.json$"
header: "^\\{$" signature: "^\\{$"
rules: rules:
- constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b"

View File

@ -2,7 +2,7 @@ filetype: julia
detect: detect:
filename: "\\.jl$" filename: "\\.jl$"
header: "^#!.*/(env +)?julia( |$)" signature: "^#!.*/(env +)?julia( |$)"
rules: rules:

View File

@ -3,7 +3,7 @@ filetype: 'justfile'
detect: detect:
filename: "(^\\.?[Jj]ustfile|\\.just)$" filename: "(^\\.?[Jj]ustfile|\\.just)$"
header: "^#!.*/(env +)?[bg]?just --justfile" signature: "^#!.*/(env +)?[bg]?just --justfile"
rules: rules:
- preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>" - preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>"

View File

@ -2,7 +2,7 @@ filetype: mail
detect: detect:
filename: "(.*/mutt-.*|\\.eml)$" filename: "(.*/mutt-.*|\\.eml)$"
header: "^From .* \\d+:\\d+:\\d+ \\d+" signature: "^From .* \\d+:\\d+:\\d+ \\d+"
rules: rules:
- type: "^From .*" - type: "^From .*"

View File

@ -1,4 +1,5 @@
//+build ignore //go:build ignore
// +build ignore
package main package main
@ -16,15 +17,15 @@ import (
type HeaderYaml struct { type HeaderYaml struct {
FileType string `yaml:"filetype"` FileType string `yaml:"filetype"`
Detect struct { Detect struct {
FNameRgx string `yaml:"filename"` FNameRgx string `yaml:"filename"`
HeaderRgx string `yaml:"header"` SignatureRgx string `yaml:"signature"`
} `yaml:"detect"` } `yaml:"detect"`
} }
type Header struct { type Header struct {
FileType string FileType string
FNameRgx string FNameRgx string
HeaderRgx string SignatureRgx string
} }
func main() { func main() {
@ -58,7 +59,7 @@ func encode(name string, c HeaderYaml) {
f, _ := os.Create(name + ".hdr") f, _ := os.Create(name + ".hdr")
f.WriteString(c.FileType + "\n") f.WriteString(c.FileType + "\n")
f.WriteString(c.Detect.FNameRgx + "\n") f.WriteString(c.Detect.FNameRgx + "\n")
f.WriteString(c.Detect.HeaderRgx + "\n") f.WriteString(c.Detect.SignatureRgx + "\n")
f.Close() f.Close()
} }
@ -69,7 +70,7 @@ func decode(name string) Header {
var hdr Header var hdr Header
hdr.FileType = string(strs[0]) hdr.FileType = string(strs[0])
hdr.FNameRgx = string(strs[1]) hdr.FNameRgx = string(strs[1])
hdr.HeaderRgx = string(strs[2]) hdr.SignatureRgx = string(strs[2])
fmt.Printf("took %v\n", time.Since(start)) fmt.Printf("took %v\n", time.Since(start))
return hdr return hdr

View File

@ -2,7 +2,7 @@ filetype: makefile
detect: detect:
filename: "([Mm]akefile|\\.ma?k)$" filename: "([Mm]akefile|\\.ma?k)$"
header: "^#!.*/(env +)?[bg]?make( |$)" signature: "^#!.*/(env +)?[bg]?make( |$)"
rules: rules:
- preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>" - preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>"

View File

@ -2,7 +2,7 @@ filetype: nginx
detect: detect:
filename: "nginx.*\\.conf$|\\.nginx$" filename: "nginx.*\\.conf$|\\.nginx$"
header: "^(server|upstream)[a-z ]*\\{$" signature: "^(server|upstream)[a-z ]*\\{$"
rules: rules:
- preproc: "\\b(events|server|http|location|upstream)[[:space:]]*\\{" - preproc: "\\b(events|server|http|location|upstream)[[:space:]]*\\{"

View File

@ -2,7 +2,7 @@ filetype: patch
detect: detect:
filename: "\\.(patch|diff)$" filename: "\\.(patch|diff)$"
header: "^diff" signature: "^diff"
rules: rules:
- brightgreen: "^\\+.*" - brightgreen: "^\\+.*"

View File

@ -2,7 +2,7 @@ filetype: perl
detect: detect:
filename: "\\.p[lmp]$" filename: "\\.p[lmp]$"
header: "^#!.*/(env +)?perl( |$)" signature: "^#!.*/(env +)?perl( |$)"
rules: rules:
- type: "\\b(accept|alarm|atan2|bin(d|mode)|c(aller|homp|h(dir|mod|op|own|root)|lose(dir)?|onnect|os|rypt)|d(bm(close|open)|efined|elete|ie|o|ump)|e(ach|of|val|x(ec|ists|it|p))|f(cntl|ileno|lock|ork))\\b|\\b(get(c|login|peername|pgrp|ppid|priority|pwnam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport)|([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|gmtime|goto|grep|hex|index|int|ioctl|join)\\b|\\b(keys|kill|last|length|link|listen|local(time)?|log|lstat|m|mkdir|msg(ctl|get|snd|rcv)|next|oct|open(dir)?|ord|pack|pipe|pop|printf?|push|q|qq|qx|rand|re(ad(dir|link)?|cv|say|do|name|quire|set|turn|verse|winddir)|rindex|rmdir|s|scalar|seek(dir)?)\\b|\\b(se(lect|mctl|mget|mop|nd|tpgrp|tpriority|tsockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|spli(ce|t)|sprintf|sqrt|srand|stat|study|substr|symlink|sys(call|read|tem|write)|tell(dir)?|time|tr(y)?|truncate|umask)\\b|\\b(un(def|link|pack|shift)|utime|values|vec|wait(pid)?|wantarray|warn|write)\\b" - type: "\\b(accept|alarm|atan2|bin(d|mode)|c(aller|homp|h(dir|mod|op|own|root)|lose(dir)?|onnect|os|rypt)|d(bm(close|open)|efined|elete|ie|o|ump)|e(ach|of|val|x(ec|ists|it|p))|f(cntl|ileno|lock|ork))\\b|\\b(get(c|login|peername|pgrp|ppid|priority|pwnam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport)|([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|gmtime|goto|grep|hex|index|int|ioctl|join)\\b|\\b(keys|kill|last|length|link|listen|local(time)?|log|lstat|m|mkdir|msg(ctl|get|snd|rcv)|next|oct|open(dir)?|ord|pack|pipe|pop|printf?|push|q|qq|qx|rand|re(ad(dir|link)?|cv|say|do|name|quire|set|turn|verse|winddir)|rindex|rmdir|s|scalar|seek(dir)?)\\b|\\b(se(lect|mctl|mget|mop|nd|tpgrp|tpriority|tsockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|spli(ce|t)|sprintf|sqrt|srand|stat|study|substr|symlink|sys(call|read|tem|write)|tell(dir)?|time|tr(y)?|truncate|umask)\\b|\\b(un(def|link|pack|shift)|utime|values|vec|wait(pid)?|wantarray|warn|write)\\b"

View File

@ -2,7 +2,7 @@ filetype: python2
detect: detect:
filename: "\\.py2$" filename: "\\.py2$"
header: "^#!.*/(env +)?python2$" signature: "^#!.*/(env +)?python2$"
rules: rules:

View File

@ -2,7 +2,7 @@ filetype: python
detect: detect:
filename: "\\.py(3)?$" filename: "\\.py(3)?$"
header: "^#!.*/(env +)?python(3)?$" signature: "^#!.*/(env +)?python(3)?$"
rules: rules:
# built-in objects # built-in objects

View File

@ -2,7 +2,7 @@ filetype: ruby
detect: detect:
filename: "\\.(rb|rake|gemspec)$|^(.*[\\/])?(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile|Appfile|Fastfile|Pluginfile|Podfile|\\.?[Bb]rewfile)$" filename: "\\.(rb|rake|gemspec)$|^(.*[\\/])?(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile|Appfile|Fastfile|Pluginfile|Podfile|\\.?[Bb]rewfile)$"
header: "^#!.*/(env +)?ruby( |$)" signature: "^#!.*/(env +)?ruby( |$)"
rules: rules:
- comment.bright: - comment.bright:

View File

@ -2,7 +2,7 @@ filetype: sage
detect: detect:
filename: "\\.sage$" filename: "\\.sage$"
header: "^#!.*/(env +)?sage( |$)" signature: "^#!.*/(env +)?sage( |$)"
rules: rules:

View File

@ -2,7 +2,7 @@ filetype: sed
detect: detect:
filename: "\\.sed$" filename: "\\.sed$"
header: "^#!.*bin/(env +)?sed( |$)" signature: "^#!.*bin/(env +)?sed( |$)"
rules: rules:
- symbol.operator: "[|^$.*+]" - symbol.operator: "[|^$.*+]"

View File

@ -24,7 +24,7 @@ filetype: shell
# * bash-fc. (followed by a random string) # * bash-fc. (followed by a random string)
detect: detect:
filename: "(\\.(sh|bash|ash|ebuild)$|(\\.bash(rc|_aliases|_functions|_profile)|\\.?profile|Pkgfile|pkgmk\\.conf|rc\\.conf|PKGBUILD|APKBUILD)$|bash-fc\\.)" filename: "(\\.(sh|bash|ash|ebuild)$|(\\.bash(rc|_aliases|_functions|_profile)|\\.?profile|Pkgfile|pkgmk\\.conf|rc\\.conf|PKGBUILD|APKBUILD)$|bash-fc\\.)"
header: "^#!.*/(env +)?(ba)?(a)?(mk)?sh( |$)" signature: "^#!.*/(env +)?(ba)?(a)?(mk)?sh( |$)"
rules: rules:
# Numbers # Numbers

View File

@ -137,7 +137,7 @@ func generateFile(filetype, syntax, header string, rules []interface{}) string {
output += fmt.Sprintf("detect: \n filename: \"%s\"\n", strings.Replace(strings.Replace(syntax, "\\", "\\\\", -1), "\"", "\\\"", -1)) output += fmt.Sprintf("detect: \n filename: \"%s\"\n", strings.Replace(strings.Replace(syntax, "\\", "\\\\", -1), "\"", "\\\"", -1))
if header != "" { if header != "" {
output += fmt.Sprintf(" header: \"%s\"\n", strings.Replace(strings.Replace(header, "\\", "\\\\", -1), "\"", "\\\"", -1)) output += fmt.Sprintf(" signature: \"%s\"\n", strings.Replace(strings.Replace(header, "\\", "\\\\", -1), "\"", "\\\"", -1))
} }
output += "\nrules:\n" output += "\nrules:\n"

View File

@ -2,7 +2,7 @@ filetype: systemd
detect: detect:
filename: "\\.(service|socket|timer)$" filename: "\\.(service|socket|timer)$"
header: "^\\[Unit\\]$" signature: "^\\[Unit\\]$"
rules: rules:
- statement: "^(Accept|After|Alias|AllowIsolate|Also|ANSI_COLOR|_AUDIT_LOGINUID|_AUDIT_SESSION|Backlog|Before|BindIPv6Only|BindsTo|BindToDevice|BlockIOReadBandwidth|BlockIOWeight|BlockIOWriteBandwidth|_BOOT_ID|Broadcast|BUG_REPORT_URL|BusName|Capabilities|CapabilityBoundingSet|CHASSIS|cipher|class|_CMDLINE|CODE_FILE|CODE_FUNC|CODE_LINE|_COMM|Compress|ConditionACPower|ConditionCapability|ConditionDirectoryNotEmpty|ConditionFileIsExecutable|ConditionFileNotEmpty|ConditionHost|ConditionKernelCommandLine|ConditionNull|ConditionPathExists|ConditionPathExistsGlob|ConditionPathIsDirectory|ConditionPathIsMountPoint|ConditionPathIsReadWrite|ConditionPathIsSymbolicLink|ConditionSecurity|ConditionVirtualization|Conflicts|ControlGroup|ControlGroupAttribute|ControlGroupModify|ControlGroupPersistent|controllers|Controllers|CPE_NAME|CPUAffinity|CPUSchedulingPolicy|CPUSchedulingPriority|CPUSchedulingResetOnFork|CPUShares|CrashChVT|CrashShell|__CURSOR|debug|DefaultControllers|DefaultDependencies|DefaultLimitAS|DefaultLimitCORE|DefaultLimitCPU|DefaultLimitDATA|DefaultLimitFSIZE|DefaultLimitLOCKS|DefaultLimitMEMLOCK|DefaultLimitMSGQUEUE|DefaultLimitNICE|DefaultLimitNOFILE|DefaultLimitNPROC|DefaultLimitRSS|DefaultLimitRTPRIO|DefaultLimitRTTIME|DefaultLimitSIGPENDING|DefaultLimitSTACK|DefaultStandardError|DefaultStandardOutput|Description|DeviceAllow|DeviceDeny|DirectoryMode|DirectoryNotEmpty|Documentation|DumpCore|entropy|Environment|EnvironmentFile|ERRNO|event_timeout|_EXE|ExecReload|ExecStart|ExecStartPost|ExecStartPre|ExecStop|ExecStopPost|ExecStopPre|filter|FONT|FONT_MAP|FONT_UNIMAP|ForwardToConsole|ForwardToKMsg|ForwardToSyslog|FreeBind|freq|FsckPassNo|fstab|_GID|Group|GuessMainPID|HandleHibernateKey|HandleLidSwitch|HandlePowerKey|HandleSuspendKey|hash|HibernateKeyIgnoreInhibited|HOME_URL|_HOSTNAME|ICON_NAME|ID|IdleAction|IdleActionSec|ID_LIKE|ID_MODEL|ID_MODEL_FROM_DATABASE|IgnoreOnIsolate|IgnoreOnSnapshot|IgnoreSIGPIPE|InaccessibleDirectories|InhibitDelayMaxSec|init|IOSchedulingClass|IOSchedulingPriority|IPTOS|IPTTL|JobTimeoutSec|JoinControllers|KeepAlive|KEYMAP|KEYMAP_TOGGLE|KillExcludeUsers|KillMode|KillOnlyUsers|KillSignal|KillUserProcesses|LidSwitchIgnoreInhibited|LimitAS|LimitCORE|LimitCPU|LimitDATA|LimitFSIZE|LimitLOCKS|LimitMEMLOCK|LimitMSGQUEUE|LimitNICE|LimitNOFILE|LimitNPROC|LimitRSS|LimitRTPRIO|LimitRTTIME|LimitSIGPENDING|LimitSTACK|link_priority|valueListenDatagram|ListenFIFO|ListenMessageQueue|ListenNetlink|ListenSequentialPacket|ListenSpecial|ListenStream|LogColor|LogLevel|LogLocation|LogTarget|luks|_MACHINE_ID|MakeDirectory|Mark|MaxConnections|MaxFileSec|MaxLevelConsole|MaxLevelKMsg|MaxLevelStore|MaxLevelSyslog|MaxRetentionSec|MemoryLimit|MemorySoftLimit|MESSAGE|MESSAGE_ID|MessageQueueMaxMessages|MessageQueueMessageSize|__MONOTONIC_TIMESTAMP|MountFlags|NAME|NAutoVTs|Nice|NonBlocking|NoNewPrivileges|NotifyAccess|OnActiveSec|OnBootSec|OnCalendar|OnFailure|OnFailureIsolate|OnStartupSec|OnUnitActiveSec|OnUnitInactiveSec|OOMScoreAdjust|Options|output|PAMName|PartOf|PassCredentials|PassSecurity|PathChanged|PathExists|PathExistsGlob|PathModified|PermissionsStartOnly|_PID|PIDFile|PipeSize|PowerKeyIgnoreInhibited|PRETTY_HOSTNAME|PRETTY_NAME|Priority|PRIORITY|PrivateNetwork|PrivateTmp|PropagatesReloadTo|pss|RateLimitBurst|RateLimitInterval|ReadOnlyDirectories|ReadWriteDirectories|__REALTIME_TIMESTAMP|ReceiveBuffer|RefuseManualStart|RefuseManualStop|rel|ReloadPropagatedFrom|RemainAfterExit|RequiredBy|Requires|RequiresMountsFor|RequiresOverridable|Requisite|RequisiteOverridable|ReserveVT|ResetControllers|Restart|RestartPreventExitStatus|RestartSec|RootDirectory|RootDirectoryStartOnly|RuntimeKeepFree|RuntimeMaxFileSize|RuntimeMaxUse|RuntimeWatchdogSec|samples|scale_x|scale_y|Seal|SecureBits|_SELINUX_CONTEXT|SendBuffer|SendSIGKILL|Service|ShowStatus|ShutdownWatchdogSec|size|SmackLabel|SmackLabelIPIn|SmackLabelIPOut|SocketMode|Sockets|SourcePath|_SOURCE_REALTIME_TIMESTAMP|SplitMode|StandardError|StandardInput|StandardOutput|StartLimitAction|StartLimitBurst|StartLimitInterval|static_node|StopWhenUnneeded|Storage|string_escape|none|replaceSuccessExitStatus|SupplementaryGroups|SUPPORT_URL|SuspendKeyIgnoreInhibited|SyslogFacility|SYSLOG_FACILITY|SyslogIdentifier|SYSLOG_IDENTIFIER|SyslogLevel|SyslogLevelPrefix|SYSLOG_PID|SystemCallFilter|SYSTEMD_ALIAS|_SYSTEMD_CGROUP|_SYSTEMD_OWNER_UID|SYSTEMD_READY|_SYSTEMD_SESSION|_SYSTEMD_UNIT|_SYSTEMD_USER_UNIT|SYSTEMD_WANTS|SystemKeepFree|SystemMaxFileSize|SystemMaxUse|SysVStartPriority|TCPCongestion|TCPWrapName|timeout|TimeoutSec|TimeoutStartSec|TimeoutStopSec|TimerSlackNSec|Transparent|_TRANSPORT|tries|TTYPath|TTYReset|TTYVHangup|TTYVTDisallocate|Type|_UID|UMask|Unit|User|UtmpIdentifier|VERSION|VERSION_ID|WantedBy|Wants|WatchdogSec|What|Where|WorkingDirectory)=" - statement: "^(Accept|After|Alias|AllowIsolate|Also|ANSI_COLOR|_AUDIT_LOGINUID|_AUDIT_SESSION|Backlog|Before|BindIPv6Only|BindsTo|BindToDevice|BlockIOReadBandwidth|BlockIOWeight|BlockIOWriteBandwidth|_BOOT_ID|Broadcast|BUG_REPORT_URL|BusName|Capabilities|CapabilityBoundingSet|CHASSIS|cipher|class|_CMDLINE|CODE_FILE|CODE_FUNC|CODE_LINE|_COMM|Compress|ConditionACPower|ConditionCapability|ConditionDirectoryNotEmpty|ConditionFileIsExecutable|ConditionFileNotEmpty|ConditionHost|ConditionKernelCommandLine|ConditionNull|ConditionPathExists|ConditionPathExistsGlob|ConditionPathIsDirectory|ConditionPathIsMountPoint|ConditionPathIsReadWrite|ConditionPathIsSymbolicLink|ConditionSecurity|ConditionVirtualization|Conflicts|ControlGroup|ControlGroupAttribute|ControlGroupModify|ControlGroupPersistent|controllers|Controllers|CPE_NAME|CPUAffinity|CPUSchedulingPolicy|CPUSchedulingPriority|CPUSchedulingResetOnFork|CPUShares|CrashChVT|CrashShell|__CURSOR|debug|DefaultControllers|DefaultDependencies|DefaultLimitAS|DefaultLimitCORE|DefaultLimitCPU|DefaultLimitDATA|DefaultLimitFSIZE|DefaultLimitLOCKS|DefaultLimitMEMLOCK|DefaultLimitMSGQUEUE|DefaultLimitNICE|DefaultLimitNOFILE|DefaultLimitNPROC|DefaultLimitRSS|DefaultLimitRTPRIO|DefaultLimitRTTIME|DefaultLimitSIGPENDING|DefaultLimitSTACK|DefaultStandardError|DefaultStandardOutput|Description|DeviceAllow|DeviceDeny|DirectoryMode|DirectoryNotEmpty|Documentation|DumpCore|entropy|Environment|EnvironmentFile|ERRNO|event_timeout|_EXE|ExecReload|ExecStart|ExecStartPost|ExecStartPre|ExecStop|ExecStopPost|ExecStopPre|filter|FONT|FONT_MAP|FONT_UNIMAP|ForwardToConsole|ForwardToKMsg|ForwardToSyslog|FreeBind|freq|FsckPassNo|fstab|_GID|Group|GuessMainPID|HandleHibernateKey|HandleLidSwitch|HandlePowerKey|HandleSuspendKey|hash|HibernateKeyIgnoreInhibited|HOME_URL|_HOSTNAME|ICON_NAME|ID|IdleAction|IdleActionSec|ID_LIKE|ID_MODEL|ID_MODEL_FROM_DATABASE|IgnoreOnIsolate|IgnoreOnSnapshot|IgnoreSIGPIPE|InaccessibleDirectories|InhibitDelayMaxSec|init|IOSchedulingClass|IOSchedulingPriority|IPTOS|IPTTL|JobTimeoutSec|JoinControllers|KeepAlive|KEYMAP|KEYMAP_TOGGLE|KillExcludeUsers|KillMode|KillOnlyUsers|KillSignal|KillUserProcesses|LidSwitchIgnoreInhibited|LimitAS|LimitCORE|LimitCPU|LimitDATA|LimitFSIZE|LimitLOCKS|LimitMEMLOCK|LimitMSGQUEUE|LimitNICE|LimitNOFILE|LimitNPROC|LimitRSS|LimitRTPRIO|LimitRTTIME|LimitSIGPENDING|LimitSTACK|link_priority|valueListenDatagram|ListenFIFO|ListenMessageQueue|ListenNetlink|ListenSequentialPacket|ListenSpecial|ListenStream|LogColor|LogLevel|LogLocation|LogTarget|luks|_MACHINE_ID|MakeDirectory|Mark|MaxConnections|MaxFileSec|MaxLevelConsole|MaxLevelKMsg|MaxLevelStore|MaxLevelSyslog|MaxRetentionSec|MemoryLimit|MemorySoftLimit|MESSAGE|MESSAGE_ID|MessageQueueMaxMessages|MessageQueueMessageSize|__MONOTONIC_TIMESTAMP|MountFlags|NAME|NAutoVTs|Nice|NonBlocking|NoNewPrivileges|NotifyAccess|OnActiveSec|OnBootSec|OnCalendar|OnFailure|OnFailureIsolate|OnStartupSec|OnUnitActiveSec|OnUnitInactiveSec|OOMScoreAdjust|Options|output|PAMName|PartOf|PassCredentials|PassSecurity|PathChanged|PathExists|PathExistsGlob|PathModified|PermissionsStartOnly|_PID|PIDFile|PipeSize|PowerKeyIgnoreInhibited|PRETTY_HOSTNAME|PRETTY_NAME|Priority|PRIORITY|PrivateNetwork|PrivateTmp|PropagatesReloadTo|pss|RateLimitBurst|RateLimitInterval|ReadOnlyDirectories|ReadWriteDirectories|__REALTIME_TIMESTAMP|ReceiveBuffer|RefuseManualStart|RefuseManualStop|rel|ReloadPropagatedFrom|RemainAfterExit|RequiredBy|Requires|RequiresMountsFor|RequiresOverridable|Requisite|RequisiteOverridable|ReserveVT|ResetControllers|Restart|RestartPreventExitStatus|RestartSec|RootDirectory|RootDirectoryStartOnly|RuntimeKeepFree|RuntimeMaxFileSize|RuntimeMaxUse|RuntimeWatchdogSec|samples|scale_x|scale_y|Seal|SecureBits|_SELINUX_CONTEXT|SendBuffer|SendSIGKILL|Service|ShowStatus|ShutdownWatchdogSec|size|SmackLabel|SmackLabelIPIn|SmackLabelIPOut|SocketMode|Sockets|SourcePath|_SOURCE_REALTIME_TIMESTAMP|SplitMode|StandardError|StandardInput|StandardOutput|StartLimitAction|StartLimitBurst|StartLimitInterval|static_node|StopWhenUnneeded|Storage|string_escape|none|replaceSuccessExitStatus|SupplementaryGroups|SUPPORT_URL|SuspendKeyIgnoreInhibited|SyslogFacility|SYSLOG_FACILITY|SyslogIdentifier|SYSLOG_IDENTIFIER|SyslogLevel|SyslogLevelPrefix|SYSLOG_PID|SystemCallFilter|SYSTEMD_ALIAS|_SYSTEMD_CGROUP|_SYSTEMD_OWNER_UID|SYSTEMD_READY|_SYSTEMD_SESSION|_SYSTEMD_UNIT|_SYSTEMD_USER_UNIT|SYSTEMD_WANTS|SystemKeepFree|SystemMaxFileSize|SystemMaxUse|SysVStartPriority|TCPCongestion|TCPWrapName|timeout|TimeoutSec|TimeoutStartSec|TimeoutStopSec|TimerSlackNSec|Transparent|_TRANSPORT|tries|TTYPath|TTYReset|TTYVHangup|TTYVTDisallocate|Type|_UID|UMask|Unit|User|UtmpIdentifier|VERSION|VERSION_ID|WantedBy|Wants|WatchdogSec|What|Where|WorkingDirectory)="

View File

@ -2,7 +2,7 @@ filetype: tcl
detect: detect:
filename: "\\.tcl$" filename: "\\.tcl$"
header: "^#!.*/(env +)?tclsh( |$)" signature: "^#!.*/(env +)?tclsh( |$)"
rules: rules:
- statement: "\\b(after|append|array|auto_execok|auto_import|auto_load|auto_load_index|auto_qualify|binary|break|case|catch|cd|clock|close|concat|continue|else|elseif|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|file|fileevent|flush|for|foreach|format|gets|glob|global|history|if|incr|info|interp|join|lappend|lindex|linsert|list|llength|load|lrange|lreplace|lsearch|lset|lsort|namespace|open|package|pid|puts|pwd|read|regexp|regsub|rename|return|scan|seek|set|socket|source|split|string|subst|switch|tclLog|tell|time|trace|unknown|unset|update|uplevel|upvar|variable|vwait|while)\\b" - statement: "\\b(after|append|array|auto_execok|auto_import|auto_load|auto_load_index|auto_qualify|binary|break|case|catch|cd|clock|close|concat|continue|else|elseif|encoding|eof|error|eval|exec|exit|expr|fblocked|fconfigure|fcopy|file|fileevent|flush|for|foreach|format|gets|glob|global|history|if|incr|info|interp|join|lappend|lindex|linsert|list|llength|load|lrange|lreplace|lsearch|lset|lsort|namespace|open|package|pid|puts|pwd|read|regexp|regsub|rename|return|scan|seek|set|socket|source|split|string|subst|switch|tclLog|tell|time|trace|unknown|unset|update|uplevel|upvar|variable|vwait|while)\\b"

View File

@ -2,7 +2,7 @@ filetype: xml
detect: detect:
filename: "\\.(xml|sgml?|rng|svg|plist)$" filename: "\\.(xml|sgml?|rng|svg|plist)$"
header: "<\\?xml.*\\?>" signature: "<\\?xml.*\\?>"
rules: rules:
- preproc: - preproc:

View File

@ -2,7 +2,7 @@ filetype: yaml
detect: detect:
filename: "\\.ya?ml$" filename: "\\.ya?ml$"
header: "%YAML" signature: "%YAML"
rules: rules:
- type: "(^| )!!(binary|bool|float|int|map|null|omap|seq|set|str) " - type: "(^| )!!(binary|bool|float|int|map|null|omap|seq|set|str) "

View File

@ -2,7 +2,7 @@ filetype: zsh
detect: detect:
filename: "(\\.zsh$|\\.?(zshenv|zprofile|zshrc|zlogin|zlogout)$)" filename: "(\\.zsh$|\\.?(zshenv|zprofile|zshrc|zlogin|zlogout)$)"
header: "^#!.*/(env +)?zsh( |$)" signature: "^#!.*/(env +)?zsh( |$)"
rules: rules:
## Numbers ## Numbers