Skip to content

Commit 728e9ad

Browse files
Switch to using document URI to store managed files (#288)
* Switch to using document URI to store managed files We also have to normalise document URI to lowercase on windows/mac to deal with case insensitive file systems We leave "getTextDocumentFromModuleName" for simplicity * Fix tests * Update changelog
1 parent 6a812d4 commit 728e9ad

18 files changed

+82
-110
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- Changed internal representation of documents to reduce the likelihood of Request Failed for "No managed text document"
12+
913
## [1.16.2] - 2023-02-01
1014

1115
### Fixed

src/DocumentationParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ std::vector<std::string> WorkspaceFolder::getComments(const Luau::ModuleName& mo
380380
return {};
381381

382382
// Get relevant text document
383-
auto textDocument = fileResolver.getTextDocument(moduleName);
383+
auto textDocument = fileResolver.getTextDocumentFromModuleName(moduleName);
384384
bool tempDocument = false;
385385
if (!textDocument)
386386
{

src/LanguageServer.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -476,16 +476,8 @@ void LanguageServer::recomputeDiagnostics(WorkspaceFolderPtr& workspace, const C
476476
// Recompute diagnostics for all currently opened files
477477
else
478478
{
479-
for (const auto& [file, document] : workspace->fileResolver.managedFiles)
480-
{
481-
auto filePath = workspace->fileResolver.resolveToRealPath(file);
482-
if (filePath)
483-
{
484-
485-
auto uri = Uri::file(*filePath);
486-
this->pushDiagnostics(workspace, uri, document.version());
487-
}
488-
}
479+
for (const auto& [_, document] : workspace->fileResolver.managedFiles)
480+
this->pushDiagnostics(workspace, document.uri(), document.version());
489481
}
490482
}
491483
else

src/Workspace.cpp

Lines changed: 14 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,54 +9,41 @@
99

1010
void WorkspaceFolder::openTextDocument(const lsp::DocumentUri& uri, const lsp::DidOpenTextDocumentParams& params)
1111
{
12-
auto moduleName = fileResolver.getModuleName(uri);
12+
auto normalisedUri = fileResolver.normalisedUriString(uri);
13+
1314
fileResolver.managedFiles.emplace(
14-
std::make_pair(moduleName, TextDocument(uri, params.textDocument.languageId, params.textDocument.version, params.textDocument.text)));
15+
std::make_pair(normalisedUri, TextDocument(uri, params.textDocument.languageId, params.textDocument.version, params.textDocument.text)));
16+
1517
// Mark the file as dirty as we don't know what changes were made to it
18+
auto moduleName = fileResolver.getModuleName(uri);
1619
frontend.markDirty(moduleName);
1720
}
1821

1922
void WorkspaceFolder::updateTextDocument(
2023
const lsp::DocumentUri& uri, const lsp::DidChangeTextDocumentParams& params, std::vector<Luau::ModuleName>* markedDirty)
2124
{
22-
auto moduleName = fileResolver.getModuleName(uri);
25+
auto normalisedUri = fileResolver.normalisedUriString(uri);
2326

24-
if (!contains(fileResolver.managedFiles, moduleName))
27+
if (!contains(fileResolver.managedFiles, normalisedUri))
2528
{
26-
// Check if we have the original file URI stored (https://github.com/JohnnyMorganz/luau-lsp/issues/26)
27-
// TODO: can be potentially removed when server generates sourcemap
28-
auto fsPath = uri.fsPath().generic_string();
29-
if (fsPath != moduleName && contains(fileResolver.managedFiles, fsPath))
30-
{
31-
// Change the managed file key to use the new modulename
32-
auto nh = fileResolver.managedFiles.extract(fsPath);
33-
nh.key() = moduleName;
34-
fileResolver.managedFiles.insert(std::move(nh));
35-
}
36-
else
37-
{
38-
client->sendLogMessage(lsp::MessageType::Error, "Text Document not loaded locally: " + uri.toString());
39-
return;
40-
}
29+
client->sendLogMessage(lsp::MessageType::Error, "Text Document not loaded locally: " + uri.toString());
30+
return;
4131
}
42-
auto& textDocument = fileResolver.managedFiles.at(moduleName);
32+
auto& textDocument = fileResolver.managedFiles.at(normalisedUri);
4333
textDocument.update(params.contentChanges, params.textDocument.version);
4434

4535
// Mark the module dirty for the typechecker
36+
auto moduleName = fileResolver.getModuleName(uri);
4637
frontend.markDirty(moduleName, markedDirty);
4738
}
4839

4940
void WorkspaceFolder::closeTextDocument(const lsp::DocumentUri& uri)
5041
{
51-
auto config = client->getConfiguration(rootUri);
52-
auto moduleName = fileResolver.getModuleName(uri);
53-
fileResolver.managedFiles.erase(moduleName);
54-
55-
// Clear out base uri fsPath as well, in case we managed it like that
56-
// TODO: can be potentially removed when server generates sourcemap
57-
fileResolver.managedFiles.erase(uri.fsPath().generic_string());
42+
fileResolver.managedFiles.erase(fileResolver.normalisedUriString(uri));
5843

5944
// Mark the module as dirty as we no longer track its changes
45+
auto config = client->getConfiguration(rootUri);
46+
auto moduleName = fileResolver.getModuleName(uri);
6047
frontend.markDirty(moduleName);
6148

6249
// Refresh workspace diagnostics to clear diagnostics on ignored files
@@ -137,29 +124,6 @@ bool WorkspaceFolder::updateSourceMap()
137124
frontend.typeChecker, instanceTypes, fileResolver, /* TODO - expressiveTypes: */ config.diagnostics.strictDatamodelTypes);
138125
types::registerInstanceTypes(frontend.typeCheckerForAutocomplete, instanceTypes, fileResolver, /* TODO - expressiveTypes: */ true);
139126

140-
// Update managed file paths as they may be converted to virtual
141-
// Check if we have the original file URIs stored (https://github.com/JohnnyMorganz/luau-lsp/issues/26)
142-
std::vector<std::pair<Luau::ModuleName, TextDocument>> movedFiles;
143-
for (auto it = fileResolver.managedFiles.begin(); it != fileResolver.managedFiles.end();)
144-
{
145-
if (!fileResolver.isVirtualPath(it->first))
146-
{
147-
if (auto virtualPath = fileResolver.resolveToVirtualPath(it->first); virtualPath && virtualPath != it->first)
148-
{
149-
// Store the new ModuleName pairing into a vector and remove the old key
150-
movedFiles.emplace_back(std::make_pair(*virtualPath, it->second));
151-
it = fileResolver.managedFiles.erase(it);
152-
continue; // Ensure we continue so we don't increment iterator and skip next element
153-
}
154-
}
155-
156-
it++;
157-
}
158-
159-
// Add any new pairings back into the map
160-
for (auto& pair : movedFiles)
161-
fileResolver.managedFiles.emplace(pair);
162-
163127
return true;
164128
}
165129
else

src/WorkspaceFileResolver.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,33 @@ Luau::ModuleName WorkspaceFileResolver::getModuleName(const Uri& name)
1616

1717
return fsPath;
1818
}
19-
const TextDocument* WorkspaceFileResolver::getTextDocument(const Luau::ModuleName& name) const
19+
20+
const std::string WorkspaceFileResolver::normalisedUriString(const lsp::DocumentUri& uri) const
21+
{
22+
auto uriString = uri.toString();
23+
24+
// As windows/macOS is case insensitive, we lowercase the URI string for simplicitly and to handle
25+
// normalisation issues
26+
#if defined(_WIN32) || defined(__APPLE__)
27+
uriString = toLower(uriString);
28+
#endif
29+
30+
return uriString;
31+
}
32+
33+
const TextDocument* WorkspaceFileResolver::getTextDocument(const lsp::DocumentUri& uri) const
2034
{
21-
auto it = managedFiles.find(name);
35+
auto it = managedFiles.find(normalisedUriString(uri));
2236
if (it != managedFiles.end())
2337
return &it->second;
2438

25-
// HACK: attempting to solve "No managed text document"
26-
// Check to see if we have the file stored using the URI instead
27-
// https://github.com/JohnnyMorganz/luau-lsp/issues/26
28-
if (auto fsPath = resolveToRealPath(name))
29-
{
30-
it = managedFiles.find(fsPath->generic_string());
31-
if (it != managedFiles.end())
32-
return &it->second;
33-
}
39+
return nullptr;
40+
}
41+
42+
const TextDocument* WorkspaceFileResolver::getTextDocumentFromModuleName(const Luau::ModuleName& name) const
43+
{
44+
if (auto filePath = resolveToRealPath(name))
45+
return getTextDocument(Uri::file(*filePath));
3446

3547
return nullptr;
3648
}
@@ -124,7 +136,7 @@ std::optional<Luau::SourceCode> WorkspaceFileResolver::readSource(const Luau::Mo
124136
sourceType = sourceCodeTypeFromPath(realFileName);
125137
}
126138

127-
if (auto textDocument = getTextDocument(name))
139+
if (auto textDocument = getTextDocumentFromModuleName(name))
128140
{
129141
source = textDocument->getText();
130142
}

src/include/LSP/WorkspaceFileResolver.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct WorkspaceFileResolver
2828
PluginNodePtr pluginInfo;
2929

3030
// Currently opened files where content is managed by client
31-
mutable std::unordered_map<Luau::ModuleName, TextDocument> managedFiles;
31+
mutable std::unordered_map</* DocumentUri */ std::string, TextDocument> managedFiles;
3232
mutable std::unordered_map<std::string, Luau::Config> configCache;
3333
// Errors found when loading .luaurc files - only used for the CLI
3434
mutable std::vector<std::pair<std::filesystem::path, std::string>> configErrors;
@@ -42,8 +42,12 @@ struct WorkspaceFileResolver
4242
WorkspaceFileResolver(const Luau::Config defaultConfig)
4343
: defaultConfig(defaultConfig){};
4444

45+
// Handle normalisation to simplify lookup
46+
const std::string normalisedUriString(const lsp::DocumentUri& uri) const;
47+
4548
/// The file is managed by the client, so FS will be out of date
46-
const TextDocument* getTextDocument(const Luau::ModuleName& name) const;
49+
const TextDocument* getTextDocument(const lsp::DocumentUri& uri) const;
50+
const TextDocument* getTextDocumentFromModuleName(const Luau::ModuleName& name) const;
4751

4852
/// The name points to a virtual path (i.e., game/ or ProjectRoot/)
4953
bool isVirtualPath(const Luau::ModuleName& name) const

src/operations/ColorProvider.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ lsp::DocumentColorResult WorkspaceFolder::documentColor(const lsp::DocumentColor
199199
return {};
200200

201201
auto moduleName = fileResolver.getModuleName(params.textDocument.uri);
202-
auto textDocument = fileResolver.getTextDocument(moduleName);
202+
auto textDocument = fileResolver.getTextDocument(params.textDocument.uri);
203203
if (!textDocument)
204-
throw JsonRpcException(lsp::ErrorCode::RequestFailed, "No managed text document for " + moduleName);
204+
throw JsonRpcException(lsp::ErrorCode::RequestFailed, "No managed text document for " + params.textDocument.uri.toString());
205205

206206
// Run the type checker to ensure we are up to date
207207
if (frontend.isDirty(moduleName))

src/operations/Completion.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static constexpr const char* Keywords = "7";
2424
void WorkspaceFolder::endAutocompletion(const lsp::CompletionParams& params)
2525
{
2626
auto moduleName = fileResolver.getModuleName(params.textDocument.uri);
27-
auto document = fileResolver.getTextDocument(moduleName);
27+
auto document = fileResolver.getTextDocument(params.textDocument.uri);
2828
if (!document)
2929
return;
3030
auto position = document->convertPosition(params.position);
@@ -306,9 +306,9 @@ std::vector<lsp::CompletionItem> WorkspaceFolder::completion(const lsp::Completi
306306
}
307307

308308
auto moduleName = fileResolver.getModuleName(params.textDocument.uri);
309-
auto textDocument = fileResolver.getTextDocument(moduleName);
309+
auto textDocument = fileResolver.getTextDocument(params.textDocument.uri);
310310
if (!textDocument)
311-
throw JsonRpcException(lsp::ErrorCode::RequestFailed, "No managed text document for " + moduleName);
311+
throw JsonRpcException(lsp::ErrorCode::RequestFailed, "No managed text document for " + params.textDocument.uri.toString());
312312

313313
auto position = textDocument->convertPosition(params.position);
314314
auto result = Luau::autocomplete(frontend, moduleName, position,

src/operations/Diagnostics.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ lsp::DocumentDiagnosticReport WorkspaceFolder::documentDiagnostics(const lsp::Do
1616
std::unordered_map<std::string /* lsp::DocumentUri */, std::vector<lsp::Diagnostic>> relatedDiagnostics;
1717

1818
auto moduleName = fileResolver.getModuleName(params.textDocument.uri);
19-
auto textDocument = fileResolver.getTextDocument(moduleName);
19+
auto textDocument = fileResolver.getTextDocument(params.textDocument.uri);
2020
if (!textDocument)
2121
return report; // Bail early with empty report - file was likely closed
2222

@@ -47,7 +47,7 @@ lsp::DocumentDiagnosticReport WorkspaceFolder::documentDiagnostics(const lsp::Do
4747
auto fileName = fileResolver.resolveToRealPath(error.moduleName);
4848
if (!fileName || isIgnoredFile(*fileName, config))
4949
continue;
50-
auto diagnostic = createTypeErrorDiagnostic(error, &fileResolver, fileResolver.getTextDocument(error.moduleName));
50+
auto diagnostic = createTypeErrorDiagnostic(error, &fileResolver, fileResolver.getTextDocumentFromModuleName(error.moduleName));
5151
auto uri = Uri::file(*fileName);
5252
auto& currentDiagnostics = relatedDiagnostics[uri.toString()];
5353
currentDiagnostics.emplace_back(diagnostic);
@@ -105,7 +105,7 @@ lsp::WorkspaceDiagnosticReport WorkspaceFolder::workspaceDiagnostics(const lsp::
105105
for (auto uri : files)
106106
{
107107
auto moduleName = fileResolver.getModuleName(uri);
108-
auto document = fileResolver.getTextDocument(moduleName);
108+
auto document = fileResolver.getTextDocument(uri);
109109

110110
lsp::WorkspaceDocumentDiagnosticReport documentReport;
111111
documentReport.uri = uri;

src/operations/DocumentSymbol.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ struct DocumentSymbolsVisitor : public Luau::AstVisitor
139139
std::optional<std::vector<lsp::DocumentSymbol>> WorkspaceFolder::documentSymbol(const lsp::DocumentSymbolParams& params)
140140
{
141141
auto moduleName = fileResolver.getModuleName(params.textDocument.uri);
142-
auto textDocument = fileResolver.getTextDocument(moduleName);
142+
auto textDocument = fileResolver.getTextDocument(params.textDocument.uri);
143143
if (!textDocument)
144-
throw JsonRpcException(lsp::ErrorCode::RequestFailed, "No managed text document for " + moduleName);
144+
throw JsonRpcException(lsp::ErrorCode::RequestFailed, "No managed text document for " + params.textDocument.uri.toString());
145145

146146
// Run the type checker to ensure we are up to date
147147
if (frontend.isDirty(moduleName))

0 commit comments

Comments
 (0)