Skip to content

Commit 137edb9

Browse files
Autocomplete require-by-string (#263)
* Update Luau * Trigger completion on / * Attach require tag * Autocomplete files * Update changelog
1 parent 2b65d08 commit 137edb9

File tree

5 files changed

+59
-3
lines changed

5 files changed

+59
-3
lines changed

CHANGELOG.md

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

1111
- Added syntax highlighting support for interpolated strings
1212
- Added color viewers for Color3.new/fromRGB/fromHSV/fromHex
13+
- Added support for autocompleting require-by-string functions with files and folders
1314
- Support documentation comments on variables:
1415

1516
```lua

luau

Submodule luau updated from be52bd9 to 8649491

src/LanguageServer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ lsp::ServerCapabilities LanguageServer::getServerCapabilities()
6161
lsp::ServerCapabilities capabilities;
6262
capabilities.textDocumentSync = lsp::TextDocumentSyncKind::Incremental;
6363
// Completion
64-
std::vector<std::string> completionTriggerCharacters{".", ":", "'", "\"", "\n"}; // \n is used to trigger end completion
64+
std::vector<std::string> completionTriggerCharacters{".", ":", "'", "\"", "/", "\n"}; // \n is used to trigger end completion
6565
lsp::CompletionOptions::CompletionItem completionItem{/* labelDetailsSupport: */ true};
6666
capabilities.completionProvider = {completionTriggerCharacters, std::nullopt, /* resolveProvider: */ false, completionItem};
6767
// Hover Provider

src/Workspace.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ void WorkspaceFolder::initialize()
164164
Luau::registerBuiltinGlobals(frontend.typeChecker);
165165
Luau::registerBuiltinGlobals(frontend.typeCheckerForAutocomplete);
166166

167+
Luau::attachTag(Luau::getGlobalBinding(frontend.typeCheckerForAutocomplete, "require"), "Require");
168+
167169
if (client->definitionsFiles.empty())
168170
{
169171
client->sendLogMessage(lsp::MessageType::Warning, "No definitions file provided by client");

src/operations/Completion.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ std::vector<lsp::CompletionItem> WorkspaceFolder::completion(const lsp::Completi
312312

313313
auto position = textDocument->convertPosition(params.position);
314314
auto result = Luau::autocomplete(frontend, moduleName, position,
315-
[&](std::string tag, std::optional<const Luau::ClassType*> ctx) -> std::optional<Luau::AutocompleteEntryMap>
315+
[&](std::string tag, std::optional<const Luau::ClassType*> ctx,
316+
std::optional<std::string> contents) -> std::optional<Luau::AutocompleteEntryMap>
316317
{
317318
if (tag == "ClassNames")
318319
{
@@ -372,6 +373,46 @@ std::vector<lsp::CompletionItem> WorkspaceFolder::completion(const lsp::Completi
372373

373374
return result;
374375
}
376+
else if (tag == "Require")
377+
{
378+
if (!contents.has_value())
379+
return std::nullopt;
380+
381+
try
382+
{
383+
auto contentsString = contents.value();
384+
auto currentDirectory = rootUri.fsPath().append(contentsString);
385+
386+
Luau::AutocompleteEntryMap result;
387+
for (const auto& dir_entry : std::filesystem::directory_iterator(currentDirectory))
388+
{
389+
if (dir_entry.is_regular_file() || dir_entry.is_directory())
390+
{
391+
std::string fileName = dir_entry.path().filename().generic_string();
392+
Luau::AutocompleteEntry entry{
393+
Luau::AutocompleteEntryKind::String, frontend.builtinTypes->stringType, false, false, Luau::TypeCorrectKind::Correct};
394+
entry.tags.push_back(dir_entry.is_directory() ? "Directory" : "File");
395+
396+
result.insert_or_assign(fileName, entry);
397+
}
398+
}
399+
400+
// Add in ".." support
401+
if (currentDirectory.has_parent_path())
402+
{
403+
Luau::AutocompleteEntry dotdotEntry{
404+
Luau::AutocompleteEntryKind::String, frontend.builtinTypes->stringType, false, false, Luau::TypeCorrectKind::Correct};
405+
dotdotEntry.tags.push_back("Directory");
406+
result.insert_or_assign("..", dotdotEntry);
407+
}
408+
409+
return result;
410+
}
411+
catch (std::exception&)
412+
{
413+
return std::nullopt;
414+
}
415+
}
375416

376417
return std::nullopt;
377418
});
@@ -424,6 +465,18 @@ std::vector<lsp::CompletionItem> WorkspaceFolder::completion(const lsp::Completi
424465
break;
425466
}
426467

468+
// Special cases: Files and directory
469+
if (std::find(entry.tags.begin(), entry.tags.end(), "File") != entry.tags.end())
470+
{
471+
item.kind = lsp::CompletionItemKind::File;
472+
// We shouldn't include the extension when inserting
473+
std::string insertText = name;
474+
insertText.erase(insertText.find_last_of('.'));
475+
item.insertText = insertText;
476+
}
477+
else if (std::find(entry.tags.begin(), entry.tags.end(), "Directory") != entry.tags.end())
478+
item.kind = lsp::CompletionItemKind::Folder;
479+
427480
// Handle if name is not an identifier
428481
if (entry.kind == Luau::AutocompleteEntryKind::Property && !Luau::isIdentifier(name))
429482
{

0 commit comments

Comments
 (0)