mirror of
https://github.com/lune-org/lune.git
synced 2024-12-14 06:00:42 +00:00
326 lines
6.5 KiB
Markdown
326 lines
6.5 KiB
Markdown
<!-- markdownlint-disable MD033 -->
|
|
<!-- markdownlint-disable MD026 -->
|
|
|
|
# ✏️ Writing Lune Scripts
|
|
|
|
If you've already written some version of Lua (or Luau) scripts before, this walkthrough will make you feel right at home.
|
|
|
|
Once you have a script you want to run, head over to the [Running Scripts](https://lune.gitbook.io/lune/home/running-scripts) page.
|
|
|
|
## Hello, Lune!
|
|
|
|
```lua
|
|
--[[
|
|
EXAMPLE #1
|
|
|
|
Using arguments given to the program
|
|
]]
|
|
|
|
if #process.args > 0 then
|
|
print("Got arguments:")
|
|
print(process.args)
|
|
if #process.args > 3 then
|
|
error("Too many arguments!")
|
|
end
|
|
else
|
|
print("Got no arguments ☹️")
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #2
|
|
|
|
Using the stdio library to prompt for terminal input
|
|
]]
|
|
|
|
local text = stdio.prompt("text", "Please write some text")
|
|
|
|
print("You wrote '" .. text .. "'!")
|
|
|
|
local confirmed = stdio.prompt("confirm", "Please confirm that you wrote some text")
|
|
if confirmed == false then
|
|
error("You didn't confirm!")
|
|
else
|
|
print("Confirmed!")
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #3
|
|
|
|
Get & set environment variables
|
|
|
|
Checks if environment variables are empty or not,
|
|
prints out ❌ if empty and ✅ if they have a value
|
|
]]
|
|
|
|
print("Reading current environment 🔎")
|
|
|
|
-- Environment variables can be read directly
|
|
assert(process.env.PATH ~= nil, "Missing PATH")
|
|
assert(process.env.PWD ~= nil, "Missing PWD")
|
|
|
|
-- And they can also be accessed using Luau's generalized iteration (but not pairs())
|
|
for key, value in process.env do
|
|
local box = if value and value ~= "" then "✅" else "❌"
|
|
print(string.format("[%s] %s", box, key))
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #4
|
|
|
|
Writing a module
|
|
|
|
Modularizing and splitting up your code is Lune is very straight-forward,
|
|
in contrast to other scripting languages and shells such as bash
|
|
]]
|
|
|
|
local module = {}
|
|
|
|
function module.sayHello()
|
|
print("Hello, Lune! 🌙")
|
|
end
|
|
|
|
return module
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #5
|
|
|
|
Using a function from another module / script
|
|
|
|
Lune has path-relative imports, similar to other popular languages such as JavaScript
|
|
]]
|
|
|
|
local module = require("../modules/module")
|
|
module.sayHello()
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #6
|
|
|
|
Spawning concurrent tasks
|
|
|
|
These tasks will run at the same time as other Lua code which lets you do primitive multitasking
|
|
]]
|
|
|
|
task.spawn(function()
|
|
print("Spawned a task that will run instantly but not block")
|
|
task.wait(5)
|
|
end)
|
|
|
|
print("Spawning a delayed task that will run in 5 seconds")
|
|
task.delay(5, function()
|
|
print("...")
|
|
task.wait(1)
|
|
print("Hello again!")
|
|
task.wait(1)
|
|
print("Goodbye again! 🌙")
|
|
end)
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #7
|
|
|
|
Read files in the current directory
|
|
|
|
This prints out directory & file names with some fancy icons
|
|
]]
|
|
|
|
print("Reading current dir 🗂️")
|
|
local entries = fs.readDir(".")
|
|
|
|
-- NOTE: We have to do this outside of the sort function
|
|
-- to avoid yielding across the metamethod boundary, all
|
|
-- of the filesystem APIs are asynchronous and yielding
|
|
local entryIsDir = {}
|
|
for _, entry in entries do
|
|
entryIsDir[entry] = fs.isDir(entry)
|
|
end
|
|
|
|
-- Sort prioritizing directories first, then alphabetically
|
|
table.sort(entries, function(entry0, entry1)
|
|
if entryIsDir[entry0] ~= entryIsDir[entry1] then
|
|
return entryIsDir[entry0]
|
|
end
|
|
return entry0 < entry1
|
|
end)
|
|
|
|
-- Make sure we got some known files that should always exist
|
|
assert(table.find(entries, "Cargo.toml") ~= nil, "Missing Cargo.toml")
|
|
assert(table.find(entries, "Cargo.lock") ~= nil, "Missing Cargo.lock")
|
|
|
|
-- Print the pretty stuff
|
|
for _, entry in entries do
|
|
if fs.isDir(entry) then
|
|
print("📁 " .. entry)
|
|
else
|
|
print("📄 " .. entry)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #8
|
|
|
|
Call out to another program / executable
|
|
|
|
You can also get creative and combine this with example #6 to spawn several programs at the same time!
|
|
]]
|
|
|
|
print("Sending 4 pings to google 🌏")
|
|
local result = process.spawn("ping", {
|
|
"google.com",
|
|
"-c 4",
|
|
})
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #9
|
|
|
|
Using the result of a spawned process, exiting the process
|
|
|
|
This looks scary with lots of weird symbols, but, it's just some Lua-style pattern matching
|
|
to parse the lines of "min/avg/max/stddev = W/X/Y/Z ms" that the ping program outputs to us
|
|
]]
|
|
|
|
if result.ok then
|
|
assert(#result.stdout > 0, "Result output was empty")
|
|
local min, avg, max, stddev = string.match(
|
|
result.stdout,
|
|
"min/avg/max/stddev = ([%d%.]+)/([%d%.]+)/([%d%.]+)/([%d%.]+) ms"
|
|
)
|
|
print(string.format("Minimum ping time: %.3fms", assert(tonumber(min))))
|
|
print(string.format("Maximum ping time: %.3fms", assert(tonumber(max))))
|
|
print(string.format("Average ping time: %.3fms", assert(tonumber(avg))))
|
|
print(string.format("Standard deviation: %.3fms", assert(tonumber(stddev))))
|
|
else
|
|
print("Failed to send ping to google!")
|
|
print(result.stderr)
|
|
process.exit(result.code)
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #10
|
|
|
|
Using the built-in networking library, encoding & decoding json
|
|
]]
|
|
|
|
print("Sending PATCH request to web API 📤")
|
|
local apiResult = net.request({
|
|
url = "https://jsonplaceholder.typicode.com/posts/1",
|
|
method = "PATCH",
|
|
headers = {
|
|
["Content-Type"] = "application/json",
|
|
},
|
|
body = net.jsonEncode({
|
|
title = "foo",
|
|
body = "bar",
|
|
}),
|
|
})
|
|
|
|
if not apiResult.ok then
|
|
print("Failed to send network request!")
|
|
print(string.format("%d (%s)", apiResult.statusCode, apiResult.statusMessage))
|
|
print(apiResult.body)
|
|
process.exit(1)
|
|
end
|
|
|
|
type ApiResponse = {
|
|
id: number,
|
|
title: string,
|
|
body: string,
|
|
userId: number,
|
|
}
|
|
|
|
local apiResponse: ApiResponse = net.jsonDecode(apiResult.body)
|
|
assert(apiResponse.title == "foo", "Invalid json response")
|
|
assert(apiResponse.body == "bar", "Invalid json response")
|
|
print("Got valid JSON response with changes applied")
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #11
|
|
|
|
Using the stdio library to print pretty
|
|
]]
|
|
|
|
print("Printing with pretty colors and auto-formatting 🎨")
|
|
|
|
print(stdio.color("blue") .. string.rep("—", 22) .. stdio.color("reset"))
|
|
|
|
info("API response:", apiResponse)
|
|
warn({
|
|
Oh = {
|
|
No = {
|
|
TooMuch = {
|
|
Nesting = {
|
|
"Will not print",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
print(stdio.color("blue") .. string.rep("—", 22) .. stdio.color("reset"))
|
|
|
|
|
|
|
|
--[[
|
|
EXAMPLE #12
|
|
|
|
Saying goodbye 😔
|
|
]]
|
|
|
|
print("Goodbye, lune! 🌙")
|
|
|
|
```
|
|
|
|
More real-world examples of how to write Lune scripts can be found in the [examples](https://github.com/filiptibell/lune/blob/main/.lune/examples/) folder.
|
|
|
|
Documentation for individual APIs and types can be found in "API Reference" in the sidebar of this wiki.
|
|
|
|
## Extras
|
|
|
|
### 🔀 Example translation from Bash
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
VALID=true
|
|
COUNT=1
|
|
while [ $VALID ]
|
|
do
|
|
echo $COUNT
|
|
if [ $COUNT -eq 5 ];
|
|
then
|
|
break
|
|
fi
|
|
((COUNT++))
|
|
done
|
|
```
|
|
|
|
**_With Lune & Luau:_**
|
|
|
|
```lua
|
|
local valid = true
|
|
local count = 1
|
|
while valid do
|
|
print(count)
|
|
if count == 5 then
|
|
break
|
|
end
|
|
count += 1
|
|
end
|
|
```
|