Skip to content

Instantly share code, notes, and snippets.

@Mark-Marks
Created January 25, 2026 12:15
Show Gist options
  • Select an option

  • Save Mark-Marks/8673723ad5290279bc78e2519c0fa2fd to your computer and use it in GitHub Desktop.

Select an option

Save Mark-Marks/8673723ad5290279bc78e2519c0fa2fd to your computer and use it in GitHub Desktop.
Smart sync
--!strict
--!optimize 2
local function Color256Fn(set: number): (code: number) -> string
return function(code: number): string
if code < 0 or code > 255 then
error("Code must be between 0 to 255", 2)
end
return string.format(`\x1b[{set};5;%dm`, code)
end
end
local function TrueColorFn(set: number): (r: number, g: number, b: number) -> string
return function(r: number, g: number, b: number): string
if r < 0 or r > 255 then
error("R must be between 0 to 255", 2)
end
if g < 0 or g > 255 then
error("G must be between 0 to 255", 2)
end
if b < 0 or b > 255 then
error("B must be between 0 to 255", 2)
end
return string.format(`\x1b[{set};2;%d;%d;%dm`, r, g, b)
end
end
local CursorMoveTemplates = {
home = "\x1b[H",
goto = "\x1b[%d;%dH",
up = "\x1b[%dA",
down = "\x1b[%dB",
right = "\x1b[%dC",
left = "\x1b[%dD",
nextline = "\x1b[%dE",
prevline = "\x1b[%dF",
gotocol = "\x1b[%dG",
}
local function cursorMove(action: string, ...): string
local template = CursorMoveTemplates[action]
if not template then
return error("UnknownKind", 2)
end
return string.format(template, ...)
end
local EraseTemplates = {
endOf = "\x1b[0J",
startOf = "\x1b[1J",
entire = "\x1b[2J",
savedLines = "\x1b[3J",
endOfLine = "\x1b[0K",
startOfLine = "\x1b[1K",
entireLine = "\x1b[2K",
}
local function erase(
erase: "endOf" | "startOf" | "entire" | "savedLines" | "endOfLine" | "startOfLine" | "entireLine"
): string
return EraseTemplates[erase] or error("UnknownKind", 2)
end
return {
black = "\x1b[30m",
red = "\x1b[31m",
green = "\x1b[32m",
yellow = "\x1b[33m",
blue = "\x1b[34m",
magenta = "\x1b[35m",
cyan = "\x1b[36m",
white = "\x1b[37m",
bright_black = "\x1b[90m",
bright_red = "\x1b[91m",
bright_green = "\x1b[92m",
bright_yellow = "\x1b[93m",
bright_blue = "\x1b[94m",
bright_magenta = "\x1b[95m",
bright_cyan = "\x1b[96m",
bright_white = "\x1b[97m",
color256 = Color256Fn(38),
trueColor = TrueColorFn(38),
bg = {
black = "\x1b[40m",
red = "\x1b[41m",
green = "\x1b[42m",
yellow = "\x1b[43m",
blue = "\x1b[44m",
magenta = "\x1b[45m",
cyan = "\x1b[46m",
white = "\x1b[47m",
bright_black = "\x1b[100m",
bright_red = "\x1b[101m",
bright_green = "\x1b[102m",
bright_yellow = "\x1b[103m",
bright_blue = "\x1b[104m",
bright_magenta = "\x1b[105m",
bright_cyan = "\x1b[106m",
bright_white = "\x1b[107m",
color256 = Color256Fn(48),
trueColor = TrueColorFn(48),
},
dim = "\x1b[2m",
bold = "\x1b[1m",
italic = "\x1b[3m",
underline = "\x1b[4m",
blink = "\x1b[5m",
inverse = "\x1b[7m",
hidden = "\x1b[8m",
strikethrough = "\x1b[9m",
reset = "\x1b[0m",
reset_bold = "\x1b[22m",
reset_dim = "\x1b[22m",
reset_italic = "\x1b[23m",
reset_underline = "\x1b[24m",
reset_blink = "\x1b[25m",
reset_inverse = "\x1b[27m",
reset_hidden = "\x1b[28m",
reset_strikethrough = "\x1b[29m",
reset_color = "\x1b[39m",
reset_bgcolor = "\x1b[49m",
cursorMove = (cursorMove :: any) :: ((action: "home") -> string) & ((action: "goto", line: number, column: number) -> string) & (
(action: "up" | "down" | "right" | "left", amount: number) -> string
) & ((action: "nextline", linesDown: number) -> string) & ((action: "prevline", linesUp: number) -> string) & ((action: "gotocol", column: number) -> string),
erase = erase,
}
local fs = zune.fs
local task = zune.task
local process = zune.process
local platform = zune.platform
local stdpath = fs.path
local function exists(path: string): boolean
return fs.stat(path).kind ~= "none"
end
local function shell_remove(path: string, flags: { recursive: boolean?, force: boolean? }?)
local args = table.create(3)
if flags then
if flags.recursive then
table.insert(args, "-r")
end
if flags.force then
table.insert(args, if platform.os == "windows" then "-Force" else "-f")
end
end
table.insert(args, path)
process.run("rm", args, { shell = if platform.os == "windows" then "pwsh" else "bash" })
end
local function watch_file(path: string, fn: (metadata: Metadata) -> ()): () -> ()
local origin_metadata = fs.metadata(path)
local last_modified = origin_metadata.modified_at
local thread = task.spawn(function()
while true do
task.wait(1)
local metadata = fs.metadata(path)
if last_modified < metadata.modified_at then
last_modified = metadata.modified_at
fn(metadata)
end
end
end)
return function()
task.cancel(thread)
end
end
type WatchEvent = "created" | "modified" | "moved" | "renamed" | "deleted" | "metadata"
local function deep_watch(path: string, fn: (path: string, event: WatchEvent) -> ()): () -> ()
local dtors = {}
local last_modified: { path: string, at: number }? = nil
local watcher = fs.watch(path, function(child_name, events)
local event_path = stdpath.join(path, child_name)
if table.find(events, "modified") then
local metadata = fs.metadata(event_path)
if
last_modified
and last_modified.at == metadata.modified_at
and last_modified.path == event_path
then
return
end
last_modified = { path = event_path, at = metadata.modified_at }
end
if
table.find(events, "deleted")
or table.find(events, "moved")
or table.find(events, "renamed")
then
local dtor = dtors[event_path]
if dtor then
dtor()
dtors[event_path] = nil
elseif fs.stat(event_path).kind == "directory" then
dtors[event_path] = deep_watch(event_path, fn)
end
end
if table.find(events, "created") and fs.stat(event_path).kind == "directory" then
dtors[event_path] = deep_watch(event_path, fn)
end
for _, event in events do
fn(event_path, event :: WatchEvent)
end
end)
local function root_dtor()
watcher:stop()
end
dtors[path] = root_dtor
for _, entry in fs.entries(path) do
if entry.kind ~= "directory" then
continue
end
local child_path = stdpath.join(path, entry.name)
dtors[child_path] = deep_watch(child_path, fn)
end
return function()
for _, dtor in dtors do
dtor()
end
dtors = {}
end
end
return {
exists = exists,
shell_remove = shell_remove,
watch_file = watch_file,
deep_watch = deep_watch,
}
local process = zune.process
local task = zune.task
local Process = {}
local mt = { __index = Process }
type Properties = {
command: string,
args: { string },
options: ProcessOptions,
}
export type Identity = typeof(setmetatable({} :: Properties, {} :: typeof(mt)))
local function constructor(command: string): Identity
local self: Properties = {
command = command,
args = {},
options = {},
}
return setmetatable(self, mt)
end
function Process.argument(self: Identity, argument: string): Identity
table.insert(self.args, argument)
return self
end
function Process.option(
self: Identity,
option: keyof<ProcessOptions>,
value: index<ProcessOptions, keyof<ProcessOptions>>
): Identity
(self.options :: any)[option] = value
return self
end
function Process.inherit_stdout(self: Identity): Identity
return self:option("stdout", "inherit"):option("stderr", "inherit")
end
function Process.create(self: Identity): ProcessChild
return process.create(self.command, self.args, self.options)
end
function Process.run(self: Identity, carry_exit: boolean?): ProcessRunResult
local result = process.run(self.command, self.args, self.options)
if not result.ok and (carry_exit == nil or carry_exit == true) then
error(result.code)
end
return result
end
function Process.spawn(self: Identity): thread
return task.spawn(process.run, self.command, self.args, self.options)
end
function Process.clone(self: Identity): Identity
local clone: Properties = {
command = self.command,
args = table.clone(self.args),
options = table.clone(self.options),
}
return setmetatable(clone, mt)
end
return {
new = constructor,
}
local Process = require("./util/Process")
local fs_util = require("./util/fs")
local ansi = require("./util/ansi")
local fs = zune.fs
local stdpath = fs.path
local function smart_sync(options: {
sourcemap_project: string,
sync_project: string,
source: string,
out: string,
})
local source_dir, out_dir = options.source, options.out
if fs_util.exists(out_dir) then
fs_util.shell_remove(out_dir, { recursive = true, force = true })
end
local pesde = Process.new("pesde"):argument("install"):inherit_stdout()
pesde:run()
fs_util.watch_file("pesde.toml", function()
pesde:spawn()
end)
local zap = Process.new("zap"):argument("net.zap"):inherit_stdout()
zap:run()
fs_util.watch_file("net.zap", function()
zap:spawn()
end)
local regenerate_sourcemap = Process.new("rojo")
:argument("sourcemap")
:argument(options.sourcemap_project)
:argument("-o")
:argument("sourcemap.json")
:inherit_stdout()
regenerate_sourcemap:run()
local darklua = Process.new("darklua")
:argument("process")
:argument("--config")
:argument(".darklua.json")
:option("env", { ROBLOX_DEV = "true" })
:inherit_stdout()
local process_all = darklua:clone():argument(source_dir):argument(out_dir)
process_all:run()
fs_util.deep_watch(source_dir, function(path, event)
if event == "metadata" then
return
end
local local_path = string.sub(path, 4) -- Removes src/ from the beginning of the path
local path_in_out = stdpath.join(out_dir, local_path)
if event == "created" or event == "modified" then
if event == "created" then
regenerate_sourcemap:run()
end
local process_this = darklua:clone():argument(path):argument(path_in_out)
process_this:run()
print(
`{ansi.green}{ansi.bold}[process]{ansi.reset} Synced {ansi.bg.black}{ansi.dim}{path}{ansi.reset} -> {ansi.bg.black}{ansi.dim}{path_in_out}{ansi.reset}`
)
return
end
if event == "deleted" then
fs_util.remove(path_in_out)
print(
`{ansi.green}{ansi.bold}[process]{ansi.reset} Removed {ansi.bg.black}{ansi.dim}{path_in_out}{ansi.reset}`
)
return
end
regenerate_sourcemap:run()
process_all:run()
print(
`{ansi.green}{ansi.bold}[process]{ansi.reset} Triggered reprocess because of {event} @ {path}`
)
end)
Process.new("rojo"):argument("serve"):argument(options.sync_project):inherit_stdout():spawn()
print(
`{ansi.green}{ansi.bold}[process]{ansi.reset} Syncing {ansi.bg.black}{ansi.dim}{source_dir}{ansi.reset} -> {ansi.bg.black}{ansi.dim}{out_dir}{ansi.reset} -> {ansi.bg.black}{ansi.dim}127.0.0.1:34872{ansi.reset}`
)
end
return smart_sync
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment