mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-06-08 17:44:11 +00:00
Pull in CC:T 1.108.1, some other fixes
- Use Cobalt's new Java patcher, allowing us to use Java 17 syntax. As such, update a couple classes to make use of that. - Pull in latest ROM. This is very noisy (due to the link syntax changes), but mostly trivial changes. - Fix wget and pastebin programs using http methods which don't exist. - Make fs.open create the parent directory when opening for write, much like newer CC versions.
This commit is contained in:
parent
35e227ed02
commit
136fbd2589
@ -1,27 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
application
|
|
||||||
alias(libs.plugins.kotlin)
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion.set(JavaLanguageVersion.of(17))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(libs.bundles.asm)
|
|
||||||
implementation(libs.bundles.kotlin)
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.jar {
|
|
||||||
manifest.attributes("Main-Class" to "cc.tweaked.build.MainKt")
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.build
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassReader
|
|
||||||
import org.objectweb.asm.ClassVisitor
|
|
||||||
import org.objectweb.asm.ClassWriter
|
|
||||||
import org.objectweb.asm.util.CheckClassAdapter
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
/** Generate additional classes which don't exist in the original source set. */
|
|
||||||
interface ClassEmitter {
|
|
||||||
/** Emit a class if it does not already exist. */
|
|
||||||
fun generate(name: String, classReader: ClassReader? = null, flags: Int = 0, write: (ClassVisitor) -> Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** An implementation of [ClassEmitter] which writes files to a directory. */
|
|
||||||
class FileClassEmitter(private val outputDir: Path) : ClassEmitter {
|
|
||||||
private val emitted = mutableSetOf<String>()
|
|
||||||
override fun generate(name: String, classReader: ClassReader?, flags: Int, write: (ClassVisitor) -> Unit) {
|
|
||||||
if (!emitted.add(name)) return
|
|
||||||
|
|
||||||
val cw = NonLoadingClassWriter(classReader, flags)
|
|
||||||
write(CheckClassAdapter(cw))
|
|
||||||
|
|
||||||
val outputFile = outputDir.resolve("$name.class")
|
|
||||||
Files.createDirectories(outputFile.parent)
|
|
||||||
Files.write(outputFile, cw.toByteArray())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A unordered pair, such that (x, y) = (y, x) */
|
|
||||||
private class UnorderedPair<T>(private val x: T, private val y: T) {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other !is cc.tweaked.build.UnorderedPair<*>) return false
|
|
||||||
return (x == other.x && y == other.y) || (x == other.y && y == other.x)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int = x.hashCode() xor y.hashCode()
|
|
||||||
override fun toString(): String = "UnorderedPair($x, $y)"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val subclassRelations = mapOf<UnorderedPair<String>, String>(
|
|
||||||
)
|
|
||||||
|
|
||||||
/** A [ClassWriter] extension which avoids loading classes when computing frames. */
|
|
||||||
private class NonLoadingClassWriter(reader: ClassReader?, flags: Int) : ClassWriter(reader, flags) {
|
|
||||||
override fun getCommonSuperClass(type1: String, type2: String): String {
|
|
||||||
if (type1 == "java/lang/Object" || type2 == "java/lang/Object") return "java/lang/Object"
|
|
||||||
|
|
||||||
val subclass = subclassRelations[UnorderedPair(type1, type2)]
|
|
||||||
if (subclass != null) return subclass
|
|
||||||
|
|
||||||
println("[WARN] Guessing the super-class of $type1 and $type2.")
|
|
||||||
return "java/lang/Object"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.build
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassReader
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import kotlin.io.path.extension
|
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
if (args.size != 2) {
|
|
||||||
System.err.println("Expected: INPUT OUTPUT")
|
|
||||||
exitProcess(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
val inputDir = Paths.get(args[0])
|
|
||||||
val outputDir = Paths.get(args[1])
|
|
||||||
|
|
||||||
val emitter = FileClassEmitter(outputDir)
|
|
||||||
Files.find(inputDir, Int.MAX_VALUE, { path, _ -> path.extension == "class" }).use { files ->
|
|
||||||
files.forEach { inputFile ->
|
|
||||||
val reader = Files.newInputStream(inputFile).use { ClassReader(it) }
|
|
||||||
emitter.generate(reader.className, flags = 0) { cw -> reader.accept(Unlambda(emitter, cw), 0) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,210 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.build
|
|
||||||
|
|
||||||
import org.objectweb.asm.*
|
|
||||||
import org.objectweb.asm.Opcodes.*
|
|
||||||
|
|
||||||
class Unlambda(private val emitter: ClassEmitter, visitor: ClassVisitor) :
|
|
||||||
ClassVisitor(ASM9, visitor) {
|
|
||||||
internal lateinit var className: String
|
|
||||||
private var isInterface: Boolean = false
|
|
||||||
|
|
||||||
private var lambda = 0
|
|
||||||
|
|
||||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<out String>?) {
|
|
||||||
super.visit(V1_6, access, name, signature, superName, interfaces)
|
|
||||||
|
|
||||||
if (version != V1_8) throw IllegalStateException("Expected Java version 8")
|
|
||||||
className = name
|
|
||||||
isInterface = (access and ACC_INTERFACE) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitMethod(access: Int, name: String, descriptor: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
|
||||||
val access = if (access.and(ACC_STATIC) != 0) access.and(ACC_PRIVATE.inv()) else access
|
|
||||||
val mw = super.visitMethod(access, name, descriptor, signature, exceptions) ?: return null
|
|
||||||
|
|
||||||
if (isInterface && name != "<clinit>") {
|
|
||||||
if ((access and ACC_STATIC) != 0) println("[WARN] $className.$name is a static method")
|
|
||||||
else if ((access and ACC_ABSTRACT) == 0) println("[WARN] $className.$name is a default method")
|
|
||||||
}
|
|
||||||
|
|
||||||
return UnlambdaMethodVisitor(this, emitter, mw)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun nextLambdaName(): String {
|
|
||||||
val name = "lambda$lambda"
|
|
||||||
lambda++
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class UnlambdaMethodVisitor(
|
|
||||||
private val parent: Unlambda,
|
|
||||||
private val emitter: ClassEmitter,
|
|
||||||
methodVisitor: MethodVisitor,
|
|
||||||
) : MethodVisitor(ASM9, methodVisitor) {
|
|
||||||
private class Bridge(val lambda: Handle, val bridgeName: String)
|
|
||||||
|
|
||||||
private val bridgeMethods = mutableListOf<Bridge>()
|
|
||||||
|
|
||||||
override fun visitMethodInsn(opcode: Int, owner: String, name: String, descriptor: String, isInterface: Boolean) {
|
|
||||||
if (opcode == INVOKESTATIC && isInterface) println("[WARN] Invoke interface $owner.$name in ${parent.className}")
|
|
||||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitInvokeDynamicInsn(name: String, descriptor: String, handle: Handle, vararg arguments: Any) {
|
|
||||||
if (handle.owner == "java/lang/invoke/LambdaMetafactory" && handle.name == "metafactory" && handle.desc == "(Ljava/lang/invoke/MethodHandles\$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;") {
|
|
||||||
visitLambda(name, descriptor, arguments[0] as Type, arguments[1] as Handle)
|
|
||||||
} else {
|
|
||||||
super.visitInvokeDynamicInsn(name, descriptor, handle, *arguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitLambda(name: String, descriptor: String, signature: Type, lambda: Handle) {
|
|
||||||
val interfaceTy = Type.getReturnType(descriptor)
|
|
||||||
val fields = Type.getArgumentTypes(descriptor)
|
|
||||||
|
|
||||||
val lambdaName = parent.nextLambdaName()
|
|
||||||
val className = "${parent.className}\$$lambdaName"
|
|
||||||
val bridgeName = "${lambdaName}Bridge"
|
|
||||||
|
|
||||||
emitter.generate(className, flags = ClassWriter.COMPUTE_MAXS) { cw ->
|
|
||||||
cw.visit(V1_6, ACC_FINAL, className, null, "java/lang/Object", arrayOf(interfaceTy.internalName))
|
|
||||||
for ((i, ty) in fields.withIndex()) {
|
|
||||||
cw.visitField(ACC_PRIVATE or ACC_FINAL, "field$i", ty.descriptor, null, null)
|
|
||||||
.visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
cw.visitMethod(ACC_STATIC, "create", Type.getMethodDescriptor(interfaceTy, *fields), null, null).let { mw ->
|
|
||||||
mw.visitCode()
|
|
||||||
mw.visitTypeInsn(NEW, className)
|
|
||||||
mw.visitInsn(DUP)
|
|
||||||
for ((i, ty) in fields.withIndex()) mw.visitVarInsn(ty.getOpcode(ILOAD), i)
|
|
||||||
mw.visitMethodInsn(INVOKESPECIAL, className, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, *fields), false)
|
|
||||||
mw.visitInsn(ARETURN)
|
|
||||||
mw.visitMaxs(0, 0)
|
|
||||||
mw.visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
cw.visitMethod(0, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, *fields), null, null).let { mw ->
|
|
||||||
mw.visitCode()
|
|
||||||
mw.visitVarInsn(ALOAD, 0)
|
|
||||||
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
|
|
||||||
for ((i, ty) in fields.withIndex()) {
|
|
||||||
mw.visitVarInsn(ALOAD, 0)
|
|
||||||
mw.visitVarInsn(ty.getOpcode(ILOAD), i + 1)
|
|
||||||
mw.visitFieldInsn(PUTFIELD, className, "field$i", ty.descriptor)
|
|
||||||
}
|
|
||||||
mw.visitInsn(RETURN)
|
|
||||||
mw.visitMaxs(0, 0)
|
|
||||||
mw.visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
cw.visitMethod(ACC_PUBLIC, name, signature.descriptor, null, null).let { mw ->
|
|
||||||
mw.visitCode()
|
|
||||||
|
|
||||||
val targetArgs = when (lambda.tag) {
|
|
||||||
H_INVOKEVIRTUAL, H_INVOKESPECIAL -> arrayOf(
|
|
||||||
Type.getObjectType(lambda.owner),
|
|
||||||
*Type.getArgumentTypes(lambda.desc),
|
|
||||||
)
|
|
||||||
|
|
||||||
H_INVOKESTATIC, H_NEWINVOKESPECIAL -> Type.getArgumentTypes(lambda.desc)
|
|
||||||
else -> throw IllegalStateException("Unhandled opcode")
|
|
||||||
}
|
|
||||||
var targetArgOffset = 0
|
|
||||||
|
|
||||||
// If we're a ::new method handle, create the object.
|
|
||||||
if (lambda.tag == H_NEWINVOKESPECIAL) {
|
|
||||||
mw.visitTypeInsn(NEW, lambda.owner)
|
|
||||||
mw.visitInsn(DUP)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load our fields
|
|
||||||
for ((i, ty) in fields.withIndex()) {
|
|
||||||
mw.visitVarInsn(ALOAD, 0)
|
|
||||||
mw.visitFieldInsn(GETFIELD, className, "field$i", ty.descriptor)
|
|
||||||
|
|
||||||
val expectedTy = targetArgs[targetArgOffset]
|
|
||||||
if (ty != expectedTy) println("$ty != $expectedTy")
|
|
||||||
targetArgOffset++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the additional arguments
|
|
||||||
val arguments = signature.argumentTypes
|
|
||||||
for ((i, ty) in arguments.withIndex()) {
|
|
||||||
mw.visitVarInsn(ty.getOpcode(ILOAD), i + 1)
|
|
||||||
val expectedTy = targetArgs[targetArgOffset]
|
|
||||||
if (ty != expectedTy) {
|
|
||||||
println("[WARN] $ty != $expectedTy, adding a cast")
|
|
||||||
mw.visitTypeInsn(CHECKCAST, expectedTy.internalName)
|
|
||||||
}
|
|
||||||
targetArgOffset++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke our init call
|
|
||||||
mw.visitMethodInsn(
|
|
||||||
when (lambda.tag) {
|
|
||||||
H_INVOKEVIRTUAL, H_INVOKESPECIAL -> INVOKEVIRTUAL
|
|
||||||
H_INVOKESTATIC -> INVOKESTATIC
|
|
||||||
H_NEWINVOKESPECIAL -> INVOKESPECIAL
|
|
||||||
else -> throw IllegalStateException("Unhandled opcode")
|
|
||||||
},
|
|
||||||
lambda.owner, if (lambda.tag == H_INVOKESPECIAL) bridgeName else lambda.name, lambda.desc, false,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if (lambda.tag != H_NEWINVOKESPECIAL) {
|
|
||||||
val expectedRetTy = signature.returnType
|
|
||||||
val retTy = Type.getReturnType(lambda.desc)
|
|
||||||
if (expectedRetTy != retTy) {
|
|
||||||
// println("[WARN] $retTy != $expectedRetTy, adding a cast")
|
|
||||||
if (retTy == Type.INT_TYPE && expectedRetTy.descriptor == "Ljava/lang/Object;") {
|
|
||||||
mw.visitMethodInsn(INVOKESTATIC, "jav/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false)
|
|
||||||
} else {
|
|
||||||
// println("[ERROR] Unhandled")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A little ugly special handling for ::new
|
|
||||||
mw.visitInsn(
|
|
||||||
if (lambda.tag == H_NEWINVOKESPECIAL) ARETURN else signature.returnType.getOpcode(IRETURN),
|
|
||||||
)
|
|
||||||
mw.visitMaxs(0, 0)
|
|
||||||
mw.visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
cw.visitEnd()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're a ::new method handle, create the object.
|
|
||||||
if (lambda.tag == H_INVOKESPECIAL) {
|
|
||||||
bridgeMethods.add(Bridge(lambda, bridgeName))
|
|
||||||
}
|
|
||||||
|
|
||||||
visitMethodInsn(INVOKESTATIC, className, "create", Type.getMethodDescriptor(interfaceTy, *fields), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitEnd() {
|
|
||||||
super.visitEnd()
|
|
||||||
|
|
||||||
for (bridge in bridgeMethods) {
|
|
||||||
println("[INFO] Using bridge method ${bridge.bridgeName} for ${bridge.lambda}")
|
|
||||||
val mw = parent.visitMethod(ACC_PUBLIC, bridge.bridgeName, bridge.lambda.desc, null, null) ?: continue
|
|
||||||
mw.visitCode()
|
|
||||||
mw.visitVarInsn(ALOAD, 0)
|
|
||||||
for ((i, ty) in Type.getArgumentTypes(bridge.lambda.desc)
|
|
||||||
.withIndex()) mw.visitVarInsn(ty.getOpcode(ILOAD), i + 1)
|
|
||||||
mw.visitMethodInsn(INVOKESPECIAL, bridge.lambda.owner, bridge.lambda.name, bridge.lambda.desc, false)
|
|
||||||
mw.visitInsn(Type.getReturnType(bridge.lambda.desc).getOpcode(IRETURN))
|
|
||||||
val size = 1 + Type.getArgumentTypes(bridge.lambda.desc).size
|
|
||||||
mw.visitMaxs(size, size)
|
|
||||||
mw.visitEnd()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,13 +20,16 @@ version = modVersion
|
|||||||
base.archivesName.convention("cc-tweaked-$mcVersion")
|
base.archivesName.convention("cc-tweaked-$mcVersion")
|
||||||
|
|
||||||
java {
|
java {
|
||||||
// Last version able to set a --release as low as 6
|
toolchain {
|
||||||
toolchain.languageVersion.set(JavaLanguageVersion.of(11))
|
languageVersion.set(JavaLanguageVersion.of(17))
|
||||||
|
}
|
||||||
|
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileJava { options.release.set(8) }
|
val runtimeToolchain = javaToolchains.launcherFor {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(8))
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@ -38,10 +41,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
volde {
|
volde {
|
||||||
forgeCapabilities {
|
|
||||||
setSrgsAsFallback(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
runs {
|
runs {
|
||||||
named("client") {
|
named("client") {
|
||||||
programArg("SquidDev")
|
programArg("SquidDev")
|
||||||
@ -50,6 +49,10 @@ volde {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(net.fabricmc.loom.task.RunTask::class.java).configureEach {
|
||||||
|
javaLauncher.set(runtimeToolchain)
|
||||||
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
val shade by registering
|
val shade by registering
|
||||||
compileOnly { extendsFrom(shade.get()) }
|
compileOnly { extendsFrom(shade.get()) }
|
||||||
@ -71,10 +74,12 @@ dependencies {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
compileOnly("com.google.code.findbugs:jsr305:3.0.2")
|
||||||
|
compileOnly("org.jetbrains:annotations:24.0.1")
|
||||||
modImplementation("maven.modrinth:computercraft:1.50")
|
modImplementation("maven.modrinth:computercraft:1.50")
|
||||||
"shade"("org.squiddev:Cobalt")
|
"shade"("org.squiddev:Cobalt")
|
||||||
|
|
||||||
"buildTools"(project(":build-tools"))
|
"buildTools"("cc.tweaked.cobalt:build-tools")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Point compileJava to emit to classes/uninstrumentedJava/main, and then add a task to instrument these classes,
|
// Point compileJava to emit to classes/uninstrumentedJava/main, and then add a task to instrument these classes,
|
||||||
@ -88,12 +93,9 @@ val instrumentJava = tasks.register(mainSource.getTaskName("Instrument", "Java")
|
|||||||
inputs.dir(untransformedClasses).withPropertyName("inputDir")
|
inputs.dir(untransformedClasses).withPropertyName("inputDir")
|
||||||
outputs.dir(javaClassesDir).withPropertyName("outputDir")
|
outputs.dir(javaClassesDir).withPropertyName("outputDir")
|
||||||
|
|
||||||
javaLauncher.set(
|
// Run under Java 8, so we can check compatibility of methods.
|
||||||
javaToolchains.launcherFor {
|
javaLauncher.set(runtimeToolchain)
|
||||||
languageVersion.set(JavaLanguageVersion.of(17))
|
mainClass.set("cc.tweaked.cobalt.build.MainKt")
|
||||||
},
|
|
||||||
)
|
|
||||||
mainClass.set("cc.tweaked.build.MainKt")
|
|
||||||
classpath = buildTools
|
classpath = buildTools
|
||||||
|
|
||||||
args = listOf(
|
args = listOf(
|
||||||
@ -129,6 +131,8 @@ tasks.jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
|
inputs.property("version", project.version)
|
||||||
|
inputs.property("mcVersion", mcVersion)
|
||||||
filesMatching("mcmod.info") {
|
filesMatching("mcmod.info") {
|
||||||
expand("version" to project.version, "mcVersion" to mcVersion)
|
expand("version" to project.version, "mcVersion" to mcVersion)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
org.gradle.jvmargs=-Xmx3G
|
org.gradle.jvmargs=-Xmx3G
|
||||||
|
|
||||||
modVersion=1.105.1
|
modVersion=1.108.1
|
||||||
|
|
||||||
mcVersion=1.4.7
|
mcVersion=1.4.7
|
||||||
|
@ -38,5 +38,3 @@ val mcVersion: String by settings
|
|||||||
rootProject.name = "cc-tweaked-$mcVersion"
|
rootProject.name = "cc-tweaked-$mcVersion"
|
||||||
|
|
||||||
includeBuild("vendor/Cobalt")
|
includeBuild("vendor/Cobalt")
|
||||||
|
|
||||||
include("build-tools")
|
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper type for "coerced" values.
|
* A wrapper type for "coerced" values.
|
||||||
* <p>
|
* <p>
|
||||||
@ -20,27 +18,9 @@ import java.util.Objects;
|
|||||||
* }
|
* }
|
||||||
* }</pre>
|
* }</pre>
|
||||||
*
|
*
|
||||||
|
* @param value The argument value.
|
||||||
* @param <T> The type of the underlying value.
|
* @param <T> The type of the underlying value.
|
||||||
* @see IArguments#getStringCoerced(int)
|
* @see IArguments#getStringCoerced(int)
|
||||||
*/
|
*/
|
||||||
public final class Coerced<T> {
|
public record Coerced<T>(T value) {
|
||||||
private final T value;
|
|
||||||
|
|
||||||
public Coerced(T value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T value() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return obj == this || obj instanceof Coerced && Objects.equals(value, ((Coerced<?>) obj).value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hashCode(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -39,6 +42,7 @@ public abstract class IArguments {
|
|||||||
* @throws IllegalStateException If accessing these arguments outside the scope of the original function. See
|
* @throws IllegalStateException If accessing these arguments outside the scope of the original function. See
|
||||||
* {@link #escapes()}.
|
* {@link #escapes()}.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public abstract Object get(int index) throws LuaException;
|
public abstract Object get(int index) throws LuaException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,8 +74,8 @@ public abstract class IArguments {
|
|||||||
* @see #get(int) To get a single argument.
|
* @see #get(int) To get a single argument.
|
||||||
*/
|
*/
|
||||||
public Object[] getAll() throws LuaException {
|
public Object[] getAll() throws LuaException {
|
||||||
Object[] result = new Object[count()];
|
var result = new Object[count()];
|
||||||
for (int i = 0; i < result.length; i++) result[i] = get(i);
|
for (var i = 0; i < result.length; i++) result[i] = get(i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,9 +88,9 @@ public abstract class IArguments {
|
|||||||
* @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN).
|
* @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN).
|
||||||
*/
|
*/
|
||||||
public double getDouble(int index) throws LuaException {
|
public double getDouble(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (!(value instanceof Number)) throw LuaValues.badArgumentOf(this, index, "number");
|
if (!(value instanceof Number number)) throw LuaValues.badArgumentOf(this, index, "number");
|
||||||
return ((Number) value).doubleValue();
|
return number.doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,9 +112,9 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a long.
|
* @throws LuaException If the value is not a long.
|
||||||
*/
|
*/
|
||||||
public long getLong(int index) throws LuaException {
|
public long getLong(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (!(value instanceof Number)) throw LuaValues.badArgumentOf(this, index, "number");
|
if (!(value instanceof Number number)) throw LuaValues.badArgumentOf(this, index, "number");
|
||||||
return LuaValues.checkFiniteNum(index, (Number) value).longValue();
|
return LuaValues.checkFiniteNum(index, number).longValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -132,9 +136,9 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a boolean.
|
* @throws LuaException If the value is not a boolean.
|
||||||
*/
|
*/
|
||||||
public boolean getBoolean(int index) throws LuaException {
|
public boolean getBoolean(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (!(value instanceof Boolean)) throw LuaValues.badArgumentOf(this, index, "boolean");
|
if (!(value instanceof Boolean bool)) throw LuaValues.badArgumentOf(this, index, "boolean");
|
||||||
return (Boolean) value;
|
return bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,9 +149,9 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a string.
|
* @throws LuaException If the value is not a string.
|
||||||
*/
|
*/
|
||||||
public String getString(int index) throws LuaException {
|
public String getString(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (!(value instanceof String)) throw LuaValues.badArgumentOf(this, index, "string");
|
if (!(value instanceof String string)) throw LuaValues.badArgumentOf(this, index, "string");
|
||||||
return (String) value;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,12 +171,12 @@ public abstract class IArguments {
|
|||||||
* @see Coerced
|
* @see Coerced
|
||||||
*/
|
*/
|
||||||
public String getStringCoerced(int index) throws LuaException {
|
public String getStringCoerced(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (value == null) return "nil";
|
if (value == null) return "nil";
|
||||||
if (value instanceof Boolean || value instanceof String) return value.toString();
|
if (value instanceof Boolean || value instanceof String) return value.toString();
|
||||||
if (value instanceof Number) {
|
if (value instanceof Number number) {
|
||||||
double asDouble = ((Number) value).doubleValue();
|
var asDouble = number.doubleValue();
|
||||||
int asInt = (int) asDouble;
|
var asInt = (int) asDouble;
|
||||||
return asInt == asDouble ? Integer.toString(asInt) : Double.toString(asDouble);
|
return asInt == asDouble ? Integer.toString(asInt) : Double.toString(asDouble);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +216,7 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a table.
|
* @throws LuaException If the value is not a table.
|
||||||
*/
|
*/
|
||||||
public Map<?, ?> getTable(int index) throws LuaException {
|
public Map<?, ?> getTable(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (!(value instanceof Map)) throw LuaValues.badArgumentOf(this, index, "table");
|
if (!(value instanceof Map)) throw LuaValues.badArgumentOf(this, index, "table");
|
||||||
return (Map<?, ?>) value;
|
return (Map<?, ?>) value;
|
||||||
}
|
}
|
||||||
@ -225,10 +229,10 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a number.
|
* @throws LuaException If the value is not a number.
|
||||||
*/
|
*/
|
||||||
public Optional<Double> optDouble(int index) throws LuaException {
|
public Optional<Double> optDouble(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (value == null) return Optional.empty();
|
if (value == null) return Optional.empty();
|
||||||
if (!(value instanceof Number)) throw LuaValues.badArgumentOf(this, index, "number");
|
if (!(value instanceof Number number)) throw LuaValues.badArgumentOf(this, index, "number");
|
||||||
return Optional.of(((Number) value).doubleValue());
|
return Optional.of(number.doubleValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,10 +254,10 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a number.
|
* @throws LuaException If the value is not a number.
|
||||||
*/
|
*/
|
||||||
public Optional<Long> optLong(int index) throws LuaException {
|
public Optional<Long> optLong(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (value == null) return Optional.empty();
|
if (value == null) return Optional.empty();
|
||||||
if (!(value instanceof Number)) throw LuaValues.badArgumentOf(this, index, "number");
|
if (!(value instanceof Number number)) throw LuaValues.badArgumentOf(this, index, "number");
|
||||||
return Optional.of(LuaValues.checkFiniteNum(index, (Number) value).longValue());
|
return Optional.of(LuaValues.checkFiniteNum(index, number).longValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -264,7 +268,7 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not finite.
|
* @throws LuaException If the value is not finite.
|
||||||
*/
|
*/
|
||||||
public Optional<Double> optFiniteDouble(int index) throws LuaException {
|
public Optional<Double> optFiniteDouble(int index) throws LuaException {
|
||||||
Optional<Double> value = optDouble(index);
|
var value = optDouble(index);
|
||||||
if (value.isPresent()) LuaValues.checkFiniteNum(index, value.get());
|
if (value.isPresent()) LuaValues.checkFiniteNum(index, value.get());
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -277,10 +281,10 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a boolean.
|
* @throws LuaException If the value is not a boolean.
|
||||||
*/
|
*/
|
||||||
public Optional<Boolean> optBoolean(int index) throws LuaException {
|
public Optional<Boolean> optBoolean(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (value == null) return Optional.empty();
|
if (value == null) return Optional.empty();
|
||||||
if (!(value instanceof Boolean)) throw LuaValues.badArgumentOf(this, index, "boolean");
|
if (!(value instanceof Boolean bool)) throw LuaValues.badArgumentOf(this, index, "boolean");
|
||||||
return Optional.of((Boolean) value);
|
return Optional.of(bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -291,10 +295,10 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a string.
|
* @throws LuaException If the value is not a string.
|
||||||
*/
|
*/
|
||||||
public Optional<String> optString(int index) throws LuaException {
|
public Optional<String> optString(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (value == null) return Optional.empty();
|
if (value == null) return Optional.empty();
|
||||||
if (!(value instanceof String)) throw LuaValues.badArgumentOf(this, index, "string");
|
if (!(value instanceof String string)) throw LuaValues.badArgumentOf(this, index, "string");
|
||||||
return Optional.of((String) value);
|
return Optional.of(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -318,7 +322,7 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a string or not a valid option for this enum.
|
* @throws LuaException If the value is not a string or not a valid option for this enum.
|
||||||
*/
|
*/
|
||||||
public <T extends Enum<T>> Optional<T> optEnum(int index, Class<T> klass) throws LuaException {
|
public <T extends Enum<T>> Optional<T> optEnum(int index, Class<T> klass) throws LuaException {
|
||||||
Optional<String> str = optString(index);
|
var str = optString(index);
|
||||||
return str.isPresent() ? Optional.of(LuaValues.checkEnum(index, klass, str.get())) : Optional.empty();
|
return str.isPresent() ? Optional.of(LuaValues.checkEnum(index, klass, str.get())) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +334,7 @@ public abstract class IArguments {
|
|||||||
* @throws LuaException If the value is not a table.
|
* @throws LuaException If the value is not a table.
|
||||||
*/
|
*/
|
||||||
public Optional<Map<?, ?>> optTable(int index) throws LuaException {
|
public Optional<Map<?, ?>> optTable(int index) throws LuaException {
|
||||||
Object value = get(index);
|
var value = get(index);
|
||||||
if (value == null) return Optional.empty();
|
if (value == null) return Optional.empty();
|
||||||
if (!(value instanceof Map)) throw LuaValues.badArgumentOf(this, index, "map");
|
if (!(value instanceof Map)) throw LuaValues.badArgumentOf(this, index, "map");
|
||||||
return Optional.of((Map<?, ?>) value);
|
return Optional.of((Map<?, ?>) value);
|
||||||
@ -340,7 +344,7 @@ public abstract class IArguments {
|
|||||||
* Get an argument as a double.
|
* Get an argument as a double.
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @param def The public value, if this argument is not given.
|
* @param def The default value, if this argument is not given.
|
||||||
* @return The argument's value, or {@code def} if none was provided.
|
* @return The argument's value, or {@code def} if none was provided.
|
||||||
* @throws LuaException If the value is not a number.
|
* @throws LuaException If the value is not a number.
|
||||||
*/
|
*/
|
||||||
@ -352,7 +356,7 @@ public abstract class IArguments {
|
|||||||
* Get an argument as an int.
|
* Get an argument as an int.
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @param def The public value, if this argument is not given.
|
* @param def The default value, if this argument is not given.
|
||||||
* @return The argument's value, or {@code def} if none was provided.
|
* @return The argument's value, or {@code def} if none was provided.
|
||||||
* @throws LuaException If the value is not a number.
|
* @throws LuaException If the value is not a number.
|
||||||
*/
|
*/
|
||||||
@ -364,7 +368,7 @@ public abstract class IArguments {
|
|||||||
* Get an argument as a long.
|
* Get an argument as a long.
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @param def The public value, if this argument is not given.
|
* @param def The default value, if this argument is not given.
|
||||||
* @return The argument's value, or {@code def} if none was provided.
|
* @return The argument's value, or {@code def} if none was provided.
|
||||||
* @throws LuaException If the value is not a number.
|
* @throws LuaException If the value is not a number.
|
||||||
*/
|
*/
|
||||||
@ -376,7 +380,7 @@ public abstract class IArguments {
|
|||||||
* Get an argument as a finite number (not infinite or NaN).
|
* Get an argument as a finite number (not infinite or NaN).
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @param def The public value, if this argument is not given.
|
* @param def The default value, if this argument is not given.
|
||||||
* @return The argument's value, or {@code def} if none was provided.
|
* @return The argument's value, or {@code def} if none was provided.
|
||||||
* @throws LuaException If the value is not finite.
|
* @throws LuaException If the value is not finite.
|
||||||
*/
|
*/
|
||||||
@ -388,7 +392,7 @@ public abstract class IArguments {
|
|||||||
* Get an argument as a boolean.
|
* Get an argument as a boolean.
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @param def The public value, if this argument is not given.
|
* @param def The default value, if this argument is not given.
|
||||||
* @return The argument's value, or {@code def} if none was provided.
|
* @return The argument's value, or {@code def} if none was provided.
|
||||||
* @throws LuaException If the value is not a boolean.
|
* @throws LuaException If the value is not a boolean.
|
||||||
*/
|
*/
|
||||||
@ -400,11 +404,13 @@ public abstract class IArguments {
|
|||||||
* Get an argument as a string.
|
* Get an argument as a string.
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @param def The public value, if this argument is not given.
|
* @param def The default value, if this argument is not given.
|
||||||
* @return The argument's value, or {@code def} if none was provided.
|
* @return The argument's value, or {@code def} if none was provided.
|
||||||
* @throws LuaException If the value is not a string.
|
* @throws LuaException If the value is not a string.
|
||||||
*/
|
*/
|
||||||
public String optString(int index, String def) throws LuaException {
|
@Nullable
|
||||||
|
@Contract("_, !null -> !null")
|
||||||
|
public String optString(int index, @Nullable String def) throws LuaException {
|
||||||
return optString(index).orElse(def);
|
return optString(index).orElse(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,11 +418,13 @@ public abstract class IArguments {
|
|||||||
* Get an argument as a table.
|
* Get an argument as a table.
|
||||||
*
|
*
|
||||||
* @param index The argument number.
|
* @param index The argument number.
|
||||||
* @param def The public value, if this argument is not given.
|
* @param def The default value, if this argument is not given.
|
||||||
* @return The argument's value, or {@code def} if none was provided.
|
* @return The argument's value, or {@code def} if none was provided.
|
||||||
* @throws LuaException If the value is not a table.
|
* @throws LuaException If the value is not a table.
|
||||||
*/
|
*/
|
||||||
public Map<?, ?> optTable(int index, Map<Object, Object> def) throws LuaException {
|
@Nullable
|
||||||
|
@Contract("_, !null -> !null")
|
||||||
|
public Map<?, ?> optTable(int index, @Nullable Map<Object, Object> def) throws LuaException {
|
||||||
return optTable(index).orElse(def);
|
return optTable(index).orElse(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,8 +445,10 @@ public abstract class IArguments {
|
|||||||
*
|
*
|
||||||
* @return An {@link IArguments} instance which can escape the current scope. May be {@code this}.
|
* @return An {@link IArguments} instance which can escape the current scope. May be {@code this}.
|
||||||
* @throws LuaException For the same reasons as {@link #get(int)}.
|
* @throws LuaException For the same reasons as {@link #get(int)}.
|
||||||
|
* @throws IllegalStateException If marking these arguments as escaping outside the scope of the original function.
|
||||||
*/
|
*/
|
||||||
public IArguments escapes() throws LuaException {
|
public IArguments escapes() throws LuaException {
|
||||||
|
// TODO(1.21.0): Make this return void, require that it mutates this.
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,21 +4,25 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An exception representing an error in Lua, like that raised by the {@code error()} function.
|
* An exception representing an error in Lua, like that raised by the {@code error()} function.
|
||||||
*/
|
*/
|
||||||
public class LuaException extends Exception {
|
public class LuaException extends Exception {
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -6136063076818512651L;
|
private static final long serialVersionUID = -6136063076818512651L;
|
||||||
private final boolean hasLevel;
|
private final boolean hasLevel;
|
||||||
private final int level;
|
private final int level;
|
||||||
|
|
||||||
public LuaException(String message) {
|
public LuaException(@Nullable String message) {
|
||||||
super(message);
|
super(message);
|
||||||
hasLevel = false;
|
hasLevel = false;
|
||||||
level = 1;
|
level = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LuaException(String message, int level) {
|
public LuaException(@Nullable String message, int level) {
|
||||||
super(message);
|
super(message);
|
||||||
hasLevel = true;
|
hasLevel = true;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -23,9 +24,9 @@ public final class LuaValues {
|
|||||||
* @return The encoded string.
|
* @return The encoded string.
|
||||||
*/
|
*/
|
||||||
public static ByteBuffer encode(String string) {
|
public static ByteBuffer encode(String string) {
|
||||||
byte[] chars = new byte[string.length()];
|
var chars = new byte[string.length()];
|
||||||
for (int i = 0; i < chars.length; i++) {
|
for (var i = 0; i < chars.length; i++) {
|
||||||
char c = string.charAt(i);
|
var c = string.charAt(i);
|
||||||
chars[i] = c < 256 ? (byte) c : 63;
|
chars[i] = c < 256 ? (byte) c : 63;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ public final class LuaValues {
|
|||||||
* @return A string representation of the given value's type, in a similar format to that provided by Lua's
|
* @return A string representation of the given value's type, in a similar format to that provided by Lua's
|
||||||
* {@code type} function.
|
* {@code type} function.
|
||||||
*/
|
*/
|
||||||
public static String getType(Object value) {
|
public static String getType(@Nullable Object value) {
|
||||||
if (value == null) return "nil";
|
if (value == null) return "nil";
|
||||||
if (value instanceof String) return "string";
|
if (value instanceof String) return "string";
|
||||||
if (value instanceof Boolean) return "boolean";
|
if (value instanceof Boolean) return "boolean";
|
||||||
@ -147,7 +148,7 @@ public final class LuaValues {
|
|||||||
* @throws LuaException If this is not a known enum value.
|
* @throws LuaException If this is not a known enum value.
|
||||||
*/
|
*/
|
||||||
public static <T extends Enum<T>> T checkEnum(int index, Class<T> klass, String value) throws LuaException {
|
public static <T extends Enum<T>> T checkEnum(int index, Class<T> klass, String value) throws LuaException {
|
||||||
for (T possibility : klass.getEnumConstants()) {
|
for (var possibility : klass.getEnumConstants()) {
|
||||||
if (possibility.name().equalsIgnoreCase(value)) return possibility;
|
if (possibility.name().equalsIgnoreCase(value)) return possibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -44,6 +45,7 @@ public final class ObjectArguments extends IArguments {
|
|||||||
return new ObjectArguments(args.subList(count, args.size()));
|
return new ObjectArguments(args.subList(count, args.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object get(int index) {
|
public Object get(int index) {
|
||||||
return index >= args.size() ? null : args.get(index);
|
return index >= args.size() ? null : args.get(index);
|
||||||
|
@ -152,6 +152,6 @@ public class FixedWidthFontRenderer {
|
|||||||
if (c >= '0' && c <= '9') return c - '0';
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
return 15 - def.ordinal();
|
return def.ordinal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,27 +371,36 @@ public class FSAPI implements ILuaAPI {
|
|||||||
public final Object[] open(String path, String mode) throws LuaException {
|
public final Object[] open(String path, String mode) throws LuaException {
|
||||||
try {
|
try {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
case "r" -> {
|
||||||
// Open the file for reading, then create a wrapper around the reader
|
// Open the file for reading, then create a wrapper around the reader
|
||||||
case "r":
|
|
||||||
return new Object[]{ new EncodedReadableHandle(getFileSystem().openForRead(path)) };
|
return new Object[]{ new EncodedReadableHandle(getFileSystem().openForRead(path)) };
|
||||||
|
}
|
||||||
|
case "w" -> {
|
||||||
// Open the file for writing, then create a wrapper around the writer
|
// Open the file for writing, then create a wrapper around the writer
|
||||||
case "w":
|
FileSystemExtensions.makeParentDir(fileSystem, path);
|
||||||
return new Object[]{ new EncodedWritableHandle(getFileSystem().openForWrite(path, false)) };
|
return new Object[]{ new EncodedWritableHandle(getFileSystem().openForWrite(path, false)) };
|
||||||
|
}
|
||||||
|
case "a" -> {
|
||||||
// Open the file for appending, then create a wrapper around the writer
|
// Open the file for appending, then create a wrapper around the writer
|
||||||
case "a":
|
FileSystemExtensions.makeParentDir(fileSystem, path);
|
||||||
return new Object[]{ new EncodedWritableHandle(getFileSystem().openForWrite(path, true)) };
|
return new Object[]{ new EncodedWritableHandle(getFileSystem().openForWrite(path, true)) };
|
||||||
|
}
|
||||||
|
case "rb" -> {
|
||||||
// Open the file for binary reading, then create a wrapper around the reader
|
// Open the file for binary reading, then create a wrapper around the reader
|
||||||
case "rb":
|
|
||||||
IMountedFileBinary reader = getFileSystem().openForBinaryRead(path);
|
IMountedFileBinary reader = getFileSystem().openForBinaryRead(path);
|
||||||
return new Object[]{ new BinaryReadableHandle(reader) };
|
return new Object[]{ new BinaryReadableHandle(reader) };
|
||||||
|
}
|
||||||
|
case "wb" -> {
|
||||||
// Open the file for binary writing, then create a wrapper around the writer
|
// Open the file for binary writing, then create a wrapper around the writer
|
||||||
case "wb":
|
FileSystemExtensions.makeParentDir(fileSystem, path);
|
||||||
return new Object[]{ new BinaryWritableHandle(getFileSystem().openForBinaryWrite(path, false)) };
|
return new Object[]{ new BinaryWritableHandle(getFileSystem().openForBinaryWrite(path, false)) };
|
||||||
|
}
|
||||||
|
case "ab" -> {
|
||||||
// Open the file for binary appending, then create a wrapper around the reader
|
// Open the file for binary appending, then create a wrapper around the reader
|
||||||
case "ab":
|
FileSystemExtensions.makeParentDir(fileSystem, path);
|
||||||
return new Object[]{ new BinaryWritableHandle(getFileSystem().openForBinaryWrite(path, true)) };
|
return new Object[]{ new BinaryWritableHandle(getFileSystem().openForBinaryWrite(path, true)) };
|
||||||
default:
|
}
|
||||||
throw new LuaException("Unsupported mode");
|
default -> throw new LuaException("Unsupported mode");
|
||||||
}
|
}
|
||||||
} catch (FileSystemException e) {
|
} catch (FileSystemException e) {
|
||||||
return new Object[]{ null, e.getMessage() };
|
return new Object[]{ null, e.getMessage() };
|
||||||
@ -442,29 +451,6 @@ public class FSAPI implements ILuaAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for files matching a string with wildcards.
|
|
||||||
* <p>
|
|
||||||
* This string is formatted like a normal path string, but can include any
|
|
||||||
* number of wildcards ({@code *}) to look for files matching anything.
|
|
||||||
* For example, <code>rom/*/command*</code> will look for any path starting with
|
|
||||||
* {@code command} inside any subdirectory of {@code /rom}.
|
|
||||||
*
|
|
||||||
* @param path The wildcard-qualified path to search for.
|
|
||||||
* @return A list of paths that match the search string.
|
|
||||||
* @throws LuaException If the path doesn't exist.
|
|
||||||
* @cc.since 1.6
|
|
||||||
*/
|
|
||||||
@LuaFunction
|
|
||||||
public final String[] find(String path) throws LuaException {
|
|
||||||
try {
|
|
||||||
return FileSystemExtensions.find(getFileSystem(), path);
|
|
||||||
} catch (FileSystemException e) {
|
|
||||||
throw new LuaException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the capacity of the drive the path is located on.
|
* Returns the capacity of the drive the path is located on.
|
||||||
*
|
*
|
||||||
|
@ -7,54 +7,15 @@ import com.google.common.base.Splitter;
|
|||||||
import dan200.computer.core.FileSystem;
|
import dan200.computer.core.FileSystem;
|
||||||
import dan200.computer.core.FileSystemException;
|
import dan200.computer.core.FileSystemException;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backports additional methods from {@link FileSystem}.
|
* Backports additional methods from {@link FileSystem}.
|
||||||
*/
|
*/
|
||||||
final class FileSystemExtensions {
|
final class FileSystemExtensions {
|
||||||
private static void findIn(FileSystem fs, String dir, List<String> matches, Pattern wildPattern) throws FileSystemException {
|
|
||||||
String[] list = fs.list(dir);
|
|
||||||
for (String entry : list) {
|
|
||||||
String entryPath = dir.isEmpty() ? entry : dir + "/" + entry;
|
|
||||||
if (wildPattern.matcher(entryPath).matches()) {
|
|
||||||
matches.add(entryPath);
|
|
||||||
}
|
|
||||||
if (fs.isDir(entryPath)) {
|
|
||||||
findIn(fs, entryPath, matches, wildPattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized String[] find(FileSystem fs, String wildPath) throws FileSystemException {
|
|
||||||
// Match all the files on the system
|
|
||||||
wildPath = sanitizePath(wildPath, true);
|
|
||||||
|
|
||||||
// If we don't have a wildcard at all just check the file exists
|
|
||||||
int starIndex = wildPath.indexOf('*');
|
|
||||||
if (starIndex == -1) {
|
|
||||||
return fs.exists(wildPath) ? new String[]{ wildPath } : new String[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the all non-wildcarded directories. For instance foo/bar/baz* -> foo/bar
|
|
||||||
int prevDir = wildPath.substring(0, starIndex).lastIndexOf('/');
|
|
||||||
String startDir = prevDir == -1 ? "" : wildPath.substring(0, prevDir);
|
|
||||||
|
|
||||||
// If this isn't a directory then just abort
|
|
||||||
if (!fs.isDir(startDir)) return new String[0];
|
|
||||||
|
|
||||||
// Scan as normal, starting from this directory
|
|
||||||
Pattern wildPattern = Pattern.compile("^\\Q" + wildPath.replaceAll("\\*", "\\\\E[^\\\\/]*\\\\Q") + "\\E$");
|
|
||||||
List<String> matches = new ArrayList<>();
|
|
||||||
findIn(fs, startDir, matches, wildPattern);
|
|
||||||
|
|
||||||
// Return matches
|
|
||||||
String[] array = matches.toArray(new String[0]);
|
|
||||||
Arrays.sort(array);
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDirectory(String path) {
|
public static String getDirectory(String path) {
|
||||||
path = sanitizePath(path, true);
|
path = sanitizePath(path, true);
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
@ -69,6 +30,11 @@ final class FileSystemExtensions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void makeParentDir(FileSystem fileSystem, String path) throws FileSystemException {
|
||||||
|
var parent = getDirectory(path);
|
||||||
|
if (!parent.isEmpty()) fileSystem.makeDir(parent);
|
||||||
|
}
|
||||||
|
|
||||||
private static final Pattern threeDotsPattern = Pattern.compile("^\\.{3,}$");
|
private static final Pattern threeDotsPattern = Pattern.compile("^\\.{3,}$");
|
||||||
|
|
||||||
public static String sanitizePath(String path, boolean allowWildcards) {
|
public static String sanitizePath(String path, boolean allowWildcards) {
|
||||||
|
@ -9,10 +9,10 @@ public final class StringUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String normaliseLabel(String label) {
|
public static String normaliseLabel(String label) {
|
||||||
int length = Math.min(32, label.length());
|
var length = Math.min(32, label.length());
|
||||||
StringBuilder builder = new StringBuilder(length);
|
var builder = new StringBuilder(length);
|
||||||
for (int i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
char c = label.charAt(i);
|
var c = label.charAt(i);
|
||||||
if ((c >= ' ' && c <= '~') || (c >= 161 && c <= 172) || (c >= 174 && c <= 255)) {
|
if ((c >= ' ' && c <= '~') || (c >= 161 && c <= 172) || (c >= 174 && c <= 255)) {
|
||||||
builder.append(c);
|
builder.append(c);
|
||||||
} else {
|
} else {
|
||||||
|
@ -687,7 +687,7 @@ settings.define("paint.default_extension", {
|
|||||||
|
|
||||||
settings.define("list.show_hidden", {
|
settings.define("list.show_hidden", {
|
||||||
default = false,
|
default = false,
|
||||||
description = [[Show hidden files (those starting with "." in the Lua REPL).]],
|
description = [[Whether the list program show hidden files (those starting with ".").]],
|
||||||
type = "boolean",
|
type = "boolean",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -3,20 +3,20 @@
|
|||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--[[- Constants and functions for colour values, suitable for working with
|
--[[- Constants and functions for colour values, suitable for working with
|
||||||
@{term} and @{redstone}.
|
[`term`] and [`redstone`].
|
||||||
|
|
||||||
This is useful in conjunction with @{redstone.setBundledOutput|Bundled Cables}
|
This is useful in conjunction with [Bundled Cables][`redstone.setBundledOutput`]
|
||||||
from mods like Project Red, and @{term.setTextColour|colors on Advanced
|
from mods like Project Red, and [colors on Advanced Computers and Advanced
|
||||||
Computers and Advanced Monitors}.
|
Monitors][`term.setTextColour`].
|
||||||
|
|
||||||
For the non-American English version just replace @{colors} with @{colours}.
|
For the non-American English version just replace [`colors`] with [`colours`].
|
||||||
This alternative API is exactly the same, except the colours use British English
|
This alternative API is exactly the same, except the colours use British English
|
||||||
(e.g. @{colors.gray} is spelt @{colours.grey}).
|
(e.g. [`colors.gray`] is spelt [`colours.grey`]).
|
||||||
|
|
||||||
On basic terminals (such as the Computer and Monitor), all the colors are
|
On basic terminals (such as the Computer and Monitor), all the colors are
|
||||||
converted to grayscale. This means you can still use all 16 colors on the
|
converted to grayscale. This means you can still use all 16 colors on the
|
||||||
screen, but they will appear as the nearest tint of gray. You can check if a
|
screen, but they will appear as the nearest tint of gray. You can check if a
|
||||||
terminal supports color by using the function @{term.isColor}.
|
terminal supports color by using the function [`term.isColor`].
|
||||||
|
|
||||||
Grayscale colors are calculated by taking the average of the three components,
|
Grayscale colors are calculated by taking the average of the three components,
|
||||||
i.e. `(red + green + blue) / 3`.
|
i.e. `(red + green + blue) / 3`.
|
||||||
@ -140,67 +140,67 @@ i.e. `(red + green + blue) / 3`.
|
|||||||
|
|
||||||
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
||||||
|
|
||||||
--- White: Written as `0` in paint files and @{term.blit}, has a default
|
--- White: Written as `0` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #F0F0F0.
|
-- terminal colour of #F0F0F0.
|
||||||
white = 0x1
|
white = 0x1
|
||||||
|
|
||||||
--- Orange: Written as `1` in paint files and @{term.blit}, has a
|
--- Orange: Written as `1` in paint files and [`term.blit`], has a
|
||||||
-- default terminal colour of #F2B233.
|
-- default terminal colour of #F2B233.
|
||||||
orange = 0x2
|
orange = 0x2
|
||||||
|
|
||||||
--- Magenta: Written as `2` in paint files and @{term.blit}, has a
|
--- Magenta: Written as `2` in paint files and [`term.blit`], has a
|
||||||
-- default terminal colour of #E57FD8.
|
-- default terminal colour of #E57FD8.
|
||||||
magenta = 0x4
|
magenta = 0x4
|
||||||
|
|
||||||
--- Light blue: Written as `3` in paint files and @{term.blit}, has a
|
--- Light blue: Written as `3` in paint files and [`term.blit`], has a
|
||||||
-- default terminal colour of #99B2F2.
|
-- default terminal colour of #99B2F2.
|
||||||
lightBlue = 0x8
|
lightBlue = 0x8
|
||||||
|
|
||||||
--- Yellow: Written as `4` in paint files and @{term.blit}, has a
|
--- Yellow: Written as `4` in paint files and [`term.blit`], has a
|
||||||
-- default terminal colour of #DEDE6C.
|
-- default terminal colour of #DEDE6C.
|
||||||
yellow = 0x10
|
yellow = 0x10
|
||||||
|
|
||||||
--- Lime: Written as `5` in paint files and @{term.blit}, has a default
|
--- Lime: Written as `5` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #7FCC19.
|
-- terminal colour of #7FCC19.
|
||||||
lime = 0x20
|
lime = 0x20
|
||||||
|
|
||||||
--- Pink: Written as `6` in paint files and @{term.blit}, has a default
|
--- Pink: Written as `6` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #F2B2CC.
|
-- terminal colour of #F2B2CC.
|
||||||
pink = 0x40
|
pink = 0x40
|
||||||
|
|
||||||
--- Gray: Written as `7` in paint files and @{term.blit}, has a default
|
--- Gray: Written as `7` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #4C4C4C.
|
-- terminal colour of #4C4C4C.
|
||||||
gray = 0x80
|
gray = 0x80
|
||||||
|
|
||||||
--- Light gray: Written as `8` in paint files and @{term.blit}, has a
|
--- Light gray: Written as `8` in paint files and [`term.blit`], has a
|
||||||
-- default terminal colour of #999999.
|
-- default terminal colour of #999999.
|
||||||
lightGray = 0x100
|
lightGray = 0x100
|
||||||
|
|
||||||
--- Cyan: Written as `9` in paint files and @{term.blit}, has a default
|
--- Cyan: Written as `9` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #4C99B2.
|
-- terminal colour of #4C99B2.
|
||||||
cyan = 0x200
|
cyan = 0x200
|
||||||
|
|
||||||
--- Purple: Written as `a` in paint files and @{term.blit}, has a
|
--- Purple: Written as `a` in paint files and [`term.blit`], has a
|
||||||
-- default terminal colour of #B266E5.
|
-- default terminal colour of #B266E5.
|
||||||
purple = 0x400
|
purple = 0x400
|
||||||
|
|
||||||
--- Blue: Written as `b` in paint files and @{term.blit}, has a default
|
--- Blue: Written as `b` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #3366CC.
|
-- terminal colour of #3366CC.
|
||||||
blue = 0x800
|
blue = 0x800
|
||||||
|
|
||||||
--- Brown: Written as `c` in paint files and @{term.blit}, has a default
|
--- Brown: Written as `c` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #7F664C.
|
-- terminal colour of #7F664C.
|
||||||
brown = 0x1000
|
brown = 0x1000
|
||||||
|
|
||||||
--- Green: Written as `d` in paint files and @{term.blit}, has a default
|
--- Green: Written as `d` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #57A64E.
|
-- terminal colour of #57A64E.
|
||||||
green = 0x2000
|
green = 0x2000
|
||||||
|
|
||||||
--- Red: Written as `e` in paint files and @{term.blit}, has a default
|
--- Red: Written as `e` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #CC4C4C.
|
-- terminal colour of #CC4C4C.
|
||||||
red = 0x4000
|
red = 0x4000
|
||||||
|
|
||||||
--- Black: Written as `f` in paint files and @{term.blit}, has a default
|
--- Black: Written as `f` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #111111.
|
-- terminal colour of #111111.
|
||||||
black = 0x8000
|
black = 0x8000
|
||||||
|
|
||||||
@ -313,18 +313,18 @@ function unpackRGB(rgb)
|
|||||||
bit32.band(rgb, 0xFF) / 255
|
bit32.band(rgb, 0xFF) / 255
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many
|
--- Either calls [`colors.packRGB`] or [`colors.unpackRGB`], depending on how many
|
||||||
-- arguments it receives.
|
-- arguments it receives.
|
||||||
--
|
--
|
||||||
-- @tparam[1] number r The red channel, as an argument to @{colors.packRGB}.
|
-- @tparam[1] number r The red channel, as an argument to [`colors.packRGB`].
|
||||||
-- @tparam[1] number g The green channel, as an argument to @{colors.packRGB}.
|
-- @tparam[1] number g The green channel, as an argument to [`colors.packRGB`].
|
||||||
-- @tparam[1] number b The blue channel, as an argument to @{colors.packRGB}.
|
-- @tparam[1] number b The blue channel, as an argument to [`colors.packRGB`].
|
||||||
-- @tparam[2] number rgb The combined hexadecimal color, as an argument to @{colors.unpackRGB}.
|
-- @tparam[2] number rgb The combined hexadecimal color, as an argument to [`colors.unpackRGB`].
|
||||||
-- @treturn[1] number The combined hexadecimal colour, as returned by @{colors.packRGB}.
|
-- @treturn[1] number The combined hexadecimal colour, as returned by [`colors.packRGB`].
|
||||||
-- @treturn[2] number The red channel, as returned by @{colors.unpackRGB}
|
-- @treturn[2] number The red channel, as returned by [`colors.unpackRGB`]
|
||||||
-- @treturn[2] number The green channel, as returned by @{colors.unpackRGB}
|
-- @treturn[2] number The green channel, as returned by [`colors.unpackRGB`]
|
||||||
-- @treturn[2] number The blue channel, as returned by @{colors.unpackRGB}
|
-- @treturn[2] number The blue channel, as returned by [`colors.unpackRGB`]
|
||||||
-- @deprecated Use @{packRGB} or @{unpackRGB} directly.
|
-- @deprecated Use [`packRGB`] or [`unpackRGB`] directly.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- ```lua
|
-- ```lua
|
||||||
-- colors.rgb8(0xb23399)
|
-- colors.rgb8(0xb23399)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--- An alternative version of @{colors} for lovers of British spelling.
|
--- An alternative version of [`colors`] for lovers of British spelling.
|
||||||
--
|
--
|
||||||
-- @see colors
|
-- @see colors
|
||||||
-- @module colours
|
-- @module colours
|
||||||
@ -13,14 +13,14 @@ for k, v in pairs(colors) do
|
|||||||
colours[k] = v
|
colours[k] = v
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Grey. Written as `7` in paint files and @{term.blit}, has a default
|
--- Grey. Written as `7` in paint files and [`term.blit`], has a default
|
||||||
-- terminal colour of #4C4C4C.
|
-- terminal colour of #4C4C4C.
|
||||||
--
|
--
|
||||||
-- @see colors.gray
|
-- @see colors.gray
|
||||||
colours.grey = colors.gray
|
colours.grey = colors.gray
|
||||||
colours.gray = nil --- @local
|
colours.gray = nil --- @local
|
||||||
|
|
||||||
--- Light grey. Written as `8` in paint files and @{term.blit}, has a
|
--- Light grey. Written as `8` in paint files and [`term.blit`], has a
|
||||||
-- default terminal colour of #999999.
|
-- default terminal colour of #999999.
|
||||||
--
|
--
|
||||||
-- @see colors.lightGray
|
-- @see colors.lightGray
|
||||||
|
@ -5,20 +5,19 @@
|
|||||||
--[[- Execute [Minecraft commands][mc] and gather data from the results from
|
--[[- Execute [Minecraft commands][mc] and gather data from the results from
|
||||||
a command computer.
|
a command computer.
|
||||||
|
|
||||||
:::note
|
> [!NOTE]
|
||||||
This API is only available on Command computers. It is not accessible to normal
|
> This API is only available on Command computers. It is not accessible to normal
|
||||||
players.
|
> players.
|
||||||
:::
|
|
||||||
|
|
||||||
While one may use @{commands.exec} directly to execute a command, the
|
While one may use [`commands.exec`] directly to execute a command, the
|
||||||
commands API also provides helper methods to execute every command. For
|
commands API also provides helper methods to execute every command. For
|
||||||
instance, `commands.say("Hi!")` is equivalent to `commands.exec("say Hi!")`.
|
instance, `commands.say("Hi!")` is equivalent to `commands.exec("say Hi!")`.
|
||||||
|
|
||||||
@{commands.async} provides a similar interface to execute asynchronous
|
[`commands.async`] provides a similar interface to execute asynchronous
|
||||||
commands. `commands.async.say("Hi!")` is equivalent to
|
commands. `commands.async.say("Hi!")` is equivalent to
|
||||||
`commands.execAsync("say Hi!")`.
|
`commands.execAsync("say Hi!")`.
|
||||||
|
|
||||||
[mc]: https://minecraft.gamepedia.com/Commands
|
[mc]: https://minecraft.wiki/w/Commands
|
||||||
|
|
||||||
@module commands
|
@module commands
|
||||||
@usage Set the block above this computer to stone:
|
@usage Set the block above this computer to stone:
|
||||||
@ -31,7 +30,7 @@ end
|
|||||||
|
|
||||||
--- The builtin commands API, without any generated command helper functions
|
--- The builtin commands API, without any generated command helper functions
|
||||||
--
|
--
|
||||||
-- This may be useful if a built-in function (such as @{commands.list}) has been
|
-- This may be useful if a built-in function (such as [`commands.list`]) has been
|
||||||
-- overwritten by a command.
|
-- overwritten by a command.
|
||||||
local native = commands.native or commands
|
local native = commands.native or commands
|
||||||
|
|
||||||
@ -112,7 +111,7 @@ end
|
|||||||
|
|
||||||
--- A table containing asynchronous wrappers for all commands.
|
--- A table containing asynchronous wrappers for all commands.
|
||||||
--
|
--
|
||||||
-- As with @{commands.execAsync}, this returns the "task id" of the enqueued
|
-- As with [`commands.execAsync`], this returns the "task id" of the enqueued
|
||||||
-- command.
|
-- command.
|
||||||
-- @see execAsync
|
-- @see execAsync
|
||||||
-- @usage Asynchronously sets the block above the computer to stone.
|
-- @usage Asynchronously sets the block above the computer to stone.
|
||||||
|
@ -9,10 +9,9 @@ locally attached drive, specify “side” as one of the six sides (e.g. `left`)
|
|||||||
use a remote disk drive, specify its name as printed when enabling its modem
|
use a remote disk drive, specify its name as printed when enabling its modem
|
||||||
(e.g. `drive_0`).
|
(e.g. `drive_0`).
|
||||||
|
|
||||||
:::tip
|
> [!TIP]
|
||||||
All computers (except command computers), turtles and pocket computers can be
|
> All computers (except command computers), turtles and pocket computers can be
|
||||||
placed within a disk drive to access it's internal storage like a disk.
|
> placed within a disk drive to access it's internal storage like a disk.
|
||||||
:::
|
|
||||||
|
|
||||||
@module disk
|
@module disk
|
||||||
@since 1.2
|
@since 1.2
|
||||||
@ -95,9 +94,9 @@ end
|
|||||||
--- Whether the current disk is a [music disk][disk] as opposed to a floppy disk
|
--- Whether the current disk is a [music disk][disk] as opposed to a floppy disk
|
||||||
-- or other item.
|
-- or other item.
|
||||||
--
|
--
|
||||||
-- If this returns true, you will can @{disk.playAudio|play} the record.
|
-- If this returns true, you will can [play][`disk.playAudio`] the record.
|
||||||
--
|
--
|
||||||
-- [disk]: https://minecraft.gamepedia.com/Music_Disc
|
-- [disk]: https://minecraft.wiki/w/Music_Disc
|
||||||
--
|
--
|
||||||
-- @tparam string name The name of the disk drive.
|
-- @tparam string name The name of the disk drive.
|
||||||
-- @treturn boolean If the disk is present and has audio saved on it.
|
-- @treturn boolean If the disk is present and has audio saved on it.
|
||||||
@ -110,10 +109,10 @@ end
|
|||||||
|
|
||||||
--- Get the title of the audio track from the music record in the drive.
|
--- Get the title of the audio track from the music record in the drive.
|
||||||
--
|
--
|
||||||
-- This generally returns the same as @{disk.getLabel} for records.
|
-- This generally returns the same as [`disk.getLabel`] for records.
|
||||||
--
|
--
|
||||||
-- @tparam string name The name of the disk drive.
|
-- @tparam string name The name of the disk drive.
|
||||||
-- @treturn string|false|nil The track title, @{false} if there is not a music
|
-- @treturn string|false|nil The track title, [`false`] if there is not a music
|
||||||
-- record in the drive or `nil` if no drive is present.
|
-- record in the drive or `nil` if no drive is present.
|
||||||
function getAudioTitle(name)
|
function getAudioTitle(name)
|
||||||
if isDrive(name) then
|
if isDrive(name) then
|
||||||
@ -126,7 +125,7 @@ end
|
|||||||
--
|
--
|
||||||
-- If any record is already playing on any disk drive, it stops before the
|
-- If any record is already playing on any disk drive, it stops before the
|
||||||
-- target drive starts playing. The record stops when it reaches the end of the
|
-- target drive starts playing. The record stops when it reaches the end of the
|
||||||
-- track, when it is removed from the drive, when @{disk.stopAudio} is called, or
|
-- track, when it is removed from the drive, when [`disk.stopAudio`] is called, or
|
||||||
-- when another record is started.
|
-- when another record is started.
|
||||||
--
|
--
|
||||||
-- @tparam string name The name of the disk drive.
|
-- @tparam string name The name of the disk drive.
|
||||||
@ -138,7 +137,7 @@ function playAudio(name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Stops the music record in the drive from playing, if it was started with
|
--- Stops the music record in the drive from playing, if it was started with
|
||||||
-- @{disk.playAudio}.
|
-- [`disk.playAudio`].
|
||||||
--
|
--
|
||||||
-- @tparam string name The name o the disk drive.
|
-- @tparam string name The name o the disk drive.
|
||||||
function stopAudio(name)
|
function stopAudio(name)
|
||||||
@ -165,7 +164,7 @@ end
|
|||||||
|
|
||||||
--- Returns a number which uniquely identifies the disk in the drive.
|
--- Returns a number which uniquely identifies the disk in the drive.
|
||||||
--
|
--
|
||||||
-- Note, unlike @{disk.getLabel}, this does not return anything for other media,
|
-- Note, unlike [`disk.getLabel`], this does not return anything for other media,
|
||||||
-- such as computers or turtles.
|
-- such as computers or turtles.
|
||||||
--
|
--
|
||||||
-- @tparam string name The name of the disk drive.
|
-- @tparam string name The name of the disk drive.
|
||||||
|
@ -13,19 +13,19 @@ local fs = _ENV
|
|||||||
for k, v in pairs(native) do fs[k] = v end
|
for k, v in pairs(native) do fs[k] = v end
|
||||||
|
|
||||||
--[[- Provides completion for a file or directory name, suitable for use with
|
--[[- Provides completion for a file or directory name, suitable for use with
|
||||||
@{_G.read}.
|
[`_G.read`].
|
||||||
|
|
||||||
When a directory is a possible candidate for completion, two entries are
|
When a directory is a possible candidate for completion, two entries are
|
||||||
included - one with a trailing slash (indicating that entries within this
|
included - one with a trailing slash (indicating that entries within this
|
||||||
directory exist) and one without it (meaning this entry is an immediate
|
directory exist) and one without it (meaning this entry is an immediate
|
||||||
completion candidate). `include_dirs` can be set to @{false} to only include
|
completion candidate). `include_dirs` can be set to [`false`] to only include
|
||||||
those with a trailing slash.
|
those with a trailing slash.
|
||||||
|
|
||||||
@tparam[1] string path The path to complete.
|
@tparam[1] string path The path to complete.
|
||||||
@tparam[1] string location The location where paths are resolved from.
|
@tparam[1] string location The location where paths are resolved from.
|
||||||
@tparam[1,opt=true] boolean include_files When @{false}, only directories will
|
@tparam[1,opt=true] boolean include_files When [`false`], only directories will
|
||||||
be included in the returned list.
|
be included in the returned list.
|
||||||
@tparam[1,opt=true] boolean include_dirs When @{false}, "raw" directories will
|
@tparam[1,opt=true] boolean include_dirs When [`false`], "raw" directories will
|
||||||
not be included in the returned list.
|
not be included in the returned list.
|
||||||
|
|
||||||
@tparam[2] string path The path to complete.
|
@tparam[2] string path The path to complete.
|
||||||
@ -133,6 +133,93 @@ function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs)
|
|||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function find_aux(path, parts, i, out)
|
||||||
|
local part = parts[i]
|
||||||
|
if not part then
|
||||||
|
-- If we're at the end of the pattern, ensure our path exists and append it.
|
||||||
|
if fs.exists(path) then out[#out + 1] = path end
|
||||||
|
elseif part.exact then
|
||||||
|
-- If we're an exact match, just recurse into this directory.
|
||||||
|
return find_aux(fs.combine(path, part.contents), parts, i + 1, out)
|
||||||
|
else
|
||||||
|
-- Otherwise we're a pattern. Check we're a directory, then recurse into each
|
||||||
|
-- matching file.
|
||||||
|
if not fs.isDir(path) then return end
|
||||||
|
|
||||||
|
local files = fs.list(path)
|
||||||
|
for j = 1, #files do
|
||||||
|
local file = files[j]
|
||||||
|
if file:find(part.contents) then find_aux(fs.combine(path, file), parts, i + 1, out) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local find_escape = {
|
||||||
|
-- Escape standard Lua pattern characters
|
||||||
|
["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%",
|
||||||
|
["."] = "%.", ["["] = "%[", ["]"] = "%]", ["+"] = "%+", ["-"] = "%-",
|
||||||
|
-- Aside from our wildcards.
|
||||||
|
["*"] = ".*",
|
||||||
|
["?"] = ".",
|
||||||
|
}
|
||||||
|
|
||||||
|
--[[- Searches for files matching a string with wildcards.
|
||||||
|
|
||||||
|
This string looks like a normal path string, but can include wildcards, which
|
||||||
|
can match multiple paths:
|
||||||
|
|
||||||
|
- "?" matches any single character in a file name.
|
||||||
|
- "*" matches any number of characters.
|
||||||
|
|
||||||
|
For example, `rom/*/command*` will look for any path starting with `command`
|
||||||
|
inside any subdirectory of `/rom`.
|
||||||
|
|
||||||
|
Note that these wildcards match a single segment of the path. For instance
|
||||||
|
`rom/*.lua` will include `rom/startup.lua` but _not_ include `rom/programs/list.lua`.
|
||||||
|
|
||||||
|
@tparam string path The wildcard-qualified path to search for.
|
||||||
|
@treturn { string... } A list of paths that match the search string.
|
||||||
|
@throws If the supplied path was invalid.
|
||||||
|
@since 1.6
|
||||||
|
@changed 1.106.0 Added support for the `?` wildcard.
|
||||||
|
|
||||||
|
@usage List all Markdown files in the help folder
|
||||||
|
|
||||||
|
fs.find("rom/help/*.md")
|
||||||
|
]]
|
||||||
|
function fs.find(pattern)
|
||||||
|
expect(1, pattern, "string")
|
||||||
|
|
||||||
|
pattern = fs.combine(pattern) -- Normalise the path, removing ".."s.
|
||||||
|
|
||||||
|
-- If the pattern is trying to search outside the computer root, just abort.
|
||||||
|
-- This will fail later on anyway.
|
||||||
|
if pattern == ".." or pattern:sub(1, 3) == "../" then
|
||||||
|
error("/" .. pattern .. ": Invalid Path", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we've no wildcards, just check the file exists.
|
||||||
|
if not pattern:find("[*?]") then
|
||||||
|
if fs.exists(pattern) then return { pattern } else return {} end
|
||||||
|
end
|
||||||
|
|
||||||
|
local parts = {}
|
||||||
|
for part in pattern:gmatch("[^/]+") do
|
||||||
|
if part:find("[*?]") then
|
||||||
|
parts[#parts + 1] = {
|
||||||
|
exact = false,
|
||||||
|
contents = "^" .. part:gsub(".", find_escape) .. "$",
|
||||||
|
}
|
||||||
|
else
|
||||||
|
parts[#parts + 1] = { exact = true, contents = part }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local out = {}
|
||||||
|
find_aux("", parts, 1, out)
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns true if a path is mounted to the parent filesystem.
|
--- Returns true if a path is mounted to the parent filesystem.
|
||||||
--
|
--
|
||||||
-- The root filesystem "/" is considered a mount, along with disk folders and
|
-- The root filesystem "/" is considered a mount, along with disk folders and
|
||||||
|
@ -2,21 +2,20 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--[[- Use @{modem|modems} to locate the position of the current turtle or
|
--[[- Use [modems][`modem`] to locate the position of the current turtle or
|
||||||
computers.
|
computers.
|
||||||
|
|
||||||
It broadcasts a PING message over @{rednet} and wait for responses. In order for
|
It broadcasts a PING message over [`rednet`] and wait for responses. In order for
|
||||||
this system to work, there must be at least 4 computers used as gps hosts which
|
this system to work, there must be at least 4 computers used as gps hosts which
|
||||||
will respond and allow trilateration. Three of these hosts should be in a plane,
|
will respond and allow trilateration. Three of these hosts should be in a plane,
|
||||||
and the fourth should be either above or below the other three. The three in a
|
and the fourth should be either above or below the other three. The three in a
|
||||||
plane should not be in a line with each other. You can set up hosts using the
|
plane should not be in a line with each other. You can set up hosts using the
|
||||||
gps program.
|
gps program.
|
||||||
|
|
||||||
:::note
|
> [!NOTE]
|
||||||
When entering in the coordinates for the host you need to put in the `x`, `y`,
|
> When entering in the coordinates for the host you need to put in the `x`, `y`,
|
||||||
and `z` coordinates of the block that the modem is connected to, not the modem.
|
> and `z` coordinates of the block that the modem is connected to, not the modem.
|
||||||
All modem distances are measured from the block that the modem is placed on.
|
> All modem distances are measured from the block that the modem is placed on.
|
||||||
:::
|
|
||||||
|
|
||||||
Also note that you may choose which axes x, y, or z refers to - so long as your
|
Also note that you may choose which axes x, y, or z refers to - so long as your
|
||||||
systems have the same definition as any GPS servers that're in range, it works
|
systems have the same definition as any GPS servers that're in range, it works
|
||||||
|
@ -74,10 +74,10 @@ handleMetatable = {
|
|||||||
|
|
||||||
This can be used in a for loop to iterate over all lines of a file
|
This can be used in a for loop to iterate over all lines of a file
|
||||||
|
|
||||||
Once the end of the file has been reached, @{nil} will be returned. The file is
|
Once the end of the file has been reached, [`nil`] will be returned. The file is
|
||||||
*not* automatically closed.
|
*not* automatically closed.
|
||||||
|
|
||||||
@param ... The argument to pass to @{Handle:read} for each line.
|
@param ... The argument to pass to [`Handle:read`] for each line.
|
||||||
@treturn function():string|nil The line iterator.
|
@treturn function():string|nil The line iterator.
|
||||||
@throws If the file cannot be opened for reading
|
@throws If the file cannot be opened for reading
|
||||||
@since 1.3
|
@since 1.3
|
||||||
@ -324,14 +324,14 @@ each time it is called, returns a new line from the file.
|
|||||||
|
|
||||||
This can be used in a for loop to iterate over all lines of a file
|
This can be used in a for loop to iterate over all lines of a file
|
||||||
|
|
||||||
Once the end of the file has been reached, @{nil} will be returned. The file is
|
Once the end of the file has been reached, [`nil`] will be returned. The file is
|
||||||
automatically closed.
|
automatically closed.
|
||||||
|
|
||||||
If no file name is given, the @{io.input|current input} will be used instead.
|
If no file name is given, the [current input][`io.input`] will be used instead.
|
||||||
In this case, the handle is not used.
|
In this case, the handle is not used.
|
||||||
|
|
||||||
@tparam[opt] string filename The name of the file to extract lines from
|
@tparam[opt] string filename The name of the file to extract lines from
|
||||||
@param ... The argument to pass to @{Handle:read} for each line.
|
@param ... The argument to pass to [`Handle:read`] for each line.
|
||||||
@treturn function():string|nil The line iterator.
|
@treturn function():string|nil The line iterator.
|
||||||
@throws If the file cannot be opened for reading
|
@throws If the file cannot be opened for reading
|
||||||
|
|
||||||
@ -362,7 +362,7 @@ function lines(filename, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Open a file with the given mode, either returning a new file handle
|
--- Open a file with the given mode, either returning a new file handle
|
||||||
-- or @{nil}, plus an error message.
|
-- or [`nil`], plus an error message.
|
||||||
--
|
--
|
||||||
-- The `mode` string can be any of the following:
|
-- The `mode` string can be any of the following:
|
||||||
-- - **"r"**: Read mode
|
-- - **"r"**: Read mode
|
||||||
@ -410,11 +410,11 @@ end
|
|||||||
|
|
||||||
--- Read from the currently opened input file.
|
--- Read from the currently opened input file.
|
||||||
--
|
--
|
||||||
-- This is equivalent to `io.input():read(...)`. See @{Handle:read|the
|
-- This is equivalent to `io.input():read(...)`. See [the documentation][`Handle:read`]
|
||||||
-- documentation} there for full details.
|
-- there for full details.
|
||||||
--
|
--
|
||||||
-- @tparam string ... The formats to read, defaulting to a whole line.
|
-- @tparam string ... The formats to read, defaulting to a whole line.
|
||||||
-- @treturn (string|nil)... The data read, or @{nil} if nothing can be read.
|
-- @treturn (string|nil)... The data read, or [`nil`] if nothing can be read.
|
||||||
function read(...)
|
function read(...)
|
||||||
return currentInput:read(...)
|
return currentInput:read(...)
|
||||||
end
|
end
|
||||||
@ -438,8 +438,8 @@ end
|
|||||||
|
|
||||||
--- Write to the currently opened output file.
|
--- Write to the currently opened output file.
|
||||||
--
|
--
|
||||||
-- This is equivalent to `io.output():write(...)`. See @{Handle:write|the
|
-- This is equivalent to `io.output():write(...)`. See [the documentation][`Handle:write`]
|
||||||
-- documentation} there for full details.
|
-- there for full details.
|
||||||
--
|
--
|
||||||
-- @tparam string ... The strings to write
|
-- @tparam string ... The strings to write
|
||||||
-- @changed 1.81.0 Multiple arguments are now allowed.
|
-- @changed 1.81.0 Multiple arguments are now allowed.
|
||||||
|
@ -51,7 +51,7 @@ end
|
|||||||
--
|
--
|
||||||
-- @tparam string image The string containing the raw-image data.
|
-- @tparam string image The string containing the raw-image data.
|
||||||
-- @treturn table The parsed image data, suitable for use with
|
-- @treturn table The parsed image data, suitable for use with
|
||||||
-- @{paintutils.drawImage}.
|
-- [`paintutils.drawImage`].
|
||||||
-- @since 1.80pr1
|
-- @since 1.80pr1
|
||||||
function parseImage(image)
|
function parseImage(image)
|
||||||
expect(1, image, "string")
|
expect(1, image, "string")
|
||||||
@ -69,7 +69,7 @@ end
|
|||||||
-- @tparam string path The file to load.
|
-- @tparam string path The file to load.
|
||||||
--
|
--
|
||||||
-- @treturn table|nil The parsed image data, suitable for use with
|
-- @treturn table|nil The parsed image data, suitable for use with
|
||||||
-- @{paintutils.drawImage}, or `nil` if the file does not exist.
|
-- [`paintutils.drawImage`], or `nil` if the file does not exist.
|
||||||
-- @usage Load an image and draw it.
|
-- @usage Load an image and draw it.
|
||||||
--
|
--
|
||||||
-- local image = paintutils.loadImage("data/example.nfp")
|
-- local image = paintutils.loadImage("data/example.nfp")
|
||||||
@ -93,7 +93,7 @@ end
|
|||||||
--
|
--
|
||||||
-- @tparam number xPos The x position to draw at, where 1 is the far left.
|
-- @tparam number xPos The x position to draw at, where 1 is the far left.
|
||||||
-- @tparam number yPos The y position to draw at, where 1 is the very top.
|
-- @tparam number yPos The y position to draw at, where 1 is the very top.
|
||||||
-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be
|
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
|
||||||
-- the current background colour if not specified.
|
-- the current background colour if not specified.
|
||||||
function drawPixel(xPos, yPos, colour)
|
function drawPixel(xPos, yPos, colour)
|
||||||
expect(1, xPos, "number")
|
expect(1, xPos, "number")
|
||||||
@ -115,7 +115,7 @@ end
|
|||||||
-- @tparam number startY The starting y position of the line.
|
-- @tparam number startY The starting y position of the line.
|
||||||
-- @tparam number endX The end x position of the line.
|
-- @tparam number endX The end x position of the line.
|
||||||
-- @tparam number endY The end y position of the line.
|
-- @tparam number endY The end y position of the line.
|
||||||
-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be
|
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
|
||||||
-- the current background colour if not specified.
|
-- the current background colour if not specified.
|
||||||
-- @usage paintutils.drawLine(2, 3, 30, 7, colors.red)
|
-- @usage paintutils.drawLine(2, 3, 30, 7, colors.red)
|
||||||
function drawLine(startX, startY, endX, endY, colour)
|
function drawLine(startX, startY, endX, endY, colour)
|
||||||
@ -189,7 +189,7 @@ end
|
|||||||
-- @tparam number startY The starting y position of the line.
|
-- @tparam number startY The starting y position of the line.
|
||||||
-- @tparam number endX The end x position of the line.
|
-- @tparam number endX The end x position of the line.
|
||||||
-- @tparam number endY The end y position of the line.
|
-- @tparam number endY The end y position of the line.
|
||||||
-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be
|
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
|
||||||
-- the current background colour if not specified.
|
-- the current background colour if not specified.
|
||||||
-- @usage paintutils.drawBox(2, 3, 30, 7, colors.red)
|
-- @usage paintutils.drawBox(2, 3, 30, 7, colors.red)
|
||||||
function drawBox(startX, startY, endX, endY, nColour)
|
function drawBox(startX, startY, endX, endY, nColour)
|
||||||
@ -242,7 +242,7 @@ end
|
|||||||
-- @tparam number startY The starting y position of the line.
|
-- @tparam number startY The starting y position of the line.
|
||||||
-- @tparam number endX The end x position of the line.
|
-- @tparam number endX The end x position of the line.
|
||||||
-- @tparam number endY The end y position of the line.
|
-- @tparam number endY The end y position of the line.
|
||||||
-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be
|
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
|
||||||
-- the current background colour if not specified.
|
-- the current background colour if not specified.
|
||||||
-- @usage paintutils.drawFilledBox(2, 3, 30, 7, colors.red)
|
-- @usage paintutils.drawFilledBox(2, 3, 30, 7, colors.red)
|
||||||
function drawFilledBox(startX, startY, endX, endY, nColour)
|
function drawFilledBox(startX, startY, endX, endY, nColour)
|
||||||
@ -278,7 +278,7 @@ function drawFilledBox(startX, startY, endX, endY, nColour)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Draw an image loaded by @{paintutils.parseImage} or @{paintutils.loadImage}.
|
--- Draw an image loaded by [`paintutils.parseImage`] or [`paintutils.loadImage`].
|
||||||
--
|
--
|
||||||
-- @tparam table image The parsed image data.
|
-- @tparam table image The parsed image data.
|
||||||
-- @tparam number xPos The x position to start drawing at.
|
-- @tparam number xPos The x position to start drawing at.
|
||||||
|
@ -6,36 +6,34 @@
|
|||||||
|
|
||||||
Functions are not actually executed simultaneously, but rather this API will
|
Functions are not actually executed simultaneously, but rather this API will
|
||||||
automatically switch between them whenever they yield (e.g. whenever they call
|
automatically switch between them whenever they yield (e.g. whenever they call
|
||||||
@{coroutine.yield}, or functions that call that - such as @{os.pullEvent} - or
|
[`coroutine.yield`], or functions that call that - such as [`os.pullEvent`] - or
|
||||||
functions that call that, etc - basically, anything that causes the function
|
functions that call that, etc - basically, anything that causes the function
|
||||||
to "pause").
|
to "pause").
|
||||||
|
|
||||||
Each function executed in "parallel" gets its own copy of the event queue,
|
Each function executed in "parallel" gets its own copy of the event queue,
|
||||||
and so "event consuming" functions (again, mostly anything that causes the
|
and so "event consuming" functions (again, mostly anything that causes the
|
||||||
script to pause - eg @{os.sleep}, @{rednet.receive}, most of the @{turtle} API,
|
script to pause - eg [`os.sleep`], [`rednet.receive`], most of the [`turtle`] API,
|
||||||
etc) can safely be used in one without affecting the event queue accessed by
|
etc) can safely be used in one without affecting the event queue accessed by
|
||||||
the other.
|
the other.
|
||||||
|
|
||||||
|
|
||||||
:::caution
|
> [!WARNING]
|
||||||
When using this API, be careful to pass the functions you want to run in
|
> When using this API, be careful to pass the functions you want to run in
|
||||||
parallel, and _not_ the result of calling those functions.
|
> parallel, and _not_ the result of calling those functions.
|
||||||
|
>
|
||||||
For instance, the following is correct:
|
> For instance, the following is correct:
|
||||||
|
>
|
||||||
```lua
|
> ```lua
|
||||||
local function do_sleep() sleep(1) end
|
> local function do_sleep() sleep(1) end
|
||||||
parallel.waitForAny(do_sleep, rednet.receive)
|
> parallel.waitForAny(do_sleep, rednet.receive)
|
||||||
```
|
> ```
|
||||||
|
>
|
||||||
but the following is **NOT**:
|
> but the following is **NOT**:
|
||||||
|
>
|
||||||
```lua
|
> ```lua
|
||||||
local function do_sleep() sleep(1) end
|
> local function do_sleep() sleep(1) end
|
||||||
parallel.waitForAny(do_sleep(), rednet.receive)
|
> parallel.waitForAny(do_sleep(), rednet.receive)
|
||||||
```
|
> ```
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
@module parallel
|
@module parallel
|
||||||
@since 1.2
|
@since 1.2
|
||||||
@ -100,7 +98,7 @@ end
|
|||||||
|
|
||||||
--[[- Switches between execution of the functions, until any of them
|
--[[- Switches between execution of the functions, until any of them
|
||||||
finishes. If any of the functions errors, the message is propagated upwards
|
finishes. If any of the functions errors, the message is propagated upwards
|
||||||
from the @{parallel.waitForAny} call.
|
from the [`parallel.waitForAny`] call.
|
||||||
|
|
||||||
@tparam function ... The functions this task will run
|
@tparam function ... The functions this task will run
|
||||||
@usage Print a message every second until the `q` key is pressed.
|
@usage Print a message every second until the `q` key is pressed.
|
||||||
@ -128,7 +126,7 @@ end
|
|||||||
|
|
||||||
--[[- Switches between execution of the functions, until all of them are
|
--[[- Switches between execution of the functions, until all of them are
|
||||||
finished. If any of the functions errors, the message is propagated upwards
|
finished. If any of the functions errors, the message is propagated upwards
|
||||||
from the @{parallel.waitForAll} call.
|
from the [`parallel.waitForAll`] call.
|
||||||
|
|
||||||
@tparam function ... The functions this task will run
|
@tparam function ... The functions this task will run
|
||||||
@usage Start off two timers and wait for them both to run.
|
@usage Start off two timers and wait for them both to run.
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
--[[- Find and control peripherals attached to this computer.
|
--[[- Find and control peripherals attached to this computer.
|
||||||
|
|
||||||
Peripherals are blocks (or turtle and pocket computer upgrades) which can
|
Peripherals are blocks (or turtle and pocket computer upgrades) which can
|
||||||
be controlled by a computer. For instance, the @{speaker} peripheral allows a
|
be controlled by a computer. For instance, the [`speaker`] peripheral allows a
|
||||||
computer to play music and the @{monitor} peripheral allows you to display text
|
computer to play music and the [`monitor`] peripheral allows you to display text
|
||||||
in the world.
|
in the world.
|
||||||
|
|
||||||
## Referencing peripherals
|
## Referencing peripherals
|
||||||
@ -18,10 +18,10 @@ computer will be called `"bottom"` in your Lua code, one to the left called
|
|||||||
`"right"`, `"front"`, `"back"`).
|
`"right"`, `"front"`, `"back"`).
|
||||||
|
|
||||||
You can list the names of all peripherals with the `peripherals` program, or the
|
You can list the names of all peripherals with the `peripherals` program, or the
|
||||||
@{peripheral.getNames} function.
|
[`peripheral.getNames`] function.
|
||||||
|
|
||||||
It's also possible to use peripherals which are further away from your computer
|
It's also possible to use peripherals which are further away from your computer
|
||||||
through the use of @{modem|Wired Modems}. Place one modem against your computer
|
through the use of [Wired Modems][`modem`]. Place one modem against your computer
|
||||||
(you may need to sneak and right click), run Networking Cable to your
|
(you may need to sneak and right click), run Networking Cable to your
|
||||||
peripheral, and then place another modem against that block. You can then right
|
peripheral, and then place another modem against that block. You can then right
|
||||||
click the modem to use (or *attach*) the peripheral. This will print a
|
click the modem to use (or *attach*) the peripheral. This will print a
|
||||||
@ -32,24 +32,23 @@ clipboard.
|
|||||||
## Using peripherals
|
## Using peripherals
|
||||||
|
|
||||||
Once you have the name of a peripheral, you can call functions on it using the
|
Once you have the name of a peripheral, you can call functions on it using the
|
||||||
@{peripheral.call} function. This takes the name of our peripheral, the name of
|
[`peripheral.call`] function. This takes the name of our peripheral, the name of
|
||||||
the function we want to call, and then its arguments.
|
the function we want to call, and then its arguments.
|
||||||
|
|
||||||
:::info
|
> [!INFO]
|
||||||
Some bits of the peripheral API call peripheral functions *methods* instead
|
> Some bits of the peripheral API call peripheral functions *methods* instead
|
||||||
(for example, the @{peripheral.getMethods} function). Don't worry, they're the
|
> (for example, the [`peripheral.getMethods`] function). Don't worry, they're the
|
||||||
same thing!
|
> same thing!
|
||||||
:::
|
|
||||||
|
|
||||||
Let's say we have a monitor above our computer (and so "top") and want to
|
Let's say we have a monitor above our computer (and so "top") and want to
|
||||||
@{monitor.write|write some text to it}. We'd write the following:
|
[write some text to it][`monitor.write`]. We'd write the following:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
peripheral.call("top", "write", "This is displayed on a monitor!")
|
peripheral.call("top", "write", "This is displayed on a monitor!")
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you start calling making a couple of peripheral calls this can get very
|
Once you start calling making a couple of peripheral calls this can get very
|
||||||
repetitive, and so we can @{peripheral.wrap|wrap} a peripheral. This builds a
|
repetitive, and so we can [wrap][`peripheral.wrap`] a peripheral. This builds a
|
||||||
table of all the peripheral's functions so you can use it like an API or module.
|
table of all the peripheral's functions so you can use it like an API or module.
|
||||||
|
|
||||||
For instance, we could have written the above example as follows:
|
For instance, we could have written the above example as follows:
|
||||||
@ -66,7 +65,7 @@ called, you just need to know it's there. For instance, if you're writing a
|
|||||||
music player, you just need a speaker - it doesn't matter if it's above or below
|
music player, you just need a speaker - it doesn't matter if it's above or below
|
||||||
the computer.
|
the computer.
|
||||||
|
|
||||||
Thankfully there's a quick way to do this: @{peripheral.find}. This takes a
|
Thankfully there's a quick way to do this: [`peripheral.find`]. This takes a
|
||||||
*peripheral type* and returns all the attached peripherals which are of this
|
*peripheral type* and returns all the attached peripherals which are of this
|
||||||
type.
|
type.
|
||||||
|
|
||||||
@ -76,10 +75,10 @@ are just called `"speaker"`, and monitors `"monitor"`. Some peripherals might
|
|||||||
have more than one type - a Minecraft chest is both a `"minecraft:chest"` and
|
have more than one type - a Minecraft chest is both a `"minecraft:chest"` and
|
||||||
`"inventory"`.
|
`"inventory"`.
|
||||||
|
|
||||||
You can get all the types a peripheral has with @{peripheral.getType}, and check
|
You can get all the types a peripheral has with [`peripheral.getType`], and check
|
||||||
a peripheral is a specific type with @{peripheral.hasType}.
|
a peripheral is a specific type with [`peripheral.hasType`].
|
||||||
|
|
||||||
To return to our original example, let's use @{peripheral.find} to find an
|
To return to our original example, let's use [`peripheral.find`] to find an
|
||||||
attached speaker:
|
attached speaker:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
@ -233,7 +232,7 @@ function getMethods(name)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the name of a peripheral wrapped with @{peripheral.wrap}.
|
--- Get the name of a peripheral wrapped with [`peripheral.wrap`].
|
||||||
--
|
--
|
||||||
-- @tparam table peripheral The peripheral to get the name of.
|
-- @tparam table peripheral The peripheral to get the name of.
|
||||||
-- @treturn string The name of the given peripheral.
|
-- @treturn string The name of the given peripheral.
|
||||||
@ -274,7 +273,7 @@ function call(name, method, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Get a table containing all functions available on a peripheral. These can
|
--- Get a table containing all functions available on a peripheral. These can
|
||||||
-- then be called instead of using @{peripheral.call} every time.
|
-- then be called instead of using [`peripheral.call`] every time.
|
||||||
--
|
--
|
||||||
-- @tparam string name The name of the peripheral to wrap.
|
-- @tparam string name The name of the peripheral to wrap.
|
||||||
-- @treturn table|nil The table containing the peripheral's methods, or `nil` if
|
-- @treturn table|nil The table containing the peripheral's methods, or `nil` if
|
||||||
@ -309,7 +308,7 @@ function wrap(name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[- Find all peripherals of a specific type, and return the
|
--[[- Find all peripherals of a specific type, and return the
|
||||||
@{peripheral.wrap|wrapped} peripherals.
|
[wrapped][`peripheral.wrap`] peripherals.
|
||||||
|
|
||||||
@tparam string ty The type of peripheral to look for.
|
@tparam string ty The type of peripheral to look for.
|
||||||
@tparam[opt] function(name:string, wrapped:table):boolean filter A
|
@tparam[opt] function(name:string, wrapped:table):boolean filter A
|
||||||
@ -329,7 +328,7 @@ and returns if it should be included in the result.
|
|||||||
return modem.isWireless() -- Check this modem is wireless.
|
return modem.isWireless() -- Check this modem is wireless.
|
||||||
end) }
|
end) }
|
||||||
|
|
||||||
@usage This abuses the `filter` argument to call @{rednet.open} on every modem.
|
@usage This abuses the `filter` argument to call [`rednet.open`] on every modem.
|
||||||
|
|
||||||
peripheral.find("modem", rednet.open)
|
peripheral.find("modem", rednet.open)
|
||||||
@since 1.6
|
@since 1.6
|
||||||
|
@ -2,42 +2,41 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--[[- Communicate with other computers by using @{modem|modems}. @{rednet}
|
--[[- Communicate with other computers by using [modems][`modem`]. [`rednet`]
|
||||||
provides a layer of abstraction on top of the main @{modem} peripheral, making
|
provides a layer of abstraction on top of the main [`modem`] peripheral, making
|
||||||
it slightly easier to use.
|
it slightly easier to use.
|
||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
In order to send a message between two computers, each computer must have a
|
In order to send a message between two computers, each computer must have a
|
||||||
modem on one of its sides (or in the case of pocket computers and turtles, the
|
modem on one of its sides (or in the case of pocket computers and turtles, the
|
||||||
modem must be equipped as an upgrade). The two computers should then call
|
modem must be equipped as an upgrade). The two computers should then call
|
||||||
@{rednet.open}, which sets up the modems ready to send and receive messages.
|
[`rednet.open`], which sets up the modems ready to send and receive messages.
|
||||||
|
|
||||||
Once rednet is opened, you can send messages using @{rednet.send} and receive
|
Once rednet is opened, you can send messages using [`rednet.send`] and receive
|
||||||
them using @{rednet.receive}. It's also possible to send a message to _every_
|
them using [`rednet.receive`]. It's also possible to send a message to _every_
|
||||||
rednet-using computer using @{rednet.broadcast}.
|
rednet-using computer using [`rednet.broadcast`].
|
||||||
|
|
||||||
:::caution Network security
|
> [Network security][!WARNING]
|
||||||
|
>
|
||||||
While rednet provides a friendly way to send messages to specific computers, it
|
> While rednet provides a friendly way to send messages to specific computers, it
|
||||||
doesn't provide any guarantees about security. Other computers could be
|
> doesn't provide any guarantees about security. Other computers could be
|
||||||
listening in to your messages, or even pretending to send messages from other computers!
|
> listening in to your messages, or even pretending to send messages from other computers!
|
||||||
|
>
|
||||||
If you're playing on a multi-player server (or at least one where you don't
|
> If you're playing on a multi-player server (or at least one where you don't
|
||||||
trust other players), it's worth encrypting or signing your rednet messages.
|
> trust other players), it's worth encrypting or signing your rednet messages.
|
||||||
:::
|
|
||||||
|
|
||||||
## Protocols and hostnames
|
## Protocols and hostnames
|
||||||
Several rednet messages accept "protocol"s - simple string names describing what
|
Several rednet messages accept "protocol"s - simple string names describing what
|
||||||
a message is about. When sending messages using @{rednet.send} and
|
a message is about. When sending messages using [`rednet.send`] and
|
||||||
@{rednet.broadcast}, you can optionally specify a protocol for the message. This
|
[`rednet.broadcast`], you can optionally specify a protocol for the message. This
|
||||||
same protocol can then be given to @{rednet.receive}, to ignore all messages not
|
same protocol can then be given to [`rednet.receive`], to ignore all messages not
|
||||||
using this protocol.
|
using this protocol.
|
||||||
|
|
||||||
It's also possible to look-up computers based on protocols, providing a basic
|
It's also possible to look-up computers based on protocols, providing a basic
|
||||||
system for service discovery and [DNS]. A computer can advertise that it
|
system for service discovery and [DNS]. A computer can advertise that it
|
||||||
supports a particular protocol with @{rednet.host}, also providing a friendly
|
supports a particular protocol with [`rednet.host`], also providing a friendly
|
||||||
"hostname". Other computers may then find all computers which support this
|
"hostname". Other computers may then find all computers which support this
|
||||||
protocol using @{rednet.lookup}.
|
protocol using [`rednet.lookup`].
|
||||||
|
|
||||||
[DNS]: https://en.wikipedia.org/wiki/Domain_Name_System "Domain Name System"
|
[DNS]: https://en.wikipedia.org/wiki/Domain_Name_System "Domain Name System"
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ bare-bones but flexible interface.
|
|||||||
|
|
||||||
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
||||||
|
|
||||||
--- The channel used by the Rednet API to @{broadcast} messages.
|
--- The channel used by the Rednet API to [`broadcast`] messages.
|
||||||
CHANNEL_BROADCAST = 65535
|
CHANNEL_BROADCAST = 65535
|
||||||
|
|
||||||
--- The channel used by the Rednet API to repeat messages.
|
--- The channel used by the Rednet API to repeat messages.
|
||||||
@ -68,12 +67,12 @@ local function id_as_channel(id)
|
|||||||
return (id or os.getComputerID()) % MAX_ID_CHANNELS
|
return (id or os.getComputerID()) % MAX_ID_CHANNELS
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[- Opens a modem with the given @{peripheral} name, allowing it to send and
|
--[[- Opens a modem with the given [`peripheral`] name, allowing it to send and
|
||||||
receive messages over rednet.
|
receive messages over rednet.
|
||||||
|
|
||||||
This will open the modem on two channels: one which has the same
|
This will open the modem on two channels: one which has the same
|
||||||
@{os.getComputerID|ID} as the computer, and another on
|
[ID][`os.getComputerID`] as the computer, and another on
|
||||||
@{CHANNEL_BROADCAST|the broadcast channel}.
|
[the broadcast channel][`CHANNEL_BROADCAST`].
|
||||||
|
|
||||||
@tparam string modem The name of the modem to open.
|
@tparam string modem The name of the modem to open.
|
||||||
@throws If there is no such modem with the given name
|
@throws If there is no such modem with the given name
|
||||||
@ -83,7 +82,7 @@ rednet messages using it.
|
|||||||
rednet.open("back")
|
rednet.open("back")
|
||||||
|
|
||||||
@usage Open rednet on all attached modems. This abuses the "filter" argument to
|
@usage Open rednet on all attached modems. This abuses the "filter" argument to
|
||||||
@{peripheral.find}.
|
[`peripheral.find`].
|
||||||
|
|
||||||
peripheral.find("modem", rednet.open)
|
peripheral.find("modem", rednet.open)
|
||||||
@see rednet.close
|
@see rednet.close
|
||||||
@ -98,7 +97,7 @@ function open(modem)
|
|||||||
peripheral.call(modem, "open", CHANNEL_BROADCAST)
|
peripheral.call(modem, "open", CHANNEL_BROADCAST)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Close a modem with the given @{peripheral} name, meaning it can no longer
|
--- Close a modem with the given [`peripheral`] name, meaning it can no longer
|
||||||
-- send and receive rednet messages.
|
-- send and receive rednet messages.
|
||||||
--
|
--
|
||||||
-- @tparam[opt] string modem The side the modem exists on. If not given, all
|
-- @tparam[opt] string modem The side the modem exists on. If not given, all
|
||||||
@ -151,21 +150,21 @@ end
|
|||||||
|
|
||||||
--[[- Allows a computer or turtle with an attached modem to send a message
|
--[[- Allows a computer or turtle with an attached modem to send a message
|
||||||
intended for a sycomputer with a specific ID. At least one such modem must first
|
intended for a sycomputer with a specific ID. At least one such modem must first
|
||||||
be @{rednet.open|opened} before sending is possible.
|
be [opened][`rednet.open`] before sending is possible.
|
||||||
|
|
||||||
Assuming the target was in range and also had a correctly opened modem, the
|
Assuming the target was in range and also had a correctly opened modem, the
|
||||||
target computer may then use @{rednet.receive} to collect the message.
|
target computer may then use [`rednet.receive`] to collect the message.
|
||||||
|
|
||||||
@tparam number recipient The ID of the receiving computer.
|
@tparam number recipient The ID of the receiving computer.
|
||||||
@param message The message to send. Like with @{modem.transmit}, this can
|
@param message The message to send. Like with [`modem.transmit`], this can
|
||||||
contain any primitive type (numbers, booleans and strings) as well as
|
contain any primitive type (numbers, booleans and strings) as well as
|
||||||
tables. Other types (like functions), as well as metatables, will not be
|
tables. Other types (like functions), as well as metatables, will not be
|
||||||
transmitted.
|
transmitted.
|
||||||
@tparam[opt] string protocol The "protocol" to send this message under. When
|
@tparam[opt] string protocol The "protocol" to send this message under. When
|
||||||
using @{rednet.receive} one can filter to only receive messages sent under a
|
using [`rednet.receive`] one can filter to only receive messages sent under a
|
||||||
particular protocol.
|
particular protocol.
|
||||||
@treturn boolean If this message was successfully sent (i.e. if rednet is
|
@treturn boolean If this message was successfully sent (i.e. if rednet is
|
||||||
currently @{rednet.open|open}). Note, this does not guarantee the message was
|
currently [open][`rednet.open`]). Note, this does not guarantee the message was
|
||||||
actually _received_.
|
actually _received_.
|
||||||
@changed 1.6 Added protocol parameter.
|
@changed 1.6 Added protocol parameter.
|
||||||
@changed 1.82.0 Now returns whether the message was successfully sent.
|
@changed 1.82.0 Now returns whether the message was successfully sent.
|
||||||
@ -217,13 +216,13 @@ function send(recipient, message, protocol)
|
|||||||
return sent
|
return sent
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[- Broadcasts a string message over the predefined @{CHANNEL_BROADCAST}
|
--[[- Broadcasts a string message over the predefined [`CHANNEL_BROADCAST`]
|
||||||
channel. The message will be received by every device listening to rednet.
|
channel. The message will be received by every device listening to rednet.
|
||||||
|
|
||||||
@param message The message to send. This should not contain coroutines or
|
@param message The message to send. This should not contain coroutines or
|
||||||
functions, as they will be converted to @{nil}.
|
functions, as they will be converted to [`nil`].
|
||||||
@tparam[opt] string protocol The "protocol" to send this message under. When
|
@tparam[opt] string protocol The "protocol" to send this message under. When
|
||||||
using @{rednet.receive} one can filter to only receive messages sent under a
|
using [`rednet.receive`] one can filter to only receive messages sent under a
|
||||||
particular protocol.
|
particular protocol.
|
||||||
@see rednet.receive
|
@see rednet.receive
|
||||||
@changed 1.6 Added protocol parameter.
|
@changed 1.6 Added protocol parameter.
|
||||||
@ -311,7 +310,7 @@ function receive(protocol_filter, timeout)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[- Register the system as "hosting" the desired protocol under the specified
|
--[[- Register the system as "hosting" the desired protocol under the specified
|
||||||
name. If a rednet @{rednet.lookup|lookup} is performed for that protocol (and
|
name. If a rednet [lookup][`rednet.lookup`] is performed for that protocol (and
|
||||||
maybe name) on the same network, the registered system will automatically
|
maybe name) on the same network, the registered system will automatically
|
||||||
respond via a background process, hence providing the system performing the
|
respond via a background process, hence providing the system performing the
|
||||||
lookup with its ID number.
|
lookup with its ID number.
|
||||||
@ -343,8 +342,8 @@ function host(protocol, hostname)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stop @{rednet.host|hosting} a specific protocol, meaning it will no longer
|
--- Stop [hosting][`rednet.host`] a specific protocol, meaning it will no longer
|
||||||
-- respond to @{rednet.lookup} requests.
|
-- respond to [`rednet.lookup`] requests.
|
||||||
--
|
--
|
||||||
-- @tparam string protocol The protocol to unregister your self from.
|
-- @tparam string protocol The protocol to unregister your self from.
|
||||||
-- @since 1.6
|
-- @since 1.6
|
||||||
@ -353,7 +352,7 @@ function unhost(protocol)
|
|||||||
hostnames[protocol] = nil
|
hostnames[protocol] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[- Search the local rednet network for systems @{rednet.host|hosting} the
|
--[[- Search the local rednet network for systems [hosting][`rednet.host`] the
|
||||||
desired protocol and returns any computer IDs that respond as "registered"
|
desired protocol and returns any computer IDs that respond as "registered"
|
||||||
against it.
|
against it.
|
||||||
|
|
||||||
@ -365,7 +364,7 @@ match is found).
|
|||||||
|
|
||||||
@treturn[1] number... A list of computer IDs hosting the given protocol.
|
@treturn[1] number... A list of computer IDs hosting the given protocol.
|
||||||
@treturn[2] number|nil The computer ID with the provided hostname and protocol,
|
@treturn[2] number|nil The computer ID with the provided hostname and protocol,
|
||||||
or @{nil} if none exists.
|
or [`nil`] if none exists.
|
||||||
@since 1.6
|
@since 1.6
|
||||||
@usage Find all computers which are hosting the `"chat"` protocol.
|
@usage Find all computers which are hosting the `"chat"` protocol.
|
||||||
|
|
||||||
@ -450,7 +449,7 @@ end
|
|||||||
local started = false
|
local started = false
|
||||||
|
|
||||||
--- Listen for modem messages and converts them into rednet messages, which may
|
--- Listen for modem messages and converts them into rednet messages, which may
|
||||||
-- then be @{receive|received}.
|
-- then be [received][`receive`].
|
||||||
--
|
--
|
||||||
-- This is automatically started in the background on computer startup, and
|
-- This is automatically started in the background on computer startup, and
|
||||||
-- should not be called manually.
|
-- should not be called manually.
|
||||||
|
@ -2,13 +2,31 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--- Read and write configuration options for CraftOS and your programs.
|
--[[- Read and write configuration options for CraftOS and your programs.
|
||||||
--
|
|
||||||
-- By default, the settings API will load its configuration from the
|
When a computer starts, it reads the current value of settings from the
|
||||||
-- `/.settings` file. One can then use @{settings.save} to update the file.
|
`/.settings` file. These values then may be [read][`settings.get`] or
|
||||||
--
|
[modified][`settings.set`].
|
||||||
-- @module settings
|
|
||||||
-- @since 1.78
|
> [!WARNING]
|
||||||
|
> Calling [`settings.set`] does _not_ update the settings file by default. You
|
||||||
|
> _must_ call [`settings.save`] to persist values.
|
||||||
|
|
||||||
|
@module settings
|
||||||
|
@since 1.78
|
||||||
|
@usage Define an basic setting `123` and read its value.
|
||||||
|
|
||||||
|
settings.define("my.setting", {
|
||||||
|
description = "An example setting",
|
||||||
|
default = 123,
|
||||||
|
type = number,
|
||||||
|
})
|
||||||
|
print("my.setting = " .. settings.get("my.setting")) -- 123
|
||||||
|
|
||||||
|
You can then use the `set` program to change its value (e.g. `set my.setting 456`),
|
||||||
|
and then re-run the `example` program to check it has changed.
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
local expect = dofile("rom/modules/main/cc/expect.lua")
|
local expect = dofile("rom/modules/main/cc/expect.lua")
|
||||||
local type, expect, field = type, expect.expect, expect.field
|
local type, expect, field = type, expect.expect, expect.field
|
||||||
@ -40,9 +58,9 @@ for _, v in ipairs(valid_types) do valid_types[v] = true end
|
|||||||
-- Options for this setting. This table accepts the following fields:
|
-- Options for this setting. This table accepts the following fields:
|
||||||
--
|
--
|
||||||
-- - `description`: A description which may be printed when running the `set` program.
|
-- - `description`: A description which may be printed when running the `set` program.
|
||||||
-- - `default`: A default value, which is returned by @{settings.get} if the
|
-- - `default`: A default value, which is returned by [`settings.get`] if the
|
||||||
-- setting has not been changed.
|
-- setting has not been changed.
|
||||||
-- - `type`: Require values to be of this type. @{set|Setting} the value to another type
|
-- - `type`: Require values to be of this type. [Setting][`set`] the value to another type
|
||||||
-- will error.
|
-- will error.
|
||||||
-- @since 1.87.0
|
-- @since 1.87.0
|
||||||
function define(name, options)
|
function define(name, options)
|
||||||
@ -66,9 +84,9 @@ function define(name, options)
|
|||||||
details[name] = options
|
details[name] = options
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove a @{define|definition} of a setting.
|
--- Remove a [definition][`define`] of a setting.
|
||||||
--
|
--
|
||||||
-- If a setting has been changed, this does not remove its value. Use @{settings.unset}
|
-- If a setting has been changed, this does not remove its value. Use [`settings.unset`]
|
||||||
-- for that.
|
-- for that.
|
||||||
--
|
--
|
||||||
-- @tparam string name The name of this option
|
-- @tparam string name The name of this option
|
||||||
@ -92,13 +110,18 @@ local function set_value(name, new)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the value of a setting.
|
--[[- Set the value of a setting.
|
||||||
--
|
|
||||||
-- @tparam string name The name of the setting to set
|
> [!WARNING]
|
||||||
-- @param value The setting's value. This cannot be `nil`, and must be
|
> Calling [`settings.set`] does _not_ update the settings file by default. You
|
||||||
-- serialisable by @{textutils.serialize}.
|
> _must_ call [`settings.save`] to persist values.
|
||||||
-- @throws If this value cannot be serialised
|
|
||||||
-- @see settings.unset
|
@tparam string name The name of the setting to set
|
||||||
|
@param value The setting's value. This cannot be `nil`, and must be
|
||||||
|
serialisable by [`textutils.serialize`].
|
||||||
|
@throws If this value cannot be serialised
|
||||||
|
@see settings.unset
|
||||||
|
]]
|
||||||
function set(name, value)
|
function set(name, value)
|
||||||
expect(1, name, "string")
|
expect(1, name, "string")
|
||||||
expect(2, value, "number", "string", "boolean", "table")
|
expect(2, value, "number", "string", "boolean", "table")
|
||||||
@ -134,7 +157,7 @@ end
|
|||||||
--
|
--
|
||||||
-- @tparam string name The name of the setting to get.
|
-- @tparam string name The name of the setting to get.
|
||||||
-- @treturn { description? = string, default? = any, type? = string, value? = any }
|
-- @treturn { description? = string, default? = any, type? = string, value? = any }
|
||||||
-- Information about this setting. This includes all information from @{settings.define},
|
-- Information about this setting. This includes all information from [`settings.define`],
|
||||||
-- as well as this setting's value.
|
-- as well as this setting's value.
|
||||||
-- @since 1.87.0
|
-- @since 1.87.0
|
||||||
function getDetails(name)
|
function getDetails(name)
|
||||||
@ -148,8 +171,8 @@ end
|
|||||||
|
|
||||||
--- Remove the value of a setting, setting it to the default.
|
--- Remove the value of a setting, setting it to the default.
|
||||||
--
|
--
|
||||||
-- @{settings.get} will return the default value until the setting's value is
|
-- [`settings.get`] will return the default value until the setting's value is
|
||||||
-- @{settings.set|set}, or the computer is rebooted.
|
-- [set][`settings.set`], or the computer is rebooted.
|
||||||
--
|
--
|
||||||
-- @tparam string name The name of the setting to unset.
|
-- @tparam string name The name of the setting to unset.
|
||||||
-- @see settings.set
|
-- @see settings.set
|
||||||
@ -159,7 +182,7 @@ function unset(name)
|
|||||||
set_value(name, nil)
|
set_value(name, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Resets the value of all settings. Equivalent to calling @{settings.unset}
|
--- Resets the value of all settings. Equivalent to calling [`settings.unset`]
|
||||||
--- on every setting.
|
--- on every setting.
|
||||||
--
|
--
|
||||||
-- @see settings.unset
|
-- @see settings.unset
|
||||||
|
@ -17,9 +17,9 @@ end
|
|||||||
|
|
||||||
local term = _ENV
|
local term = _ENV
|
||||||
|
|
||||||
--- Redirects terminal output to a monitor, a @{window}, or any other custom
|
--- Redirects terminal output to a monitor, a [`window`], or any other custom
|
||||||
-- terminal object. Once the redirect is performed, any calls to a "term"
|
-- terminal object. Once the redirect is performed, any calls to a "term"
|
||||||
-- function - or to a function that makes use of a term function, as @{print} -
|
-- function - or to a function that makes use of a term function, as [`print`] -
|
||||||
-- will instead operate with the new terminal object.
|
-- will instead operate with the new terminal object.
|
||||||
--
|
--
|
||||||
-- A "terminal object" is simply a table that contains functions with the same
|
-- A "terminal object" is simply a table that contains functions with the same
|
||||||
@ -29,9 +29,9 @@ local term = _ENV
|
|||||||
-- The redirect can be undone by pointing back to the previous terminal object
|
-- The redirect can be undone by pointing back to the previous terminal object
|
||||||
-- (which this function returns whenever you switch).
|
-- (which this function returns whenever you switch).
|
||||||
--
|
--
|
||||||
-- @tparam Redirect target The terminal redirect the @{term} API will draw to.
|
-- @tparam Redirect target The terminal redirect the [`term`] API will draw to.
|
||||||
-- @treturn Redirect The previous redirect object, as returned by
|
-- @treturn Redirect The previous redirect object, as returned by
|
||||||
-- @{term.current}.
|
-- [`term.current`].
|
||||||
-- @since 1.31
|
-- @since 1.31
|
||||||
-- @usage
|
-- @usage
|
||||||
-- Redirect to a monitor on the right of the computer.
|
-- Redirect to a monitor on the right of the computer.
|
||||||
@ -60,7 +60,7 @@ end
|
|||||||
-- @treturn Redirect The current terminal redirect
|
-- @treturn Redirect The current terminal redirect
|
||||||
-- @since 1.6
|
-- @since 1.6
|
||||||
-- @usage
|
-- @usage
|
||||||
-- Create a new @{window} which draws to the current redirect target.
|
-- Create a new [`window`] which draws to the current redirect target.
|
||||||
--
|
--
|
||||||
-- window.create(term.current(), 1, 1, 10, 10)
|
-- window.create(term.current(), 1, 1, 10, 10)
|
||||||
term.current = function()
|
term.current = function()
|
||||||
@ -70,7 +70,7 @@ end
|
|||||||
--- Get the native terminal object of the current computer.
|
--- Get the native terminal object of the current computer.
|
||||||
--
|
--
|
||||||
-- It is recommended you do not use this function unless you absolutely have
|
-- It is recommended you do not use this function unless you absolutely have
|
||||||
-- to. In a multitasked environment, @{term.native} will _not_ be the current
|
-- to. In a multitasked environment, [`term.native`] will _not_ be the current
|
||||||
-- terminal object, and so drawing may interfere with other programs.
|
-- terminal object, and so drawing may interfere with other programs.
|
||||||
--
|
--
|
||||||
-- @treturn Redirect The native terminal redirect.
|
-- @treturn Redirect The native terminal redirect.
|
||||||
|
@ -14,7 +14,7 @@ local wrap = dofile("rom/modules/main/cc/strings.lua").wrap
|
|||||||
--- Slowly writes string text at current cursor position,
|
--- Slowly writes string text at current cursor position,
|
||||||
-- character-by-character.
|
-- character-by-character.
|
||||||
--
|
--
|
||||||
-- Like @{_G.write}, this does not insert a newline at the end.
|
-- Like [`_G.write`], this does not insert a newline at the end.
|
||||||
--
|
--
|
||||||
-- @tparam string text The the text to write to the screen
|
-- @tparam string text The the text to write to the screen
|
||||||
-- @tparam[opt] number rate The number of characters to write each second,
|
-- @tparam[opt] number rate The number of characters to write each second,
|
||||||
@ -42,7 +42,7 @@ end
|
|||||||
--- Slowly prints string text at current cursor position,
|
--- Slowly prints string text at current cursor position,
|
||||||
-- character-by-character.
|
-- character-by-character.
|
||||||
--
|
--
|
||||||
-- Like @{print}, this inserts a newline after printing.
|
-- Like [`print`], this inserts a newline after printing.
|
||||||
--
|
--
|
||||||
-- @tparam string sText The the text to write to the screen
|
-- @tparam string sText The the text to write to the screen
|
||||||
-- @tparam[opt] number nRate The number of characters to write each second,
|
-- @tparam[opt] number nRate The number of characters to write each second,
|
||||||
@ -56,7 +56,7 @@ end
|
|||||||
|
|
||||||
--- Takes input time and formats it in a more readable format such as `6:30 PM`.
|
--- Takes input time and formats it in a more readable format such as `6:30 PM`.
|
||||||
--
|
--
|
||||||
-- @tparam number nTime The time to format, as provided by @{os.time}.
|
-- @tparam number nTime The time to format, as provided by [`os.time`].
|
||||||
-- @tparam[opt] boolean bTwentyFourHour Whether to format this as a 24-hour
|
-- @tparam[opt] boolean bTwentyFourHour Whether to format this as a 24-hour
|
||||||
-- clock (`18:30`) rather than a 12-hour one (`6:30 AM`)
|
-- clock (`18:30`) rather than a 12-hour one (`6:30 AM`)
|
||||||
-- @treturn string The formatted time
|
-- @treturn string The formatted time
|
||||||
@ -114,7 +114,7 @@ end
|
|||||||
--[[- Prints a given string to the display.
|
--[[- Prints a given string to the display.
|
||||||
|
|
||||||
If the action can be completed without scrolling, it acts much the same as
|
If the action can be completed without scrolling, it acts much the same as
|
||||||
@{print}; otherwise, it will throw up a "Press any key to continue" prompt at
|
[`print`]; otherwise, it will throw up a "Press any key to continue" prompt at
|
||||||
the bottom of the display. Each press will cause it to scroll down and write a
|
the bottom of the display. Each press will cause it to scroll down and write a
|
||||||
single line more before prompting again, if need be.
|
single line more before prompting again, if need be.
|
||||||
|
|
||||||
@ -253,7 +253,7 @@ end
|
|||||||
--[[- Prints tables in a structured form, stopping and prompting for input should
|
--[[- Prints tables in a structured form, stopping and prompting for input should
|
||||||
the result not fit on the terminal.
|
the result not fit on the terminal.
|
||||||
|
|
||||||
This functions identically to @{textutils.tabulate}, but will prompt for user
|
This functions identically to [`textutils.tabulate`], but will prompt for user
|
||||||
input should the whole output not fit on the display.
|
input should the whole output not fit on the display.
|
||||||
|
|
||||||
@tparam {string...}|number ... The rows and text colors to display.
|
@tparam {string...}|number ... The rows and text colors to display.
|
||||||
@ -424,12 +424,31 @@ do
|
|||||||
if map[c] == nil then map[c] = hexify(c) end
|
if map[c] == nil then map[c] = hexify(c) end
|
||||||
end
|
end
|
||||||
|
|
||||||
serializeJSONString = function(s)
|
serializeJSONString = function(s, options)
|
||||||
|
if options and options.unicode_strings and s:find("[\x80-\xff]") then
|
||||||
|
local retval = '"'
|
||||||
|
for _, code in utf8.codes(s) do
|
||||||
|
if code > 0xFFFF then
|
||||||
|
-- Encode the codepoint as a UTF-16 surrogate pair
|
||||||
|
code = code - 0x10000
|
||||||
|
local high, low = bit32.extract(code, 10, 10) + 0xD800, bit32.extract(code, 0, 10) + 0xDC00
|
||||||
|
retval = retval .. ("\\u%04X\\u%04X"):format(high, low)
|
||||||
|
elseif code <= 0x5C and map[string.char(code)] then -- 0x5C = `\`, don't run `string.char` if we don't need to
|
||||||
|
retval = retval .. map[string.char(code)]
|
||||||
|
elseif code < 0x20 or code >= 0x7F then
|
||||||
|
retval = retval .. ("\\u%04X"):format(code)
|
||||||
|
else
|
||||||
|
retval = retval .. string.char(code)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return retval .. '"'
|
||||||
|
else
|
||||||
return ('"%s"'):format(s:gsub("[\0-\x1f\"\\]", map):gsub("[\x7f-\xff]", hexify))
|
return ('"%s"'):format(s:gsub("[\0-\x1f\"\\]", map):gsub("[\x7f-\xff]", hexify))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function serializeJSONImpl(t, tTracking, bNBTStyle)
|
local function serializeJSONImpl(t, tTracking, options)
|
||||||
local sType = type(t)
|
local sType = type(t)
|
||||||
if t == empty_json_array then return "[]"
|
if t == empty_json_array then return "[]"
|
||||||
elseif t == json_null then return "null"
|
elseif t == json_null then return "null"
|
||||||
@ -450,13 +469,14 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle)
|
|||||||
local nObjectSize = 0
|
local nObjectSize = 0
|
||||||
local nArraySize = 0
|
local nArraySize = 0
|
||||||
local largestArrayIndex = 0
|
local largestArrayIndex = 0
|
||||||
|
local bNBTStyle = options and options.nbt_style
|
||||||
for k, v in pairs(t) do
|
for k, v in pairs(t) do
|
||||||
if type(k) == "string" then
|
if type(k) == "string" then
|
||||||
local sEntry
|
local sEntry
|
||||||
if bNBTStyle then
|
if bNBTStyle then
|
||||||
sEntry = tostring(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle)
|
sEntry = tostring(k) .. ":" .. serializeJSONImpl(v, tTracking, options)
|
||||||
else
|
else
|
||||||
sEntry = serializeJSONString(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle)
|
sEntry = serializeJSONString(k, options) .. ":" .. serializeJSONImpl(v, tTracking, options)
|
||||||
end
|
end
|
||||||
if nObjectSize == 0 then
|
if nObjectSize == 0 then
|
||||||
sObjectResult = sObjectResult .. sEntry
|
sObjectResult = sObjectResult .. sEntry
|
||||||
@ -473,7 +493,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle)
|
|||||||
if t[k] == nil then --if the array is nil at index k the value is "null" as to keep the unused indexes in between used ones.
|
if t[k] == nil then --if the array is nil at index k the value is "null" as to keep the unused indexes in between used ones.
|
||||||
sEntry = "null"
|
sEntry = "null"
|
||||||
else -- if the array index does not point to a nil we serialise it's content.
|
else -- if the array index does not point to a nil we serialise it's content.
|
||||||
sEntry = serializeJSONImpl(t[k], tTracking, bNBTStyle)
|
sEntry = serializeJSONImpl(t[k], tTracking, options)
|
||||||
end
|
end
|
||||||
if nArraySize == 0 then
|
if nArraySize == 0 then
|
||||||
sArrayResult = sArrayResult .. sEntry
|
sArrayResult = sArrayResult .. sEntry
|
||||||
@ -492,7 +512,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle)
|
|||||||
end
|
end
|
||||||
|
|
||||||
elseif sType == "string" then
|
elseif sType == "string" then
|
||||||
return serializeJSONString(t)
|
return serializeJSONString(t, options)
|
||||||
|
|
||||||
elseif sType == "number" or sType == "boolean" then
|
elseif sType == "number" or sType == "boolean" then
|
||||||
return tostring(t)
|
return tostring(t)
|
||||||
@ -682,13 +702,13 @@ do
|
|||||||
|
|
||||||
--[[- Converts a serialised JSON string back into a reassembled Lua object.
|
--[[- Converts a serialised JSON string back into a reassembled Lua object.
|
||||||
|
|
||||||
This may be used with @{textutils.serializeJSON}, or when communicating
|
This may be used with [`textutils.serializeJSON`], or when communicating
|
||||||
with command blocks or web APIs.
|
with command blocks or web APIs.
|
||||||
|
|
||||||
If a `null` value is encountered, it is converted into `nil`. It can be converted
|
If a `null` value is encountered, it is converted into `nil`. It can be converted
|
||||||
into @{textutils.json_null} with the `parse_null` option.
|
into [`textutils.json_null`] with the `parse_null` option.
|
||||||
|
|
||||||
If an empty array is encountered, it is converted into @{textutils.empty_json_array}.
|
If an empty array is encountered, it is converted into [`textutils.empty_json_array`].
|
||||||
It can be converted into a new empty table with the `parse_empty_array` option.
|
It can be converted into a new empty table with the `parse_empty_array` option.
|
||||||
|
|
||||||
@tparam string s The serialised string to deserialise.
|
@tparam string s The serialised string to deserialise.
|
||||||
@ -697,12 +717,12 @@ do
|
|||||||
|
|
||||||
- `nbt_style`: When true, this will accept [stringified NBT][nbt] strings,
|
- `nbt_style`: When true, this will accept [stringified NBT][nbt] strings,
|
||||||
as produced by many commands.
|
as produced by many commands.
|
||||||
- `parse_null`: When true, `null` will be parsed as @{json_null}, rather than
|
- `parse_null`: When true, `null` will be parsed as [`json_null`], rather than
|
||||||
`nil`.
|
`nil`.
|
||||||
- `parse_empty_array`: When false, empty arrays will be parsed as a new table.
|
- `parse_empty_array`: When false, empty arrays will be parsed as a new table.
|
||||||
By default (or when this value is true), they are parsed as @{empty_json_array}.
|
By default (or when this value is true), they are parsed as [`empty_json_array`].
|
||||||
|
|
||||||
[nbt]: https://minecraft.gamepedia.com/NBT_format
|
[nbt]: https://minecraft.wiki/w/NBT_format
|
||||||
@return[1] The deserialised object
|
@return[1] The deserialised object
|
||||||
@treturn[2] nil If the object could not be deserialised.
|
@treturn[2] nil If the object could not be deserialised.
|
||||||
@treturn string A message describing why the JSON string is invalid.
|
@treturn string A message describing why the JSON string is invalid.
|
||||||
@ -714,7 +734,7 @@ do
|
|||||||
|
|
||||||
textutils.unserialiseJSON('{"name": "Steve", "age": null}')
|
textutils.unserialiseJSON('{"name": "Steve", "age": null}')
|
||||||
|
|
||||||
@usage Unserialise a basic JSON object, returning null values as @{json_null}.
|
@usage Unserialise a basic JSON object, returning null values as [`json_null`].
|
||||||
|
|
||||||
textutils.unserialiseJSON('{"name": "Steve", "age": null}', { parse_null = true })
|
textutils.unserialiseJSON('{"name": "Steve", "age": null}', { parse_null = true })
|
||||||
]]
|
]]
|
||||||
@ -793,7 +813,7 @@ serialise = serialize -- GB version
|
|||||||
|
|
||||||
--- Converts a serialised string back into a reassembled Lua object.
|
--- Converts a serialised string back into a reassembled Lua object.
|
||||||
--
|
--
|
||||||
-- This is mainly used together with @{textutils.serialise}.
|
-- This is mainly used together with [`textutils.serialise`].
|
||||||
--
|
--
|
||||||
-- @tparam string s The serialised string to deserialise.
|
-- @tparam string s The serialised string to deserialise.
|
||||||
-- @return[1] The deserialised object
|
-- @return[1] The deserialised object
|
||||||
@ -813,32 +833,57 @@ end
|
|||||||
|
|
||||||
unserialise = unserialize -- GB version
|
unserialise = unserialize -- GB version
|
||||||
|
|
||||||
--- Returns a JSON representation of the given data.
|
--[[- Returns a JSON representation of the given data.
|
||||||
--
|
|
||||||
-- This function attempts to guess whether a table is a JSON array or
|
This function attempts to guess whether a table is a JSON array or
|
||||||
-- object. However, empty tables are assumed to be empty objects - use
|
object. However, empty tables are assumed to be empty objects - use
|
||||||
-- @{textutils.empty_json_array} to mark an empty array.
|
[`textutils.empty_json_array`] to mark an empty array.
|
||||||
--
|
|
||||||
-- This is largely intended for interacting with various functions from the
|
This is largely intended for interacting with various functions from the
|
||||||
-- @{commands} API, though may also be used in making @{http} requests.
|
[`commands`] API, though may also be used in making [`http`] requests.
|
||||||
--
|
|
||||||
-- @param t The value to serialise. Like @{textutils.serialise}, this should not
|
@param[1] t The value to serialise. Like [`textutils.serialise`], this should not
|
||||||
-- contain recursive tables or functions.
|
contain recursive tables or functions.
|
||||||
-- @tparam[opt] boolean bNBTStyle Whether to produce NBT-style JSON (non-quoted keys)
|
@tparam[1,opt] { nbt_style? = boolean, unicode_strings? = boolean } options Options for serialisation.
|
||||||
-- instead of standard JSON.
|
- `nbt_style`: Whether to produce NBT-style JSON (non-quoted keys) instead of standard JSON.
|
||||||
-- @treturn string The JSON representation of the input.
|
- `unicode_strings`: Whether to treat strings as containing UTF-8 characters instead of
|
||||||
-- @throws If the object contains a value which cannot be
|
using the default 8-bit character set.
|
||||||
-- serialised. This includes functions and tables which appear multiple
|
|
||||||
-- times.
|
@param[2] t The value to serialise. Like [`textutils.serialise`], this should not
|
||||||
-- @usage textutils.serialiseJSON({ values = { 1, "2", true } })
|
contain recursive tables or functions.
|
||||||
-- @since 1.7
|
@tparam[2] boolean bNBTStyle Whether to produce NBT-style JSON (non-quoted keys)
|
||||||
-- @see textutils.json_null Use to serialise a JSON `null` value.
|
instead of standard JSON.
|
||||||
-- @see textutils.empty_json_array Use to serialise a JSON empty array.
|
|
||||||
function serializeJSON(t, bNBTStyle)
|
@treturn string The JSON representation of the input.
|
||||||
|
@throws If the object contains a value which cannot be serialised. This includes
|
||||||
|
functions and tables which appear multiple times.
|
||||||
|
|
||||||
|
@usage Serialise a simple object
|
||||||
|
|
||||||
|
textutils.serialiseJSON({ values = { 1, "2", true } })
|
||||||
|
|
||||||
|
@usage Serialise an object to a NBT-style string
|
||||||
|
|
||||||
|
textutils.serialiseJSON({ values = { 1, "2", true } }, { nbt_style = true })
|
||||||
|
|
||||||
|
@since 1.7
|
||||||
|
@changed 1.106.0 Added `options` overload and `unicode_strings` option.
|
||||||
|
|
||||||
|
@see textutils.json_null Use to serialise a JSON `null` value.
|
||||||
|
@see textutils.empty_json_array Use to serialise a JSON empty array.
|
||||||
|
]]
|
||||||
|
function serializeJSON(t, options)
|
||||||
expect(1, t, "table", "string", "number", "boolean")
|
expect(1, t, "table", "string", "number", "boolean")
|
||||||
expect(2, bNBTStyle, "boolean", "nil")
|
expect(2, options, "table", "boolean", "nil")
|
||||||
|
if type(options) == "boolean" then
|
||||||
|
options = { nbt_style = options }
|
||||||
|
elseif type(options) == "table" then
|
||||||
|
field(options, "nbt_style", "boolean", "nil")
|
||||||
|
field(options, "unicode_strings", "boolean", "nil")
|
||||||
|
end
|
||||||
|
|
||||||
local tTracking = {}
|
local tTracking = {}
|
||||||
return serializeJSONImpl(t, tTracking, bNBTStyle or false)
|
return serializeJSONImpl(t, tTracking, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
serialiseJSON = serializeJSON -- GB version
|
serialiseJSON = serializeJSON -- GB version
|
||||||
@ -884,7 +929,7 @@ local tEmpty = {}
|
|||||||
-- variable name or table index.
|
-- variable name or table index.
|
||||||
--
|
--
|
||||||
-- @tparam[opt] table tSearchTable The table to find variables in, defaulting to
|
-- @tparam[opt] table tSearchTable The table to find variables in, defaulting to
|
||||||
-- the global environment (@{_G}). The function also searches the "parent"
|
-- the global environment ([`_G`]). The function also searches the "parent"
|
||||||
-- environment via the `__index` metatable field.
|
-- environment via the `__index` metatable field.
|
||||||
--
|
--
|
||||||
-- @treturn { string... } The (possibly empty) list of completions.
|
-- @treturn { string... } The (possibly empty) list of completions.
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
--- A basic 3D vector type and some common vector operations. This may be useful
|
--- A basic 3D vector type and some common vector operations. This may be useful
|
||||||
-- when working with coordinates in Minecraft's world (such as those from the
|
-- when working with coordinates in Minecraft's world (such as those from the
|
||||||
-- @{gps} API).
|
-- [`gps`] API).
|
||||||
--
|
--
|
||||||
-- An introduction to vectors can be found on [Wikipedia][wiki].
|
-- An introduction to vectors can be found on [Wikipedia][wiki].
|
||||||
--
|
--
|
||||||
@ -180,7 +180,7 @@ local vmetatable = {
|
|||||||
__eq = vector.equals,
|
__eq = vector.equals,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Construct a new @{Vector} with the given coordinates.
|
--- Construct a new [`Vector`] with the given coordinates.
|
||||||
--
|
--
|
||||||
-- @tparam number x The X coordinate or direction of the vector.
|
-- @tparam number x The X coordinate or direction of the vector.
|
||||||
-- @tparam number y The Y coordinate or direction of the vector.
|
-- @tparam number y The Y coordinate or direction of the vector.
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--[[- A @{term.Redirect|terminal redirect} occupying a smaller area of an
|
--[[- A [terminal redirect][`term.Redirect`] occupying a smaller area of an
|
||||||
existing terminal. This allows for easy definition of spaces within the display
|
existing terminal. This allows for easy definition of spaces within the display
|
||||||
that can be written/drawn to, then later redrawn/repositioned/etc as need
|
that can be written/drawn to, then later redrawn/repositioned/etc as need
|
||||||
be. The API itself contains only one function, @{window.create}, which returns
|
be. The API itself contains only one function, [`window.create`], which returns
|
||||||
the windows themselves.
|
the windows themselves.
|
||||||
|
|
||||||
Windows are considered terminal objects - as such, they have access to nearly
|
Windows are considered terminal objects - as such, they have access to nearly
|
||||||
@ -60,11 +60,11 @@ local string_sub = string.sub
|
|||||||
|
|
||||||
--[[- Returns a terminal object that is a space within the specified parent
|
--[[- Returns a terminal object that is a space within the specified parent
|
||||||
terminal object. This can then be used (or even redirected to) in the same
|
terminal object. This can then be used (or even redirected to) in the same
|
||||||
manner as eg a wrapped monitor. Refer to @{term|the term API} for a list of
|
manner as eg a wrapped monitor. Refer to [the term API][`term`] for a list of
|
||||||
functions available to it.
|
functions available to it.
|
||||||
|
|
||||||
@{term} itself may not be passed as the parent, though @{term.native} is
|
[`term`] itself may not be passed as the parent, though [`term.native`] is
|
||||||
acceptable. Generally, @{term.current} or a wrapped monitor will be most
|
acceptable. Generally, [`term.current`] or a wrapped monitor will be most
|
||||||
suitable, though windows may even have other windows assigned as their
|
suitable, though windows may even have other windows assigned as their
|
||||||
parents.
|
parents.
|
||||||
|
|
||||||
@ -131,11 +131,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
local sEmptyTextColor = tEmptyColorLines[nTextColor]
|
local sEmptyTextColor = tEmptyColorLines[nTextColor]
|
||||||
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
|
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
|
||||||
for y = 1, nHeight do
|
for y = 1, nHeight do
|
||||||
tLines[y] = {
|
tLines[y] = { sEmptyText, sEmptyTextColor, sEmptyBackgroundColor }
|
||||||
text = sEmptyText,
|
|
||||||
textColor = sEmptyTextColor,
|
|
||||||
backgroundColor = sEmptyBackgroundColor,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 0, 15 do
|
for i = 0, 15 do
|
||||||
@ -165,7 +161,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
local function redrawLine(n)
|
local function redrawLine(n)
|
||||||
local tLine = tLines[n]
|
local tLine = tLines[n]
|
||||||
parent.setCursorPos(nX, nY + n - 1)
|
parent.setCursorPos(nX, nY + n - 1)
|
||||||
parent.blit(tLine.text, tLine.textColor, tLine.backgroundColor)
|
parent.blit(tLine[1], tLine[2], tLine[3])
|
||||||
end
|
end
|
||||||
|
|
||||||
local function redraw()
|
local function redraw()
|
||||||
@ -188,9 +184,9 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
-- Modify line
|
-- Modify line
|
||||||
local tLine = tLines[nCursorY]
|
local tLine = tLines[nCursorY]
|
||||||
if nStart == 1 and nEnd == nWidth then
|
if nStart == 1 and nEnd == nWidth then
|
||||||
tLine.text = sText
|
tLine[1] = sText
|
||||||
tLine.textColor = sTextColor
|
tLine[2] = sTextColor
|
||||||
tLine.backgroundColor = sBackgroundColor
|
tLine[3] = sBackgroundColor
|
||||||
else
|
else
|
||||||
local sClippedText, sClippedTextColor, sClippedBackgroundColor
|
local sClippedText, sClippedTextColor, sClippedBackgroundColor
|
||||||
if nStart < 1 then
|
if nStart < 1 then
|
||||||
@ -210,9 +206,9 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
sClippedBackgroundColor = sBackgroundColor
|
sClippedBackgroundColor = sBackgroundColor
|
||||||
end
|
end
|
||||||
|
|
||||||
local sOldText = tLine.text
|
local sOldText = tLine[1]
|
||||||
local sOldTextColor = tLine.textColor
|
local sOldTextColor = tLine[2]
|
||||||
local sOldBackgroundColor = tLine.backgroundColor
|
local sOldBackgroundColor = tLine[3]
|
||||||
local sNewText, sNewTextColor, sNewBackgroundColor
|
local sNewText, sNewTextColor, sNewBackgroundColor
|
||||||
if nStart > 1 then
|
if nStart > 1 then
|
||||||
local nOldEnd = nStart - 1
|
local nOldEnd = nStart - 1
|
||||||
@ -231,9 +227,9 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
sNewBackgroundColor = sNewBackgroundColor .. string_sub(sOldBackgroundColor, nOldStart, nWidth)
|
sNewBackgroundColor = sNewBackgroundColor .. string_sub(sOldBackgroundColor, nOldStart, nWidth)
|
||||||
end
|
end
|
||||||
|
|
||||||
tLine.text = sNewText
|
tLine[1] = sNewText
|
||||||
tLine.textColor = sNewTextColor
|
tLine[2] = sNewTextColor
|
||||||
tLine.backgroundColor = sNewBackgroundColor
|
tLine[3] = sNewBackgroundColor
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Redraw line
|
-- Redraw line
|
||||||
@ -251,7 +247,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- The window object. Refer to the @{window|module's documentation} for
|
--- The window object. Refer to the [module's documentation][`window`] for
|
||||||
-- a full description.
|
-- a full description.
|
||||||
--
|
--
|
||||||
-- @type Window
|
-- @type Window
|
||||||
@ -280,11 +276,10 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
local sEmptyTextColor = tEmptyColorLines[nTextColor]
|
local sEmptyTextColor = tEmptyColorLines[nTextColor]
|
||||||
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
|
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
|
||||||
for y = 1, nHeight do
|
for y = 1, nHeight do
|
||||||
tLines[y] = {
|
local line = tLines[y]
|
||||||
text = sEmptyText,
|
line[1] = sEmptyText
|
||||||
textColor = sEmptyTextColor,
|
line[2] = sEmptyTextColor
|
||||||
backgroundColor = sEmptyBackgroundColor,
|
line[3] = sEmptyBackgroundColor
|
||||||
}
|
|
||||||
end
|
end
|
||||||
if bVisible then
|
if bVisible then
|
||||||
redraw()
|
redraw()
|
||||||
@ -295,14 +290,10 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
|
|
||||||
function window.clearLine()
|
function window.clearLine()
|
||||||
if nCursorY >= 1 and nCursorY <= nHeight then
|
if nCursorY >= 1 and nCursorY <= nHeight then
|
||||||
local sEmptyText = sEmptySpaceLine
|
local line = tLines[nCursorY]
|
||||||
local sEmptyTextColor = tEmptyColorLines[nTextColor]
|
line[1] = sEmptySpaceLine
|
||||||
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
|
line[2] = tEmptyColorLines[nTextColor]
|
||||||
tLines[nCursorY] = {
|
line[3] = tEmptyColorLines[nBackgroundColor]
|
||||||
text = sEmptyText,
|
|
||||||
textColor = sEmptyTextColor,
|
|
||||||
backgroundColor = sEmptyBackgroundColor,
|
|
||||||
}
|
|
||||||
if bVisible then
|
if bVisible then
|
||||||
redrawLine(nCursorY)
|
redrawLine(nCursorY)
|
||||||
updateCursorColor()
|
updateCursorColor()
|
||||||
@ -431,11 +422,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
if y >= 1 and y <= nHeight then
|
if y >= 1 and y <= nHeight then
|
||||||
tNewLines[newY] = tLines[y]
|
tNewLines[newY] = tLines[y]
|
||||||
else
|
else
|
||||||
tNewLines[newY] = {
|
tNewLines[newY] = { sEmptyText, sEmptyTextColor, sEmptyBackgroundColor }
|
||||||
text = sEmptyText,
|
|
||||||
textColor = sEmptyTextColor,
|
|
||||||
backgroundColor = sEmptyBackgroundColor,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
tLines = tNewLines
|
tLines = tNewLines
|
||||||
@ -467,8 +454,8 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
--
|
--
|
||||||
-- @tparam number y The y position of the line to get.
|
-- @tparam number y The y position of the line to get.
|
||||||
-- @treturn string The textual content of this line.
|
-- @treturn string The textual content of this line.
|
||||||
-- @treturn string The text colours of this line, suitable for use with @{term.blit}.
|
-- @treturn string The text colours of this line, suitable for use with [`term.blit`].
|
||||||
-- @treturn string The background colours of this line, suitable for use with @{term.blit}.
|
-- @treturn string The background colours of this line, suitable for use with [`term.blit`].
|
||||||
-- @throws If `y` is not between 1 and this window's height.
|
-- @throws If `y` is not between 1 and this window's height.
|
||||||
-- @since 1.84.0
|
-- @since 1.84.0
|
||||||
function window.getLine(y)
|
function window.getLine(y)
|
||||||
@ -478,7 +465,8 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
error("Line is out of range.", 2)
|
error("Line is out of range.", 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
return tLines[y].text, tLines[y].textColor, tLines[y].backgroundColor
|
local line = tLines[y]
|
||||||
|
return line[1], line[2], line[3]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Other functions
|
-- Other functions
|
||||||
@ -574,26 +562,22 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
|||||||
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
|
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
|
||||||
for y = 1, new_height do
|
for y = 1, new_height do
|
||||||
if y > nHeight then
|
if y > nHeight then
|
||||||
tNewLines[y] = {
|
tNewLines[y] = { sEmptyText, sEmptyTextColor, sEmptyBackgroundColor }
|
||||||
text = sEmptyText,
|
|
||||||
textColor = sEmptyTextColor,
|
|
||||||
backgroundColor = sEmptyBackgroundColor,
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
local tOldLine = tLines[y]
|
local tOldLine = tLines[y]
|
||||||
if new_width == nWidth then
|
if new_width == nWidth then
|
||||||
tNewLines[y] = tOldLine
|
tNewLines[y] = tOldLine
|
||||||
elseif new_width < nWidth then
|
elseif new_width < nWidth then
|
||||||
tNewLines[y] = {
|
tNewLines[y] = {
|
||||||
text = string_sub(tOldLine.text, 1, new_width),
|
string_sub(tOldLine[1], 1, new_width),
|
||||||
textColor = string_sub(tOldLine.textColor, 1, new_width),
|
string_sub(tOldLine[2], 1, new_width),
|
||||||
backgroundColor = string_sub(tOldLine.backgroundColor, 1, new_width),
|
string_sub(tOldLine[3], 1, new_width),
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tNewLines[y] = {
|
tNewLines[y] = {
|
||||||
text = tOldLine.text .. string_sub(sEmptyText, nWidth + 1, new_width),
|
tOldLine[1] .. string_sub(sEmptyText, nWidth + 1, new_width),
|
||||||
textColor = tOldLine.textColor .. string_sub(sEmptyTextColor, nWidth + 1, new_width),
|
tOldLine[2] .. string_sub(sEmptyTextColor, nWidth + 1, new_width),
|
||||||
backgroundColor = tOldLine.backgroundColor .. string_sub(sEmptyBackgroundColor, nWidth + 1, new_width),
|
tOldLine[3] .. string_sub(sEmptyBackgroundColor, nWidth + 1, new_width),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,62 @@
|
|||||||
|
# New features in CC: Tweaked 1.108.1
|
||||||
|
|
||||||
|
Several bug fixes:
|
||||||
|
* Prevent no-opped players breaking or placing command computers.
|
||||||
|
* Allow using `@LuaFunction`-annotated methods on classes defined in child classloaders.
|
||||||
|
|
||||||
|
# New features in CC: Tweaked 1.108.0
|
||||||
|
|
||||||
|
* Remove compression from terminal/monitor packets. Vanilla applies its own compression, so this ends up being less helpful than expected.
|
||||||
|
* `/computercraft` command now supports permission mods.
|
||||||
|
* Split some GUI textures into sprite sheets.
|
||||||
|
* Support the `%g` character class in string pattern matching.
|
||||||
|
|
||||||
|
Several bug fixes:
|
||||||
|
* Fix crash when playing some modded records via a disk drive.
|
||||||
|
* Fix race condition when computers attach or detach from a monitor.
|
||||||
|
* Fix the "max websocket message" config option not being read.
|
||||||
|
* `tostring` now correctly obeys `__name`.
|
||||||
|
* Fix several inconsistencies with pattern matching character classes.
|
||||||
|
|
||||||
|
# New features in CC: Tweaked 1.107.0
|
||||||
|
|
||||||
|
* Add `disabled_generic_methods` config option to disable generic methods.
|
||||||
|
* Add basic integration with EMI.
|
||||||
|
* Enchanted turtle tools now render with a glint.
|
||||||
|
* Update several translations (PatriikPlays, 1Turtle, Ale32bit).
|
||||||
|
|
||||||
|
Several bug fixes:
|
||||||
|
* Fix client config file being generated on a dedicated server.
|
||||||
|
* Fix numbers ending in "f" or "d" being treated as avalid.
|
||||||
|
* Fix `string.pack`'s "z" specifier causing out-of-bounds errors.
|
||||||
|
* Fix several issues with `turtle.dig`'s custom actions (tilling, making paths).
|
||||||
|
|
||||||
|
# New features in CC: Tweaked 1.106.1
|
||||||
|
|
||||||
|
Several bug fixes:
|
||||||
|
* Block the CGNAT range (100.64.0.0/10) by default.
|
||||||
|
* Fix conflicts with other mods replacing reach distance.
|
||||||
|
|
||||||
|
# New features in CC: Tweaked 1.106.0
|
||||||
|
|
||||||
|
* Numerous documentation improvements (MCJack123, znepb, penguinencounter).
|
||||||
|
* Port `fs.find` to Lua. This also allows using `?` as a wildcard.
|
||||||
|
* Computers cursors now glow in the dark.
|
||||||
|
* Allow changing turtle upgrades from the GUI.
|
||||||
|
* Add option to serialize Unicode strings to JSON (MCJack123).
|
||||||
|
* Small optimisations to the `window` API.
|
||||||
|
* Turtle upgrades can now preserve NBT from upgrade item stack and when broken.
|
||||||
|
* Add support for tool enchantments and durability via datapacks. This is disabled for the built-in tools.
|
||||||
|
|
||||||
|
Several bug fixes:
|
||||||
|
* Fix turtles rendering incorrectly when upside down.
|
||||||
|
* Fix misplaced calls to IArguments.escapes.
|
||||||
|
* Lua REPL no longer accepts `)(` as a valid expression.
|
||||||
|
* Fix several inconsistencies with `require`/`package.path` in the Lua REPL (Wojbie).
|
||||||
|
* Fix turtle being able to place water buckets outside its reach distance.
|
||||||
|
* Fix private several IP address ranges not being blocked by the `$private` rule.
|
||||||
|
* Improve permission checks in the `/computercraft` command.
|
||||||
|
|
||||||
# New features in CC: Tweaked 1.105.0
|
# New features in CC: Tweaked 1.105.0
|
||||||
|
|
||||||
* Optimise JSON string parsing.
|
* Optimise JSON string parsing.
|
||||||
|
@ -12,4 +12,4 @@ commands.give( "dan200", "minecraft:diamond", 64 )
|
|||||||
This works with any command. Use "commands.async" instead of "commands" to execute asynchronously.
|
This works with any command. Use "commands.async" instead of "commands" to execute asynchronously.
|
||||||
|
|
||||||
The commands API is only available on Command Computers.
|
The commands API is only available on Command Computers.
|
||||||
Visit http://minecraft.gamepedia.com/Commands for documentation on all commands.
|
Visit https://minecraft.wiki/w/Commands for documentation on all commands.
|
||||||
|
@ -6,4 +6,4 @@ if sEvent == "key" and nKey == keys.enter then
|
|||||||
-- Do something
|
-- Do something
|
||||||
end
|
end
|
||||||
|
|
||||||
See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference.
|
See https://www.minecraft.wiki/w/Key_codes, or the source code, for a complete reference.
|
||||||
|
@ -1,25 +1,7 @@
|
|||||||
New features in CC: Tweaked 1.105.0
|
New features in CC: Tweaked 1.108.1
|
||||||
|
|
||||||
* Optimise JSON string parsing.
|
|
||||||
* Add `colors.fromBlit` (Erb3).
|
|
||||||
* Upload file size limit is now configurable (khankul).
|
|
||||||
* Wired cables no longer have a distance limit.
|
|
||||||
* Java methods now coerce values to strings consistently with Lua.
|
|
||||||
* Add custom timeout support to the HTTP API.
|
|
||||||
* Support custom proxies for HTTP requests (Lemmmy).
|
|
||||||
* The `speaker` program now errors when playing HTML files.
|
|
||||||
* `edit` now shows an error message when editing read-only files.
|
|
||||||
* Update Ukranian translation (SirEdvin).
|
|
||||||
|
|
||||||
Several bug fixes:
|
Several bug fixes:
|
||||||
* Allow GPS hosts to only be 1 block apart.
|
* Prevent no-opped players breaking or placing command computers.
|
||||||
* Fix "Turn On"/"Turn Off" buttons being inverted in the computer GUI (Erb3).
|
* Allow using `@LuaFunction`-annotated methods on classes defined in child classloaders.
|
||||||
* Fix arrow keys not working in the printout UI.
|
|
||||||
* Several documentation fixes (zyxkad, Lupus590, Commandcracker).
|
|
||||||
* Fix monitor renderer debug text always being visible on Forge.
|
|
||||||
* Fix crash when another mod changes the LoggerContext.
|
|
||||||
* Fix the `monitor_renderer` option not being present in Fabric config files.
|
|
||||||
* Pasting on MacOS/OSX now uses Cmd+V rather than Ctrl+V.
|
|
||||||
* Fix turtles placing blocks upside down when at y<0.
|
|
||||||
|
|
||||||
Type "help changelog" to see the full version history.
|
Type "help changelog" to see the full version history.
|
||||||
|
@ -9,11 +9,11 @@ DFPWM (Dynamic Filter Pulse Width Modulation) is an audio codec designed by Grea
|
|||||||
format compared to raw PCM data, only using 1 bit per sample, but is simple enough to simple enough to encode and decode
|
format compared to raw PCM data, only using 1 bit per sample, but is simple enough to simple enough to encode and decode
|
||||||
in real time.
|
in real time.
|
||||||
|
|
||||||
Typically DFPWM audio is read from @{fs.BinaryReadHandle|the filesystem} or a @{http.Response|a web request} as a
|
Typically DFPWM audio is read from [the filesystem][`fs.BinaryReadHandle`] or a [a web request][`http.Response`] as a
|
||||||
string, and converted a format suitable for @{speaker.playAudio}.
|
string, and converted a format suitable for [`speaker.playAudio`].
|
||||||
|
|
||||||
## Encoding and decoding files
|
## Encoding and decoding files
|
||||||
This modules exposes two key functions, @{make_decoder} and @{make_encoder}, which construct a new decoder or encoder.
|
This modules exposes two key functions, [`make_decoder`] and [`make_encoder`], which construct a new decoder or encoder.
|
||||||
The returned encoder/decoder is itself a function, which converts between the two kinds of data.
|
The returned encoder/decoder is itself a function, which converts between the two kinds of data.
|
||||||
|
|
||||||
These encoders and decoders have lots of hidden state, so you should be careful to use the same encoder or decoder for
|
These encoders and decoders have lots of hidden state, so you should be careful to use the same encoder or decoder for
|
||||||
@ -95,10 +95,9 @@ end
|
|||||||
The returned encoder is itself a function. This function accepts a table of amplitude data between -128 and 127 and
|
The returned encoder is itself a function. This function accepts a table of amplitude data between -128 and 127 and
|
||||||
returns the encoded DFPWM data.
|
returns the encoded DFPWM data.
|
||||||
|
|
||||||
:::caution Reusing encoders
|
> [Reusing encoders][!WARNING]
|
||||||
Encoders have lots of internal state which tracks the state of the current stream. If you reuse an encoder for multiple
|
> Encoders have lots of internal state which tracks the state of the current stream. If you reuse an encoder for multiple
|
||||||
streams, or use different encoders for the same stream, the resulting audio may not sound correct.
|
> streams, or use different encoders for the same stream, the resulting audio may not sound correct.
|
||||||
:::
|
|
||||||
|
|
||||||
@treturn function(pcm: { number... }):string The encoder function
|
@treturn function(pcm: { number... }):string The encoder function
|
||||||
@see encode A helper function for encoding an entire file of audio at once.
|
@see encode A helper function for encoding an entire file of audio at once.
|
||||||
@ -138,10 +137,9 @@ end
|
|||||||
The returned decoder is itself a function. This function accepts a string and returns a table of amplitudes, each value
|
The returned decoder is itself a function. This function accepts a string and returns a table of amplitudes, each value
|
||||||
between -128 and 127.
|
between -128 and 127.
|
||||||
|
|
||||||
:::caution Reusing decoders
|
> [Reusing decoders][!WARNING]
|
||||||
Decoders have lots of internal state which tracks the state of the current stream. If you reuse an decoder for multiple
|
> Decoders have lots of internal state which tracks the state of the current stream. If you reuse an decoder for
|
||||||
streams, or use different decoders for the same stream, the resulting audio may not sound correct.
|
> multiple streams, or use different decoders for the same stream, the resulting audio may not sound correct.
|
||||||
:::
|
|
||||||
|
|
||||||
@treturn function(dfpwm: string):{ number... } The encoder function
|
@treturn function(dfpwm: string):{ number... } The encoder function
|
||||||
@see decode A helper function for decoding an entire file of audio at once.
|
@see decode A helper function for decoding an entire file of audio at once.
|
||||||
@ -167,7 +165,7 @@ local function make_decoder()
|
|||||||
local low_pass_charge = 0
|
local low_pass_charge = 0
|
||||||
local previous_charge, previous_bit = 0, false
|
local previous_charge, previous_bit = 0, false
|
||||||
|
|
||||||
return function (input, output)
|
return function (input)
|
||||||
expect(1, input, "string")
|
expect(1, input, "string")
|
||||||
|
|
||||||
local output, output_n = {}, 0
|
local output, output_n = {}, 0
|
||||||
@ -200,7 +198,7 @@ end
|
|||||||
--[[- A convenience function for decoding a complete file of audio at once.
|
--[[- A convenience function for decoding a complete file of audio at once.
|
||||||
|
|
||||||
This should only be used for short files. For larger files, one should read the file in chunks and process it using
|
This should only be used for short files. For larger files, one should read the file in chunks and process it using
|
||||||
@{make_decoder}.
|
[`make_decoder`].
|
||||||
|
|
||||||
@tparam string input The DFPWM data to convert.
|
@tparam string input The DFPWM data to convert.
|
||||||
@treturn { number... } The produced amplitude data.
|
@treturn { number... } The produced amplitude data.
|
||||||
@ -214,7 +212,7 @@ end
|
|||||||
--[[- A convenience function for encoding a complete file of audio at once.
|
--[[- A convenience function for encoding a complete file of audio at once.
|
||||||
|
|
||||||
This should only be used for complete pieces of audio. If you are writing writing multiple chunks to the same place,
|
This should only be used for complete pieces of audio. If you are writing writing multiple chunks to the same place,
|
||||||
you should use an encoder returned by @{make_encoder} instead.
|
you should use an encoder returned by [`make_encoder`] instead.
|
||||||
|
|
||||||
@tparam { number... } input The table of amplitude data.
|
@tparam { number... } input The table of amplitude data.
|
||||||
@treturn string The encoded DFPWM data.
|
@treturn string The encoded DFPWM data.
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--- A collection of helper methods for working with input completion, such
|
--- A collection of helper methods for working with input completion, such
|
||||||
-- as that require by @{_G.read}.
|
-- as that require by [`_G.read`].
|
||||||
--
|
--
|
||||||
-- @module cc.completion
|
-- @module cc.completion
|
||||||
-- @see cc.shell.completion For additional helpers to use with
|
-- @see cc.shell.completion For additional helpers to use with
|
||||||
-- @{shell.setCompletionFunction}.
|
-- [`shell.setCompletionFunction`].
|
||||||
-- @since 1.85.0
|
-- @since 1.85.0
|
||||||
|
|
||||||
local expect = require "cc.expect".expect
|
local expect = require "cc.expect".expect
|
||||||
@ -34,7 +34,7 @@ end
|
|||||||
-- @tparam { string... } choices The list of choices to complete from.
|
-- @tparam { string... } choices The list of choices to complete from.
|
||||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed item.
|
-- @tparam[opt] boolean add_space Whether to add a space after the completed item.
|
||||||
-- @treturn { string... } A list of suffixes of matching strings.
|
-- @treturn { string... } A list of suffixes of matching strings.
|
||||||
-- @usage Call @{_G.read}, completing the names of various animals.
|
-- @usage Call [`_G.read`], completing the names of various animals.
|
||||||
--
|
--
|
||||||
-- local completion = require "cc.completion"
|
-- local completion = require "cc.completion"
|
||||||
-- local animals = { "dog", "cat", "lion", "unicorn" }
|
-- local animals = { "dog", "cat", "lion", "unicorn" }
|
||||||
@ -76,7 +76,7 @@ local function side(text, add_space)
|
|||||||
return choice_impl(text, sides, add_space)
|
return choice_impl(text, sides, add_space)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Complete a @{settings|setting}.
|
--- Complete a [setting][`settings`].
|
||||||
--
|
--
|
||||||
-- @tparam string text The input string to complete.
|
-- @tparam string text The input string to complete.
|
||||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed settings.
|
-- @tparam[opt] boolean add_space Whether to add a space after the completed settings.
|
||||||
@ -92,7 +92,7 @@ end
|
|||||||
|
|
||||||
local command_list
|
local command_list
|
||||||
|
|
||||||
--- Complete the name of a Minecraft @{commands|command}.
|
--- Complete the name of a Minecraft [command][`commands`].
|
||||||
--
|
--
|
||||||
-- @tparam string text The input string to complete.
|
-- @tparam string text The input string to complete.
|
||||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed command.
|
-- @tparam[opt] boolean add_space Whether to add a space after the completed command.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: MPL-2.0
|
-- SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
--[[- The @{cc.expect} library provides helper functions for verifying that
|
--[[- The [`cc.expect`] library provides helper functions for verifying that
|
||||||
function arguments are well-formed and of the correct type.
|
function arguments are well-formed and of the correct type.
|
||||||
|
|
||||||
@module cc.expect
|
@module cc.expect
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: MPL-2.0
|
-- SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
--- Read and draw nbt ("Nitrogen Fingers Text") images.
|
--- Read and draw nft ("Nitrogen Fingers Text") images.
|
||||||
--
|
--
|
||||||
-- nft ("Nitrogen Fingers Text") is a file format for drawing basic images.
|
-- nft ("Nitrogen Fingers Text") is a file format for drawing basic images.
|
||||||
-- Unlike the images that @{paintutils.parseImage} uses, nft supports coloured
|
-- Unlike the images that [`paintutils.parseImage`] uses, nft supports coloured
|
||||||
-- text as well as simple coloured pixels.
|
-- text as well as simple coloured pixels.
|
||||||
--
|
--
|
||||||
-- @module cc.image.nft
|
-- @module cc.image.nft
|
||||||
@ -87,7 +87,7 @@ end
|
|||||||
|
|
||||||
--- Draw an nft image to the screen.
|
--- Draw an nft image to the screen.
|
||||||
--
|
--
|
||||||
-- @tparam table image An image, as returned from @{load} or @{draw}.
|
-- @tparam table image An image, as returned from [`load`] or [`parse`].
|
||||||
-- @tparam number xPos The x position to start drawing at.
|
-- @tparam number xPos The x position to start drawing at.
|
||||||
-- @tparam number xPos The y position to start drawing at.
|
-- @tparam number xPos The y position to start drawing at.
|
||||||
-- @tparam[opt] term.Redirect target The terminal redirect to draw to. Defaults to the
|
-- @tparam[opt] term.Redirect target The terminal redirect to draw to. Defaults to the
|
||||||
|
@ -4,10 +4,9 @@
|
|||||||
|
|
||||||
--[[- A pretty-printer for Lua errors.
|
--[[- A pretty-printer for Lua errors.
|
||||||
|
|
||||||
:::warning
|
> [!DANGER]
|
||||||
This is an internal module and SHOULD NOT be used in your own code. It may
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
be removed or changed at any time.
|
> be removed or changed at any time.
|
||||||
:::
|
|
||||||
|
|
||||||
This consumes a list of messages and "annotations" and displays the error to the
|
This consumes a list of messages and "annotations" and displays the error to the
|
||||||
terminal.
|
terminal.
|
||||||
@ -100,7 +99,7 @@ local code_accent = pretty.text("\x95", colours.cyan)
|
|||||||
over the underlying source, exposing the following functions:
|
over the underlying source, exposing the following functions:
|
||||||
- `get_pos`: Get the line and column of an opaque position.
|
- `get_pos`: Get the line and column of an opaque position.
|
||||||
- `get_line`: Get the source code for an opaque position.
|
- `get_line`: Get the source code for an opaque position.
|
||||||
@tparam table message The message to display, as produced by @{cc.internal.syntax.errors}.
|
@tparam table message The message to display, as produced by [`cc.internal.syntax.errors`].
|
||||||
]]
|
]]
|
||||||
return function(context, message)
|
return function(context, message)
|
||||||
expect(1, context, "table")
|
expect(1, context, "table")
|
||||||
|
@ -4,10 +4,9 @@
|
|||||||
|
|
||||||
--[[- Internal tools for working with errors.
|
--[[- Internal tools for working with errors.
|
||||||
|
|
||||||
:::warning
|
> [!DANGER]
|
||||||
This is an internal module and SHOULD NOT be used in your own code. It may
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
be removed or changed at any time.
|
> be removed or changed at any time.
|
||||||
:::
|
|
||||||
|
|
||||||
@local
|
@local
|
||||||
]]
|
]]
|
||||||
|
@ -2,12 +2,11 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: MPL-2.0
|
-- SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
--[[- Upload a list of files, as received by the @{event!file_transfer} event.
|
--[[- Upload a list of files, as received by the [`event!file_transfer`] event.
|
||||||
|
|
||||||
:::warning
|
> [!DANGER]
|
||||||
This is an internal module and SHOULD NOT be used in your own code. It may
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
be removed or changed at any time.
|
> be removed or changed at any time.
|
||||||
:::
|
|
||||||
|
|
||||||
@local
|
@local
|
||||||
]]
|
]]
|
||||||
|
@ -4,14 +4,13 @@
|
|||||||
|
|
||||||
--[[- The error messages reported by our lexer and parser.
|
--[[- The error messages reported by our lexer and parser.
|
||||||
|
|
||||||
:::warning
|
> [!DANGER]
|
||||||
This is an internal module and SHOULD NOT be used in your own code. It may
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
be removed or changed at any time.
|
> be removed or changed at any time.
|
||||||
:::
|
|
||||||
|
|
||||||
This provides a list of factory methods which take source positions and produce
|
This provides a list of factory methods which take source positions and produce
|
||||||
appropriate error messages targeting that location. These error messages can
|
appropriate error messages targeting that location. These error messages can
|
||||||
then be displayed to the user via @{cc.internal.error_printer}.
|
then be displayed to the user via [`cc.internal.error_printer`].
|
||||||
|
|
||||||
@local
|
@local
|
||||||
]]
|
]]
|
||||||
@ -121,7 +120,7 @@ function errors.unfinished_string(start_pos, end_pos, quote)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[- A string which ends with an escape sequence (so a literal `"foo\`). This
|
--[[- A string which ends with an escape sequence (so a literal `"foo\`). This
|
||||||
is slightly different from @{unfinished_string}, as we don't want to suggest
|
is slightly different from [`unfinished_string`], as we don't want to suggest
|
||||||
adding a quote.
|
adding a quote.
|
||||||
|
|
||||||
@tparam number start_pos The start position of the string.
|
@tparam number start_pos The start position of the string.
|
||||||
@ -467,7 +466,7 @@ function errors.standalone_name(pos)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[- A statement of the form `x.y`. This is similar to @{standalone_name}, but
|
--[[- A statement of the form `x.y`. This is similar to [`standalone_name`], but
|
||||||
when the next token is on another line.
|
when the next token is on another line.
|
||||||
|
|
||||||
@tparam number pos The position right after this name.
|
@tparam number pos The position right after this name.
|
||||||
|
@ -4,10 +4,9 @@
|
|||||||
|
|
||||||
--[[- The main entrypoint to our Lua parser
|
--[[- The main entrypoint to our Lua parser
|
||||||
|
|
||||||
:::warning
|
> [!DANGER]
|
||||||
This is an internal module and SHOULD NOT be used in your own code. It may
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
be removed or changed at any time.
|
> be removed or changed at any time.
|
||||||
:::
|
|
||||||
|
|
||||||
@local
|
@local
|
||||||
]]
|
]]
|
||||||
@ -21,6 +20,8 @@ local error_printer = require "cc.internal.error_printer"
|
|||||||
local error_sentinel = {}
|
local error_sentinel = {}
|
||||||
|
|
||||||
local function make_context(input)
|
local function make_context(input)
|
||||||
|
expect(1, input, "string")
|
||||||
|
|
||||||
local context = {}
|
local context = {}
|
||||||
|
|
||||||
local lines = { 1 }
|
local lines = { 1 }
|
||||||
@ -73,8 +74,9 @@ local function parse(input, start_symbol)
|
|||||||
expect(2, start_symbol, "number")
|
expect(2, start_symbol, "number")
|
||||||
|
|
||||||
local context = make_context(input)
|
local context = make_context(input)
|
||||||
function context.report(msg)
|
function context.report(msg, ...)
|
||||||
expect(1, msg, "table")
|
expect(1, msg, "table", "function")
|
||||||
|
if type(msg) == "function" then msg = msg(...) end
|
||||||
error_printer(context, msg)
|
error_printer(context, msg)
|
||||||
error(error_sentinel)
|
error(error_sentinel)
|
||||||
end
|
end
|
||||||
@ -110,8 +112,9 @@ local function parse_repl(input)
|
|||||||
local context = make_context(input)
|
local context = make_context(input)
|
||||||
|
|
||||||
local last_error = nil
|
local last_error = nil
|
||||||
function context.report(msg)
|
function context.report(msg, ...)
|
||||||
expect(1, msg, "table")
|
expect(1, msg, "table", "function")
|
||||||
|
if type(msg) == "function" then msg = msg(...) end
|
||||||
last_error = msg
|
last_error = msg
|
||||||
error(error_sentinel)
|
error(error_sentinel)
|
||||||
end
|
end
|
||||||
|
@ -4,17 +4,16 @@
|
|||||||
|
|
||||||
--[[- A lexer for Lua source code.
|
--[[- A lexer for Lua source code.
|
||||||
|
|
||||||
:::warning
|
> [!DANGER]
|
||||||
This is an internal module and SHOULD NOT be used in your own code. It may
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
be removed or changed at any time.
|
> be removed or changed at any time.
|
||||||
:::
|
|
||||||
|
|
||||||
This module provides utilities for lexing Lua code, returning tokens compatible
|
This module provides utilities for lexing Lua code, returning tokens compatible
|
||||||
with @{cc.internal.syntax.parser}. While all lexers are roughly the same, there
|
with [`cc.internal.syntax.parser`]. While all lexers are roughly the same, there
|
||||||
are some design choices worth drawing attention to:
|
are some design choices worth drawing attention to:
|
||||||
|
|
||||||
- The lexer uses Lua patterns (i.e. @{string.find}) as much as possible,
|
- The lexer uses Lua patterns (i.e. [`string.find`]) as much as possible,
|
||||||
trying to avoid @{string.sub} loops except when needed. This allows us to
|
trying to avoid [`string.sub`] loops except when needed. This allows us to
|
||||||
move string processing to native code, which ends up being much faster.
|
move string processing to native code, which ends up being much faster.
|
||||||
|
|
||||||
- We try to avoid allocating where possible. There are some cases we need to
|
- We try to avoid allocating where possible. There are some cases we need to
|
||||||
@ -96,7 +95,7 @@ local function lex_number(context, str, start)
|
|||||||
local contents = sub(str, start, pos - 1)
|
local contents = sub(str, start, pos - 1)
|
||||||
if not tonumber(contents) then
|
if not tonumber(contents) then
|
||||||
-- TODO: Separate error for "2..3"?
|
-- TODO: Separate error for "2..3"?
|
||||||
context.report(errors.malformed_number(start, pos - 1))
|
context.report(errors.malformed_number, start, pos - 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
return tokens.NUMBER, pos - 1
|
return tokens.NUMBER, pos - 1
|
||||||
@ -118,14 +117,14 @@ local function lex_string(context, str, start_pos, quote)
|
|||||||
return tokens.STRING, pos
|
return tokens.STRING, pos
|
||||||
elseif c == "\n" or c == "\r" or c == "" then
|
elseif c == "\n" or c == "\r" or c == "" then
|
||||||
-- We don't call newline here, as that's done for the next token.
|
-- We don't call newline here, as that's done for the next token.
|
||||||
context.report(errors.unfinished_string(start_pos, pos, quote))
|
context.report(errors.unfinished_string, start_pos, pos, quote)
|
||||||
return tokens.STRING, pos - 1
|
return tokens.STRING, pos - 1
|
||||||
elseif c == "\\" then
|
elseif c == "\\" then
|
||||||
c = sub(str, pos + 1, pos + 1)
|
c = sub(str, pos + 1, pos + 1)
|
||||||
if c == "\n" or c == "\r" then
|
if c == "\n" or c == "\r" then
|
||||||
pos = newline(context, str, pos + 1, c)
|
pos = newline(context, str, pos + 1, c)
|
||||||
elseif c == "" then
|
elseif c == "" then
|
||||||
context.report(errors.unfinished_string_escape(start_pos, pos, quote))
|
context.report(errors.unfinished_string_escape, start_pos, pos, quote)
|
||||||
return tokens.STRING, pos
|
return tokens.STRING, pos
|
||||||
elseif c == "z" then
|
elseif c == "z" then
|
||||||
pos = pos + 2
|
pos = pos + 2
|
||||||
@ -133,7 +132,7 @@ local function lex_string(context, str, start_pos, quote)
|
|||||||
local next_pos, _, c = find(str, "([%S\r\n])", pos)
|
local next_pos, _, c = find(str, "([%S\r\n])", pos)
|
||||||
|
|
||||||
if not next_pos then
|
if not next_pos then
|
||||||
context.report(errors.unfinished_string(start_pos, #str, quote))
|
context.report(errors.unfinished_string, start_pos, #str, quote)
|
||||||
return tokens.STRING, #str
|
return tokens.STRING, #str
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -178,7 +177,7 @@ end
|
|||||||
-- @tparam number start The start position, after the input boundary.
|
-- @tparam number start The start position, after the input boundary.
|
||||||
-- @tparam number len The expected length of the boundary. Equal to 1 + the
|
-- @tparam number len The expected length of the boundary. Equal to 1 + the
|
||||||
-- number of `=`.
|
-- number of `=`.
|
||||||
-- @treturn number|nil The end position, or @{nil} if this is not terminated.
|
-- @treturn number|nil The end position, or [`nil`] if this is not terminated.
|
||||||
local function lex_long_str(context, str, start, len)
|
local function lex_long_str(context, str, start, len)
|
||||||
local pos = start
|
local pos = start
|
||||||
while true do
|
while true do
|
||||||
@ -196,7 +195,7 @@ local function lex_long_str(context, str, start, len)
|
|||||||
elseif c == "[" then
|
elseif c == "[" then
|
||||||
local ok, boundary_pos = lex_long_str_boundary(str, pos + 1, "[")
|
local ok, boundary_pos = lex_long_str_boundary(str, pos + 1, "[")
|
||||||
if ok and boundary_pos - pos == len and len == 1 then
|
if ok and boundary_pos - pos == len and len == 1 then
|
||||||
context.report(errors.nested_long_str(pos, boundary_pos))
|
context.report(errors.nested_long_str, pos, boundary_pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
pos = boundary_pos
|
pos = boundary_pos
|
||||||
@ -238,12 +237,12 @@ local function lex_token(context, str, pos)
|
|||||||
local end_pos = lex_long_str(context, str, boundary_pos + 1, boundary_pos - pos)
|
local end_pos = lex_long_str(context, str, boundary_pos + 1, boundary_pos - pos)
|
||||||
if end_pos then return tokens.STRING, end_pos end
|
if end_pos then return tokens.STRING, end_pos end
|
||||||
|
|
||||||
context.report(errors.unfinished_long_string(pos, boundary_pos, boundary_pos - pos))
|
context.report(errors.unfinished_long_string, pos, boundary_pos, boundary_pos - pos)
|
||||||
return tokens.ERROR, #str
|
return tokens.ERROR, #str
|
||||||
elseif pos + 1 == boundary_pos then -- Just a "["
|
elseif pos + 1 == boundary_pos then -- Just a "["
|
||||||
return tokens.OSQUARE, pos
|
return tokens.OSQUARE, pos
|
||||||
else -- Malformed long string, for instance "[="
|
else -- Malformed long string, for instance "[="
|
||||||
context.report(errors.malformed_long_string(pos, boundary_pos, boundary_pos - pos))
|
context.report(errors.malformed_long_string, pos, boundary_pos, boundary_pos - pos)
|
||||||
return tokens.ERROR, boundary_pos
|
return tokens.ERROR, boundary_pos
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -260,7 +259,7 @@ local function lex_token(context, str, pos)
|
|||||||
local end_pos = lex_long_str(context, str, boundary_pos + 1, boundary_pos - comment_pos)
|
local end_pos = lex_long_str(context, str, boundary_pos + 1, boundary_pos - comment_pos)
|
||||||
if end_pos then return tokens.COMMENT, end_pos end
|
if end_pos then return tokens.COMMENT, end_pos end
|
||||||
|
|
||||||
context.report(errors.unfinished_long_comment(pos, boundary_pos, boundary_pos - comment_pos))
|
context.report(errors.unfinished_long_comment, pos, boundary_pos, boundary_pos - comment_pos)
|
||||||
return tokens.ERROR, #str
|
return tokens.ERROR, #str
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -317,18 +316,18 @@ local function lex_token(context, str, pos)
|
|||||||
if end_pos - pos <= 3 then
|
if end_pos - pos <= 3 then
|
||||||
local contents = sub(str, pos, end_pos)
|
local contents = sub(str, pos, end_pos)
|
||||||
if contents == "&&" then
|
if contents == "&&" then
|
||||||
context.report(errors.wrong_and(pos, end_pos))
|
context.report(errors.wrong_and, pos, end_pos)
|
||||||
return tokens.AND, end_pos
|
return tokens.AND, end_pos
|
||||||
elseif contents == "||" then
|
elseif contents == "||" then
|
||||||
context.report(errors.wrong_or(pos, end_pos))
|
context.report(errors.wrong_or, pos, end_pos)
|
||||||
return tokens.OR, end_pos
|
return tokens.OR, end_pos
|
||||||
elseif contents == "!=" or contents == "<>" then
|
elseif contents == "!=" or contents == "<>" then
|
||||||
context.report(errors.wrong_ne(pos, end_pos))
|
context.report(errors.wrong_ne, pos, end_pos)
|
||||||
return tokens.NE, end_pos
|
return tokens.NE, end_pos
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context.report(errors.unexpected_character(pos))
|
context.report(errors.unexpected_character, pos)
|
||||||
return tokens.ERROR, end_pos
|
return tokens.ERROR, end_pos
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,10 +4,9 @@
|
|||||||
|
|
||||||
--[[- A parser for Lua programs and expressions.
|
--[[- A parser for Lua programs and expressions.
|
||||||
|
|
||||||
:::warning
|
> [!DANGER]
|
||||||
This is an internal module and SHOULD NOT be used in your own code. It may
|
> This is an internal module and SHOULD NOT be used in your own code. It may
|
||||||
be removed or changed at any time.
|
> be removed or changed at any time.
|
||||||
:::
|
|
||||||
|
|
||||||
Most of the code in this module is automatically generated from the Lua grammar,
|
Most of the code in this module is automatically generated from the Lua grammar,
|
||||||
hence being mostly unreadable!
|
hence being mostly unreadable!
|
||||||
@ -244,7 +243,7 @@ local function handle_error(context, stack, stack_n, token, token_start, token_e
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context.report(errors.unexpected_token(token, token_start, token_end))
|
context.report(errors.unexpected_token, token, token_start, token_end)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
--[[- A pretty printer for rendering data structures in an aesthetically
|
--[[- A pretty printer for rendering data structures in an aesthetically
|
||||||
pleasing manner.
|
pleasing manner.
|
||||||
|
|
||||||
In order to display something using @{cc.pretty}, you build up a series of
|
In order to display something using [`cc.pretty`], you build up a series of
|
||||||
@{Doc|documents}. These behave a little bit like strings; you can concatenate
|
[documents][`Doc`]. These behave a little bit like strings; you can concatenate
|
||||||
them together and then print them to the screen.
|
them together and then print them to the screen.
|
||||||
|
|
||||||
However, documents also allow you to control how they should be printed. There
|
However, documents also allow you to control how they should be printed. There
|
||||||
are several functions (such as @{nest} and @{group}) which allow you to control
|
are several functions (such as [`nest`] and [`group`]) which allow you to control
|
||||||
the "layout" of the document. When you come to display the document, the 'best'
|
the "layout" of the document. When you come to display the document, the 'best'
|
||||||
(most compact) layout is used.
|
(most compact) layout is used.
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ local expect, field = expect.expect, expect.field
|
|||||||
local type, getmetatable, setmetatable, colours, str_write, tostring = type, getmetatable, setmetatable, colours, write, tostring
|
local type, getmetatable, setmetatable, colours, str_write, tostring = type, getmetatable, setmetatable, colours, write, tostring
|
||||||
local debug_info, debug_local = debug.getinfo, debug.getlocal
|
local debug_info, debug_local = debug.getinfo, debug.getlocal
|
||||||
|
|
||||||
--- @{table.insert} alternative, but with the length stored inline.
|
--- [`table.insert`] alternative, but with the length stored inline.
|
||||||
local function append(out, value)
|
local function append(out, value)
|
||||||
local n = out.n + 1
|
local n = out.n + 1
|
||||||
out[n], out.n = value, n
|
out[n], out.n = value, n
|
||||||
@ -59,10 +59,10 @@ local empty = mk_doc({ tag = "nil" })
|
|||||||
--- A document with a single space in it.
|
--- A document with a single space in it.
|
||||||
local space = mk_doc({ tag = "text", text = " " })
|
local space = mk_doc({ tag = "text", text = " " })
|
||||||
|
|
||||||
--- A line break. When collapsed with @{group}, this will be replaced with @{empty}.
|
--- A line break. When collapsed with [`group`], this will be replaced with [`empty`].
|
||||||
local line = mk_doc({ tag = "line", flat = empty })
|
local line = mk_doc({ tag = "line", flat = empty })
|
||||||
|
|
||||||
--- A line break. When collapsed with @{group}, this will be replaced with @{space}.
|
--- A line break. When collapsed with [`group`], this will be replaced with [`space`].
|
||||||
local space_line = mk_doc({ tag = "line", flat = space })
|
local space_line = mk_doc({ tag = "line", flat = space })
|
||||||
|
|
||||||
local text_cache = { [""] = empty, [" "] = space, ["\n"] = space_line }
|
local text_cache = { [""] = empty, [" "] = space, ["\n"] = space_line }
|
||||||
@ -73,7 +73,7 @@ end
|
|||||||
|
|
||||||
--- Create a new document from a string.
|
--- Create a new document from a string.
|
||||||
--
|
--
|
||||||
-- If your string contains multiple lines, @{group} will flatten the string
|
-- If your string contains multiple lines, [`group`] will flatten the string
|
||||||
-- into a single line, with spaces between each line.
|
-- into a single line, with spaces between each line.
|
||||||
--
|
--
|
||||||
-- @tparam string text The string to construct a new document with.
|
-- @tparam string text The string to construct a new document with.
|
||||||
@ -453,7 +453,7 @@ end
|
|||||||
|
|
||||||
--- Pretty-print an arbitrary object, converting it into a document.
|
--- Pretty-print an arbitrary object, converting it into a document.
|
||||||
--
|
--
|
||||||
-- This can then be rendered with @{write} or @{print}.
|
-- This can then be rendered with [`write`] or [`print`].
|
||||||
--
|
--
|
||||||
-- @param obj The object to pretty-print.
|
-- @param obj The object to pretty-print.
|
||||||
-- @tparam[opt] { function_args = boolean, function_source = boolean } options
|
-- @tparam[opt] { function_args = boolean, function_source = boolean } options
|
||||||
@ -479,7 +479,7 @@ local function pretty(obj, options)
|
|||||||
return pretty_impl(obj, actual_options, {})
|
return pretty_impl(obj, actual_options, {})
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[- A shortcut for calling @{pretty} and @{print} together.
|
--[[- A shortcut for calling [`pretty`] and [`print`] together.
|
||||||
|
|
||||||
@param obj The object to pretty-print.
|
@param obj The object to pretty-print.
|
||||||
@tparam[opt] { function_args = boolean, function_source = boolean } options
|
@tparam[opt] { function_args = boolean, function_source = boolean } options
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--[[- A pure Lua implementation of the builtin @{require} function and
|
--[[- A pure Lua implementation of the builtin [`require`] function and
|
||||||
@{package} library.
|
[`package`] library.
|
||||||
|
|
||||||
Generally you do not need to use this module - it is injected into the every
|
Generally you do not need to use this module - it is injected into the every
|
||||||
program's environment. However, it may be useful when building a custom shell or
|
program's environment. However, it may be useful when building a custom shell or
|
||||||
@ -11,7 +11,7 @@ when running programs yourself.
|
|||||||
|
|
||||||
@module cc.require
|
@module cc.require
|
||||||
@since 1.88.0
|
@since 1.88.0
|
||||||
@see using_require For an introduction on how to use @{require}.
|
@see using_require For an introduction on how to use [`require`].
|
||||||
@usage Construct the package and require function, and insert them into a
|
@usage Construct the package and require function, and insert them into a
|
||||||
custom environment.
|
custom environment.
|
||||||
|
|
||||||
@ -110,13 +110,13 @@ local function make_require(package)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Build an implementation of Lua's @{package} library, and a @{require}
|
--- Build an implementation of Lua's [`package`] library, and a [`require`]
|
||||||
-- function to load modules within it.
|
-- function to load modules within it.
|
||||||
--
|
--
|
||||||
-- @tparam table env The environment to load packages into.
|
-- @tparam table env The environment to load packages into.
|
||||||
-- @tparam string dir The directory that relative packages are loaded from.
|
-- @tparam string dir The directory that relative packages are loaded from.
|
||||||
-- @treturn function The new @{require} function.
|
-- @treturn function The new [`require`] function.
|
||||||
-- @treturn table The new @{package} library.
|
-- @treturn table The new [`package`] library.
|
||||||
local function make_package(env, dir)
|
local function make_package(env, dir)
|
||||||
expect(1, env, "table")
|
expect(1, env, "table")
|
||||||
expect(2, dir, "string")
|
expect(2, dir, "string")
|
||||||
|
@ -4,16 +4,16 @@
|
|||||||
|
|
||||||
--[[- A collection of helper methods for working with shell completion.
|
--[[- A collection of helper methods for working with shell completion.
|
||||||
|
|
||||||
Most programs may be completed using the @{build} helper method, rather than
|
Most programs may be completed using the [`build`] helper method, rather than
|
||||||
manually switching on the argument index.
|
manually switching on the argument index.
|
||||||
|
|
||||||
Note, the helper functions within this module do not accept an argument index,
|
Note, the helper functions within this module do not accept an argument index,
|
||||||
and so are not directly usable with the @{shell.setCompletionFunction}. Instead,
|
and so are not directly usable with the [`shell.setCompletionFunction`]. Instead,
|
||||||
wrap them using @{build}, or your own custom function.
|
wrap them using [`build`], or your own custom function.
|
||||||
|
|
||||||
@module cc.shell.completion
|
@module cc.shell.completion
|
||||||
@since 1.85.0
|
@since 1.85.0
|
||||||
@see cc.completion For more general helpers, suitable for use with @{_G.read}.
|
@see cc.completion For more general helpers, suitable for use with [`_G.read`].
|
||||||
@see shell.setCompletionFunction
|
@see shell.setCompletionFunction
|
||||||
|
|
||||||
@usage Register a completion handler for example.lua which prompts for a
|
@usage Register a completion handler for example.lua which prompts for a
|
||||||
@ -135,15 +135,15 @@ end
|
|||||||
--[[- A helper function for building shell completion arguments.
|
--[[- A helper function for building shell completion arguments.
|
||||||
|
|
||||||
This accepts a series of single-argument completion functions, and combines
|
This accepts a series of single-argument completion functions, and combines
|
||||||
them into a function suitable for use with @{shell.setCompletionFunction}.
|
them into a function suitable for use with [`shell.setCompletionFunction`].
|
||||||
|
|
||||||
@tparam nil|table|function ... Every argument to @{build} represents an argument
|
@tparam nil|table|function ... Every argument to [`build`] represents an argument
|
||||||
to the program you wish to complete. Each argument can be one of three types:
|
to the program you wish to complete. Each argument can be one of three types:
|
||||||
|
|
||||||
- `nil`: This argument will not be completed.
|
- `nil`: This argument will not be completed.
|
||||||
|
|
||||||
- A function: This argument will be completed with the given function. It is
|
- A function: This argument will be completed with the given function. It is
|
||||||
called with the @{shell} object, the string to complete and the arguments
|
called with the [`shell`] object, the string to complete and the arguments
|
||||||
before this one.
|
before this one.
|
||||||
|
|
||||||
- A table: This acts as a more powerful version of the function case. The table
|
- A table: This acts as a more powerful version of the function case. The table
|
||||||
@ -197,12 +197,12 @@ return {
|
|||||||
programWithArgs = programWithArgs,
|
programWithArgs = programWithArgs,
|
||||||
|
|
||||||
-- Re-export various other functions
|
-- Re-export various other functions
|
||||||
help = wrap(help.completeTopic), --- Wraps @{help.completeTopic} as a @{build} compatible function.
|
help = wrap(help.completeTopic), --- Wraps [`help.completeTopic`] as a [`build`] compatible function.
|
||||||
choice = wrap(completion.choice), --- Wraps @{cc.completion.choice} as a @{build} compatible function.
|
choice = wrap(completion.choice), --- Wraps [`cc.completion.choice`] as a [`build`] compatible function.
|
||||||
peripheral = wrap(completion.peripheral), --- Wraps @{cc.completion.peripheral} as a @{build} compatible function.
|
peripheral = wrap(completion.peripheral), --- Wraps [`cc.completion.peripheral`] as a [`build`] compatible function.
|
||||||
side = wrap(completion.side), --- Wraps @{cc.completion.side} as a @{build} compatible function.
|
side = wrap(completion.side), --- Wraps [`cc.completion.side`] as a [`build`] compatible function.
|
||||||
setting = wrap(completion.setting), --- Wraps @{cc.completion.setting} as a @{build} compatible function.
|
setting = wrap(completion.setting), --- Wraps [`cc.completion.setting`] as a [`build`] compatible function.
|
||||||
command = wrap(completion.command), --- Wraps @{cc.completion.command} as a @{build} compatible function.
|
command = wrap(completion.command), --- Wraps [`cc.completion.command`] as a [`build`] compatible function.
|
||||||
|
|
||||||
build = build,
|
build = build,
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ local expect = (require and require("cc.expect") or dofile("rom/modules/main/cc/
|
|||||||
--[[- Wraps a block of text, so that each line fits within the given width.
|
--[[- Wraps a block of text, so that each line fits within the given width.
|
||||||
|
|
||||||
This may be useful if you want to wrap text before displaying it to a
|
This may be useful if you want to wrap text before displaying it to a
|
||||||
@{monitor} or @{printer} without using @{_G.print|print}.
|
[`monitor`] or [`printer`] without using [print][`_G.print`].
|
||||||
|
|
||||||
@tparam string text The string to wrap.
|
@tparam string text The string to wrap.
|
||||||
@tparam[opt] number width The width to constrain to, defaults to the width of
|
@tparam[opt] number width The width to constrain to, defaults to the width of
|
||||||
|
@ -6,17 +6,17 @@
|
|||||||
--
|
--
|
||||||
-- When multiple programs are running, it displays a tab bar at the top of the
|
-- When multiple programs are running, it displays a tab bar at the top of the
|
||||||
-- screen, which allows you to switch between programs. New programs can be
|
-- screen, which allows you to switch between programs. New programs can be
|
||||||
-- launched using the `fg` or `bg` programs, or using the @{shell.openTab} and
|
-- launched using the `fg` or `bg` programs, or using the [`shell.openTab`] and
|
||||||
-- @{multishell.launch} functions.
|
-- [`multishell.launch`] functions.
|
||||||
--
|
--
|
||||||
-- Each process is identified by its ID, which corresponds to its position in
|
-- Each process is identified by its ID, which corresponds to its position in
|
||||||
-- the tab list. As tabs may be opened and closed, this ID is _not_ constant
|
-- the tab list. As tabs may be opened and closed, this ID is _not_ constant
|
||||||
-- over a program's run. As such, be careful not to use stale IDs.
|
-- over a program's run. As such, be careful not to use stale IDs.
|
||||||
--
|
--
|
||||||
-- As with @{shell}, @{multishell} is not a "true" API. Instead, it is a
|
-- As with [`shell`], [`multishell`] is not a "true" API. Instead, it is a
|
||||||
-- standard program, which launches a shell and injects its API into the shell's
|
-- standard program, which launches a shell and injects its API into the shell's
|
||||||
-- environment. This API is not available in the global environment, and so is
|
-- environment. This API is not available in the global environment, and so is
|
||||||
-- not available to @{os.loadAPI|APIs}.
|
-- not available to [APIs][`os.loadAPI`].
|
||||||
--
|
--
|
||||||
-- @module[module] multishell
|
-- @module[module] multishell
|
||||||
-- @since 1.6
|
-- @since 1.6
|
||||||
@ -222,7 +222,7 @@ local multishell = {} --- @export
|
|||||||
--- Get the currently visible process. This will be the one selected on
|
--- Get the currently visible process. This will be the one selected on
|
||||||
-- the tab bar.
|
-- the tab bar.
|
||||||
--
|
--
|
||||||
-- Note, this is different to @{getCurrent}, which returns the process which is
|
-- Note, this is different to [`getCurrent`], which returns the process which is
|
||||||
-- currently executing.
|
-- currently executing.
|
||||||
--
|
--
|
||||||
-- @treturn number The currently visible process's index.
|
-- @treturn number The currently visible process's index.
|
||||||
@ -235,7 +235,7 @@ end
|
|||||||
--
|
--
|
||||||
-- @tparam number n The process index to switch to.
|
-- @tparam number n The process index to switch to.
|
||||||
-- @treturn boolean If the process was changed successfully. This will
|
-- @treturn boolean If the process was changed successfully. This will
|
||||||
-- return @{false} if there is no process with this id.
|
-- return [`false`] if there is no process with this id.
|
||||||
-- @see getFocus
|
-- @see getFocus
|
||||||
function multishell.setFocus(n)
|
function multishell.setFocus(n)
|
||||||
expect(1, n, "number")
|
expect(1, n, "number")
|
||||||
@ -250,9 +250,9 @@ end
|
|||||||
--- Get the title of the given tab.
|
--- Get the title of the given tab.
|
||||||
--
|
--
|
||||||
-- This starts as the name of the program, but may be changed using
|
-- This starts as the name of the program, but may be changed using
|
||||||
-- @{multishell.setTitle}.
|
-- [`multishell.setTitle`].
|
||||||
-- @tparam number n The process index.
|
-- @tparam number n The process index.
|
||||||
-- @treturn string|nil The current process title, or @{nil} if the
|
-- @treturn string|nil The current process title, or [`nil`] if the
|
||||||
-- process doesn't exist.
|
-- process doesn't exist.
|
||||||
function multishell.getTitle(n)
|
function multishell.getTitle(n)
|
||||||
expect(1, n, "number")
|
expect(1, n, "number")
|
||||||
|
@ -275,6 +275,12 @@ local function drawCanvas()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function termResize()
|
||||||
|
w, h = term.getSize()
|
||||||
|
drawCanvas()
|
||||||
|
drawInterface()
|
||||||
|
end
|
||||||
|
|
||||||
local menu_choices = {
|
local menu_choices = {
|
||||||
Save = function()
|
Save = function()
|
||||||
if bReadOnly then
|
if bReadOnly then
|
||||||
@ -376,6 +382,8 @@ local function accessMenu()
|
|||||||
nMenuPosEnd = nMenuPosEnd + 1
|
nMenuPosEnd = nMenuPosEnd + 1
|
||||||
nMenuPosStart = nMenuPosEnd
|
nMenuPosStart = nMenuPosEnd
|
||||||
end
|
end
|
||||||
|
elseif id == "term_resize" then
|
||||||
|
termResize()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -434,9 +442,7 @@ local function handleEvents()
|
|||||||
drawInterface()
|
drawInterface()
|
||||||
end
|
end
|
||||||
elseif id == "term_resize" then
|
elseif id == "term_resize" then
|
||||||
w, h = term.getSize()
|
termResize()
|
||||||
drawCanvas()
|
|
||||||
drawInterface()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -56,14 +56,6 @@ local function get(url)
|
|||||||
)
|
)
|
||||||
|
|
||||||
if response then
|
if response then
|
||||||
-- If spam protection is activated, we get redirected to /paste with Content-Type: text/html
|
|
||||||
local headers = response.getResponseHeaders()
|
|
||||||
if not headers["Content-Type"] or not headers["Content-Type"]:find("^text/plain") then
|
|
||||||
io.stderr:write("Failed.\n")
|
|
||||||
print("Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode(paste))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
print("Success.")
|
print("Success.")
|
||||||
|
|
||||||
local sResponse = response.readAll()
|
local sResponse = response.readAll()
|
||||||
|
@ -36,13 +36,6 @@ local function getFilename(sUrl)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function get(sUrl)
|
local function get(sUrl)
|
||||||
-- Check if the URL is valid
|
|
||||||
local ok, err = http.checkURL(url)
|
|
||||||
if not ok then
|
|
||||||
printError(err or "Invalid URL.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
write("Connecting to " .. sUrl .. "... ")
|
write("Connecting to " .. sUrl .. "... ")
|
||||||
|
|
||||||
local response = http.get(sUrl , nil , true)
|
local response = http.get(sUrl , nil , true)
|
||||||
|
@ -25,21 +25,13 @@ local tEnv = {
|
|||||||
}
|
}
|
||||||
setmetatable(tEnv, { __index = _ENV })
|
setmetatable(tEnv, { __index = _ENV })
|
||||||
|
|
||||||
-- Replace our package.path, so that it loads from the current directory, rather
|
-- Replace our require with new instance that loads from the current directory
|
||||||
-- than from /rom/programs. This makes it a little more friendly to use and
|
-- rather than from /rom/programs. This makes it more friendly to use and closer
|
||||||
-- closer to what you'd expect.
|
-- to what you'd expect.
|
||||||
do
|
do
|
||||||
|
local make_package = require "cc.require".make
|
||||||
local dir = shell.dir()
|
local dir = shell.dir()
|
||||||
if dir:sub(1, 1) ~= "/" then dir = "/" .. dir end
|
_ENV.require, _ENV.package = make_package(_ENV, dir)
|
||||||
if dir:sub(-1) ~= "/" then dir = dir .. "/" end
|
|
||||||
|
|
||||||
local strip_path = "?;?.lua;?/init.lua;"
|
|
||||||
local path = package.path
|
|
||||||
if path:sub(1, #strip_path) == strip_path then
|
|
||||||
path = path:sub(#strip_path + 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
package.path = dir .. "?;" .. dir .. "?.lua;" .. dir .. "?/init.lua;" .. path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if term.isColour() then
|
if term.isColour() then
|
||||||
@ -82,18 +74,13 @@ while running do
|
|||||||
|
|
||||||
local name, offset = "=lua[" .. chunk_idx .. "]", 0
|
local name, offset = "=lua[" .. chunk_idx .. "]", 0
|
||||||
|
|
||||||
local force_print = 0
|
|
||||||
local func, err = load(input, name, "t", tEnv)
|
local func, err = load(input, name, "t", tEnv)
|
||||||
|
if load("return " .. input) then
|
||||||
local expr_func = load("return _echo(" .. input .. ");", name, "t", tEnv)
|
-- We wrap the expression with a call to _echo(...), which prevents tail
|
||||||
if not func then
|
-- calls (and thus confusing errors). Note we check this is a valid
|
||||||
if expr_func then
|
-- expression separately, to avoid accepting inputs like `)--` (which are
|
||||||
func = expr_func
|
-- parsed as `_echo()--)`.
|
||||||
offset = 13
|
func = load("return _echo(" .. input .. "\n)", name, "t", tEnv)
|
||||||
force_print = 1
|
|
||||||
end
|
|
||||||
elseif expr_func then
|
|
||||||
func = expr_func
|
|
||||||
offset = 13
|
offset = 13
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -103,9 +90,8 @@ while running do
|
|||||||
|
|
||||||
local results = table.pack(exception.try(func))
|
local results = table.pack(exception.try(func))
|
||||||
if results[1] then
|
if results[1] then
|
||||||
local n = 1
|
for i = 2, results.n do
|
||||||
while n < results.n or n <= force_print do
|
local value = results[i]
|
||||||
local value = results[n + 1]
|
|
||||||
local ok, serialised = pcall(pretty.pretty, value, {
|
local ok, serialised = pcall(pretty.pretty, value, {
|
||||||
function_args = settings.get("lua.function_args"),
|
function_args = settings.get("lua.function_args"),
|
||||||
function_source = settings.get("lua.function_source"),
|
function_source = settings.get("lua.function_source"),
|
||||||
@ -115,7 +101,6 @@ while running do
|
|||||||
else
|
else
|
||||||
print(tostring(value))
|
print(tostring(value))
|
||||||
end
|
end
|
||||||
n = n + 1
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
printError(results[2])
|
printError(results[2])
|
||||||
|
@ -4,29 +4,29 @@
|
|||||||
|
|
||||||
--[[- The shell API provides access to CraftOS's command line interface.
|
--[[- The shell API provides access to CraftOS's command line interface.
|
||||||
|
|
||||||
It allows you to @{run|start programs}, @{setCompletionFunction|add completion
|
It allows you to [start programs][`run`], [add completion for a
|
||||||
for a program}, and much more.
|
program][`setCompletionFunction`], and much more.
|
||||||
|
|
||||||
@{shell} is not a "true" API. Instead, it is a standard program, which injects
|
[`shell`] is not a "true" API. Instead, it is a standard program, which injects
|
||||||
its API into the programs that it launches. This allows for multiple shells to
|
its API into the programs that it launches. This allows for multiple shells to
|
||||||
run at the same time, but means that the API is not available in the global
|
run at the same time, but means that the API is not available in the global
|
||||||
environment, and so is unavailable to other @{os.loadAPI|APIs}.
|
environment, and so is unavailable to other [APIs][`os.loadAPI`].
|
||||||
|
|
||||||
## Programs and the program path
|
## Programs and the program path
|
||||||
When you run a command with the shell, either from the prompt or
|
When you run a command with the shell, either from the prompt or
|
||||||
@{shell.run|from Lua code}, the shell API performs several steps to work out
|
[from Lua code][`shell.run`], the shell API performs several steps to work out
|
||||||
which program to run:
|
which program to run:
|
||||||
|
|
||||||
1. Firstly, the shell attempts to resolve @{shell.aliases|aliases}. This allows
|
1. Firstly, the shell attempts to resolve [aliases][`shell.aliases`]. This allows
|
||||||
us to use multiple names for a single command. For example, the `list`
|
us to use multiple names for a single command. For example, the `list`
|
||||||
program has two aliases: `ls` and `dir`. When you write `ls /rom`, that's
|
program has two aliases: `ls` and `dir`. When you write `ls /rom`, that's
|
||||||
expanded to `list /rom`.
|
expanded to `list /rom`.
|
||||||
|
|
||||||
2. Next, the shell attempts to find where the program actually is. For this, it
|
2. Next, the shell attempts to find where the program actually is. For this, it
|
||||||
uses the @{shell.path|program path}. This is a colon separated list of
|
uses the [program path][`shell.path`]. This is a colon separated list of
|
||||||
directories, each of which is checked to see if it contains the program.
|
directories, each of which is checked to see if it contains the program.
|
||||||
|
|
||||||
`list` or `list.lua` doesn't exist in `.` (the current directory), so she
|
`list` or `list.lua` doesn't exist in `.` (the current directory), so the
|
||||||
shell now looks in `/rom/programs`, where `list.lua` can be found!
|
shell now looks in `/rom/programs`, where `list.lua` can be found!
|
||||||
|
|
||||||
3. Finally, the shell reads the file and checks if the file starts with a
|
3. Finally, the shell reads the file and checks if the file starts with a
|
||||||
@ -192,7 +192,7 @@ end
|
|||||||
|
|
||||||
--- Run a program with the supplied arguments.
|
--- Run a program with the supplied arguments.
|
||||||
--
|
--
|
||||||
-- Unlike @{shell.run}, each argument is passed to the program verbatim. While
|
-- Unlike [`shell.run`], each argument is passed to the program verbatim. While
|
||||||
-- `shell.run("echo", "b c")` runs `echo` with `b` and `c`,
|
-- `shell.run("echo", "b c")` runs `echo` with `b` and `c`,
|
||||||
-- `shell.execute("echo", "b c")` runs `echo` with a single argument `b c`.
|
-- `shell.execute("echo", "b c")` runs `echo` with a single argument `b c`.
|
||||||
--
|
--
|
||||||
@ -276,7 +276,7 @@ function shell.exit()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Return the current working directory. This is what is displayed before the
|
--- Return the current working directory. This is what is displayed before the
|
||||||
-- `> ` of the shell prompt, and is used by @{shell.resolve} to handle relative
|
-- `> ` of the shell prompt, and is used by [`shell.resolve`] to handle relative
|
||||||
-- paths.
|
-- paths.
|
||||||
--
|
--
|
||||||
-- @treturn string The current working directory.
|
-- @treturn string The current working directory.
|
||||||
@ -313,10 +313,10 @@ function shell.path()
|
|||||||
return sPath
|
return sPath
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the @{path|current program path}.
|
--- Set the [current program path][`path`].
|
||||||
--
|
--
|
||||||
-- Be careful to prefix directories with a `/`. Otherwise they will be searched
|
-- Be careful to prefix directories with a `/`. Otherwise they will be searched
|
||||||
-- for from the @{shell.dir|current directory}, rather than the computer's root.
|
-- for from the [current directory][`shell.dir`], rather than the computer's root.
|
||||||
--
|
--
|
||||||
-- @tparam string path The new program path.
|
-- @tparam string path The new program path.
|
||||||
-- @since 1.2
|
-- @since 1.2
|
||||||
@ -327,8 +327,8 @@ end
|
|||||||
|
|
||||||
--- Resolve a relative path to an absolute path.
|
--- Resolve a relative path to an absolute path.
|
||||||
--
|
--
|
||||||
-- The @{fs} and @{io} APIs work using absolute paths, and so we must convert
|
-- The [`fs`] and [`io`] APIs work using absolute paths, and so we must convert
|
||||||
-- any paths relative to the @{dir|current directory} to absolute ones. This
|
-- any paths relative to the [current directory][`dir`] to absolute ones. This
|
||||||
-- does nothing when the path starts with `/`.
|
-- does nothing when the path starts with `/`.
|
||||||
--
|
--
|
||||||
-- @tparam string path The path to resolve.
|
-- @tparam string path The path to resolve.
|
||||||
@ -357,10 +357,10 @@ local function pathWithExtension(_sPath, _sExt)
|
|||||||
return _sPath .. "." .. _sExt
|
return _sPath .. "." .. _sExt
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Resolve a program, using the @{path|program path} and list of @{aliases|aliases}.
|
--- Resolve a program, using the [program path][`path`] and list of [aliases][`aliases`].
|
||||||
--
|
--
|
||||||
-- @tparam string command The name of the program
|
-- @tparam string command The name of the program
|
||||||
-- @treturn string|nil The absolute path to the program, or @{nil} if it could
|
-- @treturn string|nil The absolute path to the program, or [`nil`] if it could
|
||||||
-- not be found.
|
-- not be found.
|
||||||
-- @since 1.2
|
-- @since 1.2
|
||||||
-- @changed 1.80pr1 Now searches for files with and without the `.lua` extension.
|
-- @changed 1.80pr1 Now searches for files with and without the `.lua` extension.
|
||||||
@ -406,7 +406,7 @@ function shell.resolveProgram(command)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a list of all programs on the @{shell.path|path}.
|
--- Return a list of all programs on the [path][`shell.path`].
|
||||||
--
|
--
|
||||||
-- @tparam[opt] boolean include_hidden Include hidden files. Namely, any which
|
-- @tparam[opt] boolean include_hidden Include hidden files. Namely, any which
|
||||||
-- start with `.`.
|
-- start with `.`.
|
||||||
@ -518,7 +518,7 @@ end
|
|||||||
-- completed to `ls rom/`.
|
-- completed to `ls rom/`.
|
||||||
--
|
--
|
||||||
-- Completion handlers for your program may be registered with
|
-- Completion handlers for your program may be registered with
|
||||||
-- @{shell.setCompletionFunction}.
|
-- [`shell.setCompletionFunction`].
|
||||||
--
|
--
|
||||||
-- @tparam string sLine The input to complete.
|
-- @tparam string sLine The input to complete.
|
||||||
-- @treturn { string }|nil The list of possible completions.
|
-- @treturn { string }|nil The list of possible completions.
|
||||||
@ -614,7 +614,7 @@ end
|
|||||||
--- Get a table containing all completion functions.
|
--- Get a table containing all completion functions.
|
||||||
--
|
--
|
||||||
-- This should only be needed when building custom shells. Use
|
-- This should only be needed when building custom shells. Use
|
||||||
-- @{setCompletionFunction} to add a completion function.
|
-- [`setCompletionFunction`] to add a completion function.
|
||||||
--
|
--
|
||||||
-- @treturn { [string] = { fnComplete = function } } A table mapping the
|
-- @treturn { [string] = { fnComplete = function } } A table mapping the
|
||||||
-- absolute path of programs, to their completion functions.
|
-- absolute path of programs, to their completion functions.
|
||||||
@ -676,12 +676,12 @@ function shell.aliases()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if multishell then
|
if multishell then
|
||||||
--- Open a new @{multishell} tab running a command.
|
--- Open a new [`multishell`] tab running a command.
|
||||||
--
|
--
|
||||||
-- This behaves similarly to @{shell.run}, but instead returns the process
|
-- This behaves similarly to [`shell.run`], but instead returns the process
|
||||||
-- index.
|
-- index.
|
||||||
--
|
--
|
||||||
-- This function is only available if the @{multishell} API is.
|
-- This function is only available if the [`multishell`] API is.
|
||||||
--
|
--
|
||||||
-- @tparam string ... The command line to run.
|
-- @tparam string ... The command line to run.
|
||||||
-- @see shell.run
|
-- @see shell.run
|
||||||
@ -706,7 +706,7 @@ if multishell then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Switch to the @{multishell} tab with the given index.
|
--- Switch to the [`multishell`] tab with the given index.
|
||||||
--
|
--
|
||||||
-- @tparam number id The tab to switch to.
|
-- @tparam number id The tab to switch to.
|
||||||
-- @see multishell.setFocus
|
-- @see multishell.setFocus
|
||||||
|
2
vendor/Cobalt
vendored
2
vendor/Cobalt
vendored
@ -1 +1 @@
|
|||||||
Subproject commit a630403859ff6321d10292fbf94dcfb30b507d9d
|
Subproject commit 6b0d2e234ebbfb1ffd20cde071ecd4c782be6da1
|
Loading…
x
Reference in New Issue
Block a user