diff options
author | mrsdizzie <info@mrsdizzie.com> | 2020-06-30 17:34:03 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-01 00:34:03 +0300 |
commit | af7ffaa2798148e2a1b249da2330200bc032d7b1 (patch) | |
tree | 4f1f41767fa620dff4142ac7ebcd74b0abd61033 /vendor/github.com/danwakefield/fnmatch/fnmatch.go | |
parent | ce5f2b9845659efaca0b81998dca6cf03882b134 (diff) | |
download | gitea-af7ffaa2798148e2a1b249da2330200bc032d7b1.tar.gz gitea-af7ffaa2798148e2a1b249da2330200bc032d7b1.zip |
Server-side syntax highlighting for all code (#12047)
* Server-side syntax hilighting for all code
This PR does a few things:
* Remove all traces of highlight.js
* Use chroma library to provide fast syntax hilighting directly on the server
* Provide syntax hilighting for diffs
* Re-style both unified and split diffs views
* Add custom syntax hilighting styling for both regular and arc-green
Fixes #7729
Fixes #10157
Fixes #11825
Fixes #7728
Fixes #3872
Fixes #3682
And perhaps gets closer to #9553
* fix line marker
* fix repo search
* Fix single line select
* properly load settings
* npm uninstall highlight.js
* review suggestion
* code review
* forgot to call function
* fix test
* Apply suggestions from code review
suggestions from @silverwind thanks
Co-authored-by: silverwind <me@silverwind.io>
* code review
* copy/paste error
* Use const for highlight size limit
* Update web_src/less/_repository.less
Co-authored-by: Lauris BH <lauris@nix.lv>
* update size limit to 1MB and other styling tweaks
* fix highlighting for certain diff sections
* fix test
* add worker back as suggested
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Lauris BH <lauris@nix.lv>
Diffstat (limited to 'vendor/github.com/danwakefield/fnmatch/fnmatch.go')
-rw-r--r-- | vendor/github.com/danwakefield/fnmatch/fnmatch.go | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/vendor/github.com/danwakefield/fnmatch/fnmatch.go b/vendor/github.com/danwakefield/fnmatch/fnmatch.go new file mode 100644 index 0000000000..07ac7b37ca --- /dev/null +++ b/vendor/github.com/danwakefield/fnmatch/fnmatch.go @@ -0,0 +1,219 @@ +// Provide string-matching based on fnmatch.3 +package fnmatch + +// There are a few issues that I believe to be bugs, but this implementation is +// based as closely as possible on BSD fnmatch. These bugs are present in the +// source of BSD fnmatch, and so are replicated here. The issues are as follows: +// +// * FNM_PERIOD is no longer observed after the first * in a pattern +// This only applies to matches done with FNM_PATHNAME as well +// * FNM_PERIOD doesn't apply to ranges. According to the documentation, +// a period must be matched explicitly, but a range will match it too + +import ( + "unicode" + "unicode/utf8" +) + +const ( + FNM_NOESCAPE = (1 << iota) + FNM_PATHNAME + FNM_PERIOD + + FNM_LEADING_DIR + FNM_CASEFOLD + + FNM_IGNORECASE = FNM_CASEFOLD + FNM_FILE_NAME = FNM_PATHNAME +) + +func unpackRune(str *string) rune { + rune, size := utf8.DecodeRuneInString(*str) + *str = (*str)[size:] + return rune +} + +// Matches the pattern against the string, with the given flags, +// and returns true if the match is successful. +// This function should match fnmatch.3 as closely as possible. +func Match(pattern, s string, flags int) bool { + // The implementation for this function was patterned after the BSD fnmatch.c + // source found at http://src.gnu-darwin.org/src/contrib/csup/fnmatch.c.html + noescape := (flags&FNM_NOESCAPE != 0) + pathname := (flags&FNM_PATHNAME != 0) + period := (flags&FNM_PERIOD != 0) + leadingdir := (flags&FNM_LEADING_DIR != 0) + casefold := (flags&FNM_CASEFOLD != 0) + // the following is some bookkeeping that the original fnmatch.c implementation did not do + // We are forced to do this because we're not keeping indexes into C strings but rather + // processing utf8-encoded strings. Use a custom unpacker to maintain our state for us + sAtStart := true + sLastAtStart := true + sLastSlash := false + sLastUnpacked := rune(0) + unpackS := func() rune { + sLastSlash = (sLastUnpacked == '/') + sLastUnpacked = unpackRune(&s) + sLastAtStart = sAtStart + sAtStart = false + return sLastUnpacked + } + for len(pattern) > 0 { + c := unpackRune(&pattern) + switch c { + case '?': + if len(s) == 0 { + return false + } + sc := unpackS() + if pathname && sc == '/' { + return false + } + if period && sc == '.' && (sLastAtStart || (pathname && sLastSlash)) { + return false + } + case '*': + // collapse multiple *'s + // don't use unpackRune here, the only char we care to detect is ASCII + for len(pattern) > 0 && pattern[0] == '*' { + pattern = pattern[1:] + } + if period && s[0] == '.' && (sAtStart || (pathname && sLastUnpacked == '/')) { + return false + } + // optimize for patterns with * at end or before / + if len(pattern) == 0 { + if pathname { + return leadingdir || (strchr(s, '/') == -1) + } else { + return true + } + return !(pathname && strchr(s, '/') >= 0) + } else if pathname && pattern[0] == '/' { + offset := strchr(s, '/') + if offset == -1 { + return false + } else { + // we already know our pattern and string have a /, skip past it + s = s[offset:] // use unpackS here to maintain our bookkeeping state + unpackS() + pattern = pattern[1:] // we know / is one byte long + break + } + } + // general case, recurse + for test := s; len(test) > 0; unpackRune(&test) { + // I believe the (flags &^ FNM_PERIOD) is a bug when FNM_PATHNAME is specified + // but this follows exactly from how fnmatch.c implements it + if Match(pattern, test, (flags &^ FNM_PERIOD)) { + return true + } else if pathname && test[0] == '/' { + break + } + } + return false + case '[': + if len(s) == 0 { + return false + } + if pathname && s[0] == '/' { + return false + } + sc := unpackS() + if !rangematch(&pattern, sc, flags) { + return false + } + case '\\': + if !noescape { + if len(pattern) > 0 { + c = unpackRune(&pattern) + } + } + fallthrough + default: + if len(s) == 0 { + return false + } + sc := unpackS() + switch { + case sc == c: + case casefold && unicode.ToLower(sc) == unicode.ToLower(c): + default: + return false + } + } + } + return len(s) == 0 || (leadingdir && s[0] == '/') +} + +func rangematch(pattern *string, test rune, flags int) bool { + if len(*pattern) == 0 { + return false + } + casefold := (flags&FNM_CASEFOLD != 0) + noescape := (flags&FNM_NOESCAPE != 0) + if casefold { + test = unicode.ToLower(test) + } + var negate, matched bool + if (*pattern)[0] == '^' || (*pattern)[0] == '!' { + negate = true + (*pattern) = (*pattern)[1:] + } + for !matched && len(*pattern) > 1 && (*pattern)[0] != ']' { + c := unpackRune(pattern) + if !noescape && c == '\\' { + if len(*pattern) > 1 { + c = unpackRune(pattern) + } else { + return false + } + } + if casefold { + c = unicode.ToLower(c) + } + if (*pattern)[0] == '-' && len(*pattern) > 1 && (*pattern)[1] != ']' { + unpackRune(pattern) // skip the - + c2 := unpackRune(pattern) + if !noescape && c2 == '\\' { + if len(*pattern) > 0 { + c2 = unpackRune(pattern) + } else { + return false + } + } + if casefold { + c2 = unicode.ToLower(c2) + } + // this really should be more intelligent, but it looks like + // fnmatch.c does simple int comparisons, therefore we will as well + if c <= test && test <= c2 { + matched = true + } + } else if c == test { + matched = true + } + } + // skip past the rest of the pattern + ok := false + for !ok && len(*pattern) > 0 { + c := unpackRune(pattern) + if c == '\\' && len(*pattern) > 0 { + unpackRune(pattern) + } else if c == ']' { + ok = true + } + } + return ok && matched != negate +} + +// define strchr because strings.Index() seems a bit overkill +// returns the index of c in s, or -1 if there is no match +func strchr(s string, c rune) int { + for i, sc := range s { + if sc == c { + return i + } + } + return -1 +} |