--[[
@author biggaboy212 & LorekeeperZinnia???
@description Integrated Development Environment to view and edit code within a ROBLOX experience.
]]
local IDEVersion = "8.0"
--// Compatibility
local NewReference = cloneref or function(Ins): Instance
return Ins
end
local Settings = {
Theme = {
Syntax = {
Text = Color3.fromRGB(204, 204, 204),
Background = Color3.fromRGB(20,20,20),
Selection = Color3.fromRGB(255,255,255),
SelectionBack = Color3.fromRGB(102, 161, 255),
Operator = Color3.fromRGB(204, 204, 204),
Number = Color3.fromRGB(255, 198, 0),
String = Color3.fromRGB(172, 240, 148),
Comment = Color3.fromRGB(102, 102, 102),
Keyword = Color3.fromRGB(248, 109, 124),
BuiltIn = Color3.fromRGB(132, 214, 247),
LocalMethod = Color3.fromRGB(253, 251, 172),
LocalProperty = Color3.fromRGB(97, 161, 241),
Nil = Color3.fromRGB(255, 198, 0),
Bool = Color3.fromRGB(255, 198, 0),
Function = Color3.fromRGB(248, 109, 124),
Local = Color3.fromRGB(248, 109, 124),
Self = Color3.fromRGB(248, 109, 124),
FunctionName = Color3.fromRGB(253, 251, 172),
Bracket = Color3.fromRGB(204, 204, 204)
},
}
}
--// Service handlers
local Services = setmetatable({}, {
__index = function(self, Name: string)
local Service = game:GetService(Name)
return NewReference(Service)
end,
})
local UserInputTypes = {
StartAndEnd = {
Enum.UserInputType.MouseButton1,
Enum.UserInputType.Touch
},
Movement = {
Enum.UserInputType.MouseMovement,
Enum.UserInputType.Touch
}
}
--// Services
local Players: Players = Services.Players
local UserInputService: UserInputService = Services.UserInputService
local RunService: RunService = Services.RunService
local TweenService: TweenService = Services.TweenService
local LocalPlayer = NewReference(Players.LocalPlayer)
local Mouse = NewReference(LocalPlayer:GetMouse())
local function Merge(Base, New)
for Key, Value in next, New do
Base[Key] = Value
end
return Base
end
local function InputTypeAllowed(Key, Type: string)
local InputType = Key.UserInputType
return table.find(UserInputTypes[Type], InputType)
end
local function NewInstance(...)
return NewReference(Instance.new(...))
end
local function createSimple(class,props)
local inst = NewInstance(class)
for i,v in next,props do
inst[i] = v
end
return inst
end
local Lib = {}
local cursor = NewInstance("Frame")
Lib.CheckMouseInGui = function(gui)
if gui == nil then return false end
local guiPosition = gui.AbsolutePosition
local guiSize = gui.AbsoluteSize
return Mouse.X >= guiPosition.X and Mouse.X < guiPosition.X + guiSize.X and Mouse.Y >= guiPosition.Y and Mouse.Y < guiPosition.Y + guiSize.Y
end
Lib.Signal = (function()
local funcs = {}
local disconnect = function(con)
local pos = table.find(con.Signal.Connections,con)
if pos then table.remove(con.Signal.Connections,pos) end
end
funcs.Connect = function(self,func)
if type(func) ~= "function" then error("Attempt to connect a non-function") end
local con = {
Signal = self,
Func = func,
Disconnect = disconnect
}
self.Connections[#self.Connections+1] = con
return con
end
funcs.Fire = function(self,...)
for i,v in next,self.Connections do
xpcall(coroutine.wrap(v.Func),function(e) warn(e.."\n"..debug.traceback()) end,...)
end
end
local mt = {
__index = funcs,
__tostring = function(self)
return "Signal: " .. tostring(#self.Connections) .. " Connections"
end
}
local function new()
local obj = {}
obj.Connections = {}
return setmetatable(obj,mt)
end
return {new = new}
end)()
Lib.CreateArrow = function(size,num,dir)
local max = num
local arrowFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Name = "Arrow",
Size = UDim2.new(0,size,0,size)
})
if dir == "up" then
for i = 1,num do
createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-(i-1),0,math.floor(size/2)+i-math.floor(max/2)-1),
Size = UDim2.new(0,i+(i-1),0,1),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "down" then
for i = 1,num do
createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-(i-1),0,math.floor(size/2)-i+math.floor(max/2)+1),
Size = UDim2.new(0,i+(i-1),0,1),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "left" then
for i = 1,num do
createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)+i-math.floor(max/2)-1,0,math.floor(size/2)-(i-1)),
Size = UDim2.new(0,1,0,i+(i-1)),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "right" then
for i = 1,num do
createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-i+math.floor(max/2)+1,0,math.floor(size/2)-(i-1)),
Size = UDim2.new(0,1,0,i+(i-1)),
Parent = arrowFrame
})
end
return arrowFrame
end
error("")
end
Lib.FastWait = (function(arg)
task.wait(arg)
end)
Lib.ScrollBar = (function()
local funcs = {}
local checkMouseInGui = Lib.CheckMouseInGui
local createArrow = Lib.CreateArrow
local function drawThumb(self)
local total = self.TotalSpace
local visible = self.VisibleSpace
local scrollThumb = self.GuiElems.ScrollThumb
local scrollThumbFrame = self.GuiElems.ScrollThumbFrame
if not (self:CanScrollUp() or self:CanScrollDown()) then
scrollThumb.Visible = false
else
scrollThumb.Visible = true
end
if self.Horizontal then
scrollThumb.Size = UDim2.new(visible/total,0,1,0)
if scrollThumb.AbsoluteSize.X < 10 then
scrollThumb.Size = UDim2.new(0,10,1,0)
end
local fs = scrollThumbFrame.AbsoluteSize.X
local bs = scrollThumb.AbsoluteSize.X
scrollThumb.Position = UDim2.new(self:GetScrollPercent()*(fs-bs)/fs,0,0,0)
else
scrollThumb.Size = UDim2.new(1,0,visible/total,0)
if scrollThumb.AbsoluteSize.Y < 10 then
scrollThumb.Size = UDim2.new(1,0,0,10)
end
local fs = scrollThumbFrame.AbsoluteSize.Y
local bs = scrollThumb.AbsoluteSize.Y
scrollThumb.Position = UDim2.new(0,0,self:GetScrollPercent()*(fs-bs)/fs,0)
end
end
local function createFrame(self)
local newFrame = createSimple("Frame",{Style=0,Active=true,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(0.35294118523598,0.35294118523598,0.35294118523598),BackgroundTransparency=0,BorderColor3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=0,ClipsDescendants=false,Draggable=false,Position=UDim2.new(1,-10,0,0),Rotation=0,Selectable=false,Size=UDim2.new(0,10,1,0),SizeConstraint=0,Visible=true,ZIndex=1,Name="ScrollBar",})
local button1 = nil
local button2 = nil
if self.Horizontal then
newFrame.Size = UDim2.new(1,0,0,10)
button1 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Left",
Size = UDim2.new(0,10,0,10),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(10,4,"left").Parent = button1
button2 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Right",
Position = UDim2.new(1,-10,0,0),
Size = UDim2.new(0,10,0,10),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(10,4,"right").Parent = button2
else
newFrame.Size = UDim2.new(0,10,1,0)
button1 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Up",
Size = UDim2.new(0,10,0,10),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(10,4,"up").Parent = button1
button2 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Down",
Position = UDim2.new(0,0,1,-10),
Size = UDim2.new(0,10,0,10),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(10,4,"down").Parent = button2
end
local scrollThumbFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Parent = newFrame
})
if self.Horizontal then
scrollThumbFrame.Position = UDim2.new(0,10,0,0)
scrollThumbFrame.Size = UDim2.new(1,-20,1,0)
else
scrollThumbFrame.Position = UDim2.new(0,0,0,10)
scrollThumbFrame.Size = UDim2.new(1,0,1,-20)
end
local scrollThumb = createSimple("Frame",{
BackgroundColor3 = Color3.new(120/255,120/255,120/255),
BorderSizePixel = 0,
Parent = scrollThumbFrame
})
local markerFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Name = "Markers",
Size = UDim2.new(1,0,1,0),
Parent = scrollThumbFrame
})
local buttonPress = false
local thumbPress = false
local thumbFramePress = false
button1.InputBegan:Connect(function(input)
if InputTypeAllowed(input, "Movement") and not buttonPress and self:CanScrollUp() then button1.BackgroundTransparency = 0.8 end
if not InputTypeAllowed(input, "StartAndEnd") or not self:CanScrollUp() then return end
buttonPress = true
button1.BackgroundTransparency = 0.5
if self:CanScrollUp() then
self:ScrollUp()
self.Scrolled:Fire()
end
local buttonTick = tick()
local releaseEvent
releaseEvent = UserInputService.InputEnded:Connect(function(input)
if not InputTypeAllowed(input, "StartAndEnd") then return end
releaseEvent:Disconnect()
if checkMouseInGui(button1) and self:CanScrollUp() then button1.BackgroundTransparency = 0.8 else button1.BackgroundTransparency = 1 end
buttonPress = false
end)
while buttonPress do
if tick() - buttonTick >= 0.3 and self:CanScrollUp() then
self:ScrollUp()
self.Scrolled:Fire()
end
wait()
end
end)
button1.InputEnded:Connect(function(input)
if InputTypeAllowed(input, "Movement") and not buttonPress then button1.BackgroundTransparency = 1 end
end)
button2.InputBegan:Connect(function(input)
if InputTypeAllowed(input, "Movement") and not buttonPress and self:CanScrollDown() then button2.BackgroundTransparency = 0.8 end
if not InputTypeAllowed(input, "StartAndEnd") or not self:CanScrollDown() then return end
buttonPress = true
button2.BackgroundTransparency = 0.5
if self:CanScrollDown() then
self:ScrollDown()
self.Scrolled:Fire()
end
local buttonTick = tick()
local releaseEvent
releaseEvent = UserInputService.InputEnded:Connect(function(input)
if not InputTypeAllowed(input, "StartAndEnd") then return end
releaseEvent:Disconnect()
if checkMouseInGui(button2) and self:CanScrollDown() then button2.BackgroundTransparency = 0.8 else button2.BackgroundTransparency = 1 end
buttonPress = false
end)
while buttonPress do
if tick() - buttonTick >= 0.3 and self:CanScrollDown() then
self:ScrollDown()
self.Scrolled:Fire()
end
wait()
end
end)
button2.InputEnded:Connect(function(input)
if InputTypeAllowed(input, "Movement") and not buttonPress then button2.BackgroundTransparency = 1 end
end)
scrollThumb.InputBegan:Connect(function(input)
if InputTypeAllowed(input, "Movement") and not thumbPress then
scrollThumb.BackgroundTransparency = 0.2
scrollThumb.BackgroundColor3 = self.ThumbSelectColor
end
if not InputTypeAllowed(input, "StartAndEnd") then return end
local dir = self.Horizontal and "X" or "Y"
local lastThumbPos = nil
buttonPress = false
thumbFramePress = false
thumbPress = true
scrollThumb.BackgroundTransparency = 0
local mouseOffset = Mouse[dir] - scrollThumb.AbsolutePosition[dir]
local releaseEvent
local mouseEvent
releaseEvent = UserInputService.InputEnded:Connect(function(input)
if not InputTypeAllowed(input, "StartAndEnd") then return end
releaseEvent:Disconnect()
if mouseEvent then mouseEvent:Disconnect() end
if checkMouseInGui(scrollThumb) then
scrollThumb.BackgroundTransparency = 0.2
else
scrollThumb.BackgroundTransparency = 0
scrollThumb.BackgroundColor3 = self.ThumbColor
end
thumbPress = false
end)
self:Update()
mouseEvent = UserInputService.InputChanged:Connect(function(input)
if InputTypeAllowed(input, "Movement") and thumbPress and releaseEvent.Connected then
local thumbFrameSize = scrollThumbFrame.AbsoluteSize[dir]-scrollThumb.AbsoluteSize[dir]
local pos = Mouse[dir] - scrollThumbFrame.AbsolutePosition[dir] - mouseOffset
if pos > thumbFrameSize then
pos = thumbFrameSize
elseif pos < 0 then
pos = 0
end
if lastThumbPos ~= pos then
lastThumbPos = pos
self:ScrollTo(math.floor(0.5+pos/thumbFrameSize*(self.TotalSpace-self.VisibleSpace)))
end
wait()
end
end)
end)
scrollThumb.InputEnded:Connect(function(input)
if InputTypeAllowed(input, "Movement") and not thumbPress then
scrollThumb.BackgroundTransparency = 0
scrollThumb.BackgroundColor3 = self.ThumbColor
end
end)
scrollThumbFrame.InputBegan:Connect(function(input)
if not InputTypeAllowed(input, "StartAndEnd") or checkMouseInGui(scrollThumb) then return end
local dir = self.Horizontal and "X" or "Y"
local scrollDir = 0
if Mouse[dir] >= scrollThumb.AbsolutePosition[dir] + scrollThumb.AbsoluteSize[dir] then
scrollDir = 1
end
local function doTick()
local scrollSize = self.VisibleSpace - 1
if scrollDir == 0 and Mouse[dir] < scrollThumb.AbsolutePosition[dir] then
self:ScrollTo(self.Index - scrollSize)
elseif scrollDir == 1 and Mouse[dir] >= scrollThumb.AbsolutePosition[dir] + scrollThumb.AbsoluteSize[dir] then
self:ScrollTo(self.Index + scrollSize)
end
end
thumbPress = false
thumbFramePress = true
doTick()
local thumbFrameTick = tick()
local releaseEvent
releaseEvent = UserInputService.InputEnded:Connect(function(input)
if not InputTypeAllowed(input, "StartAndEnd") then return end
releaseEvent:Disconnect()
thumbFramePress = false
end)
while thumbFramePress do
if tick() - thumbFrameTick >= 0.3 and checkMouseInGui(scrollThumbFrame) then
doTick()
end
wait()
end
end)
newFrame.MouseWheelForward:Connect(function()
self:ScrollTo(self.Index - self.WheelIncrement)
end)
newFrame.MouseWheelBackward:Connect(function()
self:ScrollTo(self.Index + self.WheelIncrement)
end)
self.GuiElems.ScrollThumb = scrollThumb
self.GuiElems.ScrollThumbFrame = scrollThumbFrame
self.GuiElems.Button1 = button1
self.GuiElems.Button2 = button2
self.GuiElems.MarkerFrame = markerFrame
return newFrame
end
funcs.Update = function(self,nocallback)
local total = self.TotalSpace
local visible = self.VisibleSpace
local button1 = self.GuiElems.Button1
local button2 = self.GuiElems.Button2
self.Index = math.clamp(self.Index,0,math.max(0,total-visible))
if self.LastTotalSpace ~= self.TotalSpace then
self.LastTotalSpace = self.TotalSpace
self:UpdateMarkers()
end
if self:CanScrollUp() then
for i,v in pairs(button1.Arrow:GetChildren()) do
v.BackgroundTransparency = 0
end
else
button1.BackgroundTransparency = 1
for i,v in pairs(button1.Arrow:GetChildren()) do
v.BackgroundTransparency = 0.5
end
end
if self:CanScrollDown() then
for i,v in pairs(button2.Arrow:GetChildren()) do
v.BackgroundTransparency = 0
end
else
button2.BackgroundTransparency = 1
for i,v in pairs(button2.Arrow:GetChildren()) do
v.BackgroundTransparency = 0.5
end
end
drawThumb(self)
end
funcs.UpdateMarkers = function(self)
local markerFrame = self.GuiElems.MarkerFrame
markerFrame:ClearAllChildren()
for i,v in pairs(self.Markers) do
if i < self.TotalSpace then
createSimple("Frame",{
BackgroundTransparency = 0,
BackgroundColor3 = v,
BorderSizePixel = 0,
Position = self.Horizontal and UDim2.new(i/self.TotalSpace,0,1,-6) or UDim2.new(1,-6,i/self.TotalSpace,0),
Size = self.Horizontal and UDim2.new(0,1,0,6) or UDim2.new(0,6,0,1),
Name = "Marker"..tostring(i),
Parent = markerFrame
})
end
end
end
funcs.AddMarker = function(self,ind,color)
self.Markers[ind] = color or Color3.new(0,0,0)
end
funcs.ScrollTo = function(self,ind,nocallback)
self.Index = ind
self:Update()
if not nocallback then
self.Scrolled:Fire()
end
end
funcs.ScrollUp = function(self)
self.Index = self.Index - self.Increment
self:Update()
end
funcs.ScrollDown = function(self)
self.Index = self.Index + self.Increment
self:Update()
end
funcs.CanScrollUp = function(self)
return self.Index > 0
end
funcs.CanScrollDown = function(self)
return self.Index + self.VisibleSpace < self.TotalSpace
end
funcs.GetScrollPercent = function(self)
return self.Index/(self.TotalSpace-self.VisibleSpace)
end
funcs.SetScrollPercent = function(self,perc)
self.Index = math.floor(perc*(self.TotalSpace-self.VisibleSpace))
self:Update()
end
funcs.Texture = function(self,data)
self.ThumbColor = data.ThumbColor or Color3.new(0,0,0)
self.ThumbSelectColor = data.ThumbSelectColor or Color3.new(0,0,0)
self.GuiElems.ScrollThumb.BackgroundColor3 = data.ThumbColor or Color3.new(0,0,0)
self.Gui.BackgroundColor3 = data.FrameColor or Color3.new(0,0,0)
self.GuiElems.Button1.BackgroundColor3 = data.ButtonColor or Color3.new(0,0,0)
self.GuiElems.Button2.BackgroundColor3 = data.ButtonColor or Color3.new(0,0,0)
for i,v in pairs(self.GuiElems.Button1.Arrow:GetChildren()) do
v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
end
for i,v in pairs(self.GuiElems.Button2.Arrow:GetChildren()) do
v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
end
end
funcs.SetScrollFrame = function(self,frame)
if self.ScrollUpEvent then
self.ScrollUpEvent:Disconnect()
self.ScrollUpEvent = nil
end
if self.ScrollDownEvent then
self.ScrollDownEvent:Disconnect()
self.ScrollDownEvent = nil
end
self.ScrollUpEvent = frame.MouseWheelForward:Connect(function() self:ScrollTo(self.Index - self.WheelIncrement) end)
self.ScrollDownEvent = frame.MouseWheelBackward:Connect(function() self:ScrollTo(self.Index + self.WheelIncrement) end)
end
local mt = {}
mt.__index = funcs
local function new(hor)
local obj = setmetatable({
Index = 0,
VisibleSpace = 0,
TotalSpace = 0,
Increment = 1,
WheelIncrement = 1,
Markers = {},
GuiElems = {},
Horizontal = hor,
LastTotalSpace = 0,
Scrolled = Lib.Signal.new()
},mt)
obj.Gui = createFrame(obj)
obj:Texture({
ThumbColor = Color3.fromRGB(60,60,60),
ThumbSelectColor = Color3.fromRGB(75,75,75),
ArrowColor = Color3.new(1,1,1),
FrameColor = Color3.fromRGB(40,40,40),
ButtonColor = Color3.fromRGB(75,75,75)
})
return obj
end
return {new = new}
end)()
Lib.CodeFrame = (function()
local funcs = {}
local typeMap = {
[1] = "String",
[2] = "String",
[3] = "String",
[4] = "Comment",
[5] = "Operator",
[6] = "Number",
[7] = "Keyword",
[8] = "BuiltIn",
[9] = "LocalMethod",
[10] = "LocalProperty",
[11] = "Nil",
[12] = "Bool",
[13] = "Function",
[14] = "Local",
[15] = "Self",
[16] = "FunctionName",
[17] = "Bracket"
}
local specialKeywordsTypes = {
["nil"] = 11,
["true"] = 12,
["false"] = 12,
["function"] = 13,
["local"] = 14,
["self"] = 15
}
local keywords = {
["and"] = true,
["break"] = true,
["do"] = true,
["else"] = true,
["elseif"] = true,
["end"] = true,
["false"] = true,
["for"] = true,
["function"] = true,
["if"] = true,
["in"] = true,
["local"] = true,
["nil"] = true,
["not"] = true,
["or"] = true,
["repeat"] = true,
["return"] = true,
["then"] = true,
["true"] = true,
["until"] = true,
["while"] = true,
["plugin"] = true
}
local builtIns = {
["delay"] = true,
["elapsedTime"] = true,
["require"] = true,
["spawn"] = true,
["tick"] = true,
["time"] = true,
["typeof"] = true,
["UserSettings"] = true,
["wait"] = true,
["warn"] = true,
["game"] = true,
["shared"] = true,
["script"] = true,
["workspace"] = true,
["assert"] = true,
["collectgarbage"] = true,
["error"] = true,
["getfenv"] = true,
["getmetatable"] = true,
["ipairs"] = true,
["loadstring"] = true,
["newproxy"] = true,
["next"] = true,
["pairs"] = true,
["pcall"] = true,
["print"] = true,
["rawequal"] = true,
["rawget"] = true,
["rawset"] = true,
["select"] = true,
["setfenv"] = true,
["setmetatable"] = true,
["tonumber"] = true,
["tostring"] = true,
["type"] = true,
["unpack"] = true,
["xpcall"] = true,
["_G"] = true,
["_VERSION"] = true,
["coroutine"] = true,
["debug"] = true,
["math"] = true,
["os"] = true,
["string"] = true,
["table"] = true,
["bit32"] = true,
["utf8"] = true,
["Axes"] = true,
["BrickColor"] = true,
["CFrame"] = true,
["Color3"] = true,
["ColorSequence"] = true,
["ColorSequenceKeypoint"] = true,
["DockWidgetPluginGuiInfo"] = true,
["Enum"] = true,
["Faces"] = true,
["Instance"] = true,
["NumberRange"] = true,
["NumberSequence"] = true,
["NumberSequenceKeypoint"] = true,
["PathWaypoint"] = true,
["PhysicalProperties"] = true,
["Random"] = true,
["Ray"] = true,
["Rect"] = true,
["Region3"] = true,
["Region3int16"] = true,
["TweenInfo"] = true,
["UDim"] = true,
["UDim2"] = true,
["Vector2"] = true,
["Vector2int16"] = true,
["Vector3"] = true,
["Vector3int16"] = true,
--// Libraries
["Drawing"] = true,
["syn"] = true, -- For compatability
["crypt"] = true,
["cache"] = true,
["bit"] = true,
--// Custom Lua Functions
-- File Functions
["readfile"] = true,
["writefile"] = true,
["isfile"] = true,
["appendfile"] = true,
["listfiles"] = true,
["loadfile"] = true,
["isfolder"] = true,
["makefolder"] = true,
["delfolder"] = true,
["delfile"] = true,
-- Misc Functions
["setclipboard"] = true,
["setfflag"] = true,
["getnamecallmethod"] = true,
["isluau"] = true, -- For compatability
["setnonreplicatedproperty"] = true,
["getspecialinfo"] = true,
["saveinstance"] = true,
--[=[ ["messagebox"] = true, ]=] -- Disabled for security
-- Console Functions (for compatability)
["rconsoleprint"] = true,
["rconsoleinfo"] = true,
["rconsolewarn"] = true,
["rconsoleerr"] = true,
["rconsoleclear"] = true,
["rconsolename"] = true,
["rconsoleinput"] = true,
["rconsoleinputasync"] = true,
["printconsole"] = true,
--- Reflection Functions
--[=[ ["loadstring"] = true, ]=] -- Disabled, already stated.
["checkcaller"] = true,
["islclosure"] = true,
["iscclosure"] = true,
["dumpstring"] = true,
["decompile"] = true,
-- Hooking Functions
["hookfunction"] = true,
["newcclosure"] = true,
-- KB/M Functions
["isrbxactive"] = true,
["keypress"] = true,
["keyrelease"] = true,
["mouse1click"] = true,
["mouse1press"] = true,
["mouse1release"] = true,
["mouse2click"] = true,
["mouse2press"] = true,
["mouse2release"] = true,
["mousescroll"] = true,
["mousemoveabs"] = true,
["mousemoverel"] = true,
-- Table Modification Functions
["getrawmetatable"] = true,
["setrawmetatable"] = true,
["setreadonly"] = true,
["isreadonly"] = true,
-- Script Env Functions
["getsenv"] = true,
["getcallingscript"] = true,
-- Env Helping Functions
["getgenv"] = true,
["getrenv"] = true,
["getreg"] = true,
["getgc"] = true,
["getinstances"] = true,
["getnilinstances"] = true,
["getscripts"] = true,
["getloadedmodules"] = true,
["getconnections"] = true,
["firesignal"] = true,
["fireclickdetector"] = true,
["firetouchinterest"] = true,
["fireproximityprompt"] = true
}
local builtInInited = false
local richReplace = {
["'"] = "'",
["\""] = """,
["<"] = "<",
[">"] = ">",
["&"] = "&"
}
local tabSub = "\205"
local tabReplacement = (" %s%s "):format(tabSub,tabSub)
local tabJumps = {
[("[^%s] %s"):format(tabSub,tabSub)] = 0,
[(" %s%s"):format(tabSub,tabSub)] = -1,
[("%s%s "):format(tabSub,tabSub)] = 2,
[("%s [^%s]"):format(tabSub,tabSub)] = 1,
}
local lineTweens = {}
local function initBuiltIn()
local env = getfenv()
local type = type
local tostring = tostring
for name,_ in next,builtIns do
local envVal = env[name]
if type(envVal) == "table" then
local items = {}
for i,v in next,envVal do
items[i] = true
end
builtIns[name] = items
end
end
local enumEntries = {}
local enums = Enum:GetEnums()
for i = 1,#enums do
enumEntries[tostring(enums[i])] = true
end
builtIns["Enum"] = enumEntries
builtInInited = true
end
local function setupEditBox(obj)
local editBox = obj.GuiElems.EditBox
editBox.Focused:Connect(function()
obj:ConnectEditBoxEvent()
obj.Editing = true
end)
editBox.FocusLost:Connect(function()
obj:DisconnectEditBoxEvent()
obj.Editing = false
end)
editBox:GetPropertyChangedSignal("Text"):Connect(function()
local text = editBox.Text
if #text == 0 or obj.EditBoxCopying then return end
text = text:gsub("\t", " ")
editBox.Text = ""
obj:AppendText(text)
end)
end
local function setupMouseSelection(obj)
local codeFrame = obj.GuiElems.LinesFrame
local lines = obj.Lines
codeFrame.InputBegan:Connect(function(input)
if InputTypeAllowed(input, "StartAndEnd") then
local fontSizeX,fontSizeY = math.ceil(obj.FontSize/2),obj.FontSize
local relX = Mouse.X - codeFrame.AbsolutePosition.X
local relY = Mouse.Y - codeFrame.AbsolutePosition.Y
local selX = math.round(relX / fontSizeX) + obj.ViewX
local selY = math.floor(relY / fontSizeY) + obj.ViewY
local releaseEvent,mouseEvent,scrollEvent
local scrollPowerV,scrollPowerH = 0,0
selY = math.min(#lines-1,selY)
local relativeLine = lines[selY+1] or ""
selX = math.min(#relativeLine, selX + obj:TabAdjust(selX,selY))
obj.SelectionRange = {{-1,-1},{-1,-1}}
obj:MoveCursor(selX, selY)
obj.FloatCursorX = selX
local function updateSelection()
local relX = Mouse.X - codeFrame.AbsolutePosition.X
local relY = Mouse.Y - codeFrame.AbsolutePosition.Y
local sel2X = math.max(0,math.round(relX / fontSizeX) + obj.ViewX)
local sel2Y = math.max(0,math.floor(relY / fontSizeY) + obj.ViewY)
sel2Y = math.min(#lines-1,sel2Y)
local relativeLine = lines[sel2Y+1] or ""
sel2X = math.min(#relativeLine, sel2X + obj:TabAdjust(sel2X,sel2Y))
if sel2Y < selY or (sel2Y == selY and sel2X < selX) then
obj.SelectionRange = {{sel2X,sel2Y},{selX,selY}}
else
obj.SelectionRange = {{selX,selY},{sel2X,sel2Y}}
end
obj:MoveCursor(sel2X,sel2Y)
obj.FloatCursorX = sel2X
obj:Refresh()
end
releaseEvent = UserInputService.InputEnded:Connect(function(input)
if InputTypeAllowed(input, "StartAndEnd") then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
scrollEvent:Disconnect()
obj:SetCopyableSelection()
--updateSelection()
end
end)
mouseEvent = UserInputService.InputChanged:Connect(function(input)
if InputTypeAllowed(input, "Movement") then
local upDelta = Mouse.Y - codeFrame.AbsolutePosition.Y
local downDelta = Mouse.Y - codeFrame.AbsolutePosition.Y - codeFrame.AbsoluteSize.Y
local leftDelta = Mouse.X - codeFrame.AbsolutePosition.X
local rightDelta = Mouse.X - codeFrame.AbsolutePosition.X - codeFrame.AbsoluteSize.X
scrollPowerV = 0
scrollPowerH = 0
if downDelta > 0 then
scrollPowerV = math.floor(downDelta*0.05) + 1
elseif upDelta < 0 then
scrollPowerV = math.ceil(upDelta*0.05) - 1
end
if rightDelta > 0 then
scrollPowerH = math.floor(rightDelta*0.05) + 1
elseif leftDelta < 0 then
scrollPowerH = math.ceil(leftDelta*0.05) - 1
end
updateSelection()
end
end)
scrollEvent = RunService.RenderStepped:Connect(function()
if scrollPowerV ~= 0 or scrollPowerH ~= 0 then
obj:ScrollDelta(scrollPowerH,scrollPowerV)
updateSelection()
end
end)
obj:Refresh()
end
end)
end
function funcs.MakeEditorFrame(self)
local frame = NewInstance('TextButton')
frame.BackgroundTransparency = 1
frame.TextTransparency = 1
frame.BackgroundColor3=Color3.fromRGB(40, 40, 40);
frame.BorderSizePixel=0;
frame.Size=UDim2.fromOffset(100,100);
frame.Visible=true;
local elems = {}
local linesFrame = NewInstance("Frame")
linesFrame.Name = "Lines"
linesFrame.BackgroundTransparency = 1
linesFrame.Size = UDim2.new(1,0,1,0)
linesFrame.ClipsDescendants = true
linesFrame.Parent = frame
local lineNumbersLabel = NewInstance("TextLabel")
lineNumbersLabel.Name = "LineNumbers"
lineNumbersLabel.BackgroundTransparency = 1
lineNumbersLabel.FontFace = self.FontFace
lineNumbersLabel.TextXAlignment = Enum.TextXAlignment.Right
lineNumbersLabel.TextYAlignment = Enum.TextYAlignment.Top
lineNumbersLabel.ClipsDescendants = true
lineNumbersLabel.RichText = true
lineNumbersLabel.Parent = frame
cursor.Name = "Cursor"
cursor.BackgroundColor3 = Color3.fromRGB(220,220,220)
cursor.BorderSizePixel = 0
cursor.Parent = frame
local editBox = NewInstance("TextBox")
editBox.Name = "EditBox"
editBox.MultiLine = true
editBox.Visible = false
editBox.Parent = frame
editBox.TextSize = self.FontSize
editBox.FontFace = self.FontFace
lineTweens.Invis = TweenService:Create(cursor,TweenInfo.new(0,Enum.EasingStyle.Quart,Enum.EasingDirection.Out),{BackgroundTransparency = 1})
lineTweens.Vis = TweenService:Create(cursor,TweenInfo.new(0,Enum.EasingStyle.Quart,Enum.EasingDirection.Out),{BackgroundTransparency = 0})
local scrcfrm = NewInstance('Frame')
scrcfrm.BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945);scrcfrm.BorderSizePixel=0;scrcfrm.Name="ScrollCorner";scrcfrm.Position=UDim2.new(1,-10,1,-10);scrcfrm.Size=UDim2.new(0,10,0,10);scrcfrm.Visible=false;
elems.ScrollCorner = scrcfrm
elems.LinesFrame = linesFrame
elems.LineNumbersLabel = lineNumbersLabel
elems.Cursor = cursor
elems.EditBox = editBox
elems.ScrollCorner.Parent = frame
linesFrame.InputBegan:Connect(function(input)
if InputTypeAllowed(input, "StartAndEnd") then
self:SetEditing(true,input)
end
end)
self.Frame = frame
self.Gui = frame
self.GuiElems = elems
setupEditBox(self)
setupMouseSelection(self)
return frame
end
funcs.GetSelectionText = function(self)
if not self:IsValidRange() then return "" end
local selectionRange = self.SelectionRange
local selX,selY = selectionRange[1][1], selectionRange[1][2]
local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]
local deltaLines = sel2Y-selY
local lines = self.Lines
if not lines[selY+1] or not lines[sel2Y+1] then return "" end
if deltaLines == 0 then
return self:ConvertText(lines[selY+1]:sub(selX+1,sel2X), false)
end
local leftSub = lines[selY+1]:sub(selX+1)
local rightSub = lines[sel2Y+1]:sub(1,sel2X)
local result = leftSub.."\n"
for i = selY+1,sel2Y-1 do
result = result..lines[i+1].."\n"
end
result = result..rightSub
return self:ConvertText(result,false)
end
funcs.SetCopyableSelection = function(self)
local text = self:GetSelectionText()
local editBox = self.GuiElems.EditBox
self.EditBoxCopying = true
editBox.Text = text
editBox.SelectionStart = 1
editBox.CursorPosition = #editBox.Text + 1
self.EditBoxCopying = false
end
funcs.ConnectEditBoxEvent = function(self)
if self.EditBoxEvent then
self.EditBoxEvent:Disconnect()
end
self.EditBoxEvent = UserInputService.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.Keyboard then return end
local keycodes = Enum.KeyCode
local keycode = input.KeyCode
local function setupMove(key,func)
local endCon,finished
endCon = UserInputService.InputEnded:Connect(function(input)
if input.KeyCode ~= key then return end
endCon:Disconnect()
finished = true
end)
func()
Lib.FastWait(0.5)
while not finished do
func()
Lib.FastWait(0.03)
end
end
if keycode == keycodes.Down then
setupMove(keycodes.Down,function()
self.CursorX = self.FloatCursorX
self.CursorY = self.CursorY + 1
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Up then
setupMove(keycodes.Up,function()
self.CursorX = self.FloatCursorX
self.CursorY = self.CursorY - 1
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Left then
setupMove(keycodes.Left,function()
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX - 1 - (line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
if self.CursorX < 0 then
self.CursorY = self.CursorY - 1
local line2 = self.Lines[self.CursorY+1] or ""
self.CursorX = #line2
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Right then
setupMove(keycodes.Right,function()
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX + 1 + (line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
if self.CursorX > #line then
self.CursorY = self.CursorY + 1
self.CursorX = 0
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Backspace then
setupMove(keycodes.Backspace,function()
local startRange,endRange
if self:IsValidRange() then
startRange = self.SelectionRange[1]
endRange = self.SelectionRange[2]
else
endRange = {self.CursorX,self.CursorY}
end
if not startRange then
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX - 1 - (line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
if self.CursorX < 0 then
self.CursorY = self.CursorY - 1
local line2 = self.Lines[self.CursorY+1] or ""
self.CursorX = #line2
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
startRange = startRange or {self.CursorX,self.CursorY}
end
self:DeleteRange({startRange,endRange},false,true)
self:ResetSelection(true)
self:JumpToCursor()
end)
elseif keycode == keycodes.Delete then
setupMove(keycodes.Delete,function()
local startRange,endRange
if self:IsValidRange() then
startRange = self.SelectionRange[1]
endRange = self.SelectionRange[2]
else
startRange = {self.CursorX,self.CursorY}
end
if not endRange then
local line = self.Lines[self.CursorY+1] or ""
local endCursorX = self.CursorX + 1 + (line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
local endCursorY = self.CursorY
if endCursorX > #line then
endCursorY = endCursorY + 1
endCursorX = 0
end
self:UpdateCursor()
endRange = endRange or {endCursorX,endCursorY}
end
self:DeleteRange({startRange,endRange},false,true)
self:ResetSelection(true)
self:JumpToCursor()
end)
elseif UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) then
if keycode == keycodes.A then
self.SelectionRange = {{0,5},{#self.Lines[#self.Lines],#self.Lines-1}}
self:SetCopyableSelection()
self:Refresh()
end
end
end)
end
funcs.DisconnectEditBoxEvent = function(self)
if self.EditBoxEvent then
self.EditBoxEvent:Disconnect()
cursor.BackgroundTransparency = 1
funcs.CursorAnim(self, false)
end
end
funcs.ResetSelection = function(self,norefresh)
self.SelectionRange = {{-1,-1},{-1,-1}}
if not norefresh then self:Refresh() end
end
funcs.IsValidRange = function(self,range)
local selectionRange = range or self.SelectionRange
local selX,selY = selectionRange[1][1], selectionRange[1][2]
local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]
if selX == -1 or (selX == sel2X and selY == sel2Y) then return false end
return true
end
funcs.DeleteRange = function(self,range,noprocess,updatemouse)
range = range or self.SelectionRange
if not self:IsValidRange(range) then return end
local lines = self.Lines
local selX,selY = range[1][1], range[1][2]
local sel2X,sel2Y = range[2][1], range[2][2]
local deltaLines = sel2Y-selY
if not lines[selY+1] or not lines[sel2Y+1] then return end
local leftSub = lines[selY+1]:sub(1,selX)
local rightSub = lines[sel2Y+1]:sub(sel2X+1)
lines[selY+1] = leftSub..rightSub
local remove = table.remove
for i = 1,deltaLines do
remove(lines,selY+2)
end
if range == self.SelectionRange then self.SelectionRange = {{-1,-1},{-1,-1}} end
if updatemouse then
self.CursorX = selX
self.CursorY = selY
self:UpdateCursor()
end
if not noprocess then
self:ProcessTextChange()
end
end
funcs.AppendText = function(self,text)
self:DeleteRange(nil,true,true)
local lines,cursorX,cursorY = self.Lines,self.CursorX,self.CursorY
local line = lines[cursorY+1]
local before = line:sub(1,cursorX)
local after = line:sub(cursorX+1)
text = text:gsub("\r\n","\n")
text = self:ConvertText(text,true) -- Tab Convert
local textLines = text:split("\n")
local insert = table.insert
for i = 1,#textLines do
local linePos = cursorY+i
if i > 1 then insert(lines,linePos,"") end
local textLine = textLines[i]
local newBefore = (i == 1 and before or "")
local newAfter = (i == #textLines and after or "")
lines[linePos] = newBefore..textLine..newAfter
end
if #textLines > 1 then cursorX = 0 end
self:ProcessTextChange()
self.CursorX = cursorX + #textLines[#textLines]
self.CursorY = cursorY + #textLines-1
self:UpdateCursor()
end
funcs.ScrollDelta = function(self,x,y)
self.ScrollV:ScrollTo(self.ScrollV.Index + y)
self.ScrollH:ScrollTo(self.ScrollH.Index + x)
end
-- x and y starts at 0
funcs.TabAdjust = function(self,x,y)
local lines = self.Lines
local line = lines[y+1]
x=x+1
if line then
local left = line:sub(x-1,x-1)
local middle = line:sub(x,x)
local right = line:sub(x+1,x+1)
local selRange = (#left > 0 and left or " ") .. (#middle > 0 and middle or " ") .. (#right > 0 and right or " ")
for i,v in pairs(tabJumps) do
if selRange:find(i) then
return v
end
end
end
return 0
end
funcs.SetEditing = function(self,on,input)
if input then
self:UpdateCursor(input)
end
if on then
if self.Editable then
self.GuiElems.EditBox.Text = ""
self.GuiElems.EditBox:CaptureFocus()
end
else
self.GuiElems.EditBox:ReleaseFocus()
end
end
funcs.CursorAnim = function(self,on)
local cursor = self.GuiElems.Cursor
local animTime = tick()
self.LastAnimTime = animTime
if not on then return end
lineTweens.Invis:Cancel()
lineTweens.Vis:Cancel()
cursor.BackgroundTransparency = 0
coroutine.wrap(function()
while self.Editable do
Lib.FastWait(0.5)
if self.LastAnimTime ~= animTime then return end
lineTweens.Invis:Play()
Lib.FastWait(0.5)
if self.LastAnimTime ~= animTime then return end
lineTweens.Vis:Play()
--Lib.FastWait(0.2)
end
end)()
end
funcs.MoveCursor = function(self,x,y)
self.CursorX = x
self.CursorY = y
self:UpdateCursor()
self:JumpToCursor()
end
funcs.JumpToCursor = function(self)
self:Refresh()
end
funcs.UpdateCursor = function(self,input)
local linesFrame = self.GuiElems.LinesFrame
local cursor = self.GuiElems.Cursor
local hSize = math.max(0,linesFrame.AbsoluteSize.X)
local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
local maxLines = math.ceil(vSize / self.FontSize)
local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
local viewX,viewY = self.ViewX,self.ViewY
local totalLinesStr = tostring(#self.Lines)
local fontWidth = math.ceil(self.FontSize / 2)
local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth
if input then
local LinesFrame = self.GuiElems.LinesFrame
local frameX,frameY = LinesFrame.AbsolutePosition.X,LinesFrame.AbsolutePosition.Y
local mouseX,mouseY = input.Position.X,input.Position.Y
local fontSizeX,fontSizeY = math.ceil(self.FontSize/2),self.FontSize
self.CursorX = self.ViewX + math.round((mouseX - frameX) / fontSizeX)
self.CursorY = self.ViewY + math.floor((mouseY - frameY) / fontSizeY)
end
local cursorX,cursorY = self.CursorX,self.CursorY
local line = self.Lines[cursorY+1] or ""
if cursorX > #line then cursorX = #line
elseif cursorX < 0 then cursorX = 0 end
if cursorY >= #self.Lines then
cursorY = math.max(0,#self.Lines-1)
elseif cursorY < 0 then
cursorY = 0
end
cursorX = cursorX + self:TabAdjust(cursorX,cursorY)
-- Update modified
self.CursorX = cursorX
self.CursorY = cursorY
local cursorVisible = (cursorX >= viewX) and (cursorY >= viewY) and (cursorX <= viewX + maxCols) and (cursorY <= viewY + maxLines)
if cursorVisible then
local offX = (cursorX - viewX)
local offY = (cursorY - viewY)
cursor.Position = UDim2.new(0,linesOffset + offX*math.ceil(self.FontSize/2) - 1,0,offY*self.FontSize)
cursor.Size = UDim2.new(0,1,0,self.FontSize+2)
cursor.Visible = true
self:CursorAnim(true)
else
cursor.Visible = false
end
end
funcs.MapNewLines = function(self)
local newLines = {}
local count = 1
local text = self.Text
local find = string.find
local init = 1
local pos = find(text,"\n",init,true)
while pos do
newLines[count] = pos
count = count + 1
init = pos + 1
pos = find(text,"\n",init,true)
end
self.NewLines = newLines
end
funcs.PreHighlight = function(self)
local text = self.Text:gsub("\\\\"," ")
local textLen = #text
local found = {}
local foundMap = {}
local extras = {}
local find = string.find
local sub = string.sub
self.ColoredLines = {}
local function findAll(str,pattern,typ,raw)
local count = #found+1
local init = 1
local x,y,extra = find(str,pattern,init,raw)
while x do
found[count] = x
foundMap[x] = typ
if extra then
extras[x] = extra
end
count = count+1
init = y+1
x,y,extra = find(str,pattern,init,raw)
end
end
findAll(text,'"',1,true)
findAll(text,"'",2,true)
findAll(text,"%[(=*)%[",3)
findAll(text,"--",4,true)
table.sort(found)
local newLines = self.NewLines
local curLine = 0
local lineEnd = 0
local lastEnding = 0
local foundHighlights = {}
for i = 1,#found do
local pos = found[i]
if pos <= lastEnding then continue end
local ending = pos
local typ = foundMap[pos]
if typ == 1 then
ending = find(text,'"',pos+1,true)
while ending and sub(text,ending-1,ending-1) == "\\" do
ending = find(text,'"',ending+1,true)
end
if not ending then ending = textLen end
elseif typ == 2 then
ending = find(text,"'",pos+1,true)
while ending and sub(text,ending-1,ending-1) == "\\" do
ending = find(text,"'",ending+1,true)
end
if not ending then ending = textLen end
elseif typ == 3 then
_,ending = find(text,"]"..extras[pos].."]",pos+1,true)
if not ending then ending = textLen end
elseif typ == 4 then
local ahead = foundMap[pos+2]
if ahead == 3 then
_,ending = find(text,"]"..extras[pos+2].."]",pos+1,true)
if not ending then ending = textLen end
else
ending = find(text,"\n",pos+1,true) or textLen
end
end
while pos > lineEnd do
curLine = curLine + 1
--lineTableCount = 1
lineEnd = newLines[curLine] or textLen+1
end
while true do
local lineTable = foundHighlights[curLine]
if not lineTable then
lineTable = {}
foundHighlights[curLine] = lineTable
end
lineTable[pos] = {typ,ending}
--lineTableCount = lineTableCount + 1
if ending > lineEnd then
curLine = curLine + 1
lineEnd = newLines[curLine] or textLen+1
else
break
end
end
lastEnding = ending
--if i < 200 then print(curLine) end
end
self.PreHighlights = foundHighlights
--print(tick()-start)
--print(#found,curLine)
end
funcs.HighlightLine = function(self,line)
local cached = self.ColoredLines[line]
if cached then return cached end
local sub = string.sub
local find = string.find
local match = string.match
local highlights = {}
local preHighlights = self.PreHighlights[line] or {}
local lineText = self.Lines[line] or ""
local lastEnding = 0
local currentType = 0
local lastWord = nil
local wordBeginsDotted = false
local funcStatus = 0
local lineStart = self.NewLines[line-1] or 0
local preHighlightMap = {}
for pos,data in next,preHighlights do
local relativePos = pos-lineStart
if relativePos < 1 then
currentType = data[1]
lastEnding = data[2] - lineStart
--warn(pos,data[2])
else
preHighlightMap[relativePos] = {data[1],data[2]-lineStart}
end
end
for col = 1,#lineText do
if col <= lastEnding then
highlights[col] = currentType
continue
end
local pre = preHighlightMap[col]
if pre then
currentType = pre[1]
lastEnding = pre[2]
highlights[col] = currentType
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
local char = sub(lineText,col,col)
if find(char,"[%a_]") then
local word = match(lineText,"[%a%d_]+",col)
local wordType = (keywords[word] and 7) or (builtIns[word] and 8)
lastEnding = col+#word-1
if wordType ~= 7 then
if wordBeginsDotted then
local prevBuiltIn = lastWord and builtIns[lastWord]
wordType = (prevBuiltIn and type(prevBuiltIn) == "table" and prevBuiltIn[word] and 8) or 10
end
if wordType ~= 8 then
local x,_,br = find(lineText,"^%s*([%({\"'])",lastEnding+1)
if x then
wordType = (funcStatus > 0 and br == "(" and 16) or 9
funcStatus = 0
end
end
else
wordType = specialKeywordsTypes[word] or wordType
funcStatus = (word == "function" and 1 or 0)
end
lastWord = word
wordBeginsDotted = false
if funcStatus > 0 then funcStatus = 1 end
if wordType then
currentType = wordType
highlights[col] = currentType
else
currentType = nil
end
elseif find(char,"%p") then
local isDot = (char == ".")
local isNum = isDot and find(sub(lineText,col+1,col+1),"%d")
highlights[col] = (isNum and 6 or 5)
if not isNum then
local dotStr = isDot and match(lineText,"%.%.?%.?",col)
if dotStr and #dotStr > 1 then
currentType = 5
lastEnding = col+#dotStr-1
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
if isDot then
if wordBeginsDotted then
lastWord = nil
else
wordBeginsDotted = true
end
else
wordBeginsDotted = false
lastWord = nil
end
funcStatus = ((isDot or char == ":") and funcStatus == 1 and 2) or 0
end
end
elseif find(char,"%d") then
local _,endPos = find(lineText,"%x+",col)
local endPart = sub(lineText,endPos,endPos+1)
if (endPart == "e+" or endPart == "e-") and find(sub(lineText,endPos+2,endPos+2),"%d") then
endPos = endPos + 1
end
currentType = 6
lastEnding = endPos
highlights[col] = 6
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
highlights[col] = currentType
local _,endPos = find(lineText,"%s+",col)
if endPos then
lastEnding = endPos
end
end
end
end
self.ColoredLines[line] = highlights
return highlights
end
funcs.Refresh = function(self)
local linesFrame = self.Frame.Lines
local hSize = math.max(0,linesFrame.AbsoluteSize.X)
local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
local maxLines = math.ceil(vSize / self.FontSize)
local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
local gsub = string.gsub
local sub = string.sub
local viewX,viewY = self.ViewX,self.ViewY
local lineNumberStr = ""
for row = 1,maxLines do
local lineFrame = self.LineFrames[row]
if not lineFrame then
lineFrame = NewInstance("Frame")
lineFrame.Name = "Line"
lineFrame.Position = UDim2.new(0,0,0,(row-1)*self.FontSize)
lineFrame.Size = UDim2.new(1,0,0,self.FontSize)
lineFrame.BorderSizePixel = 0
lineFrame.BackgroundTransparency = 1
local selectionHighlight = NewInstance("Frame")
selectionHighlight.Name = "SelectionHighlight"
selectionHighlight.BorderSizePixel = 0
selectionHighlight.BackgroundColor3 = Settings.Theme.Syntax.SelectionBack
selectionHighlight.Parent = lineFrame
selectionHighlight.BackgroundTransparency = 0.7
local label = NewInstance("TextLabel")
label.Name = "Label"
label.BackgroundTransparency = 1
label.FontFace = self.FontFace
label.TextSize = self.FontSize
label.Size = UDim2.new(1,0,0,self.FontSize)
label.RichText = true
label.TextXAlignment = Enum.TextXAlignment.Left
label.TextColor3 = self.Colors.Text
label.ZIndex = 2
label.Parent = lineFrame
lineFrame.Parent = linesFrame
self.LineFrames[row] = lineFrame
end
local relaY = viewY + row
local lineText = self.Lines[relaY] or ""
local resText = ""
local highlights = self:HighlightLine(relaY)
local colStart = viewX + 1
local richTemplates = self.RichTemplates
local textTemplate = richTemplates.Text
local selectionTemplate = richTemplates.Selection
local curType = highlights[colStart]
local curTemplate = richTemplates[typeMap[curType]] or textTemplate
-- Selection Highlight
local selectionRange = self.SelectionRange
local selPos1 = selectionRange[1]
local selPos2 = selectionRange[2]
local _,selRelaY = viewX,relaY-1
if selRelaY >= selPos1[2] and selRelaY <= selPos2[2] then
local fontSizeX = math.ceil(self.FontSize/2)
local posX = (selRelaY == selPos1[2] and selPos1[1] or 0) - viewX
local sizeX = (selRelaY == selPos2[2] and selPos2[1]-posX-viewX or maxCols+viewX)
lineFrame.SelectionHighlight.Position = UDim2.new(0,posX*fontSizeX,0,0)
lineFrame.SelectionHighlight.Size = UDim2.new(0,sizeX*fontSizeX,1,0)
lineFrame.SelectionHighlight.Visible = true
else
lineFrame.SelectionHighlight.Visible = false
end
for col = 2,maxCols do
local relaX = viewX + col
local posType = highlights[relaX]
if posType ~= curType then
local template = (false and selectionTemplate) or richTemplates[typeMap[posType]] or textTemplate
if template ~= curTemplate then
local nextText = gsub(sub(lineText,colStart,relaX-1),"['\"<>&]", richReplace)
resText = resText .. (curTemplate ~= textTemplate and (curTemplate .. nextText .. "") or nextText)
colStart = relaX
curTemplate = template
end
curType = posType
end
end
local lastText = gsub(sub(lineText,colStart,viewX+maxCols),"['\"<>&]", richReplace)
--warn("SUB",colStart,viewX+maxCols-1)
if #lastText > 0 then
resText = resText .. (curTemplate ~= textTemplate and (curTemplate .. lastText .. "") or lastText)
end
if self.Lines[relaY] then
lineNumberStr = lineNumberStr .. (relaY-1 == self.CursorY and (''..relaY.."\n") or relaY .. "\n")
end
lineFrame.Label.Text = resText
end
for i = maxLines+1,#self.LineFrames do
self.LineFrames[i]:Destroy()
self.LineFrames[i] = nil
end
self.Frame.LineNumbers.Text = lineNumberStr
self:UpdateCursor()
--print("REFRESH TIME",tick()-start)
end
funcs.UpdateView = function(self)
local totalLinesStr = tostring(#self.Lines)
local fontWidth = math.ceil(self.FontSize / 2)
local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth
local linesFrame = self.Frame.Lines
local hSize = linesFrame.AbsoluteSize.X
local vSize = linesFrame.AbsoluteSize.Y
local maxLines = math.ceil(vSize / self.FontSize)
local totalWidth = self.MaxTextCols*fontWidth
local scrollV = self.ScrollV
local scrollH = self.ScrollH
scrollV.VisibleSpace = maxLines
scrollV.TotalSpace = #self.Lines + 1
scrollH.VisibleSpace = math.ceil(hSize/fontWidth)
scrollH.TotalSpace = self.MaxTextCols + 1
scrollV.Gui.Visible = #self.Lines + 1 > maxLines
scrollH.Gui.Visible = totalWidth > hSize
local oldOffsets = self.FrameOffsets
self.FrameOffsets = Vector2.new(scrollV.Gui.Visible and -10 or 0, scrollH.Gui.Visible and -10 or 0)
if oldOffsets ~= self.FrameOffsets then
self:UpdateView()
else
scrollV:ScrollTo(self.ViewY,true)
scrollH:ScrollTo(self.ViewX,true)
if scrollV.Gui.Visible and scrollH.Gui.Visible then
scrollV.Gui.Size = UDim2.new(0,10,1,-10)
scrollH.Gui.Size = UDim2.new(1,-10,0,10)
self.GuiElems.ScrollCorner.Visible = true
else
scrollV.Gui.Size = UDim2.new(0,10,1,0)
scrollH.Gui.Size = UDim2.new(1,0,0,10)
self.GuiElems.ScrollCorner.Visible = false
end
self.ViewY = scrollV.Index
self.ViewX = scrollH.Index
self.Frame.Lines.Position = UDim2.new(0,linesOffset,0,0)
self.Frame.Lines.Size = UDim2.new(1,-linesOffset+oldOffsets.X,1,oldOffsets.Y)
self.Frame.LineNumbers.Position = UDim2.new(0,fontWidth,0,0)
self.Frame.LineNumbers.Size = UDim2.new(0,#totalLinesStr*fontWidth,1,oldOffsets.Y)
self.Frame.LineNumbers.TextSize = self.FontSize
end
end
funcs.ProcessTextChange = function(self)
local maxCols = 0
local lines = self.Lines
for i = 1,#lines do
local lineLen = #lines[i]
if lineLen > maxCols then
maxCols = lineLen
end
end
self.MaxTextCols = maxCols
self:UpdateView()
self.Text = table.concat(self.Lines,"\n")
self:MapNewLines()
self:PreHighlight()
self:Refresh()
--self.TextChanged:Fire()
end
funcs.ConvertText = function(self,text,toEditor)
if toEditor then
local new = text:gsub("\t", " ")
return new:gsub("\t",(" %s%s "):format(tabSub,tabSub))
else
return text:gsub((" %s%s "):format(tabSub,tabSub),"\t")
end
end
funcs.GetText = function(self) -- TODO: better (use new tab format)
local source = table.concat(self.Lines,"\n")
return self:ConvertText(source,false) -- Tab Convert
end
funcs.SetText = function(self,txt)
txt = self:ConvertText(txt,true) -- Tab Convert
local lines = self.Lines
table.clear(lines)
local count = 1
for line in txt:gmatch("([^\n\r]*)[\n\r]?") do
lines[count] = line
count = count + 1
end
self:ProcessTextChange()
end
funcs.ClearText = function(self)
local txt = self:ConvertText('',true)
local lines = self.Lines
table.clear(lines)
local count = 1
for line in txt:gmatch("([^\n\r]*)[\n\r]?") do
lines[count] = line
count = count + 1
end
self:ProcessTextChange()
end
funcs.CompileText = function(self)
local loaded = pcall(function()
local source = table.concat(self.Lines, "\n")
local convertedSource = self:ConvertText(source, false)
loadstring(convertedSource)()
end)
return loaded
end
funcs.ReturnErrors = function(self)
local loaded, err = pcall(function()
local source = table.concat(self.Lines, "\n")
local convertedSource = self:ConvertText(source, false)
loadstring(convertedSource)()
end)
return not loaded and err or nil
end
funcs.GetVersion = function(self)
return IDEVersion
end
funcs.MakeRichTemplates = function(self)
local floor = math.floor
local templates = {}
for name,color in pairs(self.Colors) do
templates[name] = (''):format(floor(color.r*255),floor(color.g*255),floor(color.b*255))
end
self.RichTemplates = templates
end
funcs.ApplyTheme = function(self)
local colors = Settings.Theme.Syntax
self.Colors = colors
self.Frame.LineNumbers.TextColor3 = colors.Text
self.Frame.BackgroundColor3 = colors.Background
end
local mt = {__index = funcs}
local function new(Overwrites)
Overwrites = Overwrites or {}
if not builtInInited then initBuiltIn() end
local scrollV = Lib.ScrollBar.new()
local scrollH = Lib.ScrollBar.new(true)
scrollH.Gui.Position = UDim2.new(0,0,1,-10)
local Base = {
FontFace = Font.fromEnum(Enum.Font.Code),
FontSize = 14,
ViewX = 0,
ViewY = 0,
Colors = Settings.Theme.Syntax,
ColoredLines = {},
Lines = {""},
LineFrames = {},
Editable = true,
Editing = false,
CursorX = 0,
CursorY = 0,
FloatCursorX = 0,
Text = "",
PreHighlights = {},
SelectionRange = {{-1,-1},{-1,-1}},
NewLines = {},
FrameOffsets = Vector2.new(0,0),
MaxTextCols = 0,
ScrollV = scrollV,
ScrollH = scrollH
}
local Properties = Merge(Base, Overwrites)
local obj = setmetatable(Properties, mt)
funcs.SetTextMultiplier = (function(arg)
obj.FontSize = arg
end)
funcs.GetTextMultiplier = (function()
return obj.FontSize
end)
scrollV.WheelIncrement = 3
scrollH.Increment = 2
scrollH.WheelIncrement = 7
scrollV.Scrolled:Connect(function()
obj.ViewY = scrollV.Index
obj:Refresh()
end)
scrollH.Scrolled:Connect(function()
obj.ViewX = scrollH.Index
obj:Refresh()
end)
obj:MakeEditorFrame(obj)
obj:MakeRichTemplates()
obj:ApplyTheme()
scrollV:SetScrollFrame(obj.Frame.Lines)
scrollV.Gui.Parent = obj.Frame
scrollH.Gui.Parent = obj.Frame
obj:UpdateView()
obj:SetText(Properties.Text)
obj.Frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
obj:UpdateView()
obj:Refresh()
end)
return obj
end
return {new = new}
end)()
return Lib