Major optimization for loading syntax files

This commit is contained in:
Zachary Yedidia
2016-04-18 14:40:07 -04:00
parent 273401d911
commit 47c32dda22
11 changed files with 348 additions and 219 deletions

View File

@@ -1,13 +1,15 @@
build:
.PHONY: runtime
build: runtime
go get -d ./cmd/micro
go build -o micro ./cmd/micro
install: build
install: build runtime
mv micro $(GOPATH)/bin
runtime:
go get -u github.com/jteeuwen/go-bindata/...
go-bindata -o runtime.go data/
go-bindata -o runtime.go runtime/...
mv runtime.go cmd/micro
test:

View File

@@ -11,7 +11,8 @@ import (
// FileTypeRules represents a complete set of syntax rules for a filetype
type FileTypeRules struct {
filetype string
rules []SyntaxRule
filename string
text string
}
// SyntaxRule represents a regex to highlight in a certain style
@@ -49,8 +50,11 @@ var preInstalledSynFiles = []string{
"erb",
"fish",
"fortran",
"gentoo",
"git",
"gentoo-ebuild",
"gentoo-etc-portage",
"git-commit",
"git-config",
"git-rebase-todo",
"glsl",
"go",
"groff",
@@ -83,7 +87,9 @@ var preInstalledSynFiles = []string{
"pkgbuild",
"po",
"pov",
"privoxy",
"privoxy-action",
"privoxy-config",
"privoxy-filter",
"puppet",
"python",
"reST",
@@ -170,15 +176,9 @@ func LoadSyntaxFile(text, filename string) {
// Regex for parsing header statements
headerParser := regexp.MustCompile(`header "(.*)"`)
// Regex for parsing standard syntax rules
ruleParser := regexp.MustCompile(`color (.*?)\s+(?:\((.*?)\)\s+)?"(.*)"`)
// Regex for parsing syntax rules with start="..." end="..."
ruleStartEndParser := regexp.MustCompile(`color (.*?)\s+(?:\((.*?)\)\s+)?start="(.*)"\s+end="(.*)"`)
var syntaxRegex *regexp.Regexp
var headerRegex *regexp.Regexp
var filetype string
var rules []SyntaxRule
for lineNum, line := range lines {
if strings.TrimSpace(line) == "" ||
strings.TrimSpace(line)[0] == '#' {
@@ -191,11 +191,8 @@ func LoadSyntaxFile(text, filename string) {
syntaxMatches := syntaxParser.FindSubmatch([]byte(line))
if len(syntaxMatches) == 3 {
if syntaxRegex != nil {
// Add the current rules to the syntaxFiles variable
regexes := [2]*regexp.Regexp{syntaxRegex, headerRegex}
syntaxFiles[regexes] = FileTypeRules{filetype, rules}
TermError(filename, lineNum, "Syntax statement redeclaration")
}
rules = rules[:0]
filetype = string(syntaxMatches[1])
extensions := JoinRule(string(syntaxMatches[2]))
@@ -224,112 +221,135 @@ func LoadSyntaxFile(text, filename string) {
TermError(filename, lineNum, "Header statement is not valid: "+line)
continue
}
} else {
// Syntax rule, but it could be standard or start-end
if ruleParser.MatchString(line) {
// Standard syntax rule
// Parse the line
submatch := ruleParser.FindSubmatch([]byte(line))
var color string
var regexStr string
var flags string
if len(submatch) == 4 {
// If len is 4 then the user specified some additional flags to use
color = string(submatch[1])
flags = string(submatch[2])
regexStr = "(?" + flags + ")" + JoinRule(string(submatch[3]))
} else if len(submatch) == 3 {
// If len is 3, no additional flags were given
color = string(submatch[1])
regexStr = JoinRule(string(submatch[2]))
} else {
// If len is not 3 or 4 there is a problem
TermError(filename, lineNum, "Invalid statement: "+line)
continue
}
// Compile the regex
regex, err := regexp.Compile(regexStr)
if err != nil {
TermError(filename, lineNum, err.Error())
continue
}
// Get the style
// The user could give us a "color" that is really a part of the colorscheme
// in which case we should look that up in the colorscheme
// They can also just give us a straight up color
st := defStyle
if _, ok := colorscheme[color]; ok {
st = colorscheme[color]
} else {
st = StringToStyle(color)
}
// Add the regex, flags, and style
// False because this is not start-end
rules = append(rules, SyntaxRule{regex, flags, false, st})
} else if ruleStartEndParser.MatchString(line) {
// Start-end syntax rule
submatch := ruleStartEndParser.FindSubmatch([]byte(line))
var color string
var start string
var end string
// Use m and s flags by default
flags := "ms"
if len(submatch) == 5 {
// If len is 5 the user provided some additional flags
color = string(submatch[1])
flags += string(submatch[2])
start = string(submatch[3])
end = string(submatch[4])
} else if len(submatch) == 4 {
// If len is 4 the user did not provide additional flags
color = string(submatch[1])
start = string(submatch[2])
end = string(submatch[3])
} else {
// If len is not 4 or 5 there is a problem
TermError(filename, lineNum, "Invalid statement: "+line)
continue
}
// Compile the regex
regex, err := regexp.Compile("(?" + flags + ")" + "(" + start + ").*?(" + end + ")")
if err != nil {
TermError(filename, lineNum, err.Error())
continue
}
// Get the style
// The user could give us a "color" that is really a part of the colorscheme
// in which case we should look that up in the colorscheme
// They can also just give us a straight up color
st := defStyle
if _, ok := colorscheme[color]; ok {
st = colorscheme[color]
} else {
st = StringToStyle(color)
}
// Add the regex, flags, and style
// True because this is start-end
rules = append(rules, SyntaxRule{regex, flags, true, st})
}
}
}
if syntaxRegex != nil {
// Add the current rules to the syntaxFiles variable
regexes := [2]*regexp.Regexp{syntaxRegex, headerRegex}
syntaxFiles[regexes] = FileTypeRules{filetype, rules}
syntaxFiles[regexes] = FileTypeRules{filetype, filename, text}
}
}
func LoadRulesFromFile(text, filename string) []SyntaxRule {
lines := strings.Split(string(text), "\n")
// Regex for parsing standard syntax rules
ruleParser := regexp.MustCompile(`color (.*?)\s+(?:\((.*?)\)\s+)?"(.*)"`)
// Regex for parsing syntax rules with start="..." end="..."
ruleStartEndParser := regexp.MustCompile(`color (.*?)\s+(?:\((.*?)\)\s+)?start="(.*)"\s+end="(.*)"`)
var rules []SyntaxRule
for lineNum, line := range lines {
if strings.TrimSpace(line) == "" ||
strings.TrimSpace(line)[0] == '#' ||
strings.HasPrefix(line, "syntax") ||
strings.HasPrefix(line, "header") {
// Ignore this line
continue
}
// Syntax rule, but it could be standard or start-end
if ruleParser.MatchString(line) {
// Standard syntax rule
// Parse the line
submatch := ruleParser.FindSubmatch([]byte(line))
var color string
var regexStr string
var flags string
if len(submatch) == 4 {
// If len is 4 then the user specified some additional flags to use
color = string(submatch[1])
flags = string(submatch[2])
regexStr = "(?" + flags + ")" + JoinRule(string(submatch[3]))
} else if len(submatch) == 3 {
// If len is 3, no additional flags were given
color = string(submatch[1])
regexStr = JoinRule(string(submatch[2]))
} else {
// If len is not 3 or 4 there is a problem
TermError(filename, lineNum, "Invalid statement: "+line)
continue
}
// Compile the regex
regex, err := regexp.Compile(regexStr)
if err != nil {
TermError(filename, lineNum, err.Error())
continue
}
// Get the style
// The user could give us a "color" that is really a part of the colorscheme
// in which case we should look that up in the colorscheme
// They can also just give us a straight up color
st := defStyle
if _, ok := colorscheme[color]; ok {
st = colorscheme[color]
} else {
st = StringToStyle(color)
}
// Add the regex, flags, and style
// False because this is not start-end
rules = append(rules, SyntaxRule{regex, flags, false, st})
} else if ruleStartEndParser.MatchString(line) {
// Start-end syntax rule
submatch := ruleStartEndParser.FindSubmatch([]byte(line))
var color string
var start string
var end string
// Use m and s flags by default
flags := "ms"
if len(submatch) == 5 {
// If len is 5 the user provided some additional flags
color = string(submatch[1])
flags += string(submatch[2])
start = string(submatch[3])
end = string(submatch[4])
} else if len(submatch) == 4 {
// If len is 4 the user did not provide additional flags
color = string(submatch[1])
start = string(submatch[2])
end = string(submatch[3])
} else {
// If len is not 4 or 5 there is a problem
TermError(filename, lineNum, "Invalid statement: "+line)
continue
}
// Compile the regex
regex, err := regexp.Compile("(?" + flags + ")" + "(" + start + ").*?(" + end + ")")
if err != nil {
TermError(filename, lineNum, err.Error())
continue
}
// Get the style
// The user could give us a "color" that is really a part of the colorscheme
// in which case we should look that up in the colorscheme
// They can also just give us a straight up color
st := defStyle
if _, ok := colorscheme[color]; ok {
st = colorscheme[color]
} else {
st = StringToStyle(color)
}
// Add the regex, flags, and style
// True because this is start-end
rules = append(rules, SyntaxRule{regex, flags, true, st})
}
}
return rules
}
// GetRules finds the syntax rules that should be used for the buffer
// and returns them. It also returns the filetype of the file
func GetRules(buf *Buffer) ([]SyntaxRule, string) {
for r := range syntaxFiles {
if r[0] != nil && r[0].MatchString(buf.path) {
return syntaxFiles[r].rules, syntaxFiles[r].filetype
// Check if the syntax statement matches the extension
return LoadRulesFromFile(syntaxFiles[r].text, syntaxFiles[r].filename), syntaxFiles[r].filetype
} else if r[1] != nil && r[1].MatchString(buf.lines[0]) {
return syntaxFiles[r].rules, syntaxFiles[r].filetype
// Check if the header statement matches the first line
return LoadRulesFromFile(syntaxFiles[r].text, syntaxFiles[r].filename), syntaxFiles[r].filetype
}
}
return nil, "Unknown"

File diff suppressed because one or more lines are too long

View File

@@ -28,23 +28,3 @@ color yellow "#.*$"
color brightyellow ""(\\.|[^\"])*"" "'(\\.|[^'])*'"
## Trailing space is bad!
color ,green "[[:space:]]+$"
## Here is an example for Portage control files
##
syntax "etc-portage" "\.(keywords|mask|unmask|use)$"
## Base text:
color green "^.+$"
## Use flags:
color brightred "[[:space:]]+\+?[a-zA-Z0-9_-]+"
color brightblue "[[:space:]]+-[a-zA-Z0-9_-]+"
## Likely version numbers:
color magenta "-[[:digit:]].*([[:space:]]|$)"
## Accepted arches:
color white "[~-]?\<(alpha|amd64|arm|hppa|ia64|mips|ppc|ppc64|s390|sh|sparc|x86|x86-fbsd)\>"
color white "[[:space:]][~-]?\*"
## Categories:
color cyan "^[[:space:]]*.*/"
## Masking regulators:
color brightmagenta "^[[:space:]]*(=|~|<|<=|=<|>|>=|=>)"
## Comments:
color yellow "#.*$"

View File

@@ -0,0 +1,19 @@
## Here is an example for Portage control files
##
syntax "etc-portage" "\.(keywords|mask|unmask|use)$"
## Base text:
color green "^.+$"
## Use flags:
color brightred "[[:space:]]+\+?[a-zA-Z0-9_-]+"
color brightblue "[[:space:]]+-[a-zA-Z0-9_-]+"
## Likely version numbers:
color magenta "-[[:digit:]].*([[:space:]]|$)"
## Accepted arches:
color white "[~-]?\<(alpha|amd64|arm|hppa|ia64|mips|ppc|ppc64|s390|sh|sparc|x86|x86-fbsd)\>"
color white "[[:space:]][~-]?\*"
## Categories:
color cyan "^[[:space:]]*.*/"
## Masking regulators:
color brightmagenta "^[[:space:]]*(=|~|<|<=|=<|>|>=|=>)"
## Comments:
color yellow "#.*$"

View File

@@ -1,16 +1,7 @@
syntax "git-config" "git(config|modules)$|\.git/config$"
color constant "\<(true|false)\>"
color keyword "^[[:space:]]*[^=]*="
color constant "^[[:space:]]*\[.*\]$"
color constant ""(\\.|[^"])*"|'(\\.|[^'])*'"
color comment "(^|[[:space:]])#([^{].*)?$"
# This code is free software; you can redistribute it and/or modify it under
# the terms of the new BSD License.
#
# Copyright (c) 2010, Sebastian Staudt
# A nano configuration file to enable syntax highlighting of some Git specific
# files with the GNU nano text editor (http://www.nano-editor.org)
#
@@ -45,34 +36,3 @@ color special "#"
# Trailing spaces (+LINT is not ok, git uses tabs)
color ,error "[[:space:]]+$"
# This syntax format is used for interactive rebasing
syntax "git-rebase-todo" "git-rebase-todo"
# Default
color ignore ".*"
# Comments
color comment "^#.*"
# Rebase commands
color keyword "^(e|edit) [0-9a-f]{7,40}"
color keyword "^# (e, edit)"
color keyword "^(f|fixup) [0-9a-f]{7,40}"
color keyword "^# (f, fixup)"
color keyword "^(p|pick) [0-9a-f]{7,40}"
color keyword "^# (p, pick)"
color keyword "^(r|reword) [0-9a-f]{7,40}"
color keyword "^# (r, reword)"
color keyword "^(s|squash) [0-9a-f]{7,40}"
color keyword "^# (s, squash)"
color keyword "^(x|exec) [^ ]+ [0-9a-f]{7,40}"
color keyword "^# (x, exec)"
# Recolor hash symbols
color special "#"
# Commit IDs
color identifier "[0-9a-f]{7,40}"

View File

@@ -0,0 +1,7 @@
syntax "git-config" "git(config|modules)$|\.git/config$"
color constant "\<(true|false)\>"
color keyword "^[[:space:]]*[^=]*="
color constant "^[[:space:]]*\[.*\]$"
color constant ""(\\.|[^"])*"|'(\\.|[^'])*'"
color comment "(^|[[:space:]])#([^{].*)?$"

View File

@@ -0,0 +1,28 @@
# This syntax format is used for interactive rebasing
syntax "git-rebase-todo" "git-rebase-todo"
# Default
color ignore ".*"
# Comments
color comment "^#.*"
# Rebase commands
color keyword "^(e|edit) [0-9a-f]{7,40}"
color keyword "^# (e, edit)"
color keyword "^(f|fixup) [0-9a-f]{7,40}"
color keyword "^# (f, fixup)"
color keyword "^(p|pick) [0-9a-f]{7,40}"
color keyword "^# (p, pick)"
color keyword "^(r|reword) [0-9a-f]{7,40}"
color keyword "^# (r, reword)"
color keyword "^(s|squash) [0-9a-f]{7,40}"
color keyword "^# (s, squash)"
color keyword "^(x|exec) [^ ]+ [0-9a-f]{7,40}"
color keyword "^# (x, exec)"
# Recolor hash symbols
color special "#"
# Commit IDs
color identifier "[0-9a-f]{7,40}"

View File

@@ -1,10 +1,3 @@
syntax "Privoxy-config" "privoxy/config$"
color cyan "(accept-intercepted-requests|actionsfile|admin-address|allow-cgi-request-crunching|buffer-limit|compression-level|confdir|connection-sharing|debug|default-server-timeout|deny-access|enable-compression|enable-edit-actions|enable-remote-http-toggle|enable-remote-toggle|enforce-blocks|filterfile|forward|forwarded-connect-retries|forward-socks4|forward-socks4a|forward-socks5|handle-as-empty-doc-returns-ok|hostname|keep-alive-timeout|listen-address|logdir|logfile|max-client-connections|permit-access|proxy-info-url|single-threaded|socket-timeout|split-large-forms|templdir|toggle|tolerate-pipelining|trustfile|trust-info-url|user-manual)[[:space:]]"
color brightblack "(^|[[:space:]])#([^{].*)?$"
color ,green "[[:space:]]+$"
color ,red " + +| + +"
syntax "Privoxy-action" "\.action$"
color brightred "[{[:space:]]\-block([[:space:]{}]|$)"
@@ -16,12 +9,3 @@ color magenta "\\.?"
color brightblack "(^|[[:space:]])#([^{].*)?$"
color ,green "[[:space:]]+$"
color ,red " + +| + +"
syntax "Privoxy-filter" "\.filter$"
color cyan "^(FILTER|CLIENT-HEADER-FILTER|CLIENT-HEADER-TAGGER|SERVER-HEADER-FILTER|SERVER-HEADER-TAGGER): [a-z-]+"
color brightblue "^(FILTER|CLIENT-HEADER-FILTER|CLIENT-HEADER-TAGGER|SERVER-HEADER-FILTER|SERVER-HEADER-TAGGER):"
color magenta "\\.?"
color brightblack "(^|[[:space:]])#([^{].*)?$"
color ,green "[[:space:]]+$"
color ,red " + +| + +"

View File

@@ -0,0 +1,6 @@
syntax "Privoxy-config" "privoxy/config$"
color cyan "(accept-intercepted-requests|actionsfile|admin-address|allow-cgi-request-crunching|buffer-limit|compression-level|confdir|connection-sharing|debug|default-server-timeout|deny-access|enable-compression|enable-edit-actions|enable-remote-http-toggle|enable-remote-toggle|enforce-blocks|filterfile|forward|forwarded-connect-retries|forward-socks4|forward-socks4a|forward-socks5|handle-as-empty-doc-returns-ok|hostname|keep-alive-timeout|listen-address|logdir|logfile|max-client-connections|permit-access|proxy-info-url|single-threaded|socket-timeout|split-large-forms|templdir|toggle|tolerate-pipelining|trustfile|trust-info-url|user-manual)[[:space:]]"
color brightblack "(^|[[:space:]])#([^{].*)?$"
color ,green "[[:space:]]+$"
color ,red " + +| + +"

View File

@@ -0,0 +1,8 @@
syntax "Privoxy-filter" "\.filter$"
color cyan "^(FILTER|CLIENT-HEADER-FILTER|CLIENT-HEADER-TAGGER|SERVER-HEADER-FILTER|SERVER-HEADER-TAGGER): [a-z-]+"
color brightblue "^(FILTER|CLIENT-HEADER-FILTER|CLIENT-HEADER-TAGGER|SERVER-HEADER-FILTER|SERVER-HEADER-TAGGER):"
color magenta "\\.?"
color brightblack "(^|[[:space:]])#([^{].*)?$"
color ,green "[[:space:]]+$"
color ,red " + +| + +"