diff --git a/doc/events/alarm.md b/doc/events/alarm.md new file mode 100644 index 000000000..db7f04845 --- /dev/null +++ b/doc/events/alarm.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] alarm +see: os.setAlarm To start an alarm. +--- + +The @{timer} event is fired when an alarm started with @{os.setAlarm} completes. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the alarm that finished. + +## Example +Starts a timer and then prints its ID: +```lua +local alarmID = os.setAlarm(os.time() + 0.05) +local event, id +repeat + event, id = os.pullEvent("alarm") +until id == alarmID +print("Alarm with ID " .. id .. " was fired") +``` diff --git a/doc/events/char.md b/doc/events/char.md new file mode 100644 index 000000000..473313702 --- /dev/null +++ b/doc/events/char.md @@ -0,0 +1,24 @@ +--- +module: [kind=event] char +see: key To listen to any key press. +--- + +The @{char} event is fired when a character is _typed_ on the keyboard. + +The @{char} event is different to a key press. Sometimes multiple key presses may result in one character being +typed (for instance, on some European keyboards). Similarly, some keys (e.g. Ctrl) do not have any +corresponding character. The @{key} should be used if you want to listen to key presses themselves. + +## Return values +1. @{string}: The event name. +2. @{string}: The string representing the character that was pressed. + + +## Example +Prints each character the user presses: +```lua +while true do + local event, character = os.pullEvent("char") + print(character .. " was pressed.") +end +``` diff --git a/doc/events/computer_command.md b/doc/events/computer_command.md new file mode 100644 index 000000000..245252399 --- /dev/null +++ b/doc/events/computer_command.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] computer_command +--- + +The @{computer_command} event is fired when the `/computercraft queue` command is run for the current computer. + +## Return Values +1. @{string}: The event name. +... @{string}: The arguments passed to the command. + +## Example +Prints the contents of messages sent: +```lua +while true do + local event = {os.pullEvent("computer_command")} + print("Received message:", table.unpack(event, 2)) +end +``` diff --git a/doc/events/disk.md b/doc/events/disk.md new file mode 100644 index 000000000..2946d70c4 --- /dev/null +++ b/doc/events/disk.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] disk +see: disk_eject For the event sent when a disk is removed. +--- + +The @{disk} event is fired when a disk is inserted into an adjacent or networked disk drive. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the disk drive that had a disk inserted. + +## Example +Prints a message when a disk is inserted: +```lua +while true do + local event, side = os.pullEvent("disk") + print("Inserted a disk on side " .. side) +end +``` diff --git a/doc/events/disk_eject.md b/doc/events/disk_eject.md new file mode 100644 index 000000000..71c3ede0a --- /dev/null +++ b/doc/events/disk_eject.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] disk_eject +see: disk For the event sent when a disk is inserted. +--- + +The @{disk_eject} event is fired when a disk is removed from an adjacent or networked disk drive. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the disk drive that had a disk removed. + +## Example +Prints a message when a disk is removed: +```lua +while true do + local event, side = os.pullEvent("disk_eject") + print("Removed a disk on side " .. side) +end +``` diff --git a/doc/events/http_check.md b/doc/events/http_check.md new file mode 100644 index 000000000..9af5ea7ca --- /dev/null +++ b/doc/events/http_check.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] http_check +see: http.checkURLAsync To check a URL asynchronously. +--- + +The @{http_check} event is fired when a URL check finishes. + +This event is normally handled inside @{http.checkURL}, but it can still be seen when using @{http.checkURLAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL requested to be checked. +3. @{boolean}: Whether the check succeeded. +4. @{string|nil}: If the check failed, a reason explaining why the check failed. diff --git a/doc/events/http_failure.md b/doc/events/http_failure.md new file mode 100644 index 000000000..dc10b40d7 --- /dev/null +++ b/doc/events/http_failure.md @@ -0,0 +1,39 @@ +--- +module: [kind=event] http_failure +see: http.request To send an HTTP request. +--- + +The @{http_failure} event is fired when an HTTP request fails. + +This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{string}: An error describing the failure. +4. @{http.Response|nil}: A response handle if the connection succeeded, but the server's response indicated failure. + +## Example +Prints an error why the website cannot be contacted: +```lua +local myURL = "https://does.not.exist.tweaked.cc" +http.request(myURL) +local event, url, err +repeat + event, url, err = os.pullEvent("http_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +``` + +Prints the contents of a webpage that does not exist: +```lua +local myURL = "https://tweaked.cc/this/does/not/exist" +http.request(myURL) +local event, url, err, handle +repeat + event, url, err, handle = os.pullEvent("http_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +print(handle.getResponseCode()) +handle.close() +``` diff --git a/doc/events/http_success.md b/doc/events/http_success.md new file mode 100644 index 000000000..3700b9211 --- /dev/null +++ b/doc/events/http_success.md @@ -0,0 +1,27 @@ +--- +module: [kind=event] http_success +see: http.request To make an HTTP request. +--- + +The @{http_success} event is fired when an HTTP request returns successfully. + +This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{http.Response}: The handle for the response text. + +## Example +Prints the content of a website (this may fail if the request fails): +```lua +local myURL = "https://tweaked.cc/" +http.request(myURL) +local event, url, handle +repeat + event, url, handle = os.pullEvent("http_success") +until url == myURL +print("Contents of " .. url .. ":") +print(handle.readAll()) +handle.close() +``` diff --git a/doc/events/key.md b/doc/events/key.md new file mode 100644 index 000000000..1f11e443b --- /dev/null +++ b/doc/events/key.md @@ -0,0 +1,26 @@ +--- +module: [kind=event] key +--- + +This event is fired when any key is pressed while the terminal is focused. + +This event returns a numerical "key code" (for instance, F1 is 290). This value may vary between versions and +so it is recommended to use the constants in the @{keys} API rather than hard coding numeric values. + +If the button pressed represented a printable character, then the @{key} event will be followed immediately by a @{char} +event. If you are consuming text input, use a @{char} event instead! + +## Return values +1. @{string}: The event name. +2. @{number}: The numerical key value of the key pressed. +3. @{boolean}: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}). + +## Example +Prints each key when the user presses it, and if the key is being held. + +```lua +while true do + local event, key, is_held = os.pullEvent("key") + print(("%s held=%s"):format(keys.getName(key), is_held)) +end +``` diff --git a/doc/events/key_up.md b/doc/events/key_up.md new file mode 100644 index 000000000..e957cae6b --- /dev/null +++ b/doc/events/key_up.md @@ -0,0 +1,24 @@ +--- +module: [kind=event] key_up +see: keys For a lookup table of the given keys. +--- + +Fired whenever a key is released (or the terminal is closed while a key was being pressed). + +This event returns a numerical "key code" (for instance, F1 is 290). This value may vary between versions and +so it is recommended to use the constants in the @{keys} API rather than hard coding numeric values. + +## Return values +1. @{string}: The event name. +2. @{number}: The numerical key value of the key pressed. + +## Example +Prints each key released on the keyboard whenever a @{key_up} event is fired. + +```lua +while true do + local event, key = os.pullEvent("key_up") + local name = keys.getName(key) or "unknown key" + print(name .. " was released.") +end +``` diff --git a/doc/events/modem_message.md b/doc/events/modem_message.md new file mode 100644 index 000000000..c7480d7fb --- /dev/null +++ b/doc/events/modem_message.md @@ -0,0 +1,26 @@ +--- +module: [kind=event] modem_message +--- + +The @{modem_message} event is fired when a message is received on an open channel on any @{modem}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the modem that received the message. +3. @{number}: The channel that the message was sent on. +4. @{number}: The reply channel set by the sender. +5. @{any}: The message as sent by the sender. +6. @{number}: The distance between the sender and the receiver, in blocks. + +## Example +Wraps a @{modem} peripheral, opens channel 0 for listening, and prints all received messages. + +```lua +local modem = peripheral.find("modem") or error("No modem attached", 0) +modem.open(0) + +while true do + local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message") + print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message))) +end +``` diff --git a/doc/events/monitor_resize.md b/doc/events/monitor_resize.md new file mode 100644 index 000000000..03de804e7 --- /dev/null +++ b/doc/events/monitor_resize.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] monitor_resize +--- + +The @{monitor_resize} event is fired when an adjacent or networked monitor's size is changed. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side or network ID of the monitor that resized. + +## Example +Prints a message when a monitor is resized: +```lua +while true do + local event, side = os.pullEvent("monitor_resize") + print("The monitor on side " .. side .. " was resized.") +end +``` diff --git a/doc/events/monitor_touch.md b/doc/events/monitor_touch.md new file mode 100644 index 000000000..0f27a9cc1 --- /dev/null +++ b/doc/events/monitor_touch.md @@ -0,0 +1,20 @@ +--- +module: [kind=event] monitor_touch +--- + +The @{monitor_touch} event is fired when an adjacent or networked Advanced Monitor is right-clicked. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side or network ID of the monitor that was touched. +3. @{number}: The X coordinate of the touch, in characters. +4. @{number}: The Y coordinate of the touch, in characters. + +## Example +Prints a message when a monitor is touched: +```lua +while true do + local event, side, x, y = os.pullEvent("monitor_touch") + print("The monitor on side " .. side .. " was touched at (" .. x .. ", " .. y .. ")") +end +``` diff --git a/doc/events/mouse_click.md b/doc/events/mouse_click.md new file mode 100644 index 000000000..83d371260 --- /dev/null +++ b/doc/events/mouse_click.md @@ -0,0 +1,34 @@ +--- +module: [kind=event] mouse_click +--- + +This event is fired when the terminal is clicked with a mouse. This event is only fired on advanced computers (including +advanced turtles and pocket computers). + +## Return values +1. @{string}: The event name. +2. @{number}: The mouse button that was clicked. +3. @{number}: The X-coordinate of the click. +4. @{number}: The Y-coordinate of the click. + +## Mouse buttons +Several mouse events (@{mouse_click}, @{mouse_up}, @{mouse_scroll}) contain a "mouse button" code. This takes a +numerical value depending on which button on your mouse was last pressed when this event occurred. + + + + + + + +
Button codeMouse button
1Left button
2Middle button
3Right button
+ +## Example +Print the button and the coordinates whenever the mouse is clicked. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_click") + print(("The mouse button %s was pressed at %d, %d"):format(button, x, y)) +end +``` diff --git a/doc/events/mouse_drag.md b/doc/events/mouse_drag.md new file mode 100644 index 000000000..15451c9f8 --- /dev/null +++ b/doc/events/mouse_drag.md @@ -0,0 +1,22 @@ +--- +module: [kind=event] mouse_drag +see: mouse_click For when a mouse button is initially pressed. +--- + +This event is fired every time the mouse is moved while a mouse button is being held. + +## Return values +1. @{string}: The event name. +2. @{number}: The [mouse button](mouse_click.html#Mouse_buttons) that is being pressed. +3. @{number}: The X-coordinate of the mouse. +4. @{number}: The Y-coordinate of the mouse. + +## Example +Print the button and the coordinates whenever the mouse is dragged. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_drag") + print(("The mouse button %s was dragged at %d, %d"):format(button, x, y)) +end +``` diff --git a/doc/events/mouse_scroll.md b/doc/events/mouse_scroll.md new file mode 100644 index 000000000..6248220a5 --- /dev/null +++ b/doc/events/mouse_scroll.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] mouse_scroll +--- + +This event is fired when a mouse wheel is scrolled in the terminal. + +## Return values +1. @{string}: The event name. +2. @{number}: The direction of the scroll. (-1 = up, 1 = down) +3. @{number}: The X-coordinate of the mouse when scrolling. +4. @{number}: The Y-coordinate of the mouse when scrolling. + +## Example +Prints the direction of each scroll, and the position of the mouse at the time. + +```lua +while true do + local event, dir, x, y = os.pullEvent("mouse_scroll") + print(("The mouse was scrolled in direction %s at %d, %d"):format(dir, x, y)) +end +``` diff --git a/doc/events/mouse_up.md b/doc/events/mouse_up.md new file mode 100644 index 000000000..886330a6d --- /dev/null +++ b/doc/events/mouse_up.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] mouse_up +--- + +This event is fired when a mouse button is released or a held mouse leaves the computer's terminal. + +## Return values +1. @{string}: The event name. +2. @{number}: The [mouse button](mouse_click.html#Mouse_buttons) that was released. +3. @{number}: The X-coordinate of the mouse. +4. @{number}: The Y-coordinate of the mouse. + +## Example +Prints the coordinates and button number whenever the mouse is released. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_up") + print(("The mouse button %s was released at %d, %d"):format(button, x, y)) +end +``` diff --git a/doc/events/paste.md b/doc/events/paste.md new file mode 100644 index 000000000..b4f8713c5 --- /dev/null +++ b/doc/events/paste.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] paste +--- + +The @{paste} event is fired when text is pasted into the computer through Ctrl-V (or ⌘V on Mac). + +## Return values +1. @{string}: The event name. +2. @{string} The text that was pasted. + +## Example +Prints pasted text: +```lua +while true do + local event, text = os.pullEvent("paste") + print('"' .. text .. '" was pasted') +end +``` diff --git a/doc/events/peripheral.md b/doc/events/peripheral.md new file mode 100644 index 000000000..5769f3942 --- /dev/null +++ b/doc/events/peripheral.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] peripheral +see: peripheral_detach For the event fired when a peripheral is detached. +--- + +The @{peripheral} event is fired when a peripheral is attached on a side or to a modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side the peripheral was attached to. + +## Example +Prints a message when a peripheral is attached: +```lua +while true do + local event, side = os.pullEvent("peripheral") + print("A peripheral was attached on side " .. side) +end +``` diff --git a/doc/events/peripheral_detach.md b/doc/events/peripheral_detach.md new file mode 100644 index 000000000..c8a462cf0 --- /dev/null +++ b/doc/events/peripheral_detach.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] peripheral_detach +see: peripheral For the event fired when a peripheral is attached. +--- + +The @{peripheral_detach} event is fired when a peripheral is detached from a side or from a modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side the peripheral was detached from. + +## Example +Prints a message when a peripheral is detached: +```lua +while true do + local event, side = os.pullEvent("peripheral_detach") + print("A peripheral was detached on side " .. side) +end +``` diff --git a/doc/events/rednet_message.md b/doc/events/rednet_message.md new file mode 100644 index 000000000..8d0bdf697 --- /dev/null +++ b/doc/events/rednet_message.md @@ -0,0 +1,30 @@ +--- +module: [kind=event] rednet_message +see: modem_message For raw modem messages sent outside of Rednet. +see: rednet.receive To wait for a Rednet message with an optional timeout and protocol filter. +--- + +The @{rednet_message} event is fired when a message is sent over Rednet. + +This event is usually handled by @{rednet.receive}, but it can also be pulled manually. + +@{rednet_message} events are sent by @{rednet.run} in the top-level coroutine in response to @{modem_message} events. A @{rednet_message} event is always preceded by a @{modem_message} event. They are generated inside CraftOS rather than being sent by the ComputerCraft machine. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the sending computer. +3. @{any}: The message sent. +4. @{string|nil}: The protocol of the message, if provided. + +## Example +Prints a message when one is sent: +```lua +while true do + local event, sender, message, protocol = os.pullEvent("rednet_message") + if protocol ~= nil then + print("Received message from " .. sender .. " with protocol " .. protocol .. " and message " .. tostring(message)) + else + print("Received message from " .. sender .. " with message " .. tostring(message)) + end +end +``` diff --git a/doc/events/redstone.md b/doc/events/redstone.md new file mode 100644 index 000000000..0c199ee5d --- /dev/null +++ b/doc/events/redstone.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] redstone +--- + +The @{event!redstone} event is fired whenever any redstone inputs on the computer change. + +## Example +Prints a message when a redstone input changes: +```lua +while true do + os.pullEvent("redstone") + print("A redstone input has changed!") +end +``` diff --git a/doc/events/speaker_audio_empty.md b/doc/events/speaker_audio_empty.md new file mode 100644 index 000000000..75a371f26 --- /dev/null +++ b/doc/events/speaker_audio_empty.md @@ -0,0 +1,27 @@ +--- +module: [kind=event] speaker_audio_empty +see: speaker.playAudio To play audio using the speaker +--- + +## Return Values +1. @{string}: The event name. +2. @{string}: The name of the speaker which is available to play more audio. + + +## Example +This uses @{io.lines} to read audio data in blocks of 16KiB from "example_song.dfpwm", and then attempts to play it +using @{speaker.playAudio}. If the speaker's buffer is full, it waits for an event and tries again. + +```lua {data-peripheral=speaker} +local dfpwm = require("cc.audio.dfpwm") +local speaker = peripheral.find("speaker") + +local decoder = dfpwm.make_decoder() +for chunk in io.lines("data/example.dfpwm", 16 * 1024) do + local buffer = decoder(chunk) + + while not speaker.playAudio(buffer) do + os.pullEvent("speaker_audio_empty") + end +end +``` diff --git a/doc/events/task_complete.md b/doc/events/task_complete.md new file mode 100644 index 000000000..eddec51d2 --- /dev/null +++ b/doc/events/task_complete.md @@ -0,0 +1,28 @@ +--- +module: [kind=event] task_complete +see: commands.execAsync To run a command which fires a task_complete event. +--- + +The @{task_complete} event is fired when an asynchronous task completes. This is usually handled inside the function call that queued the task; however, functions such as @{commands.execAsync} return immediately so the user can wait for completion. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the task that completed. +3. @{boolean}: Whether the command succeeded. +4. @{string}: If the command failed, an error message explaining the failure. (This is not present if the command succeeded.) +...: Any parameters returned from the command. + +## Example +Prints the results of an asynchronous command: +```lua +local taskID = commands.execAsync("say Hello") +local event +repeat + event = {os.pullEvent("task_complete")} +until event[2] == taskID +if event[3] == true then + print("Task " .. event[2] .. " succeeded:", table.unpack(event, 4)) +else + print("Task " .. event[2] .. " failed: " .. event[4]) +end +``` diff --git a/doc/events/term_resize.md b/doc/events/term_resize.md new file mode 100644 index 000000000..462056365 --- /dev/null +++ b/doc/events/term_resize.md @@ -0,0 +1,20 @@ +--- +module: [kind=event] term_resize +--- + +The @{term_resize} event is fired when the main terminal is resized. For instance: + - When a the tab bar is shown or hidden in @{multishell}. + - When the terminal is redirected to a monitor via the "monitor" program and the monitor is resized. + +When this event fires, some parts of the terminal may have been moved or deleted. Simple terminal programs (those +not using @{term.setCursorPos}) can ignore this event, but more complex GUI programs should redraw the entire screen. + +## Example +Prints : +```lua +while true do + os.pullEvent("term_resize") + local w, h = term.getSize() + print("The term was resized to (" .. w .. ", " .. h .. ")") +end +``` diff --git a/doc/events/terminate.md b/doc/events/terminate.md new file mode 100644 index 000000000..0760b8c3b --- /dev/null +++ b/doc/events/terminate.md @@ -0,0 +1,25 @@ +--- +module: [kind=event] terminate +--- + +The @{terminate} event is fired when Ctrl-T is held down. + +This event is normally handled by @{os.pullEvent}, and will not be returned. However, @{os.pullEventRaw} will return this event when fired. + +@{terminate} will be sent even when a filter is provided to @{os.pullEventRaw}. When using @{os.pullEventRaw} with a filter, make sure to check that the event is not @{terminate}. + +## Example +Prints a message when Ctrl-T is held: +```lua +while true do + local event = os.pullEventRaw("terminate") + if event == "terminate" then print("Terminate requested!") end +end +``` + +Exits when Ctrl-T is held: +```lua +while true do + os.pullEvent() +end +``` diff --git a/doc/events/timer.md b/doc/events/timer.md new file mode 100644 index 000000000..c359c37b4 --- /dev/null +++ b/doc/events/timer.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] timer +see: os.startTimer To start a timer. +--- + +The @{timer} event is fired when a timer started with @{os.startTimer} completes. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the timer that finished. + +## Example +Starts a timer and then prints its ID: +```lua +local timerID = os.startTimer(2) +local event, id +repeat + event, id = os.pullEvent("timer") +until id == timerID +print("Timer with ID " .. id .. " was fired") +``` diff --git a/doc/events/turtle_inventory.md b/doc/events/turtle_inventory.md new file mode 100644 index 000000000..bc9392b6b --- /dev/null +++ b/doc/events/turtle_inventory.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] turtle_inventory +--- + +The @{turtle_inventory} event is fired when a turtle's inventory is changed. + +## Example +Prints a message when the inventory is changed: +```lua +while true do + os.pullEvent("turtle_inventory") + print("The inventory was changed.") +end +``` diff --git a/doc/events/websocket_closed.md b/doc/events/websocket_closed.md new file mode 100644 index 000000000..9e3783d19 --- /dev/null +++ b/doc/events/websocket_closed.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] websocket_closed +--- + +The @{websocket_closed} event is fired when an open WebSocket connection is closed. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the WebSocket that was closed. + +## Example +Prints a message when a WebSocket is closed (this may take a minute): +```lua +local myURL = "wss://example.tweaked.cc/echo" +local ws = http.websocket(myURL) +local event, url +repeat + event, url = os.pullEvent("websocket_closed") +until url == myURL +print("The WebSocket at " .. url .. " was closed.") +``` diff --git a/doc/events/websocket_failure.md b/doc/events/websocket_failure.md new file mode 100644 index 000000000..eef34e777 --- /dev/null +++ b/doc/events/websocket_failure.md @@ -0,0 +1,25 @@ +--- +module: [kind=event] websocket_failure +see: http.websocketAsync To send an HTTP request. +--- + +The @{websocket_failure} event is fired when a WebSocket connection request fails. + +This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{string}: An error describing the failure. + +## Example +Prints an error why the website cannot be contacted: +```lua +local myURL = "wss://example.tweaked.cc/not-a-websocket" +http.websocketAsync(myURL) +local event, url, err +repeat + event, url, err = os.pullEvent("websocket_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +``` diff --git a/doc/events/websocket_message.md b/doc/events/websocket_message.md new file mode 100644 index 000000000..839e214cc --- /dev/null +++ b/doc/events/websocket_message.md @@ -0,0 +1,27 @@ +--- +module: [kind=event] websocket_message +--- + +The @{websocket_message} event is fired when a message is received on an open WebSocket connection. + +This event is normally handled by @{http.Websocket.receive}, but it can also be pulled manually. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the WebSocket. +3. @{string}: The contents of the message. +4. @{boolean}: Whether this is a binary message. + +## Example +Prints a message sent by a WebSocket: +```lua +local myURL = "wss://example.tweaked.cc/echo" +local ws = http.websocket(myURL) +ws.send("Hello!") +local event, url, message +repeat + event, url, message = os.pullEvent("websocket_message") +until url == myURL +print("Received message from " .. url .. " with contents " .. message) +ws.close() +``` diff --git a/doc/events/websocket_success.md b/doc/events/websocket_success.md new file mode 100644 index 000000000..dcde934b3 --- /dev/null +++ b/doc/events/websocket_success.md @@ -0,0 +1,28 @@ +--- +module: [kind=event] websocket_success +see: http.websocketAsync To open a WebSocket asynchronously. +--- + +The @{websocket_success} event is fired when a WebSocket connection request returns successfully. + +This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site. +3. @{http.Websocket}: The handle for the WebSocket. + +## Example +Prints the content of a website (this may fail if the request fails): +```lua +local myURL = "wss://example.tweaked.cc/echo" +http.websocketAsync(myURL) +local event, url, handle +repeat + event, url, handle = os.pullEvent("websocket_success") +until url == myURL +print("Connected to " .. url) +handle.send("Hello!") +print(handle.receive()) +handle.close() +``` diff --git a/doc/guides/speaker_audio.md b/doc/guides/speaker_audio.md new file mode 100644 index 000000000..c1baf3479 --- /dev/null +++ b/doc/guides/speaker_audio.md @@ -0,0 +1,200 @@ +--- +module: [kind=guide] speaker_audio +see: speaker.playAudio Play PCM audio using a speaker. +see: cc.audio.dfpwm Provides utilities for encoding and decoding DFPWM files. +--- + +# Playing audio with speakers +CC: Tweaked's speaker peripheral provides a powerful way to play any audio you like with the @{speaker.playAudio} +method. However, for people unfamiliar with digital audio, it's not the most intuitive thing to use. This guide provides +an introduction to digital audio, demonstrates how to play music with CC: Tweaked's speakers, and then briefly discusses +the more complex topic of audio processing. + +## A short introduction to digital audio +When sound is recorded it is captured as an analogue signal, effectively the electrical version of a sound +wave. However, this signal is continuous, and so can't be used directly by a computer. Instead, we measure (or *sample*) +the amplitude of the wave many times a second and then *quantise* that amplitude, rounding it to the nearest +representable value. + +This representation of sound - a long, uniformally sampled list of amplitudes is referred to as [Pulse-code +Modulation][PCM] (PCM). PCM can be thought of as the "standard" audio format, as it's incredibly easy to work with. For +instance, to mix two pieces of audio together, you can just samples from the two tracks together and take the average. + +CC: Tweaked's speakers also work with PCM audio. It plays back 48,000 samples a second, where each sample is an integer +between -128 and 127. This is more commonly referred to as 48kHz and an 8-bit resolution. + +Let's now look at a quick example. We're going to generate a [Sine Wave] at 220Hz, which sounds like a low monotonous +hum. First we wrap our speaker peripheral, and then we fill a table (also referred to as a *buffer*) with 128×1024 +samples - this is the maximum number of samples a speaker can accept in one go. + +In order to fill this buffer, we need to do a little maths. We want to play 220 sine waves each second, where each sine +wave completes a full oscillation in 2π "units". This means one seconds worth of audio is 2×π×220 "units" long. We then +need to split this into 48k samples, basically meaning for each sample we move 2×π×220/48k "along" the sine curve. + +```lua {data-peripheral=speaker} +local speaker = peripheral.find("speaker") + +local buffer = {} +local t, dt = 0, 2 * math.pi * 220 / 48000 +for i = 1, 128 * 1024 do + buffer[i] = math.floor(math.sin(t) * 127) + t = (t + dt) % (math.pi * 2) +end + +speaker.playAudio(buffer) +``` + +## Streaming audio +You might notice that the above snippet only generates a short bit of audio - 2.7s seconds to be precise. While we could +try increasing the number of loop iterations, we'll get an error when we try to play it through the speaker: the sound +buffer is too large for it to handle. + +Our 2.7 seconds of audio is stored in a table with over 130 _thousand_ elements. If we wanted to play a full minute of +sine waves (and why wouldn't you?), you'd need a table with almost 3 _million_. Suddenly you find these numbers adding +up very quickly, and these tables take up more and more memory. + +Instead of building our entire song (well, sine wave) in one go, we can produce it in small batches, each of which get +passed off to @{speaker.playAudio} when the time is right. This allows us to build a _stream_ of audio, where we read +chunks of audio one at a time (either from a file or a tone generator like above), do some optional processing to each +one, and then play them. + +Let's adapt our example from above to do that instead. + +```lua {data-peripheral=speaker} +local speaker = peripheral.find("speaker") + +local t, dt = 0, 2 * math.pi * 220 / 48000 +while true do + local buffer = {} + for i = 1, 16 * 1024 * 8 do + buffer[i] = math.floor(math.sin(t) * 127) + t = (t + dt) % (math.pi * 2) + end + + while not speaker.playAudio(buffer) do + os.pullEvent("speaker_audio_empty") + end +end +``` + +It looks pretty similar to before, aside from we've wrapped the generation and playing code in a while loop, and added a +rather odd loop with @{speaker.playAudio} and @{os.pullEvent}. + +Let's talk about this loop, why do we need to keep calling @{speaker.playAudio}? Remember that what we're trying to do +here is avoid keeping too much audio in memory at once. However, if we're generating audio quicker than the speakers can +play it, we're not helping at all - all this audio is still hanging around waiting to be played! + +In order to avoid this, the speaker rejects any new chunks of audio if its backlog is too large. When this happens, +@{speaker.playAudio} returns false. Once enough audio has played, and the backlog has been reduced, a +@{speaker_audio_empty} event is queued, and we can try to play our chunk once more. + +## Storing audio +PCM is a fantastic way of representing audio when we want to manipulate it, but it's not very efficient when we want to +store it to disk. Compare the size of a WAV file (which uses PCM) to an equivalent MP3, it's often 5 times the size. +Instead, we store audio in special formats (or *codecs*) and then convert them to PCM when we need to do processing on +them. + +Modern audio codecs use some incredibly impressive techniques to compress the audio as much as possible while preserving +sound quality. However, due to CC: Tweaked's limited processing power, it's not really possible to use these from your +computer. Instead, we need something much simpler. + +DFPWM (Dynamic Filter Pulse Width Modulation) is the de facto standard audio format of the ComputerCraft (and +OpenComputers) world. Originally popularised by the addon mod [Computronics], CC:T now has built-in support for it with +the @{cc.audio.dfpwm} module. This allows you to read DFPWM files from disk, decode them to PCM, and then play them +using the speaker. + +Let's dive in with an example, and we'll explain things afterwards: + +```lua {data-peripheral=speaker} +local dfpwm = require("cc.audio.dfpwm") +local speaker = peripheral.find("speaker") + +local decoder = dfpwm.make_decoder() +for chunk in io.lines("data/example.dfpwm", 16 * 1024) do + local buffer = decoder(chunk) + + while not speaker.playAudio(buffer) do + os.pullEvent("speaker_audio_empty") + end +end +``` + +Once again, we see the @{speaker.playAudio}/@{speaker_audio_empty} loop. However, the rest of the program is a little +different. + +First, we require the dfpwm module and call @{cc.audio.dfpwm.make_decoder} to construct a new decoder. This decoder +accepts blocks of DFPWM data and converts it to a list of 8-bit amplitudes, which we can then play with our speaker. + +As mentioned to above, @{speaker.playAudio} accepts at most 128×1024 samples in one go. DFPMW uses a single bit for each +sample, which means we want to process our audio in chunks of 16×1024 bytes (16KiB). In order to do this, we use +@{io.lines}, which provides a nice way to loop over chunks of a file. You can of course just use @{fs.open} and +@{fs.BinaryReadHandle.read} if you prefer. + +## Processing audio +As mentioned near the beginning of this guide, PCM audio is pretty easy to work with as it's just a list of amplitudes. +You can mix together samples from different streams by adding their amplitudes, change the rate of playback by removing +samples, etc... + +Let's put together a small demonstration here. We're going to add a small delay effect to the song above, so that you +hear a faint echo about a second later. + +In order to do this, we'll follow a format similar to the previous example, decoding the audio and then playing it. +However, we'll also add some new logic between those two steps, which loops over every sample in our chunk of audio, and +adds the sample from one second ago to it. + +For this, we'll need to keep track of the last 48k samples - exactly one seconds worth of audio. We can do this using a +[Ring Buffer], which helps makes things a little more efficient. + +```lua {data-peripheral=speaker} +local dfpwm = require("cc.audio.dfpwm") +local speaker = peripheral.find("speaker") + +-- Speakers play at 48kHz, so one second is 48k samples. We first fill our buffer +-- with 0s, as there's nothing to echo at the start of the track! +local samples_i, samples_n = 1, 48000 +local samples = {} +for i = 1, samples_n do samples[i] = 0 end + +local decoder = dfpwm.make_decoder() +for chunk in io.lines("data/example.dfpwm", 16 * 1024) do + local buffer = decoder(chunk) + + for i = 1, #buffer do + local original_value = buffer[i] + + -- Replace this sample with its current amplitude plus the amplitude from one second ago. + -- We scale both to ensure the resulting value is still between -128 and 127. + buffer[i] = original_value * 0.6 + samples[samples_i] * 0.4 + + -- Now store the current sample, and move the "head" of our ring buffer forward one place. + samples[samples_i] = original_value + samples_i = samples_i + 1 + if samples_i > samples_n then samples_i = 1 end + end + + while not speaker.playAudio(buffer) do + os.pullEvent("speaker_audio_empty") + end +end +``` + +:::note Confused? +Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't +cover. That said, don't be afraid to ask on [Discord] or [IRC] either! +::: + +It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of +the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex. +For this, you'd need to use the [Fast Fourier transform][FFT] to convert the stream of amplitudes to frequencies, +process those, and then convert them back to amplitudes. + +This is, I'm afraid, left as an exercise to the reader. + +[Computronics]: https://github.com/Vexatos/Computronics/ "Computronics on GitHub" +[FFT]: https://en.wikipedia.org/wiki/Fast_Fourier_transform "Fast Fourier transform - Wikipedia" +[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia" +[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia" +[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia" + +[Discord]: https://discord.computercraft.cc "The Minecraft Computer Mods Discord" +[IRC]: http://webchat.esper.net/?channels=computercraft "IRC webchat on EsperNet" diff --git a/doc/guides/using_require.md b/doc/guides/using_require.md new file mode 100644 index 000000000..06cc2ee20 --- /dev/null +++ b/doc/guides/using_require.md @@ -0,0 +1,83 @@ +--- +module: [kind=guide] using_require +--- + +# Reusing code with require +A library is a collection of useful functions and other definitions which is stored separately to your main program. You +might want to create a library because you have some functions which are used in multiple programs, or just to split +your program into multiple more modular files. + +Let's say we want to create a small library to make working with the @{term|terminal} a little easier. We'll provide two +functions: `reset`, which clears the terminal and sets the cursor to (1, 1), and `write_center`, which prints some text +in the middle of the screen. + +Start off by creating a file called `more_term.lua`: + +```lua {data-snippet=more_term} +local function reset() + term.clear() + term.setCursorPos(1, 1) +end + +local function write_center(text) + local x, y = term.getCursorPos() + local width, height = term.getSize() + term.setCursorPos(math.floor((width - #text) / 2) + 1, y) + term.write(text) +end + +return { reset = reset, write_center = write_center } +``` + +Now, what's going on here? We define our two functions as one might expect, and then at the bottom return a table with +the two functions. When we require this library, this table is what is returned. With that, we can then call the +original functions. Now create a new file, with the following: + +```lua {data-mount=more_term:more_term.lua} +local more_term = require("more_term") +more_term.reset() +more_term.write_center("Hello, world!") +``` + +When run, this'll clear the screen and print some text in the middle of the first line. + +## require in depth +While the previous section is a good introduction to how @{require} operates, there are a couple of remaining points +which are worth mentioning for more advanced usage. + +### Libraries can return anything +In our above example, we return a table containing the functions we want to expose. However, it's worth pointing out +that you can return ''anything'' from your library - a table, a function or even just a string! @{require} treats them +all the same, and just returns whatever your library provides. + +### Module resolution and the package path +In the above examples, we defined our library in a file, and @{require} read from it. While this is what you'll do most +of the time, it is possible to make @{require} look elsewhere for your library, such as downloading from a website or +loading from an in-memory library store. + +As a result, the *module name* you pass to @{require} doesn't correspond to a file path. One common mistake is to load +code from a sub-directory using `require("folder/library")` or even `require("folder/library.lua")`, neither of which +will do quite what you expect. + +When loading libraries (also referred to as *modules*) from files, @{require} searches along the *@{package.path|module +path}*. By default, this looks something like: + +* `?.lua` +* `?/init.lua` +* `/rom/modules/main/?.lua` +* etc... + +When you call `require("my_library")`, @{require} replaces the `?` in each element of the path with your module name, and +checks if the file exists. In this case, we'd look for `my_library.lua`, `my_library/init.lua`, +`/rom/modules/main/my_library.lua` and so on. Note that this works *relative to the current program*, so if your +program is actually called `folder/program`, then we'll look for `folder/my_library.lua`, etc... + +One other caveat is loading libraries from sub-directories. For instance, say we have a file +`my/fancy/library.lua`. This can be loaded by using `require("my.fancy.library")` - the '.'s are replaced with '/' +before we start looking for the library. + +## External links +There are several external resources which go into require in a little more detail: + + - The [Lua Module tutorial](http://lua-users.org/wiki/ModulesTutorial) on the Lua wiki. + - [Lua's manual section on @{require}](https://www.lua.org/manual/5.1/manual.html#pdf-require). diff --git a/doc/head.html b/doc/head.html new file mode 100644 index 000000000..efd18a401 --- /dev/null +++ b/doc/head.html @@ -0,0 +1 @@ + diff --git a/doc/images/basic-terminal.png b/doc/images/basic-terminal.png new file mode 100644 index 000000000..782b850cd Binary files /dev/null and b/doc/images/basic-terminal.png differ diff --git a/doc/images/peripherals.png b/doc/images/peripherals.png new file mode 100644 index 000000000..16c2e807d Binary files /dev/null and b/doc/images/peripherals.png differ diff --git a/doc/images/turtle.png b/doc/images/turtle.png new file mode 100644 index 000000000..7c58553a0 Binary files /dev/null and b/doc/images/turtle.png differ diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 000000000..74d76434b --- /dev/null +++ b/doc/index.md @@ -0,0 +1,55 @@ +# ![CC: Tweaked](logo.png) +CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the +much-beloved [ComputerCraft], it continues its legacy with better performance, stability, and a wealth of new features. + +CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It requires the [Minecraft Forge][forge] mod loader, but +[versions are available for Fabric][ccrestitched]. + +## Features +Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start +writing code and automating your Minecraft world. + +![A ComputerCraft terminal open and ready to be programmed.](images/basic-terminal.png){.big-image} + +While computers are incredibly powerful, they're rather limited by their inability to move about. *Turtles* are the +solution here. They can move about the world, placing and breaking blocks, swinging a sword to protect you from zombies, +or whatever else you program them to! + +![A turtle tunneling in Minecraft.](images/turtle.png){.big-image} + +Not all problems can be solved with a pickaxe though, and so CC: Tweaked also provides a bunch of additional peripherals +for your computers. You can play a tune with speakers, display text or images on a monitor, connect all your +computers together with modems, and much more. + +Computers can now also interact with inventories such as chests, allowing you to build complex inventory and item +management systems. + +![A chest's contents being read by a computer and displayed on a monitor.](images/peripherals.png){.big-image} + +## Getting Started +While ComputerCraft is lovely for both experienced programmers and for people who have never coded before, it can be a +little daunting getting started. Thankfully, there's several fantastic tutorials out there: + + - [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World") + - [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End") + - [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I") + +Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the +various APIs and peripherals provided by the mod. + +If you get stuck, do pop in to the [Minecraft Computer Mod Discord guild][discord] or ComputerCraft's +[IRC channel][irc]. + +## Get Involved +CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug]. + +[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub" +[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose +[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub" +[curseforge]: https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked from CurseForge" +[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth" +[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge." +[ccrestitched]: https://www.curseforge.com/minecraft/mc-mods/cc-restitched "Download CC: Restitched from CurseForge" +[lua]: https://www.lua.org/ "Lua's main website" +[discord]: https://discord.computercraft.cc "The Minecraft Computer Mods Discord" +[irc]: http://webchat.esper.net/?channels=computercraft "IRC webchat on EsperNet" diff --git a/doc/logo.png b/doc/logo.png new file mode 100644 index 000000000..33b71f8b6 Binary files /dev/null and b/doc/logo.png differ diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua new file mode 100644 index 000000000..aa40a30f3 --- /dev/null +++ b/doc/stub/fs.lua @@ -0,0 +1,36 @@ +--- The FS API allows you to manipulate files and the filesystem. +-- +-- @module fs + +--- Returns true if a path is mounted to the parent filesystem. +-- +-- The root filesystem "/" is considered a mount, along with disk folders and +-- the rom folder. Other programs (such as network shares) can exstend this to +-- make other mount types by correctly assigning their return value for getDrive. +-- +-- @tparam string path The path to check. +-- @treturn boolean If the path is mounted, rather than a normal file/folder. +-- @throws If the path does not exist. +-- @see getDrive +-- @since 1.87.0 +function isDriveRoot(path) end + +--[[- Provides completion for a file or directory name, suitable for use with +@{_G.read}. + +When a directory is a possible candidate for completion, two entries are +included - one with a trailing slash (indicating that entries within this +directory exist) and one without it (meaning this entry is an immediate +completion candidate). `include_dirs` can be set to @{false} to only include +those with a trailing slash. + +@tparam string path The path to complete. +@tparam string location The location where paths are resolved from. +@tparam[opt] boolean include_files When @{false}, only directories will be +included in the returned list. +@tparam[opt] boolean include_dirs When @{false}, "raw" directories will not be +included in the returned list. +@treturn { string... } A list of possible completion candidates. +@since 1.74 +]] +function complete(path, location, include_files, include_dirs) end diff --git a/doc/stub/global.lua b/doc/stub/global.lua new file mode 100644 index 000000000..6541da7e5 --- /dev/null +++ b/doc/stub/global.lua @@ -0,0 +1,133 @@ +--[[- +Functions in the global environment, defined in `bios.lua`. This does not +include standard Lua functions. + +@module _G +]] + +--[[- Pauses execution for the specified number of seconds. + +As it waits for a fixed amount of world ticks, `time` will automatically be +rounded up to the nearest multiple of 0.05 seconds. If you are using coroutines +or the @{parallel|parallel API}, it will only pause execution of the current +thread, not the whole program. + +:::tip +Because sleep internally uses timers, it is a function that yields. This means +that you can use it to prevent "Too long without yielding" errors, however, as +the minimum sleep time is 0.05 seconds, it will slow your program down. +::: + +:::caution +Internally, this function queues and waits for a timer event (using +@{os.startTimer}), however it does not listen for any other events. This means +that any event that occurs while sleeping will be entirely discarded. If you +need to receive events while sleeping, consider using @{os.startTimer|timers}, +or the @{parallel|parallel API}. +::: + +@tparam number time The number of seconds to sleep for, rounded up to the +nearest multiple of 0.05. + +@see os.startTimer +@usage Sleep for three seconds. + + print("Sleeping for three seconds") + sleep(3) + print("Done!") +]] +function sleep(time) end + +--- Writes a line of text to the screen without a newline at the end, wrapping +-- text if necessary. +-- +-- @tparam string text The text to write to the string +-- @treturn number The number of lines written +-- @see print A wrapper around write that adds a newline and accepts multiple arguments +-- @usage write("Hello, world") +function write(text) end + +--- Prints the specified values to the screen separated by spaces, wrapping if +-- necessary. After printing, the cursor is moved to the next line. +-- +-- @param ... The values to print on the screen +-- @treturn number The number of lines written +-- @usage print("Hello, world!") +function print(...) end + +--- Prints the specified values to the screen in red, separated by spaces, +-- wrapping if necessary. After printing, the cursor is moved to the next line. +-- +-- @param ... The values to print on the screen +-- @usage printError("Something went wrong!") +function printError(...) end + +--[[- Reads user input from the terminal, automatically handling arrow keys, +pasting, character replacement, history scrollback, auto-completion, and +default values. + +@tparam[opt] string replaceChar A character to replace each typed character with. +This can be used for hiding passwords, for example. +@tparam[opt] table history A table holding history items that can be scrolled +back to with the up/down arrow keys. The oldest item is at index 1, while the +newest item is at the highest index. +@tparam[opt] function(partial: string):({ string... }|nil) completeFn A function +to be used for completion. This function should take the partial text typed so +far, and returns a list of possible completion options. +@tparam[opt] string default Default text which should already be entered into +the prompt. + +@treturn string The text typed in. + +@see cc.completion For functions to help with completion. +@usage Read a string and echo it back to the user + + write("> ") + local msg = read() + print(msg) + +@usage Prompt a user for a password. + + while true do + write("Password> ") + local pwd = read("*") + if pwd == "let me in" then break end + print("Incorrect password, try again.") + end + print("Logged in!") + +@usage A complete example with completion, history and a default value. + + local completion = require "cc.completion" + local history = { "potato", "orange", "apple" } + local choices = { "apple", "orange", "banana", "strawberry" } + write("> ") + local msg = read(nil, history, function(text) return completion.choice(text, choices) end, "app") + print(msg) + +@changed 1.74 Added `completeFn` parameter. +@changed 1.80pr1 Added `default` parameter. +]] +function read(replaceChar, history, completeFn, default) end + +--- The ComputerCraft and Minecraft version of the current computer environment. +-- +-- For example, `ComputerCraft 1.93.0 (Minecraft 1.15.2)`. +-- @usage _HOST +-- @since 1.76 +_HOST = _HOST + +--[[- The default computer settings as defined in the ComputerCraft +configuration. + +This is a comma-separated list of settings pairs defined by the mod +configuration or server owner. By default, it is empty. + +An example value to disable autocompletion: + + shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false + +@usage _CC_DEFAULT_SETTINGS +@since 1.77 +]] +_CC_DEFAULT_SETTINGS = _CC_DEFAULT_SETTINGS diff --git a/doc/stub/http.lua b/doc/stub/http.lua new file mode 100644 index 000000000..81ba63753 --- /dev/null +++ b/doc/stub/http.lua @@ -0,0 +1,181 @@ +--- The http library allows communicating with web servers, sending and +-- receiving data from them. +-- +-- @module http +-- @since 1.1 + +--- Asynchronously make a HTTP request to the given url. +-- +-- This returns immediately, a [`http_success`](#http-success-event) or +-- [`http_failure`](#http-failure-event) will be queued once the request has +-- completed. +-- +-- @tparam string url The url to request +-- @tparam[opt] string body An optional string containing the body of the +-- request. If specified, a `POST` request will be made instead. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. +-- +-- This table form is an expanded version of the previous syntax. All arguments +-- from above are passed in as fields instead (for instance, +-- `http.request("https://example.com")` becomes `http.request { url = +-- "https://example.com" }`). +-- +-- This table also accepts several additional options: +-- +-- - `method`: Which HTTP method to use, for instance `"PATCH"` or `"DELETE"`. +-- - `redirect`: Whether to follow HTTP redirects. Defaults to true. +-- +-- @see http.get For a synchronous way to make GET requests. +-- @see http.post For a synchronous way to make POST requests. +-- +-- @changed 1.63 Added argument for headers. +-- @changed 1.80pr1 Added argument for binary handles. +-- @changed 1.80pr1.6 Added support for table argument. +-- @changed 1.86.0 Added PATCH and TRACE methods. +function request(...) end + +--- Make a HTTP GET request to the given url. +-- +-- @tparam string url The url to request +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +-- +-- @changed 1.63 Added argument for headers. +-- @changed 1.80pr1 Response handles are now returned on error if available. +-- @changed 1.80pr1 Added argument for binary handles. +-- @changed 1.80pr1.6 Added support for table argument. +-- @changed 1.86.0 Added PATCH and TRACE methods. +-- +-- @usage Make a request to [example.tweaked.cc](https://example.tweaked.cc), +-- and print the returned page. +-- ```lua +-- local request = http.get("https://example.tweaked.cc") +-- print(request.readAll()) +-- -- => HTTP is working! +-- request.close() +-- ``` +function get(...) end + +--- Make a HTTP POST request to the given url. +-- +-- @tparam string url The url to request +-- @tparam string body The body of the POST request. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +-- +-- @since 1.31 +-- @changed 1.63 Added argument for headers. +-- @changed 1.80pr1 Response handles are now returned on error if available. +-- @changed 1.80pr1 Added argument for binary handles. +-- @changed 1.80pr1.6 Added support for table argument. +-- @changed 1.86.0 Added PATCH and TRACE methods. +function post(...) end + +--- Asynchronously determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is not invalid. This does not imply that it is +-- allowed - see the comment above. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURL For a synchronous version. +function checkURLAsync(url) end + +--- Determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is valid and can be requested via @{http.request}. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURLAsync For an asynchronous version. +-- +-- @usage +-- ```lua +-- print(http.checkURL("https://example.tweaked.cc/")) +-- -- => true +-- print(http.checkURL("http://localhost/")) +-- -- => false Domain not permitted +-- print(http.checkURL("not a url")) +-- -- => false URL malformed +-- ``` +function checkURL(url) end + +--- Open a websocket. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +-- +-- @treturn Websocket The websocket connection. +-- @treturn[2] false If the websocket connection failed. +-- @treturn string An error message describing why the connection failed. +-- @since 1.80pr1.1 +-- @changed 1.80pr1.3 No longer asynchronous. +-- @changed 1.95.3 Added User-Agent to default headers. +function websocket(url, headers) end + +--- Asynchronously open a websocket. +-- +-- This returns immediately, a [`websocket_success`](#websocket-success-event) +-- or [`websocket_failure`](#websocket-failure-event) will be queued once the +-- request has completed. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +-- @since 1.80pr1.3 +-- @changed 1.95.3 Added User-Agent to default headers. +function websocketAsync(url, headers) end diff --git a/doc/stub/os.lua b/doc/stub/os.lua new file mode 100644 index 000000000..39c051ceb --- /dev/null +++ b/doc/stub/os.lua @@ -0,0 +1,128 @@ +-- Defined in bios.lua + +--[[- Loads the given API into the global environment. + +This function loads and executes the file at the given path, and all global +variables and functions exported by it will by available through the use of +`myAPI.`, where `myAPI` is the base name of the API file. + +@tparam string path The path of the API to load. +@treturn boolean Whether or not the API was successfully loaded. +@since 1.2 + +@deprecated When possible it's best to avoid using this function. It pollutes +the global table and can mask errors. + +@{require} should be used to load libraries instead. +]] +function loadAPI(path) end + +--- Unloads an API which was loaded by @{os.loadAPI}. +-- +-- This effectively removes the specified table from `_G`. +-- +-- @tparam string name The name of the API to unload. +-- @since 1.2 +-- @deprecated See @{os.loadAPI} for why. +function unloadAPI(name) end + +--[[- Pause execution of the current thread and waits for any events matching +`filter`. + +This function @{coroutine.yield|yields} the current process and waits for it +to be resumed with a vararg list where the first element matches `filter`. +If no `filter` is supplied, this will match all events. + +Unlike @{os.pullEventRaw}, it will stop the application upon a "terminate" +event, printing the error "Terminated". + +@tparam[opt] string filter Event to filter for. +@treturn string event The name of the event that fired. +@treturn any param... Optional additional parameters of the event. +@usage Listen for `mouse_click` events. + + while true do + local event, button, x, y = os.pullEvent("mouse_click") + print("Button", button, "was clicked at", x, ",", y) + end + +@usage Listen for multiple events. + + while true do + local eventData = {os.pullEvent()} + local event = eventData[1] + + if event == "mouse_click" then + print("Button", eventData[2], "was clicked at", eventData[3], ",", eventData[4]) + elseif event == "key" then + print("Key code", eventData[2], "was pressed") + end + end + +@see os.pullEventRaw To pull the terminate event. +@changed 1.3 Added filter argument. +]] +function pullEvent(filter) end + +--[[- Pause execution of the current thread and waits for events, including the +`terminate` event. + +This behaves almost the same as @{os.pullEvent}, except it allows you to handle +the `terminate` event yourself - the program will not stop execution when +Ctrl+T is pressed. + +@tparam[opt] string filter Event to filter for. +@treturn string event The name of the event that fired. +@treturn any param... Optional additional parameters of the event. +@usage Listen for `terminate` events. + + while true do + local event = os.pullEventRaw() + if event == "terminate" then + print("Caught terminate event!") + end + end + +@see os.pullEvent To pull events normally. +]] +function pullEventRaw(filter) end + +--- Pauses execution for the specified number of seconds, alias of @{_G.sleep}. +-- +-- @tparam number time The number of seconds to sleep for, rounded up to the +-- nearest multiple of 0.05. +function sleep(time) end + +--- Get the current CraftOS version (for example, `CraftOS 1.8`). +-- +-- This is defined by `bios.lua`. For the current version of CC:Tweaked, this +-- should return `CraftOS 1.8`. +-- +-- @treturn string The current CraftOS version. +-- @usage os.version() +function version() end + +--[[- Run the program at the given path with the specified environment and +arguments. + +This function does not resolve program names like the shell does. This means +that, for example, `os.run("edit")` will not work. As well as this, it does not +provide access to the @{shell} API in the environment. For this behaviour, use +@{shell.run} instead. + +If the program cannot be found, or failed to run, it will print the error and +return `false`. If you want to handle this more gracefully, use an alternative +such as @{loadfile}. + +@tparam table env The environment to run the program with. +@tparam string path The exact path of the program to run. +@param ... The arguments to pass to the program. +@treturn boolean Whether or not the program ran successfully. +@usage Run the default shell from within your program: + + os.run({}, "/rom/programs/shell.lua") + +@see shell.run +@see loadfile +]] +function run(env, path, ...) end diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua new file mode 100644 index 000000000..10ae68df7 --- /dev/null +++ b/doc/stub/turtle.lua @@ -0,0 +1,14 @@ +--[[- Craft a recipe based on the turtle's inventory. + +The turtle's inventory should set up like a crafting grid. For instance, to +craft sticks, slots 1 and 5 should contain planks. _All_ other slots should be +empty, including those outside the crafting "grid". + +@tparam[opt=64] number limit The maximum number of crafting steps to run. +@throws When limit is less than 1 or greater than 64. +@treturn[1] true If crafting succeeds. +@treturn[2] false If crafting fails. +@treturn string A string describing why crafting failed. +@since 1.4 +]] +function craft(limit) end