local i=game:GetService("\080\108\097\121\101\114\115")local F=i.LocalPlayer return function(i)local r=i.Util local G=require(script:WaitForChild("\087\105\110\100\111\119"))G.Cmdr=i local h=(require(script:WaitForChild("\065\117\116\111\067\111\109\112\108\101\116\101")))(i)G.AutoComplete=h function G.ProcessEntry(h)h=r.TrimString(h)if#h==0 then return end G:AddLine(G:GetLabel()..(" "..h),Color3.fromRGB(255,223,93))G:AddLine(i.Dispatcher:EvaluateAndRun(h,F,{IsHuman=true}))end function G.OnTextChanged(A)local X=i.Dispatcher:Evaluate(A,F,true)local C=r.SplitString(A)local W=table.remove(C,1)local E=false if X then C=r.MashExcessArguments(C,#X.Object.Args)E=#C==#X.Object.Args end local v=W and#C>0 if(A:sub(#A,#A)):match("\037\115")and not E then v=true C[#C+1]=""end if X and v then local i,F=X:Validate()G:SetIsValidInput(i,("\086\097\108\105\100\097\116\105\111\110 \101\114\114\111\114\115\058 \037\115"):format(F or""))local r={}local W=X:GetArgument(#C)if W then local i=W.TextSegmentInProgress local v=false if W.RawSegmentsAreAutocomplete then for i,F in ipairs(W.RawSegments)do r[i]={F,F}end else local F,G=W:GetAutocomplete()G=G or{}v=G.IsPartial or false for F,G in pairs(F)do r[F]={i,G}end end local q=true if#i>0 then q,F=W:Validate()end if not E and q then G:HideInvalidState()end return h:Show(r,{at=E and(#A-#i)+((A:sub(#A,#A)):match("\037\115")and-1 or 0),prefix=#W.RawSegments==1 and W.Prefix or"",isLast=#X.Arguments==#X.ArgumentDefinitions and#i>0,numArgs=#C;command=X,arg=W,name=W.Name..(W.Required and""or"\063"),type=W.Type.DisplayName,description=q==false and F or W.Object.Description;invalid=not q;isPartial=v})end elseif W and#C==0 then G:SetIsValidInput(true)local F=i.Registry:GetCommand(W)local r if F then r={F.Name;F.Name,options={name=F.Name,description=F.Description}}local i=F.Args and F.Args[1]if type(i)=="\102\117\110\099\116\105\111\110"then i=i(X)end if i and(not i.Optional and i.Default==nil)then G:SetIsValidInput(false,"\084\104\105\115 \099\111\109\109\097\110\100 \104\097\115 \114\101\113\117\105\114\101\100 \097\114\103\117\109\101\110\116\115\046")G:HideInvalidState()end else G:SetIsValidInput(false,("\037\113 \105\115 \110\111\116 \097 \118\097\108\105\100 \099\111\109\109\097\110\100 \110\097\109\101\046 \085\115\101 \116\104\101 \104\101\108\112 \099\111\109\109\097\110\100 \116\111 \115\101\101 \097\108\108 \097\118\097\105\108\097\098\108\101 \099\111\109\109\097\110\100\115\046"):format(W))end local A={r}for F,G in pairs(i.Registry:GetCommandNames())do if W:lower()==(G:lower()):sub(1,#W)and(r==nil or r[1]~=W)then local F=i.Registry:GetCommand(G)A[#A+1]={W,G;options={name=F.Name,description=F.Description}}end end return h:Show(A)end G:SetIsValidInput(false,"\085\115\101 \116\104\101 \104\101\108\112 \099\111\109\109\097\110\100 \116\111 \115\101\101 \097\108\108 \097\118\097\105\108\097\098\108\101 \099\111\109\109\097\110\100\115\046")h:Hide()end G:UpdateLabel()G:UpdateWindowHeight()return{Window=G;AutoComplete=h}end
-- Here be dragons

local Players = game:GetService("Players")
local Player = Players.LocalPlayer

return function(Cmdr)
	local Util = Cmdr.Util

	local Window = require(script:WaitForChild("Window"))
	Window.Cmdr = Cmdr

	local AutoComplete = require(script:WaitForChild("AutoComplete"))(Cmdr)
	Window.AutoComplete = AutoComplete

	-- Sets the Window.ProcessEntry callback so that we can dispatch our commands out
	function Window.ProcessEntry(text)
		text = Util.TrimString(text)

		if #text == 0 then
			return
		end

		Window:AddLine(Window:GetLabel() .. " " .. text, Color3.fromRGB(255, 223, 93))

		Window:AddLine(Cmdr.Dispatcher:EvaluateAndRun(text, Player, {
			IsHuman = true,
		}))
	end

	-- Sets the Window.OnTextChanged callback so we can update the auto complete
	function Window.OnTextChanged(text)
		local command = Cmdr.Dispatcher:Evaluate(text, Player, true)
		local arguments = Util.SplitString(text)
		local commandText = table.remove(arguments, 1)
		local atEnd = false
		if command then
			arguments = Util.MashExcessArguments(arguments, #command.Object.Args)

			atEnd = #arguments == #command.Object.Args
		end

		local entryComplete = commandText and #arguments > 0

		if text:sub(#text, #text):match("%s") and not atEnd then
			entryComplete = true
			arguments[#arguments + 1] = ""
		end

		if command and entryComplete then
			local commandValid, errorText = command:Validate()

			Window:SetIsValidInput(commandValid, ("Validation errors: %s"):format(errorText or ""))

			local acItems = {}

			local lastArgument = command:GetArgument(#arguments)
			if lastArgument then
				local typedText = lastArgument.TextSegmentInProgress

				local isPartial = false
				if lastArgument.RawSegmentsAreAutocomplete then
					for i, segment in ipairs(lastArgument.RawSegments) do
						acItems[i] = { segment, segment }
					end
				else
					local items, options = lastArgument:GetAutocomplete()
					options = options or {}
					isPartial = options.IsPartial or false

					for i, item in pairs(items) do
						acItems[i] = { typedText, item }
					end
				end

				local valid = true

				if #typedText > 0 then
					valid, errorText = lastArgument:Validate()
				end

				if not atEnd and valid then
					Window:HideInvalidState()
				end

				return AutoComplete:Show(acItems, {
					at = atEnd and #text - #typedText + (text:sub(#text, #text):match("%s") and -1 or 0),
					prefix = #lastArgument.RawSegments == 1 and lastArgument.Prefix or "",
					isLast = #command.Arguments == #command.ArgumentDefinitions and #typedText > 0,
					numArgs = #arguments,
					command = command,
					arg = lastArgument,
					name = lastArgument.Name .. (lastArgument.Required and "" or "?"),
					type = lastArgument.Type.DisplayName,
					description = (valid == false and errorText) or lastArgument.Object.Description,
					invalid = not valid,
					isPartial = isPartial,
				})
			end
		elseif commandText and #arguments == 0 then
			Window:SetIsValidInput(true)
			local exactCommand = Cmdr.Registry:GetCommand(commandText)
			local exactMatch
			if exactCommand then
				exactMatch = {
					exactCommand.Name,
					exactCommand.Name,
					options = {
						name = exactCommand.Name,
						description = exactCommand.Description,
					},
				}

				local arg = exactCommand.Args and exactCommand.Args[1]

				if type(arg) == "function" then
					arg = arg(command)
				end

				if arg and (not arg.Optional and arg.Default == nil) then
					Window:SetIsValidInput(false, "This command has required arguments.")
					Window:HideInvalidState()
				end
			else
				Window:SetIsValidInput(
					false,
					("%q is not a valid command name. Use the help command to see all available commands."):format(
						commandText
					)
				)
			end

			local acItems = { exactMatch }
			for _, cmd in pairs(Cmdr.Registry:GetCommandNames()) do
				if
					commandText:lower() == cmd:lower():sub(1, #commandText)
					and (exactMatch == nil or exactMatch[1] ~= commandText)
				then
					local commandObject = Cmdr.Registry:GetCommand(cmd)
					acItems[#acItems + 1] = {
						commandText,
						cmd,
						options = {
							name = commandObject.Name,
							description = commandObject.Description,
						},
					}
				end
			end

			return AutoComplete:Show(acItems)
		end

		Window:SetIsValidInput(false, "Use the help command to see all available commands.")
		AutoComplete:Hide()
	end

	Window:UpdateLabel()
	Window:UpdateWindowHeight()

	return {
		Window = Window,
		AutoComplete = AutoComplete,
	}
end
