ModuleScript autocomplete

i have this main modulescript that is a parent of all the modules i use

local module = {}

for i, v in script:GetChildren() do
	if v:IsA("ModuleScript") then
		module[v.Name] = require(v)
	end
end

return module

i use it to quickly access all of my modules with only one variable, that variable being

local Modules = require(game.ReplicatedStorage.Modules)

problem is there’s no autocomplete unless i manually add them to the list! like this

local module = {
	["Farter"] = require(script.Farter),
	["Stinkalizer"] = require(script.Stinkalizer)
} return module

im not against manually adding everything, but is there a way to get autocomplete while still being automated? is there a plugin or some trick or maybe some script i could run from the command bar everytime i update the modules children? im just looking for a way to have autocomplete while spending the minimum amount of effort

also, im willing to make my own plugin just for this problem

2 Likes

I’m hoping someone has some exterior knowledge, I also have a similar system and would love an auto-complete added to it, but to my current knowledge there isn’t anything that can autofill modules or functions within the modules!

3 Likes

simple answer, no you can’t

when roblox runs its “autocomplete magic,” it simply doesn’t run any runtime code, it just evaluates what it “thinks” things would be

for example

local module = {}

--v is inferred to be of an Instance type
for i, v in script:GetChildren() do
	if v:IsA("ModuleScript") then
		--because v is an Instance type
		--require(v) is then inferred to be an "any" type
		--v.Name is also inferred to be a "string" type
		module[v.Name] = require(v)
	end
end

return module

that is what Roblox sees

but, you showed you can autocomplete if you write every module seperately
you can make a plugin to do this task, all it would do is fill in the absolute path to generate the modulescript’s source

for example

function GenerateModuleListFor(inst)
	local Source = "local Module = {"
	for i,v in pairs(inst:GetDescendants()) do
		if v:IsA("ModuleScript") then
			--could use string.format but im too lazy
			Source ..= v.Name.. "=require(".. v:GetFullName().. "),"
		end
	end
	Source ..= "} return Module"
	return Source
end

although you do know it would require you to re-make the module list whenever a module

but just know the main drawback of the system is that all of the modules are dependants of the main module, which means you can’t require the main module at all in any of the modules that are children to it.

you could get around the issue above by using metatables

--trick autocomplete using this type
--(it would have to be generated using a plugin like shown above)
export type Modules = {
	Farter: typeof(require(script.Farter)),
	Stinkalizer: typeof(require(script.Stinkalizer)),
}

--assign GlobalModules as type Modules
local GlobalModules : Modules = setmetatable({}, {
	__index = function(self, moduleName)
		local module = require(script:FindFirstChild(moduleName))
		GlobalModules[moduleName] = module
		return module
	end,
})

return GlobalModules

but the main issue with global modules, and probably why roblox hasn’t implemented them is because its hard to tell what the dependants of a script or modulescript is

local Modules = require(game.ReplicatedStorage.Modules)
--^^theres no indication of what modules specifically this script needs


--imagine the lines below are buried in a 700+ line script
Modules.Farter.DoSomething()
Modules.Stinkilizer.DoSomething()

but with roblox’s current bread and butter module system it’ll look like this

local Farter = require(game.ReplicatedStorage.Farter)
local Stinkilizer = require(game.ReplicatedStorage.Stinkilizer)
--^^ now we know exactly what this script needs!
--we know that if we remove all other modules, if we have these two then this script works


--imagine the lines below are buried in a 700+ line script
Farter.DoSomething()
Stinkilizer.DoSomething()

basically, if you need to make a global modulescript, you can using the way i showed, but if you can avoid it, its good coding practice. your future self (and other co-contributers) will thank you

2 Likes

id rather not need to scroll all the way up and add a variable every time i want to use one of my modules. if i need to find out which modules a script uses, which i’ve never needed to do so far, i’ll use ctrl + f. you didn’t really help me, just told me your preference and worded it like it was fact

image
plugins can mess with autocomplete. that’s an example above. im gonna learn it now

yes, I told you the downsides of modulescript autocomplete but I also showed how you can make a plugin to generate your modules script, and a more advanced system using metatables to get around your cyclic require issues (which still produces cyclic requires after testing it unfortunately)…

^^ this is sample module code to generate modulescript source that looks like this

local Module = {Farter=require(game.ReplicatedStorage.Modules.Farter),Stinkalizer=require(game.ReplicatedStorage.Stinkalizer)} return Module

which you simply need to hook into a plugin to run, either manually with a DockWidgetPluginGui or a PluginToolbarButton, or automatically with DescendantAdded and DescendantRemoving

I believe I did help you, I supplied code that explains the easiest “quick and dirty” solution of generating the module itself in a plugin.

Along with messing with autocomplete, unless you’ve figured out a way to do this I wouldn’t. as it would require you to code an entire Luau tokenizer and typing system as the api doesn’t give you any access to typing information.