Fix Intellisense not working for saved files (#867)

* Fix tools service to store the corrected file path

* Use ClientFilePath for key

* Further fixes

* Undo spacing changes

* Fix tests

* Trigger CI rebuild
This commit is contained in:
Charles Gagnon
2019-09-19 11:28:40 -07:00
committed by GitHub
parent 9d140b53f3
commit de1bab9f1e
13 changed files with 168 additions and 116 deletions

View File

@@ -29,7 +29,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
/// Main class for the Connection Management services
/// </summary>
public class ConnectionService
{
{
public const string AdminConnectionPrefix = "ADMIN:";
internal const string PasswordPlaceholder = "******";
private const string SqlAzureEdition = "SQL Azure";
@@ -37,7 +37,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
/// <summary>
/// Singleton service instance
/// </summary>
private static readonly Lazy<ConnectionService> instance
private static readonly Lazy<ConnectionService> instance
= new Lazy<ConnectionService>(() => new ConnectionService());
/// <summary>
@@ -56,7 +56,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
/// A map containing all CancellationTokenSource objects that are associated with a given URI/ConnectionType pair.
/// Entries in this map correspond to DbConnection instances that are in the process of connecting.
/// </summary>
private readonly ConcurrentDictionary<CancelTokenKey, CancellationTokenSource> cancelTupleToCancellationTokenSourceMap =
private readonly ConcurrentDictionary<CancelTokenKey, CancellationTokenSource> cancelTupleToCancellationTokenSourceMap =
new ConcurrentDictionary<CancelTokenKey, CancellationTokenSource>();
private readonly object cancellationTokenSourceLock = new object();
@@ -92,7 +92,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
/// Service host object for sending/receiving requests/events.
/// Internal for testing purposes.
/// </summary>
internal IProtocolEndpoint ServiceHost { get; set;}
internal IProtocolEndpoint ServiceHost { get; set; }
/// <summary>
/// Gets the connection queue
@@ -465,16 +465,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
if (SqlAzureEdition.Equals(serverEdition, StringComparison.OrdinalIgnoreCase))
{
switch(serverInfo.EngineEditionId)
switch (serverInfo.EngineEditionId)
{
case (int) DatabaseEngineEdition.SqlDataWarehouse:
case (int)DatabaseEngineEdition.SqlDataWarehouse:
serverEdition = SR.AzureSqlDwEdition;
break;
case (int) DatabaseEngineEdition.SqlStretchDatabase:
case (int)DatabaseEngineEdition.SqlStretchDatabase:
serverEdition = SR.AzureSqlStretchEdition;
break;
default:
serverEdition = SR.AzureSqlDbEdition;
serverEdition = SR.AzureSqlDbEdition;
break;
}
}
@@ -516,7 +516,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
cancelTupleToCancellationTokenSourceMap[cancelKey] = source;
}
// Open the connection
await connection.OpenAsync(source.Token);
}
@@ -599,7 +599,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
throw new InvalidOperationException(SR.ConnectionServiceDbErrorDefaultNotConnected(ownerUri));
}
if(IsDedicatedAdminConnection(connectionInfo.ConnectionDetails))
if (IsDedicatedAdminConnection(connectionInfo.ConnectionDetails))
{
// Since this is a dedicated connection only 1 is allowed at any time. Return the default connection for use in the requested action
connection = defaultConnection;
@@ -618,7 +618,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
return connection;
}
private async Task<DbConnection> TryOpenConnectionForConnectionType(string ownerUri, string connectionType,
private async Task<DbConnection> TryOpenConnectionForConnectionType(string ownerUri, string connectionType,
bool alwaysPersistSecurity, ConnectionInfo connectionInfo)
{
// If the DbConnection does not exist and is not the default connection, create one.
@@ -727,7 +727,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
}
return false;
return false;
}
/// <summary>
@@ -888,14 +888,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
connectionDetails.DatabaseName = "master";
var connection = this.ConnectionFactory.CreateSqlConnection(BuildConnectionString(connectionDetails), connectionDetails.AzureAccountToken);
connection.Open();
List<string> results = new List<string>();
var systemDatabases = new[] {"master", "model", "msdb", "tempdb"};
var systemDatabases = new[] { "master", "model", "msdb", "tempdb" };
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = @"SELECT name FROM sys.databases WHERE state_desc='ONLINE' ORDER BY name ASC";
command.CommandTimeout = 15;
command.CommandType = CommandType.Text;
command.CommandType = CommandType.Text;
using (var reader = command.ExecuteReader())
{
@@ -907,7 +907,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
// Put system databases at the top of the list
results =
results =
results.Where(s => systemDatabases.Any(s.Equals)).Concat(
results.Where(s => systemDatabases.All(x => !s.Equals(x)))).ToList();
@@ -937,9 +937,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
/// Add a new method to be called when the onconnection request is submitted
/// </summary>
/// <param name="activity"></param>
public void RegisterOnConnectionTask(OnConnectionHandler activity)
{
onConnectionActivities.Add(activity);
public void RegisterOnConnectionTask(OnConnectionHandler activity)
{
onConnectionActivities.Add(activity);
}
/// <summary>
@@ -976,7 +976,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
private void RunConnectRequestHandlerTask(ConnectParams connectParams)
{
// create a task to connect asynchronously so that other requests are not blocked in the meantime
Task.Run(async () =>
Task.Run(async () =>
{
try
{
@@ -1017,7 +1017,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
bool result = CancelConnect(cancelParams);
await requestContext.SendResult(result);
}
catch(Exception ex)
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
@@ -1037,7 +1037,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
bool result = Instance.Disconnect(disconnectParams);
await requestContext.SendResult(result);
}
catch(Exception ex)
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
@@ -1058,7 +1058,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
ListDatabasesResponse result = ListDatabases(listDatabasesParams);
await requestContext.SendResult(result);
}
catch(Exception ex)
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
@@ -1075,7 +1075,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
string serverName = builder.DataSource;
return serverName != null && serverName.StartsWith(AdminConnectionPrefix, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Build a connection string from a connection details instance
/// </summary>
@@ -1099,7 +1099,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
{
connectionBuilder = new SqlConnectionStringBuilder(connectionDetails.ConnectionString);
}
else
else
{
// add alternate port to data source property if provided
string dataSource = !connectionDetails.Port.HasValue
@@ -1121,7 +1121,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
if (!string.IsNullOrEmpty(connectionDetails.AuthenticationType))
{
switch(connectionDetails.AuthenticationType)
switch (connectionDetails.AuthenticationType)
{
case "Integrated":
connectionBuilder.IntegratedSecurity = true;
@@ -1364,7 +1364,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
conn.Close();
conn.Dispose();
info.RemoveConnection(key);
string connectionString = BuildConnectionString(info.ConnectionDetails);
// create a sql connection instance
@@ -1377,7 +1377,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
conn.ChangeDatabase(newDatabaseName);
}
}
}
// Fire a connection changed event
@@ -1393,9 +1393,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
Logger.Write(
TraceEventType.Error,
string.Format(
"Exception caught while trying to change database context to [{0}] for OwnerUri [{1}]. Exception:{2}",
newDatabaseName,
ownerUri,
"Exception caught while trying to change database context to [{0}] for OwnerUri [{1}]. Exception:{2}",
newDatabaseName,
ownerUri,
e.ToString())
);
}
@@ -1511,12 +1511,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
catch (Exception ex)
{
string error = string.Format(CultureInfo.InvariantCulture,
string error = string.Format(CultureInfo.InvariantCulture,
"Failed opening a SqlConnection: error:{0} inner:{1} stacktrace:{2}",
ex.Message, ex.InnerException != null ? ex.InnerException.Message : string.Empty, ex.StackTrace);
Logger.Write(TraceEventType.Error, error);
}
return null;
}

View File

@@ -41,7 +41,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
PublishDiagnosticsNotification.Type,
new PublishDiagnosticsNotification
{
Uri = scriptFile.ClientFilePath,
Uri = scriptFile.ClientUri,
Diagnostics =
allMarkers
.Select(GetDiagnosticFromMarker)

View File

@@ -452,7 +452,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientFilePath,
scriptFile.ClientUri,
out connInfo);
var completionItems = await GetCompletionItems(
@@ -514,7 +514,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
DefinitionResult definitionResult = null;
if (scriptFile != null)
{
isConnected = ConnectionServiceInstance.TryFindConnection(scriptFile.ClientFilePath, out connInfo);
isConnected = ConnectionServiceInstance.TryFindConnection(scriptFile.ClientUri, out connInfo);
definitionResult = GetDefinition(textDocumentPosition, scriptFile, connInfo);
}
@@ -723,7 +723,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientFilePath,
scriptFile.ClientUri,
out connInfo);
// check that there is an active connection for the current editor
@@ -809,7 +809,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
foreach (var scriptFile in CurrentWorkspace.GetOpenedFiles())
{
await DiagnosticsHelper.ClearScriptDiagnostics(scriptFile.ClientFilePath, eventContext);
await DiagnosticsHelper.ClearScriptDiagnostics(scriptFile.ClientUri, eventContext);
}
}
// otherwise rerun diagnostic analysis on all opened SQL files
@@ -898,7 +898,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
public ParseResult ParseAndBind(ScriptFile scriptFile, ConnectionInfo connInfo)
{
// get or create the current parse info object
ScriptParseInfo parseInfo = GetScriptParseInfo(scriptFile.ClientFilePath, createIfNotExists: true);
ScriptParseInfo parseInfo = GetScriptParseInfo(scriptFile.ClientUri, createIfNotExists: true);
if (Monitor.TryEnter(parseInfo.BuildingMetadataLock, LanguageService.BindingTimeout))
{
@@ -1130,7 +1130,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
private bool ShouldSkipNonMssqlFile(ScriptFile scriptFile)
{
return ShouldSkipNonMssqlFile(scriptFile.ClientFilePath);
return ShouldSkipNonMssqlFile(scriptFile.ClientUri);
}
/// <summary>
@@ -1335,7 +1335,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
internal DefinitionResult GetDefinition(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ConnectionInfo connInfo)
{
// Parse sql
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(scriptFile.ClientUri);
if (scriptParseInfo == null)
{
return null;
@@ -1450,7 +1450,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
textDocumentPosition.Position.Character);
int endColumn = textDocumentPosition.Position.Character;
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(scriptFile.ClientUri);
if (scriptParseInfo != null && scriptParseInfo.ParseResult != null)
{
if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
@@ -1499,7 +1499,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
int startLine = textDocumentPosition.Position.Line;
int endColumn = textDocumentPosition.Position.Character;
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(scriptFile.ClientUri);
if (scriptParseInfo == null)
{
@@ -1509,7 +1509,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientFilePath,
scriptFile.ClientUri,
out connInfo);
// reparse and bind the SQL statement if needed
@@ -1587,7 +1587,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
bool useLowerCaseSuggestions = this.CurrentWorkspaceSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value;
// get the current script parse info object
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(scriptFile.ClientUri);
if (scriptParseInfo == null)
{
@@ -1672,7 +1672,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
ConnectionInfo connInfo;
ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientFilePath,
scriptFile.ClientUri,
out connInfo);
var parseResult = ParseAndBind(scriptFile, connInfo);
@@ -1797,10 +1797,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
continue;
}
else if (ShouldSkipNonMssqlFile(scriptFile.ClientFilePath))
else if (ShouldSkipNonMssqlFile(scriptFile.ClientUri))
{
// Clear out any existing markers in case file type was changed
await DiagnosticsHelper.ClearScriptDiagnostics(scriptFile.ClientFilePath, eventContext);
await DiagnosticsHelper.ClearScriptDiagnostics(scriptFile.ClientUri, eventContext);
continue;
}
@@ -1884,9 +1884,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <param name="scriptFile"></param>
internal bool IsPreviewWindow(ScriptFile scriptFile)
{
if (scriptFile != null && !string.IsNullOrWhiteSpace(scriptFile.ClientFilePath))
if (scriptFile != null && !string.IsNullOrWhiteSpace(scriptFile.ClientUri))
{
return scriptFile.ClientFilePath.StartsWith("tsqloutput:");
return scriptFile.ClientUri.StartsWith("tsqloutput:");
}
else
{
@@ -1971,4 +1971,4 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
}
}
}
}
}

View File

@@ -138,16 +138,23 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
}
}
internal static ResolvedFile TryGetFullPath(string filePath)
/// <summary>
/// Attempts to resolve the given filePath to an absolute path to a file on disk,
/// defaulting to the original filePath if that fails.
/// </summary>
/// <param name="filePath">The file path to resolve</param>
/// <param name="clientUri">The full file path URI used by the client</param>
/// <returns></returns>
internal static ResolvedFile TryGetFullPath(string filePath, string clientUri)
{
try
{
return new ResolvedFile(Path.GetFullPath(filePath), true);
return new ResolvedFile(Path.GetFullPath(filePath), clientUri, true);
}
catch(NotSupportedException)
{
// This is not a standard path.
return new ResolvedFile(filePath, false);
return new ResolvedFile(filePath, clientUri, false);
}
}
}

View File

@@ -19,20 +19,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
/// </summary>
internal class ResolvedFile
{
public ResolvedFile(string filePath, bool canReadFromDisk)
public ResolvedFile(string filePath, string clientUri, bool canReadFromDisk)
{
FilePath = filePath;
ClientUri = clientUri;
CanReadFromDisk = canReadFromDisk;
}
public string FilePath { get; private set; }
public string ClientUri { get; private set; }
public bool CanReadFromDisk { get; private set; }
public string LowercaseFilePath
public string LowercaseClientUri
{
get
{
return FilePath?.ToLower();
return ClientUri?.ToLower();
}
}
}

View File

@@ -21,11 +21,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// <summary>
/// Gets a unique string that identifies this file. At this time,
/// this property returns a normalized version of the value stored
/// in the FilePath property.
/// in the ClientUri property.
/// </summary>
public string Id
{
get { return this.FilePath.ToLower(); }
get { return this.ClientUri.ToLower(); }
}
/// <summary>
@@ -34,11 +34,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
public string FilePath { get; private set; }
/// <summary>
/// Gets or sets the path which the editor client uses to identify this file.
/// Gets or sets the URI which the editor client uses to identify this file.
/// Setter for testing purposes only
/// virtual to allow mocking.
/// </summary>
public virtual string ClientFilePath { get; internal set; }
public virtual string ClientUri { get; internal set; }
/// <summary>
/// Gets or sets a boolean that determines whether
@@ -103,7 +103,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// </summary>
public ScriptFile()
{
ClientFilePath = "test.sql";
ClientUri = "test.sql";
}
/// <summary>
@@ -111,15 +111,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// the given TextReader.
/// </summary>
/// <param name="filePath">The path at which the script file resides.</param>
/// <param name="clientFilePath">The path which the client uses to identify the file.</param>
/// <param name="clientUri">The URI which the client uses to identify the file.</param>
/// <param name="textReader">The TextReader to use for reading the file's contents.</param>
public ScriptFile(
string filePath,
string clientFilePath,
string clientUri,
TextReader textReader)
{
FilePath = filePath;
ClientFilePath = clientFilePath;
ClientUri = clientUri;
IsAnalysisEnabled = true;
IsInMemory = Workspace.IsPathInMemoryOrNonFileUri(filePath);
@@ -130,15 +130,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace.Contracts
/// Creates a new ScriptFile instance with the specified file contents.
/// </summary>
/// <param name="filePath">The path at which the script file resides.</param>
/// <param name="clientFilePath">The path which the client uses to identify the file.</param>
/// <param name="clientUri">The path which the client uses to identify the file.</param>
/// <param name="initialBuffer">The initial contents of the script file.</param>
public ScriptFile(
string filePath,
string clientFilePath,
string clientUri,
string initialBuffer)
{
FilePath = filePath;
ClientFilePath = clientFilePath;
ClientUri = clientUri;
IsAnalysisEnabled = true;
SetFileContents(initialBuffer);

View File

@@ -70,7 +70,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
// Resolve the full file path
ResolvedFile resolvedFile = this.ResolveFilePath(filePath);
string keyName = resolvedFile.LowercaseFilePath;
string keyName = resolvedFile.LowercaseClientUri;
ScriptFile scriptFile = null;
return this.workspaceFiles.TryGetValue(keyName, out scriptFile);
@@ -98,7 +98,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
// Resolve the full file path
ResolvedFile resolvedFile = this.ResolveFilePath(filePath);
string keyName = resolvedFile.LowercaseFilePath;
string keyName = resolvedFile.LowercaseClientUri;
// Make sure the file isn't already loaded into the workspace
ScriptFile scriptFile = null;
@@ -117,7 +117,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
using (FileStream fileStream = new FileStream(resolvedFile.FilePath, FileMode.Open, FileAccess.Read))
using (StreamReader streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
scriptFile = new ScriptFile(resolvedFile.FilePath, filePath,streamReader);
scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri,streamReader);
this.workspaceFiles.Add(keyName, scriptFile);
}
@@ -128,20 +128,26 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
return scriptFile;
}
private ResolvedFile ResolveFilePath(string filePath)
/// <summary>
/// Resolves a URI identifier into an actual file on disk if it exists.
/// </summary>
/// <param name="clientUri">The URI identifying the file</param>
/// <returns></returns>
private ResolvedFile ResolveFilePath(string clientUri)
{
bool canReadFromDisk = false;
if (!IsPathInMemoryOrNonFileUri(filePath))
string filePath = clientUri;
if (!IsPathInMemoryOrNonFileUri(clientUri))
{
if (filePath.StartsWith(@"file://"))
if (clientUri.StartsWith(@"file://"))
{
// VS Code encodes the ':' character in the drive name, which can lead to problems parsing
// the URI, so unencode it if present. See https://github.com/Microsoft/vscode/issues/2990
filePath = filePath.Replace("%3A/", ":/", StringComparison.OrdinalIgnoreCase);
clientUri = clientUri.Replace("%3A/", ":/", StringComparison.OrdinalIgnoreCase);
// Client sent the path in URI format, extract the local path and trim
// any extraneous slashes
Uri fileUri = new Uri(filePath);
Uri fileUri = new Uri(clientUri);
filePath = fileUri.LocalPath;
if (filePath.StartsWith("//") || filePath.StartsWith("\\\\") || filePath.StartsWith("/"))
{
@@ -154,21 +160,36 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
// into the SqlTools engine.
filePath = UnescapePath(filePath);
// Client paths are handled a bit differently because of how we currently identifiers in
// ADS. The URI is passed around as an identifier - but for things we control like connecting
// an editor the URI we pass in is NOT escaped fully. This is a problem for certain functionality
// which is handled by VS Code - such as Intellise Completion - as the URI passed in there is
// the fully escaped URI. That means we need to do some extra work to make sure that the URI values
// are consistent.
// So to solve that we'll make sure to unescape ALL uri's that are passed in and store that value for
// use as an identifier (filePath will be the actual file path on disk).
// # and ? are still always escaped though by ADS so we need to escape those again to get them to actually
// match
clientUri = Uri.UnescapeDataString(UnescapePath(clientUri));
clientUri = clientUri.Replace("#", "%23");
clientUri = clientUri.Replace("?", "%3F");
// switch to unix path separators on non-Windows platforms
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
filePath = filePath.Replace('\\', '/');
clientUri = clientUri.Replace('\\', '/');
}
// Get the absolute file path
ResolvedFile resolvedFile = FileUtilities.TryGetFullPath(filePath);
ResolvedFile resolvedFile = FileUtilities.TryGetFullPath(filePath, clientUri);
filePath = resolvedFile.FilePath;
canReadFromDisk = resolvedFile.CanReadFromDisk;
}
Logger.Write(TraceEventType.Verbose, "Resolved path: " + filePath);
Logger.Write(TraceEventType.Verbose, "Resolved path: " + clientUri);
return new ResolvedFile(filePath, canReadFromDisk);
return new ResolvedFile(filePath, clientUri, canReadFromDisk);
}
/// <summary>
@@ -204,13 +225,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
// Resolve the full file path
ResolvedFile resolvedFile = this.ResolveFilePath(filePath);
string keyName = resolvedFile.LowercaseFilePath;
string keyName = resolvedFile.LowercaseClientUri;
// Make sure the file isn't already loaded into the workspace
ScriptFile scriptFile = null;
if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile))
{
scriptFile = new ScriptFile(resolvedFile.FilePath, filePath, initialBuffer);
scriptFile = new ScriptFile(resolvedFile.FilePath, resolvedFile.ClientUri, initialBuffer);
this.workspaceFiles.Add(keyName, scriptFile);