1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
# Copyright 2017-2020 Palantir Technologies, Inc.
# Copyright 2021- Python Language Server Contributors.
"""A collection of URI utilities with logic built on the VSCode URI library.
https://github.com/Microsoft/vscode-uri/blob/e59cab84f5df6265aed18ae5f43552d3eef13bb9/lib/index.ts
"""
import re
from urllib import parse
from pylsp import IS_WIN
RE_DRIVE_LETTER_PATH = re.compile(r"^\/[a-zA-Z]:")
def urlparse(uri):
"""Parse and decode the parts of a URI."""
scheme, netloc, path, params, query, fragment = parse.urlparse(uri)
return (
parse.unquote(scheme),
parse.unquote(netloc),
parse.unquote(path),
parse.unquote(params),
parse.unquote(query),
parse.unquote(fragment),
)
def urlunparse(parts):
"""Unparse and encode parts of a URI."""
scheme, netloc, path, params, query, fragment = parts
# Avoid encoding the windows drive letter colon
if RE_DRIVE_LETTER_PATH.match(path):
quoted_path = path[:3] + parse.quote(path[3:])
else:
quoted_path = parse.quote(path)
return parse.urlunparse(
(
parse.quote(scheme),
parse.quote(netloc),
quoted_path,
parse.quote(params),
parse.quote(query),
parse.quote(fragment),
)
)
def to_fs_path(uri):
"""Returns the filesystem path of the given URI.
Will handle UNC paths and normalize windows drive letters to lower-case. Also
uses the platform specific path separator. Will *not* validate the path for
invalid characters and semantics. Will *not* look at the scheme of this URI.
"""
# scheme://netloc/path;parameters?query#fragment
scheme, netloc, path, _params, _query, _fragment = urlparse(uri)
if netloc and path and scheme == "file":
# unc path: file://shares/c$/far/boo
value = "//{}{}".format(netloc, path)
elif RE_DRIVE_LETTER_PATH.match(path):
# windows drive letter: file:///C:/far/boo
value = path[1].lower() + path[2:]
else:
# Other path
value = path
if IS_WIN:
value = value.replace("/", "\\")
return value
def from_fs_path(path):
"""Returns a URI for the given filesystem path."""
scheme = "file"
params, query, fragment = "", "", ""
path, netloc = _normalize_win_path(path)
return urlunparse((scheme, netloc, path, params, query, fragment))
def uri_with(
uri, scheme=None, netloc=None, path=None, params=None, query=None, fragment=None
):
"""Return a URI with the given part(s) replaced.
Parts are decoded / encoded.
"""
old_scheme, old_netloc, old_path, old_params, old_query, old_fragment = urlparse(
uri
)
path, _netloc = _normalize_win_path(path)
return urlunparse(
(
scheme or old_scheme,
netloc or old_netloc,
path or old_path,
params or old_params,
query or old_query,
fragment or old_fragment,
)
)
def _normalize_win_path(path):
netloc = ""
# normalize to fwd-slashes on windows,
# on other systems bwd-slaches are valid
# filename character, eg /f\oo/ba\r.txt
if IS_WIN:
path = path.replace("\\", "/")
# check for authority as used in UNC shares
# or use the path as given
if path[:2] == "//":
idx = path.index("/", 2)
if idx == -1:
netloc = path[2:]
else:
netloc = path[2:idx]
path = path[idx:]
# Ensure that path starts with a slash
# or that it is at least a slash
if not path.startswith("/"):
path = "/" + path
# Normalize drive paths to lower case
if RE_DRIVE_LETTER_PATH.match(path):
path = path[0] + path[1].lower() + path[2:]
return path, netloc
|