mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Fully featured wiki & slimmed down readme
This commit is contained in:
parent
3a57e1fdc2
commit
58ecbdb121
14 changed files with 494 additions and 397 deletions
|
@ -1,238 +0,0 @@
|
||||||
--> A walkthrough of all of the basic Lune features.
|
|
||||||
|
|
||||||
print("Hello, lune! 🌙")
|
|
||||||
|
|
||||||
--[==[
|
|
||||||
EXAMPLE #1
|
|
||||||
|
|
||||||
Using a function from another module
|
|
||||||
]==]
|
|
||||||
|
|
||||||
local module = require("./modules/module")
|
|
||||||
module.sayHello()
|
|
||||||
|
|
||||||
--[==[
|
|
||||||
EXAMPLE #2
|
|
||||||
|
|
||||||
Using the stdio library to prompt for input
|
|
||||||
]==]
|
|
||||||
|
|
||||||
local text = stdio.prompt("text", "Please write some text")
|
|
||||||
print("You wrote '" .. text .. "'!\n")
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
Using arguments given to the program
|
|
||||||
]==]
|
|
||||||
|
|
||||||
if #process.args > 0 then
|
|
||||||
print("\nGot arguments while running hello_lune:")
|
|
||||||
print(process.args)
|
|
||||||
if #process.args > 3 then
|
|
||||||
error("Too many arguments!")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[==[
|
|
||||||
EXAMPLE #4
|
|
||||||
|
|
||||||
Spawning tasks
|
|
||||||
]==]
|
|
||||||
|
|
||||||
task.spawn(function()
|
|
||||||
print("\nSpawned 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("\n...")
|
|
||||||
task.wait(1)
|
|
||||||
print("Hello again!")
|
|
||||||
task.wait(1)
|
|
||||||
print("Goodbye again! 🌙")
|
|
||||||
end)
|
|
||||||
|
|
||||||
--[==[
|
|
||||||
EXAMPLE #5
|
|
||||||
|
|
||||||
Get & set environment variables
|
|
||||||
|
|
||||||
Checks if environment variables are empty or not,
|
|
||||||
prints out ❌ if empty and ✅ if they have a value
|
|
||||||
]==]
|
|
||||||
|
|
||||||
print("\nReading 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 generalized iteration (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 #6
|
|
||||||
|
|
||||||
Read files in the current directory
|
|
||||||
|
|
||||||
This prints out directory & file names with some fancy icons
|
|
||||||
]==]
|
|
||||||
|
|
||||||
print("\nReading current dir 🗂️")
|
|
||||||
local entries = fs.readDir(".")
|
|
||||||
|
|
||||||
-- NOTE: We have to do this outside of the sort function
|
|
||||||
-- to avoid yielding across the metamethod boundary, any
|
|
||||||
-- calls to fs functions may yield for any reason
|
|
||||||
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
|
|
||||||
|
|
||||||
-- NOTE: We skip the ping example in GitHub Actions
|
|
||||||
-- since the ping command does not work in azure
|
|
||||||
if not process.env.GITHUB_ACTIONS then
|
|
||||||
--[==[
|
|
||||||
EXAMPLE #7
|
|
||||||
|
|
||||||
Call out to another program / executable
|
|
||||||
|
|
||||||
Here we send some pings to google to demonstrate that programs
|
|
||||||
that yield or perform any network requests work correctly
|
|
||||||
]==]
|
|
||||||
|
|
||||||
print("\nSending 4 pings to google 🌏")
|
|
||||||
local result = process.spawn("ping", {
|
|
||||||
"google.com",
|
|
||||||
"-c 4",
|
|
||||||
})
|
|
||||||
|
|
||||||
--[==[
|
|
||||||
EXAMPLE #8
|
|
||||||
|
|
||||||
Using the result of a spawned process, exiting the process
|
|
||||||
|
|
||||||
We use the result from the above ping command and parse
|
|
||||||
it to show the results it gave us in a nicer format, here we
|
|
||||||
also exit with an error (exit code 1) if spawning the process failed
|
|
||||||
]==]
|
|
||||||
|
|
||||||
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("\nFailed to send ping to google!")
|
|
||||||
print(result.stderr)
|
|
||||||
process.exit(result.code)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[==[
|
|
||||||
EXAMPLE #9
|
|
||||||
|
|
||||||
Using the built-in networking library
|
|
||||||
]==]
|
|
||||||
print("\nSending 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("\nFailed 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 #10
|
|
||||||
|
|
||||||
Using the stdio library to print pretty
|
|
||||||
]==]
|
|
||||||
|
|
||||||
print("\nPrinting 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 #11
|
|
||||||
|
|
||||||
Saying goodbye 😔
|
|
||||||
]==]
|
|
||||||
|
|
||||||
print("\nGoodbye, lune! 🌙")
|
|
|
@ -1,7 +0,0 @@
|
||||||
local module = {}
|
|
||||||
|
|
||||||
function module.sayHello()
|
|
||||||
print("\nHello from a module! 🧩\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
return module
|
|
162
README.md
162
README.md
|
@ -4,153 +4,37 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1> Lune 🌙 </h1>
|
<h1> Lune 🌙 </h1>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://crates.io/crates/lune"><img src="https://img.shields.io/crates/v/lune.svg?label=Version" alt="Current Lune library version" />
|
<a href="https://crates.io/crates/lune">
|
||||||
<a href="https://github.com/filiptibell/lune/actions"><img src="https://shields.io/endpoint?url=https://badges.readysetplay.io/workflow/filiptibell/lune/ci.yaml" alt="CI status" />
|
<img src="https://img.shields.io/crates/v/lune.svg?label=Version" alt="Current Lune library version" />
|
||||||
<a href="https://github.com/filiptibell/lune/actions"><img src="https://shields.io/endpoint?url=https://badges.readysetplay.io/workflow/filiptibell/lune/release.yaml" alt="Release status" />
|
</a>
|
||||||
<a href="https://github.com/filiptibell/lune/blob/main/LICENSE.txt"><img src="https://img.shields.io/github/license/filiptibell/lune.svg?label=License&color=informational" alt="Current Lune library version" />
|
<a href="https://github.com/filiptibell/lune/actions">
|
||||||
|
<img src="https://shields.io/endpoint?url=https://badges.readysetplay.io/workflow/filiptibell/lune/ci.yaml" alt="CI status" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/filiptibell/lune/actions">
|
||||||
|
<img src="https://shields.io/endpoint?url=https://badges.readysetplay.io/workflow/filiptibell/lune/release.yaml" alt="Release status" />
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/filiptibell/lune/blob/main/LICENSE.txt">
|
||||||
|
<img src="https://img.shields.io/github/license/filiptibell/lune.svg?label=License&color=informational" alt="Current Lune library version" />
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<br /> A standalone <a href="https://luau-lang.org">Luau</a> script runner
|
|
||||||
<br /> 🚀 Use the ergonomics and readability of Luau for your shell scripts 🚀
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
## ⚙️ Installation
|
Lune is a standalone [Luau](https://luau-lang.org) script runtime meant to be an alternative to traditional shell scripts, with the goal of drastically simplifying the typical tasks shell scripts are used for, making them easier to read and maintain.
|
||||||
|
|
||||||
The preferred way of installing Lune is using [Aftman](https://github.com/lpghatguy/aftman).
|
## Features
|
||||||
|
|
||||||
This will add `lune` to an `aftman.toml` file in the current directory, or create one if it does not exist:
|
- A strictly minimal but powerful interface that is easy to read and remember, just like Lua itself
|
||||||
|
- Fully featured APIs for the filesystem, networking, stdio, all included in the small (~1mb) executable
|
||||||
|
- World-class documentation, on the web _or_ directly in your editor, no network connection necessary
|
||||||
|
- A familiar scripting environment for Roblox developers, with an included 1-to-1 task scheduler port
|
||||||
|
|
||||||
```sh
|
## Non-goals
|
||||||
aftman add filiptibell/lune
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also download pre-built binaries for most systems directly from the GitHub Releases page.
|
- Making scripts short and terse - proper autocomplete / intellisense make scripting using Lune just as quick, and readability is important
|
||||||
|
- Running full Roblox game scripts outside of Roblox - there is some compatibility here already, but Lune is meant for different purposes
|
||||||
|
|
||||||
## ✏️ Writing Lune Scripts
|
## Where do I start?
|
||||||
|
|
||||||
A great starting point and walkthrough of Lune can be found in [Hello, Lune](.lune/hello_lune.luau). <br />
|
Head over to the [wiki](https://github.com/filiptibell/lune/wiki) to get started using Lune!
|
||||||
More examples of how to write Lune scripts can be found in the [examples](.lune/examples/) folder.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>🔎 List of APIs</b></summary>
|
|
||||||
|
|
||||||
`fs` - Filesystem <br />
|
|
||||||
`net` - Networking <br />
|
|
||||||
`process` - Current process & child processes <br />
|
|
||||||
`stdio` - Standard input / output & utility functions <br />
|
|
||||||
`task` - Task scheduler & thread spawning <br />
|
|
||||||
|
|
||||||
Documentation for individual members and types can be found using your editor of choice and [Luau LSP](https://github.com/JohnnyMorganz/luau-lsp).
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>🔀 Example translation from Bash</b></summary>
|
|
||||||
|
|
||||||
```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
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>🧑💻 Configuring VSCode for Lune</b></summary>
|
|
||||||
|
|
||||||
Lune puts developer experience first, and as such provides type definitions and configurations for several tools out of the box.
|
|
||||||
|
|
||||||
These steps assume you have already installed Lune and that it is available to run in the current directory.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Luau LSP</summary>
|
|
||||||
|
|
||||||
1. Run `lune --generate-luau-types` to generate a Luau type definitions file (`luneTypes.d.luau`) in the current directory
|
|
||||||
2. Run `lune --generate-docs-file` to generate a Luau LSP documentation file (`luneDocs.json`) in the current directory
|
|
||||||
3. Modify your VSCode settings, either by using the settings menu or in `settings.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"luau-lsp.require.mode": "relativeToFile", // Set the require mode to work with Lune
|
|
||||||
"luau-lsp.types.definitionFiles": ["luneTypes.d.luau"], // Add type definitions for Lune globals
|
|
||||||
"luau-lsp.types.documentationFiles": ["luneDocs.json"] // Add documentation for Lune globals
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
|
|
||||||
<summary>Selene</summary>
|
|
||||||
|
|
||||||
1. Run `lune --generate-selene-types` to generate a Selene type definitions file (`lune.yml`) in the current directory
|
|
||||||
2. Modify your Selene settings in `selene.toml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# Use this if Lune is the only thing you use Luau files with:
|
|
||||||
std = "luau+lune"
|
|
||||||
# OR use this if your project also contains Roblox-specific Luau code:
|
|
||||||
std = "roblox+lune"
|
|
||||||
# If you are also using the Luau type definitions file, it may cause issues, and can be safely ignored:
|
|
||||||
exclude = ["luneTypes.d.luau"]
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
**_NOTE:_** _It is highly recommended to add any generated files to your `.gitignore` and to only generate them using these commands, since this guarantees that you have type definitions compatible with your installed version of Lune._
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## 🏃 Running Lune Scripts
|
|
||||||
|
|
||||||
After you've written a script file, for example `script-name.luau`, you can run it:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
lune script-name
|
|
||||||
```
|
|
||||||
|
|
||||||
This will look for the file `script-name.luau` in a few locations:
|
|
||||||
|
|
||||||
- The current directory
|
|
||||||
- The folder `lune` in the current directory, if it exists
|
|
||||||
- The folder `.lune` in the current directory, if it exists
|
|
||||||
|
|
||||||
If you don't want Lune to look in sub-directories you can provide a full file path with the file extension included, instead of only the file name. <br />
|
|
||||||
|
|
||||||
## 💭 Additional Commands
|
|
||||||
|
|
||||||
```sh
|
|
||||||
lune --list
|
|
||||||
```
|
|
||||||
|
|
||||||
Lists all scripts found in `lune` or `.lune` directories, including any top-level description comments. <br />
|
|
||||||
Lune description comments are always written at the top of a file and start with a lua-style comment arrow (`-->`).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**_NOTE:_** _Lune also supports files with the `.lua` extension but using the `.luau` extension is highly recommended._
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!-- markdownlint-disable MD033 -->
|
||||||
|
|
||||||
|
# ⚙️ Installation
|
||||||
|
|
||||||
|
The preferred way of installing Lune is using [Aftman](https://github.com/lpghatguy/aftman).
|
||||||
|
|
||||||
|
Running this command in your terminal will add `lune` to an `aftman.toml` file in the current directory, or create one if it does not exist:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
aftman add filiptibell/lune
|
||||||
|
```
|
||||||
|
|
||||||
|
## Other options
|
||||||
|
|
||||||
|
### Building from source
|
||||||
|
|
||||||
|
Building and installing from source requires the latest version of [Rust & Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) to be installed on your system. <br />
|
||||||
|
Once installed, run the following command in your terminal:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install lune --locked
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that Lune does not make any minimum supported rust version (MSRV) guarantees and you may need to upgrade your version of Rust to update Lune in the future.
|
||||||
|
|
||||||
|
### Using GitHub Releases
|
||||||
|
|
||||||
|
You can download pre-built binaries for most systems directly from the [GitHub Releases](https://github.com/filiptibell/lune/releases) page. <br />
|
||||||
|
There are many tools that can install directly from releases, and it is up to you to choose what tool to use when installing using this method.
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
Now that you've installed Lune, head over to the [Writing Scripts](https://github.com/filiptibell/lune/wiki/Getting-Started---2-Writing-Scripts) page to write your first script!
|
|
@ -0,0 +1,326 @@
|
||||||
|
<!-- 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://github.com/filiptibell/lune/wiki/Getting-Started---3-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
|
||||||
|
```
|
|
@ -0,0 +1,43 @@
|
||||||
|
<!-- markdownlint-disable MD033 -->
|
||||||
|
|
||||||
|
# 🏃 Running Lune Scripts
|
||||||
|
|
||||||
|
After you've written a script file, for example `script-name.luau`, you can run it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
lune script-name
|
||||||
|
```
|
||||||
|
|
||||||
|
This will look for the file `script-name.luau`**_<sup>[1]</sup>_** in a few locations:
|
||||||
|
|
||||||
|
- The current directory
|
||||||
|
- The folder `lune` in the current directory, if it exists
|
||||||
|
- The folder `.lune` in the current directory, if it exists
|
||||||
|
|
||||||
|
## 🎛️ Passing Command-Line Arguments
|
||||||
|
|
||||||
|
Arguments can be passed to a Lune script directory from the command line when running it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
lune script-name arg1 arg2 "argument three"
|
||||||
|
```
|
||||||
|
|
||||||
|
These arguments will then be available in your script using `process.args`:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
print(process.args)
|
||||||
|
--> { "arg1", "arg2", "argument three" }
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💭 Additional Commands
|
||||||
|
|
||||||
|
```sh
|
||||||
|
lune --list
|
||||||
|
```
|
||||||
|
|
||||||
|
Lists all scripts found in `lune` or `.lune` directories, including any top-level description comments. <br />
|
||||||
|
Lune description comments are always written at the top of a file and start with a lua-style comment arrow (`-->`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**_<sup>[1]</sup>_** _Lune also supports files with the `.lua` extension but using the `.luau` extension is highly recommended. Additionally, if you don't want Lune to look in sub-directories you can provide a full file path with the file extension included, instead of only the file name._
|
|
@ -0,0 +1,33 @@
|
||||||
|
# 🧑💻 Configuring VSCode and tooling for Lune
|
||||||
|
|
||||||
|
Lune puts developer experience first, and as such provides type definitions and configurations for several tools out of the box.
|
||||||
|
|
||||||
|
These steps assume you have already installed Lune and that it is available to run in the current directory.
|
||||||
|
|
||||||
|
## Luau LSP
|
||||||
|
|
||||||
|
1. Run `lune --generate-luau-types` to generate a Luau type definitions file (`luneTypes.d.luau`) in the current directory
|
||||||
|
2. Run `lune --generate-docs-file` to generate a Luau LSP documentation file (`luneDocs.json`) in the current directory
|
||||||
|
3. Modify your VSCode settings, either by using the settings menu or in `settings.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"luau-lsp.require.mode": "relativeToFile", // Set the require mode to work with Lune
|
||||||
|
"luau-lsp.types.definitionFiles": ["luneTypes.d.luau"], // Add type definitions for Lune globals
|
||||||
|
"luau-lsp.types.documentationFiles": ["luneDocs.json"] // Add documentation for Lune globals
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Selene
|
||||||
|
|
||||||
|
1. Run `lune --generate-selene-types` to generate a Selene type definitions file (`lune.yml`) in the current directory
|
||||||
|
2. Modify your Selene settings in `selene.toml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Use this if Lune is the only thing you use Luau files with:
|
||||||
|
std = "luau+lune"
|
||||||
|
# OR use this if your project also contains Roblox-specific Luau code:
|
||||||
|
std = "roblox+lune"
|
||||||
|
# If you are also using the Luau type definitions file, it may cause issues, and can be safely ignored:
|
||||||
|
exclude = ["luneTypes.d.luau"]
|
||||||
|
```
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 🏠 Home
|
||||||
|
|
||||||
|
Welcome to the Lune wiki!
|
||||||
|
|
||||||
|
Here you can find tutorials as well as a full API reference for all of Lune's built-in APIs.
|
||||||
|
|
||||||
|
If you are just getting started, head over to the [installation](https://github.com/filiptibell/lune/wiki/Getting-Started---1-Installation) page!
|
||||||
|
|
||||||
|
## Page Reference
|
||||||
|
|
||||||
|
- Getting Started
|
||||||
|
|
||||||
|
- [1. Installation](https://github.com/filiptibell/lune/wiki/Getting-Started---1-Installation)
|
||||||
|
- [2. Writing Scripts](https://github.com/filiptibell/lune/wiki/Getting-Started---2-Writing-Scripts)
|
||||||
|
- [3. Running Scripts](https://github.com/filiptibell/lune/wiki/Getting-Started---3-Running-Scripts)
|
||||||
|
- [4. Editor Setup](https://github.com/filiptibell/lune/wiki/Getting-Started---4-Editor-Setup)
|
||||||
|
|
||||||
|
- API Reference
|
||||||
|
|
||||||
|
- [FS](https://github.com/filiptibell/lune/wiki/API-Reference---FS)
|
||||||
|
- [Net](https://github.com/filiptibell/lune/wiki/API-Reference---Net)
|
||||||
|
- [Process](https://github.com/filiptibell/lune/wiki/API-Reference---Process)
|
||||||
|
- [Stdio](https://github.com/filiptibell/lune/wiki/API-Reference---Stdio)
|
||||||
|
- [Task](https://github.com/filiptibell/lune/wiki/API-Reference---Task)
|
||||||
|
- [Uncategorized](https://github.com/filiptibell/lune/wiki/API-Reference---Uncategorized)
|
|
@ -2,19 +2,17 @@
|
||||||
|
|
||||||
# Home
|
# Home
|
||||||
|
|
||||||
- [Home](https://github.com/filiptibell/lune/wiki)
|
- [Getting Started](https://github.com/filiptibell/lune/wiki)
|
||||||
- [Getting Started](https://github.com/filiptibell/lune/wiki/getting-started)
|
- [1. Installation](https://github.com/filiptibell/lune/wiki/Getting-Started---1-Installation)
|
||||||
- [1. Installation](https://github.com/filiptibell/lune/wiki/getting-started-1-installation)
|
- [2. Writing Scripts](https://github.com/filiptibell/lune/wiki/Getting-Started---2-Writing-Scripts)
|
||||||
- [2. Writing Scripts](https://github.com/filiptibell/lune/wiki/getting-started-2-writing-scripts)
|
- [3. Running Scripts](https://github.com/filiptibell/lune/wiki/Getting-Started---3-Running-Scripts)
|
||||||
- [3. Running Scripts](https://github.com/filiptibell/lune/wiki/getting-started-3-running-scripts)
|
- [4. Editor Setup](https://github.com/filiptibell/lune/wiki/Getting-Started---4-Editor-Setup)
|
||||||
- [4. Editor Setup](https://github.com/filiptibell/lune/wiki/getting-started-4-editor-setup)
|
|
||||||
- [Advanced Usage](https://github.com/filiptibell/lune/wiki/advanced-usage)
|
|
||||||
|
|
||||||
# API Reference
|
# API Reference
|
||||||
|
|
||||||
- [FS](https://github.com/filiptibell/lune/wiki/api-reference-fs)
|
- [FS](https://github.com/filiptibell/lune/wiki/API-Reference---FS)
|
||||||
- [Net](https://github.com/filiptibell/lune/wiki/api-reference-net)
|
- [Net](https://github.com/filiptibell/lune/wiki/API-Reference---Net)
|
||||||
- [Process](https://github.com/filiptibell/lune/wiki/api-reference-process)
|
- [Process](https://github.com/filiptibell/lune/wiki/API-Reference---Process)
|
||||||
- [Stdio](https://github.com/filiptibell/lune/wiki/api-reference-stdio)
|
- [Stdio](https://github.com/filiptibell/lune/wiki/API-Reference---Stdio)
|
||||||
- [Task](https://github.com/filiptibell/lune/wiki/api-reference-task)
|
- [Task](https://github.com/filiptibell/lune/wiki/API-Reference---Task)
|
||||||
- [Uncategorized](https://github.com/filiptibell/lune/wiki/api-reference-uncategorized)
|
- [Uncategorized](https://github.com/filiptibell/lune/wiki/API-Reference---Uncategorized)
|
||||||
|
|
Loading…
Reference in a new issue