aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/hexops/gotextdiff/span/uri.go
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2022-09-05 14:27:54 +0200
committerGitHub <noreply@github.com>2022-09-05 12:27:54 +0000
commitb2f2446b46bf02821d90ebedadae2bf7ae0e880e (patch)
tree923cf42842918d6bebca1d6bbdc08abed54d274d /vendor/github.com/hexops/gotextdiff/span/uri.go
parente6654faff4bcca4be92e9a8596fd4b77f747c39e (diff)
go.mod, vendor: update (#3358)
* go.mod, vendor: remove unnecessary dependencies Commands: 1. go mod tidy 2. go mod vendor * go.mod, vendor: update cloud.google.com/go Commands: 1. go get -u cloud.google.com/go 2. go mod tidy 3. go mod vendor * go.mod, vendor: update cloud.google.com/* Commands: 1. go get -u cloud.google.com/storage cloud.google.com/logging 2. go mod tidy 3. go mod vendor * go.mod, .golangci.yml, vendor: update *lint* Commands: 1. go get -u golang.org/x/tools github.com/golangci/golangci-lint@v1.47.0 2. go mod tidy 3. go mod vendor 4. edit .golangci.yml to suppress new errors (resolved in the same PR later) * all: fix lint errors hash.go: copy() recommended by gosimple parse.go: ent is never nil verifier.go: signal.Notify() with unbuffered channel is bad. Have no idea why. * .golangci.yml: adjust godot rules check-all is deprecated, but still work if you're hesitating too - I'll remove this commit
Diffstat (limited to 'vendor/github.com/hexops/gotextdiff/span/uri.go')
-rw-r--r--vendor/github.com/hexops/gotextdiff/span/uri.go169
1 files changed, 169 insertions, 0 deletions
diff --git a/vendor/github.com/hexops/gotextdiff/span/uri.go b/vendor/github.com/hexops/gotextdiff/span/uri.go
new file mode 100644
index 000000000..250492135
--- /dev/null
+++ b/vendor/github.com/hexops/gotextdiff/span/uri.go
@@ -0,0 +1,169 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package span
+
+import (
+ "fmt"
+ "net/url"
+ "os"
+ "path"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "unicode"
+)
+
+const fileScheme = "file"
+
+// URI represents the full URI for a file.
+type URI string
+
+func (uri URI) IsFile() bool {
+ return strings.HasPrefix(string(uri), "file://")
+}
+
+// Filename returns the file path for the given URI.
+// It is an error to call this on a URI that is not a valid filename.
+func (uri URI) Filename() string {
+ filename, err := filename(uri)
+ if err != nil {
+ panic(err)
+ }
+ return filepath.FromSlash(filename)
+}
+
+func filename(uri URI) (string, error) {
+ if uri == "" {
+ return "", nil
+ }
+ u, err := url.ParseRequestURI(string(uri))
+ if err != nil {
+ return "", err
+ }
+ if u.Scheme != fileScheme {
+ return "", fmt.Errorf("only file URIs are supported, got %q from %q", u.Scheme, uri)
+ }
+ // If the URI is a Windows URI, we trim the leading "/" and lowercase
+ // the drive letter, which will never be case sensitive.
+ if isWindowsDriveURIPath(u.Path) {
+ u.Path = strings.ToUpper(string(u.Path[1])) + u.Path[2:]
+ }
+ return u.Path, nil
+}
+
+func URIFromURI(s string) URI {
+ if !strings.HasPrefix(s, "file://") {
+ return URI(s)
+ }
+
+ if !strings.HasPrefix(s, "file:///") {
+ // VS Code sends URLs with only two slashes, which are invalid. golang/go#39789.
+ s = "file:///" + s[len("file://"):]
+ }
+ // Even though the input is a URI, it may not be in canonical form. VS Code
+ // in particular over-escapes :, @, etc. Unescape and re-encode to canonicalize.
+ path, err := url.PathUnescape(s[len("file://"):])
+ if err != nil {
+ panic(err)
+ }
+
+ // File URIs from Windows may have lowercase drive letters.
+ // Since drive letters are guaranteed to be case insensitive,
+ // we change them to uppercase to remain consistent.
+ // For example, file:///c:/x/y/z becomes file:///C:/x/y/z.
+ if isWindowsDriveURIPath(path) {
+ path = path[:1] + strings.ToUpper(string(path[1])) + path[2:]
+ }
+ u := url.URL{Scheme: fileScheme, Path: path}
+ return URI(u.String())
+}
+
+func CompareURI(a, b URI) int {
+ if equalURI(a, b) {
+ return 0
+ }
+ if a < b {
+ return -1
+ }
+ return 1
+}
+
+func equalURI(a, b URI) bool {
+ if a == b {
+ return true
+ }
+ // If we have the same URI basename, we may still have the same file URIs.
+ if !strings.EqualFold(path.Base(string(a)), path.Base(string(b))) {
+ return false
+ }
+ fa, err := filename(a)
+ if err != nil {
+ return false
+ }
+ fb, err := filename(b)
+ if err != nil {
+ return false
+ }
+ // Stat the files to check if they are equal.
+ infoa, err := os.Stat(filepath.FromSlash(fa))
+ if err != nil {
+ return false
+ }
+ infob, err := os.Stat(filepath.FromSlash(fb))
+ if err != nil {
+ return false
+ }
+ return os.SameFile(infoa, infob)
+}
+
+// URIFromPath returns a span URI for the supplied file path.
+// It will always have the file scheme.
+func URIFromPath(path string) URI {
+ if path == "" {
+ return ""
+ }
+ // Handle standard library paths that contain the literal "$GOROOT".
+ // TODO(rstambler): The go/packages API should allow one to determine a user's $GOROOT.
+ const prefix = "$GOROOT"
+ if len(path) >= len(prefix) && strings.EqualFold(prefix, path[:len(prefix)]) {
+ suffix := path[len(prefix):]
+ path = runtime.GOROOT() + suffix
+ }
+ if !isWindowsDrivePath(path) {
+ if abs, err := filepath.Abs(path); err == nil {
+ path = abs
+ }
+ }
+ // Check the file path again, in case it became absolute.
+ if isWindowsDrivePath(path) {
+ path = "/" + strings.ToUpper(string(path[0])) + path[1:]
+ }
+ path = filepath.ToSlash(path)
+ u := url.URL{
+ Scheme: fileScheme,
+ Path: path,
+ }
+ return URI(u.String())
+}
+
+// isWindowsDrivePath returns true if the file path is of the form used by
+// Windows. We check if the path begins with a drive letter, followed by a ":".
+// For example: C:/x/y/z.
+func isWindowsDrivePath(path string) bool {
+ if len(path) < 3 {
+ return false
+ }
+ return unicode.IsLetter(rune(path[0])) && path[1] == ':'
+}
+
+// isWindowsDriveURI returns true if the file URI is of the format used by
+// Windows URIs. The url.Parse package does not specially handle Windows paths
+// (see golang/go#6027), so we check if the URI path has a drive prefix (e.g. "/C:").
+func isWindowsDriveURIPath(uri string) bool {
+ if len(uri) < 4 {
+ return false
+ }
+ return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':'
+}