From 13483602d56f984c043a722f3dcab6c24b80b6fd Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 17:49:09 +0100 Subject: [PATCH 01/12] UpdateRules: fix foundDef logic The original meaning of foundDef was: "we already found the final syntax definition in a user's custom syntax file". After introducing signatures its meaning became: "we found some potential syntax definition in a user's custom syntax file, but we don't know yet if it's the final one". This makes the code confusing and actually buggy. At least one bug is that if we found some potential filename matches in the user's custom syntax files, we don't search for more matches in the built-in syntax files. Which is wrong: we should keep searching for as many potential matches as possible, in both user's and built-in syntax files, to select the best one among them. Fix that by restoring the original meaning of foundDef and updating the logic accordingly. --- internal/buffer/buffer.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 8720aa47..0ba7aa62 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -730,11 +730,11 @@ func (b *Buffer) UpdateRules() { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) continue } - foundDef = true if header.FileType == ft { b.SyntaxDef = syndef syntaxFile = f.Name() + foundDef = true break } else { syntaxFiles = append(syntaxFiles, syntaxFileBuffer{header, f.Name(), syndef}) @@ -784,7 +784,10 @@ func (b *Buffer) UpdateRules() { for j := 0; j < limit && !signatureMatch; j++ { if syntaxFiles[i].header.MatchFileSignature(b.lines[j].data) { syntaxFile = syntaxFiles[i].fileName - b.SyntaxDef = syntaxFiles[i].syntaxDef + if syntaxFiles[i].syntaxDef != nil { + b.SyntaxDef = syntaxFiles[i].syntaxDef + foundDef = true + } header = syntaxFiles[i].header signatureMatch = true } @@ -794,7 +797,10 @@ func (b *Buffer) UpdateRules() { } if length == 1 || !signatureMatch { syntaxFile = syntaxFiles[0].fileName - b.SyntaxDef = syntaxFiles[0].syntaxDef + if syntaxFiles[0].syntaxDef != nil { + b.SyntaxDef = syntaxFiles[0].syntaxDef + foundDef = true + } header = syntaxFiles[0].header } } From 0c923aa156d9bd2aefba8b6e6e04f15d970ec725 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 18:29:03 +0100 Subject: [PATCH 02/12] UpdateRules: don't call highlight.ParseFile() needlessly No need to parse a syntax YAML file if we are not going to use it, it's a waste of CPU cycles. --- internal/buffer/buffer.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 0ba7aa62..178cd5c8 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -718,13 +718,14 @@ func (b *Buffer) UpdateRules() { screen.TermMessage("Error parsing header for syntax file " + f.Name() + ": " + err.Error()) continue } - file, err := highlight.ParseFile(data) - if err != nil { - screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) - continue - } if ((ft == "unknown" || ft == "") && header.MatchFileName(b.Path)) || header.FileType == ft { + file, err := highlight.ParseFile(data) + if err != nil { + screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) + continue + } + syndef, err := highlight.ParseDef(file, header) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) From 2b8d925925ce1fe06fd52160425108e1539c6ec2 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 18:37:55 +0100 Subject: [PATCH 03/12] UpdateRules: rename syntaxFiles to fnameMatches As a preparation for reintroducing header matches. --- internal/buffer/buffer.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 178cd5c8..228af183 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -701,7 +701,7 @@ func (b *Buffer) UpdateRules() { syntaxDef *highlight.Def } - syntaxFiles := []syntaxFileBuffer{} + fnameMatches := []syntaxFileBuffer{} syntaxFile := "" foundDef := false var header *highlight.Header @@ -738,7 +738,7 @@ func (b *Buffer) UpdateRules() { foundDef = true break } else { - syntaxFiles = append(syntaxFiles, syntaxFileBuffer{header, f.Name(), syndef}) + fnameMatches = append(fnameMatches, syntaxFileBuffer{header, f.Name(), syndef}) } } } @@ -760,7 +760,7 @@ func (b *Buffer) UpdateRules() { if ft == "unknown" || ft == "" { if header.MatchFileName(b.Path) { - syntaxFiles = append(syntaxFiles, syntaxFileBuffer{header, f.Name(), nil}) + fnameMatches = append(fnameMatches, syntaxFileBuffer{header, f.Name(), nil}) } } else if header.FileType == ft { syntaxFile = f.Name() @@ -770,7 +770,7 @@ func (b *Buffer) UpdateRules() { } if syntaxFile == "" { - length := len(syntaxFiles) + length := len(fnameMatches) if length > 0 { signatureMatch := false if length > 1 { @@ -781,15 +781,15 @@ func (b *Buffer) UpdateRules() { limit = detectlimit } for i := 0; i < length && !signatureMatch; i++ { - if syntaxFiles[i].header.HasFileSignature() { + if fnameMatches[i].header.HasFileSignature() { for j := 0; j < limit && !signatureMatch; j++ { - if syntaxFiles[i].header.MatchFileSignature(b.lines[j].data) { - syntaxFile = syntaxFiles[i].fileName - if syntaxFiles[i].syntaxDef != nil { - b.SyntaxDef = syntaxFiles[i].syntaxDef + if fnameMatches[i].header.MatchFileSignature(b.lines[j].data) { + syntaxFile = fnameMatches[i].fileName + if fnameMatches[i].syntaxDef != nil { + b.SyntaxDef = fnameMatches[i].syntaxDef foundDef = true } - header = syntaxFiles[i].header + header = fnameMatches[i].header signatureMatch = true } } @@ -797,12 +797,12 @@ func (b *Buffer) UpdateRules() { } } if length == 1 || !signatureMatch { - syntaxFile = syntaxFiles[0].fileName - if syntaxFiles[0].syntaxDef != nil { - b.SyntaxDef = syntaxFiles[0].syntaxDef + syntaxFile = fnameMatches[0].fileName + if fnameMatches[0].syntaxDef != nil { + b.SyntaxDef = fnameMatches[0].syntaxDef foundDef = true } - header = syntaxFiles[0].header + header = fnameMatches[0].header } } } From 3f4942cedb5c2b95b44b0501bfe55dcfda5855f2 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 18:26:22 +0100 Subject: [PATCH 04/12] syntax parser: reintroduce header regex in .hdr files Replacing header patterns with signature patterns was a mistake, since both have their own uses. So restore support for header regex, while keeping support for signature regex as well. --- pkg/highlight/parser.go | 21 +++++++++++++++++++-- runtime/syntax/make_headers.go | 6 +++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/pkg/highlight/parser.go b/pkg/highlight/parser.go index 92e290fe..c7f57b69 100644 --- a/pkg/highlight/parser.go +++ b/pkg/highlight/parser.go @@ -39,6 +39,7 @@ type Def struct { type Header struct { FileType string FileNameRegex *regexp.Regexp + HeaderRegex *regexp.Regexp SignatureRegex *regexp.Regexp } @@ -46,6 +47,7 @@ type HeaderYaml struct { FileType string `yaml:"filetype"` Detect struct { FNameRegexStr string `yaml:"filename"` + HeaderRegexStr string `yaml:"header"` SignatureRegexStr string `yaml:"signature"` } `yaml:"detect"` } @@ -96,18 +98,22 @@ func init() { // A yaml file might take ~400us to parse while a header file only takes ~20us func MakeHeader(data []byte) (*Header, error) { lines := bytes.Split(data, []byte{'\n'}) - if len(lines) < 3 { + if len(lines) < 4 { return nil, errors.New("Header file has incorrect format") } header := new(Header) var err error header.FileType = string(lines[0]) fnameRegexStr := string(lines[1]) - signatureRegexStr := string(lines[2]) + headerRegexStr := string(lines[2]) + signatureRegexStr := string(lines[3]) if fnameRegexStr != "" { header.FileNameRegex, err = regexp.Compile(fnameRegexStr) } + if err == nil && headerRegexStr != "" { + header.HeaderRegex, err = regexp.Compile(headerRegexStr) + } if err == nil && signatureRegexStr != "" { header.SignatureRegex, err = regexp.Compile(signatureRegexStr) } @@ -134,6 +140,9 @@ func MakeHeaderYaml(data []byte) (*Header, error) { if hdrYaml.Detect.FNameRegexStr != "" { header.FileNameRegex, err = regexp.Compile(hdrYaml.Detect.FNameRegexStr) } + if err == nil && hdrYaml.Detect.HeaderRegexStr != "" { + header.HeaderRegex, err = regexp.Compile(hdrYaml.Detect.HeaderRegexStr) + } if err == nil && hdrYaml.Detect.SignatureRegexStr != "" { header.SignatureRegex, err = regexp.Compile(hdrYaml.Detect.SignatureRegexStr) } @@ -154,6 +163,14 @@ func (header *Header) MatchFileName(filename string) bool { return false } +func (header *Header) MatchFileHeader(firstLine []byte) bool { + if header.HeaderRegex != nil { + return header.HeaderRegex.Match(firstLine) + } + + return false +} + // HasFileSignature checks the presence of a stored signature func (header *Header) HasFileSignature() bool { return header.SignatureRegex != nil diff --git a/runtime/syntax/make_headers.go b/runtime/syntax/make_headers.go index c80c680e..c00c27da 100644 --- a/runtime/syntax/make_headers.go +++ b/runtime/syntax/make_headers.go @@ -18,6 +18,7 @@ type HeaderYaml struct { FileType string `yaml:"filetype"` Detect struct { FNameRgx string `yaml:"filename"` + HeaderRgx string `yaml:"header"` SignatureRgx string `yaml:"signature"` } `yaml:"detect"` } @@ -25,6 +26,7 @@ type HeaderYaml struct { type Header struct { FileType string FNameRgx string + HeaderRgx string SignatureRgx string } @@ -59,6 +61,7 @@ func encode(name string, c HeaderYaml) { f, _ := os.Create(name + ".hdr") f.WriteString(c.FileType + "\n") f.WriteString(c.Detect.FNameRgx + "\n") + f.WriteString(c.Detect.HeaderRgx + "\n") f.WriteString(c.Detect.SignatureRgx + "\n") f.Close() } @@ -70,7 +73,8 @@ func decode(name string) Header { var hdr Header hdr.FileType = string(strs[0]) hdr.FNameRgx = string(strs[1]) - hdr.SignatureRgx = string(strs[2]) + hdr.HeaderRgx = string(strs[2]) + hdr.SignatureRgx = string(strs[3]) fmt.Printf("took %v\n", time.Since(start)) return hdr From 39e410aa46c73a51707b4c8cdd8b5bb702665d6d Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 21:24:44 +0100 Subject: [PATCH 05/12] UpdateRules: reintroduce using header regex for filetype detection Replacing header patterns with signature patterns was a mistake, since both are quite different from each other, and both have their uses. In fact, this caused a serious regression: for such files as shell scripts without *.sh extension but with #!/bin/sh inside, filetype detection does not work at all anymore. Since both header and signature patterns are useful, reintroduce support for header patterns while keeping support for signature patterns as well and make both work nicely together. Also, unlike in the old implementation (before signatures were introduced), ensure that filename matches take precedence over header matches, i.e. if there is at least one filename match found, all header matches are ignored. This makes the behavior more deterministic and prevents previously observed issues like #2894 and #3054: wrongly detected filetypes caused by some overly general header patterns. Precisely, the new behavior is: 1. if there is at least one filename match, use filename matches only 2. if there are no filename matches, use header matches 3. in both cases, try to use signatures to find the best match among multiple filename or header matches --- internal/buffer/buffer.go | 51 +++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 228af183..0f21f188 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -702,6 +702,7 @@ func (b *Buffer) UpdateRules() { } fnameMatches := []syntaxFileBuffer{} + headerMatches := []syntaxFileBuffer{} syntaxFile := "" foundDef := false var header *highlight.Header @@ -719,7 +720,19 @@ func (b *Buffer) UpdateRules() { continue } - if ((ft == "unknown" || ft == "") && header.MatchFileName(b.Path)) || header.FileType == ft { + matchedFileName := false + matchedFileHeader := false + + if ft == "unknown" || ft == "" { + if header.MatchFileName(b.Path) { + matchedFileName = true + } + if len(fnameMatches) == 0 && header.MatchFileHeader(b.lines[0].data) { + matchedFileHeader = true + } + } + + if matchedFileName || matchedFileHeader || header.FileType == ft { file, err := highlight.ParseFile(data) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) @@ -737,8 +750,12 @@ func (b *Buffer) UpdateRules() { syntaxFile = f.Name() foundDef = true break - } else { + } + + if matchedFileName { fnameMatches = append(fnameMatches, syntaxFileBuffer{header, f.Name(), syndef}) + } else if matchedFileHeader { + headerMatches = append(headerMatches, syntaxFileBuffer{header, f.Name(), syndef}) } } } @@ -762,6 +779,9 @@ func (b *Buffer) UpdateRules() { if header.MatchFileName(b.Path) { fnameMatches = append(fnameMatches, syntaxFileBuffer{header, f.Name(), nil}) } + if len(fnameMatches) == 0 && header.MatchFileHeader(b.lines[0].data) { + headerMatches = append(headerMatches, syntaxFileBuffer{header, f.Name(), nil}) + } } else if header.FileType == ft { syntaxFile = f.Name() break @@ -770,7 +790,12 @@ func (b *Buffer) UpdateRules() { } if syntaxFile == "" { - length := len(fnameMatches) + matches := fnameMatches + if len(matches) == 0 { + matches = headerMatches + } + + length := len(matches) if length > 0 { signatureMatch := false if length > 1 { @@ -781,15 +806,15 @@ func (b *Buffer) UpdateRules() { limit = detectlimit } for i := 0; i < length && !signatureMatch; i++ { - if fnameMatches[i].header.HasFileSignature() { + if matches[i].header.HasFileSignature() { for j := 0; j < limit && !signatureMatch; j++ { - if fnameMatches[i].header.MatchFileSignature(b.lines[j].data) { - syntaxFile = fnameMatches[i].fileName - if fnameMatches[i].syntaxDef != nil { - b.SyntaxDef = fnameMatches[i].syntaxDef + if matches[i].header.MatchFileSignature(b.lines[j].data) { + syntaxFile = matches[i].fileName + if matches[i].syntaxDef != nil { + b.SyntaxDef = matches[i].syntaxDef foundDef = true } - header = fnameMatches[i].header + header = matches[i].header signatureMatch = true } } @@ -797,12 +822,12 @@ func (b *Buffer) UpdateRules() { } } if length == 1 || !signatureMatch { - syntaxFile = fnameMatches[0].fileName - if fnameMatches[0].syntaxDef != nil { - b.SyntaxDef = fnameMatches[0].syntaxDef + syntaxFile = matches[0].fileName + if matches[0].syntaxDef != nil { + b.SyntaxDef = matches[0].syntaxDef foundDef = true } - header = fnameMatches[0].header + header = matches[0].header } } } From 6c3b5ad17ca67c25af6325fd80ff608bf1d40d6e Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sun, 24 Mar 2024 02:42:33 +0100 Subject: [PATCH 06/12] UpdateRules: refactor "header.FileType == ft" case --- internal/buffer/buffer.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 0f21f188..115cb64e 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -720,6 +720,7 @@ func (b *Buffer) UpdateRules() { continue } + matchedFileType := false matchedFileName := false matchedFileHeader := false @@ -730,9 +731,11 @@ func (b *Buffer) UpdateRules() { if len(fnameMatches) == 0 && header.MatchFileHeader(b.lines[0].data) { matchedFileHeader = true } + } else if header.FileType == ft { + matchedFileType = true } - if matchedFileName || matchedFileHeader || header.FileType == ft { + if matchedFileType || matchedFileName || matchedFileHeader { file, err := highlight.ParseFile(data) if err != nil { screen.TermMessage("Error parsing syntax file " + f.Name() + ": " + err.Error()) @@ -745,7 +748,7 @@ func (b *Buffer) UpdateRules() { continue } - if header.FileType == ft { + if matchedFileType { b.SyntaxDef = syndef syntaxFile = f.Name() foundDef = true From 5492d3095315c9841334a7dbf58d1667ccea228a Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sun, 24 Mar 2024 03:19:07 +0100 Subject: [PATCH 07/12] UpdateRules: add comment about the reason for signature match --- internal/buffer/buffer.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 115cb64e..a51f2dc8 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -802,6 +802,8 @@ func (b *Buffer) UpdateRules() { if length > 0 { signatureMatch := false if length > 1 { + // multiple matching syntax files found, try to resolve the ambiguity + // using signatures detectlimit := util.IntOpt(b.Settings["detectlimit"]) lineCount := len(b.lines) limit := lineCount From b2a428f1cdb748f121d1f6d4f99b7fd7ab0538e7 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 21:44:27 +0100 Subject: [PATCH 08/12] Restore `header` instead of `signature` in most syntax files Turning `header` patterns into `signature` patterns in all syntax files was a mistake. The two are different things. In almost all syntax files those patterns are things like shebangs or or i.e. things that: 1. can be (and should be) used for detecting the filetype when there is no `filename` match (and that is actually the purpose of those patterns, so it's a regression that it doesn't work anymore). 2. should only occur in the first line of the file, not in the first 100 lines or so. In other words, the old `header` semantics was exactly what was needed for those filetypes, while the new `signature` semantics makes little sense for them. So replace `signature` back with `header` in most syntax files. Keep `signature` only in C++ and Objective-C syntax files, for which it was actually introduced. --- runtime/syntax/PowerShell.yaml | 2 +- runtime/syntax/awk.yaml | 2 +- runtime/syntax/bat.yaml | 2 +- runtime/syntax/crontab.yaml | 2 +- runtime/syntax/csx.yaml | 2 +- runtime/syntax/fish.yaml | 2 +- runtime/syntax/godoc.yaml | 2 +- runtime/syntax/groovy.yaml | 2 +- runtime/syntax/html4.yaml | 2 +- runtime/syntax/html5.yaml | 2 +- runtime/syntax/javascript.yaml | 2 +- runtime/syntax/json.yaml | 2 +- runtime/syntax/julia.yaml | 2 +- runtime/syntax/justfile.yaml | 2 +- runtime/syntax/mail.yaml | 2 +- runtime/syntax/makefile.yaml | 2 +- runtime/syntax/nginx.yaml | 2 +- runtime/syntax/patch.yaml | 2 +- runtime/syntax/perl.yaml | 2 +- runtime/syntax/python2.yaml | 2 +- runtime/syntax/python3.yaml | 2 +- runtime/syntax/ruby.yaml | 2 +- runtime/syntax/sage.yaml | 2 +- runtime/syntax/sed.yaml | 2 +- runtime/syntax/sh.yaml | 2 +- runtime/syntax/systemd.yaml | 2 +- runtime/syntax/tcl.yaml | 2 +- runtime/syntax/xml.yaml | 2 +- runtime/syntax/yaml.yaml | 2 +- runtime/syntax/zsh.yaml | 2 +- 30 files changed, 30 insertions(+), 30 deletions(-) diff --git a/runtime/syntax/PowerShell.yaml b/runtime/syntax/PowerShell.yaml index daaa2b21..7a45e426 100644 --- a/runtime/syntax/PowerShell.yaml +++ b/runtime/syntax/PowerShell.yaml @@ -5,7 +5,7 @@ filetype: powershell detect: filename: "\\.ps(1|m1|d1)$" - #signature: "" + #header: "" rules: # - comment.block: # Block Comment diff --git a/runtime/syntax/awk.yaml b/runtime/syntax/awk.yaml index 93ddf9ae..ff3f6988 100644 --- a/runtime/syntax/awk.yaml +++ b/runtime/syntax/awk.yaml @@ -2,7 +2,7 @@ filetype: awk detect: filename: "\\.awk$" - signature: "^#!.*bin/(env +)?awk( |$)" + header: "^#!.*bin/(env +)?awk( |$)" rules: - preproc: "\\$[A-Za-z0-9_!@#$*?\\-]+" diff --git a/runtime/syntax/bat.yaml b/runtime/syntax/bat.yaml index 741f7437..2ef8d987 100644 --- a/runtime/syntax/bat.yaml +++ b/runtime/syntax/bat.yaml @@ -2,7 +2,7 @@ filetype: batch detect: filename: "(\\.bat$|\\.cmd$)" - # signature: "" + # header: "" rules: # Numbers diff --git a/runtime/syntax/crontab.yaml b/runtime/syntax/crontab.yaml index a5ee3746..86566512 100644 --- a/runtime/syntax/crontab.yaml +++ b/runtime/syntax/crontab.yaml @@ -2,7 +2,7 @@ filetype: crontab detect: filename: "crontab$" - signature: "^#.*?/etc/crontab" + header: "^#.*?/etc/crontab" rules: # The time and date fields are: diff --git a/runtime/syntax/csx.yaml b/runtime/syntax/csx.yaml index 61c5d6ea..5ba6ea11 100644 --- a/runtime/syntax/csx.yaml +++ b/runtime/syntax/csx.yaml @@ -1,7 +1,7 @@ filetype: csharp-script detect: filename: "\\.csx$" - signature: "^#!.*/(env +)?dotnet-script( |$)" + header: "^#!.*/(env +)?dotnet-script( |$)" rules: - include: "csharp" diff --git a/runtime/syntax/fish.yaml b/runtime/syntax/fish.yaml index e5078097..88798a04 100644 --- a/runtime/syntax/fish.yaml +++ b/runtime/syntax/fish.yaml @@ -2,7 +2,7 @@ filetype: fish detect: filename: "\\.fish$" - signature: "^#!.*/(env +)?fish( |$)" + header: "^#!.*/(env +)?fish( |$)" rules: # Numbers diff --git a/runtime/syntax/godoc.yaml b/runtime/syntax/godoc.yaml index 3d926b68..383f3097 100644 --- a/runtime/syntax/godoc.yaml +++ b/runtime/syntax/godoc.yaml @@ -5,7 +5,7 @@ filetype: godoc detect: filename: "\\.godoc$" - signature: package.*import + header: package.*import rules: - preproc: "^[^ ].*" diff --git a/runtime/syntax/groovy.yaml b/runtime/syntax/groovy.yaml index a19cdcd3..3aa0e283 100644 --- a/runtime/syntax/groovy.yaml +++ b/runtime/syntax/groovy.yaml @@ -2,7 +2,7 @@ filetype: groovy detect: filename: "(\\.(groovy|gy|gvy|gsh|gradle)$|^[Jj]enkinsfile$)" - signature: "^#!.*/(env +)?groovy *$" + header: "^#!.*/(env +)?groovy *$" rules: # And the style guide for constants is CONSTANT_CASE diff --git a/runtime/syntax/html4.yaml b/runtime/syntax/html4.yaml index a7cfae3f..c132d61e 100644 --- a/runtime/syntax/html4.yaml +++ b/runtime/syntax/html4.yaml @@ -2,7 +2,7 @@ filetype: html4 detect: filename: "\\.htm[l]?4$" - signature: "" + header: "" rules: - error: "<[^!].*?>" diff --git a/runtime/syntax/html5.yaml b/runtime/syntax/html5.yaml index 97bffde2..411d5385 100644 --- a/runtime/syntax/html5.yaml +++ b/runtime/syntax/html5.yaml @@ -2,7 +2,7 @@ filetype: html5 detect: filename: "\\.htm[l]?5$" - signature: "" + header: "" rules: - error: "<[^!].*?>" diff --git a/runtime/syntax/javascript.yaml b/runtime/syntax/javascript.yaml index 0b42caa6..b2bfe487 100644 --- a/runtime/syntax/javascript.yaml +++ b/runtime/syntax/javascript.yaml @@ -2,7 +2,7 @@ filetype: javascript detect: filename: "(\\.js$|\\.es[5678]?$|\\.mjs$)" - signature: "^#!.*/(env +)?node( |$)" + header: "^#!.*/(env +)?node( |$)" rules: - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" diff --git a/runtime/syntax/json.yaml b/runtime/syntax/json.yaml index 35705b1d..6d840833 100644 --- a/runtime/syntax/json.yaml +++ b/runtime/syntax/json.yaml @@ -2,7 +2,7 @@ filetype: json detect: filename: "\\.json$" - signature: "^\\{$" + header: "^\\{$" rules: - constant.number: "\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA-F]+)([uU][lL]?|[lL][uU]?)?\\b" diff --git a/runtime/syntax/julia.yaml b/runtime/syntax/julia.yaml index 8a46e5cf..c96ef0f3 100644 --- a/runtime/syntax/julia.yaml +++ b/runtime/syntax/julia.yaml @@ -2,7 +2,7 @@ filetype: julia detect: filename: "\\.jl$" - signature: "^#!.*/(env +)?julia( |$)" + header: "^#!.*/(env +)?julia( |$)" rules: diff --git a/runtime/syntax/justfile.yaml b/runtime/syntax/justfile.yaml index 2a856edb..926edb21 100644 --- a/runtime/syntax/justfile.yaml +++ b/runtime/syntax/justfile.yaml @@ -3,7 +3,7 @@ filetype: 'justfile' detect: filename: "(^\\.?[Jj]ustfile|\\.just)$" - signature: "^#!.*/(env +)?[bg]?just --justfile" + header: "^#!.*/(env +)?[bg]?just --justfile" rules: - preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>" diff --git a/runtime/syntax/mail.yaml b/runtime/syntax/mail.yaml index 4cf588ce..6ffe8733 100644 --- a/runtime/syntax/mail.yaml +++ b/runtime/syntax/mail.yaml @@ -2,7 +2,7 @@ filetype: mail detect: filename: "(.*/mutt-.*|\\.eml)$" - signature: "^From .* \\d+:\\d+:\\d+ \\d+" + header: "^From .* \\d+:\\d+:\\d+ \\d+" rules: - type: "^From .*" diff --git a/runtime/syntax/makefile.yaml b/runtime/syntax/makefile.yaml index 670935fa..7e90cdeb 100644 --- a/runtime/syntax/makefile.yaml +++ b/runtime/syntax/makefile.yaml @@ -2,7 +2,7 @@ filetype: makefile detect: filename: "([Mm]akefile|\\.ma?k)$" - signature: "^#!.*/(env +)?[bg]?make( |$)" + header: "^#!.*/(env +)?[bg]?make( |$)" rules: - preproc: "\\<(ifeq|ifdef|ifneq|ifndef|else|endif)\\>" diff --git a/runtime/syntax/nginx.yaml b/runtime/syntax/nginx.yaml index 4a103ca3..02ea6eb0 100644 --- a/runtime/syntax/nginx.yaml +++ b/runtime/syntax/nginx.yaml @@ -2,7 +2,7 @@ filetype: nginx detect: filename: "nginx.*\\.conf$|\\.nginx$" - signature: "^(server|upstream)[a-z ]*\\{$" + header: "^(server|upstream)[a-z ]*\\{$" rules: - preproc: "\\b(events|server|http|location|upstream)[[:space:]]*\\{" diff --git a/runtime/syntax/patch.yaml b/runtime/syntax/patch.yaml index 6275d423..996bdc38 100644 --- a/runtime/syntax/patch.yaml +++ b/runtime/syntax/patch.yaml @@ -2,7 +2,7 @@ filetype: patch detect: filename: "\\.(patch|diff)$" - signature: "^diff" + header: "^diff" rules: - brightgreen: "^\\+.*" diff --git a/runtime/syntax/perl.yaml b/runtime/syntax/perl.yaml index d43c264f..2b01b894 100644 --- a/runtime/syntax/perl.yaml +++ b/runtime/syntax/perl.yaml @@ -2,7 +2,7 @@ filetype: perl detect: filename: "\\.p[lmp]$" - signature: "^#!.*/(env +)?perl( |$)" + header: "^#!.*/(env +)?perl( |$)" 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" diff --git a/runtime/syntax/python2.yaml b/runtime/syntax/python2.yaml index 42f7ffb4..3a993b05 100644 --- a/runtime/syntax/python2.yaml +++ b/runtime/syntax/python2.yaml @@ -2,7 +2,7 @@ filetype: python2 detect: filename: "\\.py2$" - signature: "^#!.*/(env +)?python2$" + header: "^#!.*/(env +)?python2$" rules: diff --git a/runtime/syntax/python3.yaml b/runtime/syntax/python3.yaml index 7e18df6e..5a060bff 100644 --- a/runtime/syntax/python3.yaml +++ b/runtime/syntax/python3.yaml @@ -2,7 +2,7 @@ filetype: python detect: filename: "\\.py(3)?$" - signature: "^#!.*/(env +)?python(3)?$" + header: "^#!.*/(env +)?python(3)?$" rules: # built-in objects diff --git a/runtime/syntax/ruby.yaml b/runtime/syntax/ruby.yaml index c84ada44..03dac2e5 100644 --- a/runtime/syntax/ruby.yaml +++ b/runtime/syntax/ruby.yaml @@ -2,7 +2,7 @@ filetype: ruby detect: filename: "\\.(rb|rake|gemspec)$|^(.*[\\/])?(Gemfile|config.ru|Rakefile|Capfile|Vagrantfile|Guardfile|Appfile|Fastfile|Pluginfile|Podfile|\\.?[Bb]rewfile)$" - signature: "^#!.*/(env +)?ruby( |$)" + header: "^#!.*/(env +)?ruby( |$)" rules: - comment.bright: diff --git a/runtime/syntax/sage.yaml b/runtime/syntax/sage.yaml index 8d2cb07a..e24fbeb6 100644 --- a/runtime/syntax/sage.yaml +++ b/runtime/syntax/sage.yaml @@ -2,7 +2,7 @@ filetype: sage detect: filename: "\\.sage$" - signature: "^#!.*/(env +)?sage( |$)" + header: "^#!.*/(env +)?sage( |$)" rules: diff --git a/runtime/syntax/sed.yaml b/runtime/syntax/sed.yaml index a3bf1595..ed33bae5 100644 --- a/runtime/syntax/sed.yaml +++ b/runtime/syntax/sed.yaml @@ -2,7 +2,7 @@ filetype: sed detect: filename: "\\.sed$" - signature: "^#!.*bin/(env +)?sed( |$)" + header: "^#!.*bin/(env +)?sed( |$)" rules: - symbol.operator: "[|^$.*+]" diff --git a/runtime/syntax/sh.yaml b/runtime/syntax/sh.yaml index 3a0d9d45..3ace3268 100644 --- a/runtime/syntax/sh.yaml +++ b/runtime/syntax/sh.yaml @@ -24,7 +24,7 @@ filetype: shell # * bash-fc. (followed by a random string) detect: filename: "(\\.(sh|bash|ash|ebuild)$|(\\.bash(rc|_aliases|_functions|_profile)|\\.?profile|Pkgfile|pkgmk\\.conf|rc\\.conf|PKGBUILD|APKBUILD)$|bash-fc\\.)" - signature: "^#!.*/(env +)?(ba)?(a)?(mk)?sh( |$)" + header: "^#!.*/(env +)?(ba)?(a)?(mk)?sh( |$)" rules: # Numbers diff --git a/runtime/syntax/systemd.yaml b/runtime/syntax/systemd.yaml index 9b668776..a8650be4 100644 --- a/runtime/syntax/systemd.yaml +++ b/runtime/syntax/systemd.yaml @@ -2,7 +2,7 @@ filetype: systemd detect: filename: "\\.(service|socket|timer)$" - signature: "^\\[Unit\\]$" + header: "^\\[Unit\\]$" 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)=" diff --git a/runtime/syntax/tcl.yaml b/runtime/syntax/tcl.yaml index 1b4ae7e5..b87a7d79 100644 --- a/runtime/syntax/tcl.yaml +++ b/runtime/syntax/tcl.yaml @@ -2,7 +2,7 @@ filetype: tcl detect: filename: "\\.tcl$" - signature: "^#!.*/(env +)?tclsh( |$)" + header: "^#!.*/(env +)?tclsh( |$)" 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" diff --git a/runtime/syntax/xml.yaml b/runtime/syntax/xml.yaml index 0e9b901e..df4cde81 100644 --- a/runtime/syntax/xml.yaml +++ b/runtime/syntax/xml.yaml @@ -2,7 +2,7 @@ filetype: xml detect: filename: "\\.(xml|sgml?|rng|svg|plist)$" - signature: "<\\?xml.*\\?>" + header: "<\\?xml.*\\?>" rules: - preproc: diff --git a/runtime/syntax/yaml.yaml b/runtime/syntax/yaml.yaml index c21286e4..54d4a647 100644 --- a/runtime/syntax/yaml.yaml +++ b/runtime/syntax/yaml.yaml @@ -2,7 +2,7 @@ filetype: yaml detect: filename: "\\.ya?ml$" - signature: "%YAML" + header: "%YAML" rules: - type: "(^| )!!(binary|bool|float|int|map|null|omap|seq|set|str) " diff --git a/runtime/syntax/zsh.yaml b/runtime/syntax/zsh.yaml index 3b7e0593..a2832131 100644 --- a/runtime/syntax/zsh.yaml +++ b/runtime/syntax/zsh.yaml @@ -2,7 +2,7 @@ filetype: zsh detect: filename: "(\\.zsh$|\\.?(zshenv|zprofile|zshrc|zlogin|zlogout)$)" - signature: "^#!.*/(env +)?zsh( |$)" + header: "^#!.*/(env +)?zsh( |$)" rules: ## Numbers From 66a38395895f52cadbd7085817f9d35baab73a27 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sun, 24 Mar 2024 02:07:58 +0100 Subject: [PATCH 09/12] Update and clarify documentation on filetype detection patterns --- runtime/help/colors.md | 33 ++++++++++++++++++++++++++++++--- runtime/syntax/README.md | 3 ++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/runtime/help/colors.md b/runtime/help/colors.md index 80a877d7..4e7d874f 100644 --- a/runtime/help/colors.md +++ b/runtime/help/colors.md @@ -271,13 +271,40 @@ detect: ``` Micro will match this regex against a given filename to detect the filetype. -You may also provide an optional `signature` regex that will check a certain -amount of lines of a file to find specific marks. For example: + +In addition to the `filename` regex (or even instead of it) you can provide +a `header` regex that will check the first line of the line. For example: ``` detect: filename: "\\.ya?ml$" - signature: "%YAML" + header: "%YAML" +``` + +This is useful in cases when the given file name is not sufficient to determine +the filetype, e.g. with the above example, if a YAML file has no `.yaml` +extension but may contain a `%YAML` directive in its first line. + +`filename` takes precedence over `header`, i.e. if there is a syntax file that +matches the file with a filetype by the `filename` and another syntax file that +matches the same file with another filetype by the `header`, the first filetype +will be used. + +Finally, in addition to `filename` and/or `header` (but not instead of them) +you may also provide an optional `signature` regex which is useful for resolving +ambiguities when there are multiple syntax files matching the same file with +different filetypes. If a `signature` regex is given, micro will match a certain +amount of first lines in the file (this amount is determined by the `detectlimit` +option) against this regex, and if any of the lines match, this syntax file's +filetype will be preferred over other matching filetypes. + +For example, to distinguish C++ header files from C and Objective-C header files +that have the same `.h` extension: + +``` +detect: + filename: "\\.c(c|pp|xx)$|\\.h(h|pp|xx)?$" + signature: "namespace|template|public|protected|private" ``` ### Syntax rules diff --git a/runtime/syntax/README.md b/runtime/syntax/README.md index 4fa58647..3e2c5631 100644 --- a/runtime/syntax/README.md +++ b/runtime/syntax/README.md @@ -2,7 +2,8 @@ Here are micro's syntax files. -Each yaml file specifies how to detect the filetype based on file extension or given signature. The signature can be matched to all available lines of the file or to the value defined with the option `detectlimit` (to limit parse times) for a best "guess". +Each yaml file specifies how to detect the filetype based on file extension or header (first line of the line). +In addition, a signature can be provided to help resolving ambiguities when multiple matching filetypes are detected. 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 From 9ee82a6cb32db4c32abcf3314669674c25ba3880 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 21:49:53 +0100 Subject: [PATCH 10/12] UpdateRules: rename syntaxFileBuffer to syntaxFileInfo To make it more clear. Why Buffer? --- internal/buffer/buffer.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index a51f2dc8..91cfa429 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -693,16 +693,16 @@ func (b *Buffer) UpdateRules() { return } - // syntaxFileBuffer is a helper structure + // syntaxFileInfo is an internal helper structure // to store properties of one single syntax file - type syntaxFileBuffer struct { + type syntaxFileInfo struct { header *highlight.Header fileName string syntaxDef *highlight.Def } - fnameMatches := []syntaxFileBuffer{} - headerMatches := []syntaxFileBuffer{} + fnameMatches := []syntaxFileInfo{} + headerMatches := []syntaxFileInfo{} syntaxFile := "" foundDef := false var header *highlight.Header @@ -756,9 +756,9 @@ func (b *Buffer) UpdateRules() { } if matchedFileName { - fnameMatches = append(fnameMatches, syntaxFileBuffer{header, f.Name(), syndef}) + fnameMatches = append(fnameMatches, syntaxFileInfo{header, f.Name(), syndef}) } else if matchedFileHeader { - headerMatches = append(headerMatches, syntaxFileBuffer{header, f.Name(), syndef}) + headerMatches = append(headerMatches, syntaxFileInfo{header, f.Name(), syndef}) } } } @@ -780,10 +780,10 @@ func (b *Buffer) UpdateRules() { if ft == "unknown" || ft == "" { if header.MatchFileName(b.Path) { - fnameMatches = append(fnameMatches, syntaxFileBuffer{header, f.Name(), nil}) + fnameMatches = append(fnameMatches, syntaxFileInfo{header, f.Name(), nil}) } if len(fnameMatches) == 0 && header.MatchFileHeader(b.lines[0].data) { - headerMatches = append(headerMatches, syntaxFileBuffer{header, f.Name(), nil}) + headerMatches = append(headerMatches, syntaxFileInfo{header, f.Name(), nil}) } } else if header.FileType == ft { syntaxFile = f.Name() From 053949eac6b967354abffc5777e837b602c3fb5a Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sat, 23 Mar 2024 21:59:40 +0100 Subject: [PATCH 11/12] UpdateRules: de-densify code arouns signatureMatch Purely cosmetic change: make the code a bit more readable by reducing its visual "density". --- internal/buffer/buffer.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 91cfa429..ecdc90e1 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -810,17 +810,20 @@ func (b *Buffer) UpdateRules() { if detectlimit > 0 && lineCount > detectlimit { limit = detectlimit } - for i := 0; i < length && !signatureMatch; i++ { - if matches[i].header.HasFileSignature() { - for j := 0; j < limit && !signatureMatch; j++ { - if matches[i].header.MatchFileSignature(b.lines[j].data) { - syntaxFile = matches[i].fileName - if matches[i].syntaxDef != nil { - b.SyntaxDef = matches[i].syntaxDef + + matchLoop: + for _, m := range matches { + if m.header.HasFileSignature() { + for i := 0; i < limit; i++ { + if m.header.MatchFileSignature(b.lines[i].data) { + syntaxFile = m.fileName + if m.syntaxDef != nil { + b.SyntaxDef = m.syntaxDef foundDef = true } - header = matches[i].header + header = m.header signatureMatch = true + break matchLoop } } } From 1021f61a814845b436b5b84010cda6c07ab4283d Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Sun, 24 Mar 2024 15:22:43 +0100 Subject: [PATCH 12/12] syntax: remove some commented out garbage --- runtime/syntax/PowerShell.yaml | 1 - runtime/syntax/bat.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/runtime/syntax/PowerShell.yaml b/runtime/syntax/PowerShell.yaml index 7a45e426..a778199d 100644 --- a/runtime/syntax/PowerShell.yaml +++ b/runtime/syntax/PowerShell.yaml @@ -5,7 +5,6 @@ filetype: powershell detect: filename: "\\.ps(1|m1|d1)$" - #header: "" rules: # - comment.block: # Block Comment diff --git a/runtime/syntax/bat.yaml b/runtime/syntax/bat.yaml index 2ef8d987..a719a6d4 100644 --- a/runtime/syntax/bat.yaml +++ b/runtime/syntax/bat.yaml @@ -2,7 +2,6 @@ filetype: batch detect: filename: "(\\.bat$|\\.cmd$)" - # header: "" rules: # Numbers