3
3
using System . IO ;
4
4
using System . Runtime . InteropServices ;
5
5
using System . Runtime . Versioning ;
6
+ using System . Text . RegularExpressions ;
6
7
using OmniSharp . Extensions . LanguageServer . Protocol . Models ;
7
8
using static System . IO . Path ;
8
9
@@ -14,17 +15,23 @@ namespace OmniSharp.Extensions.LanguageServer.Protocol
14
15
/// <remarks>This exists because of some non-standard serialization in vscode around uris and .NET's behavior when deserializing those uris</remarks>
15
16
public class DocumentUri : IEquatable < DocumentUri >
16
17
{
18
+ private static readonly Regex WindowsPath =
19
+ new Regex ( @"^\w(?:\:|%3a)[\\|\/]" , RegexOptions . Compiled | RegexOptions . IgnoreCase ) ;
20
+
21
+ private readonly string _delimiter = SchemeDelimiter ;
22
+
17
23
/// <summary>
18
24
/// Create a new document uri
19
25
/// </summary>
20
26
/// <param name="url"></param>
21
27
public DocumentUri ( string url )
22
28
{
29
+ var uncMatch = false ;
23
30
var delimiterIndex = url . IndexOf ( SchemeDelimiter , StringComparison . Ordinal ) ;
24
- if ( delimiterIndex == - 1 )
31
+ if ( ( uncMatch = url . StartsWith ( @"\\" ) ) || ( url . StartsWith ( "/" ) ) || ( WindowsPath . IsMatch ( url ) ) )
25
32
{
26
33
// Unc path
27
- if ( url . StartsWith ( " \\ \\ " ) )
34
+ if ( uncMatch )
28
35
{
29
36
var authorityEndIndex = url . IndexOf ( '\\ ' , 2 ) ;
30
37
Authority = url . Substring ( 2 , authorityEndIndex - 2 ) ;
@@ -42,25 +49,36 @@ public DocumentUri(string url)
42
49
Query = string . Empty ;
43
50
Fragment = string . Empty ;
44
51
Path = Uri . UnescapeDataString ( url . StartsWith ( "/" ) ? url : "/" + url ) ;
45
-
46
52
return ;
47
53
}
48
54
49
- Scheme = url . Substring ( 0 , delimiterIndex ) ;
50
-
51
- var authorityIndex = url . IndexOf ( '/' , delimiterIndex + SchemeDelimiter . Length ) ;
52
- Authority = url . Substring ( delimiterIndex + SchemeDelimiter . Length ,
53
- authorityIndex - ( delimiterIndex + SchemeDelimiter . Length ) ) ;
54
-
55
- // this is a possible windows path without the proper tripple slash
56
- // file://c:/some/path.file.cs
57
- // We need deal with this case.
58
- if ( Authority . IndexOf ( ':' ) > - 1 || Authority . IndexOf ( "%3a" , StringComparison . OrdinalIgnoreCase ) > - 1 )
55
+ int authorityIndex ;
56
+ if ( delimiterIndex == - 1 )
59
57
{
58
+ delimiterIndex = url . IndexOf ( ':' ) ;
59
+ authorityIndex = delimiterIndex + 1 ;
60
60
Authority = string . Empty ;
61
- authorityIndex = delimiterIndex + SchemeDelimiter . Length ;
61
+ _delimiter = ":" ;
62
+ }
63
+ else
64
+ {
65
+ var delimiterSize = SchemeDelimiter . Length ;
66
+ authorityIndex = url . IndexOf ( '/' , delimiterIndex + delimiterSize ) ;
67
+ Authority = url . Substring ( delimiterIndex + delimiterSize ,
68
+ authorityIndex - ( delimiterIndex + delimiterSize ) ) ;
69
+
70
+ // this is a possible windows path without the proper tripple slash
71
+ // file://c:/some/path.file.cs
72
+ // We need deal with this case.
73
+ if ( Authority . IndexOf ( ':' ) > - 1 || Authority . IndexOf ( "%3a" , StringComparison . OrdinalIgnoreCase ) > - 1 )
74
+ {
75
+ Authority = string . Empty ;
76
+ authorityIndex = delimiterIndex + delimiterSize ;
77
+ }
62
78
}
63
79
80
+ Scheme = url . Substring ( 0 , delimiterIndex ) ;
81
+
64
82
var fragmentIndex = url . IndexOf ( '#' ) ;
65
83
if ( fragmentIndex > - 1 )
66
84
{
@@ -152,8 +170,16 @@ public Uri ToUri()
152
170
/// </summary>
153
171
/// <returns></returns>
154
172
/// <remarks>This will not a uri encode asian and cyrillic characters</remarks>
155
- public override string ToString ( ) =>
156
- $ "{ Scheme } { SchemeDelimiter } { Authority } { Path } { ( string . IsNullOrWhiteSpace ( Query ) ? "" : "?" + Query ) } { ( string . IsNullOrWhiteSpace ( Fragment ) ? "" : "#" + Fragment ) } ";
173
+ public override string ToString ( )
174
+ {
175
+ if ( string . IsNullOrWhiteSpace ( _stringValue ) )
176
+ {
177
+ _stringValue =
178
+ $ "{ Scheme } { _delimiter } { Authority } { Path } { ( string . IsNullOrWhiteSpace ( Query ) ? "" : "?" + Query ) } { ( string . IsNullOrWhiteSpace ( Fragment ) ? "" : "#" + Fragment ) } ";
179
+ }
180
+
181
+ return _stringValue ;
182
+ }
157
183
158
184
/// <summary>
159
185
/// Gets the file system path prefixed with / for unix platforms
@@ -166,7 +192,7 @@ public string GetFileSystemPath()
166
192
if ( Path . IndexOf ( ':' ) == - 1 && ! ( Scheme == UriSchemeFile && ! string . IsNullOrWhiteSpace ( Authority ) ) )
167
193
return Path ;
168
194
if ( ! string . IsNullOrWhiteSpace ( Authority ) )
169
- return $ " \\ \\ { Authority } { Path } ". Replace ( '/' , '\\ ' ) ;
195
+ return $@ " \\{ Authority } { Path } ". Replace ( '/' , '\\ ' ) ;
170
196
return Path . TrimStart ( '/' ) . Replace ( '/' , '\\ ' ) ;
171
197
}
172
198
@@ -299,6 +325,8 @@ public static DocumentUri From(Uri uri)
299
325
/// </summary>
300
326
public static readonly string SchemeDelimiter = Uri . SchemeDelimiter ;
301
327
328
+ private string _stringValue ;
329
+
302
330
/// <summary>
303
331
/// Get the local file-system path for the specified document URI.
304
332
/// </summary>
0 commit comments